diff options
author | jhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-14 22:40:03 +0000 |
---|---|---|
committer | jhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-14 22:40:03 +0000 |
commit | 8c938a0b244d9d12e2c57576925a2888c3e59fa8 (patch) | |
tree | 7c04195c493f8aef49a23c2c1a2505e49495013c /chrome/browser | |
parent | 0bbca872a2407e598d4c9257700568c17f591e78 (diff) | |
download | chromium_src-8c938a0b244d9d12e2c57576925a2888c3e59fa8.zip chromium_src-8c938a0b244d9d12e2c57576925a2888c3e59fa8.tar.gz chromium_src-8c938a0b244d9d12e2c57576925a2888c3e59fa8.tar.bz2 |
Implement context menu handling for the Linux tab strip.
Review URL: http://codereview.chromium.org/73053
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@13714 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/gtk/menu_gtk.cc | 4 | ||||
-rw-r--r-- | chrome/browser/gtk/menu_gtk.h | 3 | ||||
-rw-r--r-- | chrome/browser/gtk/tabs/tab_gtk.cc | 128 | ||||
-rw-r--r-- | chrome/browser/gtk/tabs/tab_gtk.h | 15 | ||||
-rw-r--r-- | chrome/browser/gtk/tabs/tab_strip_gtk.cc | 10 | ||||
-rw-r--r-- | chrome/browser/gtk/tabs/tab_strip_gtk.h | 1 |
6 files changed, 152 insertions, 9 deletions
diff --git a/chrome/browser/gtk/menu_gtk.cc b/chrome/browser/gtk/menu_gtk.cc index b9062df..9ae3765 100644 --- a/chrome/browser/gtk/menu_gtk.cc +++ b/chrome/browser/gtk/menu_gtk.cc @@ -81,6 +81,10 @@ void MenuGtk::PopupAsContext(guint32 event_time) { gtk_menu_popup(GTK_MENU(menu_.get()), NULL, NULL, NULL, NULL, 3, event_time); } +void MenuGtk::Cancel() { + gtk_menu_detach(GTK_MENU(menu_.get())); +} + void MenuGtk::BuildMenuIn(GtkWidget* menu, const MenuCreateMaterial* menu_data, GtkAccelGroup* accel_group) { diff --git a/chrome/browser/gtk/menu_gtk.h b/chrome/browser/gtk/menu_gtk.h index 428aae1..d3bd65d 100644 --- a/chrome/browser/gtk/menu_gtk.h +++ b/chrome/browser/gtk/menu_gtk.h @@ -60,6 +60,9 @@ class MenuGtk { // triggering event (e.g. right mouse click, context menu key, etc.). void PopupAsContext(guint32 event_time); + // Closes the menu. + void Cancel(); + private: // A recursive function that transforms a MenuCreateMaterial tree into a set // of GtkMenuItems. diff --git a/chrome/browser/gtk/tabs/tab_gtk.cc b/chrome/browser/gtk/tabs/tab_gtk.cc index 46823fe..02100e1 100644 --- a/chrome/browser/gtk/tabs/tab_gtk.cc +++ b/chrome/browser/gtk/tabs/tab_gtk.cc @@ -4,6 +4,7 @@ #include "chrome/browser/gtk/tabs/tab_gtk.h" +#include "chrome/browser/gtk/menu_gtk.h" #include "chrome/common/gfx/path.h" #include "chrome/common/l10n_util.h" #include "chrome/common/resource_bundle.h" @@ -13,6 +14,107 @@ static const SkScalar kTabCapWidth = 15; static const SkScalar kTabTopCurveWidth = 4; static const SkScalar kTabBottomCurveWidth = 3; +class TabGtk::ContextMenuController : public MenuGtk::Delegate { + public: + explicit ContextMenuController(TabGtk* tab) + : tab_(tab) { + menu_.reset(new MenuGtk(this)); + } + + virtual ~ContextMenuController() {} + + void RunMenu() { + menu_->PopupAsContext(gtk_get_current_event_time()); + } + + void Cancel() { + tab_ = NULL; + menu_->Cancel(); + } + + private: + + // Converts the gtk command id to the tab command id. Gtk includes the + // menu separators, but TabStripModel::ContextMenuCommand does not, so + // readjust the id to take into account separators. + // TODO(jhawkins): Add AppendMenuItemWithLabel and AppendSeparator methods + // to MenuGtk so we can avoid this hacky conversion. + int gtk_command_to_tab_command(int command_id) const { + if (command_id == 1) + return command_id; + else if (command_id < 5) + return command_id - 1; + else + return command_id - 2; + } + + // MenuGtk::Delegate implementation: + virtual bool IsCommandEnabled(int command_id) const { + if (!tab_) + return false; + + TabStripModel::ContextMenuCommand id; + id = static_cast<TabStripModel::ContextMenuCommand>( + gtk_command_to_tab_command(command_id)); + + return tab_->delegate()->IsCommandEnabledForTab(id, tab_); + } + + virtual void ExecuteCommand(int command_id) { + if (!tab_) + return; + + TabStripModel::ContextMenuCommand id; + id = static_cast<TabStripModel::ContextMenuCommand>( + gtk_command_to_tab_command(command_id)); + + tab_->delegate()->ExecuteCommandForTab(id, tab_); + } + + virtual int GetItemCount() const { + return TabStripModel::CommandLast; + } + + virtual bool IsItemSeparator(int command_id) const { + if (command_id == 2 || command_id == 5) + return true; + + return false; + } + + virtual std::string GetLabel(int command_id) const { + switch (command_id) { + case 1: + return WideToUTF8(l10n_util::GetString(IDS_TAB_CXMENU_NEWTAB)); + case 3: + return WideToUTF8(l10n_util::GetString(IDS_TAB_CXMENU_RELOAD)); + case 4: + return WideToUTF8(l10n_util::GetString(IDS_TAB_CXMENU_DUPLICATE)); + case 6: + return WideToUTF8(l10n_util::GetString(IDS_TAB_CXMENU_CLOSETAB)); + case 7: + return WideToUTF8(l10n_util::GetString(IDS_TAB_CXMENU_CLOSEOTHERTABS)); + case 8: + return WideToUTF8(l10n_util::GetString( + IDS_TAB_CXMENU_CLOSETABSTORIGHT)); + case 9: + return WideToUTF8(l10n_util::GetString( + IDS_TAB_CXMENU_CLOSETABSOPENEDBY)); + default: + NOTREACHED(); + return std::string(); + } + } + + // The context menu. + scoped_ptr<MenuGtk> menu_; + + // The Tab the context menu was brought up for. Set to NULL when the menu + // is canceled. + TabGtk* tab_; + + DISALLOW_COPY_AND_ASSIGN(ContextMenuController); +}; /////////////////////////////////////////////////////////////////////////////// // TabGtk, public: @@ -25,6 +127,13 @@ TabGtk::TabGtk(TabDelegate* delegate) } TabGtk::~TabGtk() { + if (menu_controller_.get()) { + // The menu is showing. Close the menu. + menu_controller_->Cancel(); + + // Invoke this so that we hide the highlight. + ContextMenuClosed(); + } } bool TabGtk::IsPointInBounds(const gfx::Point& point) { @@ -61,11 +170,14 @@ bool TabGtk::OnMousePress() { return false; } -void TabGtk::OnMouseRelease() { +void TabGtk::OnMouseRelease(GdkEventButton* event) { mouse_pressed_ = false; - if (close_button_state() == BS_PUSHED) + if (close_button_state() == BS_PUSHED) { delegate_->CloseTab(this); + } else if (event->button == 3) { + ShowContextMenu(); + } } /////////////////////////////////////////////////////////////////////////////// @@ -100,3 +212,15 @@ GdkRegion* TabGtk::MakeRegionForTab()const { gdk_region_offset(region, x(), y()); return region; } + +void TabGtk::ShowContextMenu() { + if (!menu_controller_.get()) + menu_controller_.reset(new ContextMenuController(this)); + + menu_controller_->RunMenu(); +} + +void TabGtk::ContextMenuClosed() { + delegate()->StopAllHighlighting(); + menu_controller_.reset(); +} diff --git a/chrome/browser/gtk/tabs/tab_gtk.h b/chrome/browser/gtk/tabs/tab_gtk.h index b36aaf4..6ef2f4d 100644 --- a/chrome/browser/gtk/tabs/tab_gtk.h +++ b/chrome/browser/gtk/tabs/tab_gtk.h @@ -84,13 +84,23 @@ class TabGtk : public TabRendererGtk { bool OnMousePress(); // Sent by the tabstrip when the mouse click is released. - void OnMouseRelease(); + void OnMouseRelease(GdkEventButton* event); private: + class ContextMenuController; + + friend class ContextMenuController; + // Creates a clickable region of the tab's visual representation. Used for // hit-testing. Caller is responsible for destroying the region. GdkRegion* MakeRegionForTab() const; + // Shows the context menu. + void ShowContextMenu(); + + // Invoked when the context menu closes. + void ContextMenuClosed(); + // An instance of a delegate object that can perform various actions based on // user gestures. TabDelegate* delegate_; @@ -101,6 +111,9 @@ class TabGtk : public TabRendererGtk { // Set if the mouse is pressed anywhere inside the tab. bool mouse_pressed_; + // The context menu controller. + scoped_ptr<ContextMenuController> menu_controller_; + DISALLOW_COPY_AND_ASSIGN(TabGtk); }; diff --git a/chrome/browser/gtk/tabs/tab_strip_gtk.cc b/chrome/browser/gtk/tabs/tab_strip_gtk.cc index 65abf1f..8d6e5fd 100644 --- a/chrome/browser/gtk/tabs/tab_strip_gtk.cc +++ b/chrome/browser/gtk/tabs/tab_strip_gtk.cc @@ -720,7 +720,7 @@ void TabStripGtk::TabChangedAt(TabContents* contents, int index, gtk_widget_queue_draw(tabstrip_.get()); } -/////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// // TabStripGtk, TabGtk::Delegate implementation: bool TabStripGtk::IsTabSelected(const TabGtk* tab) const { @@ -1174,8 +1174,7 @@ gboolean TabStripGtk::OnMotionNotify(GtkWidget* widget, GdkEventMotion* event, // static gboolean TabStripGtk::OnMousePress(GtkWidget* widget, GdkEventButton* event, TabStripGtk* tabstrip) { - // TODO(jhawkins): Handle middle and right-click. - // TODO(jhawkins): Are there no gdk constants for event->button? + // Nothing happens on mouse press for middle and right click. if (event->button != 1) return TRUE; @@ -1200,12 +1199,13 @@ gboolean TabStripGtk::OnMousePress(GtkWidget* widget, GdkEventButton* event, // static gboolean TabStripGtk::OnMouseRelease(GtkWidget* widget, GdkEventButton* event, TabStripGtk* tabstrip) { - if (event->button != 1) + // TODO(jhawkins): Handle middle click. + if (event->button == 2) return TRUE; gfx::Point point(event->x, event->y); if (tabstrip->hover_index_ != -1) { - tabstrip->GetTabAt(tabstrip->hover_index_)->OnMouseRelease(); + tabstrip->GetTabAt(tabstrip->hover_index_)->OnMouseRelease(event); } else if (tabstrip->newtab_button_.get()->IsPointInBounds(point)) { tabstrip->newtab_button_.get()->OnMouseRelease(); } diff --git a/chrome/browser/gtk/tabs/tab_strip_gtk.h b/chrome/browser/gtk/tabs/tab_strip_gtk.h index 6251829..928c87f 100644 --- a/chrome/browser/gtk/tabs/tab_strip_gtk.h +++ b/chrome/browser/gtk/tabs/tab_strip_gtk.h @@ -13,7 +13,6 @@ #include "chrome/browser/gtk/tabs/tab_gtk.h" #include "chrome/browser/tabs/tab_strip_model.h" #include "chrome/common/owned_widget_gtk.h" -#include "skia/include/SkBitmap.h" class NewTabButton; |