Initialize Tizen 2.3
[framework/uifw/xorg/lib/libx11.git] / modules / im / ximcp / imTrX.c
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
27 Permission to use, copy, modify, distribute, and sell this software
28 and its documentation for any purpose is hereby granted without fee,
29 provided that the above copyright notice appear in all copies and
30 that both that copyright notice and this permission notice appear
31 in supporting documentation, and that the name of FUJITSU LIMITED
32 not be used in advertising or publicity pertaining to distribution
33 of the software without specific, written prior permission.
34 FUJITSU LIMITED makes no representations about the suitability of
35 this software for any purpose.
36 It is provided "as is" without express or implied warranty.
37
38 FUJITSU LIMITED DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
39 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
40 EVENT SHALL FUJITSU LIMITED BE LIABLE FOR ANY SPECIAL, INDIRECT OR
41 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
42 USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
43 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
44 PERFORMANCE 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
63 Private 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
84 Private 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
99 Private 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
112 Private 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
140 Private 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
156 Private 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
227 Private 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
247 Private 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
258 Private 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
319 Private 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
443 Private 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
464 Private 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
487 Private void
488 _XimXFlush(Xim im)
489 {
490     XFlush(im->core.display);
491     return;
492 }
493
494 Public Bool
495 _XimXConf(Xim im, char *address)
496 {
497     XSpecRec    *spec;
498
499     if (!(spec = Xcalloc(1, sizeof(XSpecRec))))
500         return False;
501
502     spec->improtocolid = XInternAtom(im->core.display, _XIM_PROTOCOL, False);
503     spec->imconnectid  = XInternAtom(im->core.display, _XIM_XCONNECT, False);
504     spec->immoredataid = XInternAtom(im->core.display, _XIM_MOREDATA, False);
505     spec->major_code = MAJOR_TRANSPORT_VERSION;
506     spec->minor_code = MINOR_TRANSPORT_VERSION;
507
508     im->private.proto.spec     = (XPointer)spec;
509     im->private.proto.connect  = _XimXConnect;
510     im->private.proto.shutdown = _XimXShutdown;
511     im->private.proto.write    = _XimXWrite;
512     im->private.proto.read     = _XimXRead;
513     im->private.proto.flush    = _XimXFlush;
514     im->private.proto.register_dispatcher  = _XimXRegisterDispatcher;
515     im->private.proto.call_dispatcher = _XimXCallDispatcher;
516
517     return True;
518 }