imTrX.c revision 57f47464
1/*
2 * Copyright 1992 Oracle and/or its affiliates. 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#include "Xlibint.h"
58#include "Xlcint.h"
59#include "Ximint.h"
60#include "XimTrInt.h"
61#include "XimTrX.h"
62
63Private Bool
64_XimXRegisterDispatcher(
65    Xim			 im,
66    Bool		 (*callback)(
67				     Xim, INT16, XPointer, XPointer
68				     ),
69    XPointer		 call_data)
70{
71    XIntrCallbackPtr	 rec;
72    XSpecRec		*spec = (XSpecRec *)im->private.proto.spec;
73
74    if (!(rec = (XIntrCallbackPtr)Xmalloc(sizeof(XIntrCallbackRec))))
75        return False;
76
77    rec->func       = callback;
78    rec->call_data  = call_data;
79    rec->next       = spec->intr_cb;
80    spec->intr_cb   = rec;
81    return True;
82}
83
84Private void
85_XimXFreeIntrCallback(
86    Xim			 im)
87{
88    XSpecRec		*spec = (XSpecRec *)im->private.proto.spec;
89    register XIntrCallbackPtr rec, next;
90
91    for (rec = spec->intr_cb; rec;) {
92	next = rec->next;
93	Xfree(rec);
94	rec = next;
95    }
96    return;
97}
98
99Private Bool
100_XimXCallDispatcher(Xim im, INT16 len, XPointer data)
101{
102    register XIntrCallbackRec	*rec;
103    XSpecRec		*spec = (XSpecRec *)im->private.proto.spec;
104
105    for (rec = spec->intr_cb; rec; rec = rec->next) {
106	if ((*rec->func)(im, len, data, rec->call_data))
107	    return True;
108    }
109    return False;
110}
111
112Private Bool
113_XimXFilterWaitEvent(
114    Display	*d,
115    Window	 w,
116    XEvent	*ev,
117    XPointer	 arg)
118{
119    Xim		 im = (Xim)arg;
120    XSpecRec	*spec = (XSpecRec *)im->private.proto.spec;
121    Bool ret;
122
123    spec->ev = (XPointer)ev;
124    ret = _XimFilterWaitEvent(im);
125
126    /*
127     * If ev is a pointer to a stack variable, there could be
128     * a coredump later on if the pointer is dereferenced.
129     * Therefore, reset to NULL to force reinitialization in
130     * _XimXRead().
131     *
132     * Keep in mind _XimXRead may be called again when the stack
133     * is very different.
134     */
135     spec->ev = (XPointer)NULL;
136
137     return ret;
138}
139
140Private Bool
141_CheckConnect(
142    Display	*display,
143    XEvent	*event,
144    XPointer	 xim)
145{
146    Xim		 im = (Xim)xim;
147    XSpecRec	*spec = (XSpecRec *)im->private.proto.spec;
148
149    if ((event->type == ClientMessage)
150     && (event->xclient.message_type == spec->imconnectid)) {
151	return True;
152    }
153    return False;
154}
155
156Private Bool
157_XimXConnect(Xim im)
158{
159    XEvent	 event;
160    XSpecRec	*spec = (XSpecRec *)im->private.proto.spec;
161    CARD32	 major_code;
162    CARD32	 minor_code;
163
164    if (!(spec->lib_connect_wid = XCreateSimpleWindow(im->core.display,
165		DefaultRootWindow(im->core.display), 0, 0, 1, 1, 1, 0, 0))) {
166	return False;
167    }
168
169    event.xclient.type         = ClientMessage;
170    event.xclient.display      = im->core.display;
171    event.xclient.window       = im->private.proto.im_window;
172    event.xclient.message_type = spec->imconnectid;
173    event.xclient.format       = 32;
174    event.xclient.data.l[0]    = (CARD32)spec->lib_connect_wid;
175    event.xclient.data.l[1]    = spec->major_code;
176    event.xclient.data.l[2]    = spec->minor_code;
177    event.xclient.data.l[3]    = 0;
178    event.xclient.data.l[4]    = 0;
179
180    if(event.xclient.data.l[1] == 1 || event.xclient.data.l[1] == 2) {
181	XWindowAttributes	 atr;
182	long			 event_mask;
183
184	XGetWindowAttributes(im->core.display, spec->lib_connect_wid, &atr);
185	event_mask = atr.your_event_mask | PropertyChangeMask;
186	XSelectInput(im->core.display, spec->lib_connect_wid, event_mask);
187	_XRegisterFilterByType(im->core.display, spec->lib_connect_wid,
188			PropertyNotify, PropertyNotify,
189			 _XimXFilterWaitEvent, (XPointer)im);
190    }
191
192    XSendEvent(im->core.display, im->private.proto.im_window,
193		 False, NoEventMask, &event);
194    XFlush(im->core.display);
195
196    for (;;) {
197	XIfEvent(im->core.display, &event, _CheckConnect, (XPointer)im);
198	if (event.xclient.type != ClientMessage) {
199	    return False;
200	}
201	if (event.xclient.message_type == spec->imconnectid)
202	    break;
203    }
204
205    spec->ims_connect_wid = (Window)event.xclient.data.l[0];
206    major_code = (CARD32)event.xclient.data.l[1];
207    minor_code = (CARD32)event.xclient.data.l[2];
208
209    if (((major_code == 0) && (minor_code <= 2)) ||
210	((major_code == 1) && (minor_code == 0)) ||
211	((major_code == 2) && (minor_code <= 1))) {
212	spec->major_code = major_code;
213	spec->minor_code = minor_code;
214    }
215    if (((major_code == 0) && (minor_code == 2)) ||
216	((major_code == 2) && (minor_code == 1))) {
217	spec->BoundarySize = (CARD32)event.xclient.data.l[3];
218    }
219
220    /* ClientMessage Event Filter */
221    _XRegisterFilterByType(im->core.display, spec->lib_connect_wid,
222			ClientMessage, ClientMessage,
223			 _XimXFilterWaitEvent, (XPointer)im);
224    return True;
225}
226
227Private Bool
228_XimXShutdown(Xim im)
229{
230    XSpecRec	*spec = (XSpecRec *)im->private.proto.spec;
231
232    if (!spec)
233	return True;
234
235    /* ClientMessage Event Filter */
236    _XUnregisterFilter(im->core.display,
237	    ((XSpecRec *)im->private.proto.spec)->lib_connect_wid,
238	    _XimXFilterWaitEvent, (XPointer)im);
239    XDestroyWindow(im->core.display,
240	    ((XSpecRec *)im->private.proto.spec)->lib_connect_wid);
241    _XimXFreeIntrCallback(im);
242    Xfree(spec);
243    im->private.proto.spec = 0;
244    return True;
245}
246
247Private char *
248_NewAtom(
249    char	*atomName)
250{
251    static int	 sequence = 0;
252
253    (void)sprintf(atomName, "_client%d", sequence);
254    sequence = ((sequence < 20) ? sequence + 1 : 0);
255    return atomName;
256}
257
258Private Bool
259_XimXWrite(Xim im, INT16 len, XPointer data)
260{
261    Atom	 atom;
262    char	 atomName[16];
263    XSpecRec	*spec = (XSpecRec *)im->private.proto.spec;
264    XEvent	 event;
265    CARD8	*p;
266    CARD32	 major_code = spec->major_code;
267    CARD32	 minor_code = spec->minor_code;
268    int		 BoundSize;
269
270    bzero(&event,sizeof(XEvent));
271    event.xclient.type         = ClientMessage;
272    event.xclient.display      = im->core.display;
273    event.xclient.window       = spec->ims_connect_wid;
274    if(major_code == 1 && minor_code == 0) {
275        BoundSize = 0;
276    } else if((major_code == 0 && minor_code == 2) ||
277              (major_code == 2 && minor_code == 1)) {
278        BoundSize = spec->BoundarySize;
279    } else if(major_code == 0 && minor_code == 1) {
280        BoundSize = len;
281    } else {
282        BoundSize = XIM_CM_DATA_SIZE;
283    }
284    if (len > BoundSize) {
285	event.xclient.message_type = spec->improtocolid;
286	atom = XInternAtom(im->core.display, _NewAtom(atomName), False);
287	XChangeProperty(im->core.display, spec->ims_connect_wid,
288			atom, XA_STRING, 8, PropModeAppend,
289			(unsigned char *)data, len);
290	if(major_code == 0) {
291	    event.xclient.format = 32;
292	    event.xclient.data.l[0] = (long)len;
293	    event.xclient.data.l[1] = (long)atom;
294	    XSendEvent(im->core.display, spec->ims_connect_wid,
295					False, NoEventMask, &event);
296	}
297    } else {
298	int		 length;
299
300	event.xclient.format = 8;
301	for(length = 0 ; length < len ; length += XIM_CM_DATA_SIZE) {
302	    p = (CARD8 *)&event.xclient.data.b[0];
303	    if((length + XIM_CM_DATA_SIZE) >= len) {
304		event.xclient.message_type = spec->improtocolid;
305		bzero(p, XIM_CM_DATA_SIZE);
306		memcpy((char *)p, (data + length), (len - length));
307	    } else {
308		event.xclient.message_type = spec->immoredataid;
309		memcpy((char *)p, (data + length), XIM_CM_DATA_SIZE);
310	    }
311	    XSendEvent(im->core.display, spec->ims_connect_wid,
312					False, NoEventMask, &event);
313	}
314    }
315
316    return True;
317}
318
319Private Bool
320_XimXGetReadData(
321    Xim			  im,
322    char		 *buf,
323    int			  buf_len,
324    int			 *ret_len,
325    XEvent		 *event)
326{
327    char		 *data;
328    int			  len;
329
330    char		  tmp_buf[XIM_CM_DATA_SIZE];
331    XSpecRec		 *spec = (XSpecRec *)im->private.proto.spec;
332    unsigned long	  length;
333    Atom		  prop;
334    int			  return_code;
335    Atom		  type_ret;
336    int			  format_ret;
337    unsigned long	  nitems;
338    unsigned long	  bytes_after_ret;
339    unsigned char	 *prop_ret;
340
341    if ((event->type == ClientMessage) &&
342        !((event->xclient.message_type == spec->improtocolid) ||
343          (event->xclient.message_type == spec->immoredataid))) {
344         /* This event has nothing to do with us,
345          * FIXME should not have gotten here then...
346          */
347         return False;
348    } else if ((event->type == ClientMessage) && (event->xclient.format == 8)) {
349        data = event->xclient.data.b;
350	if (buf_len >= XIM_CM_DATA_SIZE) {
351	    (void)memcpy(buf, data, XIM_CM_DATA_SIZE);
352	    *ret_len = XIM_CM_DATA_SIZE;
353	} else {
354	    (void)memcpy(buf, data, buf_len);
355	    len = XIM_CM_DATA_SIZE - buf_len;
356	    (void)memcpy(tmp_buf, &data[buf_len], len);
357	    bzero(data, XIM_CM_DATA_SIZE);
358	    (void)memcpy(data, tmp_buf, len);
359	    XPutBackEvent(im->core.display, event);
360	    *ret_len = buf_len;
361	}
362    } else if ((event->type == ClientMessage)
363				&& (event->xclient.format == 32)) {
364	length = (unsigned long)event->xclient.data.l[0];
365	prop   = (Atom)event->xclient.data.l[1];
366	return_code = XGetWindowProperty(im->core.display,
367		spec->lib_connect_wid, prop, 0L,
368		(long)((length + 3)/ 4), True, AnyPropertyType,
369		&type_ret, &format_ret, &nitems, &bytes_after_ret, &prop_ret);
370	if (return_code != Success || format_ret == 0 || nitems == 0) {
371	    if (return_code == Success)
372		XFree(prop_ret);
373	    return False;
374	}
375	if (buf_len >= length) {
376	    (void)memcpy(buf, prop_ret, (int)nitems);
377	    *ret_len  = (int)nitems;
378	    if (bytes_after_ret > 0) {
379		XFree(prop_ret);
380		if (XGetWindowProperty(im->core.display,
381				       spec->lib_connect_wid, prop, 0L,
382				       ((length + bytes_after_ret + 3)/ 4),
383				       True, AnyPropertyType,
384				       &type_ret, &format_ret, &nitems,
385				       &bytes_after_ret,
386				       &prop_ret) == Success) {
387		    XChangeProperty(im->core.display, spec->lib_connect_wid, prop,
388				    XA_STRING, 8, PropModePrepend, &prop_ret[length],
389				    (nitems - length));
390		} else {
391		    return False;
392		}
393	    }
394	} else {
395	    (void)memcpy(buf, prop_ret, buf_len);
396	    *ret_len  = buf_len;
397	    len = nitems - buf_len;
398
399	    if (bytes_after_ret > 0) {
400		XFree(prop_ret);
401		if (XGetWindowProperty(im->core.display,
402				       spec->lib_connect_wid, prop, 0L,
403				       ((length + bytes_after_ret + 3)/ 4),
404				       True, AnyPropertyType,
405				       &type_ret, &format_ret, &nitems,
406				       &bytes_after_ret, &prop_ret) != Success) {
407		    return False;
408		}
409	    }
410	    XChangeProperty(im->core.display, spec->lib_connect_wid, prop,
411		    XA_STRING, 8, PropModePrepend, &prop_ret[buf_len], len);
412	    event->xclient.data.l[0] = (long)len;
413	    event->xclient.data.l[1] = (long)prop;
414	    XPutBackEvent(im->core.display, event);
415	}
416	XFree(prop_ret);
417    } else if (event->type == PropertyNotify) {
418	prop = event->xproperty.atom;
419	return_code = XGetWindowProperty(im->core.display,
420		spec->lib_connect_wid, prop, 0L,
421		1000000L, True, AnyPropertyType,
422		&type_ret, &format_ret, &nitems, &bytes_after_ret, &prop_ret);
423	if (return_code != Success || format_ret == 0 || nitems == 0) {
424	    if (return_code == Success)
425		XFree(prop_ret);
426	    return False;
427	}
428	if (buf_len >= nitems) {
429	    (void)memcpy(buf, prop_ret, (int)nitems);
430	    *ret_len  = (int)nitems;
431	} else {
432	    (void)memcpy(buf, prop_ret, buf_len);
433	    *ret_len  = buf_len;
434	    len = nitems - buf_len;
435	    XChangeProperty(im->core.display, spec->lib_connect_wid, prop,
436		XA_STRING, 8, PropModePrepend, &prop_ret[buf_len], len);
437	}
438	XFree(prop_ret);
439    }
440    return True;
441}
442
443Private Bool
444_CheckCMEvent(
445    Display	*display,
446    XEvent	*event,
447    XPointer	 xim)
448{
449    Xim		 im = (Xim)xim;
450    XSpecRec	*spec = (XSpecRec *)im->private.proto.spec;
451    CARD32	 major_code = spec->major_code;
452
453    if ((event->type == ClientMessage)
454     &&((event->xclient.message_type == spec->improtocolid) ||
455        (event->xclient.message_type == spec->immoredataid)))
456	return True;
457    if((major_code == 1 || major_code == 2) &&
458       (event->type == PropertyNotify) &&
459       (event->xproperty.state == PropertyNewValue))
460	return True;
461    return False;
462}
463
464Private Bool
465_XimXRead(Xim im, XPointer recv_buf, int buf_len, int *ret_len)
466{
467    XEvent	*ev;
468    XEvent	 event;
469    int		 len = 0;
470    XSpecRec	*spec = (XSpecRec *)im->private.proto.spec;
471    XPointer	  arg = spec->ev;
472
473    if (!arg) {
474	bzero(&event, sizeof(XEvent));
475	ev = &event;
476	XIfEvent(im->core.display, ev, _CheckCMEvent, (XPointer)im);
477    } else {
478	ev = (XEvent *)arg;
479	spec->ev = (XPointer)NULL;
480    }
481    if (!(_XimXGetReadData(im, recv_buf, buf_len, &len, ev)))
482	return False;
483    *ret_len = len;
484    return True;
485}
486
487Private void
488_XimXFlush(Xim im)
489{
490    XFlush(im->core.display);
491    return;
492}
493
494Public Bool
495_XimXConf(Xim im, char *address)
496{
497    XSpecRec	*spec;
498
499    if (!(spec = (XSpecRec *)Xmalloc(sizeof(XSpecRec))))
500	return False;
501    bzero(spec, sizeof(XSpecRec));
502
503    spec->improtocolid = XInternAtom(im->core.display, _XIM_PROTOCOL, False);
504    spec->imconnectid  = XInternAtom(im->core.display, _XIM_XCONNECT, False);
505    spec->immoredataid = XInternAtom(im->core.display, _XIM_MOREDATA, False);
506    spec->major_code = MAJOR_TRANSPORT_VERSION;
507    spec->minor_code = MINOR_TRANSPORT_VERSION;
508
509    im->private.proto.spec     = (XPointer)spec;
510    im->private.proto.connect  = _XimXConnect;
511    im->private.proto.shutdown = _XimXShutdown;
512    im->private.proto.write    = _XimXWrite;
513    im->private.proto.read     = _XimXRead;
514    im->private.proto.flush    = _XimXFlush;
515    im->private.proto.register_dispatcher  = _XimXRegisterDispatcher;
516    im->private.proto.call_dispatcher = _XimXCallDispatcher;
517
518    return True;
519}
520