global_menu_bar_registrar_x11.cc revision 3240926e260ce088908e02ac07a6cf7b0c0cbf44
1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h" 6 7#include "base/bind.h" 8#include "base/logging.h" 9#include "chrome/browser/ui/views/frame/global_menu_bar_x11.h" 10#include "content/public/browser/browser_thread.h" 11 12using content::BrowserThread; 13 14namespace { 15 16const char kAppMenuRegistrarName[] = "com.canonical.AppMenu.Registrar"; 17const char kAppMenuRegistrarPath[] = "/com/canonical/AppMenu/Registrar"; 18 19} // namespace 20 21// static 22GlobalMenuBarRegistrarX11* GlobalMenuBarRegistrarX11::GetInstance() { 23 return Singleton<GlobalMenuBarRegistrarX11>::get(); 24} 25 26void GlobalMenuBarRegistrarX11::OnWindowMapped(unsigned long xid) { 27 live_xids_.insert(xid); 28 29 if (registrar_proxy_) 30 RegisterXID(xid); 31} 32 33void GlobalMenuBarRegistrarX11::OnWindowUnmapped(unsigned long xid) { 34 if (registrar_proxy_) 35 UnregisterXID(xid); 36 37 live_xids_.erase(xid); 38} 39 40GlobalMenuBarRegistrarX11::GlobalMenuBarRegistrarX11() 41 : registrar_proxy_(NULL) { 42 // libdbusmenu uses the gio version of dbus; I tried using the code in dbus/, 43 // but it looks like that's isn't sharing the bus name with the gio version, 44 // even when |connection_type| is set to SHARED. 45 g_dbus_proxy_new_for_bus( 46 G_BUS_TYPE_SESSION, 47 static_cast<GDBusProxyFlags>( 48 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | 49 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | 50 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START), 51 NULL, 52 kAppMenuRegistrarName, 53 kAppMenuRegistrarPath, 54 kAppMenuRegistrarName, 55 NULL, // TODO: Probalby want a real cancelable. 56 static_cast<GAsyncReadyCallback>(OnProxyCreatedThunk), 57 this); 58} 59 60GlobalMenuBarRegistrarX11::~GlobalMenuBarRegistrarX11() { 61 if (registrar_proxy_) { 62 g_signal_handlers_disconnect_by_func( 63 registrar_proxy_, 64 reinterpret_cast<void*>(OnNameOwnerChangedThunk), 65 this); 66 g_object_unref(registrar_proxy_); 67 } 68} 69 70void GlobalMenuBarRegistrarX11::RegisterXID(unsigned long xid) { 71 DCHECK(registrar_proxy_); 72 std::string path = GlobalMenuBarX11::GetPathForWindow(xid); 73 74 // TODO(erg): The mozilla implementation goes to a lot of callback trouble 75 // just to make sure that they react to make sure there's some sort of 76 // cancelable object; including making a whole callback just to handle the 77 // cancelable. 78 // 79 // I don't see any reason why we should care if "RegisterWindow" completes or 80 // not. 81 g_dbus_proxy_call(registrar_proxy_, 82 "RegisterWindow", 83 g_variant_new("(uo)", xid, path.c_str()), 84 G_DBUS_CALL_FLAGS_NONE, -1, 85 NULL, 86 NULL, 87 NULL); 88} 89 90void GlobalMenuBarRegistrarX11::UnregisterXID(unsigned long xid) { 91 DCHECK(registrar_proxy_); 92 std::string path = GlobalMenuBarX11::GetPathForWindow(xid); 93 94 // TODO(erg): The mozilla implementation goes to a lot of callback trouble 95 // just to make sure that they react to make sure there's some sort of 96 // cancelable object; including making a whole callback just to handle the 97 // cancelable. 98 // 99 // I don't see any reason why we should care if "UnregisterWindow" completes 100 // or not. 101 g_dbus_proxy_call(registrar_proxy_, 102 "UnregisterWindow", 103 g_variant_new("(u)", xid), 104 G_DBUS_CALL_FLAGS_NONE, -1, 105 NULL, 106 NULL, 107 NULL); 108} 109 110void GlobalMenuBarRegistrarX11::OnProxyCreated(GObject* source, 111 GAsyncResult* result) { 112 GError* error = NULL; 113 GDBusProxy* proxy = g_dbus_proxy_new_for_bus_finish(result, &error); 114 if (error) { 115 g_error_free(error); 116 return; 117 } 118 119 // TODO(erg): Mozilla's implementation has a workaround for GDBus 120 // cancellation here. However, it's marked as fixed. If there's weird 121 // problems with cancelation, look at how they fixed their issues. 122 123 registrar_proxy_ = proxy; 124 125 g_signal_connect(registrar_proxy_, "notify::g-name-owner", 126 G_CALLBACK(OnNameOwnerChangedThunk), this); 127 128 OnNameOwnerChanged(NULL, NULL); 129} 130 131void GlobalMenuBarRegistrarX11::OnNameOwnerChanged(GObject* /* ignored */, 132 GParamSpec* /* ignored */) { 133 // If the name owner changed, we need to reregister all the live xids with 134 // the system. 135 for (std::set<unsigned long>::const_iterator it = live_xids_.begin(); 136 it != live_xids_.end(); ++it) { 137 RegisterXID(*it); 138 } 139} 140