GtkPlug/GtkSocket workaround for Bonobo




We really need the following change for Nautilus work. OK if I check
it in? I checked that Bonobo still works with it in both the in-proc
and out-of-proc control cases, and I am pretty sure the memory
management works out properly.


2000-01-25  Maciej Stachowiak  <mjs@eazel.com>

	* bonobo/bonobo-control.c, bonobo/bonobo-control-frame.c: Detect
	when the control is in the same process as the frame; in that
	case, reduce to a simple containement relationship instead of
	using GtkPlug/GtkSocket, to avoid bugs in GtkPlug/GtkSocket in the
	same-application case.

Index: bonobo/bonobo-control-frame.c
===================================================================
RCS file: /cvs/gnome/bonobo/bonobo/bonobo-control-frame.c,v
retrieving revision 1.8
diff -u -r1.8 bonobo-control-frame.c
--- bonobo/bonobo-control-frame.c	2000/01/24 23:43:10	1.8
+++ bonobo/bonobo-control-frame.c	2000/01/25 09:19:09
@@ -12,6 +12,7 @@
 #include <gtk/gtksignal.h>
 #include <gtk/gtkmarshal.h>
 #include <gtk/gtkplug.h>
+#include <gtk/gtkframe.h>
 #include <bonobo/gnome-main.h>
 #include <bonobo/gnome-control.h>
 #include <bonobo/gnome-control-frame.h>
@@ -37,6 +38,7 @@
 
 struct _GnomeControlFramePrivate {
 	GNOME_Control	  control;
+	GtkWidget        *control;
 	GtkWidget	 *socket;
 	GnomeUIHandler   *uih;
 	GnomePropertyBag *propbag;
@@ -198,9 +200,21 @@
 	gtk_widget_show (control_frame->priv->socket);
 
 	/*
-	 * When the socket is realized, we pass its Window ID to our
-	 * Control.
+	 * Finally, create a frame to hold the socket; this no-window
+	 * container is needed solely for the sake of bypassing
+	 * plug/socket in the local case.
 	 */
+	control_frame->priv->container = gtk_frame_new(NULL);
+	gtk_frame_set_shadow_type ( GTK_FRAME (control_frame->priv->container), GTK_SHADOW_NONE);
+	gtk_container_set_border_width (GTK_CONTAINER (control_frame->priv->container), 0);
+	gtk_container_add (GTK_CONTAINER (control_frame->priv->container), 
+			   control_frame->priv->socket);
+	gtk_widget_show (control_frame->priv->container);
+
+
+	/*
+	 * When the socket is realized, we pass its Window ID to our
+	 * Control.  */
 	gtk_signal_connect (GTK_OBJECT (control_frame->priv->socket),
 			    "realize",
 			    GTK_SIGNAL_FUNC (gnome_control_frame_set_remote_window),
@@ -525,7 +539,7 @@
 	g_return_val_if_fail (control_frame != NULL, NULL);
 	g_return_val_if_fail (GNOME_IS_CONTROL_FRAME (control_frame), NULL);
 
-	return control_frame->priv->socket;
+	return control_frame->priv->container;
 }
 
 /**
Index: bonobo/bonobo-control.c
===================================================================
RCS file: /cvs/gnome/bonobo/bonobo/bonobo-control.c,v
retrieving revision 1.12
diff -u -r1.12 bonobo-control.c
--- bonobo/bonobo-control.c	2000/01/25 07:22:50	1.12
+++ bonobo/bonobo-control.c	2000/01/25 09:19:09
@@ -35,6 +35,7 @@
 	GtkWidget          *plug;
 
 	int                 plug_destroy_id;
+	gboolean            is_local;
 
 	GtkWidget          *widget;
 
@@ -156,25 +157,56 @@
 	gnome_control_set_control_frame (control, frame);
 }
 
+
+
+GtkWidget *bonobo_gtk_widget_from_x11_id(guint32 xid)
+{
+	GdkWindow *window;
+	gpointer data;
+
+	window = gdk_window_lookup (xid);
+	
+	if (!window) {
+		return NULL;
+	}
+
+	gdk_window_get_user_data(window, &data);
+
+	if (!data || !GTK_IS_WIDGET(data)) {
+		return NULL;
+	} else {
+		return GTK_WIDGET(data);
+	}
+}
+
 static void
 impl_GNOME_Control_set_window (PortableServer_Servant servant,
 			       GNOME_Control_windowid id,
 			       CORBA_Environment *ev)
 {
 	guint32 x11_id;
+	GtkWidget *local_socket;
 	GnomeControl *control = GNOME_CONTROL (gnome_object_from_servant (servant));
 
 	x11_id = window_id_demangle (id);
 
-	control->priv->plug = gtk_plug_new (x11_id);
-	control->priv->plug_destroy_id = gtk_signal_connect (
-		GTK_OBJECT (control->priv->plug), "destroy_event",
-		GTK_SIGNAL_FUNC (gnome_control_plug_destroy_cb), control);
+	local_socket = bonobo_gtk_widget_from_x11_id(x11_id);
 
-
-	gtk_container_add (GTK_CONTAINER (control->priv->plug), control->priv->widget);
-
-	gtk_widget_show_all (control->priv->plug);
+	if (local_socket) {
+		GtkWidget *socket_parent;
+		control->priv->is_local = TRUE;
+		socket_parent = local_socket->parent;
+		gtk_container_remove (GTK_CONTAINER (socket_parent), local_socket);
+		gtk_container_add (GTK_CONTAINER (socket_parent), control->priv->widget);
+		gtk_widget_show_all (control->priv->widget);
+	} else {
+		control->priv->plug = gtk_plug_new (x11_id);
+		control->priv->plug_destroy_id = gtk_signal_connect (
+		        GTK_OBJECT (control->priv->plug), "destroy_event",
+		        GTK_SIGNAL_FUNC (gnome_control_plug_destroy_cb), control);
+		gtk_container_add (GTK_CONTAINER (control->priv->plug), control->priv->widget);
+		gtk_widget_show_all (control->priv->plug);
+	}
 }
 
 static void
@@ -187,7 +219,8 @@
 	 * Nothing.
 	 *
 	 * In the Gnome implementation of Bonobo, all size negotiation
-	 * is handled by GtkPlug/GtkSocket for us.
+	 * is handled by GtkPlug/GtkSocket for us, or GtkFrame in the
+	 * local case.
 	 */
 }
 
@@ -327,11 +360,14 @@
 	/*
 	 * If the plug still exists, destroy it.  The plug might not
 	 * exist in the case where the container application died,
-	 * taking the plug out with it.  In that case,
-	 * plug_destroy_cb() would have been invoked, and it would
-	 * have triggered the destruction of the Control.  Which is why
-	 * we're here now.
+	 * taking the plug out with it, or the optimized local case
+	 * where the plug/socket mechanism was bypassed.  In the
+	 * formaer case, plug_destroy_cb() would have been invoked,
+	 * and it would have triggered the destruction of the Control,
+	 * which is why we're here now. In the latter case, it's not
+	 * needed because there is no plug.  
 	 */
+
 	if (control->priv->plug) {
 		gtk_signal_disconnect (GTK_OBJECT (control->priv->plug), control->priv->plug_destroy_id);
 		gtk_object_destroy (GTK_OBJECT (control->priv->plug));



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