summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorjhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-14 22:40:03 +0000
committerjhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-14 22:40:03 +0000
commit8c938a0b244d9d12e2c57576925a2888c3e59fa8 (patch)
tree7c04195c493f8aef49a23c2c1a2505e49495013c /chrome/browser
parent0bbca872a2407e598d4c9257700568c17f591e78 (diff)
downloadchromium_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.cc4
-rw-r--r--chrome/browser/gtk/menu_gtk.h3
-rw-r--r--chrome/browser/gtk/tabs/tab_gtk.cc128
-rw-r--r--chrome/browser/gtk/tabs/tab_gtk.h15
-rw-r--r--chrome/browser/gtk/tabs/tab_strip_gtk.cc10
-rw-r--r--chrome/browser/gtk/tabs/tab_strip_gtk.h1
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;