summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xbase/gfx/gtk_util.cc53
-rwxr-xr-xbase/gfx/gtk_util.h15
-rw-r--r--chrome/browser/gtk/bookmark_bar_gtk.cc79
-rw-r--r--chrome/browser/gtk/bookmark_bar_gtk.h11
-rw-r--r--chrome/browser/gtk/bookmark_context_menu_gtk.cc353
-rw-r--r--chrome/browser/gtk/bookmark_context_menu_gtk.h116
-rw-r--r--chrome/browser/gtk/find_bar_gtk.cc1
-rw-r--r--chrome/browser/gtk/infobar_container_gtk.cc2
-rw-r--r--chrome/browser/gtk/infobar_gtk.cc1
-rw-r--r--chrome/browser/gtk/location_bar_view_gtk.cc1
-rw-r--r--chrome/browser/gtk/menu_gtk.cc49
-rw-r--r--chrome/browser/gtk/menu_gtk.h5
-rw-r--r--chrome/browser/tab_contents/web_contents_view_gtk.cc2
-rw-r--r--chrome/chrome.gyp8
-rw-r--r--chrome/common/gtk_util.cc81
-rw-r--r--chrome/common/gtk_util.h41
-rw-r--r--chrome/common/resource_bundle_linux.cc1
17 files changed, 700 insertions, 119 deletions
diff --git a/base/gfx/gtk_util.cc b/base/gfx/gtk_util.cc
index c307976..e01a2bd 100755
--- a/base/gfx/gtk_util.cc
+++ b/base/gfx/gtk_util.cc
@@ -8,16 +8,6 @@
#include <gtk/gtk.h>
#include "base/gfx/rect.h"
-#include "skia/include/SkBitmap.h"
-
-namespace {
-
-// Callback used in RemoveAllChildren.
-void RemoveWidget(GtkWidget* widget, gpointer container) {
- gtk_container_remove(GTK_CONTAINER(container), widget);
-}
-
-} // namespace
namespace gfx {
@@ -36,10 +26,6 @@ void SubtractRectanglesFromRegion(GdkRegion* region,
}
}
-static void FreePixels(guchar* pixels, gpointer data) {
- free(data);
-}
-
uint8_t* BGRAToRGBA(const uint8_t* pixels, int width, int height, int stride) {
if (stride == 0)
stride = width * 4;
@@ -60,43 +46,4 @@ uint8_t* BGRAToRGBA(const uint8_t* pixels, int width, int height, int stride) {
return new_pixels;
}
-GdkPixbuf* GdkPixbufFromSkBitmap(const SkBitmap* bitmap) {
- bitmap->lockPixels();
- int width = bitmap->width();
- int height = bitmap->height();
- int stride = bitmap->rowBytes();
- const guchar* orig_data = static_cast<guchar*>(bitmap->getPixels());
- guchar* data = BGRAToRGBA(orig_data, width, height, stride);
-
- // This pixbuf takes ownership of our malloc()ed data and will
- // free it for us when it is destroyed.
- GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(
- data,
- GDK_COLORSPACE_RGB, // The only colorspace gtk supports.
- true, // There is an alpha channel.
- 8,
- width, height, stride, &FreePixels, data);
-
- bitmap->unlockPixels();
- return pixbuf;
-}
-
-GtkWidget* CreateGtkBorderBin(GtkWidget* child, const GdkColor* color,
- int top, int bottom, int left, int right) {
- // Use a GtkEventBox to get the background painted. However, we can't just
- // use a container border, since it won't paint there. Use an alignment
- // inside to get the sizes exactly of how we want the border painted.
- GtkWidget* ebox = gtk_event_box_new();
- gtk_widget_modify_bg(ebox, GTK_STATE_NORMAL, color);
- GtkWidget* alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
- gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), top, bottom, left, right);
- gtk_container_add(GTK_CONTAINER(alignment), child);
- gtk_container_add(GTK_CONTAINER(ebox), alignment);
- return ebox;
-}
-
-void RemoveAllChildren(GtkWidget* container) {
- gtk_container_foreach(GTK_CONTAINER(container), RemoveWidget, container);
-}
-
} // namespace gfx
diff --git a/base/gfx/gtk_util.h b/base/gfx/gtk_util.h
index f2f860f..3a1a1d4 100755
--- a/base/gfx/gtk_util.h
+++ b/base/gfx/gtk_util.h
@@ -9,10 +9,7 @@
#include <vector>
typedef struct _GdkColor GdkColor;
-typedef struct _GdkPixbuf GdkPixbuf;
typedef struct _GdkRegion GdkRegion;
-typedef struct _GtkWidget GtkWidget;
-class SkBitmap;
// Define a macro for creating GdkColors from RGB values. This is a macro to
// allow static construction of literals, etc. Use this like:
@@ -36,18 +33,6 @@ void SubtractRectanglesFromRegion(GdkRegion* region,
// it's assumed to be 4 * |width|.
uint8_t* BGRAToRGBA(const uint8_t* pixels, int width, int height, int stride);
-// Convert and copy a SkBitmap to a GdkPixbuf. NOTE: this uses BGRAToRGBA, so
-// it is an expensive operation.
-GdkPixbuf* GdkPixbufFromSkBitmap(const SkBitmap* bitmap);
-
-// Create a GtkBin with |child| as its child widget. This bin will paint a
-// border of color |color| with the sizes specified in pixels.
-GtkWidget* CreateGtkBorderBin(GtkWidget* child, const GdkColor* color,
- int top, int bottom, int left, int right);
-
-// Remove all children from this container.
-void RemoveAllChildren(GtkWidget* container);
-
} // namespace gfx
#endif // BASE_GFX_GTK_UTIL_H_
diff --git a/chrome/browser/gtk/bookmark_bar_gtk.cc b/chrome/browser/gtk/bookmark_bar_gtk.cc
index 4c8abea..7819ad4 100644
--- a/chrome/browser/gtk/bookmark_bar_gtk.cc
+++ b/chrome/browser/gtk/bookmark_bar_gtk.cc
@@ -5,12 +5,15 @@
#include "chrome/browser/gtk/bookmark_bar_gtk.h"
#include "base/gfx/gtk_util.h"
+#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/browser.h"
+#include "chrome/browser/gtk/bookmark_context_menu_gtk.h"
#include "chrome/browser/gtk/custom_button.h"
#include "chrome/browser/gtk/gtk_chrome_button.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/profile.h"
#include "chrome/common/gfx/text_elider.h"
+#include "chrome/common/gtk_util.h"
#include "chrome/common/l10n_util.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"
@@ -115,16 +118,20 @@ void BookmarkBarGtk::Init(Profile* profile) {
G_CALLBACK(&OnToolbarDragLeave), this);
g_signal_connect(bookmark_toolbar_.get(), "drag-drop",
G_CALLBACK(&OnToolbarDragDrop), this);
+ g_signal_connect(bookmark_toolbar_.get(), "button-press-event",
+ G_CALLBACK(&OnButtonPressed), this);
gtk_box_pack_start(GTK_BOX(bookmark_hbox_), gtk_vseparator_new(),
FALSE, FALSE, 0);
other_bookmarks_button_ = gtk_chrome_button_new();
+ g_signal_connect(other_bookmarks_button_, "button-press-event",
+ G_CALLBACK(&OnButtonPressed), this);
gtk_button_set_label(GTK_BUTTON(other_bookmarks_button_),
"Other bookmarks");
gtk_button_set_image(GTK_BUTTON(other_bookmarks_button_),
gtk_image_new_from_pixbuf(folder_icon));
- // TODO(erg): Hook up a popup menu to |other_bookmarks_button_|.
+
gtk_box_pack_start(GTK_BOX(bookmark_hbox_), other_bookmarks_button_,
FALSE, FALSE, 0);
}
@@ -343,8 +350,16 @@ std::string BookmarkBarGtk::BuildTooltip(BookmarkNode* node) {
return node->GetURL().possibly_invalid_spec();
}
-BookmarkNode* BookmarkBarGtk::GetNodeForToolButton(GtkWidget* button) {
- GtkWidget* item_to_find = gtk_widget_get_parent(button);
+BookmarkNode* BookmarkBarGtk::GetNodeForToolButton(GtkWidget* widget) {
+ // First check to see if |button| is the special cased.
+ if (widget == other_bookmarks_button_)
+ return model_->other_node();
+ else if (widget == bookmark_toolbar_.get())
+ return model_->GetBookmarkBarNode();
+
+ // Search the contents of |bookmark_toolbar_| for the corresponding widget
+ // and find its index.
+ GtkWidget* item_to_find = gtk_widget_get_parent(widget);
int index_to_use = -1;
int index = 0;
GList* children = gtk_container_get_children(
@@ -363,20 +378,49 @@ BookmarkNode* BookmarkBarGtk::GetNodeForToolButton(GtkWidget* button) {
return NULL;
}
-void BookmarkBarGtk::PopupMenuForNode(BookmarkNode* node,
+void BookmarkBarGtk::PopupMenuForNode(GtkWidget* sender, BookmarkNode* node,
GdkEventButton* event) {
- GtkWidget* menu = gtk_menu_new();
- gtk_menu_shell_append(GTK_MENU_SHELL(menu),
- gtk_menu_item_new_with_label("TODO(erg): Write menus"));
- gtk_widget_show_all(menu);
- gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button,
- event->time);
+ if (!model_->IsLoaded()) {
+ // Don't do anything if the model isn't loaded.
+ return;
+ }
+
+ BookmarkNode* parent = NULL;
+ std::vector<BookmarkNode*> nodes;
+ if (sender == other_bookmarks_button_) {
+ parent = model_->GetBookmarkBarNode();
+ nodes.push_back(parent);
+ } else if (sender != bookmark_toolbar_.get()) {
+ nodes.push_back(node);
+ parent = node->GetParent();
+ } else {
+ parent = model_->GetBookmarkBarNode();
+ nodes.push_back(parent);
+ }
+
+ current_context_menu_.reset(new BookmarkContextMenuGtk(
+ GTK_WINDOW(gtk_widget_get_toplevel(sender)),
+ profile_, browser_, page_navigator_,
+ parent, nodes,
+ BookmarkContextMenuGtk::BOOKMARK_BAR));
+ current_context_menu_->PopupAsContext(event->time);
}
+// static
gboolean BookmarkBarGtk::OnButtonPressed(GtkWidget* sender,
GdkEventButton* event,
BookmarkBarGtk* bar) {
- bar->ignore_button_release_ = false;
+ if (sender != bar->other_bookmarks_button_ &&
+ sender != bar->bookmark_toolbar_.get())
+ bar->ignore_button_release_ = false;
+
+ if (event->button == 3) {
+ BookmarkNode* node = bar->GetNodeForToolButton(sender);
+ DCHECK(node);
+ DCHECK(bar->page_navigator_);
+ bar->PopupMenuForNode(sender, node, event);
+ }
+
return FALSE;
}
@@ -393,19 +437,16 @@ gboolean BookmarkBarGtk::OnButtonReleased(GtkWidget* sender,
DCHECK(node);
DCHECK(bar->page_navigator_);
- if (event->button == 3) {
- bar->PopupMenuForNode(node, event);
- return FALSE;
- }
-
if (node->is_url()) {
bar->page_navigator_->OpenURL(
node->GetURL(), GURL(),
- // TODO(erg): Detect the disposition based on the click type.
- CURRENT_TAB,
+ event_utils::DispositionFromEventFlags(event->state),
PageTransition::AUTO_BOOKMARK);
} else {
- // TODO(erg): Handle folders and extensions.
+ bookmark_utils::OpenAll(
+ GTK_WINDOW(gtk_widget_get_toplevel(sender)), bar->profile_,
+ bar->page_navigator_, node,
+ event_utils::DispositionFromEventFlags(event->state));
}
UserMetrics::RecordAction(L"ClickedBookmarkBarURLButton", bar->profile_);
diff --git a/chrome/browser/gtk/bookmark_bar_gtk.h b/chrome/browser/gtk/bookmark_bar_gtk.h
index d45fcdbb..930a26f 100644
--- a/chrome/browser/gtk/bookmark_bar_gtk.h
+++ b/chrome/browser/gtk/bookmark_bar_gtk.h
@@ -13,6 +13,7 @@
#include "chrome/common/owned_widget_gtk.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
+class BookmarkContextMenuGtk;
class Browser;
class CustomContainerButton;
class PageNavigator;
@@ -111,13 +112,15 @@ class BookmarkBarGtk : public BookmarkModelObserver {
BookmarkNode* GetNodeForToolButton(GtkWidget* button);
// Creates and displays a popup menu for BookmarkNode |node|.
- void PopupMenuForNode(BookmarkNode* node, GdkEventButton* event);
+ void PopupMenuForNode(GtkWidget* sender, BookmarkNode* node,
+ GdkEventButton* event);
// GtkButton callbacks
static gboolean OnButtonPressed(GtkWidget* sender,
GdkEventButton* event,
BookmarkBarGtk* bar);
- static gboolean OnButtonReleased(GtkWidget* sender, GdkEventButton* event,
+ static gboolean OnButtonReleased(GtkWidget* sender,
+ GdkEventButton* event,
BookmarkBarGtk* bar);
static gboolean OnButtonExpose(GtkWidget* widget, GdkEventExpose* e,
BookmarkBarGtk* button);
@@ -188,6 +191,10 @@ class BookmarkBarGtk : public BookmarkModelObserver {
// Whether we should show the instructional text in the bookmark bar.
bool show_instructions_;
+
+ // The last displayed right click menu, or NULL if no menus have been
+ // displayed yet.
+ scoped_ptr<BookmarkContextMenuGtk> current_context_menu_;
};
#endif // CHROME_BROWSER_GTK_BOOKMARK_BAR_GTK_H_
diff --git a/chrome/browser/gtk/bookmark_context_menu_gtk.cc b/chrome/browser/gtk/bookmark_context_menu_gtk.cc
new file mode 100644
index 0000000..f6fc56f
--- /dev/null
+++ b/chrome/browser/gtk/bookmark_context_menu_gtk.cc
@@ -0,0 +1,353 @@
+// Copyright (c) 2009 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/bookmark_context_menu_gtk.h"
+
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/bookmarks/bookmark_utils.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/profile.h"
+#include "chrome/common/l10n_util.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+
+namespace {
+
+// Returns true if the specified node is of type URL, or has a descendant
+// of type URL.
+bool NodeHasURLs(BookmarkNode* node) {
+ if (node->is_url())
+ return true;
+
+ for (int i = 0; i < node->GetChildCount(); ++i) {
+ if (NodeHasURLs(node->GetChild(i)))
+ return true;
+ }
+ return false;
+}
+
+} // namespace
+
+BookmarkContextMenuGtk::BookmarkContextMenuGtk(
+ GtkWindow* window,
+ Profile* profile,
+ Browser* browser,
+ PageNavigator* navigator,
+ BookmarkNode* parent,
+ const std::vector<BookmarkNode*>& selection,
+ ConfigurationType configuration)
+ : window_(window),
+ profile_(profile),
+ browser_(browser),
+ navigator_(navigator),
+ parent_(parent),
+ selection_(selection),
+ model_(profile->GetBookmarkModel()),
+ configuration_(configuration),
+ menu_(new MenuGtk(this, false)) {
+ if (configuration != BOOKMARK_MANAGER_ORGANIZE_MENU) {
+ if (selection.size() == 1 && selection[0]->is_url()) {
+ AppendItem(IDS_BOOMARK_BAR_OPEN_ALL, IDS_BOOMARK_BAR_OPEN_IN_NEW_TAB);
+ AppendItem(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW,
+ IDS_BOOMARK_BAR_OPEN_IN_NEW_WINDOW);
+ AppendItem(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO,
+ IDS_BOOMARK_BAR_OPEN_INCOGNITO);
+ } else {
+ AppendItem(IDS_BOOMARK_BAR_OPEN_ALL, IDS_BOOMARK_BAR_OPEN_ALL);
+ AppendItem(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW,
+ IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW);
+ AppendItem(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO,
+ IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO);
+ }
+ AppendSeparator();
+ }
+
+ if (selection.size() == 1 && selection[0]->is_folder()) {
+ AppendItem(IDS_BOOKMARK_BAR_RENAME_FOLDER);
+ } else {
+ AppendItem(IDS_BOOKMARK_BAR_EDIT);
+ }
+ AppendItem(IDS_BOOKMARK_BAR_REMOVE);
+
+ if (configuration == BOOKMARK_MANAGER_TABLE ||
+ configuration == BOOKMARK_MANAGER_TABLE_OTHER ||
+ configuration == BOOKMARK_MANAGER_ORGANIZE_MENU ||
+ configuration == BOOKMARK_MANAGER_ORGANIZE_MENU_OTHER) {
+ AppendItem(IDS_BOOKMARK_MANAGER_SHOW_IN_FOLDER);
+ }
+
+ if (configuration == BOOKMARK_MANAGER_TABLE ||
+ configuration == BOOKMARK_MANAGER_TABLE_OTHER ||
+ configuration == BOOKMARK_MANAGER_TREE ||
+ configuration == BOOKMARK_MANAGER_ORGANIZE_MENU ||
+ configuration == BOOKMARK_MANAGER_ORGANIZE_MENU_OTHER) {
+ AppendSeparator();
+ AppendItem(IDS_CUT);
+ AppendItem(IDS_COPY);
+ AppendItem(IDS_PASTE);
+ }
+
+ if (configuration == BOOKMARK_MANAGER_ORGANIZE_MENU) {
+ AppendSeparator();
+ AppendItem(IDS_BOOKMARK_MANAGER_SORT);
+ }
+
+ AppendSeparator();
+
+ AppendItem(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK);
+ AppendItem(IDS_BOOMARK_BAR_NEW_FOLDER);
+
+ if (configuration == BOOKMARK_BAR) {
+ AppendSeparator();
+ AppendItem(IDS_BOOKMARK_MANAGER);
+ AppendItem(IDS_BOOMARK_BAR_ALWAYS_SHOW);
+ }
+
+ model_->AddObserver(this);
+}
+
+BookmarkContextMenuGtk::~BookmarkContextMenuGtk() {
+ if (model_)
+ model_->RemoveObserver(this);
+}
+
+void BookmarkContextMenuGtk::PopupAsContext(guint32 event_time) {
+ menu_->PopupAsContext(event_time);
+}
+
+bool BookmarkContextMenuGtk::IsCommandEnabled(int index) const {
+ bool is_root_node =
+ (selection_.size() == 1 &&
+ selection_[0]->GetParent() == model_->root_node());
+ switch (index) {
+ case IDS_BOOMARK_BAR_OPEN_INCOGNITO:
+ return !profile_->IsOffTheRecord();
+
+ case IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO:
+ return HasURLs() && !profile_->IsOffTheRecord();
+
+ case IDS_BOOMARK_BAR_OPEN_ALL:
+ case IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW:
+ return HasURLs();
+
+ case IDS_BOOKMARK_BAR_RENAME_FOLDER:
+ case IDS_BOOKMARK_BAR_EDIT:
+ return selection_.size() == 1 && !is_root_node;
+
+ case IDS_BOOKMARK_BAR_REMOVE:
+ return !selection_.empty() && !is_root_node;
+
+ case IDS_BOOKMARK_MANAGER_SHOW_IN_FOLDER:
+ return (configuration_ == BOOKMARK_MANAGER_TABLE_OTHER ||
+ configuration_ == BOOKMARK_MANAGER_ORGANIZE_MENU_OTHER) &&
+ selection_.size() == 1;
+
+ case IDS_BOOKMARK_MANAGER_SORT:
+ return parent_ && parent_ != model_->root_node();
+
+ case IDS_BOOMARK_BAR_NEW_FOLDER:
+ case IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK:
+ return GetParentForNewNodes() != NULL;
+
+ case IDS_COPY:
+ case IDS_CUT:
+ return selection_.size() > 0 && !is_root_node;
+
+ // TODO(erg): Port boomark_utils::CanPasteFromClipboard
+ // case IDS_PASTE:
+ // // Always paste to parent.
+ // return bookmark_utils::CanPasteFromClipboard(parent_);
+ }
+ return true;
+}
+
+void BookmarkContextMenuGtk::ExecuteCommand(int index) {
+ switch (index) {
+ case IDS_BOOMARK_BAR_OPEN_ALL:
+ case IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO:
+ case IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW: {
+ PageNavigator* navigator = browser_ ?
+ browser_->GetSelectedTabContents() : navigator_;
+ WindowOpenDisposition initial_disposition;
+ if (index == IDS_BOOMARK_BAR_OPEN_ALL) {
+ initial_disposition = NEW_FOREGROUND_TAB;
+ UserMetrics::RecordAction(L"BookmarkBar_ContextMenu_OpenAll",
+ profile_);
+ } else if (index == IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW) {
+ initial_disposition = NEW_WINDOW;
+ UserMetrics::RecordAction(
+ L"BookmarkBar_ContextMenu_OpenAllInNewWindow", profile_);
+ } else {
+ initial_disposition = OFF_THE_RECORD;
+ UserMetrics::RecordAction(
+ L"BookmarkBar_ContextMenu_OpenAllIncognito", profile_);
+ }
+
+ bookmark_utils::OpenAll(window_, profile_, navigator,
+ selection_, initial_disposition);
+ break;
+ }
+
+ case IDS_BOOKMARK_BAR_RENAME_FOLDER:
+ case IDS_BOOKMARK_BAR_EDIT: {
+ UserMetrics::RecordAction(L"BookmarkBar_ContextMenu_Edit", profile_);
+
+ if (selection_.size() != 1) {
+ NOTREACHED();
+ return;
+ }
+
+ if (selection_[0]->is_url()) {
+ NOTIMPLEMENTED() << "Bookmark editor not implemented";
+ } else {
+ NOTIMPLEMENTED() << "Folder editor not implemented";
+ }
+ break;
+ }
+
+ case IDS_BOOKMARK_BAR_REMOVE: {
+ UserMetrics::RecordAction(L"BookmarkBar_ContextMenu_Remove", profile_);
+ BookmarkModel* model = RemoveModelObserver();
+
+ for (size_t i = 0; i < selection_.size(); ++i) {
+ model->Remove(selection_[i]->GetParent(),
+ selection_[i]->GetParent()->IndexOfChild(selection_[i]));
+ }
+ selection_.clear();
+ break;
+ }
+
+ case IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK: {
+ UserMetrics::RecordAction(L"BookmarkBar_ContextMenu_Add", profile_);
+ NOTIMPLEMENTED() << "Adding new bookmark not implemented";
+ break;
+ }
+
+ case IDS_BOOMARK_BAR_NEW_FOLDER: {
+ UserMetrics::RecordAction(L"BookmarkBar_ContextMenu_NewFolder",
+ profile_);
+
+ NOTIMPLEMENTED() << "EditFolderController not implemented";
+ break;
+ }
+
+ case IDS_BOOMARK_BAR_ALWAYS_SHOW: {
+ bookmark_utils::ToggleWhenVisible(profile_);
+ break;
+ }
+
+ case IDS_BOOKMARK_MANAGER_SHOW_IN_FOLDER: {
+ UserMetrics::RecordAction(L"BookmarkBar_ContextMenu_ShowInFolder",
+ profile_);
+
+ if (selection_.size() != 1) {
+ NOTREACHED();
+ return;
+ }
+
+ NOTIMPLEMENTED() << "Bookmark Manager not implemented";
+ break;
+ }
+
+ case IDS_BOOKMARK_MANAGER: {
+ UserMetrics::RecordAction(L"ShowBookmarkManager", profile_);
+ NOTIMPLEMENTED() << "Bookmark Manager not implemented";
+ break;
+ }
+
+ case IDS_BOOKMARK_MANAGER_SORT: {
+ UserMetrics::RecordAction(L"BookmarkManager_Sort", profile_);
+ model_->SortChildren(parent_);
+ break;
+ }
+
+ case IDS_COPY:
+ case IDS_CUT:
+ case IDS_PASTE: {
+ NOTIMPLEMENTED() << "Cut/Copy/Paste not implemented";
+ break;
+ }
+
+ default:
+ NOTREACHED();
+ }
+}
+
+void BookmarkContextMenuGtk::AppendItem(int id) {
+ menu_->AppendMenuItemWithLabel(
+ id,
+ MenuGtk::ConvertAcceleratorsFromWindowsStyle(
+ l10n_util::GetStringUTF8(id)));
+}
+
+void BookmarkContextMenuGtk::AppendItem(int id, int localization_id) {
+ menu_->AppendMenuItemWithLabel(
+ id,
+ MenuGtk::ConvertAcceleratorsFromWindowsStyle(
+ l10n_util::GetStringUTF8(localization_id)));
+}
+
+void BookmarkContextMenuGtk::AppendSeparator() {
+ menu_->AppendSeparator();
+}
+
+void BookmarkContextMenuGtk::BookmarkModelBeingDeleted(BookmarkModel* model) {
+ ModelChanged();
+}
+
+void BookmarkContextMenuGtk::BookmarkNodeMoved(BookmarkModel* model,
+ BookmarkNode* old_parent,
+ int old_index,
+ BookmarkNode* new_parent,
+ int new_index) {
+ ModelChanged();
+}
+
+void BookmarkContextMenuGtk::BookmarkNodeAdded(BookmarkModel* model,
+ BookmarkNode* parent,
+ int index) {
+ ModelChanged();
+}
+
+void BookmarkContextMenuGtk::BookmarkNodeRemoved(BookmarkModel* model,
+ BookmarkNode* parent,
+ int index,
+ BookmarkNode* node) {
+ ModelChanged();
+}
+
+void BookmarkContextMenuGtk::BookmarkNodeChanged(BookmarkModel* model,
+ BookmarkNode* node) {
+ ModelChanged();
+}
+
+void BookmarkContextMenuGtk::BookmarkNodeChildrenReordered(BookmarkModel* model,
+ BookmarkNode* node) {
+ ModelChanged();
+}
+
+void BookmarkContextMenuGtk::ModelChanged() {
+ menu_->Cancel();
+}
+
+BookmarkModel* BookmarkContextMenuGtk::RemoveModelObserver() {
+ BookmarkModel* model = model_;
+ model_->RemoveObserver(this);
+ model_ = NULL;
+ return model;
+}
+
+bool BookmarkContextMenuGtk::HasURLs() const {
+ for (size_t i = 0; i < selection_.size(); ++i) {
+ if (NodeHasURLs(selection_[i]))
+ return true;
+ }
+ return false;
+}
+
+BookmarkNode* BookmarkContextMenuGtk::GetParentForNewNodes() const {
+ return (selection_.size() == 1 && selection_[0]->is_folder()) ?
+ selection_[0] : parent_;
+}
diff --git a/chrome/browser/gtk/bookmark_context_menu_gtk.h b/chrome/browser/gtk/bookmark_context_menu_gtk.h
new file mode 100644
index 0000000..26ecee1a
--- /dev/null
+++ b/chrome/browser/gtk/bookmark_context_menu_gtk.h
@@ -0,0 +1,116 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_GTK_BOOKMARK_CONTEXT_MENU_GTK_H_
+#define CHROME_BROWSER_GTK_BOOKMARK_CONTEXT_MENU_GTK_H_
+
+#include <vector>
+
+#include "base/gfx/native_widget_types.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/gtk/menu_gtk.h"
+
+class Profile;
+class Browser;
+class PageNavigator;
+
+typedef struct _GtkWindow GtkWindow;
+
+// The context menu that opens or modifies bookmarks. (This is not the menu
+// that displays folders contents.)
+//
+// TODO(erg): This is a copy of
+// ./browser/bookmarks/bookmark_context_menu.{cc,h} and should be merged with
+// that file once it is sufficiently de-views-ed.
+class BookmarkContextMenuGtk : public MenuGtk::Delegate,
+ public BookmarkModelObserver {
+ public:
+ // Used to configure what the context menu shows.
+ enum ConfigurationType {
+ BOOKMARK_BAR,
+ BOOKMARK_MANAGER_TABLE,
+ // Used when the source is the table in the bookmark manager and the table
+ // is showing recently bookmarked or searched.
+ BOOKMARK_MANAGER_TABLE_OTHER,
+ BOOKMARK_MANAGER_TREE,
+ BOOKMARK_MANAGER_ORGANIZE_MENU,
+ // Used when the source is the bookmark manager and the table is showing
+ // recently bookmarked or searched.
+ BOOKMARK_MANAGER_ORGANIZE_MENU_OTHER
+ };
+
+ BookmarkContextMenuGtk(GtkWindow* window,
+ Profile* profile,
+ Browser* browser,
+ PageNavigator* navigator,
+ BookmarkNode* parent,
+ const std::vector<BookmarkNode*>& selection,
+ ConfigurationType configuration);
+ virtual ~BookmarkContextMenuGtk();
+
+ // Pops up this menu.
+ void PopupAsContext(guint32 event_time);
+
+ // Overridden from MenuGtk::Delegate:
+ virtual bool IsCommandEnabled(int index) const;
+ virtual void ExecuteCommand(int index);
+
+ private:
+ // BookmarkModelObserver method. Any change to the model results in closing
+ // the menu.
+ virtual void Loaded(BookmarkModel* model) {}
+ virtual void BookmarkModelBeingDeleted(BookmarkModel* model);
+ virtual void BookmarkNodeMoved(BookmarkModel* model,
+ BookmarkNode* old_parent,
+ int old_index,
+ BookmarkNode* new_parent,
+ int new_index);
+ virtual void BookmarkNodeAdded(BookmarkModel* model,
+ BookmarkNode* parent,
+ int index);
+ virtual void BookmarkNodeRemoved(BookmarkModel* model,
+ BookmarkNode* parent,
+ int index,
+ BookmarkNode* node);
+ virtual void BookmarkNodeChanged(BookmarkModel* model,
+ BookmarkNode* node);
+ virtual void BookmarkNodeFavIconLoaded(BookmarkModel* model,
+ BookmarkNode* node) {}
+ virtual void BookmarkNodeChildrenReordered(BookmarkModel* model,
+ BookmarkNode* node);
+
+ // Adds a IDS_* style command to the menu.
+ void AppendItem(int id);
+ // Adds a IDS_* style command to the menu with a different localized string.
+ void AppendItem(int id, int localization_id);
+ // Adds a separator to the menu.
+ void AppendSeparator();
+
+ // Invoked from the various bookmark model observer methods. Closes the menu.
+ void ModelChanged();
+
+ // Removes the observer from the model and NULLs out model_.
+ BookmarkModel* RemoveModelObserver();
+
+ // Returns true if selection_ has at least one bookmark of type url.
+ bool HasURLs() const;
+
+ // Returns the parent for newly created folders/bookmarks. If selection_
+ // has one element and it is a folder, selection_[0] is returned, otherwise
+ // parent_ is returned.
+ BookmarkNode* GetParentForNewNodes() const;
+
+ gfx::NativeWindow window_;
+ Profile* profile_;
+ Browser* browser_;
+ PageNavigator* navigator_;
+ BookmarkNode* parent_;
+ std::vector<BookmarkNode*> selection_;
+ BookmarkModel* model_;
+ ConfigurationType configuration_;
+
+ scoped_ptr<MenuGtk> menu_;
+};
+
+#endif // CHROME_BROWSER_GTK_BOOKMARK_CONTEXT_MENU_GTK_H_
diff --git a/chrome/browser/gtk/find_bar_gtk.cc b/chrome/browser/gtk/find_bar_gtk.cc
index b7c7845..e30da63 100644
--- a/chrome/browser/gtk/find_bar_gtk.cc
+++ b/chrome/browser/gtk/find_bar_gtk.cc
@@ -13,6 +13,7 @@
#include "chrome/browser/gtk/custom_button.h"
#include "chrome/browser/gtk/tab_contents_container_gtk.h"
#include "chrome/browser/tab_contents/web_contents.h"
+#include "chrome/common/gtk_util.h"
#include "chrome/common/l10n_util.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/gtk/infobar_container_gtk.cc b/chrome/browser/gtk/infobar_container_gtk.cc
index cc8543d..b30333e 100644
--- a/chrome/browser/gtk/infobar_container_gtk.cc
+++ b/chrome/browser/gtk/infobar_container_gtk.cc
@@ -6,11 +6,11 @@
#include <gtk/gtk.h>
-#include "base/gfx/gtk_util.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/gtk/infobar_gtk.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/gtk_util.h"
#include "chrome/common/notification_service.h"
namespace {
diff --git a/chrome/browser/gtk/infobar_gtk.cc b/chrome/browser/gtk/infobar_gtk.cc
index a8456b7..06dd38b 100644
--- a/chrome/browser/gtk/infobar_gtk.cc
+++ b/chrome/browser/gtk/infobar_gtk.cc
@@ -11,6 +11,7 @@
#include "chrome/browser/gtk/custom_button.h"
#include "chrome/browser/gtk/infobar_container_gtk.h"
#include "chrome/browser/gtk/link_button_gtk.h"
+#include "chrome/common/gtk_util.h"
namespace {
diff --git a/chrome/browser/gtk/location_bar_view_gtk.cc b/chrome/browser/gtk/location_bar_view_gtk.cc
index 845b7dd..8c858e4 100644
--- a/chrome/browser/gtk/location_bar_view_gtk.cc
+++ b/chrome/browser/gtk/location_bar_view_gtk.cc
@@ -15,6 +15,7 @@
#include "chrome/browser/autocomplete/autocomplete_edit_view_gtk.h"
#include "chrome/browser/command_updater.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/gtk_util.h"
#include "chrome/common/page_transition_types.h"
#include "skia/include/SkBitmap.h"
#include "webkit/glue/window_open_disposition.h"
diff --git a/chrome/browser/gtk/menu_gtk.cc b/chrome/browser/gtk/menu_gtk.cc
index 059755a..0b2bda0 100644
--- a/chrome/browser/gtk/menu_gtk.cc
+++ b/chrome/browser/gtk/menu_gtk.cc
@@ -4,36 +4,12 @@
#include "chrome/browser/gtk/menu_gtk.h"
-#include "base/gfx/gtk_util.h"
#include "base/logging.h"
#include "base/string_util.h"
+#include "chrome/common/gtk_util.h"
#include "chrome/common/l10n_util.h"
#include "skia/include/SkBitmap.h"
-namespace {
-
-// GTK uses _ for accelerators. Windows uses & with && as an escape for &.
-std::string ConvertAcceleratorsFromWindowsStyle(const std::string& label) {
- std::string ret;
- ret.reserve(label.length());
- for (size_t i = 0; i < label.length(); ++i) {
- if ('&' == label[i]) {
- if (i + 1 < label.length() && '&' == label[i + 1]) {
- ret.push_back(label[i]);
- ++i;
- } else {
- ret.push_back('_');
- }
- } else {
- ret.push_back(label[i]);
- }
- }
-
- return ret;
-}
-
-} // namespace
-
MenuGtk::MenuGtk(MenuGtk::Delegate* delegate,
const MenuCreateMaterial* menu_data,
GtkAccelGroup* accel_group)
@@ -103,7 +79,28 @@ void MenuGtk::PopupAsContext(guint32 event_time) {
}
void MenuGtk::Cancel() {
- gtk_menu_detach(GTK_MENU(menu_.get()));
+ gtk_menu_popdown(GTK_MENU(menu_.get()));
+}
+
+// static
+std::string MenuGtk::ConvertAcceleratorsFromWindowsStyle(
+ const std::string& label) {
+ std::string ret;
+ ret.reserve(label.length());
+ for (size_t i = 0; i < label.length(); ++i) {
+ if ('&' == label[i]) {
+ if (i + 1 < label.length() && '&' == label[i + 1]) {
+ ret.push_back(label[i]);
+ ++i;
+ } else {
+ ret.push_back('_');
+ }
+ } else {
+ ret.push_back(label[i]);
+ }
+ }
+
+ return ret;
}
void MenuGtk::BuildMenuIn(GtkWidget* menu,
diff --git a/chrome/browser/gtk/menu_gtk.h b/chrome/browser/gtk/menu_gtk.h
index 9b9a724..371ed58 100644
--- a/chrome/browser/gtk/menu_gtk.h
+++ b/chrome/browser/gtk/menu_gtk.h
@@ -67,6 +67,11 @@ class MenuGtk {
// Closes the menu.
void Cancel();
+ // Change windows accelerator style to GTK style. (GTK uses _ for
+ // accelerators. Windows uses & with && as an escape for &.)
+ static std::string ConvertAcceleratorsFromWindowsStyle(
+ const std::string& label);
+
private:
// A recursive function that transforms a MenuCreateMaterial tree into a set
// of GtkMenuItems.
diff --git a/chrome/browser/tab_contents/web_contents_view_gtk.cc b/chrome/browser/tab_contents/web_contents_view_gtk.cc
index 4187c38..96c95f3 100644
--- a/chrome/browser/tab_contents/web_contents_view_gtk.cc
+++ b/chrome/browser/tab_contents/web_contents_view_gtk.cc
@@ -8,7 +8,6 @@
#include <gtk/gtk.h>
#include "base/string_util.h"
-#include "base/gfx/gtk_util.h"
#include "base/gfx/point.h"
#include "base/gfx/rect.h"
#include "chrome/browser/gtk/browser_window_gtk.h"
@@ -18,6 +17,7 @@
#include "chrome/browser/tab_contents/render_view_context_menu_gtk.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/browser/tab_contents/web_contents.h"
+#include "chrome/common/gtk_util.h"
namespace {
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 4f20c80..350d84f 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -13,13 +13,13 @@
'sources/': [
['exclude', '/(cocoa|gtk|win)/'],
['exclude', '_(cocoa|gtk|linux|mac|posix|skia|win|x)\\.(cc|mm?)$'],
- ['exclude', '/(win|x11)_[^/]*\\.cc$'],
+ ['exclude', '/(gtk|win|x11)_[^/]*\\.cc$'],
],
'conditions': [
['OS=="linux"', {'sources/': [
['include', '/gtk/'],
['include', '_(gtk|linux|posix|skia|x)\\.cc$'],
- ['include', '/x11_[^/]*\\.cc$'],
+ ['include', '/(gtk|x11)_[^/]*\\.cc$'],
]}],
['OS=="mac"', {'sources/': [
['include', '/cocoa/'],
@@ -125,6 +125,8 @@
'common/gfx/text_elider.cc',
'common/gfx/text_elider.h',
'common/gfx/utils.h',
+ 'common/gtk_util.cc',
+ 'common/gtk_util.h',
'common/net/cookie_monster_sqlite.cc',
'common/net/cookie_monster_sqlite.h',
'common/net/dns.h',
@@ -710,6 +712,8 @@
'browser/gtk/back_forward_menu_model_gtk.h',
'browser/gtk/bookmark_bar_gtk.cc',
'browser/gtk/bookmark_bar_gtk.h',
+ 'browser/gtk/bookmark_context_menu_gtk.cc',
+ 'browser/gtk/bookmark_context_menu_gtk.h',
'browser/gtk/browser_toolbar_gtk.cc',
'browser/gtk/browser_toolbar_gtk.h',
'browser/gtk/browser_window_factory_gtk.cc',
diff --git a/chrome/common/gtk_util.cc b/chrome/common/gtk_util.cc
new file mode 100644
index 0000000..0576c0c
--- /dev/null
+++ b/chrome/common/gtk_util.cc
@@ -0,0 +1,81 @@
+// Copyright (c) 2009 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/common/gtk_util.h"
+
+#include <gtk/gtk.h>
+
+#include "base/gfx/gtk_util.h"
+#include "skia/include/SkBitmap.h"
+
+namespace {
+
+// Callback used in RemoveAllChildren.
+void RemoveWidget(GtkWidget* widget, gpointer container) {
+ gtk_container_remove(GTK_CONTAINER(container), widget);
+}
+
+void FreePixels(guchar* pixels, gpointer data) {
+ free(data);
+}
+
+} // namespace
+
+namespace event_utils {
+
+WindowOpenDisposition DispositionFromEventFlags(guint event_flags) {
+ if ((event_flags & GDK_BUTTON2_MASK) || (event_flags & GDK_CONTROL_MASK)) {
+ return (event_flags & GDK_SHIFT_MASK) ?
+ NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB;
+ }
+
+ if (event_flags & GDK_SHIFT_MASK)
+ return NEW_WINDOW;
+ return false /*event.IsAltDown()*/ ? SAVE_TO_DISK : CURRENT_TAB;
+}
+
+} // namespace event_utils
+
+namespace gfx {
+
+GdkPixbuf* GdkPixbufFromSkBitmap(const SkBitmap* bitmap) {
+ bitmap->lockPixels();
+ int width = bitmap->width();
+ int height = bitmap->height();
+ int stride = bitmap->rowBytes();
+ const guchar* orig_data = static_cast<guchar*>(bitmap->getPixels());
+ guchar* data = BGRAToRGBA(orig_data, width, height, stride);
+
+ // This pixbuf takes ownership of our malloc()ed data and will
+ // free it for us when it is destroyed.
+ GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(
+ data,
+ GDK_COLORSPACE_RGB, // The only colorspace gtk supports.
+ true, // There is an alpha channel.
+ 8,
+ width, height, stride, &FreePixels, data);
+
+ bitmap->unlockPixels();
+ return pixbuf;
+}
+
+GtkWidget* CreateGtkBorderBin(GtkWidget* child, const GdkColor* color,
+ int top, int bottom, int left, int right) {
+ // Use a GtkEventBox to get the background painted. However, we can't just
+ // use a container border, since it won't paint there. Use an alignment
+ // inside to get the sizes exactly of how we want the border painted.
+ GtkWidget* ebox = gtk_event_box_new();
+ gtk_widget_modify_bg(ebox, GTK_STATE_NORMAL, color);
+ GtkWidget* alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
+ gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), top, bottom, left, right);
+ gtk_container_add(GTK_CONTAINER(alignment), child);
+ gtk_container_add(GTK_CONTAINER(ebox), alignment);
+ return ebox;
+}
+
+void RemoveAllChildren(GtkWidget* container) {
+ gtk_container_foreach(GTK_CONTAINER(container), RemoveWidget, container);
+}
+
+} // namespace gfx
diff --git a/chrome/common/gtk_util.h b/chrome/common/gtk_util.h
new file mode 100644
index 0000000..ff3dc5c
--- /dev/null
+++ b/chrome/common/gtk_util.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_COMMON_GTK_UTIL_H_
+#define CHROME_COMMON_GTK_UTIL_H_
+
+#include <gtk/gtk.h>
+
+#include "webkit/glue/window_open_disposition.h"
+
+typedef struct _GdkPixbuf GdkPixbuf;
+typedef struct _GtkWidget GtkWidget;
+class SkBitmap;
+
+namespace event_utils {
+
+// Translates event flags into what kind of disposition they represent.
+// For example, a middle click would mean to open a background tab.
+// event_flags are the state in the GdkEvent structure.
+WindowOpenDisposition DispositionFromEventFlags(guint state);
+
+} // namespace event_utils
+
+namespace gfx {
+
+// Convert and copy a SkBitmap to a GdkPixbuf. NOTE: this uses BGRAToRGBA, so
+// it is an expensive operation.
+GdkPixbuf* GdkPixbufFromSkBitmap(const SkBitmap* bitmap);
+
+// Create a GtkBin with |child| as its child widget. This bin will paint a
+// border of color |color| with the sizes specified in pixels.
+GtkWidget* CreateGtkBorderBin(GtkWidget* child, const GdkColor* color,
+ int top, int bottom, int left, int right);
+
+// Remove all children from this container.
+void RemoveAllChildren(GtkWidget* container);
+
+} // namespace gfx
+
+#endif // CHROME_COMMON_GTK_UTIL_H_
diff --git a/chrome/common/resource_bundle_linux.cc b/chrome/common/resource_bundle_linux.cc
index 57cce50..2fe2a31 100644
--- a/chrome/common/resource_bundle_linux.cc
+++ b/chrome/common/resource_bundle_linux.cc
@@ -19,6 +19,7 @@
#include "base/string_util.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/gfx/chrome_font.h"
+#include "chrome/common/gtk_util.h"
#include "chrome/common/l10n_util.h"
#include "SkBitmap.h"