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.
5 #include "ui/gfx/gtk_native_view_id_manager.h"
10 #include "base/logging.h"
11 #include "base/memory/singleton.h"
12 #include "base/rand_util.h"
13 #include "ui/base/gtk/gdk_x_compat.h"
14 #include "ui/base/gtk/gtk_compat.h"
15 #include "ui/gfx/gtk_preserve_window.h"
17 // -----------------------------------------------------------------------------
18 // Bounce functions for GTK to callback into a C++ object...
20 void OnRealize(gfx::NativeView widget
, void* arg
) {
21 GtkNativeViewManager
* manager
= reinterpret_cast<GtkNativeViewManager
*>(arg
);
22 manager
->OnRealize(widget
);
25 void OnUnrealize(gfx::NativeView widget
, void *arg
) {
26 GtkNativeViewManager
* manager
= reinterpret_cast<GtkNativeViewManager
*>(arg
);
27 manager
->OnUnrealize(widget
);
30 static void OnDestroy(GtkObject
* obj
, void* arg
) {
31 GtkNativeViewManager
* manager
= reinterpret_cast<GtkNativeViewManager
*>(arg
);
32 manager
->OnDestroy(reinterpret_cast<GtkWidget
*>(obj
));
35 // -----------------------------------------------------------------------------
38 // -----------------------------------------------------------------------------
39 // Public functions...
41 GtkNativeViewManager::GtkNativeViewManager() {
44 GtkNativeViewManager::~GtkNativeViewManager() {
48 GtkNativeViewManager
* GtkNativeViewManager::GetInstance() {
49 return Singleton
<GtkNativeViewManager
>::get();
52 gfx::NativeViewId
GtkNativeViewManager::GetIdForWidget(gfx::NativeView widget
) {
53 // This is just for unit tests:
57 base::AutoLock
locked(lock_
);
59 std::map
<gfx::NativeView
, gfx::NativeViewId
>::const_iterator i
=
60 native_view_to_id_
.find(widget
);
62 if (i
!= native_view_to_id_
.end())
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());
72 if (gtk_widget_get_realized(widget
)) {
73 GdkWindow
*gdk_window
= gtk_widget_get_window(widget
);
75 info
.x_window_id
= GDK_WINDOW_XID(gdk_window
);
78 native_view_to_id_
[widget
] = new_id
;
79 id_to_info_
[new_id
] = info
;
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);
88 bool GtkNativeViewManager::GetXIDForId(XID
* output
, gfx::NativeViewId id
) {
89 base::AutoLock
locked(lock_
);
91 std::map
<gfx::NativeViewId
, NativeViewInfo
>::const_iterator i
=
94 if (i
== id_to_info_
.end())
97 *output
= i
->second
.x_window_id
;
101 bool GtkNativeViewManager::GetNativeViewForId(gfx::NativeView
* output
,
102 gfx::NativeViewId id
) {
103 base::AutoLock
locked(lock_
);
105 std::map
<gfx::NativeViewId
, NativeViewInfo
>::const_iterator i
=
106 id_to_info_
.find(id
);
108 if (i
== id_to_info_
.end())
111 *output
= i
->second
.widget
;
115 bool GtkNativeViewManager::GetPermanentXIDForId(XID
* output
,
116 gfx::NativeViewId id
) {
117 base::AutoLock
locked(lock_
);
119 std::map
<gfx::NativeViewId
, NativeViewInfo
>::iterator i
=
120 id_to_info_
.find(id
);
122 if (i
== id_to_info_
.end())
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
);
132 *output
= GDK_WINDOW_XID(gtk_widget_get_window(i
->second
.widget
));
134 // Update the reference count on the permanent XID.
135 PermanentXIDInfo info
;
136 info
.widget
= widget
;
138 std::pair
<std::map
<XID
, PermanentXIDInfo
>::iterator
, bool> ret
=
139 perm_xid_to_info_
.insert(std::make_pair(*output
, info
));
142 DCHECK(ret
.first
->second
.widget
== widget
);
143 ret
.first
->second
.ref_count
++;
149 bool GtkNativeViewManager::AddRefPermanentXID(XID xid
) {
150 base::AutoLock
locked(lock_
);
152 std::map
<XID
, PermanentXIDInfo
>::iterator i
=
153 perm_xid_to_info_
.find(xid
);
155 if (i
== perm_xid_to_info_
.end())
158 i
->second
.ref_count
++;
163 void GtkNativeViewManager::ReleasePermanentXID(XID xid
) {
164 base::AutoLock
locked(lock_
);
166 std::map
<XID
, PermanentXIDInfo
>::iterator i
=
167 perm_xid_to_info_
.find(xid
);
169 if (i
== perm_xid_to_info_
.end())
172 if (i
->second
.ref_count
> 1) {
173 i
->second
.ref_count
--;
175 if (i
->second
.widget
) {
176 gtk_preserve_window_set_preserve(i
->second
.widget
, FALSE
);
178 GdkWindow
* window
= reinterpret_cast<GdkWindow
*>(
179 gdk_x11_window_lookup_for_display(gdk_display_get_default(), xid
));
181 gdk_window_destroy(window
);
183 perm_xid_to_info_
.erase(i
);
187 // -----------------------------------------------------------------------------
190 // -----------------------------------------------------------------------------
191 // Private functions...
193 gfx::NativeViewId
GtkNativeViewManager::GetWidgetId(gfx::NativeView widget
) {
194 lock_
.AssertAcquired();
196 std::map
<gfx::NativeView
, gfx::NativeViewId
>::const_iterator i
=
197 native_view_to_id_
.find(widget
);
199 CHECK(i
!= native_view_to_id_
.end());
203 void GtkNativeViewManager::OnRealize(gfx::NativeView widget
) {
204 base::AutoLock
locked(lock_
);
206 const gfx::NativeViewId id
= GetWidgetId(widget
);
207 std::map
<gfx::NativeViewId
, NativeViewInfo
>::iterator i
=
208 id_to_info_
.find(id
);
210 CHECK(i
!= id_to_info_
.end());
212 GdkWindow
* gdk_window
= gtk_widget_get_window(widget
);
214 i
->second
.x_window_id
= GDK_WINDOW_XID(gdk_window
);
217 void GtkNativeViewManager::OnUnrealize(gfx::NativeView widget
) {
218 base::AutoLock
locked(lock_
);
220 const gfx::NativeViewId id
= GetWidgetId(widget
);
221 std::map
<gfx::NativeViewId
, NativeViewInfo
>::iterator i
=
222 id_to_info_
.find(id
);
224 CHECK(i
!= id_to_info_
.end());
227 void GtkNativeViewManager::OnDestroy(gfx::NativeView widget
) {
228 base::AutoLock
locked(lock_
);
230 std::map
<gfx::NativeView
, gfx::NativeViewId
>::iterator i
=
231 native_view_to_id_
.find(widget
);
232 CHECK(i
!= native_view_to_id_
.end());
234 std::map
<gfx::NativeViewId
, NativeViewInfo
>::iterator j
=
235 id_to_info_
.find(i
->second
);
236 CHECK(j
!= id_to_info_
.end());
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
)));
246 if (k
!= perm_xid_to_info_
.end())
247 k
->second
.widget
= NULL
;
250 native_view_to_id_
.erase(i
);
251 id_to_info_
.erase(j
);
254 // -----------------------------------------------------------------------------