diff --git a/imsettings-disable-imsettings-xim.patch b/imsettings-disable-imsettings-xim.patch new file mode 100644 index 0000000..3794b7e --- /dev/null +++ b/imsettings-disable-imsettings-xim.patch @@ -0,0 +1,37 @@ + 2009-01-08 Akira TAGOH + + * data/xinput.sh.in.in: stop bringing imsettings-xim up. we are relying + on XDG's autostart to provide full features of imsettings now. + +Index: data/xinput.sh.in.in +=================================================================== +--- data/xinput.sh.in.in (リビジョン 229) ++++ data/xinput.sh.in.in (リビジョン 230) +@@ -1,5 +1,5 @@ + #!/bin/bash +-# Copyright (C) 1999-2004,2007-2008 Red Hat, Inc. All rights reserved. This ++# Copyright (C) 1999-2004,2007-2009 Red Hat, Inc. All rights reserved. This + # copyrighted material is made available to anyone wishing to use, modify, + # copy, or redistribute it subject to the terms and conditions of the + # GNU General Public License version 2. +@@ -21,7 +21,7 @@ + function is_gtk_supported() { + [ -n "$IMSETTINGS_DISABLE_DESKTOP_CHECK" ] && return 0 + case "$DESKTOP_SESSION" in +- *gnome|*kde|openbox|xfce4) ++ *gnome|openbox|xfce4) + return 0 + ;; + *) +@@ -76,7 +76,10 @@ + echo "*** DRY RUN MODE: running IM through imsettings" + else + which imsettings-start > /dev/null 2>&1 && LANG="$tmplang" imsettings-start -n "$IMSETTINGS_MODULE" || : +- which imsettings-xim > /dev/null 2>&1 && imsettings-xim & ++ # NOTE: We don't bring up imsettings-xim nor imsettings-applet here to support XIM. ++ # imsettings-applet will starts through XDG autostart mechanism. ++ # If the desktop doesn't support that, this function shouldn't be invoked. ++ # but run_xim() instead. + fi + } + diff --git a/imsettings-sync-default.patch b/imsettings-sync-default.patch new file mode 100644 index 0000000..6a31427 --- /dev/null +++ b/imsettings-sync-default.patch @@ -0,0 +1,21 @@ +Index: applet/main.c +=================================================================== +--- applet/main.c (リビジョン 257) ++++ applet/main.c (リビジョン 258) +@@ -1215,6 +1215,16 @@ + if (applet->server) + g_object_set_qdata(G_OBJECT (applet->server), quark_applet, applet); + ++ val = gconf_client_get(client, "/apps/imsettings-applet/sync_on_forward", NULL); ++ if (val == NULL || gconf_value_get_bool(val)) { ++ if (XIM_IS_LOOPBACK (applet->server->default_server)) { ++ g_object_set(G_OBJECT (applet->server->default_server), ++ "synchronous", gconf_value_get_bool(val), ++ NULL); ++ } ++ } ++ gconf_value_free(val); ++ + dbus_bus_add_match(applet->conn, + "type='signal'," + "interface='" IMSETTINGS_XIM_INTERFACE_DBUS "'", diff --git a/imsettings-sync-forward-mode.patch b/imsettings-sync-forward-mode.patch new file mode 100644 index 0000000..3e8587e --- /dev/null +++ b/imsettings-sync-forward-mode.patch @@ -0,0 +1,180 @@ +diff -pruN imsettings-0.105.1.orig/applet/imsettings-applet.schemas.in imsettings-0.105.1/applet/imsettings-applet.schemas.in +--- imsettings-0.105.1.orig/applet/imsettings-applet.schemas.in 2008-09-24 18:49:35.000000000 +0900 ++++ imsettings-0.105.1/applet/imsettings-applet.schemas.in 2009-03-09 16:46:03.000000000 +0900 +@@ -58,5 +58,19 @@ + + + ++ ++ /schemas/apps/imsettings-applet/sync_on_forward ++ /apps/imsettings-applet/sync_on_forward ++ imsettings-applet ++ bool ++ TRUE ++ ++ Enable this when accelerator keys etc doesn't work ++ ++ When this option is enabled, all of key events will be sent to Input ++ Method synchronously. This might affects a performance. ++ ++ ++ + + +diff -pruN imsettings-0.105.1.orig/applet/main.c imsettings-0.105.1/applet/main.c +--- imsettings-0.105.1.orig/applet/main.c 2009-03-09 16:45:31.000000000 +0900 ++++ imsettings-0.105.1/applet/main.c 2009-03-09 16:52:21.000000000 +0900 +@@ -47,6 +47,7 @@ + #include + #include "client.h" + #include "proxy.h" ++#include "loopback.h" + #include "utils.h" + #endif + #ifdef ENABLE_XSETTINGS +@@ -80,6 +81,7 @@ typedef struct _IMApplet { + gboolean is_enabled; + gboolean need_update_xinputrc; + GtkWidget *checkbox_showicon; ++ GtkWidget *checkbox_sync; + #ifdef ENABLE_XIM + XimProxy *server; + gchar *xim_server; +@@ -356,6 +358,33 @@ _preference_showicon_toggled(GtkToggleBu + g_object_unref(client); + } + ++#ifdef ENABLE_XIM ++static void ++_preference_sync_toggled(GtkToggleButton *button, ++ gpointer data) ++{ ++ IMApplet *applet = data; ++ GConfClient *client = gconf_client_get_default(); ++ GConfValue *val; ++ GError *error = NULL; ++ ++ val = gconf_value_new(GCONF_VALUE_BOOL); ++ if (gtk_toggle_button_get_active(button)) { ++ gconf_value_set_bool(val, TRUE); ++ } else { ++ gconf_value_set_bool(val, FALSE); ++ } ++ gconf_client_set(client, "/apps/imsettings-applet/sync_on_forward", ++ val, &error); ++ if (error) { ++ notify_notification(applet, NOTIFY_URGENCY_CRITICAL, N_("Unable to store a value to GConf"), error->message, 5); ++ g_error_free(error); ++ } ++ gconf_value_free(val); ++ g_object_unref(client); ++} ++#endif /* ENABLE_XIM */ ++ + static void + _gconf_show_icon_cb(GConfClient *conf, + guint cnxn_id, +@@ -461,6 +490,22 @@ _gconf_xsettings_cb(GConfClient *client, + #endif + + static void ++_gconf_sync_cb(GConfClient *conf, ++ guint cnxn_id, ++ GConfEntry *entry, ++ gpointer user_data) ++{ ++ IMApplet *applet = user_data; ++ GConfValue *val = gconf_entry_get_value(entry); ++ ++ if (XIM_IS_LOOPBACK (applet->server->default_server)) { ++ g_object_set(G_OBJECT (applet->server->default_server), ++ "synchronous", gconf_value_get_bool(val), ++ NULL); ++ } ++} ++ ++static void + _lookup_ignorable_modifiers(GdkKeymap *keymap) + { + egg_keymap_resolve_virtual_modifiers(keymap, +@@ -720,12 +765,18 @@ _preference_activated(GtkMenuItem *item, + gpointer data) + { + IMApplet *applet = data; ++ GConfClient *client = gconf_client_get_default(); ++ GConfValue *val; + + if (applet->dialog == NULL) { + gchar *iconfile; + #ifdef ENABLE_XSETTINGS + GtkWidget *align_xsettings; + #endif ++#ifdef ENABLE_XIM ++ GtkWidget *align_sync; ++ GtkTooltips *tooltips_sync; ++#endif /* ENABLE_XIM */ + GtkWidget *align_showicon; + GtkWidget *button_trigger_grab; + GtkWidget *vbox_item_trigger, *vbox_item_trigger_value; +@@ -763,6 +814,23 @@ _preference_activated(GtkMenuItem *item, + G_CALLBACK (_preference_xsettings_toggled), applet); + #endif /* ENABLE_XSETTINGS */ + ++#ifdef ENABLE_XIM ++ /* sync mode */ ++ align_sync = gtk_alignment_new(0, 0, 0, 0); ++ applet->checkbox_sync = gtk_check_button_new_with_mnemonic(_("_Enable this when accelerator keys etc doesn't work")); ++ gtk_container_add(GTK_CONTAINER (align_sync), applet->checkbox_sync); ++ gtk_alignment_set_padding(GTK_ALIGNMENT (align_sync), 9, 6, 6, 6); ++ gtk_widget_set_sensitive(applet->checkbox_sync, ++ (applet->server != NULL && ++ XIM_IS_LOOPBACK (applet->server->default_server))); ++ g_signal_connect(applet->checkbox_sync, "toggled", ++ G_CALLBACK (_preference_sync_toggled), applet); ++ tooltips_sync = gtk_tooltips_new(); ++ gtk_tooltips_set_tip(tooltips_sync, applet->checkbox_sync, ++ _("When this option is enabled, all of key events will be sent to Input Method synchronously. this might affects a performance."), ++ ""); ++#endif /* ENABLE_XIM */ ++ + /* trigger key */ + vbox_item_trigger = gtk_vbox_new(FALSE, 0); + +@@ -813,6 +881,7 @@ _preference_activated(GtkMenuItem *item, + #ifdef ENABLE_XSETTINGS + gtk_box_pack_start(GTK_BOX (GTK_DIALOG (applet->dialog)->vbox), align_xsettings, TRUE, TRUE, 0); + #endif ++ gtk_box_pack_start(GTK_BOX (GTK_DIALOG (applet->dialog)->vbox), align_sync, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX (GTK_DIALOG (applet->dialog)->vbox), vbox_item_trigger, TRUE, TRUE, 0); + + /* */ +@@ -824,6 +893,11 @@ _preference_activated(GtkMenuItem *item, + _preference_update_entry(applet); + } + ++ val = gconf_client_get(client, "/apps/imsettings-applet/sync_on_forward", NULL); ++ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (applet->checkbox_sync), ++ val == NULL ? TRUE : gconf_value_get_bool(val)); ++ gconf_value_free(val); ++ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (applet->checkbox_showicon), + gtk_status_icon_get_visible(applet->status_icon)); + #ifdef ENABLE_XSETTINGS +@@ -835,6 +909,8 @@ _preference_activated(GtkMenuItem *item, + gtk_editable_set_editable(GTK_EDITABLE (applet->entry_grabkey), FALSE); + gtk_widget_show(applet->dialog); + gtk_widget_grab_focus(applet->close_button); ++ ++ g_object_unref(client); + } + + static void +@@ -1227,6 +1303,8 @@ _create_applet(gboolean is_xsettings_dis + #endif + gconf_client_notify_add(client, "/apps/imsettings-applet/show_icon", + _gconf_show_icon_cb, applet, NULL, &error); ++ gconf_client_notify_add(client, "/apps/imsettings-applet/sync_on_forward", ++ _gconf_sync_cb, applet, NULL, &error); + + val = gconf_client_get(client, "/apps/imsettings-applet/trigger_key", NULL); + key = gconf_value_get_string(val); diff --git a/imsettings-xim-fixes.patch b/imsettings-xim-fixes.patch new file mode 100644 index 0000000..3972f45 --- /dev/null +++ b/imsettings-xim-fixes.patch @@ -0,0 +1,637 @@ +Index: backends/xim/loopback.h +=================================================================== +--- backends/xim/loopback.h (リビジョン 242) ++++ backends/xim/loopback.h (リビジョン 276) +@@ -63,6 +63,7 @@ + + GHashTable *conn_table; + guint latest_imid; ++ gboolean sync_on_forward; + }; + + struct _XimLoopbackConnectionClass { +@@ -79,6 +80,9 @@ + struct _XimLoopbackIC { + Sequence *sequence_state; + GXimICAttr *icattr; ++ GQueue *keyeventq; ++ gboolean wait_for_reply; ++ gboolean resend; + }; + + GType xim_loopback_get_type(void) G_GNUC_CONST; +Index: backends/xim/proxy.c +=================================================================== +--- backends/xim/proxy.c (リビジョン 242) ++++ backends/xim/proxy.c (リビジョン 276) +@@ -1338,8 +1338,8 @@ + } else { + retval = g_xim_server_connection_cmd_set_ic_values_reply(conn, simid, icid); + } ++ DEC_PENDING (XIM_PROXY_CONNECTION (conn), G_XIM_SET_IC_VALUES_REPLY, 0, simid, icid); + g_free(req); +- DEC_PENDING (XIM_PROXY_CONNECTION (conn), G_XIM_SET_IC_VALUES_REPLY, 0, simid, icid); + end: + + return retval; +Index: backends/xim/compose.c +=================================================================== +--- backends/xim/compose.c (リビジョン 242) ++++ backends/xim/compose.c (リビジョン 276) +@@ -125,12 +125,10 @@ + { + GSList *list = NULL, *l; + +- if (seq->string) { +- g_set_error(error, sequence_get_error_quark(), SEQ_ERR_INVALID_SEQUENCE, +- "Child sequence won't be matched."); ++ /* Overriding old entry like what XKB does */ ++ g_free(seq->string); ++ seq->string = NULL; + +- return FALSE; +- } + if (seq->candidates == NULL) { + seq->candidates = g_tree_new(_sequence_compare); + } +@@ -139,7 +137,7 @@ + Sequence *s = l->data; + + if (s->keysym == next->keysym && +- s->modifiers == next->modifiers &&+ ++ s->modifiers == next->modifiers && + s->mod_mask == next->mod_mask) { + g_set_error(error, sequence_get_error_quark(), SEQ_ERR_SEQUENCE_EXISTS, + "Sequence [keysym:0x%lx,mods:0x%x,mask:0x%x] already exists.", +@@ -155,6 +153,23 @@ + } + + static gboolean ++sequence_replace(Sequence *seq, ++ Sequence *next, ++ GError **error) ++{ ++ g_free(seq->string); ++ if (seq->candidates) { ++ g_tree_foreach(seq->candidates, _sequence_list_free, NULL); ++ g_tree_destroy(seq->candidates); ++ seq->candidates = NULL; ++ } ++ seq->string = g_strdup(next->string); ++ seq->composed = next->composed; ++ ++ return TRUE; ++} ++ ++static gboolean + sequence_terminate(Sequence *seq, + const gchar *string, + gulong keysym, +@@ -186,7 +201,7 @@ + for (l = list; l != NULL; l = g_slist_next(l)) { + Sequence *s = l->data; + +- if (s->keysym == keysym && (modifiers & s->mod_mask) == s->modifiers) { ++ if (s->keysym == keysym && (modifiers & ~s->mod_mask) == s->modifiers) { + return s; + } + } +@@ -424,6 +439,12 @@ + gboolean pending = FALSE; + Sequence *node, *sequence; + GError *error = NULL; ++ enum { ++ RHS_NONE, ++ RHS_STRING, ++ RHS_KEYSYM, ++ RHS_BOTH ++ } rhs_type = RHS_NONE; + + g_return_val_if_fail (compose != NULL, FALSE); + g_return_val_if_fail (compose->fp != NULL, FALSE); +@@ -481,9 +502,7 @@ + + keysym = XStringToKeysym(seqbuf); + if (keysym == NoSymbol) { +- /* dirty hack to get rid of known warnings */ +- if (strncmp(seqbuf, "combining_", 10) != 0) +- g_warning("Invalid symbol: %s", seqbuf); ++ d(g_warning("Invalid symbol: %s", seqbuf)); + goto fail; + } + sequence = sequence_new(keysym, modifiers, mod_mask); +@@ -501,82 +520,97 @@ + p = data; + + if (*p == 0 || _is_comment(*p)) { +- g_warning("Invalid entry [no string]: %s", buf); ++ g_warning("Invalid entry [no string nor keysym]: %s", buf); + goto fail; + } + + if (*p != '"') { +- g_warning("Invalid data [no initiator for string]: %s", data); +- goto fail; +- } +- p++; +- pending = FALSE; +- for (i = 0; *p && i < 1024; p++) { +- if (*p == '\\') { +- if (!pending) { +- pending = TRUE; ++ /* this line may be a keysym only */ ++ rhs_type = RHS_KEYSYM; ++ string[0] = 0; ++ } else { ++ p++; ++ pending = FALSE; ++ for (i = 0; *p && i < 1024; p++) { ++ if (*p == '\\') { ++ if (!pending) { ++ pending = TRUE; ++ continue; ++ } ++ } ++ if (pending) { ++ /* FIXME: hexadecimal, octadecimal support */ ++ switch (*p) { ++ case '\\': ++ case '"': ++ string[i++] = *p; ++ break; ++ case 'n': ++ string[i++] = '\n'; ++ break; ++ case 'r': ++ string[i++] = '\r'; ++ break; ++ case 't': ++ string[i++] = '\t'; ++ break; ++ default: ++ g_warning("unknown escape format: \\%c", *p); ++ break; ++ } ++ pending = FALSE; + continue; + } ++ if (*p == '"') ++ break; ++ string[i++] = *p; + } +- if (pending) { +- /* FIXME: hexadecimal, octadecimal support */ +- switch (*p) { +- case '\\': +- case '"': +- string[i++] = *p; +- break; +- case 'n': +- string[i++] = '\n'; +- break; +- case 'r': +- string[i++] = '\r'; +- break; +- case 't': +- string[i++] = '\t'; +- break; +- default: +- g_warning("unknown escape format: \\%c", *p); +- break; +- } +- pending = FALSE; +- continue; ++ string[i] = 0; ++ if (*p != '"') { ++ g_warning("Invalid data [no terminator for string]: %s", data); ++ goto fail; + } +- if (*p == '"') +- break; +- string[i++] = *p; ++ p++; ++ _skip_whitespaces(p); ++ rhs_type = RHS_STRING; + } +- string[i] = 0; +- if (*p != '"') { +- g_warning("Invalid data [no terminator for string]: %s", data); +- goto fail; +- } +- p++; +- + /* get symbol */ +- _skip_whitespaces(p); + if (*p == 0 || _is_comment(*p)) { +- g_warning("Invalid entry [no symbol]: %s", buf); +- goto fail; ++ if (rhs_type == RHS_KEYSYM) { ++ g_warning("Invalid entry [no keysym]: %s", buf); ++ goto fail; ++ } ++ result_keysym = NoSymbol; ++ } else { ++ for (i = 0; *p && !_is_whitespace(*p) && i < 1024; i++, p++) ++ symbol[i] = *p; ++ symbol[i] = 0; ++ result_keysym = XStringToKeysym(symbol); ++ if (result_keysym == NoSymbol) { ++ d(g_warning("Invalid symbol for result: %s", symbol)); ++ goto fail; ++ } ++ if (rhs_type == RHS_STRING) ++ rhs_type = RHS_BOTH; + } +- for (i = 0; *p && !_is_whitespace(*p) && i < 1024; i++, p++) +- symbol[i] = *p; +- symbol[i] = 0; +- result_keysym = XStringToKeysym(symbol); +- if (result_keysym == NoSymbol) { +- g_warning("Invalid symbol for result: %s", symbol); ++ if (string[0] != 0) { ++ utf8_string = g_convert(string, -1, "UTF-8", charset, NULL, NULL, &error); ++ if (error) { ++ g_warning("%s: %s", error->message, buf); ++ /* error might be still re-used later */ ++ g_clear_error(&error); ++ goto fail; ++ } ++ } else { ++ utf8_string = NULL; + } +- utf8_string = g_convert(string, -1, "UTF-8", charset, NULL, NULL, &error); +- if (error) { +- g_warning("%s: %s", error->message, buf); +- g_error_free(error); +- goto fail; +- } + sequence_terminate(sequence, utf8_string, result_keysym, &error); + g_free(utf8_string); + if (error) { + /* unlikely to happen usually */ + g_warning("%s", error->message); +- g_error_free(error); ++ /* error might be still re-used later */ ++ g_clear_error(&error); + goto fail; + } + +@@ -589,6 +623,7 @@ + sequence_add(node, s, &error); + if (error) { + g_warning("%s: %s", error->message, seq); ++ g_clear_error(&error); + sequence_free(s); + goto fail; + } +@@ -596,8 +631,18 @@ + } else { + if ((i + 1) == seqarray->len) { + if (child->candidates != NULL) { ++ /* XXX: XKB seems to be overwriting old data. */ ++ sequence_replace(child, s, &error); ++ if (error) { ++ g_warning("%s: %s", error->message, seq); ++ g_clear_error(&error); ++ sequence_free(s); ++ goto fail; ++ } ++#if 0 + g_warning("Duplicate sequence: %s", seq); + goto fail; ++#endif + } else if (s->composed != child->composed || + (s->string == NULL && child->string != NULL) || + (s->string != NULL && child->string == NULL) || +Index: backends/xim/loopback.c +=================================================================== +--- backends/xim/loopback.c (リビジョン 242) ++++ backends/xim/loopback.c (リビジョン 276) +@@ -39,8 +39,26 @@ + #include + #include "loopback.h" + ++/* ++ * Borrow an idea from IsModifierKey() in Xutil.h ++ */ ++#define IS_MODIFIER_KEY(x) \ ++ ((((x) >= GDK_Shift_L) && ((x) <= GDK_Hyper_R)) || \ ++ (((x) >= GDK_ISO_Lock) && ((x) <= GDK_ISO_Group_Lock)) || \ ++ ((x) == GDK_Mode_switch) || \ ++ ((x) == GDK_Num_Lock)) ++ ++typedef struct _XimLoopbackQueueContainer { ++ GXimProtocol *proto; ++ guint16 imid; ++ guint16 icid; ++ guint16 flag; ++ GdkEvent *event; ++} XimLoopbackQueueContainer; ++ + enum { + PROP_0, ++ PROP_SYNCHRONOUS, + LAST_PROP + }; + enum { +@@ -69,6 +87,10 @@ + guint16 imid, + GSList *attributes, + gpointer data); ++static gboolean xim_loopback_real_xim_destroy_ic (GXimProtocol *proto, ++ guint16 imid, ++ guint16 icid, ++ gpointer data); + static gboolean xim_loopback_real_xim_set_ic_values (GXimProtocol *proto, + guint16 imid, + guint16 icid, +@@ -97,6 +119,7 @@ + guint16 imid, + guint16 icid, + gpointer data); ++static gboolean _process_keyevent (gpointer data); + + //static guint signals[LAST_SIGNAL] = { 0 }; + +@@ -110,7 +133,12 @@ + static XimLoopbackIC * + xim_loopback_ic_new(void) + { +- return g_new0(XimLoopbackIC, 1); ++ XimLoopbackIC *retval = g_new0(XimLoopbackIC, 1); ++ ++ G_XIM_CHECK_ALLOC (retval, NULL); ++ retval->keyeventq = g_queue_new(); ++ ++ return retval; + } + + static void +@@ -118,10 +146,49 @@ + { + XimLoopbackIC *ic = data; + +- g_free(ic); ++ if (ic) { ++ g_queue_free(ic->keyeventq); ++ g_free(ic); ++ } + } + + static void ++xim_loopback_real_set_property(GObject *object, ++ guint prop_id, ++ const GValue *value, ++ GParamSpec *pspec) ++{ ++ XimLoopback *loopback = XIM_LOOPBACK (object); ++ ++ switch (prop_id) { ++ case PROP_SYNCHRONOUS: ++ loopback->sync_on_forward = g_value_get_boolean(value); ++ break; ++ default: ++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); ++ break; ++ } ++} ++ ++static void ++xim_loopback_real_get_property(GObject *object, ++ guint prop_id, ++ GValue *value, ++ GParamSpec *pspec) ++{ ++ XimLoopback *loopback = XIM_LOOPBACK (object); ++ ++ switch (prop_id) { ++ case PROP_SYNCHRONOUS: ++ g_value_set_boolean(value, loopback->sync_on_forward); ++ break; ++ default: ++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); ++ break; ++ } ++} ++ ++static void + xim_loopback_real_finalize(GObject *object) + { + XimLoopback *loopback = XIM_LOOPBACK (object); +@@ -144,11 +211,19 @@ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GXimCoreClass *core_class = G_XIM_CORE_CLASS (klass); + ++ object_class->set_property = xim_loopback_real_set_property; ++ object_class->get_property = xim_loopback_real_get_property; + object_class->finalize = xim_loopback_real_finalize; + + core_class->setup_connection = xim_loopback_real_setup_connection; + + /* properties */ ++ g_object_class_install_property(object_class, PROP_SYNCHRONOUS, ++ g_param_spec_boolean("synchronous", ++ _("Synchronous"), ++ _("Request to send a key event synchronously"), ++ TRUE, ++ G_PARAM_READWRITE)); + + /* signals */ + } +@@ -163,6 +238,7 @@ + {"XIM_ENCODING_NEGOTIATION", G_CALLBACK (xim_loopback_real_xim_encoding_negotiation), loopback}, + {"XIM_GET_IM_VALUES", G_CALLBACK (xim_loopback_real_xim_get_im_values), loopback}, + {"XIM_CREATE_IC", G_CALLBACK (xim_loopback_real_xim_create_ic), loopback}, ++ {"XIM_DESTROY_IC", G_CALLBACK (xim_loopback_real_xim_destroy_ic), loopback}, + {"XIM_SET_IC_VALUES", G_CALLBACK (xim_loopback_real_xim_set_ic_values), loopback}, + {"XIM_GET_IC_VALUES", G_CALLBACK (xim_loopback_real_xim_get_ic_values), loopback}, + {"XIM_SET_IC_FOCUS", G_CALLBACK (xim_loopback_real_xim_set_ic_focus), loopback}, +@@ -666,7 +742,7 @@ + g_xim_server_connection_cmd_set_event_mask(G_XIM_SERVER_CONNECTION (proto), + imid, icid, + KeyPressMask | KeyReleaseMask, +- ~(KeyPressMask | KeyReleaseMask)); ++ loopback->sync_on_forward ? ~NoEventMask : ~(KeyPressMask | KeyReleaseMask)); + } else { + g_xim_connection_cmd_error(G_XIM_CONNECTION (proto), + imid, 0, G_XIM_EMASK_VALID_IMID, +@@ -685,6 +761,34 @@ + } + + static gboolean ++xim_loopback_real_xim_destroy_ic(GXimProtocol *proto, ++ guint16 imid, ++ guint16 icid, ++ gpointer data) ++{ ++ XimLoopbackConnection *lconn = XIM_LOOPBACK_CONNECTION (proto); ++ XimLoopbackIC *ic = g_hash_table_lookup(lconn->ic_table, GUINT_TO_POINTER ((guint)icid)); ++ ++ if (ic == NULL) { ++ gchar *msg = g_strdup_printf("Invalid input-context ID: [%d,%d]", imid, icid); ++ gboolean retval; ++ ++ g_xim_message_warning(G_XIM_PROTOCOL_GET_IFACE (proto)->message, ++ msg); ++ retval = g_xim_connection_cmd_error(G_XIM_CONNECTION (proto), ++ imid, icid, G_XIM_EMASK_VALID_IMID | G_XIM_EMASK_VALID_ICID, ++ G_XIM_ERR_BadProtocol, ++ 0, msg); ++ g_free(msg); ++ ++ return retval; ++ } ++ g_hash_table_remove(lconn->ic_table, GUINT_TO_POINTER ((guint)icid)); ++ ++ return g_xim_server_connection_cmd_destroy_ic_reply(G_XIM_SERVER_CONNECTION (proto), imid, icid);; ++} ++ ++static gboolean + xim_loopback_real_xim_set_ic_values(GXimProtocol *proto, + guint16 imid, + guint16 icid, +@@ -839,6 +943,27 @@ + icid); + goto end; + } ++ if (!ic->resend && ++ (ic->wait_for_reply || g_queue_get_length(ic->keyeventq) > 0)) { ++ XimLoopbackQueueContainer *c = g_new0(XimLoopbackQueueContainer, 1); ++ ++ c->proto = g_object_ref(proto); ++ c->imid = imid; ++ c->icid = icid; ++ c->flag = flag; ++ c->event = gdk_event_copy(event); ++ g_queue_push_tail(ic->keyeventq, c); ++ g_xim_message_debug(G_XIM_PROTOCOL_GET_IFACE (proto)->message, "loopback/proto/event", ++ "Queueing a keyevent. (imid: %d, icid: %d, type: %s, keyval: %X)", ++ imid, icid, ++ event->type == GDK_KEY_PRESS ? "KeyPress" : "KeyRelease", ++ event->key.keyval); ++ ++ return TRUE; ++ } ++ ++ if (IS_MODIFIER_KEY (event->key.keyval)) ++ goto end; + if (event->type == GDK_KEY_RELEASE) + goto end; + +@@ -856,16 +981,23 @@ + GString *s = g_string_new(NULL); + guchar *ctext = NULL; + gint len = 0; ++ GXimLookupType lookup_type = G_XIM_XLookupChars; + +- gdk_string_to_compound_text_for_display(dpy, string, NULL, NULL, &ctext, &len); +- g_string_append_len(s, (gchar *)ctext, len); +- g_free(ctext); ++ if (string) { ++ gdk_string_to_compound_text_for_display(dpy, string, NULL, NULL, &ctext, &len); ++ g_string_append_len(s, (gchar *)ctext, len); ++ g_free(ctext); ++ } + + /* XXX: need to look at the keymap? */ ++ if (string == NULL) ++ lookup_type = G_XIM_XLookupKeySym; + retval = g_xim_server_connection_cmd_commit(G_XIM_SERVER_CONNECTION (proto), + imid, icid, +- G_XIM_XLookupSynchronous | G_XIM_XLookupChars, ++ (sflag ? G_XIM_XLookupSynchronous : 0) | lookup_type, + keysym, s); ++ /* Ensure that we'll try to find out a sequence from the beginning next time */ ++ ic->sequence_state = NULL; + + d(g_print("result: %s [%s]: 0x%x\n", gdk_keyval_name(keysym), string, event->key.hardware_keycode)); + +@@ -879,15 +1011,21 @@ + } else { + ic->sequence_state = NULL; + } +- + + end: + if (!retval) + retval = g_xim_connection_cmd_forward_event(G_XIM_CONNECTION (proto), + imid, icid, sflag, event); +- +- if (flag & G_XIM_Event_Synchronous) ++ if (flag & G_XIM_Event_Synchronous) { + g_xim_connection_cmd_sync_reply(G_XIM_CONNECTION (proto), imid, icid); ++ /* sending XIM_SYNC_REPLY usually means synchronization is done. */ ++ ic->wait_for_reply = FALSE; ++ } else if (sflag & G_XIM_Event_Synchronous) { ++ ic->wait_for_reply = TRUE; ++ } ++ if (!ic->wait_for_reply && g_queue_get_length(ic->keyeventq)) { ++ g_idle_add_full(G_PRIORITY_HIGH_IDLE, _process_keyevent, ic->keyeventq, NULL); ++ } + + return retval; + } +@@ -898,10 +1036,62 @@ + guint16 icid, + gpointer data) + { +- /* Nothing to do */ ++ XimLoopbackConnection *lconn = XIM_LOOPBACK_CONNECTION (proto); ++ XimLoopbackIC *ic = g_hash_table_lookup(lconn->ic_table, GUINT_TO_POINTER ((guint)icid)); ++ gboolean flag = g_atomic_int_get(&ic->wait_for_reply); ++ ++ retry: ++ if (flag) { ++ if (!g_atomic_int_compare_and_exchange(&ic->wait_for_reply, flag, FALSE)) ++ goto retry; ++ } ++ if (g_queue_get_length(ic->keyeventq) > 0) { ++ g_idle_add_full(G_PRIORITY_HIGH_IDLE, _process_keyevent, ic->keyeventq, NULL); ++ } ++ + return TRUE; + } + ++static gboolean ++_process_keyevent(gpointer data) ++{ ++ GQueue *q = data; ++ XimLoopbackQueueContainer *c; ++ XimLoopbackConnection *lconn; ++ XimLoopbackIC *ic; ++ gboolean retval; ++ GClosure *closure; ++ ++ c = g_queue_pop_head(q); ++ closure = (GClosure *)g_xim_protocol_lookup_protocol_by_id(c->proto, G_XIM_FORWARD_EVENT, 0); ++ if (closure == NULL) { ++ g_xim_message_bug(G_XIM_PROTOCOL_GET_IFACE (c->proto)->message, ++ "No closure to re-send back a XIM_FORWARD_EVENT."); ++ } else { ++ lconn = XIM_LOOPBACK_CONNECTION (c->proto); ++ ic = g_hash_table_lookup(lconn->ic_table, GUINT_TO_POINTER ((guint)c->icid)); ++ ic->resend = TRUE; ++ g_xim_message_debug(G_XIM_PROTOCOL_GET_IFACE (c->proto)->message, "loopback/proto/event", ++ "Re-processing XIM_FORWARD_EVENT (imid: %d, icid: %d, type: %s, keyval: %X)", ++ c->imid, c->icid, ++ c->event->type == GDK_KEY_PRESS ? "KeyPress" : "KeyRelease", ++ c->event->key.keyval); ++ retval = g_xim_protocol_closure_emit_signal((GXimProtocolClosure *)closure, ++ c->proto, ++ c->imid, c->icid, c->flag, c->event); ++ ic->resend = FALSE; ++ if (!retval) { ++ g_xim_message_warning(G_XIM_PROTOCOL_GET_IFACE (c->proto)->message, ++ "Unable to re-send back a XIM_FORWARD_EVENT. this event will be discarded."); ++ } ++ } ++ g_object_unref(c->proto); ++ gdk_event_free(c->event); ++ g_free(c); ++ ++ return FALSE; ++} ++ + /* + * Public functions + */ diff --git a/imsettings.spec b/imsettings.spec index 57744de..618f824 100644 --- a/imsettings.spec +++ b/imsettings.spec @@ -1,6 +1,6 @@ Name: imsettings Version: 0.105.1 -Release: 3%{?dist} +Release: 4%{?dist} License: LGPLv2+ URL: http://code.google.com/p/imsettings/ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -18,6 +18,10 @@ Source1: imsettings-kde.sh Patch0: imsettings-constraint-of-language.patch Patch1: imsettings-fix-unpredictable-session-order.patch Patch2: imsettings-fix-registertriggerkeys.patch +Patch3: imsettings-disable-imsettings-xim.patch +Patch4: imsettings-sync-forward-mode.patch +Patch5: imsettings-sync-default.patch +Patch6: imsettings-xim-fixes.patch Summary: Delivery framework for general Input Method configuration Group: Applications/System @@ -84,6 +88,10 @@ This package contains a plugin to get this working on Xfce. %patch0 -p1 -b .0-lang %patch1 -p0 -b .1-session-order %patch2 -p0 -b .2-triggerkeys +%patch3 -p0 -b .3-disable-imsettings-xim +%patch4 -p1 -b .5-sync +%patch5 -p0 -b .9-sync-default +%patch6 -p0 -b .6-xim-fixes autoreconf %build @@ -202,6 +210,19 @@ fi %changelog +* Mon Mar 17 2009 Akira TAGOH - 0.105.1-4 +- Fix a dead key not working. (#483840) +- Get rid of more debugging messages. (#484142) +- Disable imsettings-xim in xinput.sh. (#485595) +- Fix a parser error on reading Compose data. +- Fix a double-free issue. +- Workaround to get the accelerator keys working again. + Note that this workaround might affects to the performance. you may want + to disable this with: + gconftool-2 -t bool -s /apps/imsettings-applet/sync_on_forward false + (#488675) +- Fix getting-stuck-issue on keyevent. (#488976, #489611) + * Tue Oct 28 2008 Akira TAGOH - 0.105.1-3 - imsettings-fix-registertriggerkeys.patch: Fix to send XIM_REGISTER_TRIGGERKEYS anyway. (#468833)