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/browser_actions_toolbar_gtk.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include <algorithm>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <vector>
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/i18n/rtl.h"
113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_browser_event_router.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_context_menu_model.h"
1421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/extensions/extension_service.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/image_loading_tracker.h"
1621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/ui/browser.h"
1872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/cairo_cached_surface.h"
19ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/gtk/extensions/extension_popup_gtk.h"
2072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/gtk_chrome_button.h"
2172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/gtk_chrome_shrinkable_hbox.h"
22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/gtk/gtk_theme_service.h"
2372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/gtk_util.h"
2472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/hover_controller_gtk.h"
2572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/menu_gtk.h"
2672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/view_id_util.h"
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension.h"
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension_action.h"
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension_resource.h"
30dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents.h"
31dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/common/notification_details.h"
32dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/common/notification_service.h"
33dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/common/notification_source.h"
34dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/common/notification_type.h"
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/app_resources.h"
363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "grit/theme_resources.h"
3772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/canvas_skia_paint.h"
3872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/gtk_util.h"
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// The width of the browser action buttons.
433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst int kButtonWidth = 27;
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// The padding between browser action buttons.
463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst int kButtonPadding = 4;
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The padding to the right of the browser action buttons (between the buttons
493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// and chevron if they are both showing).
503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst int kButtonChevronPadding = 2;
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The padding to the left, top and bottom of the browser actions toolbar
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// separator.
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kSeparatorPadding = 2;
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Width of the invisible gripper for resizing the toolbar.
573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst int kResizeGripperWidth = 4;
583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char* kDragTarget = "application/x-chrome-browseraction";
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochGtkTargetEntry GetDragTargetEntry() {
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static std::string drag_target_string(kDragTarget);
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GtkTargetEntry drag_target;
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  drag_target.target = const_cast<char*>(drag_target_string.c_str());
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  drag_target.flags = GTK_TARGET_SAME_APP;
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  drag_target.info = 0;
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return drag_target;
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The minimum width in pixels of the button hbox if |icon_count| icons are
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// showing.
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgint WidthForIconCount(gint icon_count) {
733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return std::max((kButtonWidth + kButtonPadding) * icon_count - kButtonPadding,
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  0);
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenusing ui::SimpleMenuModel;
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass BrowserActionButton : public NotificationObserver,
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            public ImageLoadingTracker::Observer,
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            public ExtensionContextMenuModel::PopupDelegate,
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            public MenuGtk::Delegate {
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BrowserActionButton(BrowserActionsToolbarGtk* toolbar,
87513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                      const Extension* extension,
88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                      GtkThemeService* theme_provider)
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      : toolbar_(toolbar),
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        extension_(extension),
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        image_(NULL),
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        tracker_(this),
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        tab_specific_icon_(NULL),
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        default_icon_(NULL) {
953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    button_.reset(new CustomDrawButton(
963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        theme_provider,
973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        IDR_BROWSER_ACTION,
983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        IDR_BROWSER_ACTION_P,
993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        IDR_BROWSER_ACTION_H,
1003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        0,
1013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        NULL));
1023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    alignment_.Own(gtk_alignment_new(0, 0, 1, 1));
1033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    gtk_container_add(GTK_CONTAINER(alignment_.get()), button());
1043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    gtk_widget_show(button());
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(extension_->browser_action());
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UpdateState();
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // The Browser Action API does not allow the default icon path to be
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // changed at runtime, so we can load this now and cache it.
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string path = extension_->browser_action()->default_icon_path();
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!path.empty()) {
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tracker_.LoadImage(extension_, extension_->GetResource(path),
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         gfx::Size(Extension::kBrowserActionIconMaxSize,
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   Extension::kBrowserActionIconMaxSize),
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         ImageLoadingTracker::DONT_CACHE);
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    signals_.Connect(button(), "button-press-event",
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     G_CALLBACK(OnButtonPress), this);
1223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    signals_.Connect(button(), "clicked",
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     G_CALLBACK(OnClicked), this);
1243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    signals_.Connect(button(), "drag-begin",
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     G_CALLBACK(&OnDragBegin), this);
1263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    signals_.ConnectAfter(widget(), "expose-event",
1273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                          G_CALLBACK(OnExposeEvent), this);
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    registrar_.Add(this, NotificationType::EXTENSION_BROWSER_ACTION_UPDATED,
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   Source<ExtensionAction>(extension->browser_action()));
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ~BrowserActionButton() {
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (tab_specific_icon_)
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      g_object_unref(tab_specific_icon_);
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (default_icon_)
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      g_object_unref(default_icon_);
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    alignment_.Destroy();
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  GtkWidget* button() { return button_->widget(); }
1443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  GtkWidget* widget() { return alignment_.get(); }
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
147513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const Extension* extension() { return extension_; }
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // NotificationObserver implementation.
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void Observe(NotificationType type,
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               const NotificationSource& source,
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               const NotificationDetails& details) {
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (type == NotificationType::EXTENSION_BROWSER_ACTION_UPDATED)
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      UpdateState();
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED();
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // ImageLoadingTracker::Observer implementation.
160ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void OnImageLoaded(SkBitmap* image, const ExtensionResource& resource,
161ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                     int index) {
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (image) {
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      default_skbitmap_ = *image;
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      default_icon_ = gfx::GdkPixbufFromSkBitmap(image);
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UpdateState();
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Updates the button based on the latest state from the associated
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // browser action.
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void UpdateState() {
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int tab_id = toolbar_->GetCurrentTabId();
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (tab_id < 0)
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string tooltip = extension_->browser_action()->GetTitle(tab_id);
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (tooltip.empty())
1783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      gtk_widget_set_has_tooltip(button(), FALSE);
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
1803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      gtk_widget_set_tooltip_text(button(), tooltip.c_str());
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SkBitmap image = extension_->browser_action()->GetIcon(tab_id);
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!image.isNull()) {
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GdkPixbuf* previous_gdk_icon = tab_specific_icon_;
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tab_specific_icon_ = gfx::GdkPixbufFromSkBitmap(&image);
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SetImage(tab_specific_icon_);
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (previous_gdk_icon)
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        g_object_unref(previous_gdk_icon);
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (default_icon_) {
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SetImage(default_icon_);
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    gtk_widget_queue_draw(button());
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkBitmap GetIcon() {
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SkBitmap& image = extension_->browser_action()->GetIcon(
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        toolbar_->GetCurrentTabId());
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!image.isNull()) {
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return image;
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return default_skbitmap_;
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MenuGtk* GetContextMenu() {
20672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (!extension_->ShowConfigureContextMenus())
20772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return NULL;
20872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    context_menu_model_ =
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        new ExtensionContextMenuModel(extension_, toolbar_->browser(), this);
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    context_menu_.reset(
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        new MenuGtk(this, context_menu_model_.get()));
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return context_menu_.get();
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // MenuGtk::Delegate implementation.
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void StoppedShowing() {
2193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    button_->UnsetPaintOverride();
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If the context menu was showing for the overflow menu, re-assert the
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // grab that was shadowed.
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (toolbar_->overflow_menu_.get())
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      gtk_util::GrabAllInput(toolbar_->overflow_menu_->widget());
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void CommandWillBeExecuted() {
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If the context menu was showing for the overflow menu, and a command
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // is executed, then stop showing the overflow menu.
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (toolbar_->overflow_menu_.get())
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      toolbar_->overflow_menu_->Cancel();
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Returns true to prevent further processing of the event that caused us to
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // show the popup, or false to continue processing.
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool ShowPopup(bool devtools) {
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ExtensionAction* browser_action = extension_->browser_action();
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int tab_id = toolbar_->GetCurrentTabId();
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (tab_id < 0) {
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED() << "No current tab.";
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (browser_action->HasPopup(tab_id)) {
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ExtensionPopupGtk::Show(
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          browser_action->GetPopupUrl(tab_id), toolbar_->browser(),
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          widget(), devtools);
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // ExtensionContextMenuModel::PopupDelegate implementation.
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void InspectPopup(ExtensionAction* action) {
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ShowPopup(true);
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void SetImage(GdkPixbuf* image) {
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!image_) {
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      image_ = gtk_image_new_from_pixbuf(image);
2633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      gtk_button_set_image(GTK_BUTTON(button()), image_);
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      gtk_image_set_from_pixbuf(GTK_IMAGE(image_), image);
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static gboolean OnButtonPress(GtkWidget* widget,
27072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                GdkEventButton* event,
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                BrowserActionButton* action) {
27272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (event->button != 3)
27372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return FALSE;
27472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
27572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    MenuGtk* menu = action->GetContextMenu();
27672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (!menu)
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return FALSE;
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    action->button_->SetPaintOverride(GTK_STATE_ACTIVE);
28072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    menu->PopupForWidget(widget, event->button, event->time);
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return TRUE;
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static void OnClicked(GtkWidget* widget, BrowserActionButton* action) {
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (action->ShowPopup(false))
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
28972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    ExtensionService* service =
29072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        action->toolbar_->browser()->profile()->GetExtensionService();
29172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    service->browser_event_router()->BrowserActionExecuted(
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        action->toolbar_->browser()->profile(), action->extension_->id(),
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        action->toolbar_->browser());
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static gboolean OnExposeEvent(GtkWidget* widget,
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                GdkEventExpose* event,
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                BrowserActionButton* button) {
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int tab_id = button->toolbar_->GetCurrentTabId();
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (tab_id < 0)
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return FALSE;
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ExtensionAction* action = button->extension_->browser_action();
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (action->GetBadgeText(tab_id).empty())
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return FALSE;
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gfx::CanvasSkiaPaint canvas(event, false);
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gfx::Rect bounding_rect(widget->allocation);
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    action->PaintBadge(&canvas, bounding_rect, tab_id);
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return FALSE;
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static void OnDragBegin(GtkWidget* widget,
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          GdkDragContext* drag_context,
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          BrowserActionButton* button) {
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Simply pass along the notification to the toolbar. The point of this
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // function is to tell the toolbar which BrowserActionButton initiated the
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // drag.
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    button->toolbar_->DragStarted(button, drag_context);
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The toolbar containing this button.
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BrowserActionsToolbarGtk* toolbar_;
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The extension that contains this browser action.
326513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const Extension* extension_;
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // The button for this browser action.
3293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  scoped_ptr<CustomDrawButton> button_;
3303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // The top level widget (parent of |button_|).
3323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  OwnedWidgetGtk alignment_;
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The one image subwidget in |button_|. We keep this out so we don't alter
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the widget hierarchy while changing the button image because changing the
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // GTK widget hierarchy invalidates all tooltips and several popular
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // extensions change browser action icon in a loop.
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GtkWidget* image_;
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Loads the button's icons for us on the file thread.
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ImageLoadingTracker tracker_;
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If we are displaying a tab-specific icon, it will be here.
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GdkPixbuf* tab_specific_icon_;
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If the browser action has a default icon, it will be here.
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GdkPixbuf* default_icon_;
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Same as |default_icon_|, but stored as SkBitmap.
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkBitmap default_skbitmap_;
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
35272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  ui::GtkSignalRegistrar signals_;
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NotificationRegistrar registrar_;
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The context menu view and model for this extension action.
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<MenuGtk> context_menu_;
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<ExtensionContextMenuModel> context_menu_model_;
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  friend class BrowserActionsToolbarGtk;
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// BrowserActionsToolbarGtk ----------------------------------------------------
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBrowserActionsToolbarGtk::BrowserActionsToolbarGtk(Browser* browser)
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : browser_(browser),
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      profile_(browser->profile()),
367ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      theme_service_(GtkThemeService::GetFrom(browser->profile())),
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      model_(NULL),
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      hbox_(gtk_hbox_new(FALSE, 0)),
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      button_hbox_(gtk_chrome_shrinkable_hbox_new(TRUE, FALSE, kButtonPadding)),
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      drag_button_(NULL),
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      drop_index_(-1),
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      resize_animation_(this),
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      desired_width_(0),
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      start_width_(0),
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      method_factory_(this) {
37721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  ExtensionService* extension_service = profile_->GetExtensionService();
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The |extension_service| can be NULL in Incognito.
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!extension_service)
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
38272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  overflow_button_.reset(new CustomDrawButton(
383ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      theme_service_,
3843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      IDR_BROWSER_ACTIONS_OVERFLOW,
3853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      IDR_BROWSER_ACTIONS_OVERFLOW_P,
3863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      IDR_BROWSER_ACTIONS_OVERFLOW_H,
3873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      0,
3883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE)));
3893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GtkWidget* gripper = gtk_button_new();
3913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  gtk_widget_set_size_request(gripper, kResizeGripperWidth, -1);
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GTK_WIDGET_UNSET_FLAGS(gripper, GTK_CAN_FOCUS);
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_widget_add_events(gripper, GDK_POINTER_MOTION_MASK);
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  signals_.Connect(gripper, "motion-notify-event",
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnGripperMotionNotifyThunk), this);
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  signals_.Connect(gripper, "expose-event",
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnGripperExposeThunk), this);
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  signals_.Connect(gripper, "enter-notify-event",
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnGripperEnterNotifyThunk), this);
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  signals_.Connect(gripper, "leave-notify-event",
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnGripperLeaveNotifyThunk), this);
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  signals_.Connect(gripper, "button-release-event",
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnGripperButtonReleaseThunk), this);
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  signals_.Connect(gripper, "button-press-event",
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnGripperButtonPressThunk), this);
4063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  signals_.Connect(chevron(), "button-press-event",
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnOverflowButtonPressThunk), this);
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // |overflow_alignment| adds padding to the right of the browser action
4103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // buttons, but only appears when the overflow menu is showing.
4113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  overflow_alignment_ = gtk_alignment_new(0, 0, 1, 1);
4123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  gtk_container_add(GTK_CONTAINER(overflow_alignment_), chevron());
4133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
4143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // |overflow_area_| holds the overflow chevron and the separator, which
4153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // is only shown in GTK+ theme mode.
4163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  overflow_area_ = gtk_hbox_new(FALSE, 0);
4173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  gtk_box_pack_start(GTK_BOX(overflow_area_), overflow_alignment_,
4183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                     FALSE, FALSE, 0);
4193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
4203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  separator_ = gtk_vseparator_new();
4213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  gtk_box_pack_start(GTK_BOX(overflow_area_), separator_,
4223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                     FALSE, FALSE, 0);
4233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  gtk_widget_set_no_show_all(separator_, TRUE);
4243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
4253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  gtk_widget_show_all(overflow_area_);
4263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  gtk_widget_set_no_show_all(overflow_area_, TRUE);
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_box_pack_start(GTK_BOX(hbox_.get()), gripper, FALSE, FALSE, 0);
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_box_pack_start(GTK_BOX(hbox_.get()), button_hbox_.get(), TRUE, TRUE, 0);
4303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  gtk_box_pack_start(GTK_BOX(hbox_.get()), overflow_area_, FALSE, FALSE, 0);
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  model_ = extension_service->toolbar_model();
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  model_->AddObserver(this);
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SetupDrags();
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (model_->extensions_initialized()) {
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CreateAllButtons();
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SetContainerWidth();
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We want to connect to "set-focus" on the toplevel window; we have to wait
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // until we are added to a toplevel window to do so.
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  signals_.Connect(widget(), "hierarchy-changed",
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnHierarchyChangedThunk), this);
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ViewIDUtil::SetID(button_hbox_.get(), VIEW_ID_BROWSER_ACTION_TOOLBAR);
4473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
4483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  registrar_.Add(this,
4493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                 NotificationType::BROWSER_THEME_CHANGED,
4503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                 NotificationService::AllSources());
451ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  theme_service_->InitThemesFor(this);
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBrowserActionsToolbarGtk::~BrowserActionsToolbarGtk() {
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (model_)
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    model_->RemoveObserver(this);
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  button_hbox_.Destroy();
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  hbox_.Destroy();
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BrowserActionsToolbarGtk::GetCurrentTabId() {
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabContents* selected_tab = browser_->GetSelectedTabContents();
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!selected_tab)
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return -1;
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return selected_tab->controller().session_id().id();
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsToolbarGtk::Update() {
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (ExtensionButtonMap::iterator iter = extension_button_map_.begin();
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       iter != extension_button_map_.end(); ++iter) {
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    iter->second->UpdateState();
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BrowserActionsToolbarGtk::Observe(NotificationType type,
4773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                       const NotificationSource& source,
4783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                       const NotificationDetails& details) {
4793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK(NotificationType::BROWSER_THEME_CHANGED == type);
480ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (theme_service_->UseGtkTheme())
4813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    gtk_widget_show(separator_);
4823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  else
4833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    gtk_widget_hide(separator_);
4843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
4853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsToolbarGtk::SetupDrags() {
487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GtkTargetEntry drag_target = GetDragTargetEntry();
488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_drag_dest_set(button_hbox_.get(), GTK_DEST_DEFAULT_DROP, &drag_target, 1,
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    GDK_ACTION_MOVE);
490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  signals_.Connect(button_hbox_.get(), "drag-motion",
492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnDragMotionThunk), this);
493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsToolbarGtk::CreateAllButtons() {
496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  extension_button_map_.clear();
497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int i = 0;
499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (ExtensionList::iterator iter = model_->begin();
500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       iter != model_->end(); ++iter) {
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CreateButtonForExtension(*iter, i++);
502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsToolbarGtk::SetContainerWidth() {
506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int showing_actions = model_->GetVisibleIconCount();
507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (showing_actions >= 0)
508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SetButtonHBoxWidth(WidthForIconCount(showing_actions));
509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
511513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid BrowserActionsToolbarGtk::CreateButtonForExtension(
512513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const Extension* extension, int index) {
513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ShouldDisplayBrowserAction(extension))
514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (profile_->IsOffTheRecord())
517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    index = model_->OriginalIndexToIncognito(index);
518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  RemoveButtonForExtension(extension);
520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  linked_ptr<BrowserActionButton> button(
521ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      new BrowserActionButton(this, extension, theme_service_));
522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_chrome_shrinkable_hbox_pack_start(
523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GTK_CHROME_SHRINKABLE_HBOX(button_hbox_.get()), button->widget(), 0);
524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_box_reorder_child(GTK_BOX(button_hbox_.get()), button->widget(), index);
525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  extension_button_map_[extension->id()] = button;
526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GtkTargetEntry drag_target = GetDragTargetEntry();
5283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  gtk_drag_source_set(button->button(), GDK_BUTTON1_MASK, &drag_target, 1,
529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      GDK_ACTION_MOVE);
530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We ignore whether the drag was a "success" or "failure" in Gtk's opinion.
5313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  signals_.Connect(button->button(), "drag-end",
532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(&OnDragEndThunk), this);
5333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  signals_.Connect(button->button(), "drag-failed",
534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(&OnDragFailedThunk), this);
535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Any time a browser action button is shown or hidden we have to update
537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the chevron state.
538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  signals_.Connect(button->widget(), "show",
539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(&OnButtonShowOrHideThunk), this);
540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  signals_.Connect(button->widget(), "hide",
541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(&OnButtonShowOrHideThunk), this);
542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_widget_show(button->widget());
544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UpdateVisibility();
546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
548c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochGtkWidget* BrowserActionsToolbarGtk::GetBrowserActionWidget(
549513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const Extension* extension) {
550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExtensionButtonMap::iterator it = extension_button_map_.find(
551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      extension->id());
552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (it == extension_button_map_.end())
553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NULL;
554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return it->second.get()->widget();
556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
558513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid BrowserActionsToolbarGtk::RemoveButtonForExtension(
559513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const Extension* extension) {
560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (extension_button_map_.erase(extension->id()))
561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UpdateVisibility();
562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UpdateChevronVisibility();
563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsToolbarGtk::UpdateVisibility() {
566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (button_count() == 0)
567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gtk_widget_hide(widget());
568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  else
569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gtk_widget_show(widget());
570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BrowserActionsToolbarGtk::ShouldDisplayBrowserAction(
573513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const Extension* extension) {
574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Only display incognito-enabled extensions while in incognito mode.
575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return (!profile_->IsOffTheRecord() ||
576ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          profile_->GetExtensionService()->IsIncognitoEnabled(extension->id()));
577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsToolbarGtk::HidePopup() {
580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExtensionPopupGtk* popup = ExtensionPopupGtk::get_current_extension_popup();
581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (popup)
582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    popup->DestroyPopup();
583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsToolbarGtk::AnimateToShowNIcons(int count) {
586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  desired_width_ = WidthForIconCount(count);
587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  start_width_ = button_hbox_->allocation.width;
588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  resize_animation_.Reset();
589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  resize_animation_.Show();
590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
592513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid BrowserActionsToolbarGtk::BrowserActionAdded(const Extension* extension,
593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                  int index) {
594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  overflow_menu_.reset();
595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CreateButtonForExtension(extension, index);
597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If we are still initializing the container, don't bother animating.
599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!model_->extensions_initialized())
600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Animate the addition if we are showing all browser action buttons.
6033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!GTK_WIDGET_VISIBLE(overflow_area_)) {
604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    AnimateToShowNIcons(button_count());
605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    model_->SetVisibleIconCount(button_count());
606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
609513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid BrowserActionsToolbarGtk::BrowserActionRemoved(
610513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const Extension* extension) {
611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  overflow_menu_.reset();
612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (drag_button_ != NULL) {
614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Break the current drag.
615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gtk_grab_remove(button_hbox_.get());
616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  RemoveButtonForExtension(extension);
619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
6203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!GTK_WIDGET_VISIBLE(overflow_area_)) {
621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    AnimateToShowNIcons(button_count());
622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    model_->SetVisibleIconCount(button_count());
623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
626513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid BrowserActionsToolbarGtk::BrowserActionMoved(const Extension* extension,
627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                  int index) {
628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We initiated this move action, and have already moved the button.
629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (drag_button_ != NULL)
630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GtkWidget* button_widget = GetBrowserActionWidget(extension);
633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!button_widget) {
634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (ShouldDisplayBrowserAction(extension))
635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED();
636c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (profile_->IsOffTheRecord())
640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    index = model_->OriginalIndexToIncognito(index);
641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_box_reorder_child(GTK_BOX(button_hbox_.get()), button_widget, index);
643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsToolbarGtk::ModelLoaded() {
646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SetContainerWidth();
647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
648c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
6493f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid BrowserActionsToolbarGtk::AnimationProgressed(
6503f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    const ui::Animation* animation) {
651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int width = start_width_ + (desired_width_ - start_width_) *
652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      animation->GetCurrentValue();
653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_widget_set_size_request(button_hbox_.get(), width, -1);
654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (width == desired_width_)
656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    resize_animation_.Reset();
657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
658c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
6593f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid BrowserActionsToolbarGtk::AnimationEnded(const ui::Animation* animation) {
660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_widget_set_size_request(button_hbox_.get(), desired_width_, -1);
661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UpdateChevronVisibility();
662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
66421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool BrowserActionsToolbarGtk::IsCommandIdChecked(int command_id) const {
66521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return false;
66621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
66721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
66821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool BrowserActionsToolbarGtk::IsCommandIdEnabled(int command_id) const {
66921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return true;
67021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
67121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
67221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool BrowserActionsToolbarGtk::GetAcceleratorForCommandId(
67321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    int command_id,
67472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    ui::Accelerator* accelerator) {
67521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return false;
67621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
67721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
678c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsToolbarGtk::ExecuteCommand(int command_id) {
679513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const Extension* extension = model_->GetExtensionByIndex(command_id);
680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExtensionAction* browser_action = extension->browser_action();
681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int tab_id = GetCurrentTabId();
683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (tab_id < 0) {
684c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED() << "No current tab.";
685c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
686c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
687c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
688c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (browser_action->HasPopup(tab_id)) {
689c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ExtensionPopupGtk::Show(
690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        browser_action->GetPopupUrl(tab_id), browser(),
6913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        chevron(),
692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        false);
693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
69472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    ExtensionService* service = browser()->profile()->GetExtensionService();
69572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    service->browser_event_router()->BrowserActionExecuted(
696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        browser()->profile(), extension->id(), browser());
697c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsToolbarGtk::StoppedShowing() {
7013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  overflow_button_->UnsetPaintOverride();
702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
704731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool BrowserActionsToolbarGtk::AlwaysShowIconForCmd(int command_id) const {
705731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return true;
706731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
707731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsToolbarGtk::DragStarted(BrowserActionButton* button,
709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           GdkDragContext* drag_context) {
710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // No representation of the widget following the cursor.
711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 1, 1);
712c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_drag_set_icon_pixbuf(drag_context, pixbuf, 0, 0);
713c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_object_unref(pixbuf);
714c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
715c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!drag_button_);
716c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  drag_button_ = button;
717c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
718c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsToolbarGtk::SetButtonHBoxWidth(int new_width) {
720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gint max_width = WidthForIconCount(button_count());
721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  new_width = std::min(max_width, new_width);
722c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  new_width = std::max(new_width, 0);
723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_widget_set_size_request(button_hbox_.get(), new_width, -1);
724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsToolbarGtk::UpdateChevronVisibility() {
727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int showing_icon_count =
728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      gtk_chrome_shrinkable_hbox_get_visible_child_count(
729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          GTK_CHROME_SHRINKABLE_HBOX(button_hbox_.get()));
7303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (showing_icon_count == 0) {
7313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    gtk_alignment_set_padding(GTK_ALIGNMENT(overflow_alignment_), 0, 0, 0, 0);
7323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } else {
7333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    gtk_alignment_set_padding(GTK_ALIGNMENT(overflow_alignment_), 0, 0,
7343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                              kButtonChevronPadding, 0);
7353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
737c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (button_count() > showing_icon_count) {
7383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!GTK_WIDGET_VISIBLE(overflow_area_)) {
739c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (drag_button_) {
740c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // During drags, when the overflow chevron shows for the first time,
741c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // take that much space away from |button_hbox_| to make the drag look
742c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // smoother.
743c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        GtkRequisition req;
7443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        gtk_widget_size_request(chevron(), &req);
745c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        gint overflow_width = req.width;
746c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        gtk_widget_size_request(button_hbox_.get(), &req);
747c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        gint button_hbox_width = req.width;
748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        button_hbox_width = std::max(button_hbox_width - overflow_width, 0);
749c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        gtk_widget_set_size_request(button_hbox_.get(), button_hbox_width, -1);
750c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
751c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      gtk_widget_show(overflow_area_);
753c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
754c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
7553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    gtk_widget_hide(overflow_area_);
756c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
758c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
759c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean BrowserActionsToolbarGtk::OnDragMotion(GtkWidget* widget,
760c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                GdkDragContext* drag_context,
761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                gint x, gint y, guint time) {
762c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Only handle drags we initiated.
763c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!drag_button_)
764c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return FALSE;
765c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
766c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (base::i18n::IsRTL())
767c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    x = widget->allocation.width - x;
7683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  drop_index_ = x < kButtonWidth ? 0 : x / (kButtonWidth + kButtonPadding);
769c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
770c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We will go ahead and reorder the child in order to provide visual feedback
771c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // to the user. We don't inform the model that it has moved until the drag
772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // ends.
773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_box_reorder_child(GTK_BOX(button_hbox_.get()), drag_button_->widget(),
774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        drop_index_);
775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gdk_drag_status(drag_context, GDK_ACTION_MOVE, time);
777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return TRUE;
778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
779c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
780c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsToolbarGtk::OnDragEnd(GtkWidget* button,
781c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         GdkDragContext* drag_context) {
782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (drop_index_ != -1) {
783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (profile_->IsOffTheRecord())
784c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      drop_index_ = model_->IncognitoIndexToOriginal(drop_index_);
785c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
786c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    model_->MoveBrowserAction(drag_button_->extension(), drop_index_);
787c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
788c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
789c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  drag_button_ = NULL;
790c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  drop_index_ = -1;
791c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
792c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
793c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean BrowserActionsToolbarGtk::OnDragFailed(GtkWidget* widget,
794c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                GdkDragContext* drag_context,
795c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                GtkDragResult result) {
796c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We connect to this signal and return TRUE so that the default failure
797c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // animation (wherein the drag widget floats back to the start of the drag)
798c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // does not show, and the drag-end signal is emitted immediately instead of
799c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // several seconds later.
800c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return TRUE;
801c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
802c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsToolbarGtk::OnHierarchyChanged(
804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GtkWidget* widget, GtkWidget* previous_toplevel) {
805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!GTK_WIDGET_TOPLEVEL(toplevel))
807c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
809c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  signals_.Connect(toplevel, "set-focus", G_CALLBACK(OnSetFocusThunk), this);
810c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsToolbarGtk::OnSetFocus(GtkWidget* widget,
813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          GtkWidget* focus_widget) {
814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExtensionPopupGtk* popup = ExtensionPopupGtk::get_current_extension_popup();
815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The focus of the parent window has changed. Close the popup. Delay the hide
816c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // because it will destroy the RenderViewHost, which may still be on the
817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // call stack.
818c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!popup || popup->being_inspected())
819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MessageLoop::current()->PostTask(FROM_HERE,
821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      method_factory_.NewRunnableMethod(&BrowserActionsToolbarGtk::HidePopup));
822c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
823c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
824c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean BrowserActionsToolbarGtk::OnGripperMotionNotify(
825c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GtkWidget* widget, GdkEventMotion* event) {
826c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!(event->state & GDK_BUTTON1_MASK))
827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return FALSE;
828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Calculate how much the user dragged the gripper and subtract that off the
830c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // button container's width.
831c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int distance_dragged = base::i18n::IsRTL() ?
832c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      -event->x :
833c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      event->x - widget->allocation.width;
834c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gint new_width = button_hbox_->allocation.width - distance_dragged;
835c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SetButtonHBoxWidth(new_width);
836c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
837c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return FALSE;
838c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
839c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
840c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean BrowserActionsToolbarGtk::OnGripperExpose(GtkWidget* gripper,
841c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                   GdkEventExpose* expose) {
842c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return TRUE;
843c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
844c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
845c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// These three signal handlers (EnterNotify, LeaveNotify, and ButtonRelease)
846c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// are used to give the gripper the resize cursor. Since it doesn't have its
847c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// own window, we have to set the cursor whenever the pointer moves into the
848c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// button or leaves the button, and be sure to leave it on when the user is
849c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// dragging.
850c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean BrowserActionsToolbarGtk::OnGripperEnterNotify(
851c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GtkWidget* gripper, GdkEventCrossing* event) {
852c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gdk_window_set_cursor(gripper->window,
853201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                        gfx::GetCursor(GDK_SB_H_DOUBLE_ARROW));
854c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return FALSE;
855c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
856c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
857c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean BrowserActionsToolbarGtk::OnGripperLeaveNotify(
858c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GtkWidget* gripper, GdkEventCrossing* event) {
8593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!(event->state & GDK_BUTTON1_MASK))
860c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gdk_window_set_cursor(gripper->window, NULL);
861c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return FALSE;
862c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
863c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
864c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean BrowserActionsToolbarGtk::OnGripperButtonRelease(
865c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GtkWidget* gripper, GdkEventButton* event) {
866c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Rect gripper_rect(0, 0,
867c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         gripper->allocation.width, gripper->allocation.height);
868c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Point release_point(event->x, event->y);
8693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!gripper_rect.Contains(release_point))
870c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gdk_window_set_cursor(gripper->window, NULL);
871c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
872c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // After the user resizes the toolbar, we want to smartly resize it to be
873c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the perfect size to fit the buttons.
874c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int visible_icon_count =
875c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      gtk_chrome_shrinkable_hbox_get_visible_child_count(
876c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          GTK_CHROME_SHRINKABLE_HBOX(button_hbox_.get()));
877c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AnimateToShowNIcons(visible_icon_count);
878c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  model_->SetVisibleIconCount(visible_icon_count);
879c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
880c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return FALSE;
881c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
882c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
883c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean BrowserActionsToolbarGtk::OnGripperButtonPress(
884c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GtkWidget* gripper, GdkEventButton* event) {
885c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  resize_animation_.Reset();
886c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
887c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return FALSE;
888c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
889c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
890c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean BrowserActionsToolbarGtk::OnOverflowButtonPress(
891c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GtkWidget* overflow, GdkEventButton* event) {
892c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  overflow_menu_model_.reset(new SimpleMenuModel(this));
893c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
894c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int visible_icon_count =
895c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      gtk_chrome_shrinkable_hbox_get_visible_child_count(
896c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          GTK_CHROME_SHRINKABLE_HBOX(button_hbox_.get()));
897c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = visible_icon_count; i < button_count(); ++i) {
898c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int model_index = i;
899c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (profile_->IsOffTheRecord())
900c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      model_index = model_->IncognitoIndexToOriginal(i);
901c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
902513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const Extension* extension = model_->GetExtensionByIndex(model_index);
903c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BrowserActionButton* button = extension_button_map_[extension->id()].get();
904c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
905c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    overflow_menu_model_->AddItem(model_index, UTF8ToUTF16(extension->name()));
906c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    overflow_menu_model_->SetIcon(overflow_menu_model_->GetItemCount() - 1,
907c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  button->GetIcon());
908c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
909c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // TODO(estade): set the menu item's tooltip.
910c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
911c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
912c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  overflow_menu_.reset(new MenuGtk(this, overflow_menu_model_.get()));
913c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  signals_.Connect(overflow_menu_->widget(), "button-press-event",
914c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnOverflowMenuButtonPressThunk), this);
915c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
9163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  overflow_button_->SetPaintOverride(GTK_STATE_ACTIVE);
9173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  overflow_menu_->PopupAsFromKeyEvent(chevron());
918c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
919c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return FALSE;
920c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
921c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
922c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean BrowserActionsToolbarGtk::OnOverflowMenuButtonPress(
923c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GtkWidget* overflow, GdkEventButton* event) {
924c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (event->button != 3)
925c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return FALSE;
926c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
927c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GtkWidget* menu_item = GTK_MENU_SHELL(overflow)->active_menu_item;
928c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!menu_item)
929c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return FALSE;
930c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
931c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int item_index = g_list_index(GTK_MENU_SHELL(overflow)->children, menu_item);
932c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (item_index == -1) {
933c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
934c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return FALSE;
935c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
936c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
937c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  item_index += gtk_chrome_shrinkable_hbox_get_visible_child_count(
938c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GTK_CHROME_SHRINKABLE_HBOX(button_hbox_.get()));
939c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (profile_->IsOffTheRecord())
940c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    item_index = model_->IncognitoIndexToOriginal(item_index);
941c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
942513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const Extension* extension = model_->GetExtensionByIndex(item_index);
943c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExtensionButtonMap::iterator it = extension_button_map_.find(
944c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      extension->id());
945c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (it == extension_button_map_.end()) {
946c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
947c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return FALSE;
948c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
949c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
95072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  MenuGtk* menu = it->second.get()->GetContextMenu();
95172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!menu)
95272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return FALSE;
95372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
95472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  menu->PopupAsContext(gfx::Point(event->x_root, event->y_root),
95572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                       event->time);
956c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return TRUE;
957c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
958c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
959c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserActionsToolbarGtk::OnButtonShowOrHide(GtkWidget* sender) {
960c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!resize_animation_.is_animating())
961c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UpdateChevronVisibility();
962c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
963