Chromium Code Reviews| Index: chrome/browser/ui/gtk/reload_button_gtk.cc |
| diff --git a/chrome/browser/ui/gtk/reload_button_gtk.cc b/chrome/browser/ui/gtk/reload_button_gtk.cc |
| index a3cc4b52f12ea76e9cded846d1935733534254e5..cd3c91539ec8276d7c5394efefe27f0b64bb00f4 100644 |
| --- a/chrome/browser/ui/gtk/reload_button_gtk.cc |
| +++ b/chrome/browser/ui/gtk/reload_button_gtk.cc |
| @@ -28,6 +28,16 @@ |
| // doesn't change sizes when switching between the two. |
| static int GtkButtonWidth = 0; |
| +// The time in milliseconds between when the user clicks and the menu appears. |
| +static const int kReloadMenuTimerDelay = 500; |
| + |
| +// Content of the Reload drop-down menu. |
| +static const int kReloadMenuItems[] = { |
| + IDS_RELOAD_MENU_NORMAL_RELOAD_ITEM, |
| + IDS_RELOAD_MENU_HARD_RELOAD_ITEM, |
| + IDS_RELOAD_MENU_CLEAR_AND_HARD_RELOAD_ITEM, |
| +}; |
| + |
| //////////////////////////////////////////////////////////////////////////////// |
| // ReloadButton, public: |
| @@ -43,8 +53,14 @@ ReloadButtonGtk::ReloadButtonGtk(LocationBarViewGtk* location_bar, |
| stop_(theme_service_, IDR_STOP, IDR_STOP_P, IDR_STOP_H, IDR_STOP_D), |
| widget_(gtk_chrome_button_new()), |
| stop_to_reload_timer_delay_(base::TimeDelta::FromMilliseconds(1350)), |
| + weak_factory_(this), |
| testing_mouse_hovered_(false), |
| testing_reload_count_(0) { |
| + menu_model_.reset(new ui::SimpleMenuModel(this)); |
| + for (size_t i = 0; i < arraysize(kReloadMenuItems); i++) { |
| + menu_model_->AddItemWithStringId(kReloadMenuItems[i], kReloadMenuItems[i]); |
| + } |
| + |
| gtk_widget_set_size_request(widget(), reload_.Width(), reload_.Height()); |
| gtk_widget_set_app_paintable(widget(), TRUE); |
| @@ -59,6 +75,17 @@ ReloadButtonGtk::ReloadButtonGtk(LocationBarViewGtk* location_bar, |
| g_signal_connect(widget(), "query-tooltip", G_CALLBACK(OnQueryTooltipThunk), |
| this); |
| + g_signal_connect(widget(), "button-press-event", |
| + G_CALLBACK(OnButtonPressThunk), this); |
| + gtk_widget_add_events(widget(), GDK_POINTER_MOTION_MASK); |
| + g_signal_connect(widget(), "motion-notify-event", |
| + G_CALLBACK(OnMouseMoveThunk), this); |
| + |
| + // Popup the menu as left-aligned relative to this widget rather than the |
| + // default of right aligned. |
| + g_object_set_data(G_OBJECT(widget()), "left-align-popup", |
| + reinterpret_cast<void*>(true)); |
| + |
| hover_controller_.Init(widget()); |
| gtk_util::SetButtonTriggersNavigation(widget()); |
| @@ -144,9 +171,54 @@ void ReloadButtonGtk::Observe(int type, |
| } |
| //////////////////////////////////////////////////////////////////////////////// |
| +// ReloadButtonGtk, MenuGtk::Delegate implementation: |
| + |
| +void ReloadButtonGtk::StoppedShowing() { |
| + reload_.set_paint_override(-1); |
| +} |
| + |
| +//////////////////////////////////////////////////////////////////////////////// |
| +// ReloadButtonGtk, SimpleMenuModel::Delegate implementation: |
| + |
| +bool ReloadButtonGtk::IsCommandIdChecked(int command_id) const { |
| + return false; |
| +} |
| + |
| +bool ReloadButtonGtk::IsCommandIdEnabled(int command_id) const { |
| + return true; |
| +} |
| + |
| +bool ReloadButtonGtk::IsCommandIdVisible(int command_id) const { |
| + return true; |
| +} |
| + |
| +bool ReloadButtonGtk::GetAcceleratorForCommandId(int command_id, |
| + ui::Accelerator* accelerator) { |
| + return false; |
| +} |
| + |
| +void ReloadButtonGtk::ExecuteCommand(int command_id) { |
| + switch (command_id) { |
| + case IDS_RELOAD_MENU_NORMAL_RELOAD_ITEM: |
| + DoReload(IDC_RELOAD); |
| + break; |
| + case IDS_RELOAD_MENU_HARD_RELOAD_ITEM: |
| + DoReload(IDC_RELOAD_IGNORING_CACHE); |
| + break; |
| + case IDS_RELOAD_MENU_CLEAR_AND_HARD_RELOAD_ITEM: |
| + ClearCache(); |
| + DoReload(IDC_RELOAD_IGNORING_CACHE); |
| + break; |
| + default: |
| + LOG(ERROR) << "Unknown reload menu command"; |
| + } |
| +} |
| + |
| +//////////////////////////////////////////////////////////////////////////////// |
| // ReloadButtonGtk, private: |
| void ReloadButtonGtk::OnClicked(GtkWidget* /* sender */) { |
| + weak_factory_.InvalidateWeakPtrs(); |
| if (visible_mode_ == MODE_STOP) { |
| // Do nothing if Stop was disabled due to an attempt to change back to |
| // RELOAD mode while hovered. |
| @@ -160,40 +232,7 @@ void ReloadButtonGtk::OnClicked(GtkWidget* /* sender */) { |
| // even if the mouse is still hovering. |
| ChangeMode(MODE_RELOAD, true); |
| } else if (!double_click_timer_.IsRunning()) { |
| - // Shift-clicking or Ctrl-clicking the reload button means we should ignore |
| - // any cached content. |
| - int command; |
| - GdkModifierType modifier_state; |
| - gtk_get_current_event_state(&modifier_state); |
| - guint modifier_state_uint = modifier_state; |
| - if (modifier_state_uint & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) { |
| - command = IDC_RELOAD_IGNORING_CACHE; |
| - // Mask off Shift and Control so they don't affect the disposition below. |
| - modifier_state_uint &= ~(GDK_SHIFT_MASK | GDK_CONTROL_MASK); |
| - } else { |
| - command = IDC_RELOAD; |
| - } |
| - |
| - WindowOpenDisposition disposition = |
| - event_utils::DispositionFromGdkState(modifier_state_uint); |
| - if ((disposition == CURRENT_TAB) && location_bar_) { |
| - // Forcibly reset the location bar, since otherwise it won't discard any |
| - // ongoing user edits, since it doesn't realize this is a user-initiated |
| - // action. |
| - location_bar_->Revert(); |
| - } |
| - |
| - // Start a timer - while this timer is running, the reload button cannot be |
| - // changed to a stop button. We do not set |intended_mode_| to MODE_STOP |
| - // here as the browser will do that when it actually starts loading (which |
| - // may happen synchronously, thus the need to do this before telling the |
| - // browser to execute the reload command). |
| - double_click_timer_.Start(FROM_HERE, double_click_timer_delay_, this, |
| - &ReloadButtonGtk::OnDoubleClickTimer); |
| - |
| - if (browser_) |
| - chrome::ExecuteCommandWithDisposition(browser_, command, disposition); |
| - ++testing_reload_count_; |
| + DoReload(0); |
| } |
| } |
| @@ -221,12 +260,55 @@ gboolean ReloadButtonGtk::OnQueryTooltip(GtkWidget* /* sender */, |
| if (!location_bar_) |
| return FALSE; |
| + int reload_tooltip = ReloadMenuEnabled() ? |
| + IDS_TOOLTIP_RELOAD_WITH_MENU : IDS_TOOLTIP_RELOAD; |
| gtk_tooltip_set_text(tooltip, l10n_util::GetStringUTF8( |
| (visible_mode_ == MODE_RELOAD) ? |
| - IDS_TOOLTIP_RELOAD : IDS_TOOLTIP_STOP).c_str()); |
| + reload_tooltip : IDS_TOOLTIP_STOP).c_str()); |
| return TRUE; |
| } |
| +gboolean ReloadButtonGtk::OnButtonPress(GtkWidget* widget, |
| + GdkEventButton* event) { |
| + if (!ReloadMenuEnabled() || visible_mode_ == MODE_STOP) |
| + return FALSE; |
| + |
| + if (event->button == 3) |
| + ShowReloadMenu(event->button, event->time); |
| + |
| + if (event->button != 1) |
| + return FALSE; |
| + |
| + y_position_of_last_press_ = static_cast<int>(event->y); |
| + MessageLoop::current()->PostDelayedTask( |
| + FROM_HERE, |
| + base::Bind(&ReloadButtonGtk::ShowReloadMenu, |
| + weak_factory_.GetWeakPtr(), |
| + event->button, |
| + event->time), |
| + base::TimeDelta::FromMilliseconds(kReloadMenuTimerDelay)); |
| + return FALSE; |
| +} |
| + |
| +gboolean ReloadButtonGtk::OnMouseMove(GtkWidget* widget, |
| + GdkEventMotion* event) { |
| + // If we aren't waiting to show the back forward menu, do nothing. |
| + if (!weak_factory_.HasWeakPtrs()) |
| + return FALSE; |
| + |
| + // We only count moves about a certain threshold. |
| + GtkSettings* settings = gtk_widget_get_settings(widget); |
| + int drag_min_distance; |
| + g_object_get(settings, "gtk-dnd-drag-threshold", &drag_min_distance, NULL); |
| + if (event->y - y_position_of_last_press_ < drag_min_distance) |
| + return FALSE; |
| + |
| + // We will show the menu now. Cancel the delayed event. |
| + weak_factory_.InvalidateWeakPtrs(); |
| + ShowReloadMenu(/* button */ 1, event->time); |
| + return FALSE; |
| +} |
| + |
| void ReloadButtonGtk::UpdateThemeButtons() { |
| bool use_gtk = theme_service_ && theme_service_->UsingNativeTheme(); |
| @@ -283,3 +365,65 @@ void ReloadButtonGtk::OnDoubleClickTimer() { |
| void ReloadButtonGtk::OnStopToReloadTimer() { |
| ChangeMode(intended_mode_, true); |
| } |
| + |
| +void ReloadButtonGtk::ShowReloadMenu(int button, guint32 event_time) { |
| + if (!ReloadMenuEnabled() || visible_mode_ == MODE_STOP) |
| + return; |
| + |
| + menu_.reset(new MenuGtk(this, menu_model_.get())); |
| + reload_.set_paint_override(GTK_STATE_ACTIVE); |
| + menu_->PopupForWidget(widget(), button, event_time); |
| +} |
| + |
| +void ReloadButtonGtk::DoReload(int command) { |
| + // Shift-clicking or Ctrl-clicking the reload button means we should ignore |
| + // any cached content. |
| + GdkModifierType modifier_state; |
| + gtk_get_current_event_state(&modifier_state); |
| + guint modifier_state_uint = modifier_state; |
| + |
| + // Default reload behaviour. |
| + if (command == 0) { |
| + if (modifier_state_uint & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) { |
| + command = IDC_RELOAD_IGNORING_CACHE; |
| + // Mask off Shift and Control so they don't affect the disposition below. |
| + modifier_state_uint &= ~(GDK_SHIFT_MASK | GDK_CONTROL_MASK); |
| + } else { |
| + command = IDC_RELOAD; |
| + } |
| + } |
| + |
| + WindowOpenDisposition disposition = |
| + event_utils::DispositionFromGdkState(modifier_state_uint); |
| + if ((disposition == CURRENT_TAB) && location_bar_) { |
| + // Forcibly reset the location bar, since otherwise it won't discard any |
| + // ongoing user edits, since it doesn't realize this is a user-initiated |
| + // action. |
| + location_bar_->Revert(); |
| + } |
| + |
| + // Start a timer - while this timer is running, the reload button cannot be |
| + // changed to a stop button. We do not set |intended_mode_| to MODE_STOP |
| + // here as the browser will do that when it actually starts loading (which |
| + // may happen synchronously, thus the need to do this before telling the |
| + // browser to execute the reload command). |
| + double_click_timer_.Start(FROM_HERE, double_click_timer_delay_, this, |
| + &ReloadButtonGtk::OnDoubleClickTimer); |
| + |
| + if (browser_) |
| + chrome::ExecuteCommandWithDisposition(browser_, command, disposition); |
| + ++testing_reload_count_; |
| +} |
| + |
| +bool ReloadButtonGtk::ReloadMenuEnabled() { |
| + if (!browser_) |
| + return false; |
| + return chrome::IsDebuggerAttachedToCurrentTab(browser_); |
| +} |
| + |
| +void ReloadButtonGtk::ClearCache() { |
| + if (browser_) { |
|
Evan Stade
2012/07/11 02:13:30
no curlies
|
| + chrome::ClearCache(browser_); |
| + } |
| +} |
| + |