Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2867)

Unified Diff: chrome/browser/gtk/menu_gtk.cc

Issue 20245: Port the Menu class to GTK. (Closed)
Patch Set: Fixes for evanm Created 11 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/gtk/menu_gtk.cc
diff --git a/chrome/browser/gtk/menu_gtk.cc b/chrome/browser/gtk/menu_gtk.cc
new file mode 100644
index 0000000000000000000000000000000000000000..7eaab60a460bae26a31934f9ff182cb7157610ef
--- /dev/null
+++ b/chrome/browser/gtk/menu_gtk.cc
@@ -0,0 +1,151 @@
+// 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/menu_gtk.h"
+
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "chrome/common/l10n_util.h"
+
+MenuGtk::MenuGtk(MenuGtk::Delegate* delegate,
+ const MenuCreateMaterial* menu_data)
+ : delegate_(delegate),
+ menu_(gtk_menu_new()) {
+ BuildMenuIn(menu_, menu_data);
+}
+
+MenuGtk::~MenuGtk() {
+ g_object_unref(menu_);
+}
+
+void MenuGtk::Popup(GtkWidget* widget, GdkEvent* event) {
+ DCHECK(event->type == GDK_BUTTON_PRESS)
+ << "Non-button press event sent to RunMenuAt";
+
+ gtk_container_foreach(GTK_CONTAINER(menu_), SetMenuItemInfo, this);
+
+ GdkEventButton* event_button = reinterpret_cast<GdkEventButton*>(event);
+ gtk_menu_popup(GTK_MENU(menu_), NULL, NULL,
+ MenuPositionFunc,
+ widget,
+ event_button->button, event_button->time);
+}
+
+void MenuGtk::BuildMenuIn(GtkWidget* menu,
+ const MenuCreateMaterial* menu_data) {
+ for (; menu_data->type != MENU_END; menu_data++) {
+ GtkWidget* menu_item = NULL;
+
+ std::wstring label;
+ if (menu_data->label_argument) {
+ label = l10n_util::GetStringF(
+ menu_data->label_id,
+ l10n_util::GetString(menu_data->label_argument));
+ } else if (menu_data->label_id) {
+ label = l10n_util::GetString(menu_data->label_id);
+ } else {
+ DCHECK(menu_data->type == MENU_SEPARATOR) << "Menu definition broken";
+ }
+
+ switch (menu_data->type) {
+ case MENU_CHECKBOX:
+ menu_item = gtk_check_menu_item_new_with_label(
+ WideToUTF8(label).c_str());
+ break;
+ case MENU_SEPARATOR:
+ menu_item = gtk_separator_menu_item_new();
+ break;
+ case MENU_NORMAL:
+ default:
+ menu_item = gtk_menu_item_new_with_label(WideToUTF8(label).c_str());
+ break;
+ }
+
+ if (menu_data->submenu) {
+ GtkWidget* submenu = gtk_menu_new();
+ BuildMenuIn(submenu, menu_data->submenu);
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu);
+ }
+
+ g_object_set_data(G_OBJECT(menu_item), "menu-data",
+ const_cast<MenuCreateMaterial*>(menu_data));
+
+ g_signal_connect(G_OBJECT(menu_item), "activate",
+ G_CALLBACK(OnMenuItemActivated), this);
+
+ gtk_widget_show(menu_item);
+ gtk_menu_append(menu, menu_item);
+ }
+}
+
+/* static */
+void MenuGtk::OnMenuItemActivated(GtkMenuItem* menuitem, MenuGtk* menu) {
+ // We receive activation messages when highlighting a menu that has a
+ // submenu. Ignore them.
+ if (!gtk_menu_item_get_submenu(menuitem)) {
+ const MenuCreateMaterial* data =
+ reinterpret_cast<const MenuCreateMaterial*>(
+ g_object_get_data(G_OBJECT(menuitem), "menu-data"));
+ menu->delegate_->ExecuteCommand(data->id);
+ }
+}
+
+/* static */
Dean McNamee 2009/02/18 12:35:17 I've seen this in a few places now. I don't think
+void MenuGtk::MenuPositionFunc(GtkMenu* menu,
+ int* x,
+ int* y,
+ gboolean* push_in,
+ void* void_widget) {
+ GtkWidget* widget = GTK_WIDGET(void_widget);
+ GtkRequisition menu_req;
+ GdkRectangle monitor;
+
+ gtk_widget_size_request(GTK_WIDGET(menu), &menu_req);
+
+ GdkScreen* screen = gtk_widget_get_screen(GTK_WIDGET(menu));
+ gint monitor_num = gdk_screen_get_monitor_at_window(screen, widget->window);
+ if (monitor_num < 0)
+ monitor_num = 0;
+ gdk_screen_get_monitor_geometry(screen, monitor_num, &monitor);
+
+ gdk_window_get_origin(widget->window, x, y);
+ *x += widget->allocation.x + widget->allocation.width;
+ *y += widget->allocation.y + widget->allocation.height;
+
+ *x -= menu_req.width;
+
+ // TODO(erg): Deal with this scrolling off the bottom of the screen.
+
+ // Regretfully, we can't rely on push_in to alter the coordinates above to
+ // always make the menu fit on screen. It'd make the above calculations just
+ // work though...
+ *push_in = FALSE;
+}
+
+/* static */
+void MenuGtk::SetMenuItemInfo(GtkWidget* widget, void* raw_menu) {
+ MenuGtk* menu = static_cast<MenuGtk*>(raw_menu);
+ const MenuCreateMaterial* data =
+ reinterpret_cast<const MenuCreateMaterial*>(
+ g_object_get_data(G_OBJECT(widget), "menu-data"));
+
+ if (data) {
+ if (GTK_IS_CHECK_MENU_ITEM(widget)) {
+ GtkCheckMenuItem* item = GTK_CHECK_MENU_ITEM(widget);
+ gtk_check_menu_item_set_active(
+ item, menu->delegate_->IsItemChecked(data->id));
+ }
+
+ if (GTK_IS_MENU_ITEM(widget)) {
+ gtk_widget_set_sensitive(
+ widget, menu->delegate_->IsCommandEnabled(data->id));
+
+ GtkWidget* submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(widget));
+ if (submenu) {
+ gtk_container_foreach(GTK_CONTAINER(submenu), &MenuGtk::SetMenuItemInfo,
+ raw_menu);
+ }
+ }
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698