[PATCH libX11 2/2] XIM: Fix sync problem on focus change.

Egbert Eich eich at freedesktop.org
Fri Dec 7 02:57:52 PST 2012


XSetICFocus() and XUnsetICFocus() are both asynchronous events.
This is a pretty stupid idea: those functions may undo certain
settings on the client side for which requests from the server
may still be in the queue unprocessed. Thus things may be set
in the wrong order ie instead of set -> unest it will be unset -> set.
Moreover there is no way for either the client or the server to
cause the event queue to be flushed - which is pretty bad as
XIM is bidirectional.
The scenario is as follows:
Two ICs are created:
        ic1 = XCreateIC(im,
            XNInputStyle, XIMPreeditCallbacks | XIMStatusCallbacks,
            XNClientWindow, window,
            XNPreeditAttributes, preedit_attr,
            XNStatusAttributes, status_attr,
            NULL);
        ic2 = XCreateIC(im, XNInputStyle,
                       XIMPreeditNothing | XIMStatusNothing,
                       XNClientWindow, window, NULL);
Then the focus is removed from ic2:
        XUnsetICFocus(ic2);
If SCIM is used as the input server it will send a bunch of requests
following an XCreateIC(). One of the requests registers a key release
filter. XUnsetICFocus() unsets both key press and release filters.
Since it is asynchronous, the input server requests to register key
press and release filters may not have been processed, when XUnsetICFocus()
is called. Since there is no explicite way for client programs to enforce
the request queue to be flushed explicitely before an X[Set/Unset]ICFocus()
call it would be safest to make those two calls synchronous in the sense
that they ensure the request queue has been handled before they execute.
The easiest way to do this from Xlib is thru a call to XGetICValues()
which sends a request to the server and subsequently reads the queue
from the server to the client. This will cause all outstanding requests
in the queue to be read and handled.
This is an ugly hack and this could be fixed directly in the client,
however it seems to be easier to fix Xlib than to fix numerous clients.
This problem arose since there is no well documented way how to handle
and synchronize XIM requests and not all input servers send requests
when an IC is created.
This has been discussed extensively in:
 https://bugzilla.novell.com/show_bug.cgi?id=221326

Signed-off-by: Egbert Eich <eich at freedesktop.org>
---
 modules/im/ximcp/imDefIc.c |   27 +++++++++++++++++++++++++++
 1 files changed, 27 insertions(+), 0 deletions(-)

diff --git a/modules/im/ximcp/imDefIc.c b/modules/im/ximcp/imDefIc.c
index 3b5fa41..f7e4847 100644
--- a/modules/im/ximcp/imDefIc.c
+++ b/modules/im/ximcp/imDefIc.c
@@ -927,6 +927,30 @@ _XimProtoDestroyIC(
     return;
 }
 
+/*
+ * Some functions require the request queue from the server to be flushed
+ * so that the ordering of client initiated status changes and those requested
+ * by the server is well defined.
+ * _XimSync() would be the function of choice here as it should get a
+ * XIM_SYNC_REPLY back from the server.
+ * This however isn't implemented in the piece of junk that is used by most
+ * input servers as the server side protocol if to XIM.
+ * Since this code is not shipped as a library together with the client side
+ * XIM code but is duplicated by every input server around the world there
+ * is no easy fix to this but this ugly hack below.
+ * Obtaining an IC value from the server sends a request and empties out the
+ * event/server request queue until the answer to this request is found.
+ * Thus it is guaranteed that any pending server side request gets processed.
+ * This is what the hack below is doing.
+ */
+
+static void
+BrokenSyncWithServer(XIC xic)
+{
+    CARD32 dummy;
+    XGetICValues(xic, XNFilterEvents, &dummy, NULL);
+}
+
 static void
 _XimProtoSetFocus(
     XIC		 xic)
@@ -957,6 +981,7 @@ _XimProtoSetFocus(
 	}
     }
 #endif /* XIM_CONNECTABLE */
+    BrokenSyncWithServer(xic);
 
     buf_s[0] = im->private.proto.imid;		/* imid */
     buf_s[1] = ic->private.proto.icid;		/* icid */
@@ -1003,6 +1028,8 @@ _XimProtoUnsetFocus(
     }
 #endif /* XIM_CONNECTABLE */
 
+    BrokenSyncWithServer(xic);
+
     buf_s[0] = im->private.proto.imid;		/* imid */
     buf_s[1] = ic->private.proto.icid;		/* icid */
 
-- 
1.7.7



More information about the xorg-devel mailing list