# define IDEBUG(a...)
#endif
+#define MAX_QUEUED_EVENTS 20
+
struct _IBusIMContext {
GtkIMContext parent;
/* cancellable */
GCancellable *cancellable;
+ GQueue *events_queue;
};
struct _IBusIMContextClass {
static GtkIMContextClass *parent_class = NULL;
static IBusBus *_bus = NULL;
+static guint _daemon_name_watch_id = 0;
+static gboolean _daemon_is_running = FALSE;
void
ibus_im_context_register_type (GTypeModule *type_module)
gdk_event_free ((GdkEvent *)event);
}
+static gboolean
+_process_key_event (IBusInputContext *context,
+ GdkEventKey *event)
+{
+ guint state = event->state;
+ gboolean retval = FALSE;
+
+ if (event->type == GDK_KEY_RELEASE) {
+ state |= IBUS_RELEASE_MASK;
+ }
+
+ if (_use_sync_mode) {
+ retval = ibus_input_context_process_key_event (context,
+ event->keyval,
+ event->hardware_keycode - 8,
+ state);
+ }
+ else {
+ ibus_input_context_process_key_event_async (context,
+ event->keyval,
+ event->hardware_keycode - 8,
+ state,
+ -1,
+ NULL,
+ _process_key_event_done,
+ gdk_event_copy ((GdkEvent *) event));
+
+ retval = TRUE;
+ }
+
+ if (retval) {
+ event->state |= IBUS_HANDLED_MASK;
+ }
+ else {
+ event->state |= IBUS_IGNORED_MASK;
+ }
+
+ return retval;
+}
+
/* emit "retrieve-surrounding" glib signal of GtkIMContext, if
* context->caps has IBUS_CAP_SURROUNDING_TEXT and the current IBus
ibusimcontext->time = event->time;
}
- guint state = event->state;
- if (event->type == GDK_KEY_RELEASE) {
- state |= IBUS_RELEASE_MASK;
- }
-
- if (_use_sync_mode) {
- retval = ibus_input_context_process_key_event (
- ibuscontext,
- event->keyval,
- event->hardware_keycode - 8,
- state);
- }
- else {
- ibus_input_context_process_key_event_async (
- ibuscontext,
- event->keyval,
- event->hardware_keycode - 8,
- state,
- -1,
- NULL,
- _process_key_event_done,
- gdk_event_copy ((GdkEvent *) event));
- retval = TRUE;
-
- }
-
- if (retval) {
- event->state |= IBUS_HANDLED_MASK;
- }
- else {
- event->state |= IBUS_IGNORED_MASK;
- }
+ retval = _process_key_event (ibuscontext, event);
if (ibusimcontext != NULL) {
/* unref ibusimcontext could call ibus_im_context_finalize here
}
static void
+daemon_name_appeared (GDBusConnection *connection,
+ const gchar *name,
+ const gchar *owner,
+ gpointer data)
+{
+ _daemon_is_running = TRUE;
+}
+
+static void
+daemon_name_vanished (GDBusConnection *connection,
+ const gchar *name,
+ gpointer data)
+{
+ _daemon_is_running = FALSE;
+}
+
+static void
ibus_im_context_class_init (IBusIMContextClass *class)
{
IDEBUG ("%s", __FUNCTION__);
/* always install snooper */
if (_key_snooper_id == 0)
_key_snooper_id = gtk_key_snooper_install (_key_snooper_cb, NULL);
+
+ _daemon_name_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
+ IBUS_SERVICE_IBUS,
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ daemon_name_appeared,
+ daemon_name_vanished,
+ NULL,
+ NULL);
}
static void
gtk_key_snooper_remove (_key_snooper_id);
_key_snooper_id = 0;
}
+
+ g_bus_unwatch_name (_daemon_name_watch_id);
}
/* Copied from gtk+2.0-2.20.1/modules/input/imcedilla.c to fix crosbug.com/11421.
ibusimcontext->caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS;
#endif
+ ibusimcontext->events_queue = g_queue_new ();
// Create slave im context
ibusimcontext->slave = gtk_im_context_simple_new ();
g_signal_handlers_disconnect_by_func (_bus, G_CALLBACK (_bus_connected_cb), obj);
+ if (ibusimcontext->cancellable != NULL) {
+ /* Cancel any ongoing create input context request */
+ g_cancellable_cancel (ibusimcontext->cancellable);
+ g_object_unref (ibusimcontext->cancellable);
+ ibusimcontext->cancellable = NULL;
+ }
+
if (ibusimcontext->ibuscontext) {
ibus_proxy_destroy ((IBusProxy *)ibusimcontext->ibuscontext);
}
pango_attr_list_unref (ibusimcontext->preedit_attrs);
}
+ g_queue_free_full (ibusimcontext->events_queue,
+ (GDestroyNotify)gdk_event_free);
+
G_OBJECT_CLASS(parent_class)->finalize (obj);
}
IBusIMContext *ibusimcontext = IBUS_IM_CONTEXT (context);
- if (G_LIKELY (ibusimcontext->ibuscontext && ibusimcontext->has_focus)) {
- /* If context does not have focus, ibus will process key event in sync mode.
- * It is a workaround for increase search in treeview.
- */
- gboolean retval = FALSE;
-
- if (event->state & IBUS_HANDLED_MASK)
- return TRUE;
+ if (!_daemon_is_running)
+ return gtk_im_context_filter_keypress (ibusimcontext->slave, event);
- if (event->state & IBUS_IGNORED_MASK)
- return gtk_im_context_filter_keypress (ibusimcontext->slave, event);
+ /* If context does not have focus, ibus will process key event in
+ * sync mode. It is a workaround for increase search in treeview.
+ */
+ if (!ibusimcontext->has_focus)
+ return gtk_im_context_filter_keypress (ibusimcontext->slave, event);
- /* XXX it is a workaround for some applications do not set client window. */
- if (ibusimcontext->client_window == NULL && event->window != NULL)
- gtk_im_context_set_client_window ((GtkIMContext *)ibusimcontext, event->window);
+ if (event->state & IBUS_HANDLED_MASK)
+ return TRUE;
- _request_surrounding_text (ibusimcontext);
+ if (event->state & IBUS_IGNORED_MASK)
+ return gtk_im_context_filter_keypress (ibusimcontext->slave, event);
- if (ibusimcontext != NULL) {
- ibusimcontext->time = event->time;
- }
+ /* XXX it is a workaround for some applications do not set client
+ * window. */
+ if (ibusimcontext->client_window == NULL && event->window != NULL)
+ gtk_im_context_set_client_window ((GtkIMContext *)ibusimcontext,
+ event->window);
- guint state = event->state;
- if (event->type == GDK_KEY_RELEASE) {
- state |= IBUS_RELEASE_MASK;
- }
+ _request_surrounding_text (ibusimcontext);
- if (_use_sync_mode) {
- retval = ibus_input_context_process_key_event (
- ibusimcontext->ibuscontext,
- event->keyval,
- event->hardware_keycode - 8,
- state);
- }
- else {
- ibus_input_context_process_key_event_async (
- ibusimcontext->ibuscontext,
- event->keyval,
- event->hardware_keycode - 8,
- state,
- -1,
- NULL,
- _process_key_event_done,
- gdk_event_copy ((GdkEvent *) event));
- retval = TRUE;
- }
+ ibusimcontext->time = event->time;
- if (retval) {
- event->state |= IBUS_HANDLED_MASK;
+ if (ibusimcontext->ibuscontext) {
+ if (_process_key_event (ibusimcontext->ibuscontext, event))
return TRUE;
- }
- else {
- event->state |= IBUS_IGNORED_MASK;
- return gtk_im_context_filter_keypress (ibusimcontext->slave, event);
- }
+ else
+ return gtk_im_context_filter_keypress (ibusimcontext->slave,
+ event);
}
- else {
- return gtk_im_context_filter_keypress (ibusimcontext->slave, event);
+
+ /* At this point we _should_ be waiting for the IBus context to be
+ * created or the connection to IBus to be established. If that's
+ * the case we queue events to be processed when the IBus context
+ * is ready. */
+ g_return_val_if_fail (ibusimcontext->cancellable != NULL ||
+ ibus_bus_is_connected (_bus) == FALSE,
+ FALSE);
+ g_queue_push_tail (ibusimcontext->events_queue,
+ gdk_event_copy ((GdkEvent *)event));
+
+ if (g_queue_get_length (ibusimcontext->events_queue) > MAX_QUEUED_EVENTS) {
+ g_warning ("Events queue growing too big, will start to drop.");
+ gdk_event_free ((GdkEvent *)
+ g_queue_pop_head (ibusimcontext->events_queue));
}
+
+ return TRUE;
}
static void
ibus_input_context_focus_in (ibusimcontext->ibuscontext);
_set_cursor_location_internal (ibusimcontext);
}
+
+ if (!g_queue_is_empty (ibusimcontext->events_queue)) {
+ GdkEventKey *event;
+ while (event = g_queue_pop_head (ibusimcontext->events_queue)) {
+ _process_key_event (context, event);
+ gdk_event_free ((GdkEvent *)event);
+ }
+ }
}
g_object_unref (ibusimcontext);
g_assert (ibusimcontext->ibuscontext == NULL);
- if (ibusimcontext->cancellable != NULL) {
- /* Cancel previous create input context request */
- g_cancellable_cancel (ibusimcontext->cancellable);
- g_object_unref (ibusimcontext->cancellable);
- ibusimcontext->cancellable = NULL;
- }
+ g_return_if_fail (ibusimcontext->cancellable == NULL);
ibusimcontext->cancellable = g_cancellable_new ();