upload tizen 2.0 beta code
[profile/ivi/isf.git] / ism / modules / frontend / imdkit / i18nMethod.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 <X11/Xlib.h>
33 #include <X11/Xatom.h>
34 #ifndef NEED_EVENTS
35 #define NEED_EVENTS
36 #endif
37 #include <X11/Xproto.h>
38 #undef NEED_EVENTS
39 #include "FrameMgr.h"
40 #include "IMdkit.h"
41 #include "Xi18n.h"
42 #include "XimFunc.h"
43
44 extern Xi18nClient *_Xi18nFindClient (Xi18n, CARD16);
45
46 static void *xi18n_setup (Display *, XIMArg *);
47 static Status xi18n_openIM (XIMS);
48 static Status xi18n_closeIM (XIMS);
49 static char *xi18n_setIMValues (XIMS, XIMArg *);
50 static char *xi18n_getIMValues (XIMS, XIMArg *);
51 static Status xi18n_forwardEvent (XIMS, XPointer);
52 static Status xi18n_commit (XIMS, XPointer);
53 static int xi18n_callCallback (XIMS, XPointer);
54 static int xi18n_preeditStart (XIMS, XPointer);
55 static int xi18n_preeditEnd (XIMS, XPointer);
56 static int xi18n_syncXlib (XIMS, XPointer);
57
58 #ifndef XIM_SERVERS
59 #define XIM_SERVERS "XIM_SERVERS"
60 #endif
61 static Atom XIM_Servers = None;
62
63
64 IMMethodsRec Xi18n_im_methods =
65 {
66     xi18n_setup,
67     xi18n_openIM,
68     xi18n_closeIM,
69     xi18n_setIMValues,
70     xi18n_getIMValues,
71     xi18n_forwardEvent,
72     xi18n_commit,
73     xi18n_callCallback,
74     xi18n_preeditStart,
75     xi18n_preeditEnd,
76     xi18n_syncXlib,
77 };
78
79 extern Bool _Xi18nCheckXAddress (Xi18n, TransportSW *, char *);
80 extern Bool _Xi18nCheckTransAddress (Xi18n, TransportSW *, char *);
81
82 TransportSW _TransR[] =
83 {
84     {"X",               1, _Xi18nCheckXAddress},
85 #ifdef TCPCONN
86     {"tcp",             3, _Xi18nCheckTransAddress},
87     {"local",           5, _Xi18nCheckTransAddress},
88 #endif
89 #ifdef DNETCONN
90     {"decnet",          6, _Xi18nCheckTransAddress},
91 #endif
92     {(char *) NULL,     0, (Bool (*) ()) NULL}
93 };
94
95 static Bool GetInputStyles (Xi18n i18n_core, XIMStyles **p_style)
96 {
97     Xi18nAddressRec *address = (Xi18nAddressRec *) &i18n_core->address;
98     XIMStyles *p;
99     int i;
100
101     p = &address->input_styles;
102     if ((*p_style = (XIMStyles *) malloc (sizeof (XIMStyles)
103                                           + p->count_styles*sizeof (XIMStyle)))
104         == NULL)
105     {
106         return False;
107     }
108     /*endif*/
109     (*p_style)->count_styles = p->count_styles;
110     (*p_style)->supported_styles = (XIMStyle *) ((XPointer) *p_style + sizeof (XIMStyles));
111     for (i = 0;  i < (int) p->count_styles;  i++)
112         (*p_style)->supported_styles[i] = p->supported_styles[i];
113     /*endfor*/
114     return True;
115 }
116
117 static Bool GetOnOffKeys (Xi18n i18n_core, long mask, XIMTriggerKeys **p_key)
118 {
119     Xi18nAddressRec *address = (Xi18nAddressRec *) &i18n_core->address;
120     XIMTriggerKeys *p;
121     int i;
122
123     if (mask & I18N_ON_KEYS)
124         p = &address->on_keys;
125     else
126         p = &address->off_keys;
127     /*endif*/
128     if ((*p_key = (XIMTriggerKeys *) malloc (sizeof(XIMTriggerKeys)
129                                              + p->count_keys*sizeof(XIMTriggerKey)))
130         == NULL)
131     {
132         return False;
133     }
134     /*endif*/
135     (*p_key)->count_keys = p->count_keys;
136     (*p_key)->keylist =
137         (XIMTriggerKey *) ((XPointer) *p_key + sizeof(XIMTriggerKeys));
138     for (i = 0;  i < (int) p->count_keys;  i++)
139     {
140         (*p_key)->keylist[i].keysym = p->keylist[i].keysym;
141         (*p_key)->keylist[i].modifier = p->keylist[i].modifier;
142         (*p_key)->keylist[i].modifier_mask = p->keylist[i].modifier_mask;
143     }
144     /*endfor*/
145     return True;
146 }
147
148 static Bool GetEncodings(Xi18n i18n_core, XIMEncodings **p_encoding)
149 {
150     Xi18nAddressRec *address = (Xi18nAddressRec *) &i18n_core->address;
151     XIMEncodings *p;
152     int i;
153
154     p = &address->encoding_list;
155
156     if ((*p_encoding = (XIMEncodings *) malloc (sizeof (XIMEncodings)
157                                               + p->count_encodings*sizeof(XIMEncoding))) == NULL)
158     {
159         return False;
160     }
161     /*endif*/
162     (*p_encoding)->count_encodings = p->count_encodings;
163     (*p_encoding)->supported_encodings =
164         (XIMEncoding *) ((XPointer)*p_encoding + sizeof (XIMEncodings));
165     for (i = 0;  i < (int) p->count_encodings;  i++)
166     {
167         (*p_encoding)->supported_encodings[i]
168             = (char *) malloc (strlen (p->supported_encodings[i]) + 1);
169         strcpy ((*p_encoding)->supported_encodings[i],
170                 p->supported_encodings[i]);
171     }
172     /*endif*/
173     return True;
174 }
175
176 static char *ParseArgs (Xi18n i18n_core, int mode, XIMArg *args)
177 {
178     Xi18nAddressRec *address = (Xi18nAddressRec *) &i18n_core->address;
179     XIMArg *p;
180
181     if (mode == I18N_OPEN  ||  mode == I18N_SET)
182     {
183         for (p = args;  p->name != NULL;  p++)
184         {
185             if (strcmp (p->name, IMLocale) == 0)
186             {
187                 if (address->imvalue_mask & I18N_IM_LOCALE)
188                     return IMLocale;
189                 /*endif*/
190                 address->im_locale = (char *) malloc (strlen (p->value) + 1);
191                 if (!address->im_locale)
192                     return IMLocale;
193                 /*endif*/
194                 strcpy (address->im_locale, p->value);
195                 address->imvalue_mask |= I18N_IM_LOCALE;
196             }
197             else if (strcmp (p->name, IMServerTransport) == 0)
198             {
199                 if (address->imvalue_mask & I18N_IM_ADDRESS)
200                     return IMServerTransport;
201                 /*endif*/
202                 address->im_addr = (char *) malloc (strlen (p->value) + 1);
203                 if (!address->im_addr)
204                     return IMServerTransport;
205                 /*endif*/
206                 strcpy(address->im_addr, p->value);
207                 address->imvalue_mask |= I18N_IM_ADDRESS;
208             }
209             else if (strcmp (p->name, IMServerName) == 0)
210             {
211                 if (address->imvalue_mask & I18N_IM_NAME)
212                     return IMServerName;
213                 /*endif*/
214                 address->im_name = (char *) malloc (strlen (p->value) + 1);
215                 if (!address->im_name)
216                     return IMServerName;
217                 /*endif*/
218                 strcpy (address->im_name, p->value);
219                 address->imvalue_mask |= I18N_IM_NAME;
220             }
221             else if (strcmp (p->name, IMServerWindow) == 0)
222             {
223                 if (address->imvalue_mask & I18N_IMSERVER_WIN)
224                     return IMServerWindow;
225                 /*endif*/
226                 address->im_window = (Window) p->value;
227                 address->imvalue_mask |= I18N_IMSERVER_WIN;
228             }
229             else if (strcmp (p->name, IMInputStyles) == 0)
230             {
231                 if (address->imvalue_mask & I18N_INPUT_STYLES)
232                     return IMInputStyles;
233                 /*endif*/
234                 address->input_styles.count_styles =
235                     ((XIMStyles*)p->value)->count_styles;
236                 address->input_styles.supported_styles =
237                     (XIMStyle *) malloc (sizeof (XIMStyle)*address->input_styles.count_styles);
238                 if (address->input_styles.supported_styles == (XIMStyle *) NULL)
239                     return IMInputStyles;
240                 /*endif*/
241                 memmove (address->input_styles.supported_styles,
242                          ((XIMStyles *) p->value)->supported_styles,
243                          sizeof (XIMStyle)*address->input_styles.count_styles);
244                 address->imvalue_mask |= I18N_INPUT_STYLES;
245             }
246             else if (strcmp (p->name, IMProtocolHandler) == 0)
247             {
248                 address->improto = (IMProtoHandler) p->value;
249                 address->imvalue_mask |= I18N_IM_HANDLER;
250             }
251             else if (strcmp (p->name, IMOnKeysList) == 0)
252             {
253                 if (address->imvalue_mask & I18N_ON_KEYS)
254                     return IMOnKeysList;
255                 /*endif*/
256                 address->on_keys.count_keys =
257                     ((XIMTriggerKeys *) p->value)->count_keys;
258                 address->on_keys.keylist =
259                     (XIMTriggerKey *) malloc (sizeof (XIMTriggerKey)*address->on_keys.count_keys);
260                 if (address->on_keys.keylist == (XIMTriggerKey *) NULL)
261                     return IMOnKeysList;
262                 /*endif*/
263                 memmove (address->on_keys.keylist,
264                          ((XIMTriggerKeys *) p->value)->keylist,
265                          sizeof (XIMTriggerKey)*address->on_keys.count_keys);
266                 address->imvalue_mask |= I18N_ON_KEYS;
267             }
268             else if (strcmp (p->name, IMOffKeysList) == 0)
269             {
270                 if (address->imvalue_mask & I18N_OFF_KEYS)
271                     return IMOffKeysList;
272                 /*endif*/
273                 address->off_keys.count_keys =
274                     ((XIMTriggerKeys *) p->value)->count_keys;
275                 address->off_keys.keylist =
276                     (XIMTriggerKey *) malloc (sizeof (XIMTriggerKey)*address->off_keys.count_keys);
277                 if (address->off_keys.keylist == (XIMTriggerKey *) NULL)
278                     return IMOffKeysList;
279                 /*endif*/
280                 memmove (address->off_keys.keylist,
281                          ((XIMTriggerKeys *) p->value)->keylist,
282                          sizeof (XIMTriggerKey)*address->off_keys.count_keys);
283                 address->imvalue_mask |= I18N_OFF_KEYS;
284             }
285             else if (strcmp (p->name, IMEncodingList) == 0)
286             {
287                 if (address->imvalue_mask & I18N_ENCODINGS)
288                     return IMEncodingList;
289                 /*endif*/
290                 address->encoding_list.count_encodings =
291                     ((XIMEncodings *) p->value)->count_encodings;
292                 address->encoding_list.supported_encodings =
293                     (XIMEncoding *) malloc (sizeof (XIMEncoding)*address->encoding_list.count_encodings);
294                 if (address->encoding_list.supported_encodings
295                     == (XIMEncoding *) NULL)
296                 {
297                     return IMEncodingList;
298                 }
299                 /*endif*/
300                 memmove (address->encoding_list.supported_encodings,
301                          ((XIMEncodings *) p->value)->supported_encodings,
302                          sizeof (XIMEncoding)*address->encoding_list.count_encodings);
303                 address->imvalue_mask |= I18N_ENCODINGS;
304             }
305             else if (strcmp (p->name, IMFilterEventMask) == 0)
306             {
307                 if (address->imvalue_mask & I18N_FILTERMASK)
308                     return IMFilterEventMask;
309                 /*endif*/
310                 address->filterevent_mask = (long) p->value;
311                 address->imvalue_mask |= I18N_FILTERMASK;
312             }
313             /*endif*/
314         }
315         /*endfor*/
316         if (mode == I18N_OPEN)
317         {
318             /* check mandatory IM values */
319             if (!(address->imvalue_mask & I18N_IM_LOCALE))
320             {
321                 /* locales must be set in IMOpenIM */
322                 return IMLocale;
323             }
324             /*endif*/
325             if (!(address->imvalue_mask & I18N_IM_ADDRESS))
326             {
327                 /* address must be set in IMOpenIM */
328                 return IMServerTransport;
329             }
330             /*endif*/
331         }
332         /*endif*/
333     }
334     else if (mode == I18N_GET)
335     {
336         for (p = args;  p->name != NULL;  p++)
337         {
338             if (strcmp (p->name, IMLocale) == 0)
339             {
340                 p->value = (char *) malloc (strlen (address->im_locale) + 1);
341                 if (!p->value)
342                     return IMLocale;
343                 /*endif*/
344                 strcpy (p->value, address->im_locale);
345             }
346             else if (strcmp (p->name, IMServerTransport) == 0)
347             {
348                 p->value = (char *) malloc (strlen (address->im_addr) + 1);
349                 if (!p->value)
350                     return IMServerTransport;
351                 /*endif*/
352                 strcpy (p->value, address->im_addr);
353             }
354             else if (strcmp (p->name, IMServerName) == 0)
355             {
356                 if (address->imvalue_mask & I18N_IM_NAME)
357                 {
358                     p->value = (char *) malloc (strlen (address->im_name) + 1);
359                     if (!p->value)
360                         return IMServerName;
361                     /*endif*/
362                     strcpy (p->value, address->im_name);
363                 }
364                 else
365                 {
366                     return IMServerName;
367                 }
368                 /*endif*/
369             }
370             else if (strcmp (p->name, IMServerWindow) == 0)
371             {
372                 if (address->imvalue_mask & I18N_IMSERVER_WIN)
373                     *((Window *) (p->value)) = address->im_window;
374                 else
375                     return IMServerWindow;
376                 /*endif*/
377             }
378             else if (strcmp (p->name, IMInputStyles) == 0)
379             {
380                 if (GetInputStyles (i18n_core,
381                                     (XIMStyles **) p->value) == False)
382                 {
383                     return IMInputStyles;
384                 }
385                 /*endif*/
386             }
387             else if (strcmp (p->name, IMProtocolHandler) == 0)
388             {
389                 if (address->imvalue_mask & I18N_IM_HANDLER)
390                     *((IMProtoHandler *) (p->value)) = address->improto;
391                 else
392                     return IMProtocolHandler;
393                 /*endif*/
394             }
395             else if (strcmp (p->name, IMOnKeysList) == 0)
396             {
397                 if (address->imvalue_mask & I18N_ON_KEYS)
398                 {
399                     if (GetOnOffKeys (i18n_core,
400                                       I18N_ON_KEYS,
401                                       (XIMTriggerKeys **) p->value) == False)
402                     {
403                         return IMOnKeysList;
404                     }
405                     /*endif*/
406                 }
407                 else
408                 {
409                     return IMOnKeysList;
410                 }
411                 /*endif*/
412             }
413             else if (strcmp (p->name, IMOffKeysList) == 0)
414             {
415                 if (address->imvalue_mask & I18N_OFF_KEYS)
416                 {
417                     if (GetOnOffKeys (i18n_core,
418                                       I18N_OFF_KEYS,
419                                       (XIMTriggerKeys **) p->value) == False)
420                     {
421                         return IMOffKeysList;
422                     }
423                     /*endif*/
424                 }
425                 else
426                 {
427                     return IMOffKeysList;
428                 }
429                 /*endif*/
430             }
431             else if (strcmp (p->name, IMEncodingList) == 0)
432             {
433                 if (address->imvalue_mask & I18N_ENCODINGS)
434                 {
435                     if (GetEncodings (i18n_core,
436                                       (XIMEncodings **) p->value) == False)
437                     {
438                         return IMEncodingList;
439                     }
440                     /*endif*/
441                 }
442                 else
443                 {
444                     return IMEncodingList;
445                 }
446                 /*endif*/
447             }
448             else if (strcmp (p->name, IMFilterEventMask) == 0)
449             {
450                 if (address->imvalue_mask & I18N_FILTERMASK)
451                     *((long *) (p->value)) = address->filterevent_mask;
452                 else
453                     return IMFilterEventMask;
454                 /*endif*/
455             }
456             /*endif*/
457         }
458         /*endfor*/
459     }
460     /*endif*/
461     return NULL;
462 }
463
464 static int CheckIMName (Xi18n i18n_core)
465 {
466     char *address = i18n_core->address.im_addr;
467     int i;
468
469     for (i = 0;  _TransR[i].transportname;  i++)
470     {
471         while (*address == ' '  ||  *address == '\t')
472             address++;
473         /*endwhile*/
474         if (strncmp (address,
475                      _TransR[i].transportname,
476                      _TransR[i].namelen) == 0
477             &&
478             address[_TransR[i].namelen] == '/')
479         {
480             if (_TransR[i].checkAddr (i18n_core,
481                                       &_TransR[i],
482                                       address + _TransR[i].namelen + 1) == True)
483             {
484                 return True;
485             }
486             /*endif*/
487             return False;
488         }
489         /*endif*/
490     }
491     /*endfor*/
492     return False;
493 }
494
495 static int SetXi18nSelectionOwner(Xi18n i18n_core)
496 {
497     Display *dpy = i18n_core->address.dpy;
498     Window ims_win = i18n_core->address.im_window;
499     Window root = RootWindow (dpy, DefaultScreen (dpy));
500     Atom realtype;
501     int realformat;
502     unsigned long bytesafter;
503     long *data=NULL;
504     unsigned long length;
505     Atom atom;
506     int i;
507     int found;
508     int forse = False;
509     char buf[256];
510
511     (void)snprintf(buf, 256, "@server=%s", i18n_core->address.im_name);
512     if ((atom = XInternAtom(dpy, buf, False)) == 0)
513         return False;
514     i18n_core->address.selection = atom;
515
516     if (XIM_Servers == None)
517         XIM_Servers = XInternAtom (dpy, XIM_SERVERS, False);
518     /*endif*/
519     XGetWindowProperty (dpy,
520                         root,
521                         XIM_Servers,
522                         0L,
523                         1000000L,
524                         False,
525                         XA_ATOM,
526                         &realtype,
527                         &realformat,
528                         &length,
529                         &bytesafter,
530                         (unsigned char **) (&data));
531     if (realtype != None && (realtype != XA_ATOM || realformat != 32)) {
532         if (data != NULL)
533             XFree ((char *) data);
534         return False;
535     }
536
537     found = False;
538     for (i = 0; i < length; i++) {
539         if (data[i] == atom) {
540             Window owner;
541             found = True;
542             if ((owner = XGetSelectionOwner (dpy, atom)) != ims_win) {
543                 if (owner == None  ||  forse == True)
544                     XSetSelectionOwner (dpy, atom, ims_win, CurrentTime);
545                 else
546                     return False;
547             }
548             break;
549         }
550     }
551
552     if (found == False) {
553         XSetSelectionOwner (dpy, atom, ims_win, CurrentTime);
554         XChangeProperty (dpy,
555                          root,
556                          XIM_Servers,
557                          XA_ATOM,
558                          32,
559                          PropModePrepend,
560                          (unsigned char *) &atom,
561                          1);
562     }
563     else {
564         /* 
565          * We always need to generate the PropertyNotify to the Root Window 
566          */
567         XChangeProperty (dpy,
568                          root,
569                          XIM_Servers,
570                          XA_ATOM,
571                          32,
572                          PropModePrepend,
573                          (unsigned char *) data,
574                          0);
575     }
576     if (data != NULL)
577         XFree ((char *) data);
578     
579     /* Intern "LOCALES" and "TRANSOPORT" Target Atoms */
580     i18n_core->address.Localename = XInternAtom (dpy, LOCALES, False);
581     i18n_core->address.Transportname = XInternAtom (dpy, TRANSPORT, False);
582     return (XGetSelectionOwner (dpy, atom) == ims_win);
583 }
584
585 static int DeleteXi18nAtom(Xi18n i18n_core)
586 {
587     Display *dpy = i18n_core->address.dpy;
588     Window root = RootWindow (dpy, DefaultScreen (dpy));
589     Atom realtype;
590     int realformat;
591     unsigned long bytesafter;
592     long *data=NULL;
593     unsigned long length;
594     Atom atom;
595     int i, ret;
596     int found;
597     char buf[256];
598
599     (void)snprintf(buf, 256, "@server=%s", i18n_core->address.im_name);
600     if ((atom = XInternAtom(dpy, buf, False)) == 0)
601         return False;
602     i18n_core->address.selection = atom;
603
604     if (XIM_Servers == None)
605         XIM_Servers = XInternAtom (dpy, XIM_SERVERS, False);
606     XGetWindowProperty (dpy,
607                         root,
608                         XIM_Servers,
609                         0L,
610                         1000000L,
611                         False,
612                         XA_ATOM,
613                         &realtype,
614                         &realformat,
615                         &length,
616                         &bytesafter,
617                         (unsigned char **) (&data));
618     if (realtype != XA_ATOM || realformat != 32) {
619         if (data != NULL)
620             XFree ((char *) data);
621         return False;
622     }
623
624     found = False;
625     for (i = 0; i < length; i++) {
626         if (data[i] == atom) {
627             found = True;
628             break;
629         }
630     }
631
632     if (found == True) {
633         for (i=i+1; i<length; i++)
634             data[i-1] = data[i];
635         XChangeProperty (dpy,
636                          root,
637                          XIM_Servers,
638                          XA_ATOM,
639                          32,
640                          PropModeReplace,
641                          (unsigned char *)data,
642                          length-1);
643         ret = True;
644     }
645     else {
646         XChangeProperty (dpy,
647                          root,
648                          XIM_Servers,
649                          XA_ATOM,
650                          32,
651                          PropModePrepend,
652                          (unsigned char *)data,
653                          0);
654         ret = False;
655     }
656     if (data != NULL)
657         XFree ((char *) data);
658     return ret;
659 }
660
661
662 /* XIM protocol methods */
663 static void *xi18n_setup (Display *dpy, XIMArg *args)
664 {
665     Xi18n i18n_core;
666     CARD16 endian = 1;
667
668     if ((i18n_core = (Xi18n) malloc (sizeof (Xi18nCore))) == (Xi18n) NULL)
669         return NULL;
670     /*endif*/
671     
672     memset (i18n_core, 0, sizeof (Xi18nCore));
673
674     i18n_core->address.dpy = dpy;
675
676     if (ParseArgs (i18n_core, I18N_OPEN, args) != NULL)
677     {
678         XFree (i18n_core);
679         return NULL;
680     }
681     /*endif*/
682     if (*(char *) &endian)
683         i18n_core->address.im_byteOrder = 'l';
684     else
685         i18n_core->address.im_byteOrder = 'B';
686     /*endif*/
687     
688     /* install IMAttr and ICAttr list in i18n_core */
689     _Xi18nInitAttrList (i18n_core);
690
691     /* install IMExtension list in i18n_core */
692     _Xi18nInitExtension (i18n_core);
693
694     return i18n_core;
695 }
696
697 static void ReturnSelectionNotify (Xi18n i18n_core, XSelectionRequestEvent *ev)
698 {
699     XEvent event;
700     Display *dpy = i18n_core->address.dpy;
701     char buf[4096];
702
703     event.type = SelectionNotify;
704     event.xselection.requestor = ev->requestor;
705     event.xselection.selection = ev->selection;
706     event.xselection.target = ev->target;
707     event.xselection.time = ev->time;
708     event.xselection.property = ev->property;
709     if (ev->target == i18n_core->address.Localename)
710     {
711         snprintf (buf, 4096, "@locale=%s", i18n_core->address.im_locale);
712     }
713     else if (ev->target == i18n_core->address.Transportname)
714     {
715         snprintf (buf, 4096, "@transport=%s", i18n_core->address.im_addr);
716     }
717     /*endif*/
718     XChangeProperty (dpy,
719                      event.xselection.requestor,
720                      ev->target,
721                      ev->target,
722                      8,
723                      PropModeReplace,
724                      (unsigned char *) buf,
725                      strlen (buf));
726     XSendEvent (dpy, event.xselection.requestor, False, NoEventMask, &event);
727     XFlush (i18n_core->address.dpy);
728 }
729
730 static Bool WaitXSelectionRequest (Display *dpy,
731                                    Window win,
732                                    XEvent *ev,
733                                    XPointer client_data)
734 {
735     XIMS ims = (XIMS) client_data;
736     Xi18n i18n_core = ims->protocol;
737
738     if (((XSelectionRequestEvent *) ev)->selection
739         == i18n_core->address.selection)
740     {
741         ReturnSelectionNotify (i18n_core, (XSelectionRequestEvent *) ev);
742         return True;
743     }
744     /*endif*/
745     return False;
746 }
747
748 static Status xi18n_openIM(XIMS ims)
749 {
750     Xi18n i18n_core = ims->protocol;
751     Display *dpy = i18n_core->address.dpy;
752
753     if (!CheckIMName (i18n_core)
754         ||
755         !SetXi18nSelectionOwner (i18n_core)
756         ||
757         !i18n_core->methods.begin (ims))
758     {
759         XFree (i18n_core->address.im_name);
760         XFree (i18n_core->address.im_locale);
761         XFree (i18n_core->address.im_addr);
762         XFree (i18n_core);
763         return False;
764     }
765     /*endif*/
766
767     _XRegisterFilterByType (dpy,
768                             i18n_core->address.im_window,
769                             SelectionRequest,
770                             SelectionRequest,
771                             WaitXSelectionRequest,
772                             (XPointer)ims);
773     XFlush(dpy);
774     return True;
775 }
776
777 static Status xi18n_closeIM(XIMS ims)
778 {
779     Xi18n i18n_core = ims->protocol;
780     Display *dpy = i18n_core->address.dpy;
781
782     DeleteXi18nAtom(i18n_core);
783     if (!i18n_core->methods.end (ims))
784         return False;
785     
786     _XUnregisterFilter (dpy,
787                         i18n_core->address.im_window,
788                         WaitXSelectionRequest,
789                         (XPointer)ims);
790     XFree (i18n_core->address.im_name);
791     XFree (i18n_core->address.im_locale);
792     XFree (i18n_core->address.im_addr);
793     XFree (i18n_core);
794     return True;
795 }
796
797 static char *xi18n_setIMValues (XIMS ims, XIMArg *args)
798 {
799     Xi18n i18n_core = ims->protocol;
800     char *ret;
801
802     if ((ret = ParseArgs (i18n_core, I18N_SET, args)) != NULL)
803         return ret;
804     /*endif*/
805     return NULL;
806 }
807
808 static char *xi18n_getIMValues (XIMS ims, XIMArg *args)
809 {
810     Xi18n i18n_core = ims->protocol;
811     char *ret;
812
813     if ((ret = ParseArgs (i18n_core, I18N_GET, args)) != NULL)
814         return ret;
815     /*endif*/
816     return NULL;
817 }
818
819 static void EventToWireEvent (XEvent *ev, xEvent *event,
820                               CARD16 *serial, Bool byte_swap)
821 {
822     FrameMgr fm;
823     extern XimFrameRec wire_keyevent_fr[];
824     extern XimFrameRec short_fr[];
825     BYTE b;
826     CARD16 c16;
827     CARD32 c32;
828
829     *serial = (CARD16)(ev->xany.serial >> 16);
830     switch (ev->type) {
831       case KeyPress:
832       case KeyRelease:
833         {
834             XKeyEvent *kev = (XKeyEvent*)ev;
835             /* create FrameMgr */
836             fm = FrameMgrInit(wire_keyevent_fr, (char *)(&(event->u)), byte_swap);
837
838             /* set values */
839             b = (BYTE)kev->type;          FrameMgrPutToken(fm, b);
840             b = (BYTE)kev->keycode;       FrameMgrPutToken(fm, b);
841             c16 = (CARD16)(kev->serial & (unsigned long)0xffff);
842                                           FrameMgrPutToken(fm, c16);
843             c32 = (CARD32)kev->time;      FrameMgrPutToken(fm, c32);
844             c32 = (CARD32)kev->root;      FrameMgrPutToken(fm, c32);
845             c32 = (CARD32)kev->window;    FrameMgrPutToken(fm, c32);
846             c32 = (CARD32)kev->subwindow; FrameMgrPutToken(fm, c32);
847             c16 = (CARD16)kev->x_root;    FrameMgrPutToken(fm, c16);
848             c16 = (CARD16)kev->y_root;    FrameMgrPutToken(fm, c16);
849             c16 = (CARD16)kev->x;         FrameMgrPutToken(fm, c16);
850             c16 = (CARD16)kev->y;         FrameMgrPutToken(fm, c16);
851             c16 = (CARD16)kev->state;     FrameMgrPutToken(fm, c16);
852             b = (BYTE)kev->same_screen;   FrameMgrPutToken(fm, b);
853         }
854         break;
855       default:
856           /* create FrameMgr */
857           fm = FrameMgrInit(short_fr, (char *)(&(event->u.u.sequenceNumber)),
858                             byte_swap);
859           c16 = (CARD16)(ev->xany.serial & (unsigned long)0xffff);
860           FrameMgrPutToken(fm, c16);
861           break;
862     }
863     /* free FrameMgr */
864     FrameMgrFree(fm);
865 }
866
867 static Status xi18n_forwardEvent (XIMS ims, XPointer xp)
868 {
869     Xi18n i18n_core = ims->protocol;
870     IMForwardEventStruct *call_data = (IMForwardEventStruct *)xp;
871     FrameMgr fm;
872     extern XimFrameRec forward_event_fr[];
873     register int total_size;
874     unsigned char *reply = NULL;
875     unsigned char *replyp;
876     CARD16 serial;
877     int event_size;
878     Xi18nClient *client;
879
880     client = (Xi18nClient *) _Xi18nFindClient (i18n_core, call_data->connect_id);
881
882     /* create FrameMgr */
883     fm = FrameMgrInit (forward_event_fr,
884                        NULL,
885                        _Xi18nNeedSwap (i18n_core, call_data->connect_id));
886
887     total_size = FrameMgrGetTotalSize (fm);
888     event_size = sizeof (xEvent);
889     reply = (unsigned char *) malloc (total_size + event_size);
890     if (!reply)
891     {
892         _Xi18nSendMessage (ims,
893                            call_data->connect_id,
894                            XIM_ERROR,
895                            0,
896                            0,
897                            0);
898         return False;
899     }
900     /*endif*/
901     memset (reply, 0, total_size + event_size);
902     FrameMgrSetBuffer (fm, reply);
903     replyp = reply;
904
905     call_data->sync_bit = 1;    /* always sync */
906     client->sync = True;
907
908     FrameMgrPutToken (fm, call_data->connect_id);
909     FrameMgrPutToken (fm, call_data->icid);
910     FrameMgrPutToken (fm, call_data->sync_bit);
911
912     replyp += total_size;
913     EventToWireEvent (&(call_data->event),
914                       (xEvent *) replyp,
915                       &serial,
916                       _Xi18nNeedSwap (i18n_core, call_data->connect_id));
917
918     FrameMgrPutToken (fm, serial);
919
920     _Xi18nSendMessage (ims,
921                        call_data->connect_id,
922                        XIM_FORWARD_EVENT,
923                        0,
924                        reply,
925                        total_size + event_size);
926
927     XFree (reply);
928     FrameMgrFree (fm);
929
930     return True;
931 }
932
933 static Status xi18n_commit (XIMS ims, XPointer xp)
934 {
935     Xi18n i18n_core = ims->protocol;
936     IMCommitStruct *call_data = (IMCommitStruct *)xp;
937     FrameMgr fm;
938     extern XimFrameRec commit_chars_fr[];
939     extern XimFrameRec commit_both_fr[];
940     register int total_size;
941     unsigned char *reply = NULL;
942     CARD16 str_length;
943
944     call_data->flag |= XimSYNCHRONUS;  /* always sync */
945
946     if (!(call_data->flag & XimLookupKeySym)
947         &&
948         (call_data->flag & XimLookupChars))
949     {
950         fm = FrameMgrInit (commit_chars_fr,
951                            NULL,
952                            _Xi18nNeedSwap (i18n_core, call_data->connect_id));
953
954         /* set length of STRING8 */
955         str_length = strlen (call_data->commit_string);
956         FrameMgrSetSize (fm, str_length);
957         total_size = FrameMgrGetTotalSize (fm);
958         reply = (unsigned char *) malloc (total_size);
959         if (!reply)
960         {
961             _Xi18nSendMessage (ims,
962                                call_data->connect_id,
963                                XIM_ERROR,
964                                0,
965                                0,
966                                0);
967             return False;
968         }
969         /*endif*/
970         memset (reply, 0, total_size);
971         FrameMgrSetBuffer (fm, reply);
972
973         str_length = FrameMgrGetSize (fm);
974         FrameMgrPutToken (fm, call_data->connect_id);
975         FrameMgrPutToken (fm, call_data->icid);
976         FrameMgrPutToken (fm, call_data->flag);
977         FrameMgrPutToken (fm, str_length);
978         FrameMgrPutToken (fm, call_data->commit_string);
979     }
980     else
981     {
982         fm = FrameMgrInit (commit_both_fr,
983                            NULL,
984                            _Xi18nNeedSwap (i18n_core, call_data->connect_id));
985         /* set length of STRING8 */
986         str_length = strlen (call_data->commit_string);
987         if (str_length > 0)
988             FrameMgrSetSize (fm, str_length);
989         /*endif*/
990         total_size = FrameMgrGetTotalSize (fm);
991         reply = (unsigned char *) malloc (total_size);
992         if (!reply)
993         {
994             _Xi18nSendMessage (ims,
995                                call_data->connect_id,
996                                XIM_ERROR,
997                                0,
998                                0,
999                                0);
1000             return False;
1001         }
1002         /*endif*/
1003         FrameMgrSetBuffer (fm, reply);
1004         FrameMgrPutToken (fm, call_data->connect_id);
1005         FrameMgrPutToken (fm, call_data->icid);
1006         FrameMgrPutToken (fm, call_data->flag);
1007         FrameMgrPutToken (fm, call_data->keysym);
1008         if (str_length > 0)
1009         {
1010             str_length = FrameMgrGetSize (fm);
1011             FrameMgrPutToken (fm, str_length);
1012             FrameMgrPutToken (fm, call_data->commit_string);
1013         }
1014         /*endif*/
1015     }
1016     /*endif*/
1017     _Xi18nSendMessage (ims,
1018                        call_data->connect_id,
1019                        XIM_COMMIT,
1020                        0,
1021                        reply,
1022                        total_size);
1023     FrameMgrFree (fm);
1024     XFree (reply);
1025
1026     return True;
1027 }
1028
1029 static int xi18n_callCallback (XIMS ims, XPointer xp)
1030 {
1031     IMProtocol *call_data = (IMProtocol *)xp;
1032     switch (call_data->major_code)
1033     {
1034     case XIM_GEOMETRY:
1035         return _Xi18nGeometryCallback (ims, call_data);
1036
1037     case XIM_PREEDIT_START:
1038         return _Xi18nPreeditStartCallback (ims, call_data);
1039
1040     case XIM_PREEDIT_DRAW:
1041         return _Xi18nPreeditDrawCallback (ims, call_data);
1042
1043     case XIM_PREEDIT_CARET:
1044         return _Xi18nPreeditCaretCallback (ims, call_data);
1045
1046     case XIM_PREEDIT_DONE:
1047         return _Xi18nPreeditDoneCallback (ims, call_data);
1048
1049     case XIM_STATUS_START:
1050         return _Xi18nStatusStartCallback (ims, call_data);
1051
1052     case XIM_STATUS_DRAW:
1053         return _Xi18nStatusDrawCallback (ims, call_data);
1054
1055     case XIM_STATUS_DONE:
1056         return _Xi18nStatusDoneCallback (ims, call_data);
1057
1058     case XIM_STR_CONVERSION:
1059         return _Xi18nStringConversionCallback (ims, call_data);
1060     }
1061     /*endswitch*/
1062     return False;
1063 }
1064
1065 /* preeditStart and preeditEnd are used only for Dynamic Event Flow. */
1066 static int xi18n_preeditStart (XIMS ims, XPointer xp)
1067 {
1068     IMProtocol *call_data = (IMProtocol *)xp;
1069     Xi18n i18n_core = ims->protocol;
1070     IMPreeditStateStruct *preedit_state =
1071         (IMPreeditStateStruct *) &call_data->preedit_state;
1072     long mask;
1073     int on_key_num = i18n_core->address.on_keys.count_keys;
1074     int off_key_num = i18n_core->address.off_keys.count_keys;
1075
1076     if (on_key_num == 0  &&  off_key_num == 0)
1077         return False;
1078     /*endif*/
1079     if (i18n_core->address.imvalue_mask & I18N_FILTERMASK)
1080         mask = i18n_core->address.filterevent_mask;
1081     else
1082         mask = DEFAULT_FILTER_MASK;
1083     /*endif*/
1084     _Xi18nSetEventMask (ims,
1085                         preedit_state->connect_id,
1086                         preedit_state->connect_id,
1087                         preedit_state->icid,
1088                         mask,
1089                         ~mask);
1090     return True;
1091 }
1092
1093 static int xi18n_preeditEnd (XIMS ims, XPointer xp)
1094 {
1095     IMProtocol *call_data = (IMProtocol *)xp;
1096     Xi18n i18n_core = ims->protocol;
1097     int on_key_num = i18n_core->address.on_keys.count_keys;
1098     int off_key_num = i18n_core->address.off_keys.count_keys;
1099     IMPreeditStateStruct *preedit_state;
1100
1101     preedit_state = (IMPreeditStateStruct *) &call_data->preedit_state;
1102
1103     if (on_key_num == 0  &&  off_key_num == 0)
1104         return False;
1105     /*endif*/
1106     
1107     _Xi18nSetEventMask (ims,
1108                         preedit_state->connect_id,
1109                         preedit_state->connect_id,
1110                         preedit_state->icid,
1111                         0,
1112                         0);
1113     return True;
1114 }
1115
1116 static int xi18n_syncXlib (XIMS ims, XPointer xp)
1117 {
1118     IMProtocol *call_data = (IMProtocol *)xp;
1119     Xi18n i18n_core = ims->protocol;
1120     IMSyncXlibStruct *sync_xlib;
1121
1122     extern XimFrameRec sync_fr[];
1123     FrameMgr fm;
1124     CARD16 connect_id = call_data->any.connect_id;
1125     int total_size;
1126     unsigned char *reply;
1127
1128     sync_xlib = (IMSyncXlibStruct *) &call_data->sync_xlib;
1129     fm = FrameMgrInit (sync_fr, NULL,
1130                        _Xi18nNeedSwap (i18n_core, connect_id));
1131     total_size = FrameMgrGetTotalSize(fm);
1132     reply = (unsigned char *) malloc (total_size);
1133     if (!reply) {
1134         _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
1135         return False;
1136     }
1137     memset (reply, 0, total_size);
1138     FrameMgrSetBuffer (fm, reply);
1139
1140     /* input input-method ID */
1141     FrameMgrPutToken (fm, connect_id);
1142     /* input input-context ID */
1143     FrameMgrPutToken (fm, sync_xlib->icid);
1144     _Xi18nSendMessage (ims, connect_id, XIM_SYNC, 0, reply, total_size);
1145
1146     FrameMgrFree (fm);
1147     XFree(reply);
1148     return True;
1149 }
1150