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