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->on_keys.keylist != NULL)
254 		    free(address->on_keys.keylist);
255 
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)snprintf(buf, sizeof(buf), "@server=%s", i18n_core->address.im_name);
512     buf[sizeof(buf) - 1] = '\0';
513     if ((atom = XInternAtom(dpy, buf, False)) == 0)
514         return False;
515     i18n_core->address.selection = atom;
516 
517     if (XIM_Servers == None)
518         XIM_Servers = XInternAtom (dpy, XIM_SERVERS, False);
519     /*endif*/
520     XGetWindowProperty (dpy,
521                         root,
522                         XIM_Servers,
523                         0L,
524                         1000000L,
525                         False,
526                         XA_ATOM,
527                         &realtype,
528                         &realformat,
529                         &length,
530                         &bytesafter,
531                         (unsigned char **) (&data));
532     if (realtype != None && (realtype != XA_ATOM || realformat != 32)) {
533         if (data != NULL)
534             XFree ((char *) data);
535         return False;
536     }
537 
538     found = False;
539     for (i = 0; i < length; i++) {
540         if (data[i] == atom) {
541             Window owner;
542             found = True;
543             if ((owner = XGetSelectionOwner (dpy, atom)) != ims_win) {
544                 if (owner == None  ||  forse == True)
545                     XSetSelectionOwner (dpy, atom, ims_win, CurrentTime);
546                 else
547                     return False;
548             }
549             break;
550         }
551     }
552 
553     if (found == False) {
554         XSetSelectionOwner (dpy, atom, ims_win, CurrentTime);
555         XChangeProperty (dpy,
556                          root,
557                          XIM_Servers,
558                          XA_ATOM,
559                          32,
560                          PropModePrepend,
561                          (unsigned char *) &atom,
562                          1);
563     }
564     else {
565 	/*
566 	 * We always need to generate the PropertyNotify to the Root Window
567 	 */
568         XChangeProperty (dpy,
569                          root,
570                          XIM_Servers,
571                          XA_ATOM,
572                          32,
573                          PropModePrepend,
574                          (unsigned char *) data,
575                          0);
576     }
577     if (data != NULL)
578         XFree ((char *) data);
579 
580     /* Intern "LOCALES" and "TRANSOPORT" Target Atoms */
581     i18n_core->address.Localename = XInternAtom (dpy, LOCALES, False);
582     i18n_core->address.Transportname = XInternAtom (dpy, TRANSPORT, False);
583     return (XGetSelectionOwner (dpy, atom) == ims_win);
584 }
585 
DeleteXi18nAtom(Xi18n i18n_core)586 static int DeleteXi18nAtom(Xi18n i18n_core)
587 {
588     Display *dpy = i18n_core->address.dpy;
589     Window root = RootWindow (dpy, DefaultScreen (dpy));
590     Atom realtype;
591     int realformat;
592     unsigned long bytesafter;
593     long *data=NULL;
594     unsigned long length;
595     Atom atom;
596     int i, ret;
597     int found;
598     char buf[256];
599 
600     (void)snprintf(buf, sizeof(buf), "@server=%s", i18n_core->address.im_name);
601     buf[sizeof(buf) - 1] = '\0';
602     if ((atom = XInternAtom(dpy, buf, False)) == 0)
603         return False;
604     i18n_core->address.selection = atom;
605 
606     if (XIM_Servers == None)
607         XIM_Servers = XInternAtom (dpy, XIM_SERVERS, False);
608     XGetWindowProperty (dpy,
609                         root,
610                         XIM_Servers,
611                         0L,
612                         1000000L,
613                         False,
614                         XA_ATOM,
615                         &realtype,
616                         &realformat,
617                         &length,
618                         &bytesafter,
619                         (unsigned char **) (&data));
620     if (realtype != XA_ATOM || realformat != 32) {
621         if (data != NULL)
622             XFree ((char *) data);
623         return False;
624     }
625 
626     found = False;
627     for (i = 0; i < length; i++) {
628         if (data[i] == atom) {
629             found = True;
630             break;
631         }
632     }
633 
634     if (found == True) {
635         for (i=i+1; i<length; i++)
636             data[i-1] = data[i];
637         XChangeProperty (dpy,
638                          root,
639                          XIM_Servers,
640                          XA_ATOM,
641                          32,
642                          PropModeReplace,
643                          (unsigned char *)data,
644                          length-1);
645         ret = True;
646     }
647     else {
648         XChangeProperty (dpy,
649                          root,
650                          XIM_Servers,
651                          XA_ATOM,
652                          32,
653                          PropModePrepend,
654                          (unsigned char *)data,
655                          0);
656         ret = False;
657     }
658     if (data != NULL)
659         XFree ((char *) data);
660     return ret;
661 }
662 
663 
664 /* XIM protocol methods */
xi18n_setup(Display * dpy,XIMArg * args)665 static void *xi18n_setup (Display *dpy, XIMArg *args)
666 {
667     Xi18n i18n_core;
668     CARD16 endian = 1;
669 
670     if ((i18n_core = (Xi18n) malloc (sizeof (Xi18nCore))) == (Xi18n) NULL)
671         return NULL;
672     /*endif*/
673 
674     memset (i18n_core, 0, sizeof (Xi18nCore));
675 
676     i18n_core->address.dpy = dpy;
677 
678     if (ParseArgs (i18n_core, I18N_OPEN, args) != NULL)
679     {
680         free (i18n_core);
681         return NULL;
682     }
683     /*endif*/
684     if (*(char *) &endian)
685         i18n_core->address.im_byteOrder = 'l';
686     else
687         i18n_core->address.im_byteOrder = 'B';
688     /*endif*/
689 
690     /* install IMAttr and ICAttr list in i18n_core */
691     _Xi18nInitAttrList (i18n_core);
692 
693     /* install IMExtension list in i18n_core */
694     _Xi18nInitExtension (i18n_core);
695 
696     return i18n_core;
697 }
698 
ReturnSelectionNotify(Xi18n i18n_core,XSelectionRequestEvent * ev)699 static void ReturnSelectionNotify (Xi18n i18n_core, XSelectionRequestEvent *ev)
700 {
701     XEvent event;
702     Display *dpy = i18n_core->address.dpy;
703     char buf[4096];
704 
705     event.type = SelectionNotify;
706     event.xselection.requestor = ev->requestor;
707     event.xselection.selection = ev->selection;
708     event.xselection.target = ev->target;
709     event.xselection.time = ev->time;
710     event.xselection.property = ev->property;
711     if (ev->target == i18n_core->address.Localename)
712     {
713         snprintf (buf, sizeof(buf), "@locale=%s", i18n_core->address.im_locale);
714 	buf[sizeof(buf) - 1] = '\0';
715     }
716     else if (ev->target == i18n_core->address.Transportname)
717     {
718         snprintf (buf, sizeof(buf), "@transport=%s", i18n_core->address.im_addr);
719 	buf[sizeof(buf) - 1] = '\0';
720     }
721     /*endif*/
722     XChangeProperty (dpy,
723                      event.xselection.requestor,
724                      ev->target,
725                      ev->target,
726                      8,
727                      PropModeReplace,
728                      (unsigned char *) buf,
729                      strlen (buf));
730     XSendEvent (dpy, event.xselection.requestor, False, NoEventMask, &event);
731     XFlush (i18n_core->address.dpy);
732 }
733 
WaitXSelectionRequest(Display * dpy,Window win,XEvent * ev,XPointer client_data)734 static Bool WaitXSelectionRequest (Display *dpy,
735                                    Window win,
736                                    XEvent *ev,
737                                    XPointer client_data)
738 {
739     XIMS ims = (XIMS) client_data;
740     Xi18n i18n_core = ims->protocol;
741 
742     if (((XSelectionRequestEvent *) ev)->selection
743         == i18n_core->address.selection)
744     {
745         ReturnSelectionNotify (i18n_core, (XSelectionRequestEvent *) ev);
746         return True;
747     }
748     /*endif*/
749     return False;
750 }
751 
xi18n_openIM(XIMS ims)752 static Status xi18n_openIM(XIMS ims)
753 {
754     Xi18n i18n_core = ims->protocol;
755     Display *dpy = i18n_core->address.dpy;
756 
757     if (!CheckIMName (i18n_core)
758         ||
759         !SetXi18nSelectionOwner (i18n_core)
760         ||
761         !i18n_core->methods.begin (ims))
762     {
763         free (i18n_core->address.im_name);
764         free (i18n_core->address.im_locale);
765         free (i18n_core->address.im_addr);
766         free (i18n_core);
767         return False;
768     }
769     /*endif*/
770 
771     _XRegisterFilterByType (dpy,
772                             i18n_core->address.im_window,
773                             SelectionRequest,
774                             SelectionRequest,
775                             WaitXSelectionRequest,
776                             (XPointer)ims);
777     XFlush(dpy);
778     return True;
779 }
780 
xi18n_closeIM(XIMS ims)781 static Status xi18n_closeIM(XIMS ims)
782 {
783     Xi18n i18n_core = ims->protocol;
784     Display *dpy = i18n_core->address.dpy;
785 
786     /* remove all client connections */
787     while (i18n_core->address.clients != NULL) {
788 	int connect_id = i18n_core->address.clients->connect_id;
789 	i18n_core->methods.disconnect(ims, connect_id);
790     }
791 
792     DeleteXi18nAtom(i18n_core);
793     if (!i18n_core->methods.end (ims))
794         return False;
795 
796     _XUnregisterFilter (dpy,
797                         i18n_core->address.im_window,
798                         WaitXSelectionRequest,
799                         (XPointer)ims);
800 
801     _Xi18nDeleteAllClients(i18n_core);
802     _Xi18nDeleteFreeClients(i18n_core);
803 
804     free (i18n_core->address.im_name);
805     free (i18n_core->address.im_locale);
806     free (i18n_core->address.im_addr);
807     free (i18n_core->address.input_styles.supported_styles);
808     free (i18n_core->address.on_keys.keylist);
809     free (i18n_core->address.off_keys.keylist);
810     free (i18n_core->address.encoding_list.supported_encodings);
811     free (i18n_core->address.xim_attr);
812     free (i18n_core->address.xic_attr);
813     free (i18n_core->address.connect_addr);
814     free (i18n_core);
815     return True;
816 }
817 
xi18n_setIMValues(XIMS ims,XIMArg * args)818 static char *xi18n_setIMValues (XIMS ims, XIMArg *args)
819 {
820     Xi18n i18n_core = ims->protocol;
821     char *ret;
822 
823     if ((ret = ParseArgs (i18n_core, I18N_SET, args)) != NULL)
824         return ret;
825     /*endif*/
826     return NULL;
827 }
828 
xi18n_getIMValues(XIMS ims,XIMArg * args)829 static char *xi18n_getIMValues (XIMS ims, XIMArg *args)
830 {
831     Xi18n i18n_core = ims->protocol;
832     char *ret;
833 
834     if ((ret = ParseArgs (i18n_core, I18N_GET, args)) != NULL)
835         return ret;
836     /*endif*/
837     return NULL;
838 }
839 
840 /* For byte swapping */
841 #define Swap16(n) \
842 	(((n) << 8 & 0xFF00) | \
843 	 ((n) >> 8 & 0xFF)     \
844 	)
845 #define Swap32(n) \
846         (((n) << 24 & 0xFF000000) | \
847          ((n) <<  8 & 0xFF0000) |   \
848          ((n) >>  8 & 0xFF00) |     \
849          ((n) >> 24 & 0xFF)         \
850         )
851 #define Swap64(n) \
852         (((n) << 56 & 0xFF00000000000000) | \
853          ((n) << 40 & 0xFF000000000000) |   \
854          ((n) << 24 & 0xFF0000000000) |     \
855          ((n) <<  8 & 0xFF00000000) |       \
856          ((n) >>  8 & 0xFF000000) |         \
857          ((n) >> 24 & 0xFF0000) |           \
858          ((n) >> 40 & 0xFF00) |             \
859          ((n) >> 56 & 0xFF)                 \
860         )
861 
EventToWireEvent(XEvent * ev,xEvent * event,CARD16 * serial,Bool need_swap)862 static void EventToWireEvent (XEvent *ev, xEvent *event, CARD16 *serial, Bool need_swap)
863 {
864     *serial = (CARD16) (ev->xany.serial >> 16);
865     event->u.u.sequenceNumber =
866         (CARD16) (ev->xany.serial & (unsigned long) 0xFFFF);
867 
868     switch (ev->type)
869     {
870     case KeyPress:
871     case KeyRelease:
872         {
873             XKeyEvent *kev = (XKeyEvent *) ev;
874 
875 	    if (need_swap) {
876 		event->u.u.type = ev->type;
877 		event->u.keyButtonPointer.root = Swap32(kev->root);
878 		event->u.keyButtonPointer.state = Swap16(kev->state);
879 		event->u.keyButtonPointer.time = Swap32(kev->time);
880 		event->u.keyButtonPointer.event = Swap32(kev->window);
881 		event->u.keyButtonPointer.child = Swap32(kev->subwindow);
882 		event->u.keyButtonPointer.eventX = Swap16(kev->x);
883 		event->u.keyButtonPointer.eventY = Swap16(kev->y);
884 		event->u.keyButtonPointer.rootX = Swap16(kev->x_root);
885 		event->u.keyButtonPointer.rootY = Swap16(kev->y_root);
886 		event->u.keyButtonPointer.sameScreen = kev->same_screen;
887 		event->u.u.detail = kev->keycode;
888 	    } else {
889 		event->u.u.type = ev->type;
890 		event->u.keyButtonPointer.root = kev->root;
891 		event->u.keyButtonPointer.state = kev->state;
892 		event->u.keyButtonPointer.time = kev->time;
893 		event->u.keyButtonPointer.event = kev->window;
894 		event->u.keyButtonPointer.child = kev->subwindow;
895 		event->u.keyButtonPointer.eventX = kev->x;
896 		event->u.keyButtonPointer.eventY = kev->y;
897 		event->u.keyButtonPointer.rootX = kev->x_root;
898 		event->u.keyButtonPointer.rootY = kev->y_root;
899 		event->u.keyButtonPointer.sameScreen = kev->same_screen;
900 		event->u.u.detail = kev->keycode;
901 	    }
902         }
903     }
904     /*endswitch*/
905 }
906 
xi18n_forwardEvent(XIMS ims,XPointer xp)907 static Status xi18n_forwardEvent (XIMS ims, XPointer xp)
908 {
909     Xi18n i18n_core = ims->protocol;
910     IMForwardEventStruct *call_data = (IMForwardEventStruct *)xp;
911     FrameMgr fm;
912     extern XimFrameRec forward_event_fr[];
913     register int total_size;
914     unsigned char *reply = NULL;
915     unsigned char *replyp;
916     CARD16 serial;
917     int event_size;
918     Xi18nClient *client;
919     Bool need_swap;
920 
921     client = (Xi18nClient *) _Xi18nFindClient (i18n_core, call_data->connect_id);
922 
923     /* create FrameMgr */
924     need_swap = _Xi18nNeedSwap (i18n_core, call_data->connect_id);
925     fm = FrameMgrInit (forward_event_fr,
926                        NULL,
927                        need_swap);
928 
929     total_size = FrameMgrGetTotalSize (fm);
930     event_size = sizeof (xEvent);
931     reply = (unsigned char *) malloc (total_size + event_size);
932     if (!reply)
933     {
934         _Xi18nSendMessage (ims,
935                            call_data->connect_id,
936                            XIM_ERROR,
937                            0,
938                            0,
939                            0);
940         return False;
941     }
942     /*endif*/
943     memset (reply, 0, total_size + event_size);
944     FrameMgrSetBuffer (fm, reply);
945     replyp = reply;
946 
947     call_data->sync_bit = 1; 	/* always sync */
948     client->sync = True;
949 
950     FrameMgrPutToken (fm, call_data->connect_id);
951     FrameMgrPutToken (fm, call_data->icid);
952     FrameMgrPutToken (fm, call_data->sync_bit);
953 
954     replyp += total_size;
955     EventToWireEvent (&(call_data->event), (xEvent *) replyp, &serial, need_swap);
956 
957     FrameMgrPutToken (fm, serial);
958 
959     _Xi18nSendMessage (ims,
960                        call_data->connect_id,
961                        XIM_FORWARD_EVENT,
962                        0,
963                        reply,
964                        total_size + event_size);
965 
966     free (reply);
967     FrameMgrFree (fm);
968 
969     return True;
970 }
971 
xi18n_commit(XIMS ims,XPointer xp)972 static Status xi18n_commit (XIMS ims, XPointer xp)
973 {
974     Xi18n i18n_core = ims->protocol;
975     IMCommitStruct *call_data = (IMCommitStruct *)xp;
976     FrameMgr fm;
977     extern XimFrameRec commit_chars_fr[];
978     extern XimFrameRec commit_both_fr[];
979     register int total_size;
980     unsigned char *reply = NULL;
981     CARD16 str_length;
982 
983     call_data->flag |= XimSYNCHRONUS;  /* always sync */
984 
985     if (!(call_data->flag & XimLookupKeySym)
986         &&
987         (call_data->flag & XimLookupChars))
988     {
989         fm = FrameMgrInit (commit_chars_fr,
990                            NULL,
991                            _Xi18nNeedSwap (i18n_core, call_data->connect_id));
992 
993         /* set length of STRING8 */
994         str_length = strlen (call_data->commit_string);
995         FrameMgrSetSize (fm, str_length);
996         total_size = FrameMgrGetTotalSize (fm);
997         reply = (unsigned char *) malloc (total_size);
998         if (!reply)
999         {
1000             _Xi18nSendMessage (ims,
1001                                call_data->connect_id,
1002                                XIM_ERROR,
1003                                0,
1004                                0,
1005                                0);
1006             return False;
1007         }
1008         /*endif*/
1009         memset (reply, 0, total_size);
1010         FrameMgrSetBuffer (fm, reply);
1011 
1012         str_length = FrameMgrGetSize (fm);
1013         FrameMgrPutToken (fm, call_data->connect_id);
1014         FrameMgrPutToken (fm, call_data->icid);
1015         FrameMgrPutToken (fm, call_data->flag);
1016         FrameMgrPutToken (fm, str_length);
1017         FrameMgrPutToken (fm, call_data->commit_string);
1018     }
1019     else
1020     {
1021         fm = FrameMgrInit (commit_both_fr,
1022                            NULL,
1023                            _Xi18nNeedSwap (i18n_core, call_data->connect_id));
1024         /* set length of STRING8 */
1025         str_length = strlen (call_data->commit_string);
1026         if (str_length > 0)
1027             FrameMgrSetSize (fm, str_length);
1028         /*endif*/
1029         total_size = FrameMgrGetTotalSize (fm);
1030         reply = (unsigned char *) malloc (total_size);
1031         if (!reply)
1032         {
1033             _Xi18nSendMessage (ims,
1034                                call_data->connect_id,
1035                                XIM_ERROR,
1036                                0,
1037                                0,
1038                                0);
1039             return False;
1040         }
1041         /*endif*/
1042         FrameMgrSetBuffer (fm, reply);
1043         FrameMgrPutToken (fm, call_data->connect_id);
1044         FrameMgrPutToken (fm, call_data->icid);
1045         FrameMgrPutToken (fm, call_data->flag);
1046         FrameMgrPutToken (fm, call_data->keysym);
1047         if (str_length > 0)
1048         {
1049             str_length = FrameMgrGetSize (fm);
1050             FrameMgrPutToken (fm, str_length);
1051             FrameMgrPutToken (fm, call_data->commit_string);
1052         }
1053         /*endif*/
1054     }
1055     /*endif*/
1056     _Xi18nSendMessage (ims,
1057                        call_data->connect_id,
1058                        XIM_COMMIT,
1059                        0,
1060                        reply,
1061                        total_size);
1062     FrameMgrFree (fm);
1063     free (reply);
1064 
1065     return True;
1066 }
1067 
xi18n_callCallback(XIMS ims,XPointer xp)1068 static int xi18n_callCallback (XIMS ims, XPointer xp)
1069 {
1070     IMProtocol *call_data = (IMProtocol *)xp;
1071     switch (call_data->major_code)
1072     {
1073     case XIM_GEOMETRY:
1074         return _Xi18nGeometryCallback (ims, call_data);
1075 
1076     case XIM_PREEDIT_START:
1077         return _Xi18nPreeditStartCallback (ims, call_data);
1078 
1079     case XIM_PREEDIT_DRAW:
1080         return _Xi18nPreeditDrawCallback (ims, call_data);
1081 
1082     case XIM_PREEDIT_CARET:
1083         return _Xi18nPreeditCaretCallback (ims, call_data);
1084 
1085     case XIM_PREEDIT_DONE:
1086         return _Xi18nPreeditDoneCallback (ims, call_data);
1087 
1088     case XIM_STATUS_START:
1089         return _Xi18nStatusStartCallback (ims, call_data);
1090 
1091     case XIM_STATUS_DRAW:
1092         return _Xi18nStatusDrawCallback (ims, call_data);
1093 
1094     case XIM_STATUS_DONE:
1095         return _Xi18nStatusDoneCallback (ims, call_data);
1096 
1097     case XIM_STR_CONVERSION:
1098         return _Xi18nStringConversionCallback (ims, call_data);
1099     }
1100     /*endswitch*/
1101     return False;
1102 }
1103 
1104 /* preeditStart and preeditEnd are used only for Dynamic Event Flow. */
xi18n_preeditStart(XIMS ims,XPointer xp)1105 static int xi18n_preeditStart (XIMS ims, XPointer xp)
1106 {
1107     IMProtocol *call_data = (IMProtocol *)xp;
1108     Xi18n i18n_core = ims->protocol;
1109     IMPreeditStateStruct *preedit_state =
1110         (IMPreeditStateStruct *) &call_data->preedit_state;
1111     long mask;
1112     int on_key_num = i18n_core->address.on_keys.count_keys;
1113     int off_key_num = i18n_core->address.off_keys.count_keys;
1114 
1115     if (on_key_num == 0  &&  off_key_num == 0)
1116         return False;
1117     /*endif*/
1118     if (i18n_core->address.imvalue_mask & I18N_FILTERMASK)
1119         mask = i18n_core->address.filterevent_mask;
1120     else
1121         mask = DEFAULT_FILTER_MASK;
1122     /*endif*/
1123     _Xi18nSetEventMask (ims,
1124                         preedit_state->connect_id,
1125                         preedit_state->connect_id,
1126                         preedit_state->icid,
1127                         mask,
1128                         ~mask);
1129     return True;
1130 }
1131 
xi18n_preeditEnd(XIMS ims,XPointer xp)1132 static int xi18n_preeditEnd (XIMS ims, XPointer xp)
1133 {
1134     IMProtocol *call_data = (IMProtocol *)xp;
1135     Xi18n i18n_core = ims->protocol;
1136     int on_key_num = i18n_core->address.on_keys.count_keys;
1137     int off_key_num = i18n_core->address.off_keys.count_keys;
1138     IMPreeditStateStruct *preedit_state;
1139 
1140     preedit_state = (IMPreeditStateStruct *) &call_data->preedit_state;
1141 
1142     if (on_key_num == 0  &&  off_key_num == 0)
1143         return False;
1144     /*endif*/
1145 
1146     _Xi18nSetEventMask (ims,
1147                         preedit_state->connect_id,
1148                         preedit_state->connect_id,
1149                         preedit_state->icid,
1150                         0,
1151                         0);
1152     return True;
1153 }
1154 
xi18n_syncXlib(XIMS ims,XPointer xp)1155 static int xi18n_syncXlib (XIMS ims, XPointer xp)
1156 {
1157     IMProtocol *call_data = (IMProtocol *)xp;
1158     Xi18n i18n_core = ims->protocol;
1159     IMSyncXlibStruct *sync_xlib;
1160 
1161     extern XimFrameRec sync_fr[];
1162     FrameMgr fm;
1163     CARD16 connect_id = call_data->any.connect_id;
1164     int total_size;
1165     unsigned char *reply;
1166 
1167     sync_xlib = (IMSyncXlibStruct *) &call_data->sync_xlib;
1168     fm = FrameMgrInit (sync_fr, NULL,
1169                        _Xi18nNeedSwap (i18n_core, connect_id));
1170     total_size = FrameMgrGetTotalSize(fm);
1171     reply = (unsigned char *) malloc (total_size);
1172     if (!reply) {
1173         _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
1174         return False;
1175     }
1176     memset (reply, 0, total_size);
1177     FrameMgrSetBuffer (fm, reply);
1178 
1179     /* input input-method ID */
1180     FrameMgrPutToken (fm, connect_id);
1181     /* input input-context ID */
1182     FrameMgrPutToken (fm, sync_xlib->icid);
1183     _Xi18nSendMessage (ims, connect_id, XIM_SYNC, 0, reply, total_size);
1184 
1185     FrameMgrFree (fm);
1186     free(reply);
1187     return True;
1188 }
1189 
1190