X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=registryd%2Fregistry.c;h=31dbb81d0debfe7493111326aed39d3c6230262d;hb=99f0f510b665fb2298bc8cdd6613e384e445406b;hp=6ae9ed2cdb57e07804bec348d1a1226c4a110b20;hpb=3f3795dd1c05e3d7f106b1bee1d1f3baf3724569;p=platform%2Fcore%2Fuifw%2Fat-spi2-atk.git diff --git a/registryd/registry.c b/registryd/registry.c index 6ae9ed2..31dbb81 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 { @@ -152,8 +158,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); } @@ -626,27 +632,278 @@ 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.type = CORBA_string_dup (ctx->e_out.type); + new_ctx->e_out.source = ctx->e_out.source; + new_ctx->e_out.detail1 = ctx->e_out.detail1; + new_ctx->e_out.detail2 = ctx->e_out.detail2; + CORBA_any__copy (&(new_ctx->e_out.any_data), &(ctx->e_out.any_data)); + 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 ((void *)q_ctx->e_out.type); + 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) +{ + NotifyContext *q_ctx = registry_clone_notify_context (ctx); +#ifdef SPI_QUEUE_DEBUG + if (q_ctx->etype.type_cat != ETYPE_MOUSE) + fprintf (stderr, "push! %s %p\n", q_ctx->etype.event_name, q_ctx); +#endif + if (registry->is_queueing) + { + g_queue_push_head (registry->deferred_event_queue, q_ctx); + + return FALSE; + } + else + { + bonobo_object_release_unref (q_ctx->source, NULL); + CORBA_free ((void *)q_ctx->etype.event_name); + CORBA_free ((void *)q_ctx->e_out.type); + g_free (q_ctx); + 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 = *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 +927,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 +976,7 @@ spi_registry_init (SpiRegistry *registry) BONOBO_TYPE_FUNC_FULL (SpiRegistry, Accessibility_Registry, PARENT_TYPE, - spi_registry); + spi_registry) SpiRegistry * spi_registry_new (void)