summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/ui/views/frame/browser_desktop_root_window_host_x11.cc35
-rw-r--r--chrome/browser/ui/views/frame/browser_desktop_root_window_host_x11.h18
-rw-r--r--chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc139
-rw-r--r--chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h54
-rw-r--r--chrome/browser/ui/views/frame/global_menu_bar_x11.cc420
-rw-r--r--chrome/browser/ui/views/frame/global_menu_bar_x11.h106
-rw-r--r--chrome/chrome_browser_ui.gypi5
7 files changed, 770 insertions, 7 deletions
diff --git a/chrome/browser/ui/views/frame/browser_desktop_root_window_host_x11.cc b/chrome/browser/ui/views/frame/browser_desktop_root_window_host_x11.cc
index f1c3002..b7f3fdb 100644
--- a/chrome/browser/ui/views/frame/browser_desktop_root_window_host_x11.cc
+++ b/chrome/browser/ui/views/frame/browser_desktop_root_window_host_x11.cc
@@ -10,10 +10,12 @@
BrowserDesktopRootWindowHostX11::BrowserDesktopRootWindowHostX11(
views::internal::NativeWidgetDelegate* native_widget_delegate,
views::DesktopNativeWidgetAura* desktop_native_widget_aura,
- const gfx::Rect& initial_bounds)
+ const gfx::Rect& initial_bounds,
+ BrowserView* browser_view)
: DesktopRootWindowHostX11(native_widget_delegate,
- desktop_native_widget_aura,
- initial_bounds) {
+ desktop_native_widget_aura,
+ initial_bounds),
+ browser_view_(browser_view) {
}
BrowserDesktopRootWindowHostX11::~BrowserDesktopRootWindowHostX11() {
@@ -37,6 +39,28 @@ bool BrowserDesktopRootWindowHostX11::UsesNativeSystemMenu() const {
}
////////////////////////////////////////////////////////////////////////////////
+// BrowserDesktopRootWindowHostX11,
+// views::DesktopRootWindowHostX11 implementation:
+
+aura::RootWindow* BrowserDesktopRootWindowHostX11::Init(
+ aura::Window* content_window,
+ const views::Widget::InitParams& params) {
+ aura::RootWindow* root_window = views::DesktopRootWindowHostX11::Init(
+ content_window, params);
+
+ // We have now created our backing X11 window. We now need to (possibly)
+ // alert Unity that there's a menu bar attached to it.
+ global_menu_bar_x11_.reset(new GlobalMenuBarX11(browser_view_, this));
+
+ return root_window;
+}
+
+void BrowserDesktopRootWindowHostX11::CloseNow() {
+ global_menu_bar_x11_.reset();
+ DesktopRootWindowHostX11::CloseNow();
+}
+
+////////////////////////////////////////////////////////////////////////////////
// BrowserDesktopRootWindowHost, public:
// static
@@ -48,6 +72,7 @@ BrowserDesktopRootWindowHost*
BrowserView* browser_view,
BrowserFrame* browser_frame) {
return new BrowserDesktopRootWindowHostX11(native_widget_delegate,
- desktop_native_widget_aura,
- initial_bounds);
+ desktop_native_widget_aura,
+ initial_bounds,
+ browser_view);
}
diff --git a/chrome/browser/ui/views/frame/browser_desktop_root_window_host_x11.h b/chrome/browser/ui/views/frame/browser_desktop_root_window_host_x11.h
index 3461ebf..52aa8d7 100644
--- a/chrome/browser/ui/views/frame/browser_desktop_root_window_host_x11.h
+++ b/chrome/browser/ui/views/frame/browser_desktop_root_window_host_x11.h
@@ -7,6 +7,7 @@
#include "ui/views/widget/desktop_aura/desktop_root_window_host_x11.h"
#include "chrome/browser/ui/views/frame/browser_desktop_root_window_host.h"
+#include "chrome/browser/ui/views/frame/global_menu_bar_x11.h"
class BrowserFrame;
class BrowserView;
@@ -22,7 +23,8 @@ class BrowserDesktopRootWindowHostX11
BrowserDesktopRootWindowHostX11(
views::internal::NativeWidgetDelegate* native_widget_delegate,
views::DesktopNativeWidgetAura* desktop_native_widget_aura,
- const gfx::Rect& initial_bounds);
+ const gfx::Rect& initial_bounds,
+ BrowserView* browser_view);
virtual ~BrowserDesktopRootWindowHostX11();
private:
@@ -31,8 +33,20 @@ class BrowserDesktopRootWindowHostX11
virtual int GetMinimizeButtonOffset() const OVERRIDE;
virtual bool UsesNativeSystemMenu() const OVERRIDE;
+ // Overridden from views::DesktopRootWindowHostX11:
+ virtual aura::RootWindow* Init(
+ aura::Window* content_window,
+ const views::Widget::InitParams& params) OVERRIDE;
+ virtual void CloseNow() OVERRIDE;
+
+ BrowserView* browser_view_;
+
+ // Each browser frame maintains its own menu bar object because the lower
+ // level dbus protocol associates a xid to a menu bar; we can't map multiple
+ // xids to the same menu bar.
+ scoped_ptr<GlobalMenuBarX11> global_menu_bar_x11_;
+
DISALLOW_COPY_AND_ASSIGN(BrowserDesktopRootWindowHostX11);
};
-
#endif // CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_DESKTOP_ROOT_WINDOW_HOST_X11_H_
diff --git a/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc b/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc
new file mode 100644
index 0000000..55f2b27
--- /dev/null
+++ b/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc
@@ -0,0 +1,139 @@
+// Copyright 2013 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/ui/views/frame/global_menu_bar_registrar_x11.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "chrome/browser/ui/views/frame/global_menu_bar_x11.h"
+#include "content/public/browser/browser_thread.h"
+
+using content::BrowserThread;
+
+namespace {
+
+const char kAppMenuRegistrarName[] = "com.canonical.AppMenu.Registrar";
+const char kAppMenuRegistrarPath[] = "/com/canonical/AppMenu/Registrar";
+
+} // namespace
+
+// static
+GlobalMenuBarRegistrarX11* GlobalMenuBarRegistrarX11::GetInstance() {
+ return Singleton<GlobalMenuBarRegistrarX11>::get();
+}
+
+void GlobalMenuBarRegistrarX11::OnWindowMapped(unsigned long xid) {
+ live_xids_.insert(xid);
+
+ if (registrar_proxy_)
+ RegisterXID(xid);
+}
+
+void GlobalMenuBarRegistrarX11::OnWindowUnmapped(unsigned long xid) {
+ if (registrar_proxy_)
+ UnregisterXID(xid);
+
+ live_xids_.erase(xid);
+}
+
+GlobalMenuBarRegistrarX11::GlobalMenuBarRegistrarX11()
+ : registrar_proxy_(NULL) {
+ // libdbusmenu uses the gio version of dbus; I tried using the code in dbus/,
+ // but it looks like that's isn't sharing the bus name with the gio version,
+ // even when |connection_type| is set to SHARED.
+ g_dbus_proxy_new_for_bus(
+ G_BUS_TYPE_SESSION,
+ static_cast<GDBusProxyFlags>(
+ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
+ G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS |
+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START),
+ NULL,
+ kAppMenuRegistrarName,
+ kAppMenuRegistrarPath,
+ kAppMenuRegistrarName,
+ NULL, // TODO: Probalby want a real cancelable.
+ static_cast<GAsyncReadyCallback>(OnProxyCreatedThunk),
+ this);
+}
+
+GlobalMenuBarRegistrarX11::~GlobalMenuBarRegistrarX11() {
+ if (registrar_proxy_) {
+ g_signal_handlers_disconnect_by_func(
+ registrar_proxy_,
+ reinterpret_cast<void*>(OnNameOwnerChangedThunk),
+ this);
+ g_object_unref(registrar_proxy_);
+ }
+}
+
+void GlobalMenuBarRegistrarX11::RegisterXID(unsigned long xid) {
+ DCHECK(registrar_proxy_);
+ std::string path = GlobalMenuBarX11::GetPathForWindow(xid);
+
+ // TODO(erg): The mozilla implementation goes to a lot of callback trouble
+ // just to make sure that they react to make sure there's some sort of
+ // cancelable object; including making a whole callback just to handle the
+ // cancelable.
+ //
+ // I don't see any reason why we should care if "RegisterWindow" completes or
+ // not.
+ g_dbus_proxy_call(registrar_proxy_,
+ "RegisterWindow",
+ g_variant_new("(uo)", xid, path.c_str()),
+ G_DBUS_CALL_FLAGS_NONE, -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+void GlobalMenuBarRegistrarX11::UnregisterXID(unsigned long xid) {
+ DCHECK(registrar_proxy_);
+ std::string path = GlobalMenuBarX11::GetPathForWindow(xid);
+
+ // TODO(erg): The mozilla implementation goes to a lot of callback trouble
+ // just to make sure that they react to make sure there's some sort of
+ // cancelable object; including making a whole callback just to handle the
+ // cancelable.
+ //
+ // I don't see any reason why we should care if "UnregisterWindow" completes
+ // or not.
+ g_dbus_proxy_call(registrar_proxy_,
+ "UnregisterWindow",
+ g_variant_new("(u)", xid),
+ G_DBUS_CALL_FLAGS_NONE, -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+void GlobalMenuBarRegistrarX11::OnProxyCreated(GObject* source,
+ GAsyncResult* result) {
+ GError* error = NULL;
+ GDBusProxy* proxy = g_dbus_proxy_new_for_bus_finish(result, &error);
+ if (error) {
+ g_error_free(error);
+ return;
+ }
+
+ // TODO(erg): Mozilla's implementation has a workaround for GDBus
+ // cancellation here. However, it's marked as fixed. If there's weird
+ // problems with cancelation, look at how they fixed their issues.
+
+ registrar_proxy_ = proxy;
+
+ g_signal_connect(registrar_proxy_, "notify::g-name-owner",
+ G_CALLBACK(OnNameOwnerChangedThunk), this);
+
+ OnNameOwnerChanged(NULL, NULL);
+}
+
+void GlobalMenuBarRegistrarX11::OnNameOwnerChanged(GObject* /* ignored */,
+ GParamSpec* /* ignored */) {
+ // If the name owner changed, we need to reregister all the live xids with
+ // the system.
+ for (std::set<unsigned long>::const_iterator it = live_xids_.begin();
+ it != live_xids_.end(); ++it) {
+ RegisterXID(*it);
+ }
+}
diff --git a/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h b/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h
new file mode 100644
index 0000000..e35e87c
--- /dev/null
+++ b/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h
@@ -0,0 +1,54 @@
+// Copyright 2013 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_UI_VIEWS_FRAME_GLOBAL_MENU_BAR_REGISTRAR_X11_H_
+#define CHROME_BROWSER_UI_VIEWS_FRAME_GLOBAL_MENU_BAR_REGISTRAR_X11_H_
+
+#include <gio/gio.h>
+
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/singleton.h"
+#include "ui/base/glib/glib_signal.h"
+
+// Advertises our menu bars to Unity.
+//
+// GlobalMenuBarX11 is responsible for managing the DbusmenuServer for each
+// XID. We need a separate object to own the dbus channel to
+// com.canonical.AppMenu.Registrar and to register/unregister the mapping
+// between a XID and the DbusmenuServer instance we are offering.
+class GlobalMenuBarRegistrarX11 {
+ public:
+ static GlobalMenuBarRegistrarX11* GetInstance();
+
+ void OnWindowMapped(unsigned long xid);
+ void OnWindowUnmapped(unsigned long xid);
+
+ private:
+ friend struct DefaultSingletonTraits<GlobalMenuBarRegistrarX11>;
+
+ GlobalMenuBarRegistrarX11();
+ ~GlobalMenuBarRegistrarX11();
+
+ // Sends the actual message.
+ void RegisterXID(unsigned long xid);
+ void UnregisterXID(unsigned long xid);
+
+ CHROMEG_CALLBACK_1(GlobalMenuBarRegistrarX11, void, OnProxyCreated,
+ GObject*, GAsyncResult*);
+ CHROMEG_CALLBACK_1(GlobalMenuBarRegistrarX11, void, OnNameOwnerChanged,
+ GObject*, GParamSpec*);
+
+ GDBusProxy* registrar_proxy_;
+
+ // Window XIDs which want to be registered, but haven't yet been because
+ // we're waiting for the proxy to become available.
+ std::set<unsigned long> live_xids_;
+
+ DISALLOW_COPY_AND_ASSIGN(GlobalMenuBarRegistrarX11);
+};
+
+#endif // CHROME_BROWSER_UI_VIEWS_FRAME_GLOBAL_MENU_BAR_REGISTRAR_X11_H_
diff --git a/chrome/browser/ui/views/frame/global_menu_bar_x11.cc b/chrome/browser/ui/views/frame/global_menu_bar_x11.cc
new file mode 100644
index 0000000..e6ccb3e
--- /dev/null
+++ b/chrome/browser/ui/views/frame/global_menu_bar_x11.cc
@@ -0,0 +1,420 @@
+// Copyright 2013 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/ui/views/frame/global_menu_bar_x11.h"
+
+#include <dlfcn.h>
+#include <glib-object.h>
+
+#include "base/logging.h"
+#include "base/prefs/pref_service.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/views/frame/browser_desktop_root_window_host_x11.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h"
+#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
+#include "ui/base/accelerators/menu_label_accelerator_util_linux.h"
+#include "ui/base/keycodes/keyboard_code_conversion_x.h"
+#include "ui/base/l10n/l10n_util.h"
+
+// libdbusmenu-glib types
+typedef struct _DbusmenuMenuitem DbusmenuMenuitem;
+typedef DbusmenuMenuitem* (*dbusmenu_menuitem_new_func)();
+typedef DbusmenuMenuitem* (*dbusmenu_menuitem_new_with_id_func)(int id);
+
+typedef int (*dbusmenu_menuitem_get_id_func)(DbusmenuMenuitem* item);
+typedef DbusmenuMenuitem* (*dbusmenu_menuitem_child_append_func)(
+ DbusmenuMenuitem* parent,
+ DbusmenuMenuitem* child);
+typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_func)(
+ DbusmenuMenuitem* item,
+ const char* property,
+ const char* value);
+typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_variant_func)(
+ DbusmenuMenuitem* item,
+ const char* property,
+ GVariant* value);
+typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_bool_func)(
+ DbusmenuMenuitem* item,
+ const char* property,
+ bool value);
+typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_int_func)(
+ DbusmenuMenuitem* item,
+ const char* property,
+ int value);
+
+typedef struct _DbusmenuServer DbusmenuServer;
+typedef DbusmenuServer* (*dbusmenu_server_new_func)(const char* object);
+typedef void (*dbusmenu_server_set_root_func)(DbusmenuServer* self,
+ DbusmenuMenuitem* root);
+
+// A line in the static menu definitions.
+struct GlobalMenuBarCommand {
+ int str_id;
+ int command;
+ int tag;
+};
+
+namespace {
+
+// Retrieved functions from libdbusmenu-glib.
+
+// DbusmenuMenuItem methods:
+dbusmenu_menuitem_new_func menuitem_new = NULL;
+dbusmenu_menuitem_new_with_id_func menuitem_new_with_id = NULL;
+dbusmenu_menuitem_get_id_func menuitem_get_id = NULL;
+dbusmenu_menuitem_child_append_func menuitem_child_append = NULL;
+dbusmenu_menuitem_property_set_func menuitem_property_set = NULL;
+dbusmenu_menuitem_property_set_variant_func menuitem_property_set_variant =
+ NULL;
+dbusmenu_menuitem_property_set_bool_func menuitem_property_set_bool = NULL;
+dbusmenu_menuitem_property_set_int_func menuitem_property_set_int = NULL;
+
+// DbusmenuServer methods:
+dbusmenu_server_new_func server_new = NULL;
+dbusmenu_server_set_root_func server_set_root = NULL;
+
+// Properties that we set on menu items:
+const char kPropertyEnabled[] = "enabled";
+const char kPropertyLabel[] = "label";
+const char kPropertyShortcut[] = "shortcut";
+const char kPropertyType[] = "type";
+const char kPropertyToggleType[] = "toggle-type";
+const char kPropertyToggleState[] = "toggle-state";
+const char kPropertyVisible[] = "visible";
+
+const char kTypeCheckmark[] = "checkmark";
+const char kTypeSeparator[] = "separator";
+
+// Constants used in menu definitions
+const int MENU_SEPARATOR =-1;
+const int MENU_END = -2;
+const int MENU_DISABLED_LABEL = -3;
+
+GlobalMenuBarCommand file_menu[] = {
+ { IDS_NEW_TAB, IDC_NEW_TAB },
+ { IDS_NEW_WINDOW, IDC_NEW_WINDOW },
+ { IDS_NEW_INCOGNITO_WINDOW, IDC_NEW_INCOGNITO_WINDOW },
+ { IDS_REOPEN_CLOSED_TABS_LINUX, IDC_RESTORE_TAB },
+ { IDS_OPEN_FILE_LINUX, IDC_OPEN_FILE },
+ { IDS_OPEN_LOCATION_LINUX, IDC_FOCUS_LOCATION },
+
+ { MENU_SEPARATOR, MENU_SEPARATOR },
+
+ { IDS_CREATE_SHORTCUTS, IDC_CREATE_SHORTCUTS },
+
+ { MENU_SEPARATOR, MENU_SEPARATOR },
+
+ { IDS_CLOSE_WINDOW_LINUX, IDC_CLOSE_WINDOW },
+ { IDS_CLOSE_TAB_LINUX, IDC_CLOSE_TAB },
+ { IDS_SAVE_PAGE, IDC_SAVE_PAGE },
+
+ { MENU_SEPARATOR, MENU_SEPARATOR },
+
+ { IDS_PRINT, IDC_PRINT },
+
+ { MENU_END, MENU_END }
+};
+
+GlobalMenuBarCommand edit_menu[] = {
+ { IDS_CUT, IDC_CUT },
+ { IDS_COPY, IDC_COPY },
+ { IDS_PASTE, IDC_PASTE },
+
+ { MENU_SEPARATOR, MENU_SEPARATOR },
+
+ { IDS_FIND, IDC_FIND },
+
+ { MENU_SEPARATOR, MENU_SEPARATOR },
+
+ { IDS_PREFERENCES, IDC_OPTIONS },
+
+ { MENU_END, MENU_END }
+};
+
+
+GlobalMenuBarCommand view_menu[] = {
+ { IDS_SHOW_BOOKMARK_BAR, IDC_SHOW_BOOKMARK_BAR },
+
+ { MENU_SEPARATOR, MENU_SEPARATOR },
+
+ { IDS_STOP_MENU_LINUX, IDC_STOP },
+ { IDS_RELOAD_MENU_LINUX, IDC_RELOAD },
+
+ { MENU_SEPARATOR, MENU_SEPARATOR },
+
+ { IDS_FULLSCREEN, IDC_FULLSCREEN },
+ { IDS_TEXT_DEFAULT_LINUX, IDC_ZOOM_NORMAL },
+ { IDS_TEXT_BIGGER_LINUX, IDC_ZOOM_PLUS },
+ { IDS_TEXT_SMALLER_LINUX, IDC_ZOOM_MINUS },
+
+ { MENU_END, MENU_END }
+};
+
+// TODO(erg): History menu.
+
+GlobalMenuBarCommand tools_menu[] = {
+ { IDS_SHOW_DOWNLOADS, IDC_SHOW_DOWNLOADS },
+ { IDS_SHOW_HISTORY, IDC_SHOW_HISTORY },
+ { IDS_SHOW_EXTENSIONS, IDC_MANAGE_EXTENSIONS },
+
+ { MENU_SEPARATOR, MENU_SEPARATOR },
+
+ { IDS_TASK_MANAGER, IDC_TASK_MANAGER },
+ { IDS_CLEAR_BROWSING_DATA, IDC_CLEAR_BROWSING_DATA },
+
+ { MENU_SEPARATOR, MENU_SEPARATOR },
+
+ { IDS_VIEW_SOURCE, IDC_VIEW_SOURCE },
+ { IDS_DEV_TOOLS, IDC_DEV_TOOLS },
+ { IDS_DEV_TOOLS_CONSOLE, IDC_DEV_TOOLS_CONSOLE },
+
+ { MENU_END, MENU_END }
+};
+
+GlobalMenuBarCommand help_menu[] = {
+ { IDS_FEEDBACK, IDC_FEEDBACK },
+ { IDS_HELP_PAGE , IDC_HELP_PAGE_VIA_MENU },
+ { MENU_END, MENU_END }
+};
+
+
+void EnsureMethodsLoaded() {
+ static bool attempted_load = false;
+ if (attempted_load)
+ return;
+ attempted_load = true;
+
+ void* dbusmenu_lib = dlopen("libdbusmenu-glib.so", RTLD_LAZY);
+ if (!dbusmenu_lib)
+ return;
+
+ // DbusmenuMenuItem methods.
+ menuitem_new = reinterpret_cast<dbusmenu_menuitem_new_func>(
+ dlsym(dbusmenu_lib, "dbusmenu_menuitem_new"));
+ menuitem_new_with_id = reinterpret_cast<dbusmenu_menuitem_new_with_id_func>(
+ dlsym(dbusmenu_lib, "dbusmenu_menuitem_new_with_id"));
+ menuitem_get_id = reinterpret_cast<dbusmenu_menuitem_get_id_func>(
+ dlsym(dbusmenu_lib, "dbusmenu_menuitem_get_id"));
+ menuitem_child_append = reinterpret_cast<dbusmenu_menuitem_child_append_func>(
+ dlsym(dbusmenu_lib, "dbusmenu_menuitem_child_append"));
+ menuitem_property_set = reinterpret_cast<dbusmenu_menuitem_property_set_func>(
+ dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set"));
+ menuitem_property_set_variant =
+ reinterpret_cast<dbusmenu_menuitem_property_set_variant_func>(
+ dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set_variant"));
+ menuitem_property_set_bool =
+ reinterpret_cast<dbusmenu_menuitem_property_set_bool_func>(
+ dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set_bool"));
+ menuitem_property_set_int =
+ reinterpret_cast<dbusmenu_menuitem_property_set_int_func>(
+ dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set_int"));
+
+ // DbusmenuServer methods.
+ server_new = reinterpret_cast<dbusmenu_server_new_func>(
+ dlsym(dbusmenu_lib, "dbusmenu_server_new"));
+ server_set_root = reinterpret_cast<dbusmenu_server_set_root_func>(
+ dlsym(dbusmenu_lib, "dbusmenu_server_set_root"));
+}
+
+} // namespace
+
+GlobalMenuBarX11::GlobalMenuBarX11(BrowserView* browser_view,
+ BrowserDesktopRootWindowHostX11* host)
+ : browser_(browser_view->browser()),
+ browser_view_(browser_view),
+ host_(host),
+ server_(NULL),
+ root_item_(NULL) {
+ EnsureMethodsLoaded();
+
+ if (server_new)
+ host_->AddObserver(this);
+}
+
+GlobalMenuBarX11::~GlobalMenuBarX11() {
+ if (server_) {
+ Disable();
+ g_object_unref(server_);
+ host_->RemoveObserver(this);
+ }
+}
+
+// static
+std::string GlobalMenuBarX11::GetPathForWindow(unsigned long xid) {
+ return base::StringPrintf("/com/canonical/menu/%lX", xid);
+}
+
+void GlobalMenuBarX11::InitServer(unsigned long xid) {
+ std::string path = GetPathForWindow(xid);
+ server_ = server_new(path.c_str());
+
+ root_item_ = menuitem_new();
+ menuitem_property_set(root_item_, kPropertyLabel, "Root");
+ menuitem_property_set_bool(root_item_, kPropertyVisible, true);
+
+ BuildMenuFrom(root_item_, IDS_FILE_MENU_LINUX, &id_to_menu_item_, file_menu);
+ BuildMenuFrom(root_item_, IDS_EDIT_MENU_LINUX, &id_to_menu_item_, edit_menu);
+ BuildMenuFrom(root_item_, IDS_VIEW_MENU_LINUX, &id_to_menu_item_, view_menu);
+ // TODO(erg): History menu.
+ BuildMenuFrom(root_item_, IDS_TOOLS_MENU_LINUX, &id_to_menu_item_,
+ tools_menu);
+ BuildMenuFrom(root_item_, IDS_HELP_MENU_LINUX, &id_to_menu_item_, help_menu);
+
+ for (CommandIDMenuItemMap::const_iterator it = id_to_menu_item_.begin();
+ it != id_to_menu_item_.end(); ++it) {
+ menuitem_property_set_bool(it->second, kPropertyEnabled,
+ chrome::IsCommandEnabled(browser_, it->first));
+
+ ui::Accelerator accelerator;
+ if (browser_view_->GetAccelerator(it->first, &accelerator))
+ RegisterAccelerator(it->second, accelerator);
+
+ chrome::AddCommandObserver(browser_, it->first, this);
+ }
+
+ pref_change_registrar_.Init(browser_->profile()->GetPrefs());
+ pref_change_registrar_.Add(
+ prefs::kShowBookmarkBar,
+ base::Bind(&GlobalMenuBarX11::OnBookmarkBarVisibilityChanged,
+ base::Unretained(this)));
+ OnBookmarkBarVisibilityChanged();
+
+ server_set_root(server_, root_item_);
+}
+
+void GlobalMenuBarX11::Disable() {
+ for (CommandIDMenuItemMap::const_iterator it = id_to_menu_item_.begin();
+ it != id_to_menu_item_.end(); ++it) {
+ chrome::RemoveCommandObserver(browser_, it->first, this);
+ }
+ id_to_menu_item_.clear();
+
+ pref_change_registrar_.RemoveAll();
+}
+
+void GlobalMenuBarX11::BuildMenuFrom(
+ DbusmenuMenuitem* parent,
+ int menu_str_id,
+ std::map<int, DbusmenuMenuitem*>* id_to_menu_item,
+ GlobalMenuBarCommand* commands) {
+ DbusmenuMenuitem* top = menuitem_new();
+ menuitem_property_set(
+ top, kPropertyLabel,
+ ui::RemoveWindowsStyleAccelerators(
+ l10n_util::GetStringUTF8(menu_str_id)).c_str());
+ menuitem_property_set_bool(top, kPropertyVisible, true);
+
+ for (int i = 0; commands[i].str_id != MENU_END; ++i) {
+ DbusmenuMenuitem* menu_item = BuildMenuItem(
+ commands[i].str_id, commands[i].command, commands[i].tag,
+ id_to_menu_item);
+ menuitem_child_append(top, menu_item);
+ }
+
+ menuitem_child_append(parent, top);
+}
+
+DbusmenuMenuitem* GlobalMenuBarX11::BuildMenuItem(
+ int string_id,
+ int command_id,
+ int tag_id,
+ std::map<int, DbusmenuMenuitem*>* id_to_menu_item) {
+ DbusmenuMenuitem* item = menuitem_new();
+
+ if (string_id == MENU_SEPARATOR) {
+ menuitem_property_set(item, kPropertyType, kTypeSeparator);
+ } else {
+ std::string label = ui::ConvertAcceleratorsFromWindowsStyle(
+ l10n_util::GetStringUTF8(string_id));
+ menuitem_property_set(item, kPropertyLabel, label.c_str());
+
+ if (command_id == IDC_SHOW_BOOKMARK_BAR)
+ menuitem_property_set(item, kPropertyToggleType, kTypeCheckmark);
+
+ if (tag_id)
+ g_object_set_data(G_OBJECT(item), "type-tag", GINT_TO_POINTER(tag_id));
+
+ if (command_id == MENU_DISABLED_LABEL) {
+ menuitem_property_set_bool(item, kPropertyEnabled, false);
+ } else {
+ id_to_menu_item->insert(std::make_pair(command_id, item));
+ g_object_set_data(G_OBJECT(item), "command-id",
+ GINT_TO_POINTER(command_id));
+ g_signal_connect(item, "item-activated",
+ G_CALLBACK(OnItemActivatedThunk), this);
+ }
+ }
+
+ menuitem_property_set_bool(item, kPropertyVisible, true);
+ return item;
+}
+
+void GlobalMenuBarX11::RegisterAccelerator(DbusmenuMenuitem* item,
+ const ui::Accelerator& accelerator) {
+ // A translation of libdbusmenu-gtk's menuitem_property_set_shortcut()
+ // translated from GDK types to ui::Accelerator types.
+ GVariantBuilder builder;
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
+
+ if (accelerator.IsCtrlDown())
+ g_variant_builder_add(&builder, "s", "Control");
+ if (accelerator.IsAltDown())
+ g_variant_builder_add(&builder, "s", "Alt");
+ if (accelerator.IsShiftDown())
+ g_variant_builder_add(&builder, "s", "Shift");
+
+ char* name = XKeysymToString(XKeysymForWindowsKeyCode(
+ accelerator.key_code(), false));
+ if (!name) {
+ NOTIMPLEMENTED();
+ return;
+ }
+ g_variant_builder_add(&builder, "s", name);
+
+ GVariant* inside_array = g_variant_builder_end(&builder);
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_add_value(&builder, inside_array);
+ GVariant* outside_array = g_variant_builder_end(&builder);
+
+ menuitem_property_set_variant(item, kPropertyShortcut, outside_array);
+}
+
+void GlobalMenuBarX11::OnBookmarkBarVisibilityChanged() {
+ CommandIDMenuItemMap::iterator it =
+ id_to_menu_item_.find(IDC_SHOW_BOOKMARK_BAR);
+ if (it != id_to_menu_item_.end()) {
+ PrefService* prefs = browser_->profile()->GetPrefs();
+ // Note: Unlike the GTK version, we don't appear to need to do tricks where
+ // we block activation while setting the toggle.
+ menuitem_property_set_int(it->second, kPropertyToggleState,
+ prefs->GetBoolean(prefs::kShowBookmarkBar));
+ }
+}
+
+void GlobalMenuBarX11::EnabledStateChangedForCommand(int id, bool enabled) {
+ CommandIDMenuItemMap::iterator it = id_to_menu_item_.find(id);
+ if (it != id_to_menu_item_.end())
+ menuitem_property_set_bool(it->second, kPropertyEnabled, enabled);
+}
+
+void GlobalMenuBarX11::OnWindowMapped(unsigned long xid) {
+ if (!server_)
+ InitServer(xid);
+
+ GlobalMenuBarRegistrarX11::GetInstance()->OnWindowMapped(xid);
+}
+
+void GlobalMenuBarX11::OnWindowUnmapped(unsigned long xid) {
+ GlobalMenuBarRegistrarX11::GetInstance()->OnWindowUnmapped(xid);
+}
+
+void GlobalMenuBarX11::OnItemActivated(DbusmenuMenuitem* item,
+ unsigned int timestamp) {
+ int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(item), "command-id"));
+ chrome::ExecuteCommand(browser_, id);
+}
diff --git a/chrome/browser/ui/views/frame/global_menu_bar_x11.h b/chrome/browser/ui/views/frame/global_menu_bar_x11.h
new file mode 100644
index 0000000..46f8cf3
--- /dev/null
+++ b/chrome/browser/ui/views/frame/global_menu_bar_x11.h
@@ -0,0 +1,106 @@
+// Copyright 2013 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_UI_VIEWS_FRAME_GLOBAL_MENU_BAR_X11_H_
+#define CHROME_BROWSER_UI_VIEWS_FRAME_GLOBAL_MENU_BAR_X11_H_
+
+#include <map>
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/prefs/pref_change_registrar.h"
+#include "chrome/browser/command_observer.h"
+#include "ui/base/glib/glib_signal.h"
+#include "ui/views/widget/desktop_aura/desktop_root_window_host_observer_x11.h"
+
+typedef struct _DbusmenuMenuitem DbusmenuMenuitem;
+typedef struct _DbusmenuServer DbusmenuServer;
+
+namespace ui {
+class Accelerator;
+}
+
+class Browser;
+class BrowserView;
+
+class BrowserDesktopRootWindowHostX11;
+struct GlobalMenuBarCommand;
+
+// Controls the Mac style menu bar on Unity.
+//
+// Unity has an Apple-like menu bar at the top of the screen that changes
+// depending on the active window. In the GTK port, we had a hidden GtkMenuBar
+// object in each GtkWindow which existed only to be scrapped by the
+// libdbusmenu-gtk code. Since we don't have GtkWindows anymore, we need to
+// interface directly with the lower level libdbusmenu-glib, which we
+// opportunistically dlopen() since not everyone is running Ubuntu.
+class GlobalMenuBarX11 : public CommandObserver,
+ public views::DesktopRootWindowHostObserverX11 {
+ public:
+ GlobalMenuBarX11(BrowserView* browser_view,
+ BrowserDesktopRootWindowHostX11* host);
+ virtual ~GlobalMenuBarX11();
+
+ // Creates the object path for DbusemenuServer which is attached to |xid|.
+ static std::string GetPathForWindow(unsigned long xid);
+
+ private:
+ typedef std::map<int, DbusmenuMenuitem*> CommandIDMenuItemMap;
+
+ // Creates a DbusmenuServer, and attaches all the menu items.
+ void InitServer(unsigned long xid);
+
+ // Stops listening to enable state changed events.
+ void Disable();
+
+ // Creates a whole menu defined with |commands| and titled with the string
+ // |menu_str_id|. Then appends it to |parent|.
+ void BuildMenuFrom(DbusmenuMenuitem* parent,
+ int menu_str_id,
+ CommandIDMenuItemMap* id_to_menu_item,
+ GlobalMenuBarCommand* commands);
+
+ // Creates an individual menu item from a title and command, and subscribes
+ // to the activation signal.
+ DbusmenuMenuitem* BuildMenuItem(
+ int string_id,
+ int command_id,
+ int tag_id,
+ CommandIDMenuItemMap* id_to_menu_item);
+
+ // Sets the accelerator for |item|.
+ void RegisterAccelerator(DbusmenuMenuitem* item,
+ const ui::Accelerator& accelerator);
+
+ // Updates the visibility of the bookmark bar on pref changes.
+ void OnBookmarkBarVisibilityChanged();
+
+ // Overridden from CommandObserver:
+ virtual void EnabledStateChangedForCommand(int id, bool enabled) OVERRIDE;
+
+ // Overridden from DesktopRootWindowHostObserverX11:
+ virtual void OnWindowMapped(unsigned long xid) OVERRIDE;
+ virtual void OnWindowUnmapped(unsigned long xid) OVERRIDE;
+
+ CHROMEG_CALLBACK_1(GlobalMenuBarX11, void, OnItemActivated, DbusmenuMenuitem*,
+ unsigned int);
+
+ Browser* browser_;
+ BrowserView* browser_view_;
+ BrowserDesktopRootWindowHostX11* host_;
+
+ // Maps command ids to DbusmenuMenuitems so we can modify their
+ // enabled/checked state in response to state change notifications.
+ CommandIDMenuItemMap id_to_menu_item_;
+
+ DbusmenuServer* server_;
+ DbusmenuMenuitem* root_item_;
+
+ // Tracks value of the kShowBookmarkBar preference.
+ PrefChangeRegistrar pref_change_registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(GlobalMenuBarX11);
+};
+
+#endif // CHROME_BROWSER_UI_VIEWS_FRAME_GLOBAL_MENU_BAR_X11_H_
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index 9d177f11..640b247 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -1707,6 +1707,10 @@
'browser/ui/views/frame/browser_desktop_root_window_host_x11.h',
'browser/ui/views/frame/glass_browser_frame_view.cc',
'browser/ui/views/frame/glass_browser_frame_view.h',
+ 'browser/ui/views/frame/global_menu_bar_x11.cc',
+ 'browser/ui/views/frame/global_menu_bar_x11.h',
+ 'browser/ui/views/frame/global_menu_bar_registrar_x11.cc',
+ 'browser/ui/views/frame/global_menu_bar_registrar_x11.h',
'browser/ui/views/frame/immersive_mode_controller.cc',
'browser/ui/views/frame/immersive_mode_controller.h',
'browser/ui/views/frame/immersive_mode_controller_ash.cc',
@@ -2629,6 +2633,7 @@
# world.
'browser/ui/libgtk2ui/libgtk2ui.gyp:gtk2ui',
'../ui/linux_ui/linux_ui.gyp:linux_ui',
+ '../build/linux/system.gyp:gio',
],
}],
['use_aura==0 or chromeos==1 or OS!="linux"', {