Home | History | Annotate | Download | only in gtk
      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 
     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 
     70 BackForwardButtonGtk::~BackForwardButtonGtk() {
     71 }
     72 
     73 void BackForwardButtonGtk::StoppedShowing() {
     74   button_->UnsetPaintOverride();
     75 }
     76 
     77 bool BackForwardButtonGtk::AlwaysShowIconForCmd(int command_id) const {
     78   return true;
     79 }
     80 
     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 
     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 
     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 
    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