| Index: chrome/browser/gtk/browser_actions_toolbar_gtk.cc
|
| ===================================================================
|
| --- chrome/browser/gtk/browser_actions_toolbar_gtk.cc (revision 71352)
|
| +++ chrome/browser/gtk/browser_actions_toolbar_gtk.cc (working copy)
|
| @@ -1,945 +0,0 @@
|
| -// Copyright (c) 2010 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "chrome/browser/gtk/browser_actions_toolbar_gtk.h"
|
| -
|
| -#include <vector>
|
| -
|
| -#include "base/i18n/rtl.h"
|
| -#include "base/utf_string_conversions.h"
|
| -#include "chrome/browser/extensions/extension_browser_event_router.h"
|
| -#include "chrome/browser/extensions/extension_context_menu_model.h"
|
| -#include "chrome/browser/extensions/extension_service.h"
|
| -#include "chrome/browser/extensions/image_loading_tracker.h"
|
| -#include "chrome/browser/gtk/cairo_cached_surface.h"
|
| -#include "chrome/browser/gtk/extension_popup_gtk.h"
|
| -#include "chrome/browser/gtk/gtk_chrome_button.h"
|
| -#include "chrome/browser/gtk/gtk_chrome_shrinkable_hbox.h"
|
| -#include "chrome/browser/gtk/gtk_theme_provider.h"
|
| -#include "chrome/browser/gtk/gtk_util.h"
|
| -#include "chrome/browser/gtk/hover_controller_gtk.h"
|
| -#include "chrome/browser/gtk/menu_gtk.h"
|
| -#include "chrome/browser/gtk/view_id_util.h"
|
| -#include "chrome/browser/profiles/profile.h"
|
| -#include "chrome/browser/tab_contents/tab_contents.h"
|
| -#include "chrome/browser/ui/browser.h"
|
| -#include "chrome/common/extensions/extension.h"
|
| -#include "chrome/common/extensions/extension_action.h"
|
| -#include "chrome/common/extensions/extension_resource.h"
|
| -#include "chrome/common/notification_details.h"
|
| -#include "chrome/common/notification_service.h"
|
| -#include "chrome/common/notification_source.h"
|
| -#include "chrome/common/notification_type.h"
|
| -#include "gfx/canvas_skia_paint.h"
|
| -#include "gfx/gtk_util.h"
|
| -#include "grit/app_resources.h"
|
| -#include "grit/theme_resources.h"
|
| -
|
| -namespace {
|
| -
|
| -// The width of the browser action buttons.
|
| -const int kButtonWidth = 27;
|
| -
|
| -// The padding between browser action buttons.
|
| -const int kButtonPadding = 4;
|
| -
|
| -// The padding to the right of the browser action buttons (between the buttons
|
| -// and chevron if they are both showing).
|
| -const int kButtonChevronPadding = 2;
|
| -
|
| -// The padding to the left, top and bottom of the browser actions toolbar
|
| -// separator.
|
| -const int kSeparatorPadding = 2;
|
| -
|
| -// Width of the invisible gripper for resizing the toolbar.
|
| -const int kResizeGripperWidth = 4;
|
| -
|
| -const char* kDragTarget = "application/x-chrome-browseraction";
|
| -
|
| -GtkTargetEntry GetDragTargetEntry() {
|
| - static std::string drag_target_string(kDragTarget);
|
| - GtkTargetEntry drag_target;
|
| - drag_target.target = const_cast<char*>(drag_target_string.c_str());
|
| - drag_target.flags = GTK_TARGET_SAME_APP;
|
| - drag_target.info = 0;
|
| - return drag_target;
|
| -}
|
| -
|
| -// The minimum width in pixels of the button hbox if |icon_count| icons are
|
| -// showing.
|
| -gint WidthForIconCount(gint icon_count) {
|
| - return std::max((kButtonWidth + kButtonPadding) * icon_count - kButtonPadding,
|
| - 0);
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -using menus::SimpleMenuModel;
|
| -
|
| -class BrowserActionButton : public NotificationObserver,
|
| - public ImageLoadingTracker::Observer,
|
| - public ExtensionContextMenuModel::PopupDelegate,
|
| - public MenuGtk::Delegate {
|
| - public:
|
| - BrowserActionButton(BrowserActionsToolbarGtk* toolbar,
|
| - const Extension* extension,
|
| - GtkThemeProvider* theme_provider)
|
| - : toolbar_(toolbar),
|
| - extension_(extension),
|
| - image_(NULL),
|
| - tracker_(this),
|
| - tab_specific_icon_(NULL),
|
| - default_icon_(NULL) {
|
| - button_.reset(new CustomDrawButton(
|
| - theme_provider,
|
| - IDR_BROWSER_ACTION,
|
| - IDR_BROWSER_ACTION_P,
|
| - IDR_BROWSER_ACTION_H,
|
| - 0,
|
| - NULL));
|
| - alignment_.Own(gtk_alignment_new(0, 0, 1, 1));
|
| - gtk_container_add(GTK_CONTAINER(alignment_.get()), button());
|
| - gtk_widget_show(button());
|
| -
|
| - DCHECK(extension_->browser_action());
|
| -
|
| - UpdateState();
|
| -
|
| - // The Browser Action API does not allow the default icon path to be
|
| - // changed at runtime, so we can load this now and cache it.
|
| - std::string path = extension_->browser_action()->default_icon_path();
|
| - if (!path.empty()) {
|
| - tracker_.LoadImage(extension_, extension_->GetResource(path),
|
| - gfx::Size(Extension::kBrowserActionIconMaxSize,
|
| - Extension::kBrowserActionIconMaxSize),
|
| - ImageLoadingTracker::DONT_CACHE);
|
| - }
|
| -
|
| - signals_.Connect(button(), "button-press-event",
|
| - G_CALLBACK(OnButtonPress), this);
|
| - signals_.Connect(button(), "clicked",
|
| - G_CALLBACK(OnClicked), this);
|
| - signals_.Connect(button(), "drag-begin",
|
| - G_CALLBACK(&OnDragBegin), this);
|
| - signals_.ConnectAfter(widget(), "expose-event",
|
| - G_CALLBACK(OnExposeEvent), this);
|
| -
|
| - registrar_.Add(this, NotificationType::EXTENSION_BROWSER_ACTION_UPDATED,
|
| - Source<ExtensionAction>(extension->browser_action()));
|
| - }
|
| -
|
| - ~BrowserActionButton() {
|
| - if (tab_specific_icon_)
|
| - g_object_unref(tab_specific_icon_);
|
| -
|
| - if (default_icon_)
|
| - g_object_unref(default_icon_);
|
| -
|
| - alignment_.Destroy();
|
| - }
|
| -
|
| - GtkWidget* button() { return button_->widget(); }
|
| -
|
| - GtkWidget* widget() { return alignment_.get(); }
|
| -
|
| - const Extension* extension() { return extension_; }
|
| -
|
| - // NotificationObserver implementation.
|
| - void Observe(NotificationType type,
|
| - const NotificationSource& source,
|
| - const NotificationDetails& details) {
|
| - if (type == NotificationType::EXTENSION_BROWSER_ACTION_UPDATED)
|
| - UpdateState();
|
| - else
|
| - NOTREACHED();
|
| - }
|
| -
|
| - // ImageLoadingTracker::Observer implementation.
|
| - void OnImageLoaded(SkBitmap* image, ExtensionResource resource, int index) {
|
| - if (image) {
|
| - default_skbitmap_ = *image;
|
| - default_icon_ = gfx::GdkPixbufFromSkBitmap(image);
|
| - }
|
| - UpdateState();
|
| - }
|
| -
|
| - // Updates the button based on the latest state from the associated
|
| - // browser action.
|
| - void UpdateState() {
|
| - int tab_id = toolbar_->GetCurrentTabId();
|
| - if (tab_id < 0)
|
| - return;
|
| -
|
| - std::string tooltip = extension_->browser_action()->GetTitle(tab_id);
|
| - if (tooltip.empty())
|
| - gtk_widget_set_has_tooltip(button(), FALSE);
|
| - else
|
| - gtk_widget_set_tooltip_text(button(), tooltip.c_str());
|
| -
|
| - SkBitmap image = extension_->browser_action()->GetIcon(tab_id);
|
| - if (!image.isNull()) {
|
| - GdkPixbuf* previous_gdk_icon = tab_specific_icon_;
|
| - tab_specific_icon_ = gfx::GdkPixbufFromSkBitmap(&image);
|
| - SetImage(tab_specific_icon_);
|
| - if (previous_gdk_icon)
|
| - g_object_unref(previous_gdk_icon);
|
| - } else if (default_icon_) {
|
| - SetImage(default_icon_);
|
| - }
|
| - gtk_widget_queue_draw(button());
|
| - }
|
| -
|
| - SkBitmap GetIcon() {
|
| - const SkBitmap& image = extension_->browser_action()->GetIcon(
|
| - toolbar_->GetCurrentTabId());
|
| - if (!image.isNull()) {
|
| - return image;
|
| - } else {
|
| - return default_skbitmap_;
|
| - }
|
| - }
|
| -
|
| - MenuGtk* GetContextMenu() {
|
| - context_menu_model_ =
|
| - new ExtensionContextMenuModel(extension_, toolbar_->browser(), this);
|
| - context_menu_.reset(
|
| - new MenuGtk(this, context_menu_model_.get()));
|
| - return context_menu_.get();
|
| - }
|
| -
|
| - private:
|
| - // MenuGtk::Delegate implementation.
|
| - virtual void StoppedShowing() {
|
| - button_->UnsetPaintOverride();
|
| -
|
| - // If the context menu was showing for the overflow menu, re-assert the
|
| - // grab that was shadowed.
|
| - if (toolbar_->overflow_menu_.get())
|
| - gtk_util::GrabAllInput(toolbar_->overflow_menu_->widget());
|
| - }
|
| -
|
| - virtual void CommandWillBeExecuted() {
|
| - // If the context menu was showing for the overflow menu, and a command
|
| - // is executed, then stop showing the overflow menu.
|
| - if (toolbar_->overflow_menu_.get())
|
| - toolbar_->overflow_menu_->Cancel();
|
| - }
|
| -
|
| - // Returns true to prevent further processing of the event that caused us to
|
| - // show the popup, or false to continue processing.
|
| - bool ShowPopup(bool devtools) {
|
| - ExtensionAction* browser_action = extension_->browser_action();
|
| -
|
| - int tab_id = toolbar_->GetCurrentTabId();
|
| - if (tab_id < 0) {
|
| - NOTREACHED() << "No current tab.";
|
| - return true;
|
| - }
|
| -
|
| - if (browser_action->HasPopup(tab_id)) {
|
| - ExtensionPopupGtk::Show(
|
| - browser_action->GetPopupUrl(tab_id), toolbar_->browser(),
|
| - widget(), devtools);
|
| - return true;
|
| - }
|
| -
|
| - return false;
|
| - }
|
| -
|
| - // ExtensionContextMenuModel::PopupDelegate implementation.
|
| - virtual void InspectPopup(ExtensionAction* action) {
|
| - ShowPopup(true);
|
| - }
|
| -
|
| - void SetImage(GdkPixbuf* image) {
|
| - if (!image_) {
|
| - image_ = gtk_image_new_from_pixbuf(image);
|
| - gtk_button_set_image(GTK_BUTTON(button()), image_);
|
| - } else {
|
| - gtk_image_set_from_pixbuf(GTK_IMAGE(image_), image);
|
| - }
|
| - }
|
| -
|
| - static gboolean OnButtonPress(GtkWidget* widget,
|
| - GdkEvent* event,
|
| - BrowserActionButton* action) {
|
| - if (event->button.button != 3)
|
| - return FALSE;
|
| -
|
| - action->button_->SetPaintOverride(GTK_STATE_ACTIVE);
|
| - action->GetContextMenu()->Popup(widget, event);
|
| -
|
| - return TRUE;
|
| - }
|
| -
|
| - static void OnClicked(GtkWidget* widget, BrowserActionButton* action) {
|
| - if (action->ShowPopup(false))
|
| - return;
|
| -
|
| - ExtensionBrowserEventRouter::GetInstance()->BrowserActionExecuted(
|
| - action->toolbar_->browser()->profile(), action->extension_->id(),
|
| - action->toolbar_->browser());
|
| - }
|
| -
|
| - static gboolean OnExposeEvent(GtkWidget* widget,
|
| - GdkEventExpose* event,
|
| - BrowserActionButton* button) {
|
| - int tab_id = button->toolbar_->GetCurrentTabId();
|
| - if (tab_id < 0)
|
| - return FALSE;
|
| -
|
| - ExtensionAction* action = button->extension_->browser_action();
|
| - if (action->GetBadgeText(tab_id).empty())
|
| - return FALSE;
|
| -
|
| - gfx::CanvasSkiaPaint canvas(event, false);
|
| - gfx::Rect bounding_rect(widget->allocation);
|
| - action->PaintBadge(&canvas, bounding_rect, tab_id);
|
| - return FALSE;
|
| - }
|
| -
|
| - static void OnDragBegin(GtkWidget* widget,
|
| - GdkDragContext* drag_context,
|
| - BrowserActionButton* button) {
|
| - // Simply pass along the notification to the toolbar. The point of this
|
| - // function is to tell the toolbar which BrowserActionButton initiated the
|
| - // drag.
|
| - button->toolbar_->DragStarted(button, drag_context);
|
| - }
|
| -
|
| - // The toolbar containing this button.
|
| - BrowserActionsToolbarGtk* toolbar_;
|
| -
|
| - // The extension that contains this browser action.
|
| - const Extension* extension_;
|
| -
|
| - // The button for this browser action.
|
| - scoped_ptr<CustomDrawButton> button_;
|
| -
|
| - // The top level widget (parent of |button_|).
|
| - OwnedWidgetGtk alignment_;
|
| -
|
| - // The one image subwidget in |button_|. We keep this out so we don't alter
|
| - // the widget hierarchy while changing the button image because changing the
|
| - // GTK widget hierarchy invalidates all tooltips and several popular
|
| - // extensions change browser action icon in a loop.
|
| - GtkWidget* image_;
|
| -
|
| - // Loads the button's icons for us on the file thread.
|
| - ImageLoadingTracker tracker_;
|
| -
|
| - // If we are displaying a tab-specific icon, it will be here.
|
| - GdkPixbuf* tab_specific_icon_;
|
| -
|
| - // If the browser action has a default icon, it will be here.
|
| - GdkPixbuf* default_icon_;
|
| -
|
| - // Same as |default_icon_|, but stored as SkBitmap.
|
| - SkBitmap default_skbitmap_;
|
| -
|
| - GtkSignalRegistrar signals_;
|
| - NotificationRegistrar registrar_;
|
| -
|
| - // The context menu view and model for this extension action.
|
| - scoped_ptr<MenuGtk> context_menu_;
|
| - scoped_refptr<ExtensionContextMenuModel> context_menu_model_;
|
| -
|
| - friend class BrowserActionsToolbarGtk;
|
| -};
|
| -
|
| -// BrowserActionsToolbarGtk ----------------------------------------------------
|
| -
|
| -BrowserActionsToolbarGtk::BrowserActionsToolbarGtk(Browser* browser)
|
| - : browser_(browser),
|
| - profile_(browser->profile()),
|
| - theme_provider_(GtkThemeProvider::GetFrom(browser->profile())),
|
| - model_(NULL),
|
| - hbox_(gtk_hbox_new(FALSE, 0)),
|
| - button_hbox_(gtk_chrome_shrinkable_hbox_new(TRUE, FALSE, kButtonPadding)),
|
| - drag_button_(NULL),
|
| - drop_index_(-1),
|
| - resize_animation_(this),
|
| - desired_width_(0),
|
| - start_width_(0),
|
| - method_factory_(this) {
|
| - ExtensionService* extension_service = profile_->GetExtensionService();
|
| - // The |extension_service| can be NULL in Incognito.
|
| - if (!extension_service)
|
| - return;
|
| -
|
| - overflow_button_.reset(new CustomDrawButton(
|
| - theme_provider_,
|
| - IDR_BROWSER_ACTIONS_OVERFLOW,
|
| - IDR_BROWSER_ACTIONS_OVERFLOW_P,
|
| - IDR_BROWSER_ACTIONS_OVERFLOW_H,
|
| - 0,
|
| - gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE)));
|
| -
|
| - GtkWidget* gripper = gtk_button_new();
|
| - gtk_widget_set_size_request(gripper, kResizeGripperWidth, -1);
|
| - GTK_WIDGET_UNSET_FLAGS(gripper, GTK_CAN_FOCUS);
|
| - gtk_widget_add_events(gripper, GDK_POINTER_MOTION_MASK);
|
| - signals_.Connect(gripper, "motion-notify-event",
|
| - G_CALLBACK(OnGripperMotionNotifyThunk), this);
|
| - signals_.Connect(gripper, "expose-event",
|
| - G_CALLBACK(OnGripperExposeThunk), this);
|
| - signals_.Connect(gripper, "enter-notify-event",
|
| - G_CALLBACK(OnGripperEnterNotifyThunk), this);
|
| - signals_.Connect(gripper, "leave-notify-event",
|
| - G_CALLBACK(OnGripperLeaveNotifyThunk), this);
|
| - signals_.Connect(gripper, "button-release-event",
|
| - G_CALLBACK(OnGripperButtonReleaseThunk), this);
|
| - signals_.Connect(gripper, "button-press-event",
|
| - G_CALLBACK(OnGripperButtonPressThunk), this);
|
| - signals_.Connect(chevron(), "button-press-event",
|
| - G_CALLBACK(OnOverflowButtonPressThunk), this);
|
| -
|
| - // |overflow_alignment| adds padding to the right of the browser action
|
| - // buttons, but only appears when the overflow menu is showing.
|
| - overflow_alignment_ = gtk_alignment_new(0, 0, 1, 1);
|
| - gtk_container_add(GTK_CONTAINER(overflow_alignment_), chevron());
|
| -
|
| - // |overflow_area_| holds the overflow chevron and the separator, which
|
| - // is only shown in GTK+ theme mode.
|
| - overflow_area_ = gtk_hbox_new(FALSE, 0);
|
| - gtk_box_pack_start(GTK_BOX(overflow_area_), overflow_alignment_,
|
| - FALSE, FALSE, 0);
|
| -
|
| - separator_ = gtk_vseparator_new();
|
| - gtk_box_pack_start(GTK_BOX(overflow_area_), separator_,
|
| - FALSE, FALSE, 0);
|
| - gtk_widget_set_no_show_all(separator_, TRUE);
|
| -
|
| - gtk_widget_show_all(overflow_area_);
|
| - gtk_widget_set_no_show_all(overflow_area_, TRUE);
|
| -
|
| - gtk_box_pack_start(GTK_BOX(hbox_.get()), gripper, FALSE, FALSE, 0);
|
| - gtk_box_pack_start(GTK_BOX(hbox_.get()), button_hbox_.get(), TRUE, TRUE, 0);
|
| - gtk_box_pack_start(GTK_BOX(hbox_.get()), overflow_area_, FALSE, FALSE, 0);
|
| -
|
| - model_ = extension_service->toolbar_model();
|
| - model_->AddObserver(this);
|
| - SetupDrags();
|
| -
|
| - if (model_->extensions_initialized()) {
|
| - CreateAllButtons();
|
| - SetContainerWidth();
|
| - }
|
| -
|
| - // We want to connect to "set-focus" on the toplevel window; we have to wait
|
| - // until we are added to a toplevel window to do so.
|
| - signals_.Connect(widget(), "hierarchy-changed",
|
| - G_CALLBACK(OnHierarchyChangedThunk), this);
|
| -
|
| - ViewIDUtil::SetID(button_hbox_.get(), VIEW_ID_BROWSER_ACTION_TOOLBAR);
|
| -
|
| - registrar_.Add(this,
|
| - NotificationType::BROWSER_THEME_CHANGED,
|
| - NotificationService::AllSources());
|
| - theme_provider_->InitThemesFor(this);
|
| -}
|
| -
|
| -BrowserActionsToolbarGtk::~BrowserActionsToolbarGtk() {
|
| - if (model_)
|
| - model_->RemoveObserver(this);
|
| - button_hbox_.Destroy();
|
| - hbox_.Destroy();
|
| -}
|
| -
|
| -int BrowserActionsToolbarGtk::GetCurrentTabId() {
|
| - TabContents* selected_tab = browser_->GetSelectedTabContents();
|
| - if (!selected_tab)
|
| - return -1;
|
| -
|
| - return selected_tab->controller().session_id().id();
|
| -}
|
| -
|
| -void BrowserActionsToolbarGtk::Update() {
|
| - for (ExtensionButtonMap::iterator iter = extension_button_map_.begin();
|
| - iter != extension_button_map_.end(); ++iter) {
|
| - iter->second->UpdateState();
|
| - }
|
| -}
|
| -
|
| -void BrowserActionsToolbarGtk::Observe(NotificationType type,
|
| - const NotificationSource& source,
|
| - const NotificationDetails& details) {
|
| - DCHECK(NotificationType::BROWSER_THEME_CHANGED == type);
|
| - if (theme_provider_->UseGtkTheme())
|
| - gtk_widget_show(separator_);
|
| - else
|
| - gtk_widget_hide(separator_);
|
| -}
|
| -
|
| -void BrowserActionsToolbarGtk::SetupDrags() {
|
| - GtkTargetEntry drag_target = GetDragTargetEntry();
|
| - gtk_drag_dest_set(button_hbox_.get(), GTK_DEST_DEFAULT_DROP, &drag_target, 1,
|
| - GDK_ACTION_MOVE);
|
| -
|
| - signals_.Connect(button_hbox_.get(), "drag-motion",
|
| - G_CALLBACK(OnDragMotionThunk), this);
|
| -}
|
| -
|
| -void BrowserActionsToolbarGtk::CreateAllButtons() {
|
| - extension_button_map_.clear();
|
| -
|
| - int i = 0;
|
| - for (ExtensionList::iterator iter = model_->begin();
|
| - iter != model_->end(); ++iter) {
|
| - CreateButtonForExtension(*iter, i++);
|
| - }
|
| -}
|
| -
|
| -void BrowserActionsToolbarGtk::SetContainerWidth() {
|
| - int showing_actions = model_->GetVisibleIconCount();
|
| - if (showing_actions >= 0)
|
| - SetButtonHBoxWidth(WidthForIconCount(showing_actions));
|
| -}
|
| -
|
| -void BrowserActionsToolbarGtk::CreateButtonForExtension(
|
| - const Extension* extension, int index) {
|
| - if (!ShouldDisplayBrowserAction(extension))
|
| - return;
|
| -
|
| - if (profile_->IsOffTheRecord())
|
| - index = model_->OriginalIndexToIncognito(index);
|
| -
|
| - RemoveButtonForExtension(extension);
|
| - linked_ptr<BrowserActionButton> button(
|
| - new BrowserActionButton(this, extension, theme_provider_));
|
| - gtk_chrome_shrinkable_hbox_pack_start(
|
| - GTK_CHROME_SHRINKABLE_HBOX(button_hbox_.get()), button->widget(), 0);
|
| - gtk_box_reorder_child(GTK_BOX(button_hbox_.get()), button->widget(), index);
|
| - extension_button_map_[extension->id()] = button;
|
| -
|
| - GtkTargetEntry drag_target = GetDragTargetEntry();
|
| - gtk_drag_source_set(button->button(), GDK_BUTTON1_MASK, &drag_target, 1,
|
| - GDK_ACTION_MOVE);
|
| - // We ignore whether the drag was a "success" or "failure" in Gtk's opinion.
|
| - signals_.Connect(button->button(), "drag-end",
|
| - G_CALLBACK(&OnDragEndThunk), this);
|
| - signals_.Connect(button->button(), "drag-failed",
|
| - G_CALLBACK(&OnDragFailedThunk), this);
|
| -
|
| - // Any time a browser action button is shown or hidden we have to update
|
| - // the chevron state.
|
| - signals_.Connect(button->widget(), "show",
|
| - G_CALLBACK(&OnButtonShowOrHideThunk), this);
|
| - signals_.Connect(button->widget(), "hide",
|
| - G_CALLBACK(&OnButtonShowOrHideThunk), this);
|
| -
|
| - gtk_widget_show(button->widget());
|
| -
|
| - UpdateVisibility();
|
| -}
|
| -
|
| -GtkWidget* BrowserActionsToolbarGtk::GetBrowserActionWidget(
|
| - const Extension* extension) {
|
| - ExtensionButtonMap::iterator it = extension_button_map_.find(
|
| - extension->id());
|
| - if (it == extension_button_map_.end())
|
| - return NULL;
|
| -
|
| - return it->second.get()->widget();
|
| -}
|
| -
|
| -void BrowserActionsToolbarGtk::RemoveButtonForExtension(
|
| - const Extension* extension) {
|
| - if (extension_button_map_.erase(extension->id()))
|
| - UpdateVisibility();
|
| - UpdateChevronVisibility();
|
| -}
|
| -
|
| -void BrowserActionsToolbarGtk::UpdateVisibility() {
|
| - if (button_count() == 0)
|
| - gtk_widget_hide(widget());
|
| - else
|
| - gtk_widget_show(widget());
|
| -}
|
| -
|
| -bool BrowserActionsToolbarGtk::ShouldDisplayBrowserAction(
|
| - const Extension* extension) {
|
| - // Only display incognito-enabled extensions while in incognito mode.
|
| - return (!profile_->IsOffTheRecord() ||
|
| - profile_->GetExtensionService()->IsIncognitoEnabled(extension));
|
| -}
|
| -
|
| -void BrowserActionsToolbarGtk::HidePopup() {
|
| - ExtensionPopupGtk* popup = ExtensionPopupGtk::get_current_extension_popup();
|
| - if (popup)
|
| - popup->DestroyPopup();
|
| -}
|
| -
|
| -void BrowserActionsToolbarGtk::AnimateToShowNIcons(int count) {
|
| - desired_width_ = WidthForIconCount(count);
|
| - start_width_ = button_hbox_->allocation.width;
|
| - resize_animation_.Reset();
|
| - resize_animation_.Show();
|
| -}
|
| -
|
| -void BrowserActionsToolbarGtk::BrowserActionAdded(const Extension* extension,
|
| - int index) {
|
| - overflow_menu_.reset();
|
| -
|
| - CreateButtonForExtension(extension, index);
|
| -
|
| - // If we are still initializing the container, don't bother animating.
|
| - if (!model_->extensions_initialized())
|
| - return;
|
| -
|
| - // Animate the addition if we are showing all browser action buttons.
|
| - if (!GTK_WIDGET_VISIBLE(overflow_area_)) {
|
| - AnimateToShowNIcons(button_count());
|
| - model_->SetVisibleIconCount(button_count());
|
| - }
|
| -}
|
| -
|
| -void BrowserActionsToolbarGtk::BrowserActionRemoved(
|
| - const Extension* extension) {
|
| - overflow_menu_.reset();
|
| -
|
| - if (drag_button_ != NULL) {
|
| - // Break the current drag.
|
| - gtk_grab_remove(button_hbox_.get());
|
| - }
|
| -
|
| - RemoveButtonForExtension(extension);
|
| -
|
| - if (!GTK_WIDGET_VISIBLE(overflow_area_)) {
|
| - AnimateToShowNIcons(button_count());
|
| - model_->SetVisibleIconCount(button_count());
|
| - }
|
| -}
|
| -
|
| -void BrowserActionsToolbarGtk::BrowserActionMoved(const Extension* extension,
|
| - int index) {
|
| - // We initiated this move action, and have already moved the button.
|
| - if (drag_button_ != NULL)
|
| - return;
|
| -
|
| - GtkWidget* button_widget = GetBrowserActionWidget(extension);
|
| - if (!button_widget) {
|
| - if (ShouldDisplayBrowserAction(extension))
|
| - NOTREACHED();
|
| - return;
|
| - }
|
| -
|
| - if (profile_->IsOffTheRecord())
|
| - index = model_->OriginalIndexToIncognito(index);
|
| -
|
| - gtk_box_reorder_child(GTK_BOX(button_hbox_.get()), button_widget, index);
|
| -}
|
| -
|
| -void BrowserActionsToolbarGtk::ModelLoaded() {
|
| - SetContainerWidth();
|
| -}
|
| -
|
| -void BrowserActionsToolbarGtk::AnimationProgressed(
|
| - const ui::Animation* animation) {
|
| - int width = start_width_ + (desired_width_ - start_width_) *
|
| - animation->GetCurrentValue();
|
| - gtk_widget_set_size_request(button_hbox_.get(), width, -1);
|
| -
|
| - if (width == desired_width_)
|
| - resize_animation_.Reset();
|
| -}
|
| -
|
| -void BrowserActionsToolbarGtk::AnimationEnded(const ui::Animation* animation) {
|
| - gtk_widget_set_size_request(button_hbox_.get(), desired_width_, -1);
|
| - UpdateChevronVisibility();
|
| -}
|
| -
|
| -bool BrowserActionsToolbarGtk::IsCommandIdChecked(int command_id) const {
|
| - return false;
|
| -}
|
| -
|
| -bool BrowserActionsToolbarGtk::IsCommandIdEnabled(int command_id) const {
|
| - return true;
|
| -}
|
| -
|
| -bool BrowserActionsToolbarGtk::GetAcceleratorForCommandId(
|
| - int command_id,
|
| - menus::Accelerator* accelerator) {
|
| - return false;
|
| -}
|
| -
|
| -void BrowserActionsToolbarGtk::ExecuteCommand(int command_id) {
|
| - const Extension* extension = model_->GetExtensionByIndex(command_id);
|
| - ExtensionAction* browser_action = extension->browser_action();
|
| -
|
| - int tab_id = GetCurrentTabId();
|
| - if (tab_id < 0) {
|
| - NOTREACHED() << "No current tab.";
|
| - return;
|
| - }
|
| -
|
| - if (browser_action->HasPopup(tab_id)) {
|
| - ExtensionPopupGtk::Show(
|
| - browser_action->GetPopupUrl(tab_id), browser(),
|
| - chevron(),
|
| - false);
|
| - } else {
|
| - ExtensionBrowserEventRouter::GetInstance()->BrowserActionExecuted(
|
| - browser()->profile(), extension->id(), browser());
|
| - }
|
| -}
|
| -
|
| -void BrowserActionsToolbarGtk::StoppedShowing() {
|
| - overflow_button_->UnsetPaintOverride();
|
| -}
|
| -
|
| -bool BrowserActionsToolbarGtk::AlwaysShowIconForCmd(int command_id) const {
|
| - return true;
|
| -}
|
| -
|
| -void BrowserActionsToolbarGtk::DragStarted(BrowserActionButton* button,
|
| - GdkDragContext* drag_context) {
|
| - // No representation of the widget following the cursor.
|
| - GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 1, 1);
|
| - gtk_drag_set_icon_pixbuf(drag_context, pixbuf, 0, 0);
|
| - g_object_unref(pixbuf);
|
| -
|
| - DCHECK(!drag_button_);
|
| - drag_button_ = button;
|
| -}
|
| -
|
| -void BrowserActionsToolbarGtk::SetButtonHBoxWidth(int new_width) {
|
| - gint max_width = WidthForIconCount(button_count());
|
| - new_width = std::min(max_width, new_width);
|
| - new_width = std::max(new_width, 0);
|
| - gtk_widget_set_size_request(button_hbox_.get(), new_width, -1);
|
| -}
|
| -
|
| -void BrowserActionsToolbarGtk::UpdateChevronVisibility() {
|
| - int showing_icon_count =
|
| - gtk_chrome_shrinkable_hbox_get_visible_child_count(
|
| - GTK_CHROME_SHRINKABLE_HBOX(button_hbox_.get()));
|
| - if (showing_icon_count == 0) {
|
| - gtk_alignment_set_padding(GTK_ALIGNMENT(overflow_alignment_), 0, 0, 0, 0);
|
| - } else {
|
| - gtk_alignment_set_padding(GTK_ALIGNMENT(overflow_alignment_), 0, 0,
|
| - kButtonChevronPadding, 0);
|
| - }
|
| -
|
| - if (button_count() > showing_icon_count) {
|
| - if (!GTK_WIDGET_VISIBLE(overflow_area_)) {
|
| - if (drag_button_) {
|
| - // During drags, when the overflow chevron shows for the first time,
|
| - // take that much space away from |button_hbox_| to make the drag look
|
| - // smoother.
|
| - GtkRequisition req;
|
| - gtk_widget_size_request(chevron(), &req);
|
| - gint overflow_width = req.width;
|
| - gtk_widget_size_request(button_hbox_.get(), &req);
|
| - gint button_hbox_width = req.width;
|
| - button_hbox_width = std::max(button_hbox_width - overflow_width, 0);
|
| - gtk_widget_set_size_request(button_hbox_.get(), button_hbox_width, -1);
|
| - }
|
| -
|
| - gtk_widget_show(overflow_area_);
|
| - }
|
| - } else {
|
| - gtk_widget_hide(overflow_area_);
|
| - }
|
| -}
|
| -
|
| -gboolean BrowserActionsToolbarGtk::OnDragMotion(GtkWidget* widget,
|
| - GdkDragContext* drag_context,
|
| - gint x, gint y, guint time) {
|
| - // Only handle drags we initiated.
|
| - if (!drag_button_)
|
| - return FALSE;
|
| -
|
| - if (base::i18n::IsRTL())
|
| - x = widget->allocation.width - x;
|
| - drop_index_ = x < kButtonWidth ? 0 : x / (kButtonWidth + kButtonPadding);
|
| -
|
| - // We will go ahead and reorder the child in order to provide visual feedback
|
| - // to the user. We don't inform the model that it has moved until the drag
|
| - // ends.
|
| - gtk_box_reorder_child(GTK_BOX(button_hbox_.get()), drag_button_->widget(),
|
| - drop_index_);
|
| -
|
| - gdk_drag_status(drag_context, GDK_ACTION_MOVE, time);
|
| - return TRUE;
|
| -}
|
| -
|
| -void BrowserActionsToolbarGtk::OnDragEnd(GtkWidget* button,
|
| - GdkDragContext* drag_context) {
|
| - if (drop_index_ != -1) {
|
| - if (profile_->IsOffTheRecord())
|
| - drop_index_ = model_->IncognitoIndexToOriginal(drop_index_);
|
| -
|
| - model_->MoveBrowserAction(drag_button_->extension(), drop_index_);
|
| - }
|
| -
|
| - drag_button_ = NULL;
|
| - drop_index_ = -1;
|
| -}
|
| -
|
| -gboolean BrowserActionsToolbarGtk::OnDragFailed(GtkWidget* widget,
|
| - GdkDragContext* drag_context,
|
| - GtkDragResult result) {
|
| - // We connect to this signal and return TRUE so that the default failure
|
| - // animation (wherein the drag widget floats back to the start of the drag)
|
| - // does not show, and the drag-end signal is emitted immediately instead of
|
| - // several seconds later.
|
| - return TRUE;
|
| -}
|
| -
|
| -void BrowserActionsToolbarGtk::OnHierarchyChanged(
|
| - GtkWidget* widget, GtkWidget* previous_toplevel) {
|
| - GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
|
| - if (!GTK_WIDGET_TOPLEVEL(toplevel))
|
| - return;
|
| -
|
| - signals_.Connect(toplevel, "set-focus", G_CALLBACK(OnSetFocusThunk), this);
|
| -}
|
| -
|
| -void BrowserActionsToolbarGtk::OnSetFocus(GtkWidget* widget,
|
| - GtkWidget* focus_widget) {
|
| - ExtensionPopupGtk* popup = ExtensionPopupGtk::get_current_extension_popup();
|
| - // The focus of the parent window has changed. Close the popup. Delay the hide
|
| - // because it will destroy the RenderViewHost, which may still be on the
|
| - // call stack.
|
| - if (!popup || popup->being_inspected())
|
| - return;
|
| - MessageLoop::current()->PostTask(FROM_HERE,
|
| - method_factory_.NewRunnableMethod(&BrowserActionsToolbarGtk::HidePopup));
|
| -}
|
| -
|
| -gboolean BrowserActionsToolbarGtk::OnGripperMotionNotify(
|
| - GtkWidget* widget, GdkEventMotion* event) {
|
| - if (!(event->state & GDK_BUTTON1_MASK))
|
| - return FALSE;
|
| -
|
| - // Calculate how much the user dragged the gripper and subtract that off the
|
| - // button container's width.
|
| - int distance_dragged = base::i18n::IsRTL() ?
|
| - -event->x :
|
| - event->x - widget->allocation.width;
|
| - gint new_width = button_hbox_->allocation.width - distance_dragged;
|
| - SetButtonHBoxWidth(new_width);
|
| -
|
| - return FALSE;
|
| -}
|
| -
|
| -gboolean BrowserActionsToolbarGtk::OnGripperExpose(GtkWidget* gripper,
|
| - GdkEventExpose* expose) {
|
| - return TRUE;
|
| -}
|
| -
|
| -// These three signal handlers (EnterNotify, LeaveNotify, and ButtonRelease)
|
| -// are used to give the gripper the resize cursor. Since it doesn't have its
|
| -// own window, we have to set the cursor whenever the pointer moves into the
|
| -// button or leaves the button, and be sure to leave it on when the user is
|
| -// dragging.
|
| -gboolean BrowserActionsToolbarGtk::OnGripperEnterNotify(
|
| - GtkWidget* gripper, GdkEventCrossing* event) {
|
| - gdk_window_set_cursor(gripper->window,
|
| - gfx::GetCursor(GDK_SB_H_DOUBLE_ARROW));
|
| - return FALSE;
|
| -}
|
| -
|
| -gboolean BrowserActionsToolbarGtk::OnGripperLeaveNotify(
|
| - GtkWidget* gripper, GdkEventCrossing* event) {
|
| - if (!(event->state & GDK_BUTTON1_MASK))
|
| - gdk_window_set_cursor(gripper->window, NULL);
|
| - return FALSE;
|
| -}
|
| -
|
| -gboolean BrowserActionsToolbarGtk::OnGripperButtonRelease(
|
| - GtkWidget* gripper, GdkEventButton* event) {
|
| - gfx::Rect gripper_rect(0, 0,
|
| - gripper->allocation.width, gripper->allocation.height);
|
| - gfx::Point release_point(event->x, event->y);
|
| - if (!gripper_rect.Contains(release_point))
|
| - gdk_window_set_cursor(gripper->window, NULL);
|
| -
|
| - // After the user resizes the toolbar, we want to smartly resize it to be
|
| - // the perfect size to fit the buttons.
|
| - int visible_icon_count =
|
| - gtk_chrome_shrinkable_hbox_get_visible_child_count(
|
| - GTK_CHROME_SHRINKABLE_HBOX(button_hbox_.get()));
|
| - AnimateToShowNIcons(visible_icon_count);
|
| - model_->SetVisibleIconCount(visible_icon_count);
|
| -
|
| - return FALSE;
|
| -}
|
| -
|
| -gboolean BrowserActionsToolbarGtk::OnGripperButtonPress(
|
| - GtkWidget* gripper, GdkEventButton* event) {
|
| - resize_animation_.Reset();
|
| -
|
| - return FALSE;
|
| -}
|
| -
|
| -gboolean BrowserActionsToolbarGtk::OnOverflowButtonPress(
|
| - GtkWidget* overflow, GdkEventButton* event) {
|
| - overflow_menu_model_.reset(new SimpleMenuModel(this));
|
| -
|
| - int visible_icon_count =
|
| - gtk_chrome_shrinkable_hbox_get_visible_child_count(
|
| - GTK_CHROME_SHRINKABLE_HBOX(button_hbox_.get()));
|
| - for (int i = visible_icon_count; i < button_count(); ++i) {
|
| - int model_index = i;
|
| - if (profile_->IsOffTheRecord())
|
| - model_index = model_->IncognitoIndexToOriginal(i);
|
| -
|
| - const Extension* extension = model_->GetExtensionByIndex(model_index);
|
| - BrowserActionButton* button = extension_button_map_[extension->id()].get();
|
| -
|
| - overflow_menu_model_->AddItem(model_index, UTF8ToUTF16(extension->name()));
|
| - overflow_menu_model_->SetIcon(overflow_menu_model_->GetItemCount() - 1,
|
| - button->GetIcon());
|
| -
|
| - // TODO(estade): set the menu item's tooltip.
|
| - }
|
| -
|
| - overflow_menu_.reset(new MenuGtk(this, overflow_menu_model_.get()));
|
| - signals_.Connect(overflow_menu_->widget(), "button-press-event",
|
| - G_CALLBACK(OnOverflowMenuButtonPressThunk), this);
|
| -
|
| - overflow_button_->SetPaintOverride(GTK_STATE_ACTIVE);
|
| - overflow_menu_->PopupAsFromKeyEvent(chevron());
|
| -
|
| - return FALSE;
|
| -}
|
| -
|
| -gboolean BrowserActionsToolbarGtk::OnOverflowMenuButtonPress(
|
| - GtkWidget* overflow, GdkEventButton* event) {
|
| - if (event->button != 3)
|
| - return FALSE;
|
| -
|
| - GtkWidget* menu_item = GTK_MENU_SHELL(overflow)->active_menu_item;
|
| - if (!menu_item)
|
| - return FALSE;
|
| -
|
| - int item_index = g_list_index(GTK_MENU_SHELL(overflow)->children, menu_item);
|
| - if (item_index == -1) {
|
| - NOTREACHED();
|
| - return FALSE;
|
| - }
|
| -
|
| - item_index += gtk_chrome_shrinkable_hbox_get_visible_child_count(
|
| - GTK_CHROME_SHRINKABLE_HBOX(button_hbox_.get()));
|
| - if (profile_->IsOffTheRecord())
|
| - item_index = model_->IncognitoIndexToOriginal(item_index);
|
| -
|
| - const Extension* extension = model_->GetExtensionByIndex(item_index);
|
| - ExtensionButtonMap::iterator it = extension_button_map_.find(
|
| - extension->id());
|
| - if (it == extension_button_map_.end()) {
|
| - NOTREACHED();
|
| - return FALSE;
|
| - }
|
| -
|
| - it->second.get()->GetContextMenu()->PopupAsContext(event->time);
|
| - return TRUE;
|
| -}
|
| -
|
| -void BrowserActionsToolbarGtk::OnButtonShowOrHide(GtkWidget* sender) {
|
| - if (!resize_animation_.is_animating())
|
| - UpdateChevronVisibility();
|
| -}
|
|
|