diff --git a/imsettings-xim-fixes.patch b/imsettings-xim-fixes.patch new file mode 100644 index 0000000..8ec432f --- /dev/null +++ b/imsettings-xim-fixes.patch @@ -0,0 +1,412 @@ +Index: applet/imsettings-applet.schemas.in +=================================================================== +--- applet/imsettings-applet.schemas.in (リビジョン 263) ++++ applet/imsettings-applet.schemas.in (リビジョン 277) +@@ -50,7 +50,7 @@ + /apps/imsettings-applet/sync_on_forward + imsettings-applet + bool +- FALSE ++ TRUE + + Enable this when accelerator keys etc doesn't work + +Index: applet/main.c +=================================================================== +--- applet/main.c (リビジョン 263) ++++ applet/main.c (リビジョン 277) +@@ -779,7 +779,8 @@ + 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); ++ if (val) ++ gconf_value_free(val); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (applet->checkbox_showicon), + gtk_status_icon_get_visible(applet->status_icon)); +@@ -1223,7 +1224,8 @@ + "synchronous", val == NULL ? TRUE : gconf_value_get_bool(val), + NULL); + } +- gconf_value_free(val); ++ if (val) ++ gconf_value_free(val); + + dbus_bus_add_match(applet->conn, + "type='signal'," +Index: backends/xim/loopback.h +=================================================================== +--- backends/xim/loopback.h (リビジョン 263) ++++ backends/xim/loopback.h (リビジョン 277) +@@ -80,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 (リビジョン 263) ++++ backends/xim/proxy.c (リビジョン 277) +@@ -1337,8 +1337,8 @@ + g_queue_get_length(priv->sendq)); + } 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); + } ++ DEC_PENDING (XIM_PROXY_CONNECTION (conn), G_XIM_SET_IC_VALUES_REPLY, 0, simid, icid); + g_free(req); + end: + +Index: backends/xim/compose.c +=================================================================== +--- backends/xim/compose.c (リビジョン 263) ++++ backends/xim/compose.c (リビジョン 277) +@@ -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; + } + } +@@ -487,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); +@@ -574,7 +587,8 @@ + symbol[i] = 0; + result_keysym = XStringToKeysym(symbol); + if (result_keysym == NoSymbol) { +- g_warning("Invalid symbol for result: %s", symbol); ++ d(g_warning("Invalid symbol for result: %s", symbol)); ++ goto fail; + } + if (rhs_type == RHS_STRING) + rhs_type = RHS_BOTH; +@@ -617,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 (リビジョン 263) ++++ backends/xim/loopback.c (リビジョン 277) +@@ -39,6 +39,23 @@ + #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, +@@ -70,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, +@@ -98,6 +119,7 @@ + guint16 imid, + guint16 icid, + gpointer data); ++static gboolean _process_keyevent (gpointer data); + + //static guint signals[LAST_SIGNAL] = { 0 }; + +@@ -111,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 +@@ -119,7 +146,10 @@ + { + XimLoopbackIC *ic = data; + +- g_free(ic); ++ if (ic) { ++ g_queue_free(ic->keyeventq); ++ g_free(ic); ++ } + } + + static void +@@ -208,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}, +@@ -730,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, +@@ -884,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; + +@@ -914,8 +994,10 @@ + lookup_type = G_XIM_XLookupKeySym; + retval = g_xim_server_connection_cmd_commit(G_XIM_SERVER_CONNECTION (proto), + imid, icid, +- G_XIM_XLookupSynchronous | lookup_type, ++ (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)); + +@@ -929,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; + } +@@ -948,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 36fe60f..cc6eb05 100644 --- a/imsettings.spec +++ b/imsettings.spec @@ -1,6 +1,6 @@ Name: imsettings Version: 0.106.1 -Release: 1%{?dist} +Release: 2%{?dist} License: LGPLv2+ URL: http://code.google.com/p/imsettings/ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -15,6 +15,7 @@ Source0: http://imsettings.googlecode.com/files/%{name}-%{version}.tar.bz2 # workaround for KDE, it will be removed when we have a correct fix Source1: imsettings-kde.sh Patch0: imsettings-constraint-of-language.patch +Patch1: imsettings-xim-fixes.patch Summary: Delivery framework for general Input Method configuration Group: Applications/System @@ -80,6 +81,7 @@ This package contains a plugin to get this working on Xfce. %prep %setup -q %patch0 -p1 -b .0-lang +%patch1 -p0 -b .1-xim-fixes %build %configure \ @@ -197,6 +199,11 @@ fi %changelog +* Wed Mar 18 2009 Akira TAGOH - 0.106.1-2 +- Fix XIM-related issues. +- Fix a parser error during reading Compose data. (#484142) +- Get rid of more debugging messages. + * Tue Mar 10 2009 Akira TAGOH - 0.106.1-1 - New upstream release. - Fix a double-free issue. (#485595)