diff options
Diffstat (limited to 'gfx')
-rw-r--r-- | gfx/gtk_native_view_id_manager.cc | 57 | ||||
-rw-r--r-- | gfx/gtk_native_view_id_manager.h | 29 | ||||
-rw-r--r-- | gfx/gtk_preserve_window.cc | 8 |
3 files changed, 87 insertions, 7 deletions
diff --git a/gfx/gtk_native_view_id_manager.cc b/gfx/gtk_native_view_id_manager.cc index 6aa460c..8d9334d 100644 --- a/gfx/gtk_native_view_id_manager.cc +++ b/gfx/gtk_native_view_id_manager.cc @@ -63,7 +63,7 @@ gfx::NativeViewId GtkNativeViewManager::GetIdForWidget(gfx::NativeView widget) { info.widget = widget; if (GTK_WIDGET_REALIZED(widget)) { GdkWindow *gdk_window = widget->window; - CHECK(gdk_window); + DCHECK(gdk_window); info.x_window_id = GDK_WINDOW_XID(gdk_window); } @@ -102,17 +102,52 @@ bool GtkNativeViewManager::GetPermanentXIDForId(XID* output, // We only return permanent XIDs for widgets that allow us to guarantee that // the XID will not change. - if (!GTK_IS_PRESERVE_WINDOW(i->second.widget)) - return false; - + DCHECK(GTK_IS_PRESERVE_WINDOW(i->second.widget)); GtkPreserveWindow* widget = reinterpret_cast<GtkPreserveWindow*>(i->second.widget); gtk_preserve_window_set_preserve(widget, TRUE); *output = GDK_WINDOW_XID(i->second.widget->window); + + // Update the reference count on the permanent XID. + PermanentXIDInfo info; + info.widget = widget; + info.ref_count = 1; + std::pair<std::map<XID, PermanentXIDInfo>::iterator, bool> ret = + perm_xid_to_info_.insert(std::make_pair(*output, info)); + + if (!ret.second) { + DCHECK(ret.first->second.widget == widget); + ret.first->second.ref_count++; + } + return true; } +void GtkNativeViewManager::ReleasePermanentXID(XID xid) { + AutoLock locked(lock_); + + std::map<XID, PermanentXIDInfo>::iterator i = + perm_xid_to_info_.find(xid); + + if (i == perm_xid_to_info_.end()) + return; + + if (i->second.ref_count > 1) { + i->second.ref_count--; + } else { + if (i->second.widget) { + gtk_preserve_window_set_preserve(i->second.widget, FALSE); + } else { + GdkWindow* window = reinterpret_cast<GdkWindow*>( + gdk_xid_table_lookup(xid)); + DCHECK(window); + gdk_window_destroy(window); + } + perm_xid_to_info_.erase(i); + } +} + // ----------------------------------------------------------------------------- @@ -151,8 +186,6 @@ void GtkNativeViewManager::OnUnrealize(gfx::NativeView widget) { id_to_info_.find(id); CHECK(i != id_to_info_.end()); - - i->second.x_window_id = 0; } void GtkNativeViewManager::OnDestroy(gfx::NativeView widget) { @@ -166,6 +199,18 @@ void GtkNativeViewManager::OnDestroy(gfx::NativeView widget) { id_to_info_.find(i->second); CHECK(j != id_to_info_.end()); + // If the XID is supposed to outlive the widget, mark it + // in the lookup table. + if (GTK_IS_PRESERVE_WINDOW(widget) && + gtk_preserve_window_get_preserve( + reinterpret_cast<GtkPreserveWindow*>(widget))) { + std::map<XID, PermanentXIDInfo>::iterator k = + perm_xid_to_info_.find(GDK_WINDOW_XID(widget->window)); + + if (k != perm_xid_to_info_.end()) + k->second.widget = NULL; + } + native_view_to_id_.erase(i); id_to_info_.erase(j); } diff --git a/gfx/gtk_native_view_id_manager.h b/gfx/gtk_native_view_id_manager.h index 513537a..05cf0d7 100644 --- a/gfx/gtk_native_view_id_manager.h +++ b/gfx/gtk_native_view_id_manager.h @@ -12,6 +12,7 @@ #include "gfx/native_widget_types.h" typedef unsigned long XID; +struct _GtkPreserveWindow; // NativeViewIds are the opaque values which the renderer holds as a reference // to a window. These ids are often used in sync calls from the renderer and @@ -70,6 +71,14 @@ class GtkNativeViewManager { // returns: true if |id| is a valid id, false otherwise. bool GetPermanentXIDForId(XID* xid, gfx::NativeViewId id); + // Must be called from the UI thread because we may need to access a + // GtkWidget or destroy a GdkWindow. + // + // If the widget associated with the XID is still alive, allow the widget + // to destroy the associated XID when it wants. Otherwise, destroy the + // GdkWindow associated with the XID. + void ReleasePermanentXID(XID xid); + // These are actually private functions, but need to be called from statics. void OnRealize(gfx::NativeView widget); void OnUnrealize(gfx::NativeView widget); @@ -105,6 +114,26 @@ class GtkNativeViewManager { std::map<gfx::NativeView, gfx::NativeViewId> native_view_to_id_; std::map<gfx::NativeViewId, NativeViewInfo> id_to_info_; + struct PermanentXIDInfo { + PermanentXIDInfo() : widget(NULL), ref_count(0) { + } + _GtkPreserveWindow* widget; + int ref_count; + }; + + // Used to maintain the reference count for permanent XIDs + // (referenced by GetPermanentXIDForId and dereferenced by + // ReleasePermanentXID). Only those XIDs with a positive reference count + // will be in the table. + // + // In general, several GTK widgets may share the same X window. We assume + // that is not true of the widgets stored in this registry. + // + // An XID will map to NULL, if there is an outstanding reference but the + // widget was destroyed. In this case, the destruction of the X window + // is deferred to the dropping of all references. + std::map<XID, PermanentXIDInfo> perm_xid_to_info_; + DISALLOW_COPY_AND_ASSIGN(GtkNativeViewManager); }; diff --git a/gfx/gtk_preserve_window.cc b/gfx/gtk_preserve_window.cc index c49bd31..20215d1 100644 --- a/gfx/gtk_preserve_window.cc +++ b/gfx/gtk_preserve_window.cc @@ -61,10 +61,13 @@ GtkWidget* gtk_preserve_window_new() { static void gtk_preserve_window_destroy(GtkObject* object) { GtkWidget* widget = reinterpret_cast<GtkWidget*>(object); + GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget); if (widget->window) { gdk_window_set_user_data(widget->window, NULL); - gdk_window_destroy(widget->window); + // If the window is preserved, someone else must destroy it. + if (!priv->preserve_window) + gdk_window_destroy(widget->window); widget->window = NULL; } @@ -167,6 +170,9 @@ void gtk_preserve_window_set_preserve(GtkPreserveWindow* window, attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP; widget->window = gdk_window_new( gdk_get_default_root_window(), &attributes, attributes_mask); + } else if (!value && widget->window && !GTK_WIDGET_REALIZED(widget)) { + gdk_window_destroy(widget->window); + widget->window = NULL; } } |