1 // Copyright (c) 2012 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 "ui/gfx/gtk_native_view_id_manager.h" 6 7 #include <gdk/gdkx.h> 8 #include <gtk/gtk.h> 9 10 #include "base/logging.h" 11 #include "base/memory/singleton.h" 12 #include "base/rand_util.h" 13 #include "ui/gfx/gdk_compat.h" 14 #include "ui/gfx/gtk_compat.h" 15 #include "ui/gfx/gtk_preserve_window.h" 16 17 // ----------------------------------------------------------------------------- 18 // Bounce functions for GTK to callback into a C++ object... 19 20 void OnRealize(gfx::NativeView widget, void* arg) { 21 GtkNativeViewManager* manager = reinterpret_cast<GtkNativeViewManager*>(arg); 22 manager->OnRealize(widget); 23 } 24 25 void OnUnrealize(gfx::NativeView widget, void *arg) { 26 GtkNativeViewManager* manager = reinterpret_cast<GtkNativeViewManager*>(arg); 27 manager->OnUnrealize(widget); 28 } 29 30 static void OnDestroy(GtkObject* obj, void* arg) { 31 GtkNativeViewManager* manager = reinterpret_cast<GtkNativeViewManager*>(arg); 32 manager->OnDestroy(reinterpret_cast<GtkWidget*>(obj)); 33 } 34 35 // ----------------------------------------------------------------------------- 36 37 38 // ----------------------------------------------------------------------------- 39 // Public functions... 40 41 GtkNativeViewManager::GtkNativeViewManager() { 42 } 43 44 GtkNativeViewManager::~GtkNativeViewManager() { 45 } 46 47 // static 48 GtkNativeViewManager* GtkNativeViewManager::GetInstance() { 49 return Singleton<GtkNativeViewManager>::get(); 50 } 51 52 gfx::NativeViewId GtkNativeViewManager::GetIdForWidget(gfx::NativeView widget) { 53 // This is just for unit tests: 54 if (!widget) 55 return 0; 56 57 base::AutoLock locked(lock_); 58 59 std::map<gfx::NativeView, gfx::NativeViewId>::const_iterator i = 60 native_view_to_id_.find(widget); 61 62 if (i != native_view_to_id_.end()) 63 return i->second; 64 65 gfx::NativeViewId new_id = 66 static_cast<gfx::NativeViewId>(base::RandUint64()); 67 while (id_to_info_.find(new_id) != id_to_info_.end()) 68 new_id = static_cast<gfx::NativeViewId>(base::RandUint64()); 69 70 NativeViewInfo info; 71 info.widget = widget; 72 if (gtk_widget_get_realized(widget)) { 73 GdkWindow *gdk_window = gtk_widget_get_window(widget); 74 DCHECK(gdk_window); 75 info.x_window_id = GDK_WINDOW_XID(gdk_window); 76 } 77 78 native_view_to_id_[widget] = new_id; 79 id_to_info_[new_id] = info; 80 81 g_signal_connect(widget, "realize", G_CALLBACK(::OnRealize), this); 82 g_signal_connect(widget, "unrealize", G_CALLBACK(::OnUnrealize), this); 83 g_signal_connect(widget, "destroy", G_CALLBACK(::OnDestroy), this); 84 85 return new_id; 86 } 87 88 bool GtkNativeViewManager::GetXIDForId(XID* output, gfx::NativeViewId id) { 89 base::AutoLock locked(lock_); 90 91 std::map<gfx::NativeViewId, NativeViewInfo>::const_iterator i = 92 id_to_info_.find(id); 93 94 if (i == id_to_info_.end()) 95 return false; 96 97 *output = i->second.x_window_id; 98 return true; 99 } 100 101 bool GtkNativeViewManager::GetNativeViewForId(gfx::NativeView* output, 102 gfx::NativeViewId id) { 103 base::AutoLock locked(lock_); 104 105 std::map<gfx::NativeViewId, NativeViewInfo>::const_iterator i = 106 id_to_info_.find(id); 107 108 if (i == id_to_info_.end()) 109 return false; 110 111 *output = i->second.widget; 112 return true; 113 } 114 115 bool GtkNativeViewManager::GetPermanentXIDForId(XID* output, 116 gfx::NativeViewId id) { 117 base::AutoLock locked(lock_); 118 119 std::map<gfx::NativeViewId, NativeViewInfo>::iterator i = 120 id_to_info_.find(id); 121 122 if (i == id_to_info_.end()) 123 return false; 124 125 // We only return permanent XIDs for widgets that allow us to guarantee that 126 // the XID will not change. 127 DCHECK(GTK_IS_PRESERVE_WINDOW(i->second.widget)); 128 GtkPreserveWindow* widget = 129 reinterpret_cast<GtkPreserveWindow*>(i->second.widget); 130 gtk_preserve_window_set_preserve(widget, TRUE); 131 132 *output = GDK_WINDOW_XID(gtk_widget_get_window(i->second.widget)); 133 134 // Update the reference count on the permanent XID. 135 PermanentXIDInfo info; 136 info.widget = widget; 137 info.ref_count = 1; 138 std::pair<std::map<XID, PermanentXIDInfo>::iterator, bool> ret = 139 perm_xid_to_info_.insert(std::make_pair(*output, info)); 140 141 if (!ret.second) { 142 DCHECK(ret.first->second.widget == widget); 143 ret.first->second.ref_count++; 144 } 145 146 return true; 147 } 148 149 bool GtkNativeViewManager::AddRefPermanentXID(XID xid) { 150 base::AutoLock locked(lock_); 151 152 std::map<XID, PermanentXIDInfo>::iterator i = 153 perm_xid_to_info_.find(xid); 154 155 if (i == perm_xid_to_info_.end()) 156 return false; 157 158 i->second.ref_count++; 159 160 return true; 161 } 162 163 void GtkNativeViewManager::ReleasePermanentXID(XID xid) { 164 base::AutoLock locked(lock_); 165 166 std::map<XID, PermanentXIDInfo>::iterator i = 167 perm_xid_to_info_.find(xid); 168 169 if (i == perm_xid_to_info_.end()) 170 return; 171 172 if (i->second.ref_count > 1) { 173 i->second.ref_count--; 174 } else { 175 if (i->second.widget) { 176 gtk_preserve_window_set_preserve(i->second.widget, FALSE); 177 } else { 178 GdkWindow* window = reinterpret_cast<GdkWindow*>( 179 gdk_x11_window_lookup_for_display(gdk_display_get_default(), xid)); 180 DCHECK(window); 181 gdk_window_destroy(window); 182 } 183 perm_xid_to_info_.erase(i); 184 } 185 } 186 187 // ----------------------------------------------------------------------------- 188 189 190 // ----------------------------------------------------------------------------- 191 // Private functions... 192 193 gfx::NativeViewId GtkNativeViewManager::GetWidgetId(gfx::NativeView widget) { 194 lock_.AssertAcquired(); 195 196 std::map<gfx::NativeView, gfx::NativeViewId>::const_iterator i = 197 native_view_to_id_.find(widget); 198 199 CHECK(i != native_view_to_id_.end()); 200 return i->second; 201 } 202 203 void GtkNativeViewManager::OnRealize(gfx::NativeView widget) { 204 base::AutoLock locked(lock_); 205 206 const gfx::NativeViewId id = GetWidgetId(widget); 207 std::map<gfx::NativeViewId, NativeViewInfo>::iterator i = 208 id_to_info_.find(id); 209 210 CHECK(i != id_to_info_.end()); 211 212 GdkWindow* gdk_window = gtk_widget_get_window(widget); 213 CHECK(gdk_window); 214 i->second.x_window_id = GDK_WINDOW_XID(gdk_window); 215 } 216 217 void GtkNativeViewManager::OnUnrealize(gfx::NativeView widget) { 218 base::AutoLock locked(lock_); 219 220 const gfx::NativeViewId id = GetWidgetId(widget); 221 std::map<gfx::NativeViewId, NativeViewInfo>::iterator i = 222 id_to_info_.find(id); 223 224 CHECK(i != id_to_info_.end()); 225 } 226 227 void GtkNativeViewManager::OnDestroy(gfx::NativeView widget) { 228 base::AutoLock locked(lock_); 229 230 std::map<gfx::NativeView, gfx::NativeViewId>::iterator i = 231 native_view_to_id_.find(widget); 232 CHECK(i != native_view_to_id_.end()); 233 234 std::map<gfx::NativeViewId, NativeViewInfo>::iterator j = 235 id_to_info_.find(i->second); 236 CHECK(j != id_to_info_.end()); 237 238 // If the XID is supposed to outlive the widget, mark it 239 // in the lookup table. 240 if (GTK_IS_PRESERVE_WINDOW(widget) && 241 gtk_preserve_window_get_preserve( 242 reinterpret_cast<GtkPreserveWindow*>(widget))) { 243 std::map<XID, PermanentXIDInfo>::iterator k = 244 perm_xid_to_info_.find(GDK_WINDOW_XID(gtk_widget_get_window(widget))); 245 246 if (k != perm_xid_to_info_.end()) 247 k->second.widget = NULL; 248 } 249 250 native_view_to_id_.erase(i); 251 id_to_info_.erase(j); 252 } 253 254 // ----------------------------------------------------------------------------- 255