b=540114 reparent foreign children of the socket window before it gets destroyed r=cjones
authorKarl Tomlinson <karlt+@karlt.net>
Tue, 16 Feb 2010 10:40:46 +1300
changeset 46681 448ac1b0a3917253acf8e87f96218e7eeb6eec8b
parent 46680 8b8708718f6dfec6b4d7e0e7dca8fed7f6d0a9bf
child 46682 eb57ae66e03f27e921848c2da38cf8cad140d5a8
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewerscjones
bugs540114
milestone1.9.3a2pre
b=540114 reparent foreign children of the socket window before it gets destroyed r=cjones
modules/plugin/base/src/nsPluginNativeWindowGtk2.cpp
--- a/modules/plugin/base/src/nsPluginNativeWindowGtk2.cpp
+++ b/modules/plugin/base/src/nsPluginNativeWindowGtk2.cpp
@@ -86,16 +86,17 @@ private:
     gpointer data);
 
   Damage     mDamage;
   GtkWidget* mParentWindow;
 #endif
 };
 
 static gboolean plug_removed_cb   (GtkWidget *widget, gpointer data);
+static void socket_unrealize_cb   (GtkWidget *widget, gpointer data);
 
 nsPluginNativeWindowGtk2::nsPluginNativeWindowGtk2() : nsPluginNativeWindow()
 {
   // initialize the struct fields
   window = nsnull; 
   x = 0; 
   y = 0; 
   width = 0; 
@@ -246,16 +247,19 @@ nsresult nsPluginNativeWindowGtk2::Creat
 
   // Make sure to handle the plug_removed signal.  If we don't the
   // socket will automatically be destroyed when the plug is
   // removed, which means we're destroying it more than once.
   // SYNTAX ERROR.
   g_signal_connect(mSocketWidget, "plug_removed",
                    G_CALLBACK(plug_removed_cb), NULL);
 
+  g_signal_connect(mSocketWidget, "unrealize",
+                   G_CALLBACK(socket_unrealize_cb), NULL);
+
   g_signal_connect(mSocketWidget, "destroy",
                    G_CALLBACK(gtk_widget_destroyed), &mSocketWidget);
 
   gpointer user_data = NULL;
   gdk_window_get_user_data(parent_win, &user_data);
 
   GtkContainer *container = GTK_CONTAINER(user_data);
   gtk_container_add(container, mSocketWidget);
@@ -440,9 +444,40 @@ PRBool nsPluginNativeWindowGtk2::CanGetV
 /* static */
 gboolean
 plug_removed_cb (GtkWidget *widget, gpointer data)
 {
   // Gee, thanks for the info!
   return TRUE;
 }
 
+static void
+socket_unrealize_cb(GtkWidget *widget, gpointer data)
+{
+  // Unmap and reparent any child windows that GDK does not yet know about.
+  // (See bug 540114 comment 10.)
+  GdkWindow* socket_window = widget->window;
+  Display* display = GDK_DISPLAY();
 
+  // Ignore X errors that may happen if windows get destroyed (possibly
+  // requested by the plugin) between XQueryTree and when we operate on them.
+  gdk_error_trap_push();
+
+  Window root, parent;
+  Window* children;
+  unsigned int nchildren;
+  if (!XQueryTree(display, gdk_x11_drawable_get_xid(socket_window),
+                  &root, &parent, &children, &nchildren))
+    return;
+
+  for (unsigned int i = 0; i < nchildren; ++i) {
+    Window child = children[i];
+    if (!gdk_window_lookup(child)) {
+      // This window is not known to GDK.
+      XUnmapWindow(display, child);
+      XReparentWindow(display, child, DefaultRootWindow(display), 0, 0);
+    }
+  }
+
+  if (children) XFree(children);
+
+  gdk_error_trap_pop();
+}