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