• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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/ui/gtk/back_forward_button_gtk.h"
6 
7 #include <gtk/gtk.h>
8 
9 #include "base/message_loop.h"
10 #include "chrome/app/chrome_command_ids.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
14 #include "chrome/browser/ui/gtk/gtk_util.h"
15 #include "chrome/browser/ui/gtk/menu_gtk.h"
16 #include "chrome/browser/ui/toolbar/back_forward_menu_model.h"
17 #include "grit/generated_resources.h"
18 #include "grit/theme_resources.h"
19 #include "ui/base/l10n/l10n_util.h"
20 
21 // The time in milliseconds between when the user clicks and the menu appears.
22 static const int kMenuTimerDelay = 500;
23 
BackForwardButtonGtk(Browser * browser,bool is_forward)24 BackForwardButtonGtk::BackForwardButtonGtk(Browser* browser, bool is_forward)
25     : browser_(browser),
26       is_forward_(is_forward),
27       show_menu_factory_(this) {
28   int normal, pushed, hover, disabled, tooltip;
29   const char* stock;
30   if (is_forward) {
31     normal = IDR_FORWARD;
32     pushed = IDR_FORWARD_P;
33     hover = IDR_FORWARD_H;
34     disabled = IDR_FORWARD_D;
35     tooltip = IDS_TOOLTIP_FORWARD;
36     stock = GTK_STOCK_GO_FORWARD;
37   } else {
38     normal = IDR_BACK;
39     pushed = IDR_BACK_P;
40     hover = IDR_BACK_H;
41     disabled = IDR_BACK_D;
42     tooltip = IDS_TOOLTIP_BACK;
43     stock = GTK_STOCK_GO_BACK;
44   }
45   button_.reset(new CustomDrawButton(
46       GtkThemeService::GetFrom(browser_->profile()),
47       normal, pushed, hover, disabled, stock, GTK_ICON_SIZE_SMALL_TOOLBAR));
48   gtk_widget_set_tooltip_text(widget(),
49                               l10n_util::GetStringUTF8(tooltip).c_str());
50   menu_model_.reset(new BackForwardMenuModel(browser, is_forward ?
51       BackForwardMenuModel::FORWARD_MENU :
52       BackForwardMenuModel::BACKWARD_MENU));
53 
54   g_signal_connect(widget(), "clicked",
55                    G_CALLBACK(OnClickThunk), this);
56   g_signal_connect(widget(), "button-press-event",
57                    G_CALLBACK(OnButtonPressThunk), this);
58   gtk_widget_add_events(widget(), GDK_POINTER_MOTION_MASK);
59   g_signal_connect(widget(), "motion-notify-event",
60                    G_CALLBACK(OnMouseMoveThunk), this);
61 
62   // Popup the menu as left-aligned relative to this widget rather than the
63   // default of right aligned.
64   g_object_set_data(G_OBJECT(widget()), "left-align-popup",
65                     reinterpret_cast<void*>(true));
66 
67   gtk_util::SetButtonTriggersNavigation(widget());
68 }
69 
~BackForwardButtonGtk()70 BackForwardButtonGtk::~BackForwardButtonGtk() {
71 }
72 
StoppedShowing()73 void BackForwardButtonGtk::StoppedShowing() {
74   button_->UnsetPaintOverride();
75 }
76 
AlwaysShowIconForCmd(int command_id) const77 bool BackForwardButtonGtk::AlwaysShowIconForCmd(int command_id) const {
78   return true;
79 }
80 
ShowBackForwardMenu(int button,guint32 event_time)81 void BackForwardButtonGtk::ShowBackForwardMenu(int button, guint32 event_time) {
82   menu_.reset(new MenuGtk(this, menu_model_.get()));
83   button_->SetPaintOverride(GTK_STATE_ACTIVE);
84   menu_->PopupForWidget(widget(), button, event_time);
85 }
86 
OnClick(GtkWidget * widget)87 void BackForwardButtonGtk::OnClick(GtkWidget* widget) {
88   show_menu_factory_.RevokeAll();
89 
90   browser_->ExecuteCommandWithDisposition(
91       is_forward_ ? IDC_FORWARD : IDC_BACK,
92       gtk_util::DispositionForCurrentButtonPressEvent());
93 }
94 
OnButtonPress(GtkWidget * widget,GdkEventButton * event)95 gboolean BackForwardButtonGtk::OnButtonPress(GtkWidget* widget,
96                                              GdkEventButton* event) {
97   if (event->button == 3)
98     ShowBackForwardMenu(event->button, event->time);
99 
100   if (event->button != 1)
101     return FALSE;
102 
103   y_position_of_last_press_ = static_cast<int>(event->y);
104   MessageLoop::current()->PostDelayedTask(FROM_HERE,
105       show_menu_factory_.NewRunnableMethod(
106           &BackForwardButtonGtk::ShowBackForwardMenu,
107           event->button, event->time),
108       kMenuTimerDelay);
109   return FALSE;
110 }
111 
OnMouseMove(GtkWidget * widget,GdkEventMotion * event)112 gboolean BackForwardButtonGtk::OnMouseMove(GtkWidget* widget,
113                                            GdkEventMotion* event) {
114   // If we aren't waiting to show the back forward menu, do nothing.
115   if (show_menu_factory_.empty())
116     return FALSE;
117 
118   // We only count moves about a certain threshold.
119   GtkSettings* settings = gtk_widget_get_settings(widget);
120   int drag_min_distance;
121   g_object_get(settings, "gtk-dnd-drag-threshold", &drag_min_distance, NULL);
122   if (event->y - y_position_of_last_press_ < drag_min_distance)
123     return FALSE;
124 
125   // We will show the menu now. Cancel the delayed event.
126   show_menu_factory_.RevokeAll();
127   ShowBackForwardMenu(/* button */ 1, event->time);
128   return FALSE;
129 }
130