X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;ds=sidebyside;f=registryd%2Fregistry.c;h=6119cdf77fafdaae7570c2153db046b5dbe8bbe7;hb=d8761880c8bd6c1c2b48749f57bab780900c274b;hp=6ae9ed2cdb57e07804bec348d1a1226c4a110b20;hpb=3f3795dd1c05e3d7f106b1bee1d1f3baf3724569;p=platform%2Fcore%2Fuifw%2Fat-spi2-atk.git diff --git a/registryd/registry.c b/registryd/registry.c index 6ae9ed2..6119cdf 100644 --- a/registryd/registry.c +++ b/registryd/registry.c @@ -25,6 +25,7 @@ #undef SPI_LISTENER_DEBUG #undef SPI_DEBUG +#undef SPI_QUEUE_DEBUG #include #ifdef SPI_DEBUG @@ -41,6 +42,11 @@ /* A pointer to our parent object class */ static SpiListenerClass *spi_registry_parent_class; +static GQuark _deactivate_quark = 0; +static GQuark _activate_quark = 0; +static GQuark _state_quark = 0; +static GQuark _state_changed_focused_quark = 0; + int _dbg = 0; typedef enum { @@ -75,7 +81,7 @@ spi_registry_set_debug (const char *debug_flag_string) _dbg = (int) g_ascii_strtod (debug_flag_string, NULL); } -SpiListenerStruct * +static SpiListenerStruct * spi_listener_struct_new (Accessibility_EventListener listener, CORBA_Environment *ev) { SpiListenerStruct *retval = g_malloc (sizeof (SpiListenerStruct)); @@ -84,7 +90,7 @@ spi_listener_struct_new (Accessibility_EventListener listener, CORBA_Environment } -void +static void spi_listener_struct_free (SpiListenerStruct *ls, CORBA_Environment *ev) { bonobo_object_release_unref (ls->listener, ev); @@ -110,7 +116,11 @@ desktop_add_application (SpiDesktop *desktop, /* FIXME spi_init_any_object (&e.any_data, a); */ - spi_init_any_nil (&e.any_data); + spi_init_any_nil (&e.any_data, + e.source, + Accessibility_ROLE_DESKTOP_FRAME, + ""); + Accessibility_Registry_notifyEvent (BONOBO_OBJREF (registry), &e, &ev); bonobo_object_release_unref (a, &ev); @@ -125,7 +135,7 @@ desktop_remove_application (SpiDesktop *desktop, { BonoboObject *registry = BONOBO_OBJECT (data); Accessibility_Event e; - Accessibility_Accessible a; + /* Accessibility_Accessible a; FIXME */ CORBA_Environment ev; CORBA_exception_init (&ev); @@ -134,13 +144,16 @@ desktop_remove_application (SpiDesktop *desktop, e.source = BONOBO_OBJREF (desktop); e.detail1 = index; e.detail2 = 0; + /* FIXME a = Accessibility_Accessible_getChildAtIndex (BONOBO_OBJREF (desktop), index, &ev); - /* FIXME spi_init_any_object (&e.any_data, a); */ - spi_init_any_nil (&e.any_data); - Accessibility_Accessible_unref (a, &ev); + spi_init_any_nil (&e.any_data, + e.source, + Accessibility_ROLE_DESKTOP_FRAME, + ""); + /* Accessibility_Accessible_unref (a, &ev); */ Accessibility_Registry_notifyEvent (BONOBO_OBJREF (registry), &e, &ev); Accessibility_Desktop_unref (e.source, &ev); @@ -152,8 +165,8 @@ static void spi_registry_object_finalize (GObject *object) { DBG (1, g_warning ("spi_registry_object_finalize called\n")); + g_object_unref (SPI_REGISTRY (object)->de_controller); - /* TODO: unref deviceeventcontroller, which disconnects key listener */ G_OBJECT_CLASS (spi_registry_parent_class)->finalize (object); } @@ -280,6 +293,10 @@ parse_event_type (EventTypeStruct *etype, const char *event_name) { etype->type_cat = ETYPE_OBJECT; } + else if (!g_ascii_strncasecmp (event_name, "document:", 9)) + { + etype->type_cat = ETYPE_OBJECT; + } else if (!g_ascii_strncasecmp (event_name, "window:", 7)) { etype->type_cat = ETYPE_WINDOW; @@ -312,7 +329,7 @@ parse_event_type (EventTypeStruct *etype, const char *event_name) else { etype->minor = etype->major; - etype->detail = g_quark_from_static_string (""); //etype->major; + etype->detail = g_quark_from_static_string (""); /*etype->major;*/ } } else @@ -417,20 +434,31 @@ impl_accessibility_registry_register_global_event_listener ( } } +typedef struct { + gboolean remove_all; + Accessibility_EventListener listener; + EventTypeStruct etype; +} RemoveListenerClosure; + static SpiReEntrantContinue remove_listener_cb (GList * const *list, gpointer user_data) { SpiListenerStruct *ls = (SpiListenerStruct *) (*list)->data; CORBA_Environment ev; - Accessibility_EventListener listener = user_data; + RemoveListenerClosure *cl = user_data; CORBA_exception_init (&ev); - - if (CORBA_Object_is_equivalent (ls->listener, listener, &ev)) - { - spi_re_entrant_list_delete_link (list); - spi_listener_struct_free (ls, &ev); - } + + if (cl->remove_all || (((cl->etype.minor == ls->event_type_quark) || + (cl->etype.major == ls->event_type_quark)) && + cl->etype.type_cat == ls->event_type_cat ) ) + { + if (CORBA_Object_is_equivalent (ls->listener, cl->listener, &ev)) + { + spi_re_entrant_list_delete_link (list); + spi_listener_struct_free (ls, &ev); + } + } CORBA_exception_free (&ev); @@ -449,14 +477,18 @@ impl_accessibility_registry_deregister_global_event_listener_all ( int i; GList **lists[3]; SpiRegistry *registry = SPI_REGISTRY (bonobo_object_from_servant (servant)); + RemoveListenerClosure cl = { 0, }; lists[0] = ®istry->object_listeners; lists[1] = ®istry->window_listeners; lists[2] = ®istry->toolkit_listeners; + cl.remove_all = TRUE; + cl.listener = listener; + for (i = 0; i < sizeof (lists) / sizeof (lists[0]); i++) { - spi_re_entrant_list_foreach (lists [i], remove_listener_cb, listener); + spi_re_entrant_list_foreach (lists [i], remove_listener_cb, &cl); } } @@ -472,14 +504,16 @@ impl_accessibility_registry_deregister_global_event_listener ( CORBA_Environment *ev) { SpiRegistry *registry; - EventTypeStruct etype; + RemoveListenerClosure cl = { 0, }; registry = SPI_REGISTRY (bonobo_object_from_servant (servant)); - parse_event_type (&etype, (char *) event_name); + cl.remove_all = FALSE; + parse_event_type (&cl.etype, (char *) event_name); + cl.listener = listener; - spi_re_entrant_list_foreach (get_listener_list (registry, etype.type_cat), - remove_listener_cb, listener); + spi_re_entrant_list_foreach (get_listener_list (registry, cl.etype.type_cat), + remove_listener_cb, &cl); } @@ -572,7 +606,7 @@ typedef struct { CORBA_Environment *ev; Bonobo_Unknown source; EventTypeStruct etype; - Accessibility_Event e_out; + Accessibility_Event *e_out; } NotifyContext; static SpiReEntrantContinue @@ -604,12 +638,12 @@ notify_listeners_cb (GList * const *list, gpointer user_data) } #endif - ctx->e_out.source = ctx->source; + ctx->e_out->source = ctx->source; if ((*list) && (*list)->data == ls) { Accessibility_EventListener_notifyEvent ( - (Accessibility_EventListener) ls->listener, &ctx->e_out, ctx->ev); + (Accessibility_EventListener) ls->listener, ctx->e_out, ctx->ev); if (ctx->ev->_major != CORBA_NO_EXCEPTION) { DBG (1, g_warning ("Accessibility app error: exception during " @@ -626,27 +660,271 @@ notify_listeners_cb (GList * const *list, gpointer user_data) } static void +registry_emit_event (SpiRegistry *registry, NotifyContext *ctx) +{ + GList **list = get_listener_list (registry, ctx->etype.type_cat); + + if (list && *list) + { + + spi_re_entrant_list_foreach (list, notify_listeners_cb, ctx); + } +} + +static NotifyContext* +registry_clone_notify_context (NotifyContext *ctx) +{ + NotifyContext *new_ctx = g_new0 (NotifyContext, 1); + + new_ctx->ev = NULL; + new_ctx->source = bonobo_object_dup_ref (ctx->source, NULL); + new_ctx->etype.event_name = CORBA_string_dup (ctx->etype.event_name); + new_ctx->etype.type_cat = ctx->etype.type_cat; + new_ctx->etype.major = ctx->etype.major; + new_ctx->etype.minor = ctx->etype.minor; + new_ctx->etype.detail = ctx->etype.detail; + new_ctx->e_out = ORBit_copy_value (ctx->e_out, TC_Accessibility_Event); + return new_ctx; +} + +static void +registry_flush_event_queue (SpiRegistry *registry, + gboolean discard, + CORBA_Environment *ev) +{ + NotifyContext *q_ctx; + while (!g_queue_is_empty (registry->deferred_event_queue)) { + q_ctx = g_queue_pop_tail (registry->deferred_event_queue); +#ifdef SPI_QUEUE_DEBUG + fprintf (stderr, "%s! %s [n=%d] %p\n", (discard ? "discard" : "pop"), + q_ctx->etype.event_name, + (int) registry->deferred_event_queue->length, q_ctx); +#endif + if (!discard) { + q_ctx->ev = ev; + registry_emit_event (registry, q_ctx); + } + if (discard && + (q_ctx->etype.type_cat == ETYPE_OBJECT) && + (q_ctx->etype.major == _state_quark) && + (q_ctx->etype.minor == _state_changed_focused_quark)) { + registry->focus_object = q_ctx->source; +#ifdef SPI_QUEUE_DEBUG + fprintf (stderr, "discard!: set focus_object %p\n", registry->focus_object); +#endif + } + else { + bonobo_object_release_unref (q_ctx->source, NULL); + } + CORBA_free ((void *)q_ctx->etype.event_name); + CORBA_free (q_ctx->e_out); + g_free (q_ctx); + } + registry->is_queueing = FALSE; +} + +static gboolean +registry_timeout_flush_queue (gpointer data) +{ + SpiRegistry *registry = data; + CORBA_Environment ev; +#ifdef SPI_QUEUE_DEBUG + fprintf (stderr, "timeout! flushing queue...\n"); +#endif + CORBA_exception_init (&ev); + registry->queue_handler_id = 0; + registry_flush_event_queue (registry, FALSE, &ev); + return FALSE; +} + +static gboolean +registry_discard_on_event (SpiRegistry *registry, NotifyContext *ctx) +{ + gboolean retval = FALSE; + NotifyContext *q_ctx = g_queue_peek_tail (registry->deferred_event_queue); + if ((q_ctx != NULL) && + (ctx->etype.type_cat == ETYPE_WINDOW) && + (ctx->etype.major == _activate_quark)) { + if (CORBA_Object_is_equivalent (ctx->source, q_ctx->source, NULL)) { + retval = TRUE; + } + } + return retval; +} + +static gboolean +registry_reset_on_event (SpiRegistry *registry, NotifyContext *ctx) +{ + return (ctx->etype.type_cat == ETYPE_WINDOW) ? TRUE : FALSE; +} + +#ifdef SPI_QUEUE_DEBUG +#include +#endif + +static void +registry_start_queue (SpiRegistry *registry) +{ +#ifdef SPI_QUEUE_DEBUG + struct timeval tp; + gettimeofday (&tp, NULL); + fprintf (stderr, "start queueing at %i.%.6i\n", tp.tv_sec, tp.tv_usec); +#endif + if (registry->queue_handler_id != 0) + g_source_remove (registry->queue_handler_id); + + if (registry->focus_object) + { +#ifdef SPI_QUEUE_DEBUG + fprintf (stderr, "registry_start_queue: release focus_object %p\n", registry->focus_object); +#endif + bonobo_object_release_unref (registry->focus_object, NULL); + registry->focus_object = NULL; + } + registry->queue_handler_id = g_timeout_add_full (G_PRIORITY_HIGH_IDLE, + registry->exit_notify_timeout, + registry_timeout_flush_queue, registry, + NULL); + registry->is_queueing = TRUE; +} + +static gboolean +registry_discard_event (SpiRegistry *registry, NotifyContext *ctx) +{ + gboolean ret = FALSE; + + if (ctx->etype.type_cat == ETYPE_FOCUS) + { + if (registry->focus_object) + { + if (CORBA_Object_is_equivalent (registry->focus_object, ctx->source, NULL)) + { + ret = TRUE; + } +#ifdef SPI_QUEUE_DEBUG + fprintf (stderr, "registry_discard_event: release focus_object %p\n", registry->focus_object); +#endif + bonobo_object_release_unref (registry->focus_object, NULL); + registry->focus_object = NULL; + } + } + return ret; +} + +static gboolean +registry_defer_on_event (SpiRegistry *registry, NotifyContext *ctx) +{ + gboolean defer = FALSE; + if ((ctx->etype.type_cat == ETYPE_WINDOW) && + (ctx->etype.major == _deactivate_quark)) { + defer = TRUE; + registry_start_queue (registry); + } + /* defer all object:state-change events after a window:deactivate */ + else if ((ctx->etype.type_cat == ETYPE_FOCUS) || + ((ctx->etype.type_cat == ETYPE_OBJECT) && + (ctx->etype.major == _state_quark))) { + defer = TRUE; + } + return defer; +} + +static gboolean +registry_queue_event (SpiRegistry *registry, NotifyContext *ctx) +{ +#ifdef SPI_QUEUE_DEBUG + if (ctx->etype.type_cat != ETYPE_MOUSE) + fprintf (stderr, "push! %s %p\n", ctx->etype.event_name, ctx); +#endif + if (registry->is_queueing) + { + NotifyContext *q_ctx = registry_clone_notify_context (ctx); + + g_queue_push_head (registry->deferred_event_queue, q_ctx); + + return FALSE; + } + else + { + return TRUE; + } +} + +/** + * Dispose of event in one of several ways: + * 1) discard; + * 2) initiate queuing and push onto queue (below) + * 3) push on existing queue to either pop on timeout or on subsequent event + * 4) pass-through immediately + * 5) pass-through, discarding queued events + * 6) emit queued events and then pass through + **/ +static gboolean +registry_filter_event (SpiRegistry *registry, NotifyContext *ctx, + CORBA_Environment *ev) +{ + g_assert (ctx != NULL); + + if (registry_discard_event (registry, ctx)) + return FALSE; + + if (registry_defer_on_event (registry, ctx)) { /* #2, #3 */ + if (registry->is_queueing) { + return registry_queue_event (registry, ctx); + } + else { /* #4a */ + return TRUE; + } + } + else if (registry_reset_on_event (registry, ctx)) { /* #5, #6 */ + gboolean discard = registry_discard_on_event (registry, ctx); +#ifdef SPI_QUEUE_DEBUG + fprintf (stderr, "event %s caused reset, discard=%d\n", + ctx->etype.event_name, (int) discard); + { + struct timeval tp; + gettimeofday (&tp, NULL); + fprintf (stderr, "event at %i.%.6i\n", tp.tv_sec, tp.tv_usec); + } +#endif + registry_flush_event_queue (registry, discard, ev); + return (discard ? FALSE : TRUE); + } + else { /* #4b */ + return TRUE; + } +} + +static void impl_registry_notify_event (PortableServer_Servant servant, const Accessibility_Event *e, CORBA_Environment *ev) { SpiRegistry *registry; - GList **list; NotifyContext ctx; + static int level = 0; + level++; registry = SPI_REGISTRY (bonobo_object_from_servant (servant)); parse_event_type (&ctx.etype, e->type); - list = get_listener_list (registry, ctx.etype.type_cat); - - if (list && *list) - { - ctx.ev = ev; - ctx.e_out = *e; - ctx.source = e->source; - spi_re_entrant_list_foreach (list, notify_listeners_cb, &ctx); - } + ctx.ev = ev; + ctx.e_out = (Accessibility_Event *)e; + ctx.source = e->source; + +#ifdef SPI_QUEUE_DEBUG + if (ctx.etype.type_cat != ETYPE_MOUSE) + fprintf (stderr, "filter! %s level: %d\n", ctx.etype.event_name, level); +#endif + if (registry_filter_event (registry, &ctx, ev)) { +#ifdef SPI_QUEUE_DEBUG + if (ctx.etype.type_cat != ETYPE_MOUSE) + fprintf (stderr, "emit! %s level: %d\n", ctx.etype.event_name, level); +#endif + registry_emit_event (registry, &ctx); + } + level--; } static void @@ -670,15 +948,37 @@ spi_registry_class_init (SpiRegistryClass *klass) epv->getDesktopCount = impl_accessibility_registry_get_desktop_count; epv->getDesktop = impl_accessibility_registry_get_desktop; epv->getDesktopList = impl_accessibility_registry_get_desktop_list; + _deactivate_quark = g_quark_from_static_string ("deactivate"); + _activate_quark = g_quark_from_static_string ("activate"); + _state_quark = g_quark_from_static_string ("state-changed"); + _state_changed_focused_quark = g_quark_from_static_string ("state-changedfocused"); } static void spi_registry_init (SpiRegistry *registry) { spi_registry_set_debug (g_getenv ("AT_SPI_DEBUG")); + /* + * TODO: FIXME, this module makes the foolish assumptions that + * registryd uses the same display as the apps, and that the + * DISPLAY environment variable is set. + */ + gdk_init (NULL, NULL); + registry->object_listeners = NULL; registry->window_listeners = NULL; registry->toolkit_listeners = NULL; + registry->deferred_event_queue = g_queue_new (); + registry->exit_notify_timeout = 200; + registry->queue_handler_id = 0; + /* + * The focus_object is set when a state-change:focused event is discarded + * after a window:deactivate event is received because a window:activate + * event has been received for the same window within the timeout period. + * The focus object is used to suppress a focus event for that object. + * It is released when a window:deactivate event is received. + */ + registry->focus_object = NULL; registry->desktop = spi_desktop_new (); /* Register callback notification for application addition and removal */ g_signal_connect (G_OBJECT (registry->desktop), @@ -697,7 +997,7 @@ spi_registry_init (SpiRegistry *registry) BONOBO_TYPE_FUNC_FULL (SpiRegistry, Accessibility_Registry, PARENT_TYPE, - spi_registry); + spi_registry) SpiRegistry * spi_registry_new (void)