| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/gtk/go_button_gtk.h" |
| 6 #include "base/logging.h" |
| 7 #include "base/message_loop.h" |
| 8 #include "chrome/app/chrome_dll_resource.h" |
| 9 #include "chrome/browser/browser.h" |
| 10 #include "grit/theme_resources.h" |
| 11 |
| 12 GoButtonGtk::GoButtonGtk(Browser* browser) |
| 13 : browser_(browser), |
| 14 button_delay_(0), |
| 15 stop_timer_(this), |
| 16 intended_mode_(MODE_GO), |
| 17 visible_mode_(MODE_GO), |
| 18 state_(BS_NORMAL), |
| 19 go_(IDR_GO, IDR_GO_P, IDR_GO_H, 0), |
| 20 stop_(IDR_STOP, IDR_STOP_P, IDR_STOP_H, 0), |
| 21 widget_(gtk_button_new()) { |
| 22 gtk_widget_set_size_request(widget_.get(), |
| 23 gdk_pixbuf_get_width(go_.pixbufs(0)), |
| 24 gdk_pixbuf_get_height(go_.pixbufs(0))); |
| 25 |
| 26 gtk_widget_set_app_paintable(widget_.get(), TRUE); |
| 27 // We effectively double-buffer by virtue of having only one image... |
| 28 gtk_widget_set_double_buffered(widget_.get(), FALSE); |
| 29 |
| 30 g_signal_connect(G_OBJECT(widget_.get()), "expose-event", |
| 31 G_CALLBACK(OnExpose), this); |
| 32 g_signal_connect(G_OBJECT(widget_.get()), "enter", |
| 33 G_CALLBACK(OnEnter), this); |
| 34 g_signal_connect(G_OBJECT(widget_.get()), "leave", |
| 35 G_CALLBACK(OnLeave), this); |
| 36 g_signal_connect(G_OBJECT(widget_.get()), "clicked", |
| 37 G_CALLBACK(OnClicked), this); |
| 38 GTK_WIDGET_UNSET_FLAGS(widget_.get(), GTK_CAN_FOCUS); |
| 39 |
| 40 // TODO(willchan): Implement tooltips. |
| 41 gtk_widget_set_tooltip_text(widget_.get(), "Implement toggleable tooltips"); |
| 42 } |
| 43 |
| 44 GoButtonGtk::~GoButtonGtk() { |
| 45 widget_.Destroy(); |
| 46 } |
| 47 |
| 48 void GoButtonGtk::ChangeMode(Mode mode) { |
| 49 if (mode != visible_mode_) { |
| 50 gtk_widget_queue_draw(widget_.get()); |
| 51 } |
| 52 stop_timer_.RevokeAll(); |
| 53 intended_mode_ = mode; |
| 54 visible_mode_ = mode; |
| 55 } |
| 56 |
| 57 void GoButtonGtk::ScheduleChangeMode(Mode mode) { |
| 58 if (mode == MODE_STOP) { |
| 59 // If we still have a timer running, we can't yet change to a stop sign, |
| 60 // so we'll queue up the change for when the timer expires or for when |
| 61 // the mouse exits the button. |
| 62 if (!stop_timer_.empty() && state() == BS_HOT) { |
| 63 intended_mode_ = MODE_STOP; |
| 64 } else { |
| 65 ChangeMode(MODE_STOP); |
| 66 } |
| 67 } else { |
| 68 // If we want to change the button to a go button, but the user's mouse |
| 69 // is hovering, don't change the mode just yet - this prevents the |
| 70 // stop button changing to a go under the user's mouse cursor. |
| 71 if (visible_mode_ == MODE_STOP && state() == BS_HOT) { |
| 72 intended_mode_ = MODE_GO; |
| 73 } else { |
| 74 ChangeMode(MODE_GO); |
| 75 } |
| 76 } |
| 77 } |
| 78 |
| 79 Task* GoButtonGtk::CreateButtonTimerTask() { |
| 80 return stop_timer_.NewRunnableMethod(&GoButtonGtk::OnButtonTimer); |
| 81 } |
| 82 |
| 83 void GoButtonGtk::OnButtonTimer() { |
| 84 if (intended_mode_ != visible_mode_) { |
| 85 ChangeMode(intended_mode_); |
| 86 } |
| 87 |
| 88 stop_timer_.RevokeAll(); |
| 89 } |
| 90 |
| 91 // static |
| 92 gboolean GoButtonGtk::OnExpose(GtkWidget* widget, |
| 93 GdkEventExpose* e, |
| 94 GoButtonGtk* button) { |
| 95 if (button->visible_mode_ == MODE_GO) { |
| 96 return button->go_.OnExpose(widget, e); |
| 97 } else { |
| 98 return button->stop_.OnExpose(widget, e); |
| 99 } |
| 100 } |
| 101 |
| 102 // static |
| 103 gboolean GoButtonGtk::OnEnter(GtkButton* widget, GoButtonGtk* button) { |
| 104 DCHECK_EQ(BS_NORMAL, button->state()); |
| 105 button->state_ = BS_HOT; |
| 106 return TRUE; |
| 107 } |
| 108 |
| 109 // static |
| 110 gboolean GoButtonGtk::OnLeave(GtkButton* widget, GoButtonGtk* button) { |
| 111 DCHECK_EQ(BS_HOT, button->state()); |
| 112 button->state_ = BS_NORMAL; |
| 113 if (button->visible_mode_ != button->intended_mode_) { |
| 114 button->ChangeMode(button->intended_mode_); |
| 115 } |
| 116 return TRUE; |
| 117 } |
| 118 |
| 119 // static |
| 120 gboolean GoButtonGtk::OnClicked(GtkButton* widget, GoButtonGtk* button) { |
| 121 if (button->visible_mode_ == MODE_STOP) { |
| 122 if (button->browser_) |
| 123 button->browser_->Stop(); |
| 124 |
| 125 // The user has clicked, so we can feel free to update the button, |
| 126 // even if the mouse is still hovering. |
| 127 button->ChangeMode(MODE_GO); |
| 128 } else if (button->visible_mode_ == MODE_GO && button->stop_timer_.empty()) { |
| 129 // If the go button is visible and not within the double click timer, go. |
| 130 if (button->browser_) |
| 131 button->browser_->ExecuteCommand(IDC_GO); |
| 132 |
| 133 // Figure out the system double-click time. |
| 134 if (button->button_delay_ == 0) { |
| 135 GtkSettings* settings = gtk_settings_get_default(); |
| 136 g_object_get(G_OBJECT(settings), |
| 137 "gtk-double-click-time", |
| 138 &button->button_delay_, |
| 139 NULL); |
| 140 } |
| 141 |
| 142 // Stop any existing timers. |
| 143 button->stop_timer_.RevokeAll(); |
| 144 |
| 145 // Start a timer - while this timer is running, the go button |
| 146 // cannot be changed to a stop button. We do not set intended_mode_ |
| 147 // to MODE_STOP here as we want to wait for the browser to tell |
| 148 // us that it has started loading (and this may occur only after |
| 149 // some delay). |
| 150 MessageLoop::current()->PostDelayedTask(FROM_HERE, |
| 151 button->CreateButtonTimerTask(), |
| 152 button->button_delay_); |
| 153 } |
| 154 |
| 155 return TRUE; |
| 156 } |
| OLD | NEW |