172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/back_forward_button_gtk.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <gtk/gtk.h>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/message_loop.h"
10513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/app/chrome_command_ids.h"
1121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/ui/browser.h"
13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/gtk/gtk_theme_service.h"
1472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/gtk_util.h"
1572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/menu_gtk.h"
1621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/toolbar/back_forward_menu_model.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/theme_resources.h"
1972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h"
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The time in milliseconds between when the user clicks and the menu appears.
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kMenuTimerDelay = 500;
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBackForwardButtonGtk::BackForwardButtonGtk(Browser* browser, bool is_forward)
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : browser_(browser),
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      is_forward_(is_forward),
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      show_menu_factory_(this) {
283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int normal, pushed, hover, disabled, tooltip;
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char* stock;
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (is_forward) {
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    normal = IDR_FORWARD;
323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    pushed = IDR_FORWARD_P;
333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    hover = IDR_FORWARD_H;
343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    disabled = IDR_FORWARD_D;
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    tooltip = IDS_TOOLTIP_FORWARD;
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    stock = GTK_STOCK_GO_FORWARD;
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    normal = IDR_BACK;
393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    pushed = IDR_BACK_P;
403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    hover = IDR_BACK_H;
413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    disabled = IDR_BACK_D;
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    tooltip = IDS_TOOLTIP_BACK;
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    stock = GTK_STOCK_GO_BACK;
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  button_.reset(new CustomDrawButton(
46ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      GtkThemeService::GetFrom(browser_->profile()),
473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      normal, pushed, hover, disabled, stock, GTK_ICON_SIZE_SMALL_TOOLBAR));
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_widget_set_tooltip_text(widget(),
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              l10n_util::GetStringUTF8(tooltip).c_str());
503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  menu_model_.reset(new BackForwardMenuModel(browser, is_forward ?
513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      BackForwardMenuModel::FORWARD_MENU :
523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      BackForwardMenuModel::BACKWARD_MENU));
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_signal_connect(widget(), "clicked",
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnClickThunk), this);
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_signal_connect(widget(), "button-press-event",
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnButtonPressThunk), this);
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_widget_add_events(widget(), GDK_POINTER_MOTION_MASK);
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_signal_connect(widget(), "motion-notify-event",
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnMouseMoveThunk), this);
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Popup the menu as left-aligned relative to this widget rather than the
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // default of right aligned.
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_object_set_data(G_OBJECT(widget()), "left-align-popup",
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    reinterpret_cast<void*>(true));
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_util::SetButtonTriggersNavigation(widget());
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBackForwardButtonGtk::~BackForwardButtonGtk() {
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BackForwardButtonGtk::StoppedShowing() {
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  button_->UnsetPaintOverride();
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
77731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool BackForwardButtonGtk::AlwaysShowIconForCmd(int command_id) const {
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
8172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid BackForwardButtonGtk::ShowBackForwardMenu(int button, guint32 event_time) {
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  menu_.reset(new MenuGtk(this, menu_model_.get()));
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  button_->SetPaintOverride(GTK_STATE_ACTIVE);
8472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  menu_->PopupForWidget(widget(), button, event_time);
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BackForwardButtonGtk::OnClick(GtkWidget* widget) {
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  show_menu_factory_.RevokeAll();
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  browser_->ExecuteCommandWithDisposition(
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      is_forward_ ? IDC_FORWARD : IDC_BACK,
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      gtk_util::DispositionForCurrentButtonPressEvent());
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean BackForwardButtonGtk::OnButtonPress(GtkWidget* widget,
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                             GdkEventButton* event) {
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (event->button == 3)
9872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    ShowBackForwardMenu(event->button, event->time);
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (event->button != 1)
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return FALSE;
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  y_position_of_last_press_ = static_cast<int>(event->y);
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MessageLoop::current()->PostDelayedTask(FROM_HERE,
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      show_menu_factory_.NewRunnableMethod(
10672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          &BackForwardButtonGtk::ShowBackForwardMenu,
10772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          event->button, event->time),
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      kMenuTimerDelay);
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return FALSE;
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean BackForwardButtonGtk::OnMouseMove(GtkWidget* widget,
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           GdkEventMotion* event) {
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If we aren't waiting to show the back forward menu, do nothing.
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (show_menu_factory_.empty())
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return FALSE;
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We only count moves about a certain threshold.
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GtkSettings* settings = gtk_widget_get_settings(widget);
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int drag_min_distance;
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_object_get(settings, "gtk-dnd-drag-threshold", &drag_min_distance, NULL);
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (event->y - y_position_of_last_press_ < drag_min_distance)
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return FALSE;
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We will show the menu now. Cancel the delayed event.
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  show_menu_factory_.RevokeAll();
12772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  ShowBackForwardMenu(/* button */ 1, event->time);
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return FALSE;
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
130