imTrX.c revision b4ee4795
1/*
2 * Copyright 1992 Sun Microsystems, Inc.  All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23/******************************************************************
24
25           Copyright 1992, 1993, 1994 by FUJITSU LIMITED
26
27Permission to use, copy, modify, distribute, and sell this software
28and its documentation for any purpose is hereby granted without fee,
29provided that the above copyright notice appear in all copies and
30that both that copyright notice and this permission notice appear
31in supporting documentation, and that the name of FUJITSU LIMITED
32not be used in advertising or publicity pertaining to distribution
33of the software without specific, written prior permission.
34FUJITSU LIMITED makes no representations about the suitability of
35this software for any purpose.
36It is provided "as is" without express or implied warranty.
37
38FUJITSU LIMITED DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
39INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
40EVENT SHALL FUJITSU LIMITED BE LIABLE FOR ANY SPECIAL, INDIRECT OR
41CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
42USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
43OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
44PERFORMANCE OF THIS SOFTWARE.
45
46  Author: Hideki Hiura (hhiura@Sun.COM) Sun Microsystems, Inc.
47          Takashi Fujiwara     FUJITSU LIMITED
48                               fujiwara@a80.tech.yk.fujitsu.co.jp
49
50******************************************************************/
51
52#ifdef HAVE_CONFIG_H
53#include <config.h>
54#endif
55#include <string.h>
56#include <X11/Xatom.h>
57#define NEED_EVENTS
58#include "Xlibint.h"
59#include "Xlcint.h"
60#include "Ximint.h"
61#include "XimTrInt.h"
62#include "XimTrX.h"
63
64Private Bool
65_XimXRegisterDispatcher(
66    Xim			 im,
67    Bool		 (*callback)(
68				     Xim, INT16, XPointer, XPointer
69				     ),
70    XPointer		 call_data)
71{
72    XIntrCallbackPtr	 rec;
73    XSpecRec		*spec = (XSpecRec *)im->private.proto.spec;
74
75    if (!(rec = (XIntrCallbackPtr)Xmalloc(sizeof(XIntrCallbackRec))))
76        return False;
77
78    rec->func       = callback;
79    rec->call_data  = call_data;
80    rec->next       = spec->intr_cb;
81    spec->intr_cb   = rec;
82    return True;
83}
84
85Private void
86_XimXFreeIntrCallback(
87    Xim			 im)
88{
89    XSpecRec		*spec = (XSpecRec *)im->private.proto.spec;
90    register XIntrCallbackPtr rec, next;
91
92    for (rec = spec->intr_cb; rec;) {
93	next = rec->next;
94	Xfree(rec);
95	rec = next;
96    }
97    return;
98}
99
100Private Bool
101_XimXCallDispatcher(Xim im, INT16 len, XPointer data)
102{
103    register XIntrCallbackRec	*rec;
104    XSpecRec		*spec = (XSpecRec *)im->private.proto.spec;
105
106    for (rec = spec->intr_cb; rec; rec = rec->next) {
107	if ((*rec->func)(im, len, data, rec->call_data))
108	    return True;
109    }
110    return False;
111}
112
113Private Bool
114_XimXFilterWaitEvent(
115    Display	*d,
116    Window	 w,
117    XEvent	*ev,
118    XPointer	 arg)
119{
120    Xim		 im = (Xim)arg;
121    XSpecRec	*spec = (XSpecRec *)im->private.proto.spec;
122    Bool ret;
123
124    spec->ev = (XPointer)ev;
125    ret = _XimFilterWaitEvent(im);
126
127    /*
128     * If ev is a pointer to a stack variable, there could be
129     * a coredump later on if the pointer is dereferenced.
130     * Therefore, reset to NULL to force reinitialization in
131     * _XimXRead().
132     *
133     * Keep in mind _XimXRead may be called again when the stack
134     * is very different.
135     */
136     spec->ev = (XPointer)NULL;
137
138     return ret;
139}
140
141Private Bool
142_CheckConnect(
143    Display	*display,
144    XEvent	*event,
145    XPointer	 xim)
146{
147    Xim		 im = (Xim)xim;
148    XSpecRec	*spec = (XSpecRec *)im->private.proto.spec;
149
150    if ((event->type == ClientMessage)
151     && (event->xclient.message_type == spec->imconnectid)) {
152	return True;
153    }
154    return False;
155}
156
157Private Bool
158_XimXConnect(Xim im)
159{
160    XEvent	 event;
161    XSpecRec	*spec = (XSpecRec *)im->private.proto.spec;
162    CARD32	 major_code;
163    CARD32	 minor_code;
164
165    if (!(spec->lib_connect_wid = XCreateSimpleWindow(im->core.display,
166		DefaultRootWindow(im->core.display), 0, 0, 1, 1, 1, 0, 0))) {
167	return False;
168    }
169
170    event.xclient.type         = ClientMessage;
171    event.xclient.display      = im->core.display;
172    event.xclient.window       = im->private.proto.im_window;
173    event.xclient.message_type = spec->imconnectid;
174    event.xclient.format       = 32;
175    event.xclient.data.l[0]    = (CARD32)spec->lib_connect_wid;
176    event.xclient.data.l[1]    = spec->major_code;
177    event.xclient.data.l[2]    = spec->minor_code;
178    event.xclient.data.l[3]    = 0;
179    event.xclient.data.l[4]    = 0;
180
181    if(event.xclient.data.l[1] == 1 || event.xclient.data.l[1] == 2) {
182	XWindowAttributes	 atr;
183	long			 event_mask;
184
185	XGetWindowAttributes(im->core.display, spec->lib_connect_wid, &atr);
186	event_mask = atr.your_event_mask | PropertyChangeMask;
187	XSelectInput(im->core.display, spec->lib_connect_wid, event_mask);
188	_XRegisterFilterByType(im->core.display, spec->lib_connect_wid,
189			PropertyNotify, PropertyNotify,
190			 _XimXFilterWaitEvent, (XPointer)im);
191    }
192
193    XSendEvent(im->core.display, im->private.proto.im_window,
194		 False, NoEventMask, &event);
195    XFlush(im->core.display);
196
197    for (;;) {
198	XIfEvent(im->core.display, &event, _CheckConnect, (XPointer)im);
199	if (event.xclient.type != ClientMessage) {
200	    return False;
201	}
202	if (event.xclient.message_type == spec->imconnectid)
203	    break;
204    }
205
206    spec->ims_connect_wid = (Window)event.xclient.data.l[0];
207    major_code = (CARD32)event.xclient.data.l[1];
208    minor_code = (CARD32)event.xclient.data.l[2];
209
210    if (((major_code == 0) && (minor_code <= 2)) ||
211	((major_code == 1) && (minor_code == 0)) ||
212	((major_code == 2) && (minor_code <= 1))) {
213	spec->major_code = major_code;
214	spec->minor_code = minor_code;
215    }
216    if (((major_code == 0) && (minor_code == 2)) ||
217	((major_code == 2) && (minor_code == 1))) {
218	spec->BoundarySize = (CARD32)event.xclient.data.l[3];
219    }
220
221    /* ClientMessage Event Filter */
222    _XRegisterFilterByType(im->core.display, spec->lib_connect_wid,
223			ClientMessage, ClientMessage,
224			 _XimXFilterWaitEvent, (XPointer)im);
225    return True;
226}
227
228Private Bool
229_XimXShutdown(Xim im)
230{
231    XSpecRec	*spec = (XSpecRec *)im->private.proto.spec;
232
233    if (!spec)
234	return True;
235
236    /* ClientMessage Event Filter */
237    _XUnregisterFilter(im->core.display,
238	    ((XSpecRec *)im->private.proto.spec)->lib_connect_wid,
239	    _XimXFilterWaitEvent, (XPointer)im);
240    XDestroyWindow(im->core.display,
241	    ((XSpecRec *)im->private.proto.spec)->lib_connect_wid);
242    _XimXFreeIntrCallback(im);
243    Xfree(spec);
244    im->private.proto.spec = 0;
245    return True;
246}
247
248Private char *
249_NewAtom(
250    char	*atomName)
251{
252    static int	 sequence = 0;
253
254    (void)sprintf(atomName, "_client%d", sequence);
255    sequence = ((sequence < 20) ? sequence + 1 : 0);
256    return atomName;
257}
258
259Private Bool
260_XimXWrite(Xim im, INT16 len, XPointer data)
261{
262    Atom	 atom;
263    char	 atomName[16];
264    XSpecRec	*spec = (XSpecRec *)im->private.proto.spec;
265    XEvent	 event;
266    CARD8	*p;
267    CARD32	 major_code = spec->major_code;
268    CARD32	 minor_code = spec->minor_code;
269    int		 BoundSize;
270
271    bzero(&event,sizeof(XEvent));
272    event.xclient.type         = ClientMessage;
273    event.xclient.display      = im->core.display;
274    event.xclient.window       = spec->ims_connect_wid;
275    if(major_code == 1 && minor_code == 0) {
276        BoundSize = 0;
277    } else if((major_code == 0 && minor_code == 2) ||
278              (major_code == 2 && minor_code == 1)) {
279        BoundSize = spec->BoundarySize;
280    } else if(major_code == 0 && minor_code == 1) {
281        BoundSize = len;
282    } else {
283        BoundSize = XIM_CM_DATA_SIZE;
284    }
285    if (len > BoundSize) {
286	event.xclient.message_type = spec->improtocolid;
287	atom = XInternAtom(im->core.display, _NewAtom(atomName), False);
288	XChangeProperty(im->core.display, spec->ims_connect_wid,
289			atom, XA_STRING, 8, PropModeAppend,
290			(unsigned char *)data, len);
291	if(major_code == 0) {
292	    event.xclient.format = 32;
293	    event.xclient.data.l[0] = (long)len;
294	    event.xclient.data.l[1] = (long)atom;
295	    XSendEvent(im->core.display, spec->ims_connect_wid,
296					False, NoEventMask, &event);
297	}
298    } else {
299	int		 length;
300
301	event.xclient.format = 8;
302	for(length = 0 ; length < len ; length += XIM_CM_DATA_SIZE) {
303	    p = (CARD8 *)&event.xclient.data.b[0];
304	    if((length + XIM_CM_DATA_SIZE) >= len) {
305		event.xclient.message_type = spec->improtocolid;
306		bzero(p, XIM_CM_DATA_SIZE);
307		memcpy((char *)p, (data + length), (len - length));
308	    } else {
309		event.xclient.message_type = spec->immoredataid;
310		memcpy((char *)p, (data + length), XIM_CM_DATA_SIZE);
311	    }
312	    XSendEvent(im->core.display, spec->ims_connect_wid,
313					False, NoEventMask, &event);
314	}
315    }
316
317    return True;
318}
319
320Private Bool
321_XimXGetReadData(
322    Xim			  im,
323    char		 *buf,
324    int			  buf_len,
325    int			 *ret_len,
326    XEvent		 *event)
327{
328    char		 *data;
329    int			  len;
330
331    char		  tmp_buf[XIM_CM_DATA_SIZE];
332    XSpecRec		 *spec = (XSpecRec *)im->private.proto.spec;
333    unsigned long	  length;
334    Atom		  prop;
335    int			  return_code;
336    Atom		  type_ret;
337    int			  format_ret;
338    unsigned long	  nitems;
339    unsigned long	  bytes_after_ret;
340    unsigned char	 *prop_ret;
341
342    if ((event->type == ClientMessage) &&
343        !((event->xclient.message_type == spec->improtocolid) ||
344          (event->xclient.message_type == spec->immoredataid))) {
345         /* This event has nothing to do with us,
346          * FIXME should not have gotten here then...
347          */
348         return False;
349    } else if ((event->type == ClientMessage) && (event->xclient.format == 8)) {
350        data = event->xclient.data.b;
351	if (buf_len >= XIM_CM_DATA_SIZE) {
352	    (void)memcpy(buf, data, XIM_CM_DATA_SIZE);
353	    *ret_len = XIM_CM_DATA_SIZE;
354	} else {
355	    (void)memcpy(buf, data, buf_len);
356	    len = XIM_CM_DATA_SIZE - buf_len;
357	    (void)memcpy(tmp_buf, &data[buf_len], len);
358	    bzero(data, XIM_CM_DATA_SIZE);
359	    (void)memcpy(data, tmp_buf, len);
360	    XPutBackEvent(im->core.display, event);
361	    *ret_len = buf_len;
362	}
363    } else if ((event->type == ClientMessage)
364				&& (event->xclient.format == 32)) {
365	length = (unsigned long)event->xclient.data.l[0];
366	prop   = (Atom)event->xclient.data.l[1];
367	return_code = XGetWindowProperty(im->core.display,
368		spec->lib_connect_wid, prop, 0L,
369		(long)((length + 3)/ 4), True, AnyPropertyType,
370		&type_ret, &format_ret, &nitems, &bytes_after_ret, &prop_ret);
371	if (return_code != Success || format_ret == 0 || nitems == 0) {
372	    if (return_code == Success)
373		XFree(prop_ret);
374	    return False;
375	}
376	if (buf_len >= length) {
377	    (void)memcpy(buf, prop_ret, (int)nitems);
378	    *ret_len  = (int)nitems;
379	    if (bytes_after_ret > 0) {
380		XFree(prop_ret);
381	        XGetWindowProperty(im->core.display,
382		    spec->lib_connect_wid, prop, 0L,
383		    ((length + bytes_after_ret + 3)/ 4), True, AnyPropertyType,
384		    &type_ret, &format_ret, &nitems, &bytes_after_ret,
385		    &prop_ret);
386	        XChangeProperty(im->core.display, spec->lib_connect_wid, prop,
387		    XA_STRING, 8, PropModePrepend, &prop_ret[length],
388		    (nitems - length));
389	    }
390	} else {
391	    (void)memcpy(buf, prop_ret, buf_len);
392	    *ret_len  = buf_len;
393	    len = nitems - buf_len;
394
395	    if (bytes_after_ret > 0) {
396		XFree(prop_ret);
397	        XGetWindowProperty(im->core.display,
398		spec->lib_connect_wid, prop, 0L,
399		((length + bytes_after_ret + 3)/ 4), True, AnyPropertyType,
400		&type_ret, &format_ret, &nitems, &bytes_after_ret, &prop_ret);
401	    }
402	    XChangeProperty(im->core.display, spec->lib_connect_wid, prop,
403		    XA_STRING, 8, PropModePrepend, &prop_ret[buf_len], len);
404	    event->xclient.data.l[0] = (long)len;
405	    event->xclient.data.l[1] = (long)prop;
406	    XPutBackEvent(im->core.display, event);
407	}
408	XFree(prop_ret);
409    } else if (event->type == PropertyNotify) {
410	prop = event->xproperty.atom;
411	return_code = XGetWindowProperty(im->core.display,
412		spec->lib_connect_wid, prop, 0L,
413		1000000L, True, AnyPropertyType,
414		&type_ret, &format_ret, &nitems, &bytes_after_ret, &prop_ret);
415	if (return_code != Success || format_ret == 0 || nitems == 0) {
416	    if (return_code == Success)
417		XFree(prop_ret);
418	    return False;
419	}
420	if (buf_len >= nitems) {
421	    (void)memcpy(buf, prop_ret, (int)nitems);
422	    *ret_len  = (int)nitems;
423	} else {
424	    (void)memcpy(buf, prop_ret, buf_len);
425	    *ret_len  = buf_len;
426	    len = nitems - buf_len;
427	    XChangeProperty(im->core.display, spec->lib_connect_wid, prop,
428		XA_STRING, 8, PropModePrepend, &prop_ret[buf_len], len);
429	}
430	XFree(prop_ret);
431    }
432    return True;
433}
434
435Private Bool
436_CheckCMEvent(
437    Display	*display,
438    XEvent	*event,
439    XPointer	 xim)
440{
441    Xim		 im = (Xim)xim;
442    XSpecRec	*spec = (XSpecRec *)im->private.proto.spec;
443    CARD32	 major_code = spec->major_code;
444
445    if ((event->type == ClientMessage)
446     &&((event->xclient.message_type == spec->improtocolid) ||
447        (event->xclient.message_type == spec->immoredataid)))
448	return True;
449    if((major_code == 1 || major_code == 2) &&
450       (event->type == PropertyNotify) &&
451       (event->xproperty.state == PropertyNewValue))
452	return True;
453    return False;
454}
455
456Private Bool
457_XimXRead(Xim im, XPointer recv_buf, int buf_len, int *ret_len)
458{
459    XEvent	*ev;
460    XEvent	 event;
461    int		 len = 0;
462    XSpecRec	*spec = (XSpecRec *)im->private.proto.spec;
463    XPointer	  arg = spec->ev;
464
465    if (!arg) {
466	bzero(&event, sizeof(XEvent));
467	ev = &event;
468	XIfEvent(im->core.display, ev, _CheckCMEvent, (XPointer)im);
469    } else {
470	ev = (XEvent *)arg;
471	spec->ev = (XPointer)NULL;
472    }
473    if (!(_XimXGetReadData(im, recv_buf, buf_len, &len, ev)))
474	return False;
475    *ret_len = len;
476    return True;
477}
478
479Private void
480_XimXFlush(Xim im)
481{
482    XFlush(im->core.display);
483    return;
484}
485
486Public Bool
487_XimXConf(Xim im, char *address)
488{
489    XSpecRec	*spec;
490
491    if (!(spec = (XSpecRec *)Xmalloc(sizeof(XSpecRec))))
492	return False;
493    bzero(spec, sizeof(XSpecRec));
494
495    spec->improtocolid = XInternAtom(im->core.display, _XIM_PROTOCOL, False);
496    spec->imconnectid  = XInternAtom(im->core.display, _XIM_XCONNECT, False);
497    spec->immoredataid = XInternAtom(im->core.display, _XIM_MOREDATA, False);
498    spec->major_code = MAJOR_TRANSPORT_VERSION;
499    spec->minor_code = MINOR_TRANSPORT_VERSION;
500
501    im->private.proto.spec     = (XPointer)spec;
502    im->private.proto.connect  = _XimXConnect;
503    im->private.proto.shutdown = _XimXShutdown;
504    im->private.proto.write    = _XimXWrite;
505    im->private.proto.read     = _XimXRead;
506    im->private.proto.flush    = _XimXFlush;
507    im->private.proto.register_dispatcher  = _XimXRegisterDispatcher;
508    im->private.proto.call_dispatcher = _XimXCallDispatcher;
509
510    return True;
511}
512