1/******************************************************************
2
3           Copyright 1992, 1993, 1994 by FUJITSU LIMITED
4
5Permission to use, copy, modify, distribute, and sell this software
6and its documentation for any purpose is hereby granted without fee,
7provided that the above copyright notice appear in all copies and
8that both that copyright notice and this permission notice appear
9in supporting documentation, and that the name of FUJITSU LIMITED
10not be used in advertising or publicity pertaining to distribution
11of the software without specific, written prior permission.
12FUJITSU LIMITED makes no representations about the suitability of
13this software for any purpose.
14It is provided "as is" without express or implied warranty.
15
16FUJITSU LIMITED DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18EVENT SHALL FUJITSU LIMITED BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
20USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
21OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22PERFORMANCE OF THIS SOFTWARE.
23
24  Author: Takashi Fujiwara     FUJITSU LIMITED
25                               fujiwara@a80.tech.yk.fujitsu.co.jp
26
27******************************************************************/
28
29#ifdef HAVE_CONFIG_H
30#include <config.h>
31#endif
32#include <X11/Xatom.h>
33#include "Xlibint.h"
34#include "Xlcint.h"
35#include "Ximint.h"
36
37/*
38 * index of extensions
39 */
40
41#define	XIM_EXT_SET_EVENT_MASK_IDX	0
42#ifdef EXT_FORWARD
43#define	XIM_EXT_FORWARD_KEYEVENT_IDX	1
44#endif
45#ifdef EXT_MOVE
46#define	XIM_EXT_MOVE_IDX		2
47#endif
48
49typedef struct	_XIM_QueryExtRec {
50    Bool	 is_support;
51    const char	*name;
52    int		 name_len;
53    CARD16	 major_opcode;
54    CARD16	 minor_opcode;
55    int		 idx;
56} XIM_QueryExtRec;
57
58static XIM_QueryExtRec	extensions[] = {
59	{False, "XIM_EXT_SET_EVENT_MASK", 0, 0, 0,
60					XIM_EXT_SET_EVENT_MASK_IDX},
61#ifdef EXT_FORWARD
62	{False, "XIM_EXT_FORWARD_KEYEVENT", 0, 0, 0,
63					XIM_EXT_FORWARD_KEYEVENT_IDX},
64#endif
65#ifdef EXT_MOVE
66	{False, "XIM_EXT_MOVE", 0, 0, 0, XIM_EXT_MOVE_IDX},
67#endif
68	{False, NULL, 0, 0, 0, 0}		/* dummy */
69};
70
71static int
72_XimIsSupportExt(
73    int		 idx)
74{
75    register int i;
76    int		 n = XIMNumber(extensions) - 1;
77
78    for (i = 0; i < n; i++) {
79	if (extensions[i].idx == idx) {
80	    if (extensions[i].is_support)
81		return i;
82	    else
83		break;
84	}
85    }
86    return -1;
87}
88
89static Bool
90_XimProcExtSetEventMask(
91    Xim		 im,
92    Xic		 ic,
93    XPointer	 buf)
94{
95    EVENTMASK	*buf_l = (EVENTMASK *)buf;
96    EVENTMASK	 select_mask = _XimGetWindowEventmask(ic);
97
98    ic->private.proto.filter_event_mask      = buf_l[0];
99    ic->private.proto.intercept_event_mask   = buf_l[1];
100    ic->private.proto.select_event_mask      = buf_l[2];
101    ic->private.proto.forward_event_mask     = buf_l[3];
102    ic->private.proto.synchronous_event_mask = buf_l[4];
103
104    select_mask &= ~ic->private.proto.intercept_event_mask;
105						/* deselected event mask */
106    select_mask |= ic->private.proto.select_event_mask;
107						/* selected event mask */
108    XSelectInput(im->core.display, ic->core.focus_window, select_mask);
109    _XimReregisterFilter(ic);
110
111    if (!(_XimProcSyncReply(im, ic)))
112	return False;
113    return True;
114}
115
116static Bool
117_XimExtSetEventMaskCallback(
118    Xim		 xim,
119    INT16	 len,
120    XPointer	 data,
121    XPointer	 call_data)
122{
123    CARD16	*buf_s = (CARD16 *)((CARD8 *)data + XIM_HEADER_SIZE);
124    XIMID	 imid = buf_s[0];
125    XICID	 icid = buf_s[1];
126    Xim		 im = (Xim)call_data;
127    Xic		 ic;
128
129    if ((imid == im->private.proto.imid)
130     && (ic = _XimICOfXICID(im, icid))) {
131	(void)_XimProcExtSetEventMask(im, ic, (XPointer)&buf_s[2]);
132	return True;
133    }
134    return False;
135}
136
137#ifdef EXT_FORWARD
138static Bool
139_XimProcExtForwardKeyEvent(
140    Xim		 im,
141    Xic		 ic,
142    XPointer	 buf)
143{
144    CARD8	*buf_b = (CARD8 *)buf;
145    CARD16	*buf_s = (CARD16 *)buf;
146    CARD32	*buf_l = (CARD32 *)buf;
147    XEvent	 ev;
148    XKeyEvent	*kev = (XKeyEvent *)&ev;
149
150    bzero(&ev, sizeof(XEvent));
151    kev->send_event	= False;
152    kev->display	= im->core.display;
153    kev->serial		= buf_s[1];		/* sequence number */
154    kev->type		= buf_b[4] & 0x7f;	/* xEvent.u.u.type */
155    kev->keycode	= buf_b[5];		/* Keycode */
156    kev->state		= buf_s[3];		/* state */
157    kev->time		= buf_l[2];		/* time */
158
159    XPutBackEvent(im->core.display, &ev);
160
161    _XimRespSyncReply(ic, buf_s[0]);
162    MARK_FABRICATED(im);
163
164    return True;
165}
166
167static Bool
168_XimExtForwardKeyEventCallback(
169    Xim		 xim,
170    INT16	 len,
171    XPointer	 data,
172    XPointer	 call_data)
173{
174    CARD16	*buf_s = (CARD16 *)((CARD8 *)data + XIM_HEADER_SIZE);
175    XIMID	 imid = buf_s[0];
176    XICID	 icid = buf_s[1];
177    Xim		 im = (Xim)call_data;
178    Xic		 ic;
179
180    if ((imid == im->private.proto.imid)
181     && (ic = _XimICOfXICID(im, icid))) {
182	(void)_XimProcExtForwardKeyEvent(im, ic, (XPointer)&buf_s[2]);
183	return True;
184    }
185    return False;
186}
187
188static Bool
189_XimExtForwardKeyEventCheck(
190    Xim          im,
191    INT16        len,
192    XPointer	 data,
193    XPointer     arg)
194{
195    Xic		 ic  = (Xic)arg;
196    CARD16	*buf_s = (CARD16 *)((CARD8 *)data + XIM_HEADER_SIZE);
197    CARD8	 major_opcode = *((CARD8 *)data);
198    CARD8	 minor_opcode = *((CARD8 *)data + 1);
199    XIMID	 imid = buf_s[0];
200    XICID	 icid = buf_s[1];
201
202    if ((major_opcode == XIM_SYNC_REPLY)
203     && (minor_opcode == 0)
204     && (imid == im->private.proto.imid)
205     && (icid == ic->private.proto.icid))
206    if ((major_opcode == XIM_ERROR)
207     && (minor_opcode == 0)
208     && (buf_s[2] & XIM_IMID_VALID)
209     && (imid == im->private.proto.imid)
210     && (buf_s[2] & XIM_ICID_VALID)
211     && (icid == ic->private.proto.icid))
212	return True;
213    return False;
214}
215
216Bool
217_XimExtForwardKeyEvent(
218    Xic		 ic,
219    XKeyEvent	*ev,
220    Bool	 sync)
221{
222    Xim		 im = (Xim) ic->core.im;
223    CARD32	 buf32[BUFSIZE/4];
224    CARD8	*buf = (CARD8 *)buf32;
225    CARD8	*buf_b = &buf[XIM_HEADER_SIZE];
226    CARD16	*buf_s = (CARD16 *)buf_b;
227    CARD32	*buf_l = (CARD32 *)buf_b;
228    CARD32	 reply32[BUFSIZE/4];
229    char	*reply = (char *)reply32;
230    XPointer	preply;
231    int		buf_size;
232    int		ret_code;
233    INT16	len;
234    int		idx;
235
236    if ((idx = _XimIsSupportExt(XIM_EXT_FORWARD_KEYEVENT_IDX)) < 0)
237	return False;
238
239    buf_s[0] = im->private.proto.imid;		/* imid */
240    buf_s[1] = ic->private.proto.icid;		/* icid */
241    buf_s[2] = sync ? XimSYNCHRONUS : 0;	/* flag */
242    buf_s[3] = (CARD16)(((XAnyEvent *)ev)->serial & ((unsigned long) 0xffff));
243						/* sequence number */
244    buf_b[8] = ev->type;			/* xEvent.u.u.type */
245    buf_b[9] = ev->keycode;			/* keycode */
246    buf_s[5] = ev->state;			/* state */
247    buf_l[3] = ev->time;			/* time */
248    len = sizeof(CARD16)			/* sizeof imid */
249	+ sizeof(CARD16)			/* sizeof icid */
250	+ sizeof(BITMASK16)			/* sizeof flag */
251	+ sizeof(CARD16)			/* sizeof sequence number */
252	+ sizeof(BYTE)				/* sizeof xEvent.u.u.type */
253	+ sizeof(BYTE)				/* sizeof keycode */
254	+ sizeof(CARD16)			/* sizeof state */
255	+ sizeof(CARD32);			/* sizeof time */
256
257    _XimSetHeader((XPointer)buf,
258		extensions[idx].major_opcode,
259		extensions[idx].minor_opcode, &len);
260    if (!(_XimWrite(im, len, (XPointer)buf)))
261	return False;
262    _XimFlush(im);
263    if (sync) {
264    	buf_size = BUFSIZE;
265    	ret_code = _XimRead(im, &len, (XPointer)reply, buf_size,
266    				_XimExtForwardKeyEventCheck, (XPointer)ic);
267    	if(ret_code == XIM_TRUE) {
268    	    preply = reply;
269    	} else if(ret_code == XIM_OVERFLOW) {
270    	    if(len <= 0) {
271    		preply = reply;
272    	    } else {
273    		buf_sizex = len;
274		preply = Xmalloc(buf_size);
275    		ret_code = _XimRead(im, &len, preply, buf_size,
276    				_XimExtForwardKeyEventCheck, (XPointer)ic);
277    		if(ret_code != XIM_TRUE) {
278		    Xfree(preply);
279    		    return False;
280		}
281    	    }
282    	} else
283	    return False;
284    	buf_s = (CARD16 *)((char *)preply + XIM_HEADER_SIZE);
285    	if (*((CARD8 *)preply) == XIM_ERROR) {
286	    _XimProcError(im, 0, (XPointer)&buf_s[3]);
287    	    if(reply != preply)
288    		Xfree(preply);
289	    return False;
290	}
291    	if(reply != preply)
292    	    Xfree(preply);
293    }
294    return True;
295}
296#endif /* EXT_FORWARD */
297
298static int
299_XimCheckExtensionListSize(void)
300{
301    register int i;
302    int		 len;
303    int		 total = 0;
304    int		 n = XIMNumber(extensions) - 1;
305
306    for (i = 0; i < n; i++) {
307	len = strlen(extensions[i].name);
308	extensions[i].name_len = len;
309	len += sizeof(BYTE);
310	total += len;
311    }
312    return total;
313}
314
315static void
316_XimSetExtensionList(
317    CARD8	*buf)
318{
319    register int i;
320    int		 len;
321    int		 n = XIMNumber(extensions) - 1;
322
323    for (i = 0; i < n; i++) {
324	len = extensions[i].name_len;
325	buf[0] = (BYTE)len;
326	(void)strcpy((char *)&buf[1], extensions[i].name);
327	len += sizeof(BYTE);
328	buf += len;
329    }
330    return;
331}
332
333static unsigned int
334_XimCountNumberOfExtension(
335    INT16	 total,
336    CARD8	*ext)
337{
338    unsigned int n;
339    INT16	 len;
340    INT16	 min_len = sizeof(CARD8)
341			 + sizeof(CARD8)
342			 + sizeof(INT16);
343
344    n = 0;
345    while (total > min_len) {
346	len = *((INT16 *)(&ext[2]));
347	len += (min_len + XIM_PAD(len));
348	total -= len;
349	ext += len;
350	n++;
351    }
352    return n;
353}
354
355static Bool
356_XimParseExtensionList(
357    Xim			 im,
358    CARD16		*data)
359{
360    int			 num = XIMNumber(extensions) - 1;
361    unsigned int	 n;
362    CARD8		*buf;
363    register int	 i;
364    register int	 j;
365    INT16		 len;
366
367    if (!(n = _XimCountNumberOfExtension(data[0], (CARD8 *)&data[1])))
368	return True;
369
370    buf = (CARD8 *)&data[1];
371    for (i = 0; i < n; i++) {
372	len = *((INT16 *)(&buf[2]));
373	for (j = 0; j < num; j++) {
374	    if (!(strncmp(extensions[j].name, (char *)&buf[4], len))) {
375		extensions[j].major_opcode = buf[0];
376		extensions[j].minor_opcode = buf[1];
377		extensions[j].is_support   = True;
378		break;
379	    }
380	}
381	len += sizeof(CARD8)		/* sizeof major_opcode */
382	     + sizeof(CARD8)		/* sizeof minor_opcode */
383	     + sizeof(INT16)		/* sizeof length */
384	     + XIM_PAD(len);		/* sizeof pad */
385	buf += len;
386    }
387
388    return True;
389}
390
391static Bool
392_XimQueryExtensionCheck(
393    Xim          im,
394    INT16        len,
395    XPointer	 data,
396    XPointer     arg)
397{
398    CARD16	*buf_s = (CARD16 *)((CARD8 *)data + XIM_HEADER_SIZE);
399    CARD8	 major_opcode = *((CARD8 *)data);
400    CARD8	 minor_opcode = *((CARD8 *)data + 1);
401    XIMID	 imid = buf_s[0];
402
403    if ((major_opcode == XIM_QUERY_EXTENSION_REPLY)
404     && (minor_opcode == 0)
405     && (imid == im->private.proto.imid))
406	return True;
407    if ((major_opcode == XIM_ERROR)
408     && (minor_opcode == 0)
409     && (buf_s[2] & XIM_IMID_VALID)
410     && (imid == im->private.proto.imid))
411	return True;
412    return False;
413}
414
415Bool
416_XimExtension(
417    Xim		 im)
418{
419    CARD8	*buf;
420    CARD16	*buf_s;
421    int		 buf_len;
422    INT16	 len;
423    CARD32	 reply32[BUFSIZE/4];
424    char	*reply = (char *)reply32;
425    XPointer	 preply;
426    int		 buf_size;
427    int		 ret_code;
428    int		 idx;
429
430    if (!(len = _XimCheckExtensionListSize()))
431	return True;
432
433    buf_len = XIM_HEADER_SIZE
434	    + sizeof(CARD16)
435	    + sizeof(INT16)
436	    + len
437	    + XIM_PAD(len);
438
439    if (!(buf = Xmalloc(buf_len)))
440	return False;
441    buf_s = (CARD16 *)&buf[XIM_HEADER_SIZE];
442
443    buf_s[0] = im->private.proto.imid;	/* imid */
444    buf_s[1] = len;			/* length of Extensions */
445    _XimSetExtensionList((CARD8 *)&buf_s[2]);
446					/* extensions supported */
447    XIM_SET_PAD(&buf_s[2], len);	/* pad */
448    len += sizeof(CARD16)		/* sizeof imid */
449	 + sizeof(INT16);		/* sizeof length of extensions */
450
451    _XimSetHeader((XPointer)buf, XIM_QUERY_EXTENSION, 0, &len);
452    if (!(_XimWrite(im, len, (XPointer)buf))) {
453        XFree(buf);
454	return False;
455    }
456    XFree(buf);
457    _XimFlush(im);
458    buf_size = BUFSIZE;
459    ret_code = _XimRead(im, &len, (XPointer)reply, buf_size,
460    					_XimQueryExtensionCheck, 0);
461    if(ret_code == XIM_TRUE) {
462    	preply = reply;
463    } else if(ret_code == XIM_OVERFLOW) {
464    	if(len <= 0) {
465    	    preply = reply;
466    	} else {
467    	    buf_size = len;
468	    preply = Xmalloc(buf_size);
469    	    ret_code = _XimRead(im, &len, preply, buf_size,
470    					_XimQueryExtensionCheck, 0);
471    	    if(ret_code != XIM_TRUE) {
472		Xfree(preply);
473    		return False;
474	    }
475    	}
476    } else
477	return False;
478    buf_s = (CARD16 *)((char *)preply + XIM_HEADER_SIZE);
479    if (*((CARD8 *)preply) == XIM_ERROR) {
480	_XimProcError(im, 0, (XPointer)&buf_s[3]);
481    	if(reply != preply)
482    	    Xfree(preply);
483	return False;
484    }
485
486    if (!(_XimParseExtensionList(im, &buf_s[1]))) {
487    	if(reply != preply)
488    	    Xfree(preply);
489	return False;
490    }
491    if(reply != preply)
492    	Xfree(preply);
493
494    if ((idx = _XimIsSupportExt(XIM_EXT_SET_EVENT_MASK_IDX)) >= 0)
495	_XimRegProtoIntrCallback(im,
496	 	extensions[idx].major_opcode,
497	 	extensions[idx].minor_opcode,
498		_XimExtSetEventMaskCallback, (XPointer)im);
499#ifdef EXT_FORWARD
500    if ((idx = _XimIsSupportExt(XIM_EXT_FORWARD_KEYEVENT_IDX)) >= 0)
501	_XimRegProtoIntrCallback(im,
502		extensions[idx].major_opcode,
503		extensions[idx].minor_opcode,
504		_XimExtForwardKeyEventCallback, (XPointer)im);
505#endif
506
507    return True;
508}
509
510#ifdef EXT_MOVE
511/* flag of ExtenArgCheck */
512#define	EXT_XNSPOTLOCATION	(1L<<0)
513
514/* macro for ExtenArgCheck */
515#define SET_EXT_XNSPOTLOCATION(flag) (flag |= EXT_XNSPOTLOCATION)
516#define IS_EXT_XNSPOTLOCATION(flag)  (flag & EXT_XNSPOTLOCATION)
517
518/* length of XPoint attribute */
519#define	XIM_Xpoint_length	12
520
521static Bool
522_XimExtMove(
523    Xim		 im,
524    Xic		 ic,
525    CARD16	 x,
526    CARD16	 y)
527{
528    CARD32	 buf32[BUFSIZE/4];
529    CARD8	*buf = (CARD8 *)buf32;
530    CARD16	*buf_s = (CARD16 *)&buf[XIM_HEADER_SIZE];
531    INT16	 len;
532    int		idx;
533
534    if ((idx = _XimIsSupportExt(XIM_EXT_MOVE_IDX)) < 0)
535	return False;
536
537    buf_s[0] = im->private.proto.imid;	/* imid */
538    buf_s[1] = ic->private.proto.icid;	/* icid */
539    buf_s[2] = x;			/* X */
540    buf_s[3] = y;			/* Y */
541    len = sizeof(CARD16)		/* sizeof imid */
542	+ sizeof(CARD16)		/* sizeof icid */
543	+ sizeof(INT16)			/* sizeof X */
544	+ sizeof(INT16);		/* sizeof Y */
545
546    _XimSetHeader((XPointer)buf, extensions[idx].major_opcode,
547			extensions[idx].minor_opcode, &len);
548    if (!(_XimWrite(im, len, (XPointer)buf)))
549	return False;
550    _XimFlush(im);
551    return True;
552}
553
554BITMASK32
555_XimExtenArgCheck(
556    XIMArg	*arg)
557{
558    CARD32	flag = 0L;
559    if (!strcmp(arg->name, XNSpotLocation))
560	SET_EXT_XNSPOTLOCATION(flag);
561    return flag;
562}
563
564Bool
565_XimExtenMove(
566    Xim		 im,
567    Xic		 ic,
568    CARD32	 flag,
569    CARD16	*buf,
570    INT16	 length)
571{
572    if ((IS_EXT_XNSPOTLOCATION(flag)) && (length == XIM_Xpoint_length))
573	return _XimExtMove(im, ic, buf[4], buf[5]);
574    return False;
575}
576#endif /* EXT_MOVE */
577