Fixes for Deprecated Canvas Components
- From: bob gibbs <gibbsrc npt nuwc navy mil>
- To: gnome-components-list gnome org
- Subject: Fixes for Deprecated Canvas Components
- Date: Tue, 15 Apr 2003 21:41:49 -0400
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]