Tizen 2.1 base
[platform/core/uifw/ise-engine-sunpinyin.git] / wrapper / xim / IMdkit / i18nX.c
1 /******************************************************************
2
3          Copyright 1994, 1995 by Sun Microsystems, Inc.
4          Copyright 1993, 1994 by Hewlett-Packard Company
5
6 Permission to use, copy, modify, distribute, and sell this software
7 and its documentation for any purpose is hereby granted without fee,
8 provided that the above copyright notice appear in all copies and
9 that both that copyright notice and this permission notice appear
10 in supporting documentation, and that the name of Sun Microsystems, Inc.
11 and Hewlett-Packard not be used in advertising or publicity pertaining to
12 distribution of the software without specific, written prior permission.
13 Sun Microsystems, Inc. and Hewlett-Packard make no representations about
14 the suitability of this software for any purpose.  It is provided "as is"
15 without express or implied warranty.
16
17 SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
18 WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
20 SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
21 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
22 RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
23 CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
24 IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25
26   Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
27
28     This version tidied and debugged by Steve Underwood May 1999
29
30 ******************************************************************/
31
32 #include <limits.h>
33 #include <X11/Xlib.h>
34 #include <X11/Xatom.h>
35 #include "FrameMgr.h"
36 #include "IMdkit.h"
37 #include "Xi18n.h"
38 #include "Xi18nX.h"
39 #include "XimFunc.h"
40
41 extern Xi18nClient *_Xi18nFindClient(Xi18n, CARD16);
42 extern Xi18nClient *_Xi18nNewClient(Xi18n);
43 extern void _Xi18nDeleteClient(Xi18n, CARD16);
44 static Bool WaitXConnectMessage(Display*, Window,
45                                 XEvent*, XPointer);
46 static Bool WaitXIMProtocol(Display*, Window, XEvent*, XPointer);
47
48 static XClient *NewXClient (Xi18n i18n_core, Window new_client)
49 {
50     Display *dpy = i18n_core->address.dpy;
51     Xi18nClient *client = _Xi18nNewClient (i18n_core);
52     XClient *x_client;
53
54     x_client = (XClient *) malloc (sizeof (XClient));
55     x_client->client_win = new_client;
56     x_client->accept_win = XCreateSimpleWindow (dpy,
57                                                 DefaultRootWindow(dpy),
58                                                 0,
59                                                 0,
60                                                 1,
61                                                 1,
62                                                 1,
63                                                 0,
64                                                 0);
65     client->trans_rec = x_client;
66     return ((XClient *) x_client);
67 }
68
69 static unsigned char *ReadXIMMessage (XIMS ims,
70                                       XClientMessageEvent *ev,
71                                       int *connect_id)
72 {
73     Xi18n i18n_core = ims->protocol;
74     Xi18nClient *client = i18n_core->address.clients;
75     XClient *x_client = NULL;
76     FrameMgr fm;
77     extern XimFrameRec packet_header_fr[];
78     unsigned char *p = NULL;
79     unsigned char *p1;
80
81     while (client != NULL) {
82         x_client = (XClient *) client->trans_rec;
83         if (x_client->accept_win == ev->window) {
84             *connect_id = client->connect_id;
85             break;
86         }
87         client = client->next;
88     }
89
90     if (ev->format == 8) {
91         /* ClientMessage only */
92         XimProtoHdr *hdr = (XimProtoHdr *) ev->data.b;
93         unsigned char *rec = (unsigned char *) (hdr + 1);
94         register int total_size;
95         CARD8 major_opcode;
96         CARD8 minor_opcode;
97         CARD16 length;
98         extern int _Xi18nNeedSwap (Xi18n, CARD16);
99
100         if (client->byte_order == '?')
101         {
102             if (hdr->major_opcode != XIM_CONNECT)
103                 return (unsigned char *) NULL; /* can do nothing */
104             client->byte_order = (CARD8) rec[0];
105         }
106
107         fm = FrameMgrInit (packet_header_fr,
108                            (char *) hdr,
109                            _Xi18nNeedSwap (i18n_core, *connect_id));
110         total_size = FrameMgrGetTotalSize (fm);
111         /* get data */
112         FrameMgrGetToken (fm, major_opcode);
113         FrameMgrGetToken (fm, minor_opcode);
114         FrameMgrGetToken (fm, length);
115         FrameMgrFree (fm);
116
117         if ((p = (unsigned char *) malloc (total_size + length * 4)) == NULL)
118             return (unsigned char *) NULL;
119
120         p1 = p;
121         memmove (p1, &major_opcode, sizeof (CARD8));
122         p1 += sizeof (CARD8);
123         memmove (p1, &minor_opcode, sizeof (CARD8));
124         p1 += sizeof (CARD8);
125         memmove (p1, &length, sizeof (CARD16));
126         p1 += sizeof (CARD16);
127         memmove (p1, rec, length * 4);
128     }
129     else if (ev->format == 32) {
130         /* ClientMessage and WindowProperty */
131         unsigned long length = (unsigned long) ev->data.l[0];
132         unsigned long get_length;
133         Atom atom = (Atom) ev->data.l[1];
134         int return_code;
135         Atom actual_type_ret;
136         int actual_format_ret;
137         unsigned long bytes_after_ret;
138         unsigned char *prop;
139         unsigned long nitems;
140
141         /* Round up length to next 4 byte value. */
142         get_length = length + 3;
143         if (get_length > LONG_MAX)
144             get_length = LONG_MAX;
145         get_length /= 4;
146         if (get_length == 0) {
147             fprintf(stderr, "%s: invalid length 0\n", __func__);
148             return NULL;
149         }
150         return_code = XGetWindowProperty (i18n_core->address.dpy,
151                                           x_client->accept_win,
152                                           atom,
153                                           client->property_offset / 4,
154                                           get_length,
155                                           True,
156                                           AnyPropertyType,
157                                           &actual_type_ret,
158                                           &actual_format_ret,
159                                           &nitems,
160                                           &bytes_after_ret,
161                                           &prop);
162         if (return_code != Success || actual_format_ret == 0 || nitems == 0) {
163             if (return_code == Success)
164                 XFree (prop);
165             client->property_offset = 0;
166             return (unsigned char *) NULL;
167         }
168         /* Update the offset to read next time as needed */
169         if (bytes_after_ret > 0)
170             client->property_offset += length;
171         else
172             client->property_offset = 0;
173         switch (actual_format_ret) {
174         case 8:
175         case 16:
176         case 32:
177             length = nitems * actual_format_ret / 8;
178             break;
179         default:
180             fprintf(stderr, "%s: unknown property return format: %d\n",
181                         __func__, actual_format_ret);
182             XFree(prop);
183             client->property_offset = 0;
184             return NULL;
185         }
186         /* if hit, it might be an error */
187         if ((p = (unsigned char *) malloc (length)) == NULL)
188             return (unsigned char *) NULL;
189
190         memmove (p, prop, length);
191         XFree (prop);
192     }
193     return (unsigned char *) p;
194 }
195
196 static void ReadXConnectMessage (XIMS ims, XClientMessageEvent *ev)
197 {
198     Xi18n i18n_core = ims->protocol;
199     XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
200     XEvent event;
201     Display *dpy = i18n_core->address.dpy;
202     Window new_client = ev->data.l[0];
203     CARD32 major_version = ev->data.l[1];
204     CARD32 minor_version = ev->data.l[2];
205     XClient *x_client = NewXClient (i18n_core, new_client);
206
207     if (ev->window != i18n_core->address.im_window)
208         return; /* incorrect connection request */
209     /*endif*/
210     if (major_version != 0  ||  minor_version != 0)
211     {
212         major_version =
213         minor_version = 0;
214         /* Only supporting only-CM & Property-with-CM method */
215     }
216     /*endif*/
217     _XRegisterFilterByType (dpy,
218                             x_client->accept_win,
219                             ClientMessage,
220                             ClientMessage,
221                             WaitXIMProtocol,
222                             (XPointer)ims);
223     event.xclient.type = ClientMessage;
224     event.xclient.display = dpy;
225     event.xclient.window = new_client;
226     event.xclient.message_type = spec->connect_request;
227     event.xclient.format = 32;
228     event.xclient.data.l[0] = x_client->accept_win;
229     event.xclient.data.l[1] = major_version;
230     event.xclient.data.l[2] = minor_version;
231     event.xclient.data.l[3] = XCM_DATA_LIMIT;
232
233     XSendEvent (dpy,
234                 new_client,
235                 False,
236                 NoEventMask,
237                 &event);
238     XFlush (dpy);
239 }
240
241 static Bool Xi18nXBegin (XIMS ims)
242 {
243     Xi18n i18n_core = ims->protocol;
244     Display *dpy = i18n_core->address.dpy;
245     XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
246
247     spec->xim_request = XInternAtom (i18n_core->address.dpy,
248                                      _XIM_PROTOCOL,
249                                      False);
250     spec->connect_request = XInternAtom (i18n_core->address.dpy,
251                                          _XIM_XCONNECT,
252                                          False);
253
254     _XRegisterFilterByType (dpy,
255                             i18n_core->address.im_window,
256                             ClientMessage,
257                             ClientMessage,
258                             WaitXConnectMessage,
259                             (XPointer)ims);
260     return True;
261 }
262
263 static Bool Xi18nXEnd(XIMS ims)
264 {
265     Xi18n i18n_core = ims->protocol;
266     Display *dpy = i18n_core->address.dpy;
267
268     _XUnregisterFilter (dpy,
269                         i18n_core->address.im_window,
270                         WaitXConnectMessage,
271                         (XPointer)ims);
272     return True;
273 }
274
275 static char *MakeNewAtom (CARD16 connect_id, char *atomName)
276 {
277     static int sequence = 0;
278
279     sprintf (atomName,
280              "_server%d_%d",
281              connect_id,
282              ((sequence > 20)  ?  (sequence = 0)  :  sequence++));
283     return atomName;
284 }
285
286 static Bool Xi18nXSend (XIMS ims,
287                         CARD16 connect_id,
288                         unsigned char *reply,
289                         long length)
290 {
291     Xi18n i18n_core = ims->protocol;
292     Xi18nClient *client = _Xi18nFindClient (i18n_core, connect_id);
293     XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
294     XClient *x_client = (XClient *) client->trans_rec;
295     XEvent event;
296
297     memset(&event, 0, sizeof(XEvent));
298     event.type = ClientMessage;
299     event.xclient.serial = 0;
300     event.xclient.send_event = True;
301     event.xclient.display = i18n_core->address.dpy;
302     event.xclient.window = x_client->client_win;
303     event.xclient.message_type = spec->xim_request;
304
305     if (length > XCM_DATA_LIMIT)
306     {
307         Atom atom;
308         char atomName[16];
309         Atom actual_type_ret;
310         int actual_format_ret;
311         int return_code;
312         unsigned long nitems_ret;
313         unsigned long bytes_after_ret;
314         unsigned char *win_data;
315
316         event.xclient.format = 32;
317         atom = XInternAtom (i18n_core->address.dpy,
318                             MakeNewAtom (connect_id, atomName),
319                             False);
320         return_code = XGetWindowProperty (i18n_core->address.dpy,
321                                           x_client->client_win,
322                                           atom,
323                                           0L,
324                                           10000L,
325                                           False,
326                                           XA_STRING,
327                                           &actual_type_ret,
328                                           &actual_format_ret,
329                                           &nitems_ret,
330                                           &bytes_after_ret,
331                                           &win_data);
332         if (return_code != Success)
333             return False;
334         /*endif*/
335         if (win_data)
336             XFree ((char *) win_data);
337         /*endif*/
338         XChangeProperty (i18n_core->address.dpy,
339                          x_client->client_win,
340                          atom,
341                          XA_STRING,
342                          8,
343                          PropModeAppend,
344                          (unsigned char *) reply,
345                          length);
346         event.xclient.data.l[0] = length;
347         event.xclient.data.l[1] = atom;
348     }
349     else
350     {
351         unsigned char buffer[XCM_DATA_LIMIT];
352         int i;
353
354         event.xclient.format = 8;
355
356         /* Clear unused field with NULL */
357         memmove(buffer, reply, length);
358         for (i = length; i < XCM_DATA_LIMIT; i++)
359             buffer[i] = (char) 0;
360         /*endfor*/
361         length = XCM_DATA_LIMIT;
362         memmove (event.xclient.data.b, buffer, length);
363     }
364     XSendEvent (i18n_core->address.dpy,
365                 x_client->client_win,
366                 False,
367                 NoEventMask,
368                 &event);
369     XFlush (i18n_core->address.dpy);
370     return True;
371 }
372
373 static Bool CheckCMEvent (Display *display, XEvent *event, XPointer xi18n_core)
374 {
375     Xi18n i18n_core = (Xi18n) ((void *) xi18n_core);
376     XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
377
378     if ((event->type == ClientMessage)
379         &&
380         (event->xclient.message_type == spec->xim_request))
381     {
382         return  True;
383     }
384     /*endif*/
385     return  False;
386 }
387
388 static Bool Xi18nXWait (XIMS ims,
389                         CARD16 connect_id,
390                         CARD8 major_opcode,
391                         CARD8 minor_opcode)
392 {
393     Xi18n i18n_core = ims->protocol;
394     XEvent event;
395     Xi18nClient *client = _Xi18nFindClient (i18n_core, connect_id);
396     XClient *x_client = (XClient *) client->trans_rec;
397
398     for (;;)
399     {
400         unsigned char *packet;
401         XimProtoHdr *hdr;
402         int connect_id_ret;
403
404         XIfEvent (i18n_core->address.dpy,
405                   &event,
406                   CheckCMEvent,
407                   (XPointer) i18n_core);
408         if (event.xclient.window == x_client->accept_win)
409         {
410             if ((packet = ReadXIMMessage (ims,
411                                           (XClientMessageEvent *) & event,
412                                           &connect_id_ret))
413                 == (unsigned char*) NULL)
414             {
415                 return False;
416             }
417             /*endif*/
418             hdr = (XimProtoHdr *)packet;
419
420             if ((hdr->major_opcode == major_opcode)
421                 &&
422                 (hdr->minor_opcode == minor_opcode))
423             {
424                 return True;
425             }
426             else if (hdr->major_opcode == XIM_ERROR)
427             {
428                 return False;
429             }
430             /*endif*/
431         }
432         /*endif*/
433     }
434     /*endfor*/
435 }
436
437 static Bool Xi18nXDisconnect (XIMS ims, CARD16 connect_id)
438 {
439     Xi18n i18n_core = ims->protocol;
440     Display *dpy = i18n_core->address.dpy;
441     Xi18nClient *client = _Xi18nFindClient (i18n_core, connect_id);
442     XClient *x_client = (XClient *) client->trans_rec;
443
444     XDestroyWindow (dpy, x_client->accept_win);
445     _XUnregisterFilter (dpy,
446                         x_client->accept_win,
447                         WaitXIMProtocol,
448                         (XPointer)ims);
449     XFree (x_client);
450     _Xi18nDeleteClient (i18n_core, connect_id);
451     return True;
452 }
453
454 Bool _Xi18nCheckXAddress (Xi18n i18n_core,
455                           TransportSW *transSW,
456                           char *address)
457 {
458     XSpecRec *spec;
459
460     if (!(spec = (XSpecRec *) malloc (sizeof (XSpecRec))))
461         return False;
462     /*endif*/
463
464     i18n_core->address.connect_addr = (XSpecRec *) spec;
465     i18n_core->methods.begin = Xi18nXBegin;
466     i18n_core->methods.end = Xi18nXEnd;
467     i18n_core->methods.send = Xi18nXSend;
468     i18n_core->methods.wait = Xi18nXWait;
469     i18n_core->methods.disconnect = Xi18nXDisconnect;
470     return True;
471 }
472
473 static Bool WaitXConnectMessage (Display *dpy,
474                                  Window win,
475                                  XEvent *ev,
476                                  XPointer client_data)
477 {
478     XIMS ims = (XIMS)client_data;
479     Xi18n i18n_core = ims->protocol;
480     XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
481
482     if (((XClientMessageEvent *) ev)->message_type
483         == spec->connect_request)
484     {
485         ReadXConnectMessage (ims, (XClientMessageEvent *) ev);
486         return True;
487     }
488     /*endif*/
489     return False;
490 }
491
492 static Bool WaitXIMProtocol (Display *dpy,
493                              Window win,
494                              XEvent *ev,
495                              XPointer client_data)
496 {
497     extern void _Xi18nMessageHandler (XIMS, CARD16, unsigned char *, Bool *);
498     XIMS ims = (XIMS) client_data;
499     Xi18n i18n_core = ims->protocol;
500     XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
501     Bool delete = True;
502     unsigned char *packet;
503     int connect_id;
504
505     if (((XClientMessageEvent *) ev)->message_type
506         == spec->xim_request)
507     {
508         if ((packet = ReadXIMMessage (ims,
509                                       (XClientMessageEvent *) ev,
510                                       &connect_id))
511             == (unsigned char *)  NULL)
512         {
513             return False;
514         }
515         /*endif*/
516         _Xi18nMessageHandler (ims, connect_id, packet, &delete);
517         if (delete == True)
518             XFree (packet);
519         /*endif*/
520         return True;
521     }
522     /*endif*/
523     return False;
524 }