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