15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/browser_actions_toolbar_gtk.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <gtk/gtk.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/rtl.h"
149ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/api/commands/command_service.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_action.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_action_icon_factory.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_action_manager.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_context_menu_model.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/extension_system.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sessions/session_tab_helper.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/browser_window_gtk.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/custom_button.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/extensions/extension_popup_gtk.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/gtk_chrome_button.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/gtk_chrome_shrinkable_hbox.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/gtk_theme_service.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/gtk_util.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/hover_controller_gtk.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/menu_gtk.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/view_id_util.h"
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension_manifest_constants.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_details.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_source.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/theme_resources.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/ui_resources.h"
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/accelerators/platform_accelerator_gtk.h"
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/gtk/gtk_compat.h"
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas_skia_paint.h"
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/gtk_util.h"
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image.h"
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image_skia_operations.h"
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using extensions::Extension;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using extensions::ExtensionActionManager;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The width of the browser action buttons.
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kButtonWidth = 27;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The padding between browser action buttons.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kButtonPadding = 4;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The padding to the right of the browser action buttons (between the buttons
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and chevron if they are both showing).
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kButtonChevronPadding = 2;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The padding to the left, top and bottom of the browser actions toolbar
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// separator.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kSeparatorPadding = 2;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Width of the invisible gripper for resizing the toolbar.
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kResizeGripperWidth = 4;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kDragTarget[] = "application/x-chrome-browseraction";
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GtkTargetEntry GetDragTargetEntry() {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkTargetEntry drag_target;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  drag_target.target = const_cast<char*>(kDragTarget);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  drag_target.flags = GTK_TARGET_SAME_APP;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  drag_target.info = 0;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return drag_target;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The minimum width in pixels of the button hbox if |icon_count| icons are
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// showing.
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gint WidthForIconCount(gint icon_count) {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::max((kButtonWidth + kButtonPadding) * icon_count - kButtonPadding,
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  0);
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using ui::SimpleMenuModel;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class BrowserActionButton : public content::NotificationObserver,
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            public ExtensionActionIconFactory::Observer,
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            public ExtensionContextMenuModel::PopupDelegate,
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            public MenuGtk::Delegate {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserActionButton(BrowserActionsToolbarGtk* toolbar,
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      const Extension* extension,
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      GtkThemeService* theme_provider)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : toolbar_(toolbar),
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        extension_(extension),
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        image_(NULL),
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        icon_factory_(toolbar->browser()->profile(), extension,
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                      browser_action(), this),
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        accel_group_(NULL) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    button_.reset(new CustomDrawButton(
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        theme_provider,
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDR_BROWSER_ACTION,
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDR_BROWSER_ACTION_P,
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDR_BROWSER_ACTION_H,
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        0,
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NULL));
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_widget_set_size_request(button(), kButtonWidth, kButtonWidth);
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    alignment_.Own(gtk_alignment_new(0, 0, 1, 1));
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_container_add(GTK_CONTAINER(alignment_.get()), button());
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_widget_show(button());
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(browser_action());
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateState();
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    signals_.Connect(button(), "button-press-event",
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     G_CALLBACK(OnButtonPress), this);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    signals_.Connect(button(), "clicked",
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     G_CALLBACK(OnClicked), this);
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    signals_.Connect(button(), "drag-begin",
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     G_CALLBACK(OnDragBegin), this);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    signals_.ConnectAfter(widget(), "expose-event",
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     G_CALLBACK(OnExposeEvent), this);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (toolbar_->browser()->window()) {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If the window exists already, then the browser action button has been
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // recreated after the window was created, for example when the extension
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // is reloaded.
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ConnectBrowserActionPopupAccelerator();
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Window doesn't exist yet, wait for it.
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      signals_.Connect(toolbar->widget(), "realize",
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       G_CALLBACK(OnRealize), this);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    registrar_.Add(
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this, chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED,
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::Source<ExtensionAction>(browser_action()));
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    registrar_.Add(
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::Source<Profile>(
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            toolbar->browser()->profile()->GetOriginalProfile()));
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    registrar_.Add(
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this, chrome::NOTIFICATION_EXTENSION_COMMAND_ADDED,
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::Source<Profile>(
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        toolbar->browser()->profile()->GetOriginalProfile()));
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    registrar_.Add(
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this, chrome::NOTIFICATION_EXTENSION_COMMAND_REMOVED,
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::Source<Profile>(
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        toolbar->browser()->profile()->GetOriginalProfile()));
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~BrowserActionButton() {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DisconnectBrowserActionPopupAccelerator();
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    alignment_.Destroy();
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkWidget* button() { return button_->widget(); }
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkWidget* widget() { return alignment_.get(); }
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Extension* extension() { return extension_; }
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NotificationObserver implementation.
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void Observe(int type,
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       const content::NotificationSource& source,
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       const content::NotificationDetails& details) OVERRIDE {
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (type) {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     case chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED:
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UpdateState();
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     case chrome::NOTIFICATION_EXTENSION_UNLOADED:
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     case chrome::NOTIFICATION_WINDOW_CLOSED:
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DisconnectBrowserActionPopupAccelerator();
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     case chrome::NOTIFICATION_EXTENSION_COMMAND_ADDED:
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     case chrome::NOTIFICATION_EXTENSION_COMMAND_REMOVED: {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::pair<const std::string, const std::string>* payload =
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          content::Details<std::pair<const std::string, const std::string> >(
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              details).ptr();
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (extension_->id() == payload->first &&
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          payload->second ==
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              extension_manifest_values::kBrowserActionCommandEvent) {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (type == chrome::NOTIFICATION_EXTENSION_COMMAND_ADDED)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ConnectBrowserActionPopupAccelerator();
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          DisconnectBrowserActionPopupAccelerator();
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     }
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     default:
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ExtensionActionIconFactory::Observer implementation.
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnIconUpdated() OVERRIDE {
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateState();
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Updates the button based on the latest state from the associated
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // browser action.
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void UpdateState() {
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int tab_id = toolbar_->GetCurrentTabId();
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (tab_id < 0)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string tooltip = browser_action()->GetTitle(tab_id);
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (tooltip.empty())
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gtk_widget_set_has_tooltip(button(), FALSE);
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gtk_widget_set_tooltip_text(button(), tooltip.c_str());
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    enabled_ = browser_action()->GetIsVisible(tab_id);
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!enabled_)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      button_->SetPaintOverride(GTK_STATE_INSENSITIVE);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      button_->UnsetPaintOverride();
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Image image = icon_factory_.GetIcon(tab_id);
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!image.IsEmpty()) {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (enabled_) {
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SetImage(image);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SetImage(gfx::Image(gfx::ImageSkiaOperations::CreateTransparentImage(
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            image.AsImageSkia(), .25)));
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_widget_queue_draw(button());
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Image GetIcon() {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return icon_factory_.GetIcon(toolbar_->GetCurrentTabId());
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MenuGtk* GetContextMenu() {
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!extension_->ShowConfigureContextMenus())
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return NULL;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    context_menu_model_ =
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new ExtensionContextMenuModel(extension_, toolbar_->browser(), this);
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    context_menu_.reset(
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new MenuGtk(this, context_menu_model_.get()));
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return context_menu_.get();
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Activate the browser action.
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Activate(GtkWidget* widget) {
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ExtensionToolbarModel* model = toolbar_->model();
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension = extension_;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Browser* browser = toolbar_->browser();
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GURL popup_url;
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (model->ExecuteBrowserAction(extension, browser, &popup_url)) {
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case ExtensionToolbarModel::ACTION_NONE:
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case ExtensionToolbarModel::ACTION_SHOW_POPUP:
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ExtensionPopupGtk::Show(popup_url, browser, widget,
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                ExtensionPopupGtk::SHOW);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // MenuGtk::Delegate implementation.
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void StoppedShowing() OVERRIDE {
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (enabled_)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      button_->UnsetPaintOverride();
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      button_->SetPaintOverride(GTK_STATE_INSENSITIVE);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the context menu was showing for the overflow menu, re-assert the
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // grab that was shadowed.
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (toolbar_->overflow_menu_.get())
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gtk_util::GrabAllInput(toolbar_->overflow_menu_->widget());
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void CommandWillBeExecuted() OVERRIDE {
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the context menu was showing for the overflow menu, and a command
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // is executed, then stop showing the overflow menu.
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (toolbar_->overflow_menu_.get())
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      toolbar_->overflow_menu_->Cancel();
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ExtensionContextMenuModel::PopupDelegate implementation.
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void InspectPopup(ExtensionAction* action) OVERRIDE {
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GURL popup_url = action->GetPopupUrl(toolbar_->GetCurrentTabId());
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ExtensionPopupGtk::Show(popup_url, toolbar_->browser(), widget(),
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            ExtensionPopupGtk::SHOW_AND_INSPECT);
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SetImage(const gfx::Image& image) {
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!image_) {
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      image_ = gtk_image_new_from_pixbuf(image.ToGdkPixbuf());
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gtk_button_set_image(GTK_BUTTON(button()), image_);
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gtk_image_set_from_pixbuf(GTK_IMAGE(image_), image.ToGdkPixbuf());
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static gboolean OnButtonPress(GtkWidget* widget,
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                GdkEventButton* event,
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                BrowserActionButton* button) {
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (event->button != 3)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return FALSE;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MenuGtk* menu = button->GetContextMenu();
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!menu)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return FALSE;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    button->button_->SetPaintOverride(GTK_STATE_ACTIVE);
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    menu->PopupForWidget(widget, event->button, event->time);
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TRUE;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void OnClicked(GtkWidget* widget, BrowserActionButton* button) {
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (button->enabled_)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      button->Activate(widget);
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static gboolean OnExposeEvent(GtkWidget* widget,
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                GdkEventExpose* event,
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                BrowserActionButton* button) {
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int tab_id = button->toolbar_->GetCurrentTabId();
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (tab_id < 0)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return FALSE;
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ExtensionAction* action = button->browser_action();
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (action->GetBadgeText(tab_id).empty())
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return FALSE;
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::CanvasSkiaPaint canvas(event, false);
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GtkAllocation allocation;
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_widget_get_allocation(widget, &allocation);
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    action->PaintBadge(&canvas, gfx::Rect(allocation), tab_id);
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void OnDragBegin(GtkWidget* widget,
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          GdkDragContext* drag_context,
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          BrowserActionButton* button) {
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Simply pass along the notification to the toolbar. The point of this
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // function is to tell the toolbar which BrowserActionButton initiated the
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // drag.
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    button->toolbar_->DragStarted(button, drag_context);
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The accelerator handler for when the shortcuts to open the popup is struck.
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static gboolean OnGtkAccelerator(GtkAccelGroup* accel_group,
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   GObject* acceleratable,
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   guint keyval,
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   GdkModifierType modifier,
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   BrowserActionButton* button) {
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Open the popup for this extension.
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GtkWidget* anchor = button->widget();
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The anchor might be in the overflow menu. Then we point to the chevron.
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!gtk_widget_get_visible(anchor))
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      anchor = button->toolbar_->chevron();
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    button->Activate(anchor);
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TRUE;
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The handler for when the browser action is realized. |user_data| contains a
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // pointer to the BrowserAction shown.
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void OnRealize(GtkWidget* widget, void* user_data) {
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserActionButton* button = static_cast<BrowserActionButton*>(user_data);
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    button->ConnectBrowserActionPopupAccelerator();
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Connect the accelerator for the browser action popup.
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ConnectBrowserActionPopupAccelerator() {
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    extensions::CommandService* command_service =
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        extensions::CommandService::Get(toolbar_->browser()->profile());
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    extensions::Command command;
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (command_service->GetBrowserActionCommand(extension_->id(),
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        extensions::CommandService::ACTIVE_ONLY,
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        &command,
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NULL)) {
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Found the browser action shortcut command, register it.
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      keybinding_ = command.accelerator();
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::NativeWindow window =
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          toolbar_->browser()->window()->GetNativeWindow();
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      accel_group_ = gtk_accel_group_new();
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gtk_window_add_accel_group(window, accel_group_);
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gtk_accel_group_connect(
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          accel_group_,
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          ui::GetGdkKeyCodeForAccelerator(keybinding_),
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          ui::GetGdkModifierForAccelerator(keybinding_),
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GtkAccelFlags(0),
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          g_cclosure_new(G_CALLBACK(OnGtkAccelerator), this, NULL));
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Since we've added an accelerator, we'll need to unregister it before
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the window is closed, so we listen for the window being closed.
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      registrar_.Add(this,
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     chrome::NOTIFICATION_WINDOW_CLOSED,
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     content::Source<GtkWindow>(window));
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Disconnect the accelerator for the browser action popup and delete clean up
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the accelerator group registration.
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DisconnectBrowserActionPopupAccelerator() {
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (accel_group_) {
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::NativeWindow window =
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          toolbar_->browser()->window()->GetNativeWindow();
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gtk_accel_group_disconnect_key(
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          accel_group_,
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          ui::GetGdkKeyCodeForAccelerator(keybinding_),
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          GetGdkModifierForAccelerator(keybinding_));
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gtk_window_remove_accel_group(window, accel_group_);
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_object_unref(accel_group_);
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      accel_group_ = NULL;
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      keybinding_ = ui::Accelerator();
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We've removed the accelerator, so no need to listen to this anymore.
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      registrar_.Remove(this,
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        chrome::NOTIFICATION_WINDOW_CLOSED,
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        content::Source<GtkWindow>(window));
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionAction* browser_action() const {
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ExtensionActionManager::Get(toolbar_->browser()->profile())->
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GetBrowserAction(*extension_);
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The toolbar containing this button.
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserActionsToolbarGtk* toolbar_;
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The extension that contains this browser action.
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Extension* extension_;
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The button for this browser action.
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<CustomDrawButton> button_;
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Whether the browser action is enabled (equivalent to whether a page action
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is visible).
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool enabled_;
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The top level widget (parent of |button_|).
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::OwnedWidgetGtk alignment_;
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The one image subwidget in |button_|. We keep this out so we don't alter
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the widget hierarchy while changing the button image because changing the
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // GTK widget hierarchy invalidates all tooltips and several popular
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // extensions change browser action icon in a loop.
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkWidget* image_;
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The object that will be used to get the browser action icon for us.
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It may load the icon asynchronously (in which case the initial icon
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // returned by the factory will be transparent), so we have to observe it for
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // updates to the icon.
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionActionIconFactory icon_factory_;
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Same as |default_icon_|, but stored as SkBitmap.
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SkBitmap default_skbitmap_;
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::GtkSignalRegistrar signals_;
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::NotificationRegistrar registrar_;
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The accelerator group used to handle accelerators, owned by this object.
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkAccelGroup* accel_group_;
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The keybinding accelerator registered to show the browser action popup.
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui::Accelerator keybinding_;
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The context menu view and model for this extension action.
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<MenuGtk> context_menu_;
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<ExtensionContextMenuModel> context_menu_model_;
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class BrowserActionsToolbarGtk;
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// BrowserActionsToolbarGtk ----------------------------------------------------
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BrowserActionsToolbarGtk::BrowserActionsToolbarGtk(Browser* browser)
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : browser_(browser),
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile_(browser->profile()),
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      theme_service_(GtkThemeService::GetFrom(browser->profile())),
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      model_(NULL),
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hbox_(gtk_hbox_new(FALSE, 0)),
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      button_hbox_(gtk_chrome_shrinkable_hbox_new(TRUE, FALSE, kButtonPadding)),
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      drag_button_(NULL),
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      drop_index_(-1),
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      resize_animation_(this),
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      desired_width_(0),
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      start_width_(0),
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      weak_factory_(this) {
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExtensionService* extension_service =
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extensions::ExtensionSystem::Get(profile_)->extension_service();
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!extension_service)
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_button_.reset(new CustomDrawButton(
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      theme_service_,
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IDR_BROWSER_ACTIONS_OVERFLOW,
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IDR_BROWSER_ACTIONS_OVERFLOW_P,
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IDR_BROWSER_ACTIONS_OVERFLOW_H,
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      0,
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE)));
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkWidget* gripper = gtk_button_new();
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_set_size_request(gripper, kResizeGripperWidth, -1);
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_set_can_focus(gripper, FALSE);
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_add_events(gripper, GDK_POINTER_MOTION_MASK);
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signals_.Connect(gripper, "motion-notify-event",
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(OnGripperMotionNotifyThunk), this);
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signals_.Connect(gripper, "expose-event",
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(OnGripperExposeThunk), this);
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signals_.Connect(gripper, "enter-notify-event",
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(OnGripperEnterNotifyThunk), this);
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signals_.Connect(gripper, "leave-notify-event",
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(OnGripperLeaveNotifyThunk), this);
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signals_.Connect(gripper, "button-release-event",
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(OnGripperButtonReleaseThunk), this);
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signals_.Connect(gripper, "button-press-event",
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(OnGripperButtonPressThunk), this);
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signals_.Connect(chevron(), "button-press-event",
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(OnOverflowButtonPressThunk), this);
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |overflow_alignment| adds padding to the right of the browser action
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // buttons, but only appears when the overflow menu is showing.
538c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  overflow_alignment_.Own(gtk_alignment_new(0, 0, 1, 1));
539c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  gtk_container_add(GTK_CONTAINER(overflow_alignment_.get()), chevron());
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |overflow_area_| holds the overflow chevron and the separator, which
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is only shown in GTK+ theme mode.
543c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  overflow_area_.Own(gtk_hbox_new(FALSE, 0));
544c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  gtk_box_pack_start(GTK_BOX(overflow_area_.get()), overflow_alignment_.get(),
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     FALSE, FALSE, 0);
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
547c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  separator_.Own(gtk_vseparator_new());
548c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  gtk_box_pack_start(GTK_BOX(overflow_area_.get()), separator_.get(),
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     FALSE, FALSE, 0);
550c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  gtk_widget_set_no_show_all(separator_.get(), TRUE);
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
552c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  gtk_widget_show_all(overflow_area_.get());
553c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  gtk_widget_set_no_show_all(overflow_area_.get(), TRUE);
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_box_pack_start(GTK_BOX(hbox_.get()), gripper, FALSE, FALSE, 0);
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_box_pack_start(GTK_BOX(hbox_.get()), button_hbox_.get(), TRUE, TRUE, 0);
557c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  gtk_box_pack_start(GTK_BOX(hbox_.get()), overflow_area_.get(), FALSE, FALSE,
558c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     0);
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_ = extension_service->toolbar_model();
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->AddObserver(this);
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetupDrags();
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (model_->extensions_initialized()) {
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CreateAllButtons();
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetContainerWidth();
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We want to connect to "set-focus" on the toplevel window; we have to wait
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // until we are added to a toplevel window to do so.
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signals_.Connect(widget(), "hierarchy-changed",
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(OnHierarchyChangedThunk), this);
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ViewIDUtil::SetID(button_hbox_.get(), VIEW_ID_BROWSER_ACTION_TOOLBAR);
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registrar_.Add(this,
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 content::Source<ThemeService>(theme_service_));
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  theme_service_->InitThemesFor(this);
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BrowserActionsToolbarGtk::~BrowserActionsToolbarGtk() {
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (model_)
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model_->RemoveObserver(this);
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  button_hbox_.Destroy();
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hbox_.Destroy();
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BrowserActionsToolbarGtk::GetCurrentTabId() const {
5902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  content::WebContents* active_tab =
5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      browser_->tab_strip_model()->GetActiveWebContents();
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!active_tab)
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SessionTabHelper::FromWebContents(active_tab)->session_id().id();
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsToolbarGtk::Update() {
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ExtensionButtonMap::iterator iter = extension_button_map_.begin();
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       iter != extension_button_map_.end(); ++iter) {
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    iter->second->UpdateState();
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsToolbarGtk::Observe(
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int type,
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const content::NotificationSource& source,
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const content::NotificationDetails& details) {
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(chrome::NOTIFICATION_BROWSER_THEME_CHANGED == type);
610c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  gtk_widget_set_visible(separator_.get(), theme_service_->UsingNativeTheme());
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsToolbarGtk::SetupDrags() {
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkTargetEntry drag_target = GetDragTargetEntry();
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_drag_dest_set(button_hbox_.get(), GTK_DEST_DEFAULT_DROP, &drag_target, 1,
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    GDK_ACTION_MOVE);
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signals_.Connect(button_hbox_.get(), "drag-motion",
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(OnDragMotionThunk), this);
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsToolbarGtk::CreateAllButtons() {
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extension_button_map_.clear();
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i = 0;
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const extensions::ExtensionList& toolbar_items = model_->toolbar_items();
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (extensions::ExtensionList::const_iterator iter = toolbar_items.begin();
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       iter != toolbar_items.end(); ++iter) {
629868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    CreateButtonForExtension(iter->get(), i++);
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsToolbarGtk::SetContainerWidth() {
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int showing_actions = model_->GetVisibleIconCount();
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (showing_actions >= 0)
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetButtonHBoxWidth(WidthForIconCount(showing_actions));
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsToolbarGtk::CreateButtonForExtension(
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension, int index) {
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ShouldDisplayBrowserAction(extension))
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (profile_->IsOffTheRecord())
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index = model_->OriginalIndexToIncognito(index);
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RemoveButtonForExtension(extension);
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  linked_ptr<BrowserActionButton> button(
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new BrowserActionButton(this, extension, theme_service_));
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_chrome_shrinkable_hbox_pack_start(
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GTK_CHROME_SHRINKABLE_HBOX(button_hbox_.get()), button->widget(), 0);
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_box_reorder_child(GTK_BOX(button_hbox_.get()), button->widget(), index);
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extension_button_map_[extension->id()] = button;
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkTargetEntry drag_target = GetDragTargetEntry();
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_drag_source_set(button->button(), GDK_BUTTON1_MASK, &drag_target, 1,
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      GDK_ACTION_MOVE);
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We ignore whether the drag was a "success" or "failure" in Gtk's opinion.
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signals_.Connect(button->button(), "drag-end",
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(&OnDragEndThunk), this);
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signals_.Connect(button->button(), "drag-failed",
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(&OnDragFailedThunk), this);
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Any time a browser action button is shown or hidden we have to update
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the chevron state.
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signals_.Connect(button->widget(), "show",
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(&OnButtonShowOrHideThunk), this);
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signals_.Connect(button->widget(), "hide",
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(&OnButtonShowOrHideThunk), this);
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_show(button->widget());
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateVisibility();
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GtkWidget* BrowserActionsToolbarGtk::GetBrowserActionWidget(
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension) {
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionButtonMap::iterator it = extension_button_map_.find(
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extension->id());
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it == extension_button_map_.end())
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return it->second.get()->widget();
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsToolbarGtk::RemoveButtonForExtension(
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension) {
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (extension_button_map_.erase(extension->id()))
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateVisibility();
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateChevronVisibility();
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsToolbarGtk::UpdateVisibility() {
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_set_visible(widget(), button_count() != 0);
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BrowserActionsToolbarGtk::ShouldDisplayBrowserAction(
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension) {
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only display incognito-enabled extensions while in incognito mode.
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (!profile_->IsOffTheRecord() ||
7012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          extensions::ExtensionSystem::Get(profile_)->extension_service()->
7022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              IsIncognitoEnabled(extension->id()));
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsToolbarGtk::HidePopup() {
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionPopupGtk* popup = ExtensionPopupGtk::get_current_extension_popup();
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (popup)
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    popup->DestroyPopup();
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsToolbarGtk::AnimateToShowNIcons(int count) {
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  desired_width_ = WidthForIconCount(count);
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkAllocation allocation;
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_get_allocation(button_hbox_.get(), &allocation);
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  start_width_ = allocation.width;
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resize_animation_.Reset();
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resize_animation_.Show();
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsToolbarGtk::BrowserActionAdded(const Extension* extension,
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  int index) {
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_menu_.reset();
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CreateButtonForExtension(extension, index);
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we are still initializing the container, don't bother animating.
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!model_->extensions_initialized())
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Animate the addition if we are showing all browser action buttons.
733c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!gtk_widget_get_visible(overflow_area_.get())) {
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AnimateToShowNIcons(button_count());
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model_->SetVisibleIconCount(button_count());
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsToolbarGtk::BrowserActionRemoved(
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension) {
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_menu_.reset();
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (drag_button_ != NULL) {
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Break the current drag.
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_grab_remove(button_hbox_.get());
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RemoveButtonForExtension(extension);
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
750c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!gtk_widget_get_visible(overflow_area_.get())) {
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AnimateToShowNIcons(button_count());
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model_->SetVisibleIconCount(button_count());
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsToolbarGtk::BrowserActionMoved(const Extension* extension,
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  int index) {
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We initiated this move action, and have already moved the button.
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (drag_button_ != NULL)
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkWidget* button_widget = GetBrowserActionWidget(extension);
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!button_widget) {
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ShouldDisplayBrowserAction(extension))
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (profile_->IsOffTheRecord())
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index = model_->OriginalIndexToIncognito(index);
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_box_reorder_child(GTK_BOX(button_hbox_.get()), button_widget, index);
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsToolbarGtk::ModelLoaded() {
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetContainerWidth();
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsToolbarGtk::AnimationProgressed(
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ui::Animation* animation) {
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int width = start_width_ + (desired_width_ - start_width_) *
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      animation->GetCurrentValue();
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_set_size_request(button_hbox_.get(), width, -1);
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (width == desired_width_)
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    resize_animation_.Reset();
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsToolbarGtk::AnimationEnded(const ui::Animation* animation) {
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_set_size_request(button_hbox_.get(), desired_width_, -1);
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateChevronVisibility();
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BrowserActionsToolbarGtk::IsCommandIdChecked(int command_id) const {
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BrowserActionsToolbarGtk::IsCommandIdEnabled(int command_id) const {
799868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const Extension* extension = model_->toolbar_items()[command_id].get();
800868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return ExtensionActionManager::Get(profile_)->GetBrowserAction(*extension)
801868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      ->GetIsVisible(GetCurrentTabId());
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BrowserActionsToolbarGtk::GetAcceleratorForCommandId(
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int command_id,
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ui::Accelerator* accelerator) {
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BrowserActionsToolbarGtk::ExecuteCommand(int command_id, int event_flags) {
811868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const Extension* extension = model_->toolbar_items()[command_id].get();
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL popup_url;
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (model_->ExecuteBrowserAction(extension, browser(), &popup_url)) {
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ExtensionToolbarModel::ACTION_NONE:
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ExtensionToolbarModel::ACTION_SHOW_POPUP:
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ExtensionPopupGtk::Show(popup_url, browser(), chevron(),
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              ExtensionPopupGtk::SHOW);
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsToolbarGtk::StoppedShowing() {
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_button_->UnsetPaintOverride();
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BrowserActionsToolbarGtk::AlwaysShowIconForCmd(int command_id) const {
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsToolbarGtk::DragStarted(BrowserActionButton* button,
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           GdkDragContext* drag_context) {
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No representation of the widget following the cursor.
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 1, 1);
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_drag_set_icon_pixbuf(drag_context, pixbuf, 0, 0);
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_object_unref(pixbuf);
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!drag_button_);
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  drag_button_ = button;
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsToolbarGtk::SetButtonHBoxWidth(int new_width) {
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gint max_width = WidthForIconCount(button_count());
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new_width = std::min(max_width, new_width);
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new_width = std::max(new_width, 0);
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_set_size_request(button_hbox_.get(), new_width, -1);
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsToolbarGtk::UpdateChevronVisibility() {
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int showing_icon_count =
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gtk_chrome_shrinkable_hbox_get_visible_child_count(
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GTK_CHROME_SHRINKABLE_HBOX(button_hbox_.get()));
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (showing_icon_count == 0) {
855c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    gtk_alignment_set_padding(GTK_ALIGNMENT(overflow_alignment_.get()),
856c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                              0, 0, 0, 0);
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
858c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    gtk_alignment_set_padding(GTK_ALIGNMENT(overflow_alignment_.get()),
859c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                              0, 0, kButtonChevronPadding, 0);
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (button_count() > showing_icon_count) {
863c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!gtk_widget_get_visible(overflow_area_.get())) {
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (drag_button_) {
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // During drags, when the overflow chevron shows for the first time,
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // take that much space away from |button_hbox_| to make the drag look
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // smoother.
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GtkRequisition req;
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        gtk_widget_size_request(chevron(), &req);
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        gint overflow_width = req.width;
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        gtk_widget_size_request(button_hbox_.get(), &req);
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        gint button_hbox_width = req.width;
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        button_hbox_width = std::max(button_hbox_width - overflow_width, 0);
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        gtk_widget_set_size_request(button_hbox_.get(), button_hbox_width, -1);
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
877c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      gtk_widget_show(overflow_area_.get());
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
880c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    gtk_widget_hide(overflow_area_.get());
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean BrowserActionsToolbarGtk::OnDragMotion(GtkWidget* widget,
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                GdkDragContext* drag_context,
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                gint x, gint y, guint time) {
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only handle drags we initiated.
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!drag_button_)
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::i18n::IsRTL()) {
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GtkAllocation allocation;
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_widget_get_allocation(widget, &allocation);
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    x = allocation.width - x;
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  drop_index_ = x < kButtonWidth ? 0 : x / (kButtonWidth + kButtonPadding);
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We will go ahead and reorder the child in order to provide visual feedback
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to the user. We don't inform the model that it has moved until the drag
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ends.
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_box_reorder_child(GTK_BOX(button_hbox_.get()), drag_button_->widget(),
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        drop_index_);
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gdk_drag_status(drag_context, GDK_ACTION_MOVE, time);
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TRUE;
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsToolbarGtk::OnDragEnd(GtkWidget* button,
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         GdkDragContext* drag_context) {
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (drop_index_ != -1) {
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (profile_->IsOffTheRecord())
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      drop_index_ = model_->IncognitoIndexToOriginal(drop_index_);
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model_->MoveBrowserAction(drag_button_->extension(), drop_index_);
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  drag_button_ = NULL;
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  drop_index_ = -1;
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean BrowserActionsToolbarGtk::OnDragFailed(GtkWidget* widget,
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                GdkDragContext* drag_context,
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                GtkDragResult result) {
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We connect to this signal and return TRUE so that the default failure
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // animation (wherein the drag widget floats back to the start of the drag)
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // does not show, and the drag-end signal is emitted immediately instead of
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // several seconds later.
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TRUE;
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsToolbarGtk::OnHierarchyChanged(
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GtkWidget* widget, GtkWidget* previous_toplevel) {
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!gtk_widget_is_toplevel(toplevel))
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signals_.Connect(toplevel, "set-focus", G_CALLBACK(OnSetFocusThunk), this);
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsToolbarGtk::OnSetFocus(GtkWidget* widget,
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          GtkWidget* focus_widget) {
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionPopupGtk* popup = ExtensionPopupGtk::get_current_extension_popup();
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The focus of the parent window has changed. Close the popup. Delay the hide
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // because it will destroy the RenderViewHost, which may still be on the
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // call stack.
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!popup || popup->being_inspected())
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
949b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&BrowserActionsToolbarGtk::HidePopup,
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 weak_factory_.GetWeakPtr()));
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean BrowserActionsToolbarGtk::OnGripperMotionNotify(
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GtkWidget* widget, GdkEventMotion* event) {
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!(event->state & GDK_BUTTON1_MASK))
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Calculate how much the user dragged the gripper and subtract that off the
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // button container's width.
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int distance_dragged;
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::i18n::IsRTL()) {
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    distance_dragged = -event->x;
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GtkAllocation widget_allocation;
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_widget_get_allocation(widget, &widget_allocation);
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    distance_dragged = event->x - widget_allocation.width;
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkAllocation button_hbox_allocation;
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_get_allocation(button_hbox_.get(), &button_hbox_allocation);
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gint new_width = button_hbox_allocation.width - distance_dragged;
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetButtonHBoxWidth(new_width);
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return FALSE;
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean BrowserActionsToolbarGtk::OnGripperExpose(GtkWidget* gripper,
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   GdkEventExpose* expose) {
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TRUE;
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// These three signal handlers (EnterNotify, LeaveNotify, and ButtonRelease)
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// are used to give the gripper the resize cursor. Since it doesn't have its
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// own window, we have to set the cursor whenever the pointer moves into the
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// button or leaves the button, and be sure to leave it on when the user is
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// dragging.
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean BrowserActionsToolbarGtk::OnGripperEnterNotify(
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GtkWidget* gripper, GdkEventCrossing* event) {
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gdk_window_set_cursor(gtk_widget_get_window(gripper),
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        gfx::GetCursor(GDK_SB_H_DOUBLE_ARROW));
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return FALSE;
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean BrowserActionsToolbarGtk::OnGripperLeaveNotify(
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GtkWidget* gripper, GdkEventCrossing* event) {
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!(event->state & GDK_BUTTON1_MASK))
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gdk_window_set_cursor(gtk_widget_get_window(gripper), NULL);
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return FALSE;
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean BrowserActionsToolbarGtk::OnGripperButtonRelease(
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GtkWidget* gripper, GdkEventButton* event) {
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkAllocation allocation;
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_get_allocation(gripper, &allocation);
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect gripper_rect(0, 0, allocation.width, allocation.height);
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Point release_point(event->x, event->y);
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!gripper_rect.Contains(release_point))
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gdk_window_set_cursor(gtk_widget_get_window(gripper), NULL);
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // After the user resizes the toolbar, we want to smartly resize it to be
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the perfect size to fit the buttons.
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int visible_icon_count =
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gtk_chrome_shrinkable_hbox_get_visible_child_count(
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GTK_CHROME_SHRINKABLE_HBOX(button_hbox_.get()));
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AnimateToShowNIcons(visible_icon_count);
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->SetVisibleIconCount(visible_icon_count);
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return FALSE;
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean BrowserActionsToolbarGtk::OnGripperButtonPress(
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GtkWidget* gripper, GdkEventButton* event) {
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resize_animation_.Reset();
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return FALSE;
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean BrowserActionsToolbarGtk::OnOverflowButtonPress(
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GtkWidget* overflow, GdkEventButton* event) {
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_menu_model_.reset(new SimpleMenuModel(this));
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int visible_icon_count =
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gtk_chrome_shrinkable_hbox_get_visible_child_count(
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GTK_CHROME_SHRINKABLE_HBOX(button_hbox_.get()));
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = visible_icon_count; i < button_count(); ++i) {
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int model_index = i;
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (profile_->IsOffTheRecord())
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      model_index = model_->IncognitoIndexToOriginal(i);
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1043868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const Extension* extension = model_->toolbar_items()[model_index].get();
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserActionButton* button = extension_button_map_[extension->id()].get();
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    overflow_menu_model_->AddItem(model_index, UTF8ToUTF16(extension->name()));
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    overflow_menu_model_->SetIcon(overflow_menu_model_->GetItemCount() - 1,
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  button->GetIcon());
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(estade): set the menu item's tooltip.
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_menu_.reset(new MenuGtk(this, overflow_menu_model_.get()));
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signals_.Connect(overflow_menu_->widget(), "button-press-event",
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(OnOverflowMenuButtonPressThunk), this);
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_button_->SetPaintOverride(GTK_STATE_ACTIVE);
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_menu_->PopupAsFromKeyEvent(chevron());
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return FALSE;
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean BrowserActionsToolbarGtk::OnOverflowMenuButtonPress(
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GtkWidget* overflow, GdkEventButton* event) {
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event->button != 3)
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkWidget* menu_item = GTK_MENU_SHELL(overflow)->active_menu_item;
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!menu_item)
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int item_index = g_list_index(GTK_MENU_SHELL(overflow)->children, menu_item);
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (item_index == -1) {
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  item_index += gtk_chrome_shrinkable_hbox_get_visible_child_count(
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GTK_CHROME_SHRINKABLE_HBOX(button_hbox_.get()));
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (profile_->IsOffTheRecord())
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    item_index = model_->IncognitoIndexToOriginal(item_index);
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1083868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const Extension* extension = model_->toolbar_items()[item_index].get();
1084868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ExtensionButtonMap::iterator it = extension_button_map_.find(extension->id());
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it == extension_button_map_.end()) {
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MenuGtk* menu = it->second.get()->GetContextMenu();
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!menu)
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu->PopupAsContext(gfx::Point(event->x_root, event->y_root),
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       event->time);
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TRUE;
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserActionsToolbarGtk::OnButtonShowOrHide(GtkWidget* sender) {
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!resize_animation_.is_animating())
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateChevronVisibility();
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1103