Updated unexpected window destruction patch.




Hello guys,

    Here is my new window destruction patch, updated to reflect
everyone's suggestions.  It really improves the robustness of Bonobo
components dramatically, so it would be a boon for us if it could make
it into the next Gtk 1.2 distribution.  If there's anything I can do
to facilitate this, please let me know.

Best,
Nat

Sun Aug 22 19:08:28 1999  Nat Friedman  <nat@nat.org>

	* gtk/gtkplug.c (gtk_plug_class_init): Override the widget class
 	unrealize function with gtk_plug_unrealize.  Store a new
 	GtkWindowClass in a static global, parent_class.
	(gtk_plug_construct): Store the widget pointer in the
 	socket_window's user data.
	(gtk_plug_unrealize): New unrealize handler for GtkPlug.

	* gdk/gdkwindow.c (gdk_window_destroy_notify_new):
 	gdk_window_destroy_notify was renamed to this function to maintain
 	binary compatibility.  If a window is unexpectedly destroyed,
 	rewrite the DestroyNotify event to occur on the window's first
 	foreign ancestor, if it has one.
	(gdk_window_destroy_notify): Call gdk_window_destroy_notify_new.

	* gdk/gdkevents.c (gdk_event_translate): Pass the event to
 	gdk_window_destroy_notify_new.

Index: gdk/gdkevents.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkevents.c,v
retrieving revision 1.20.2.6
diff -u -r1.20.2.6 gdkevents.c
--- gdk/gdkevents.c	1999/08/20 02:18:15	1.20.2.6
+++ gdk/gdkevents.c	1999/08/24 18:03:44
@@ -1622,7 +1622,8 @@
       return_val = window_private && !window_private->destroyed;
       
       if(window && window_private->xwindow != GDK_ROOT_WINDOW())
-	gdk_window_destroy_notify (window);
+	gdk_window_destroy_notify_new (window, event);
+
       break;
       
     case UnmapNotify:
Index: gdk/gdkprivate.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkprivate.h,v
retrieving revision 1.36
diff -u -r1.36 gdkprivate.h
--- gdk/gdkprivate.h	1999/02/24 07:33:09	1.36
+++ gdk/gdkprivate.h	1999/08/24 18:03:44
@@ -241,6 +241,8 @@
 
 void gdk_window_add_colormap_windows (GdkWindow *window);
 void gdk_window_destroy_notify	     (GdkWindow *window);
+/* Take note: gdk_window_destroy_notify_new will be removed in 1.3 */
+void gdk_window_destroy_notify_new   (GdkWindow *window, GdkEvent *event);
 
 void	 gdk_xid_table_insert (XID	*xid,
 			       gpointer	 data);
Index: gdk/gdkwindow.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkwindow.c,v
retrieving revision 1.80.2.5
diff -u -r1.80.2.5 gdkwindow.c
--- gdk/gdkwindow.c	1999/08/18 20:21:06	1.80.2.5
+++ gdk/gdkwindow.c	1999/08/24 18:03:44
@@ -687,12 +687,11 @@
 }
 
 /* This function is called when the XWindow is really gone.  */
-
 void
-gdk_window_destroy_notify (GdkWindow *window)
+gdk_window_destroy_notify_new (GdkWindow *window, GdkEvent *event)
 {
   GdkWindowPrivate *private;
-  
+
   g_return_if_fail (window != NULL);
   
   private = (GdkWindowPrivate*) window;
@@ -701,12 +700,50 @@
     {
       if (private->window_type == GDK_WINDOW_FOREIGN)
 	gdk_window_internal_destroy (window, FALSE, FALSE);
-      else
+      else {
+	GdkWindowPrivate *parent;
+
 	g_warning ("GdkWindow %#lx unexpectedly destroyed", private->xwindow);
+
+	gdk_window_internal_destroy (window, FALSE, FALSE);
+
+	/*
+	 * A window has been unexpectedly destroyed by the X server.
+	 *
+	 * In the case where a foreign, reparented window (such as is
+	 * used by GtkPlug) is destroyed by the death of the client
+	 * which created it, the X server will recursively destroy all
+	 * of that window's subwindows.  In what is effectively a
+	 * random order.  So what we do here is to walk up the window
+	 * tree until we encounter the first foreign window, and
+	 * rewrite the event to occur on that window.  That way, the
+	 * first widget to be destroyed will be the GtkPlug, and its
+	 * subwidgets can be killed politely.
+	 *
+	 * If there is no foreign ancestral window, we don't rewrite
+	 * the event.
+	 */
+	parent = private;
+	while (parent != NULL && parent->window_type != GDK_WINDOW_FOREIGN)
+	  parent = (GdkWindowPrivate *) parent->parent;
+
+	if (parent != NULL)
+	  event->any.window = (GdkWindow *) parent;
+      }
     }
   
   gdk_xid_table_remove (private->xwindow);
   gdk_window_unref (window);
+}
+
+/*
+ * FIXME: gdk_window_destroy_notify() and
+ * gdk_window_destroy_notify_new() should be consolidated in 1.3.
+ */
+void
+gdk_window_destroy_notify (GdkWindow *window)
+{
+  gdk_window_destroy_notify_new (window, NULL);
 }
 
 GdkWindow*
cvs server: Diffing gtk
Index: gtk/gtkplug.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkplug.c,v
retrieving revision 1.6
diff -u -r1.6 gtkplug.c
--- gtk/gtkplug.c	1999/02/24 07:35:47	1.6
+++ gtk/gtkplug.c	1999/08/24 18:03:44
@@ -29,10 +29,13 @@
 #include "gdk/gdkkeysyms.h"
 #include "gtkplug.h"
 
+static GtkWindowClass *parent_class = NULL;
+
 static void gtk_plug_class_init (GtkPlugClass *klass);
 static void gtk_plug_init       (GtkPlug      *plug);
 
 static void gtk_plug_realize    (GtkWidget *widget);
+static void gtk_plug_unrealize	(GtkWidget *widget);
 static gint gtk_plug_key_press_event (GtkWidget   *widget,
 				      GdkEventKey *event);
 static void gtk_plug_forward_key_press (GtkPlug *plug, GdkEventKey *event);
@@ -76,8 +79,10 @@
 
   widget_class = (GtkWidgetClass *)class;
   window_class = (GtkWindowClass *)class;
+  parent_class = gtk_type_new (GTK_TYPE_WINDOW);
 
   widget_class->realize = gtk_plug_realize;
+  widget_class->unrealize = gtk_plug_unrealize;
   widget_class->key_press_event = gtk_plug_key_press_event;
   widget_class->focus_in_event = gtk_plug_focus_in_event;
   widget_class->focus_out_event = gtk_plug_focus_out_event;
@@ -105,6 +110,7 @@
   if (plug->socket_window == NULL)
     {
       plug->socket_window = gdk_window_foreign_new (socket_id);
+      gdk_window_set_user_data (plug->socket_window, plug);
       plug->same_app = FALSE;
     }
 }
@@ -117,6 +123,29 @@
   plug = GTK_PLUG (gtk_type_new (gtk_plug_get_type ()));
   gtk_plug_construct (plug, socket_id);
   return GTK_WIDGET (plug);
+}
+
+static void
+gtk_plug_unrealize (GtkWidget *widget)
+{
+  GtkPlug *plug;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_PLUG (widget));
+
+  plug = GTK_PLUG (widget);
+
+  if (plug->socket_window != NULL)
+    {
+      gdk_window_set_user_data (plug->socket_window, NULL);
+      gdk_window_destroy (plug->socket_window);
+
+      gdk_window_set_user_data (widget->window, NULL);
+      gdk_window_destroy (widget->window);
+    }
+
+  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
+    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
 }
 
 static void



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]