Fixes for Deprecated Canvas Components



Hello,

	I know canvas component is deprecated, but it looked too good not to
try out. After many hours of debugging, I have it working perfectly, at
least with respect to its original design.

	I don't know if there are any plans to keep canvas components in
BonoboUI, but just in case, I thought I'd offer the changes to the 
group. I think using the canvas SVP as a separation layer from a canvas
application has lots of potential.

	At the moment, I don't have CVS commit access, but if you want me to
submit the changes I can get set up.

	I also have a very simple demo program that shows two-way events
between multiple canvas's and components at greater than 100hz.

Thanks
Bob Gibbs.
                
===========================================================================
                
ChangeLog:

bonobo-canvas-component.h

(bonobo_canvas_component_factory_new): new.  Convenience to replace old
embeddable way of creating the canvas component.

bonobo-canvas-component.c

(impl_Bonobo_Canvas_Component_update): Call rih group update here vice
inside
rih_update. Solves for case where a request_update is made while the
component
is waiting for a response.

(handle_event): new. Passes the remote item's event back into the
local pseudo-canvas so that canvas items can see events the normal way
as if
they were not using bonobo.

(rih_update): Moved rih group update into
impl_Bonobo_Canvas_Component_update.
This solves for case where a request_update is made while the component
is
waiting for a response to its last
Bonobo_Canvas_ComponentProxy_requestUpdate.

(impl_Bonobo_Canvas_Component_event): Added mutex lock check to prevent
event
from being passed if any pseudo-canvas is in its idle loop. This is not
thread
related.  See code for further info.

(bonobo_canvas_new): Put into container to prevent gtk warning.

(bonobo_canvas_component_factory_new): new.  Convenience to replace old
embeddable way of creating the canvas component.

bonobo-canvas-item.c

(gbi_set_property): Moved proxy_size_allocate call from gbi_set_property
to
gbi_realize. Sometimes widget is not realized when user sets the
properties.

(gdk_event_to_bonobo_event): fixed x/y mixup for motion notify

(bonobo_canvas_item_class_init): Make sure set_property callback is
initialized
before calling install_property.

(impl_Bonobo_Canvas_ComponentProxy_requestUpdate): Added idle_handler
that
gets invoked whenever the canvas has already had one added.  This solves
for
case of NEED_UPDATE flags getting out of sync and canvas refusing to
update the
remote item forever thereafter. See code for further details.

(create_proxy): Fixed to allocate space for base epv before
initializing.


===========================================================================
--- bonobo-canvas-component.h.orig	Mon Mar 24 09:43:14 2003
+++ bonobo-canvas-component.h	Mon Mar 24 09:43:46 2003
@@ -69,6 +69,16 @@
 GnomeCanvas *bonobo_canvas_new (gboolean                     is_aa,
 				Bonobo_Canvas_ComponentProxy proxy);
 
+
+/* Sets up a callback to be invoked when the container activates the
object.
+ * Creating the component factory will do nothing until the container
connects.
+ */
+typedef BonoboCanvasComponent *(*GnomeItemCreator) 
+   (GnomeCanvas *canvas, void *user_data);
+
+BonoboObject *bonobo_canvas_component_factory_new(GnomeItemCreator
item_factory,
+      void *data);
+
 G_END_DECLS
 
 #endif /* BONOBO_UI_DISABLE_DEPRECATED */


===========================================================================
--- bonobo-canvas-component.c.orig	Mon Mar 24 09:42:46 2003
+++ bonobo-canvas-component.c	Mon Apr 14 21:42:11 2003
@@ -16,10 +16,13 @@
 #include <libgnomecanvas/gnome-canvas.h>
 #include <gdk/gdkx.h>
 #include <gdk/gdkprivate.h>
+#include <gtk/gtk.h>
 #include <bonobo/bonobo-exception.h>
 #include <bonobo/bonobo-ui-component.h>
 #include <bonobo/bonobo-canvas-component.h>
 #include <bonobo/bonobo-ui-marshal.h>
+#undef BONOBO_DISABLE_DEPRECATED
+#include <bonobo/bonobo-xobject.h>
 
 enum {
 	SET_BOUNDS,
@@ -171,9 +174,11 @@
 			    | GNOME_CANVAS_UPDATE_CLIP
 			    | GNOME_CANVAS_UPDATE_VISIBILITY))
 	    && GNOME_CANVAS_ITEM_GET_CLASS (item)->update)
+        {
 		(* GNOME_CANVAS_ITEM_GET_CLASS (item)->update) (
 			item, child_affine, clip_path, child_flags);
-}
+        }
+}       
 
 static Bonobo_Canvas_ArtUTA *
 impl_Bonobo_Canvas_Component_update (PortableServer_Servant    
servant,
@@ -194,6 +199,8 @@
 	ArtSVP *svp = NULL;
 	Bonobo_Canvas_ArtUTA *cuta;
 
+	GnomeCanvasItemClass *gci_class = gtk_type_class (
+					gnome_canvas_item_get_type ());
 	restore_state (item, state);
 	for (i = 0; i < 6; i++)
 		affine [i] = aff [i];
@@ -221,7 +228,7 @@
 			}
 		}
 	}
-	
+
 	invoke_update (item, (double *)aff, svp, flags);
 
 	if (svp){
@@ -247,6 +254,10 @@
 	/*
 	 * Now, mark our canvas as fully up to date
 	 */
+
+        /* Clears flags for root item. */
+	(* gci_class->update) (item->canvas->root, affine, svp, flags);
+
 	if (item->canvas->redraw_area) {
 		art_uta_free (item->canvas->redraw_area);
 		item->canvas->redraw_area = NULL;
@@ -540,6 +551,82 @@
 		g_free (event->key.string);
 }
 
+/**
+ * handle_event:
+ * @canvas: the pseudo-canvas that this component is part of.
+ * @ev: The GdkEvent event as set up for the component.
+ *
+ * Returns: True if a canvas item handles the event and returns true.
+ *
+ * Passes the remote item's event back into the local pseudo-canvas so
that
+ * canvas items can see events the normal way as if they were not using
bonobo.
+ */
+static gboolean 
+handle_event(GtkWidget* canvas, GdkEvent *ev)
+{
+        GtkWidgetClass *klass = GTK_WIDGET_GET_CLASS(canvas);
+        gboolean retval = 0;
+
+        switch (ev->type) {
+                case GDK_ENTER_NOTIFY:
+                       
gnome_canvas_world_to_window(GNOME_CANVAS(canvas),
+                                        ev->crossing.x, ev->crossing.y,
+                                        &ev->crossing.x,
&ev->crossing.y);
+                        retval = (klass->enter_notify_event)(canvas, 
+                                        &ev->crossing);
+                        break;
+                case GDK_LEAVE_NOTIFY:
+                       
gnome_canvas_world_to_window(GNOME_CANVAS(canvas),
+                                        ev->crossing.x, ev->crossing.y,
+                                        &ev->crossing.x,
&ev->crossing.y);
+                        retval = (klass->leave_notify_event)(canvas, 
+                                        &ev->crossing);
+                        break;
+                case GDK_MOTION_NOTIFY:
+                       
gnome_canvas_world_to_window(GNOME_CANVAS(canvas),
+                                        ev->motion.x, ev->motion.y,
+                                        &ev->motion.x, &ev->motion.y);
+                        retval = (klass->motion_notify_event)(canvas, 
+                                        &ev->motion);
+                        break;
+                case GDK_BUTTON_PRESS:
+                case GDK_2BUTTON_PRESS:
+                case GDK_3BUTTON_PRESS:
+                       
gnome_canvas_world_to_window(GNOME_CANVAS(canvas),
+                                        ev->button.x, ev->button.y,
+                                        &ev->button.x, &ev->button.y);
+                        retval = (klass->button_press_event)(canvas, 
+                                        &ev->button);
+                        break;
+                case GDK_BUTTON_RELEASE:
+                       
gnome_canvas_world_to_window(GNOME_CANVAS(canvas),
+                                        ev->button.x, ev->button.y,
+                                        &ev->button.x, &ev->button.y);
+                        retval = (klass->button_release_event)(canvas, 
+                                        &ev->button);
+                        break;
+                case GDK_KEY_PRESS:
+                        retval = (klass->key_press_event)(canvas,
&ev->key);
+                        break;
+                case GDK_KEY_RELEASE:
+                        retval = (klass->key_release_event)(canvas,
&ev->key);
+                        break;
+                case GDK_FOCUS_CHANGE:
+                        if (&ev->focus_change.in)
+                                retval =
(klass->focus_in_event)(canvas,
+                                        &ev->focus_change);
+                        else
+                                retval =
(klass->focus_out_event)(canvas,
+                                        &ev->focus_change);
+                        break;
+                default:
+                        g_warning("Canvas event not handled %d",
ev->type);
+                        break;
+
+        }
+        return retval;
+}
+
 /*
  * Receives events from the container end, decodes it into a synthetic
  * GdkEvent and forwards this to the CanvasItem
@@ -553,19 +640,56 @@
 	Gcc *gcc = GCC (bonobo_object_from_servant (servant));
 	GnomeCanvasItem *item = GNOME_CANVAS_ITEM (gcc->priv->item);
 	GdkEvent gdk_event;
-	int retval;
-
-	Bonobo_Gdk_Event_to_GdkEvent (gnome_event, &gdk_event);
+	int retval = 0;
 
 	restore_state (item, state);
+        
+        gdk_event.any.window = item->canvas->layout.bin_window;
 
-	g_signal_emit_by_name (gcc, "event", &gdk_event);
-
-	if (ICLASS (item)->event)
-		retval = ICLASS (item)->event (item, &gdk_event);
-	else
-		retval = FALSE;
+	Bonobo_Gdk_Event_to_GdkEvent (gnome_event, &gdk_event);
 
+        /*
+         * Problem:
+         * When dealing with multiple canvas component's within the
same process
+         * it is possible to get to this point when one of the
pseudo-canvas's
+         * is inside its idle loop.  This is normally not a problem
unless an
+         * event from one component can trigger a request for an update
on
+         * another component.
+         *
+         * In this way programs that use bonobo/orbit proxies behave
like
+         * multithreaded programs even if they are not multi-threaded
+         * programs.
+         *
+         * Solution:
+         * The only way I can think of at the moment to remedy this
situation is
+         * to not allow a item event to occur if any of the
pseudo-canvas's are
+         * inside their idle loop. i.e., Throw away the event. Because
this is a
+         * rare case, at least I think it is, I have added this mutex
check.
+         * For this to work, the main program must call g_thread_init()
and
+         * gdk_threads_init() whether it is using threads or not.
+         *
+         * Main programs that do not have this multiple component
effect
+         * described above do not need to initialize for threads and
everything
+         * will work fine.
+         *
+         * A better solution may be to implement a special mutex lock
inside the
+         * gnome canvas with a public interface specifically for
supporting
+         * Bonobo. A secondary problem resulting from this logic is
that it is
+         * possible for an even to get dropped.  This is no big deal
for motion
+         * events but could be for focus events.
+         */
+        if (gdk_threads_mutex) {
+               if (g_mutex_trylock(gdk_threads_mutex)) {
+
+                        retval = handle_event(GTK_WIDGET(item->canvas),
+                                        &gdk_event);
+                        g_mutex_unlock(gdk_threads_mutex);
+
+               }
+        }
+        else 
+                retval = handle_event(GTK_WIDGET(item->canvas),
&gdk_event);
+                
 	free_event (&gdk_event);
 
 	return retval;
@@ -809,23 +933,10 @@
 {
 	RootItemHack *rih = (RootItemHack *) item;
 	CORBA_Environment ev;
-	GnomeCanvasItemClass *gci_class = gtk_type_class (
-					gnome_canvas_item_get_type ());
 
 	CORBA_exception_init (&ev);
 	Bonobo_Canvas_ComponentProxy_requestUpdate (rih->proxy, &ev);
 	CORBA_exception_free (&ev);
-
-	/*
-	 * Mark our canvas and item as fully updated
-	 */
-
-	(* gci_class->update) (item, affine, svp, flags);
-
-	if (item->canvas->redraw_area)
-		art_uta_free (item->canvas->redraw_area);
-	item->canvas->redraw_area = NULL;
-	item->canvas->need_redraw = FALSE;
 }
 
 static void
@@ -898,8 +1009,12 @@
 
 	canvas->root = GNOME_CANVAS_ITEM (root_item_hack_new (canvas, proxy));
 
+        /* A hack to prevent gtkwidget from issuing a warning about
there not
+           being a parent class. */
+        gtk_container_add(GTK_CONTAINER
(gtk_window_new(GTK_WINDOW_TOPLEVEL)),
+                            GTK_WIDGET(canvas));
 	gtk_widget_realize (GTK_WIDGET (canvas));
-	
+
 	/* Gross */
 	GTK_WIDGET_SET_FLAGS (canvas, GTK_VISIBLE | GTK_MAPPED);
 
@@ -990,3 +1105,103 @@
 	return corba_uic;
 }
 
+/* BonoboCanvasComponentFactory is used to replace the old
BonoboEmbeddable
+ * object.  It sets up a canvas component factory to conform with the
current
+ * Bonobo IDL.
+ */
+
+#define BONOBO_CANVAS_COMPONENT_FACTORY_TYPE       \
+   (bonobo_canvas_component_factory_get_type())
+
+#define BONOBO_CANVAS_COMPONENT_FACTORY(o)    \
+   (G_TYPE_CHECK_INSTANCE_CAST ((o),\
+   BONOBO_CANVAS_COMPONENT_FACTORY_TYPE, BonoboCanvasComponentFactory))
+
+typedef struct _BonoboCanvasComponentFactoryPrivate \
+   BonoboCanvasComponentFactoryPrivate;
+
+typedef struct {
+        BonoboObject base;
+        BonoboCanvasComponentFactoryPrivate *priv;
+} BonoboCanvasComponentFactory;
+
+typedef struct {
+        BonoboObjectClass parent_class;
+
+        POA_Bonobo_CanvasComponentFactory__epv epv;
+} BonoboCanvasComponentFactoryClass;
+       
+GType bonobo_canvas_component_factory_get_type(void) G_GNUC_CONST;
+
+struct _BonoboCanvasComponentFactoryPrivate {
+   GnomeItemCreator item_creator;
+   void *item_creator_data;
+};
+
+static GObjectClass *gccf_parent_class;
+
+static Bonobo_Canvas_Component
+impl_Bonobo_canvas_component_factory_createCanvasItem (
+   PortableServer_Servant servant, CORBA_boolean aa,
+   const Bonobo_Canvas_ComponentProxy _item_proxy,
+   CORBA_Environment *ev)
+{
+        BonoboCanvasComponentFactory *factory =
BONOBO_CANVAS_COMPONENT_FACTORY(
+              bonobo_object_from_servant (servant));
+        Bonobo_Canvas_ComponentProxy item_proxy;
+        BonoboCanvasComponent *component;
+        GnomeCanvas *pseudo_canvas;
+
+        if (factory->priv->item_creator == NULL)
+                return CORBA_OBJECT_NIL;
+
+        item_proxy = CORBA_Object_duplicate (_item_proxy, ev);
+
+	pseudo_canvas = bonobo_canvas_new (aa, item_proxy);
+
+        component = (*factory->priv->item_creator)(
+                /*factory,*/ pseudo_canvas,
factory->priv->item_creator_data);
+
+        return bonobo_object_dup_ref (BONOBO_OBJREF (component), ev);
+}
+
+static void
+bonobo_canvas_component_factory_class_init (
+      BonoboCanvasComponentFactoryClass *klass)
+{
+        POA_Bonobo_CanvasComponentFactory__epv *epv = &klass->epv;
+
+        gccf_parent_class = g_type_class_peek_parent(klass);
+        epv->createCanvasComponent = 
+           impl_Bonobo_canvas_component_factory_createCanvasItem;
+}
+
+static void
+bonobo_canvas_component_factory_init (BonoboCanvasComponentFactory
*factory)
+{
+        factory->priv = g_new0 (BonoboCanvasComponentFactoryPrivate,
1);
+}
+
+BONOBO_TYPE_FUNC_FULL (BonoboCanvasComponentFactory,
+                       Bonobo_CanvasComponentFactory,
+                       BONOBO_TYPE_X_OBJECT,
+                       bonobo_canvas_component_factory);
+
+/**
+ * bonobo_canvas_component_factory_new:
+ * @item_factory: A callback invoke when the container activates the
object.
+ * @user_data: User data pointer.
+ *
+ * Returns: The object to be passed into bonobo_generic_factory_main.
+ */
+BonoboObject *bonobo_canvas_component_factory_new(
+      GnomeItemCreator item_factory, void *user_data)
+{
+        BonoboCanvasComponentFactory *factory;
+        factory = g_object_new (BONOBO_CANVAS_COMPONENT_FACTORY_TYPE,
NULL);
+
+        factory->priv->item_creator = item_factory;
+        factory->priv->item_creator_data = user_data;
+
+        return BONOBO_OBJECT(factory); 
+}


===========================================================================
--- bonobo-canvas-item.c.orig	Mon Mar 24 09:43:01 2003
+++ bonobo-canvas-item.c	Mon Apr 14 20:59:54 2003
@@ -192,6 +192,7 @@
 
 	CORBA_exception_init (&ev);
 	prepare_state (item, &state);
+
 	cuta = Bonobo_Canvas_Component_update (
 		gbi->priv->object,
 		&state, affine, clip_path, item_flags,
@@ -200,6 +201,7 @@
 
 	if (!BONOBO_EX (&ev)){
 		if (cuta->width > 0 && cuta->height > 0){
+
 			ArtUta *uta;
 
 			uta = uta_from_cuta (cuta);
@@ -250,6 +252,11 @@
 		gbi->priv->realize_pending = 1;
 		return;
 	}
+
+        proxy_size_allocate (
+                item->canvas,
+                &(GTK_WIDGET (item->canvas)->allocation),
+                BONOBO_CANVAS_ITEM(item));
 		
 	g_signal_connect (item->canvas, "size_allocate",
 			  G_CALLBACK (proxy_size_allocate), item);
@@ -447,7 +454,7 @@
 		e->_d = Bonobo_Gdk_MOTION;
 		e->_u.motion.time = event->motion.time;
 		e->_u.motion.x = event->motion.x;
-		e->_u.motion.y = event->motion.x;
+		e->_u.motion.y = event->motion.y;
 		e->_u.motion.x_root = event->motion.x_root;
 		e->_u.motion.y_root = event->motion.y_root;
 #ifdef FIXME
@@ -556,7 +563,11 @@
 
 		gbi->priv->object = bonobo_object_release_unref (gbi->priv->object,
&ev);
 
-		factory = bonobo_value_get_corba_object (value);
+                /* FIXME: I can't make it work as corba_object. 
+                   Using bonobo_unknown for now. */
+		/* factory = bonobo_value_get_corba_object (value); */
+               
+		factory = bonobo_value_get_unknown (value);
 
 		g_return_if_fail (factory != CORBA_OBJECT_NIL);
 
@@ -580,12 +591,6 @@
 			return;
 		}
 
-		/* Initial size notification */
-		proxy_size_allocate (
-			GNOME_CANVAS_ITEM (gbi)->canvas,
-			&(GTK_WIDGET (GNOME_CANVAS_ITEM (gbi)->canvas)->allocation),
-			gbi);
-	
 		if (gbi->priv->realize_pending){
 			gbi->priv->realize_pending = 0;
 			gbi_realize (GNOME_CANVAS_ITEM (gbi));
@@ -639,6 +644,8 @@
 	GnomeCanvasItemClass *item_class =
 		(GnomeCanvasItemClass *) object_class;
 
+	gobject_class->set_property = gbi_set_property;
+
 	g_object_class_install_property (
 		gobject_class,
 		PROP_CORBA_FACTORY,
@@ -660,7 +667,6 @@
 			G_PARAM_WRITABLE));
 	
 	gobject_class->finalize     = gbi_finalize;
-	gobject_class->set_property = gbi_set_property;
 
 	item_class->update     = gbi_update;
 	item_class->realize    = gbi_realize;
@@ -672,13 +678,42 @@
 	item_class->event      = gbi_event;
 }
 
+static gboolean
+gbi_idle_handler (GnomeCanvasItem *item)
+{
+	gnome_canvas_item_request_update (item);
+        return FALSE;
+}
+
 static void
 impl_Bonobo_Canvas_ComponentProxy_requestUpdate (PortableServer_Servant
servant,
 					         CORBA_Environment     *ev)
 {
 	ComponentProxyServant *item_proxy = (ComponentProxyServant *) servant;
 
-	gnome_canvas_item_request_update (item_proxy->item_bound);
+        if (item_proxy->item_bound->canvas->idle_id == 0)
+        {
+        	gnome_canvas_item_request_update (item_proxy->item_bound);
+        }
+        else
+        {
+                /* Problem: It is possible to get here at a time when
the canvas
+                 * is in the middle of a do_update due to the manner in
which
+                 * proxies are handled by Bonobo/Orbit. The do_update
can
+                 * request a redraw from the component.  When the
Component
+                 * replies a requestUpdate proxy may be included in the
queue.
+                 *
+                 * Solution:
+                 * The canvas is either in its do_update routine or it
is
+                 * waiting to do an update.  If it is waiting this
idle_handler
+                 * will get called just before the canvas's handler. 
If it is
+                 * in the middle of a do_update, then this will queue
for the
+                 * next one.
+                 */
+
+                 g_idle_add_full(GDK_PRIORITY_REDRAW-4,
gbi_idle_handler, 
+                        item_proxy->item_bound, NULL);
+        }
 
 }
 					    
@@ -719,10 +754,12 @@
 	return bonobo_object_dup_ref (item_proxy->ui_container, NULL);
 }
 
+static PortableServer_ServantBase__epv item_proxy_base_epv;
+
 static POA_Bonobo_Canvas_ComponentProxy__epv item_proxy_epv;
 
 static POA_Bonobo_Canvas_ComponentProxy__vepv item_proxy_vepv = {
-	NULL,
+	&item_proxy_base_epv,
 	&item_proxy_epv
 };
 
@@ -736,6 +773,8 @@
 	ComponentProxyServant *item_proxy = g_new0 (ComponentProxyServant, 1);
 	CORBA_Environment ev;
 	
+        item_proxy->proxy_servant.vepv = &item_proxy_vepv;
+
 	CORBA_exception_init (&ev);
 	POA_Bonobo_Canvas_ComponentProxy__init ((PortableServer_Servant)
item_proxy, &ev);
 
@@ -744,7 +783,6 @@
 	item_proxy_epv.ungrabFocus    =
impl_Bonobo_Canvas_ComponentProxy_ungrabFocus;
 	item_proxy_epv.getUIContainer =
impl_Bonobo_Canvas_ComponentProxy_getUIContainer;
 
-	item_proxy->proxy_servant.vepv = &item_proxy_vepv;
 	item_proxy->item_bound = item;
 
 	item_proxy->oid = PortableServer_POA_activate_object (






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