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 
GetInputStyles(Xi18n i18n_core,XIMStyles ** p_style)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 
GetOnOffKeys(Xi18n i18n_core,long mask,XIMTriggerKeys ** p_key)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 
GetEncodings(Xi18n i18n_core,XIMEncodings ** p_encoding)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 
ParseArgs(Xi18n i18n_core,int mode,XIMArg * args)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 
CheckIMName(Xi18n i18n_core)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 
SetXi18nSelectionOwner(Xi18n i18n_core)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)sprintf(buf, "@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 
DeleteXi18nAtom(Xi18n i18n_core)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)sprintf(buf, "@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 */
xi18n_setup(Display * dpy,XIMArg * args)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 
ReturnSelectionNotify(Xi18n i18n_core,XSelectionRequestEvent * ev)697 static void ReturnSelectionNotify (Xi18n i18n_core, XSelectionRequestEvent *ev)
698 {
699     XEvent event;
700     Display *dpy = i18n_core->address.dpy;
701     char buf[256];
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         sprintf (buf, "@locale=%s", i18n_core->address.im_locale);
712     }
713     else if (ev->target == i18n_core->address.Transportname)
714     {
715         sprintf (buf, "@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 
WaitXSelectionRequest(Display * dpy,Window win,XEvent * ev,XPointer client_data)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 
xi18n_openIM(XIMS ims)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 
xi18n_closeIM(XIMS ims)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 
xi18n_setIMValues(XIMS ims,XIMArg * args)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 
xi18n_getIMValues(XIMS ims,XIMArg * args)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 
EventToWireEvent(XEvent * ev,xEvent * event,CARD16 * serial)819 static void EventToWireEvent (XEvent *ev, xEvent *event, CARD16 *serial)
820 {
821     *serial = (CARD16) (ev->xany.serial >> 16);
822     event->u.u.sequenceNumber =
823         (CARD16) (ev->xany.serial & (unsigned long) 0xFFFF);
824 
825     switch (ev->type)
826     {
827     case KeyPress:
828     case KeyRelease:
829         {
830             XKeyEvent *kev = (XKeyEvent *) ev;
831 
832             event->u.u.type = ev->type;
833             event->u.keyButtonPointer.root = kev->root;
834             event->u.keyButtonPointer.state = kev->state;
835             event->u.keyButtonPointer.time = kev->time;
836             event->u.keyButtonPointer.event = kev->window;
837             event->u.keyButtonPointer.child = kev->subwindow;
838             event->u.keyButtonPointer.eventX = kev->x;
839             event->u.keyButtonPointer.eventY = kev->y;
840             event->u.keyButtonPointer.rootX = kev->x_root;
841             event->u.keyButtonPointer.rootY = kev->y_root;
842             event->u.keyButtonPointer.sameScreen = kev->same_screen;
843             event->u.u.detail = kev->keycode;
844         }
845     }
846     /*endswitch*/
847 }
848 
xi18n_forwardEvent(XIMS ims,XPointer xp)849 static Status xi18n_forwardEvent (XIMS ims, XPointer xp)
850 {
851     Xi18n i18n_core = ims->protocol;
852     IMForwardEventStruct *call_data = (IMForwardEventStruct *)xp;
853     FrameMgr fm;
854     extern XimFrameRec forward_event_fr[];
855     register int total_size;
856     unsigned char *reply = NULL;
857     unsigned char *replyp;
858     CARD16 serial;
859     int event_size;
860     Xi18nClient *client;
861 
862     client = (Xi18nClient *) _Xi18nFindClient (i18n_core, call_data->connect_id);
863 
864     /* create FrameMgr */
865     fm = FrameMgrInit (forward_event_fr,
866                        NULL,
867                        _Xi18nNeedSwap (i18n_core, call_data->connect_id));
868 
869     total_size = FrameMgrGetTotalSize (fm);
870     event_size = sizeof (xEvent);
871     reply = (unsigned char *) malloc (total_size + event_size);
872     if (!reply)
873     {
874         _Xi18nSendMessage (ims,
875                            call_data->connect_id,
876                            XIM_ERROR,
877                            0,
878                            0,
879                            0);
880         return False;
881     }
882     /*endif*/
883     memset (reply, 0, total_size + event_size);
884     FrameMgrSetBuffer (fm, reply);
885     replyp = reply;
886 
887     call_data->sync_bit = 1; 	/* always sync */
888     client->sync = True;
889 
890     FrameMgrPutToken (fm, call_data->connect_id);
891     FrameMgrPutToken (fm, call_data->icid);
892     FrameMgrPutToken (fm, call_data->sync_bit);
893 
894     replyp += total_size;
895     EventToWireEvent (&(call_data->event), (xEvent *) replyp, &serial);
896 
897     FrameMgrPutToken (fm, serial);
898 
899     _Xi18nSendMessage (ims,
900                        call_data->connect_id,
901                        XIM_FORWARD_EVENT,
902                        0,
903                        reply,
904                        total_size + event_size);
905 
906     XFree (reply);
907     FrameMgrFree (fm);
908 
909     return True;
910 }
911 
xi18n_commit(XIMS ims,XPointer xp)912 static Status xi18n_commit (XIMS ims, XPointer xp)
913 {
914     Xi18n i18n_core = ims->protocol;
915     IMCommitStruct *call_data = (IMCommitStruct *)xp;
916     FrameMgr fm;
917     extern XimFrameRec commit_chars_fr[];
918     extern XimFrameRec commit_both_fr[];
919     register int total_size;
920     unsigned char *reply = NULL;
921     CARD16 str_length;
922 
923     call_data->flag |= XimSYNCHRONUS;  /* always sync */
924 
925     if (!(call_data->flag & XimLookupKeySym)
926         &&
927         (call_data->flag & XimLookupChars))
928     {
929         fm = FrameMgrInit (commit_chars_fr,
930                            NULL,
931                            _Xi18nNeedSwap (i18n_core, call_data->connect_id));
932 
933         /* set length of STRING8 */
934         str_length = strlen (call_data->commit_string);
935         FrameMgrSetSize (fm, str_length);
936         total_size = FrameMgrGetTotalSize (fm);
937         reply = (unsigned char *) malloc (total_size);
938         if (!reply)
939         {
940             _Xi18nSendMessage (ims,
941                                call_data->connect_id,
942                                XIM_ERROR,
943                                0,
944                                0,
945                                0);
946             return False;
947         }
948         /*endif*/
949         memset (reply, 0, total_size);
950         FrameMgrSetBuffer (fm, reply);
951 
952         str_length = FrameMgrGetSize (fm);
953         FrameMgrPutToken (fm, call_data->connect_id);
954         FrameMgrPutToken (fm, call_data->icid);
955         FrameMgrPutToken (fm, call_data->flag);
956         FrameMgrPutToken (fm, str_length);
957         FrameMgrPutToken (fm, call_data->commit_string);
958     }
959     else
960     {
961         fm = FrameMgrInit (commit_both_fr,
962                            NULL,
963                            _Xi18nNeedSwap (i18n_core, call_data->connect_id));
964         /* set length of STRING8 */
965         str_length = strlen (call_data->commit_string);
966         if (str_length > 0)
967             FrameMgrSetSize (fm, str_length);
968         /*endif*/
969         total_size = FrameMgrGetTotalSize (fm);
970         reply = (unsigned char *) malloc (total_size);
971         if (!reply)
972         {
973             _Xi18nSendMessage (ims,
974                                call_data->connect_id,
975                                XIM_ERROR,
976                                0,
977                                0,
978                                0);
979             return False;
980         }
981         /*endif*/
982         FrameMgrSetBuffer (fm, reply);
983         FrameMgrPutToken (fm, call_data->connect_id);
984         FrameMgrPutToken (fm, call_data->icid);
985         FrameMgrPutToken (fm, call_data->flag);
986         FrameMgrPutToken (fm, call_data->keysym);
987         if (str_length > 0)
988         {
989             str_length = FrameMgrGetSize (fm);
990             FrameMgrPutToken (fm, str_length);
991             FrameMgrPutToken (fm, call_data->commit_string);
992         }
993         /*endif*/
994     }
995     /*endif*/
996     _Xi18nSendMessage (ims,
997                        call_data->connect_id,
998                        XIM_COMMIT,
999                        0,
1000                        reply,
1001                        total_size);
1002     FrameMgrFree (fm);
1003     XFree (reply);
1004 
1005     return True;
1006 }
1007 
xi18n_callCallback(XIMS ims,XPointer xp)1008 static int xi18n_callCallback (XIMS ims, XPointer xp)
1009 {
1010     IMProtocol *call_data = (IMProtocol *)xp;
1011     switch (call_data->major_code)
1012     {
1013     case XIM_GEOMETRY:
1014         return _Xi18nGeometryCallback (ims, call_data);
1015 
1016     case XIM_PREEDIT_START:
1017         return _Xi18nPreeditStartCallback (ims, call_data);
1018 
1019     case XIM_PREEDIT_DRAW:
1020         return _Xi18nPreeditDrawCallback (ims, call_data);
1021 
1022     case XIM_PREEDIT_CARET:
1023         return _Xi18nPreeditCaretCallback (ims, call_data);
1024 
1025     case XIM_PREEDIT_DONE:
1026         return _Xi18nPreeditDoneCallback (ims, call_data);
1027 
1028     case XIM_STATUS_START:
1029         return _Xi18nStatusStartCallback (ims, call_data);
1030 
1031     case XIM_STATUS_DRAW:
1032         return _Xi18nStatusDrawCallback (ims, call_data);
1033 
1034     case XIM_STATUS_DONE:
1035         return _Xi18nStatusDoneCallback (ims, call_data);
1036 
1037     case XIM_STR_CONVERSION:
1038         return _Xi18nStringConversionCallback (ims, call_data);
1039     }
1040     /*endswitch*/
1041     return False;
1042 }
1043 
1044 /* preeditStart and preeditEnd are used only for Dynamic Event Flow. */
xi18n_preeditStart(XIMS ims,XPointer xp)1045 static int xi18n_preeditStart (XIMS ims, XPointer xp)
1046 {
1047     IMProtocol *call_data = (IMProtocol *)xp;
1048     Xi18n i18n_core = ims->protocol;
1049     IMPreeditStateStruct *preedit_state =
1050         (IMPreeditStateStruct *) &call_data->preedit_state;
1051     long mask;
1052     int on_key_num = i18n_core->address.on_keys.count_keys;
1053     int off_key_num = i18n_core->address.off_keys.count_keys;
1054 
1055     if (on_key_num == 0  &&  off_key_num == 0)
1056         return False;
1057     /*endif*/
1058     if (i18n_core->address.imvalue_mask & I18N_FILTERMASK)
1059         mask = i18n_core->address.filterevent_mask;
1060     else
1061         mask = DEFAULT_FILTER_MASK;
1062     /*endif*/
1063     _Xi18nSetEventMask (ims,
1064                         preedit_state->connect_id,
1065                         preedit_state->connect_id,
1066                         preedit_state->icid,
1067                         mask,
1068                         ~mask);
1069     return True;
1070 }
1071 
xi18n_preeditEnd(XIMS ims,XPointer xp)1072 static int xi18n_preeditEnd (XIMS ims, XPointer xp)
1073 {
1074     IMProtocol *call_data = (IMProtocol *)xp;
1075     Xi18n i18n_core = ims->protocol;
1076     int on_key_num = i18n_core->address.on_keys.count_keys;
1077     int off_key_num = i18n_core->address.off_keys.count_keys;
1078     IMPreeditStateStruct *preedit_state;
1079 
1080     preedit_state = (IMPreeditStateStruct *) &call_data->preedit_state;
1081 
1082     if (on_key_num == 0  &&  off_key_num == 0)
1083         return False;
1084     /*endif*/
1085 
1086     _Xi18nSetEventMask (ims,
1087                         preedit_state->connect_id,
1088                         preedit_state->connect_id,
1089                         preedit_state->icid,
1090                         0,
1091                         0);
1092     return True;
1093 }
1094 
xi18n_syncXlib(XIMS ims,XPointer xp)1095 static int xi18n_syncXlib (XIMS ims, XPointer xp)
1096 {
1097     IMProtocol *call_data = (IMProtocol *)xp;
1098     Xi18n i18n_core = ims->protocol;
1099     IMSyncXlibStruct *sync_xlib;
1100 
1101     extern XimFrameRec sync_fr[];
1102     FrameMgr fm;
1103     CARD16 connect_id = call_data->any.connect_id;
1104     int total_size;
1105     unsigned char *reply;
1106 
1107     sync_xlib = (IMSyncXlibStruct *) &call_data->sync_xlib;
1108     fm = FrameMgrInit (sync_fr, NULL,
1109                        _Xi18nNeedSwap (i18n_core, connect_id));
1110     total_size = FrameMgrGetTotalSize(fm);
1111     reply = (unsigned char *) malloc (total_size);
1112     if (!reply) {
1113         _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
1114         return False;
1115     }
1116     memset (reply, 0, total_size);
1117     FrameMgrSetBuffer (fm, reply);
1118 
1119     /* input input-method ID */
1120     FrameMgrPutToken (fm, connect_id);
1121     /* input input-context ID */
1122     FrameMgrPutToken (fm, sync_xlib->icid);
1123     _Xi18nSendMessage (ims, connect_id, XIM_SYNC, 0, reply, total_size);
1124 
1125     FrameMgrFree (fm);
1126     XFree(reply);
1127     return True;
1128 }
1129 
1130