Skip to content

Instantly share code, notes, and snippets.

@klemensbaum
Last active August 29, 2015 14:10
Show Gist options
  • Save klemensbaum/87cd0ff77a34abb9d353 to your computer and use it in GitHub Desktop.
Save klemensbaum/87cd0ff77a34abb9d353 to your computer and use it in GitHub Desktop.
diff --git a/util/IMdkit/Makefile.am b/util/IMdkit/Makefile.am
index e3946d7..8a3714c 100644
--- a/util/IMdkit/Makefile.am
+++ b/util/IMdkit/Makefile.am
@@ -29,6 +29,7 @@ libIMdkit_la_SOURCES = \
i18nIc.c \
i18nIMProto.c \
i18nMethod.c \
+ i18nOffsetCache.c \
i18nPtHdr.c \
i18nUtil.c \
i18nX.c \
diff --git a/util/IMdkit/Xi18n.h b/util/IMdkit/Xi18n.h
index 484cc62..e9d3426 100644
--- a/util/IMdkit/Xi18n.h
+++ b/util/IMdkit/Xi18n.h
@@ -45,6 +45,7 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#define XIM_EXT_MOVE (0x33)
#define COMMON_EXTENSIONS_NUM 3
+#include <stddef.h>
#include <stdlib.h>
#include "IMdkit.h"
@@ -138,6 +139,19 @@ typedef struct
char *name;
} XIMExt;
+typedef struct
+{
+ Atom key;
+ unsigned long offset;
+} Xi18nAtomOffsetPair;
+
+typedef struct
+{
+ size_t capacity;
+ size_t size;
+ Xi18nAtomOffsetPair *data;
+} Xi18nOffsetCache;
+
typedef struct _Xi18nClient
{
int connect_id;
@@ -149,8 +163,7 @@ typedef struct _Xi18nClient
*/
int sync;
XIMPending *pending;
- /* property offset to read next data */
- long property_offset;
+ Xi18nOffsetCache offset_cache;
void *trans_rec; /* contains transport specific data */
struct _Xi18nClient *next;
} Xi18nClient;
diff --git a/util/IMdkit/i18nOffsetCache.c b/util/IMdkit/i18nOffsetCache.c
new file mode 100644
index 0000000..da289c1
--- /dev/null
+++ b/util/IMdkit/i18nOffsetCache.c
@@ -0,0 +1,67 @@
+#include <X11/Xlib.h>
+#include <stddef.h>
+#include "IMdkit.h"
+#include "Xi18n.h"
+
+/*
+* The XIM specification does not limit the number of window properties
+* that can be used to transfer data, but Xlib uses the atom strings
+* _client0 through _client20.
+*
+* So use that as a sensible initial size for the offset cache.
+*/
+#define INITIAL_OFFSET_CACHE_CAPACITY 21
+#define OFFSET_CACHE_GROWTH_FACTOR 2
+
+void _Xi18nInitOffsetCache(Xi18nOffsetCache *offset_cache)
+{
+ offset_cache->size = 0;
+ offset_cache->capacity = INITIAL_OFFSET_CACHE_CAPACITY;
+ offset_cache->data = (Xi18nAtomOffsetPair *)malloc(
+ INITIAL_OFFSET_CACHE_CAPACITY * sizeof(Xi18nAtomOffsetPair));
+}
+
+unsigned long _Xi18nLookupPropertyOffset(Xi18nOffsetCache *offset_cache,
+ Atom key)
+{
+ Xi18nAtomOffsetPair *data = offset_cache->data;
+ size_t i;
+
+ for (i = 0; i < offset_cache->size; ++i)
+ {
+ if (data[i].key == key)
+ {
+ return data[i].offset;
+ }
+ }
+
+ return 0;
+}
+
+void _Xi18nSetPropertyOffset(Xi18nOffsetCache *offset_cache, Atom key,
+ unsigned long offset)
+{
+ Xi18nAtomOffsetPair *data = offset_cache->data;
+ size_t i;
+
+ for (i = 0; i < offset_cache->size; ++i)
+ {
+ if (data[i].key == key)
+ {
+ data[i].offset = offset;
+ return;
+ }
+ }
+
+ if (++offset_cache->size > offset_cache->capacity)
+ {
+ offset_cache->capacity *= OFFSET_CACHE_GROWTH_FACTOR;
+ data = (Xi18nAtomOffsetPair *)realloc(data,
+ offset_cache->capacity * sizeof(Xi18nAtomOffsetPair));
+ offset_cache->data = data;
+ }
+
+ data[i].key = key;
+ data[i].offset = offset;
+}
+
diff --git a/util/IMdkit/i18nUtil.c b/util/IMdkit/i18nUtil.c
index c07de48..e04e290 100644
--- a/util/IMdkit/i18nUtil.c
+++ b/util/IMdkit/i18nUtil.c
@@ -36,6 +36,7 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "XimFunc.h"
Xi18nClient *_Xi18nFindClient (Xi18n, CARD16);
+void _Xi18nInitOffsetCache(Xi18nOffsetCache *);
int
_Xi18nNeedSwap (Xi18n i18n_core, CARD16 connect_id)
@@ -70,7 +71,7 @@ Xi18nClient *_Xi18nNewClient(Xi18n i18n_core)
client->sync = False;
client->byte_order = '?'; /* initial value */
memset (&client->pending, 0, sizeof (XIMPending *));
- client->property_offset = 0;
+ _Xi18nInitOffsetCache(&client->offset_cache);
client->next = i18n_core->address.clients;
i18n_core->address.clients = client;
diff --git a/util/IMdkit/i18nX.c b/util/IMdkit/i18nX.c
index 0a54058..98e1bcc 100644
--- a/util/IMdkit/i18nX.c
+++ b/util/IMdkit/i18nX.c
@@ -29,6 +29,7 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
******************************************************************/
+#include <stddef.h>
#include <limits.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
@@ -41,6 +42,8 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
extern Xi18nClient *_Xi18nFindClient(Xi18n, CARD16);
extern Xi18nClient *_Xi18nNewClient(Xi18n);
extern void _Xi18nDeleteClient(Xi18n, CARD16);
+extern unsigned long _Xi18nLookupPropertyOffset(Xi18nOffsetCache *, Atom);
+extern void _Xi18nSetPropertyOffset(Xi18nOffsetCache *, Atom, unsigned long);
static Bool WaitXConnectMessage(Display*, Window,
XEvent*, XPointer);
static Bool WaitXIMProtocol(Display*, Window, XEvent*, XPointer);
@@ -129,7 +132,6 @@ static unsigned char *ReadXIMMessage (XIMS ims,
else if (ev->format == 32) {
/* ClientMessage and WindowProperty */
unsigned long length = (unsigned long) ev->data.l[0];
- unsigned long get_length;
Atom atom = (Atom) ev->data.l[1];
int return_code;
Atom actual_type_ret;
@@ -137,21 +139,28 @@ static unsigned char *ReadXIMMessage (XIMS ims,
unsigned long bytes_after_ret;
unsigned char *prop;
unsigned long nitems;
-
- /* Round up length to next 4 byte value. */
- get_length = length + 3;
- if (get_length > LONG_MAX)
- get_length = LONG_MAX;
- get_length /= 4;
- if (get_length == 0) {
- fprintf(stderr, "%s: invalid length 0\n", __func__);
+ Xi18nOffsetCache *offset_cache = &client->offset_cache;
+ unsigned long offset;
+ unsigned long end;
+ unsigned long long_begin;
+ unsigned long long_end;
+
+ if (length == 0) {
+ fprintf (stderr, "%s: invalid length 0\n", __func__);
return NULL;
}
+
+ offset = _Xi18nLookupPropertyOffset (offset_cache, atom);
+ end = offset + length;
+
+ /* The property data is retrieved in 32-bit chunks */
+ long_begin = offset / 4;
+ long_end = (end + 3) / 4;
return_code = XGetWindowProperty (i18n_core->address.dpy,
x_client->accept_win,
atom,
- client->property_offset / 4,
- get_length,
+ long_begin,
+ long_end - long_begin,
True,
AnyPropertyType,
&actual_type_ret,
@@ -162,32 +171,22 @@ static unsigned char *ReadXIMMessage (XIMS ims,
if (return_code != Success || actual_format_ret == 0 || nitems == 0) {
if (return_code == Success)
XFree (prop);
- client->property_offset = 0;
+ fprintf (stderr,
+ "(XIM-IMdkit) ERROR: XGetWindowProperty failed.\n"
+ "Protocol data is likely to be inconsistent.\n");
+ _Xi18nSetPropertyOffset (offset_cache, atom, 0);
return (unsigned char *) NULL;
}
/* Update the offset to read next time as needed */
if (bytes_after_ret > 0)
- client->property_offset += length;
+ _Xi18nSetPropertyOffset (offset_cache, atom, offset + length);
else
- client->property_offset = 0;
- switch (actual_format_ret) {
- case 8:
- case 16:
- case 32:
- length = nitems * actual_format_ret / 8;
- break;
- default:
- fprintf(stderr, "%s: unknown property return format: %d\n",
- __func__, actual_format_ret);
- XFree(prop);
- client->property_offset = 0;
- return NULL;
- }
+ _Xi18nSetPropertyOffset (offset_cache, atom, 0);
/* if hit, it might be an error */
if ((p = (unsigned char *) malloc (length)) == NULL)
return (unsigned char *) NULL;
- memmove (p, prop, length);
+ memcpy (p, prop + (offset % 4), length);
XFree (prop);
}
return (unsigned char *) p;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment