1 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
2 /******************************************************************
3 
4          Copyright 1994, 1995 by Sun Microsystems, Inc.
5          Copyright 1993, 1994 by Hewlett-Packard Company
6 
7 Permission to use, copy, modify, distribute, and sell this software
8 and its documentation for any purpose is hereby granted without fee,
9 provided that the above copyright notice appear in all copies and
10 that both that copyright notice and this permission notice appear
11 in supporting documentation, and that the name of Sun Microsystems, Inc.
12 and Hewlett-Packard not be used in advertising or publicity pertaining to
13 distribution of the software without specific, written prior permission.
14 Sun Microsystems, Inc. and Hewlett-Packard make no representations about
15 the suitability of this software for any purpose.  It is provided "as is"
16 without express or implied warranty.
17 
18 SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
19 WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
21 SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
22 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
23 RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
24 CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
25 IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26 
27   Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
28 
29     This version tidied and debugged by Steve Underwood May 1999
30 
31 ******************************************************************/
32 
33 #include "i18nMethod.h"
34 #include "FrameMgr.h"
35 #include "Xi18n.h"
36 #include "XimFunc.h"
37 #include <glib.h>
38 
39 /* How to generate SUPPORTED_LOCALES
40 #!/usr/bin/ruby
41 # -*- coding: utf-8 -*-
42 
43 require 'set'
44 
45 set = Set.new
46 
47 File.open("/usr/share/i18n/SUPPORTED", "r").each do |line|
48   set << line.split(/_| /)[0]
49 end
50 
51 puts set.to_a.join(",")
52 */
53 #define SUPPORTED_LOCALES \
54   "aa,af,agr,ak,am,an,anp,ar,ayc,az,as,ast,be,bem,ber,bg,bhb,bho,bi,bn,bo,"   \
55   "br,brx,bs,byn,ca,ce,chr,cmn,crh,cs,csb,cv,cy,da,de,doi,dsb,dv,dz,el,en,"   \
56   "eo,es,et,eu,fa,ff,fi,fil,fo,fr,fur,fy,ga,gd,gez,gl,gu,gv,ha,hak,he,hi,"    \
57   "hif,hne,hr,hsb,ht,hu,hy,ia,id,ig,ik,is,it,iu,ja,ka,kab,kk,kl,km,kn,ko,"    \
58   "kok,ks,ku,kw,ky,lb,lg,li,lij,ln,lo,lt,lv,lzh,mag,mai,mfe,mg,mhr,mi,miq,"   \
59   "mjw,mk,ml,mn,mni,mr,ms,mt,my,nan,nb,nds,ne,nhn,niu,nl,nn,nr,nso,oc,om,or," \
60   "os,pa,pap,pl,ps,pt,quz,raj,ro,ru,rw,sa,sah,sat,sc,sd,se,sgs,shn,shs,si,"   \
61   "sid,sk,sl,sm,so,sq,sr,ss,st,sv,sw,szl,ta,tcy,te,tg,th,the,ti,tig,tk,tl,"   \
62   "tn,to,tpi,tr,ts,tt,ug,uk,unm,ur,uz,ve,vi,wa,wae,wal,wo,xh,yi,yo,yue,yuw,"  \
63   "zh,zu"
64 
65 extern Xi18nClient *_Xi18nFindClient (NimfXim *, CARD16);
66 
67 #ifndef XIM_SERVERS
68 #define XIM_SERVERS "XIM_SERVERS"
69 #endif
70 static Atom XIM_Servers = None;
71 
SetXi18nSelectionOwner(NimfXim * xim,Window im_window)72 static int SetXi18nSelectionOwner (NimfXim *xim, Window im_window)
73 {
74     Window root = RootWindow (xim->display, DefaultScreen (xim->display));
75     Atom realtype;
76     int realformat;
77     unsigned long bytesafter;
78     long *data=NULL;
79     unsigned long length;
80     Atom atom;
81     int i;
82     int found;
83     int forse = False;
84 
85     if ((atom = XInternAtom (xim->display, "@server=nimf", False)) == 0)
86         return False;
87 
88     xim->address.selection = atom;
89 
90     if (XIM_Servers == None)
91         XIM_Servers = XInternAtom (xim->display, XIM_SERVERS, False);
92     /*endif*/
93     XGetWindowProperty (xim->display,
94                         root,
95                         XIM_Servers,
96                         0L,
97                         1000000L,
98                         False,
99                         XA_ATOM,
100                         &realtype,
101                         &realformat,
102                         &length,
103                         &bytesafter,
104                         (unsigned char **) (&data));
105     if (realtype != None && (realtype != XA_ATOM || realformat != 32)) {
106         if (data != NULL)
107             XFree ((char *) data);
108         return False;
109     }
110 
111     found = False;
112     for (i = 0; i < length; i++) {
113         if (data[i] == atom) {
114             Window owner;
115             found = True;
116             if ((owner = XGetSelectionOwner (xim->display, atom)) != im_window) {
117                 if (owner == None  ||  forse == True)
118                     XSetSelectionOwner (xim->display, atom, im_window, CurrentTime);
119                 else
120                     return False;
121             }
122             break;
123         }
124     }
125 
126     if (found == False) {
127         XSetSelectionOwner (xim->display, atom, im_window, CurrentTime);
128         XChangeProperty (xim->display,
129                          root,
130                          XIM_Servers,
131                          XA_ATOM,
132                          32,
133                          PropModePrepend,
134                          (unsigned char *) &atom,
135                          1);
136     }
137     else {
138 	/*
139 	 * We always need to generate the PropertyNotify to the Root Window
140 	 */
141         XChangeProperty (xim->display,
142                          root,
143                          XIM_Servers,
144                          XA_ATOM,
145                          32,
146                          PropModePrepend,
147                          (unsigned char *) data,
148                          0);
149     }
150     if (data != NULL)
151         XFree ((char *) data);
152 
153     /* Intern "LOCALES" and "TRANSOPORT" Target Atoms */
154     xim->address.Localename = XInternAtom (xim->display, LOCALES, False);
155     xim->address.Transportname = XInternAtom (xim->display, TRANSPORT, False);
156     return (XGetSelectionOwner (xim->display, atom) == im_window);
157 }
158 
DeleteXi18nAtom(NimfXim * xim)159 static int DeleteXi18nAtom (NimfXim *xim)
160 {
161     Window root = RootWindow (xim->display, DefaultScreen (xim->display));
162     Atom realtype;
163     int realformat;
164     unsigned long bytesafter;
165     long *data=NULL;
166     unsigned long length;
167     Atom atom;
168     int i, ret;
169     int found;
170 
171     if ((atom = XInternAtom (xim->display, "@server=nimf", False)) == 0)
172         return False;
173 
174     xim->address.selection = atom;
175 
176     if (XIM_Servers == None)
177         XIM_Servers = XInternAtom (xim->display, XIM_SERVERS, False);
178     XGetWindowProperty (xim->display,
179                         root,
180                         XIM_Servers,
181                         0L,
182                         1000000L,
183                         False,
184                         XA_ATOM,
185                         &realtype,
186                         &realformat,
187                         &length,
188                         &bytesafter,
189                         (unsigned char **) (&data));
190     if (realtype != XA_ATOM || realformat != 32) {
191         if (data != NULL)
192             XFree ((char *) data);
193         return False;
194     }
195 
196     found = False;
197     for (i = 0; i < length; i++) {
198         if (data[i] == atom) {
199             found = True;
200             break;
201         }
202     }
203 
204     if (found == True) {
205         for (i=i+1; i<length; i++)
206             data[i-1] = data[i];
207         XChangeProperty (xim->display,
208                          root,
209                          XIM_Servers,
210                          XA_ATOM,
211                          32,
212                          PropModeReplace,
213                          (unsigned char *)data,
214                          length-1);
215         ret = True;
216     }
217     else {
218         XChangeProperty (xim->display,
219                          root,
220                          XIM_Servers,
221                          XA_ATOM,
222                          32,
223                          PropModePrepend,
224                          (unsigned char *)data,
225                          0);
226         ret = False;
227     }
228     if (data != NULL)
229         XFree ((char *) data);
230     return ret;
231 }
232 
233 static void
ReturnSelectionNotify(NimfXim * xim,XSelectionRequestEvent * ev)234 ReturnSelectionNotify (NimfXim *xim, XSelectionRequestEvent *ev)
235 {
236   XEvent event;
237   const char *data = NULL;
238 
239   event.type = SelectionNotify;
240   event.xselection.requestor = ev->requestor;
241   event.xselection.selection = ev->selection;
242   event.xselection.target = ev->target;
243   event.xselection.time = ev->time;
244   event.xselection.property = ev->property;
245 
246   if (ev->target == xim->address.Localename)
247     data = "@locale=C" SUPPORTED_LOCALES;
248   else if (ev->target == xim->address.Transportname)
249     data = "@transport=X/";
250 
251   XChangeProperty (xim->display,
252                    event.xselection.requestor,
253                    ev->target,
254                    ev->target,
255                    8,
256                    PropModeReplace,
257                    (unsigned char *) data,
258                    strlen (data));
259   XSendEvent (xim->display, event.xselection.requestor, False, NoEventMask, &event);
260   XFlush (xim->display);
261 }
262 
263 Bool
WaitXSelectionRequest(NimfXim * xim,XEvent * ev)264 WaitXSelectionRequest (NimfXim *xim,
265                        XEvent  *ev)
266 {
267     if (((XSelectionRequestEvent *) ev)->selection == xim->address.selection)
268     {
269         ReturnSelectionNotify (xim, (XSelectionRequestEvent *) ev);
270         return True;
271     }
272 
273     return False;
274 }
275 
276 Status
xi18n_openIM(NimfXim * xim,Window im_window)277 xi18n_openIM (NimfXim *xim, Window im_window)
278 {
279   if (!SetXi18nSelectionOwner (xim, im_window))
280     return False;
281 
282   xim->_protocol = XInternAtom (xim->display, "_XIM_PROTOCOL", False);
283   xim->_xconnect = XInternAtom (xim->display, "_XIM_XCONNECT", False);
284 
285   XFlush (xim->display);
286   return True;
287 }
288 
xi18n_closeIM(NimfXim * xim)289 Status xi18n_closeIM (NimfXim *xim)
290 {
291     DeleteXi18nAtom (xim);
292     return True;
293 }
294 
EventToWireEvent(XEvent * ev,xEvent * event,CARD16 * serial,Bool byte_swap)295 static void EventToWireEvent (XEvent *ev, xEvent *event,
296 			      CARD16 *serial, Bool byte_swap)
297 {
298     FrameMgr fm;
299     extern XimFrameRec wire_keyevent_fr[];
300     extern XimFrameRec short_fr[];
301     BYTE b;
302     CARD16 c16;
303     CARD32 c32;
304 
305     *serial = (CARD16)(ev->xany.serial >> 16);
306     switch (ev->type) {
307       case KeyPress:
308       case KeyRelease:
309 	{
310 	    XKeyEvent *kev = (XKeyEvent*)ev;
311 	    /* create FrameMgr */
312 	    fm = FrameMgrInit(wire_keyevent_fr, (char *)(&(event->u)), byte_swap);
313 
314 	    /* set values */
315 	    b = (BYTE)kev->type;          FrameMgrPutToken(fm, b);
316 	    b = (BYTE)kev->keycode;       FrameMgrPutToken(fm, b);
317 	    c16 = (CARD16)(kev->serial & (unsigned long)0xffff);
318 					  FrameMgrPutToken(fm, c16);
319 	    c32 = (CARD32)kev->time;      FrameMgrPutToken(fm, c32);
320 	    c32 = (CARD32)kev->root;      FrameMgrPutToken(fm, c32);
321 	    c32 = (CARD32)kev->window;    FrameMgrPutToken(fm, c32);
322 	    c32 = (CARD32)kev->subwindow; FrameMgrPutToken(fm, c32);
323 	    c16 = (CARD16)kev->x_root;    FrameMgrPutToken(fm, c16);
324 	    c16 = (CARD16)kev->y_root;    FrameMgrPutToken(fm, c16);
325 	    c16 = (CARD16)kev->x;         FrameMgrPutToken(fm, c16);
326 	    c16 = (CARD16)kev->y;         FrameMgrPutToken(fm, c16);
327 	    c16 = (CARD16)kev->state;     FrameMgrPutToken(fm, c16);
328 	    b = (BYTE)kev->same_screen;   FrameMgrPutToken(fm, b);
329 	}
330 	break;
331       default:
332 	  /* create FrameMgr */
333 	  fm = FrameMgrInit(short_fr, (char *)(&(event->u.u.sequenceNumber)),
334 			    byte_swap);
335 	  c16 = (CARD16)(ev->xany.serial & (unsigned long)0xffff);
336 	  FrameMgrPutToken(fm, c16);
337 	  break;
338     }
339     /* free FrameMgr */
340     FrameMgrFree(fm);
341 }
342 
xi18n_forwardEvent(NimfXim * xim,XPointer xp)343 Status xi18n_forwardEvent (NimfXim *xim, XPointer xp)
344 {
345     IMForwardEventStruct *call_data = (IMForwardEventStruct *)xp;
346     FrameMgr fm;
347     extern XimFrameRec forward_event_fr[];
348     register int total_size;
349     unsigned char *reply = NULL;
350     unsigned char *replyp;
351     CARD16 serial;
352     int event_size;
353     Xi18nClient *client;
354 
355     client = (Xi18nClient *) _Xi18nFindClient (xim, call_data->connect_id);
356 
357     /* create FrameMgr */
358     fm = FrameMgrInit (forward_event_fr,
359                        NULL,
360                        _Xi18nNeedSwap (xim, call_data->connect_id));
361 
362     total_size = FrameMgrGetTotalSize (fm);
363     event_size = sizeof (xEvent);
364     reply = (unsigned char *) malloc (total_size + event_size);
365     if (!reply)
366     {
367         _Xi18nSendMessage (xim,
368                            call_data->connect_id,
369                            XIM_ERROR,
370                            0,
371                            0,
372                            0);
373         return False;
374     }
375     /*endif*/
376     memset (reply, 0, total_size + event_size);
377     FrameMgrSetBuffer (fm, reply);
378     replyp = reply;
379 
380     call_data->sync_bit = 1; 	/* always sync */
381     client->sync = True;
382 
383     FrameMgrPutToken (fm, call_data->connect_id);
384     FrameMgrPutToken (fm, call_data->icid);
385     FrameMgrPutToken (fm, call_data->sync_bit);
386 
387     replyp += total_size;
388     EventToWireEvent (&(call_data->event),
389                       (xEvent *) replyp,
390                       &serial,
391                       _Xi18nNeedSwap (xim, call_data->connect_id));
392 
393     FrameMgrPutToken (fm, serial);
394 
395     _Xi18nSendMessage (xim,
396                        call_data->connect_id,
397                        XIM_FORWARD_EVENT,
398                        0,
399                        reply,
400                        total_size + event_size);
401 
402     XFree (reply);
403     FrameMgrFree (fm);
404 
405     return True;
406 }
407 
xi18n_commit(NimfXim * xim,XPointer xp)408 Status xi18n_commit (NimfXim *xim, XPointer xp)
409 {
410     IMCommitStruct *call_data = (IMCommitStruct *)xp;
411     FrameMgr fm;
412     extern XimFrameRec commit_chars_fr[];
413     extern XimFrameRec commit_both_fr[];
414     register int total_size;
415     unsigned char *reply = NULL;
416     CARD16 str_length;
417 
418     call_data->flag |= XimSYNCHRONUS;  /* always sync */
419 
420     if (!(call_data->flag & XimLookupKeySym)
421         &&
422         (call_data->flag & XimLookupChars))
423     {
424         fm = FrameMgrInit (commit_chars_fr,
425                            NULL,
426                            _Xi18nNeedSwap (xim, call_data->connect_id));
427 
428         /* set length of STRING8 */
429         str_length = strlen (call_data->commit_string);
430         FrameMgrSetSize (fm, str_length);
431         total_size = FrameMgrGetTotalSize (fm);
432         reply = (unsigned char *) malloc (total_size);
433         if (!reply)
434         {
435             _Xi18nSendMessage (xim,
436                                call_data->connect_id,
437                                XIM_ERROR,
438                                0,
439                                0,
440                                0);
441             return False;
442         }
443         /*endif*/
444         memset (reply, 0, total_size);
445         FrameMgrSetBuffer (fm, reply);
446 
447         str_length = FrameMgrGetSize (fm);
448         FrameMgrPutToken (fm, call_data->connect_id);
449         FrameMgrPutToken (fm, call_data->icid);
450         FrameMgrPutToken (fm, call_data->flag);
451         FrameMgrPutToken (fm, str_length);
452         FrameMgrPutToken (fm, call_data->commit_string);
453     }
454     else
455     {
456         fm = FrameMgrInit (commit_both_fr,
457                            NULL,
458                            _Xi18nNeedSwap (xim, call_data->connect_id));
459         /* set length of STRING8 */
460         str_length = strlen (call_data->commit_string);
461         if (str_length > 0)
462             FrameMgrSetSize (fm, str_length);
463         /*endif*/
464         total_size = FrameMgrGetTotalSize (fm);
465         reply = (unsigned char *) malloc (total_size);
466         if (!reply)
467         {
468             _Xi18nSendMessage (xim,
469                                call_data->connect_id,
470                                XIM_ERROR,
471                                0,
472                                0,
473                                0);
474             return False;
475         }
476         /*endif*/
477         FrameMgrSetBuffer (fm, reply);
478         FrameMgrPutToken (fm, call_data->connect_id);
479         FrameMgrPutToken (fm, call_data->icid);
480         FrameMgrPutToken (fm, call_data->flag);
481         FrameMgrPutToken (fm, call_data->keysym);
482         if (str_length > 0)
483         {
484             str_length = FrameMgrGetSize (fm);
485             FrameMgrPutToken (fm, str_length);
486             FrameMgrPutToken (fm, call_data->commit_string);
487         }
488         /*endif*/
489     }
490     /*endif*/
491     _Xi18nSendMessage (xim,
492                        call_data->connect_id,
493                        XIM_COMMIT,
494                        0,
495                        reply,
496                        total_size);
497     FrameMgrFree (fm);
498     XFree (reply);
499 
500     return True;
501 }
502 
nimf_xim_call_callback(NimfXim * xim,XPointer xp)503 int nimf_xim_call_callback (NimfXim *xim, XPointer xp)
504 {
505     IMProtocol *call_data = (IMProtocol *)xp;
506     switch (call_data->major_code)
507     {
508     case XIM_GEOMETRY:
509         return _Xi18nGeometryCallback (xim, call_data);
510 
511     case XIM_PREEDIT_START:
512         return _Xi18nPreeditStartCallback (xim, call_data);
513 
514     case XIM_PREEDIT_DRAW:
515         return _Xi18nPreeditDrawCallback (xim, call_data);
516 
517     case XIM_PREEDIT_CARET:
518         return _Xi18nPreeditCaretCallback (xim, call_data);
519 
520     case XIM_PREEDIT_DONE:
521         return _Xi18nPreeditDoneCallback (xim, call_data);
522 
523     case XIM_STATUS_START:
524         return _Xi18nStatusStartCallback (xim, call_data);
525 
526     case XIM_STATUS_DRAW:
527         return _Xi18nStatusDrawCallback (xim, call_data);
528 
529     case XIM_STATUS_DONE:
530         return _Xi18nStatusDoneCallback (xim, call_data);
531 
532     case XIM_STR_CONVERSION:
533         return _Xi18nStringConversionCallback (xim, call_data);
534     }
535     /*endswitch*/
536     return False;
537 }
538