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