1 // Copyright (c) 2012 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.
5 #include "chrome/browser/ui/gtk/back_forward_button_gtk.h"
10 #include "base/message_loop/message_loop.h"
11 #include "chrome/app/chrome_command_ids.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/ui/browser.h"
14 #include "chrome/browser/ui/browser_commands.h"
15 #include "chrome/browser/ui/gtk/event_utils.h"
16 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
17 #include "chrome/browser/ui/gtk/gtk_util.h"
18 #include "chrome/browser/ui/gtk/menu_gtk.h"
19 #include "chrome/browser/ui/toolbar/back_forward_menu_model.h"
20 #include "grit/generated_resources.h"
21 #include "grit/theme_resources.h"
22 #include "ui/base/l10n/l10n_util.h"
24 // The time in milliseconds between when the user clicks and the menu appears.
25 static const int kMenuTimerDelay
= 500;
27 BackForwardButtonGtk::BackForwardButtonGtk(Browser
* browser
, bool is_forward
)
29 is_forward_(is_forward
),
31 int normal
, pushed
, hover
, disabled
, tooltip
;
35 pushed
= IDR_FORWARD_P
;
36 hover
= IDR_FORWARD_H
;
37 disabled
= IDR_FORWARD_D
;
38 tooltip
= IDS_TOOLTIP_FORWARD
;
39 stock
= GTK_STOCK_GO_FORWARD
;
44 disabled
= IDR_BACK_D
;
45 tooltip
= IDS_TOOLTIP_BACK
;
46 stock
= GTK_STOCK_GO_BACK
;
48 button_
.reset(new CustomDrawButton(
49 GtkThemeService::GetFrom(browser_
->profile()),
50 normal
, pushed
, hover
, disabled
, stock
, GTK_ICON_SIZE_SMALL_TOOLBAR
));
51 gtk_widget_set_tooltip_text(widget(),
52 l10n_util::GetStringUTF8(tooltip
).c_str());
53 menu_model_
.reset(new BackForwardMenuModel(browser
, is_forward
?
54 BackForwardMenuModel::FORWARD_MENU
:
55 BackForwardMenuModel::BACKWARD_MENU
));
57 g_signal_connect(widget(), "clicked",
58 G_CALLBACK(OnClickThunk
), this);
59 g_signal_connect(widget(), "button-press-event",
60 G_CALLBACK(OnButtonPressThunk
), this);
61 gtk_widget_add_events(widget(), GDK_POINTER_MOTION_MASK
);
62 g_signal_connect(widget(), "motion-notify-event",
63 G_CALLBACK(OnMouseMoveThunk
), this);
65 // Popup the menu as left-aligned relative to this widget rather than the
66 // default of right aligned.
67 g_object_set_data(G_OBJECT(widget()), "left-align-popup",
68 reinterpret_cast<void*>(true));
70 gtk_util::SetButtonTriggersNavigation(widget());
73 BackForwardButtonGtk::~BackForwardButtonGtk() {
76 void BackForwardButtonGtk::StoppedShowing() {
77 button_
->UnsetPaintOverride();
80 bool BackForwardButtonGtk::AlwaysShowIconForCmd(int command_id
) const {
84 void BackForwardButtonGtk::ShowBackForwardMenu(int button
, guint32 event_time
) {
85 menu_
.reset(new MenuGtk(this, menu_model_
.get()));
86 button_
->SetPaintOverride(GTK_STATE_ACTIVE
);
87 menu_
->PopupForWidget(widget(), button
, event_time
);
90 void BackForwardButtonGtk::OnClick(GtkWidget
* widget
) {
91 weak_factory_
.InvalidateWeakPtrs();
93 chrome::ExecuteCommandWithDisposition(
95 is_forward_
? IDC_FORWARD
: IDC_BACK
,
96 event_utils::DispositionForCurrentButtonPressEvent());
99 gboolean
BackForwardButtonGtk::OnButtonPress(GtkWidget
* widget
,
100 GdkEventButton
* event
) {
101 if (event
->button
== 3)
102 ShowBackForwardMenu(event
->button
, event
->time
);
104 if (event
->button
!= 1)
107 y_position_of_last_press_
= static_cast<int>(event
->y
);
108 base::MessageLoop::current()->PostDelayedTask(
110 base::Bind(&BackForwardButtonGtk::ShowBackForwardMenu
,
111 weak_factory_
.GetWeakPtr(),
114 base::TimeDelta::FromMilliseconds(kMenuTimerDelay
));
118 gboolean
BackForwardButtonGtk::OnMouseMove(GtkWidget
* widget
,
119 GdkEventMotion
* event
) {
120 // If we aren't waiting to show the back forward menu, do nothing.
121 if (!weak_factory_
.HasWeakPtrs())
124 // We only count moves about a certain threshold.
125 GtkSettings
* settings
= gtk_widget_get_settings(widget
);
126 int drag_min_distance
;
127 g_object_get(settings
, "gtk-dnd-drag-threshold", &drag_min_distance
, NULL
);
128 if (event
->y
- y_position_of_last_press_
< drag_min_distance
)
131 // We will show the menu now. Cancel the delayed event.
132 weak_factory_
.InvalidateWeakPtrs();
133 ShowBackForwardMenu(/* button */ 1, event
->time
);