imTrX.c revision e9fcaa8a
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	        XGetWindowProperty(im->core.display,
381		    spec->lib_connect_wid, prop, 0L,
382		    ((length + bytes_after_ret + 3)/ 4), True, AnyPropertyType,
383		    &type_ret, &format_ret, &nitems, &bytes_after_ret,
384		    &prop_ret);
385	        XChangeProperty(im->core.display, spec->lib_connect_wid, prop,
386		    XA_STRING, 8, PropModePrepend, &prop_ret[length],
387		    (nitems - length));
388	    }
389	} else {
390	    (void)memcpy(buf, prop_ret, buf_len);
391	    *ret_len  = buf_len;
392	    len = nitems - buf_len;
393
394	    if (bytes_after_ret > 0) {
395		XFree(prop_ret);
396	        XGetWindowProperty(im->core.display,
397		spec->lib_connect_wid, prop, 0L,
398		((length + bytes_after_ret + 3)/ 4), True, AnyPropertyType,
399		&type_ret, &format_ret, &nitems, &bytes_after_ret, &prop_ret);
400	    }
401	    XChangeProperty(im->core.display, spec->lib_connect_wid, prop,
402		    XA_STRING, 8, PropModePrepend, &prop_ret[buf_len], len);
403	    event->xclient.data.l[0] = (long)len;
404	    event->xclient.data.l[1] = (long)prop;
405	    XPutBackEvent(im->core.display, event);
406	}
407	XFree(prop_ret);
408    } else if (event->type == PropertyNotify) {
409	prop = event->xproperty.atom;
410	return_code = XGetWindowProperty(im->core.display,
411		spec->lib_connect_wid, prop, 0L,
412		1000000L, True, AnyPropertyType,
413		&type_ret, &format_ret, &nitems, &bytes_after_ret, &prop_ret);
414	if (return_code != Success || format_ret == 0 || nitems == 0) {
415	    if (return_code == Success)
416		XFree(prop_ret);
417	    return False;
418	}
419	if (buf_len >= nitems) {
420	    (void)memcpy(buf, prop_ret, (int)nitems);
421	    *ret_len  = (int)nitems;
422	} else {
423	    (void)memcpy(buf, prop_ret, buf_len);
424	    *ret_len  = buf_len;
425	    len = nitems - buf_len;
426	    XChangeProperty(im->core.display, spec->lib_connect_wid, prop,
427		XA_STRING, 8, PropModePrepend, &prop_ret[buf_len], len);
428	}
429	XFree(prop_ret);
430    }
431    return True;
432}
433
434Private Bool
435_CheckCMEvent(
436    Display	*display,
437    XEvent	*event,
438    XPointer	 xim)
439{
440    Xim		 im = (Xim)xim;
441    XSpecRec	*spec = (XSpecRec *)im->private.proto.spec;
442    CARD32	 major_code = spec->major_code;
443
444    if ((event->type == ClientMessage)
445     &&((event->xclient.message_type == spec->improtocolid) ||
446        (event->xclient.message_type == spec->immoredataid)))
447	return True;
448    if((major_code == 1 || major_code == 2) &&
449       (event->type == PropertyNotify) &&
450       (event->xproperty.state == PropertyNewValue))
451	return True;
452    return False;
453}
454
455Private Bool
456_XimXRead(Xim im, XPointer recv_buf, int buf_len, int *ret_len)
457{
458    XEvent	*ev;
459    XEvent	 event;
460    int		 len = 0;
461    XSpecRec	*spec = (XSpecRec *)im->private.proto.spec;
462    XPointer	  arg = spec->ev;
463
464    if (!arg) {
465	bzero(&event, sizeof(XEvent));
466	ev = &event;
467	XIfEvent(im->core.display, ev, _CheckCMEvent, (XPointer)im);
468    } else {
469	ev = (XEvent *)arg;
470	spec->ev = (XPointer)NULL;
471    }
472    if (!(_XimXGetReadData(im, recv_buf, buf_len, &len, ev)))
473	return False;
474    *ret_len = len;
475    return True;
476}
477
478Private void
479_XimXFlush(Xim im)
480{
481    XFlush(im->core.display);
482    return;
483}
484
485Public Bool
486_XimXConf(Xim im, char *address)
487{
488    XSpecRec	*spec;
489
490    if (!(spec = (XSpecRec *)Xmalloc(sizeof(XSpecRec))))
491	return False;
492    bzero(spec, sizeof(XSpecRec));
493
494    spec->improtocolid = XInternAtom(im->core.display, _XIM_PROTOCOL, False);
495    spec->imconnectid  = XInternAtom(im->core.display, _XIM_XCONNECT, False);
496    spec->immoredataid = XInternAtom(im->core.display, _XIM_MOREDATA, False);
497    spec->major_code = MAJOR_TRANSPORT_VERSION;
498    spec->minor_code = MINOR_TRANSPORT_VERSION;
499
500    im->private.proto.spec     = (XPointer)spec;
501    im->private.proto.connect  = _XimXConnect;
502    im->private.proto.shutdown = _XimXShutdown;
503    im->private.proto.write    = _XimXWrite;
504    im->private.proto.read     = _XimXRead;
505    im->private.proto.flush    = _XimXFlush;
506    im->private.proto.register_dispatcher  = _XimXRegisterDispatcher;
507    im->private.proto.call_dispatcher = _XimXCallDispatcher;
508
509    return True;
510}
511