comparison lib/IMProto.c @ 0:92745d501b9a

initial import from kinput2-v3.1
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Mon, 08 Mar 2010 04:44:30 +0900
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:92745d501b9a
1 #ifndef lint
2 static char *rcsid = "$Id: IMProto.c,v 1.20 1999/04/12 08:52:23 ishisone Exp $";
3 #endif
4 /*-
5 * Copyright (c) 1991, 1994 Software Research Associates, Inc.
6 *
7 * Permission to use, copy, modify, and distribute this software and its
8 * documentation for any purpose and without fee is hereby granted, provided
9 * that the above copyright notice appear in all copies and that both that
10 * copyright notice and this permission notice appear in supporting
11 * documentation, and that the name of Software Research Associates not be
12 * used in advertising or publicity pertaining to distribution of the
13 * software without specific, written prior permission. Software Research
14 * Associates makes no representations about the suitability of this software
15 * for any purpose. It is provided "as is" without express or implied
16 * warranty.
17 *
18 * Author: Makoto Ishisone, Software Research Associates, Inc., Japan
19 */
20
21 /*
22 * X Input Method Protocol handler is considered to be still in
23 * beta testing phase. Current version has the following
24 * restrictions.
25 * - it does not support on-demand-synchronous method.
26 * - it does not support front-end model.
27 * - it does not SetIMValues operation.
28 * - it supports only X, local and TCP transports.
29 * Also, there might be various bugs.
30 */
31
32 #define DEBUG_VAR debug_IMProtocol
33
34 #include <ctype.h>
35 #include <X11/Xos.h>
36 #include <sys/stat.h>
37 #include <X11/IntrinsicP.h>
38 #include <X11/StringDefs.h>
39 #include <X11/Xatom.h>
40 #include <X11/Xmu/SysUtil.h>
41 #include "IMProtoP.h"
42 #include "ParseKey.h"
43 #include "InputConv.h"
44 #include "im.h"
45
46
47 #define SERVER_NAME "kinput2"
48 #define UNIX_SOCKET_DIR "/tmp/.ki2-unix"
49
50 /*- resource table -*/
51 static XtResource resources[] = {
52 #define offset(field) XtOffset(IMProtocolWidget, imp.field)
53 { XtNserverName, XtCServerName, XtRString, sizeof(String),
54 offset(server_name), XtRString, (XtPointer)SERVER_NAME },
55 { XtNlanguage, XtCLanguage, XtRString, sizeof(String),
56 offset(language), XtRImmediate, (XtPointer)NULL },
57 { XtNlocales, XtCLocales, XtRString, sizeof(String),
58 offset(locales), XtRImmediate, (XtPointer)NULL },
59 { XtNinputObjectClass, XtCClass, XtRPointer, sizeof(WidgetClass),
60 offset(input_object_class), XtRImmediate, (XtPointer)NULL },
61 { XtNdisplayObjectClass, XtCClass, XtRPointer, sizeof(WidgetClass),
62 offset(display_object_class), XtRImmediate, (XtPointer)NULL },
63 { XtNdefaultFontList, XtCFontList, XtRString, sizeof(String),
64 offset(default_fontlist), XtRImmediate, (XtPointer)NULL },
65 { XtNconversionStartKeys, XtCConversionStartKeys, XtRString, sizeof(String),
66 offset(conversion_start_keys), XtRImmediate, (XtPointer)NULL },
67 { XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel),
68 offset(foreground), XtRString, XtDefaultForeground },
69 { XtNstatusWidth, XtCStatusWidth, XtRDimension, sizeof(Dimension),
70 offset(status_width), XtRImmediate, (XtPointer)0 },
71 { XtNtransports, XtCTransports, XtRString, sizeof(String),
72 offset(transport_list), XtRString, (XtPointer)"tcp,unix,x" },
73 #undef offset
74 };
75
76 static void Initialize _Pt_((Widget req, Widget new,
77 ArgList args, Cardinal *num_args));
78 static void Destroy _Pt_((Widget w));
79 static void Realize _Pt_((Widget w, XtValueMask *mask,
80 XSetWindowAttributes *value));
81
82 /*- IMProtocolClassRec -*/
83 IMProtocolClassRec imProtocolClassRec = {
84 { /* core fields */
85 /* superclass */ (WidgetClass) &widgetClassRec,
86 /* class_name */ "IMProtocol",
87 /* widget_size */ sizeof(IMProtocolRec),
88 /* class_initialize */ NULL,
89 /* class_part_initialize */ NULL,
90 /* class_inited */ FALSE,
91 /* initialize */ Initialize,
92 /* initialize_hook */ NULL,
93 /* realize */ Realize,
94 /* actions */ NULL,
95 /* num_actions */ 0,
96 /* resources */ resources,
97 /* num_resources */ XtNumber(resources),
98 /* xrm_class */ NULLQUARK,
99 /* compress_motion */ TRUE,
100 /* compress_exposure */ TRUE,
101 /* compress_enterleave */ TRUE,
102 /* visible_interest */ FALSE,
103 /* destroy */ Destroy,
104 /* resize */ NULL,
105 /* expose */ NULL,
106 /* set_values */ NULL,
107 /* set_values_hook */ NULL,
108 /* set_values_almost */ XtInheritSetValuesAlmost,
109 /* get_values_hook */ NULL,
110 /* accept_focus */ NULL,
111 /* version */ XtVersion,
112 /* callback_private */ NULL,
113 /* tm_table */ NULL,
114 /* query_geometry */ XtInheritQueryGeometry,
115 /* display_accelerator */ XtInheritDisplayAccelerator,
116 /* extension */ NULL
117 },
118 { /* imProtocol fields */
119 /* dummy */ 0
120 }
121 };
122
123 WidgetClass imProtocolWidgetClass = (WidgetClass)&imProtocolClassRec;
124
125 static void getAtoms _Pt_((IMProtocolWidget ipw));
126 static void setProperty _Pt_((IMProtocolWidget ipw));
127 static int ownSelection _Pt_((IMProtocolWidget ipw));
128 static Boolean convertSelection _Pt_((Widget w, Atom *selectionp,
129 Atom *targetp, Atom *typep,
130 XtPointer *valuep,
131 unsigned long *lengthp, int *formatp));
132 static void loseSelection _Pt_((Widget w, Atom *selectionp));
133 #ifdef IM_TCP_TRANSPORT
134 static void acceptTCPService _Pt_((XtPointer client_data,
135 int *sourcep, XtInputId *idp));
136 #endif
137 #ifdef IM_UNIX_TRANSPORT
138 static void acceptUnixService _Pt_((XtPointer client_data,
139 int *sourcep, XtInputId *idp));
140 #endif
141 #ifdef IM_X_TRANSPORT
142 static void acceptXService _Pt_((Widget w, XtPointer client_data,
143 XEvent *event, Boolean *continuep));
144 #endif
145 static void initializeError _Pt_((Widget w, String resname));
146 static char *compactList _Pt_((char *s));
147 static void setTransport _Pt_((Widget w));
148 static int makeConverter _Pt_((Widget w));
149 static void getTriggerKeys _Pt_((Widget w));
150 static void ioeCallback _Pt_((XPointer cldata));
151
152
153 /*
154 *+ Core class methods
155 */
156
157 /*- Initialize: intern Atoms, get default fonts, etc. -*/
158 /* ARGSUSED */
159 static void
160 Initialize(req, new, args, num_args)
161 Widget req;
162 Widget new;
163 ArgList args;
164 Cardinal *num_args;
165 {
166 IMProtocolWidget ipw = (IMProtocolWidget)new;
167
168 TRACE(("IMProtocolWidget:Initialize()\n"));
169
170 /*
171 * Check resources which must be specified at the initialization.
172 */
173 #define NULLorEMPTY(p) ((p) == NULL || (p)[0] == '\0')
174 if (NULLorEMPTY(ipw->imp.server_name)) {
175 initializeError(new, XtNserverName);
176 }
177
178 ipw->imp.server_name = XtNewString(ipw->imp.server_name);
179
180 if (NULLorEMPTY(ipw->imp.language)) {
181 initializeError(new, XtNlanguage);
182 } else if (NULLorEMPTY(ipw->imp.locales)) {
183 initializeError(new, XtNlocales);
184 } else if (ipw->imp.input_object_class == NULL) {
185 initializeError(new, XtNinputObjectClass);
186 } else if (ipw->imp.display_object_class == NULL) {
187 initializeError(new, XtNdisplayObjectClass);
188 }
189 ipw->imp.locales = compactList(XtNewString(ipw->imp.locales));
190 #undef NULLorEMPTY
191
192 /*
193 * Initialize converter info.
194 */
195 if (makeConverter(new) < 0) {
196 /*
197 * locales is empty.
198 */
199 String params[1];
200 Cardinal num_params;
201
202 params[0] = XtClass(new)->core_class.class_name;
203 num_params = 1;
204 XtAppErrorMsg(XtWidgetToApplicationContext(new),
205 "initializeError", "invalidValue", "WidgetError",
206 "%s: locale list is empty",
207 params, &num_params);
208 }
209
210 /*
211 * Create font bank (a bank of cached fonts) and enter
212 * default fonts.
213 */
214 ipw->imp.font_bank = FontBankCreate(XtDisplay(new), ipw->imp.language);
215 if (ipw->imp.font_bank == NULL) {
216 /*
217 * The specified language is not supported.
218 */
219 String params[2];
220 Cardinal num_params;
221
222 params[0] = XtClass(new)->core_class.class_name;
223 params[1] = ipw->imp.language;
224 num_params = 2;
225 XtAppErrorMsg(XtWidgetToApplicationContext(new),
226 "initializeError", "invalidValue", "WidgetError",
227 "%s: language %s not supported",
228 params, &num_params);
229 }
230
231 if (ipw->imp.default_fontlist != NULL) {
232 ipw->imp.default_fontlist = XtNewString(ipw->imp.default_fontlist);
233
234 DDPRINT(2, ("cache default fonts: %s\n", ipw->imp.default_fontlist));
235 ipw->imp.default_fonts = FontBankGet(ipw->imp.font_bank,
236 ipw->imp.default_fontlist,
237 &ipw->imp.num_default_fonts);
238 } else {
239 ipw->imp.default_fonts = NULL;
240 ipw->imp.num_default_fonts = 0;
241 }
242
243 /*
244 * Initialize private data.
245 */
246 ipw->imp.connection_list = NULL;
247 ipw->imp.no_more_connections = False;
248 ipw->imp.scheduler_queue = NULL;
249 setTransport(new);
250 getTriggerKeys(new);
251 IMInitHash(new);
252 getAtoms(ipw);
253
254 /*
255 * Initialilze transport layer.
256 */
257 /* 1. TCP/IP */
258 ipw->imp.tcp_sock = -1;
259 #ifdef IM_TCP_TRANSPORT
260 if (ipw->imp.use_tcp_transport) {
261 ipw->imp.tcp_port = 0; /* let the system choose the port number */
262 ipw->imp.tcp_sock = IMCreateTCPService(&ipw->imp.tcp_port);
263 }
264 if (ipw->imp.tcp_sock >= 0) {
265 TRACE(("call XtAppAddInput for tcp socket(%d)\n", ipw->imp.tcp_sock));
266 ipw->imp.tcp_id = XtAppAddInput(XtWidgetToApplicationContext(new),
267 ipw->imp.tcp_sock,
268 (XtPointer)XtInputReadMask,
269 acceptTCPService, (XtPointer)ipw);
270 }
271 #endif /* IM_TCP_TRANSPORT */
272
273 /* 2. UNIX domain */
274 ipw->imp.unix_sock = -1;
275 #ifdef IM_UNIX_TRANSPORT
276 if (ipw->imp.use_unix_transport) {
277 char path[1024];
278 char *p;
279
280 /*
281 * The unix domain socket pathname has the following form:
282 * <UNIX_SOCKET_DIR>/<Display Name>-<Language>
283 */
284 (void)mkdir(UNIX_SOCKET_DIR, 0777);
285 #ifdef S_IFLNK
286 {
287 /*
288 * This system has symbolic links. Make sure UNIX_SOCKET_DIR
289 * is not a symbolic link but a directory before calling
290 * chmod().
291 */
292 struct stat st;
293 if (lstat(UNIX_SOCKET_DIR, &st) == 0 &&
294 (st.st_mode & S_IFMT) == S_IFDIR) {
295 (void)chmod(UNIX_SOCKET_DIR, 0777);
296 }
297 }
298 #else
299 (void)chmod(UNIX_SOCKET_DIR, 0777);
300 #endif
301 (void)sprintf(path, "%s/%s", UNIX_SOCKET_DIR,
302 DisplayString(XtDisplay(new)));
303 /*
304 * Omit screen number and the preceding period.
305 */
306 for (p = path + strlen(path) - 1; p > path && *p != ':'; p--) {
307 if (*p == '.') {
308 *p = '\0';
309 break;
310 }
311 }
312 /*
313 * Append language part.
314 */
315 (void)strcat(path, "-");
316 (void)strcat(path, ipw->imp.language);
317 /*
318 * Change every ':' in the path name to '_', since ':' is not
319 * included in POSIX Portable Filename Character Set.
320 */
321 for (p = path; *p != '\0'; p++) {
322 if (*p == ':') *p = '_';
323 }
324 ipw->imp.unix_path = XtNewString(path);
325 ipw->imp.unix_sock = IMCreateUnixService(ipw->imp.unix_path);
326 }
327 if (ipw->imp.unix_sock >= 0) {
328 TRACE(("call XtAppAddInput for unix socket(%d)\n", ipw->imp.unix_sock));
329 ipw->imp.unix_id = XtAppAddInput(XtWidgetToApplicationContext(new),
330 ipw->imp.unix_sock,
331 (XtPointer)XtInputReadMask,
332 acceptUnixService, (XtPointer)ipw);
333 ipw->imp.ioe_handle = XIOESet(ioeCallback, (XPointer)ipw);
334 }
335 #endif /* IM_UNIX_TRANSPORT */
336
337 #ifdef IM_X_TRANSPORT
338 if (ipw->imp.use_x_transport) {
339 TRACE(("call XtAddEventHandler for X transport\n"));
340 XtAddEventHandler(new, NoEventMask, True, acceptXService,
341 (XtPointer)NULL);
342 }
343 #endif /* IM_X_TRANSPORT */
344
345 /*
346 * Compile request dispatching table.
347 */
348 IMCompileReq();
349 }
350
351 /*- Destroy: free allocated memory -*/
352 static void
353 Destroy(w)
354 Widget w;
355 {
356 IMProtocolWidget ipw = (IMProtocolWidget)w;
357 IMConnection *conn;
358 int i;
359
360 TRACE(("IMProtocolWidget:Destroy()\n"));
361
362 XtFree(ipw->imp.server_name);
363 XtFree(ipw->imp.locales);
364 if (ipw->imp.default_fontlist != NULL) XtFree(ipw->imp.default_fontlist);
365 if (ipw->imp.trigger_keys != NULL) XtFree((char *)ipw->imp.trigger_keys);
366
367 for (i = 0; i < ipw->imp.converter.num_locales; i++) {
368 XtFree(ipw->imp.converter.supported_locales[i]);
369 }
370 XtFree((char *)ipw->imp.converter.supported_locales);
371
372 /*
373 * Close down all connections.
374 */
375 conn = ipw->imp.connection_list;
376 while (conn != NULL) {
377 IMConnection *next = conn->next;
378
379 IMCloseConnection(conn);
380 conn = next;
381 }
382
383 /*
384 * Close down TCP/Unix service sockets.
385 */
386 if (ipw->imp.tcp_sock >= 0) {
387 XtRemoveInput(ipw->imp.tcp_id);
388 (void)close(ipw->imp.tcp_sock);
389 }
390 if (ipw->imp.unix_sock >= 0) {
391 XIOEUnset(ipw->imp.ioe_handle);
392 (void)unlink(ipw->imp.unix_path);
393 XtRemoveInput(ipw->imp.unix_id);
394 (void)close(ipw->imp.unix_sock);
395 XtFree(ipw->imp.unix_path);
396 }
397
398 /*
399 * Unload default fonts.
400 */
401 if (ipw->imp.num_default_fonts > 0) {
402 FontBankFreeFonts(ipw->imp.font_bank,
403 ipw->imp.default_fonts,
404 ipw->imp.num_default_fonts);
405 }
406
407 /*
408 * Free font bank.
409 */
410 FontBankDestroy(ipw->imp.font_bank);
411 }
412
413 /*- Realize: own selection -*/
414 static void
415 Realize(w, mask, value)
416 Widget w;
417 XtValueMask *mask;
418 XSetWindowAttributes *value;
419 {
420 IMProtocolWidget ipw = (IMProtocolWidget)w;
421 CoreWidgetClass super = (CoreWidgetClass)XtClass(w)->core_class.superclass;
422
423 TRACE(("IMProtocolWidget:Realize()\n"));
424
425 (*super->core_class.realize)(w, mask, value);
426
427 if (ownSelection(ipw) < 0) {
428 String params[1];
429 Cardinal num_params;
430
431 params[0] = XtClass(w)->core_class.class_name;
432 num_params = 1;
433 XtAppWarningMsg(XtWidgetToApplicationContext(w),
434 "selectionError", "ownSelection", "WidgetError",
435 "%s: can't own selection", params, &num_params);
436
437 XtDestroyWidget(w);
438 }
439
440 setProperty(ipw);
441 }
442
443 /*
444 *+ Atom, property and selection handling
445 */
446
447 /*- getAtoms: intern atoms -*/
448 static void
449 getAtoms(ipw)
450 IMProtocolWidget ipw;
451 {
452 Display *dpy = XtDisplay((Widget)ipw);
453 char buf[256];
454
455 TRACE(("IMProtocolWidget:getAtoms()\n"));
456
457 (void)strcpy(buf, "@server=");
458 (void)strcat(buf, ipw->imp.server_name);
459 #define MAKEATOM(s) XInternAtom(dpy, s, False)
460 ipw->imp.server_atom = MAKEATOM(buf);
461 ipw->imp.ctext_atom = MAKEATOM("COMPOUND_TEXT");
462 ipw->imp.locales_atom = MAKEATOM("LOCALES");
463 ipw->imp.transport_atom = MAKEATOM("TRANSPORT");
464 ipw->imp.ki2comm_atom = MAKEATOM("_KINPUT2_COMM");
465 ipw->imp.xim_xconnect = MAKEATOM("_XIM_XCONNECT");
466 ipw->imp.xim_protocol = MAKEATOM("_XIM_PROTOCOL");
467 ipw->imp.xim_moredata = MAKEATOM("_XIM_MOREDATA");
468 #undef MAKEATOM
469 }
470
471 /*- setProperty: set XIM_SERVERS property -*/
472 static void
473 setProperty(ipw)
474 IMProtocolWidget ipw;
475 {
476 Display *dpy = XtDisplay((Widget)ipw);
477 Atom xim_servers = XInternAtom(dpy, "XIM_SERVERS", False);
478 Atom server_atom = ipw->imp.server_atom;
479 Window root0 = RootWindow(dpy, 0);
480 int op_mode = PropModePrepend;
481 int no_registration = 0;
482 Atom type;
483 int format;
484 unsigned long nitems;
485 unsigned long bytes_after;
486 unsigned char *value;
487 unsigned long data;
488
489 TRACE(("IMProtocolWidget:setProperty()\n"));
490
491 /*
492 * For atomic operation, grab the server.
493 */
494 #ifndef DEBUG
495 XGrabServer(dpy);
496 #endif
497
498 /*
499 * First, check the XIM_SERVERS property's existance.
500 * If it exists, examine the contents.
501 */
502 if (XGetWindowProperty(dpy, root0, xim_servers, 0L, 1024L, False,
503 AnyPropertyType, &type, &format, &nitems,
504 &bytes_after, &value) == Success) {
505 if (type != XA_ATOM || format != 32) {
506 /*
507 * The contents of the property is invalid.
508 */
509 DDPRINT(2, ("XIM_SERVERS is corrupted (type=%ld, format=%d)\n",
510 type, format));
511 op_mode = PropModeReplace;
512 } else {
513 int i;
514 unsigned long *atoms = (unsigned long *)value;
515
516 for (i = 0; i < nitems; i++) {
517 if (atoms[i] == server_atom) {
518 /*
519 * Already registered.
520 */
521 TRACE(("server is already registered in XIM_SERVERS\n"));
522 no_registration = 1;
523 break;
524 }
525 }
526 }
527 if (value != NULL) XFree((char *)value);
528 }
529
530 if (!no_registration) {
531 TRACE(("changing XIM_SERVERS property\n"));
532 data = ipw->imp.server_atom;
533 XChangeProperty(dpy, root0, xim_servers, XA_ATOM, 32, op_mode,
534 (unsigned char *)&data, 1);
535 } else {
536 TRACE(("touching XIM_SERVERS property to generate PropertyNotify\n"));
537 XChangeProperty(dpy, root0, xim_servers, XA_ATOM, 32, PropModeAppend,
538 (unsigned char *)&data, 0);
539 }
540
541 #ifndef DEBUG
542 XUngrabServer(dpy);
543 #endif
544 }
545
546 /*- ownSelection: own conversion selection -*/
547 static int
548 ownSelection(ipw)
549 IMProtocolWidget ipw;
550 {
551 Display *dpy = XtDisplay((Widget)ipw);
552 Time time = XtLastTimestampProcessed(dpy);
553
554
555 TRACE(("IMProtocolWidget:ownSelection()\n"));
556
557 if (!XtOwnSelection((Widget)ipw, ipw->imp.server_atom, time,
558 convertSelection, loseSelection,
559 (XtSelectionDoneProc)NULL)) {
560 DPRINT(("cannot own selection"));
561 return -1;
562 }
563 DPRINT(("selection atom:%ld owner: %08lx (%ld)\n", ipw->imp.server_atom,
564 XtWindow((Widget)ipw), XtWindow((Widget)ipw)));
565 return 0;
566 }
567
568 /*- convertSelection: convert selections -*/
569 /* ARGSUSED */
570 static Boolean
571 convertSelection(w, selectionp, targetp, typep, valuep, lengthp, formatp)
572 Widget w;
573 Atom *selectionp;
574 Atom *targetp;
575 Atom *typep;
576 XtPointer *valuep;
577 unsigned long *lengthp;
578 int *formatp;
579 {
580 Display *dpy = XtDisplay(w);
581 IMProtocolWidget ipw = (IMProtocolWidget)w;
582
583 TRACE(("IMProtocolWidget:convertSelection()\n"));
584
585 if (*targetp == XInternAtom(dpy, "TARGETS", False)) {
586 Atom *targets;
587
588 TRACE(("target is \"TARGETS\"\n"));
589 targets = (Atom *)XtMalloc(sizeof(Atom) * 2);
590 targets[0] = ATOM_LOCALES(w);
591 targets[1] = ATOM_TRANSPORT(w);
592
593 *typep = XA_ATOM;
594 *valuep = (XtPointer)targets;
595 *lengthp = 2;
596 *formatp = 32;
597 return True;
598 } else if (*targetp == ATOM_LOCALES(w)) {
599 char buf[1024];
600
601 TRACE(("target is \"LOCALES\"\n"));
602 (void)strcpy(buf, "@locale=");
603 (void)strcat(buf, ipw->imp.locales);
604 TRACE(("\ttype: STRING, value: %s\n", buf));
605 /*
606 * The protocol spec is unclear on the type of the
607 * selection value. Since R6 sample implementation
608 * uses LOCALES, use it.
609 */
610 *typep = *targetp;
611 /* *typep = XA_STRING; */
612 *valuep = (XtPointer)XtNewString(buf);
613 *lengthp = strlen(buf);
614 *formatp = 8;
615 return True;
616 } else if (*targetp == ATOM_TRANSPORT(w)) {
617 char buf[1024];
618 char hostname[256];
619
620 TRACE(("target is \"TRANSPORT\"\n"));
621
622 XmuGetHostname(hostname, 256);
623
624 (void)strcpy(buf, "@transport=");
625
626 #ifdef IM_X_TRANSPORT
627 if (ipw->imp.use_x_transport) {
628 (void)strcat(buf, "X/,");
629 }
630 #endif /* IM_X_TRANSPORT */
631
632 #ifdef IM_TCP_TRANSPORT
633 if (ipw->imp.use_tcp_transport) {
634 char t_buf[1024];
635 (void)sprintf(t_buf, "tcp/%s:%d,", hostname, ipw->imp.tcp_port);
636 (void)strcat(buf, t_buf);
637 }
638 #endif /* IM_TCP_TRANSPORT */
639
640 #ifdef IM_UNIX_TRANSPORT
641 if (ipw->imp.use_unix_transport) {
642 char u_buf[1024];
643 (void)sprintf(u_buf, "local/%s:%s,", hostname, ipw->imp.unix_path);
644 (void)strcat(buf, u_buf);
645 }
646 #endif /* IM_UNIX_TRANSPORT */
647
648 /* delete trailing comma */
649 if (buf[strlen(buf) - 1] == ',') buf[strlen(buf) - 1] = '\0';
650 TRACE(("\ttype: STRING, value: %s\n", buf));
651
652 *typep = *targetp; /* -- see the comment on LOCALES above */
653 *valuep = (XtPointer)XtNewString(buf);
654 *lengthp = strlen(buf);
655 *formatp = 8;
656 return True;
657 } else {
658 DDPRINT(2, ("unknown target atom (%ld)\n", *targetp));
659 return False;
660 }
661 }
662
663 /*- loseSelection: disable IM protocol handling -*/
664 /* ARGSUSED */
665 static void
666 loseSelection(w, selectionp)
667 Widget w;
668 Atom *selectionp;
669 {
670 IMProtocolWidget ipw = (IMProtocolWidget)w;
671
672 TRACE(("IMProtocolWidget:loseSelection()\n"));
673
674 /*
675 * Someone takes over the selection. That means
676 * another kinput2 process has been started.
677 * Let the newly process handle new clients, but
678 * as long as existing clients are remained, we have
679 * to maintain them.
680 */
681
682 if (ipw->imp.connection_list == NULL) {
683 /*
684 * There are no clients. It is OK to destroy protocol handler.
685 */
686 XtDestroyWidget(w);
687 return;
688 }
689
690 ipw->imp.no_more_connections = True;
691
692 /*
693 * Close down TCP/Unix service sockets.
694 */
695 if (ipw->imp.tcp_sock >= 0) {
696 TRACE(("\tclose tcp socket\n"));
697 XtRemoveInput(ipw->imp.tcp_id);
698 (void)close(ipw->imp.tcp_sock);
699 ipw->imp.tcp_sock = -1;
700 }
701 if (ipw->imp.unix_sock >= 0) {
702 TRACE(("\tclose unix socket\n"));
703 XtRemoveInput(ipw->imp.unix_id);
704 (void)close(ipw->imp.unix_sock);
705 ipw->imp.unix_sock = -1;
706 }
707 }
708
709
710 /*
711 *+ Connection acceptance
712 */
713
714 #ifdef IM_TCP_TRANSPORT
715 /*- acceptTCPService: establish connection via TCP transport -*/
716 /* ARGSUSED */
717 static void
718 acceptTCPService(client_data, sourcep, idp)
719 XtPointer client_data;
720 int *sourcep;
721 XtInputId *idp;
722 {
723 IMProtocolWidget ipw = (IMProtocolWidget)client_data;
724 IMConnection *conn;
725
726 TRACE(("IMProtocolWidget:acceptTCPService()\n"));
727
728 /*
729 * Accept connection request.
730 */
731 conn = IMTCPConnection((Widget)ipw, *sourcep);
732
733 /*
734 * Set dispatcher.
735 */
736 if (conn != NULL) IMSetInitialDispatcher(conn);
737
738 /*
739 * Enter to the connections list.
740 */
741 if (conn != NULL) IMRegisterConnection(conn);
742 }
743 #endif /* IM_TCP_TRANSPORT */
744
745 #ifdef IM_UNIX_TRANSPORT
746 /*- acceptUnixService: establish connection via UNIX domain transport -*/
747 /* ARGSUSED */
748 static void
749 acceptUnixService(client_data, sourcep, idp)
750 XtPointer client_data;
751 int *sourcep;
752 XtInputId *idp;
753 {
754 IMProtocolWidget ipw = (IMProtocolWidget)client_data;
755 IMConnection *conn;
756
757 TRACE(("IMProtocolWidget:acceptUnixService()\n"));
758
759 /*
760 * Accept connection request.
761 */
762 conn = IMUnixConnection((Widget)ipw, *sourcep);
763
764 /*
765 * Set dispatcher.
766 */
767 if (conn != NULL) IMSetInitialDispatcher(conn);
768
769 /*
770 * Enter to the connections list.
771 */
772 if (conn != NULL) IMRegisterConnection(conn);
773 }
774 #endif /* IM_UNIX_TRANSPORT */
775
776 #ifdef IM_X_TRANSPORT
777 /*- acceptXService: establish connection via X transport -*/
778 /* ARGSUSED */
779 static void
780 acceptXService(w, client_data, event, continuep)
781 Widget w;
782 XtPointer client_data;
783 XEvent *event;
784 Boolean *continuep;
785 {
786 IMConnection *conn;
787
788 TRACE(("IMProtocolWidget:acceptXService()\n"));
789
790 /*
791 * Check if the event is really a connection request.
792 */
793 if (event->type != ClientMessage) return;
794 conn = IMXConnection(w, event);
795
796 /*
797 * Set dispatcher.
798 */
799 if (conn != NULL) IMSetInitialDispatcher(conn);
800
801 /*
802 * Enter to the connections list.
803 */
804 if (conn != NULL) IMRegisterConnection(conn);
805 }
806 #endif /* IM_X_TRANSPORT */
807
808
809 /*
810 *+ utility functions
811 */
812
813 /*- initializeError: display error message when resource isn't specified -*/
814 static void
815 initializeError(w, resname)
816 Widget w;
817 String resname;
818 {
819 String params[2];
820 Cardinal num_params;
821
822 params[0] = XtClass(w)->core_class.class_name;
823 params[1] = resname;
824 num_params = 2;
825 XtAppErrorMsg(XtWidgetToApplicationContext(w),
826 "initializeError", "noResource", "WidgetError",
827 "%s: resource %s must be specified at widget creation",
828 params, &num_params);
829 }
830
831 /*- compactList: remove unnecessary spaces in a comma-separated list -*/
832 static char *
833 compactList(s)
834 char *s;
835 {
836 char *src, *dst;
837 int c;
838
839 src = dst = s;
840 for (;;) {
841 /* skip leading space */
842 while (isspace(*src)) src++;
843
844 if (*src == '\0') {
845 *dst = '\0';
846 return s;
847 }
848
849 /* copy string until comma or NUL appears */
850 while ((c = *dst++ = *src++) != ',') {
851 if (c == '\0') return s;
852 }
853 }
854 }
855
856 /*- setTransport: determine which transport to be used -*/
857 static void
858 setTransport(w)
859 Widget w;
860 {
861 IMProtocolWidget ipw = (IMProtocolWidget)w;
862 char *p;
863
864 TRACE(("IMProtocolWidget:setTransport(%s)\n", ipw->imp.transport_list));
865
866 ipw->imp.use_tcp_transport = False;
867 ipw->imp.use_unix_transport = False;
868 ipw->imp.use_x_transport = False;
869
870 p = ipw->imp.transport_list;
871 while (*p != '\0') {
872 char lower[256];
873 char *q;
874
875 while (isspace(*p)) p++;
876 if (*p == '\0') break;
877
878 q = lower;
879 while (*p != '\0' && *p != ',' && !isspace(*p)) {
880 if (isupper(*p)) {
881 *q++ = tolower(*p);
882 } else {
883 *q++ = *p;
884 }
885 p++;
886 }
887 *q = '\0';
888 while (isspace(*p)) p++;
889 if (*p == ',') p++;
890
891 if (!strcmp(lower, "tcp")) {
892 TRACE(("\tTCP transport\n"));
893 ipw->imp.use_tcp_transport = True;
894 } else if (!strcmp(lower, "unix")) {
895 TRACE(("\tUNIX domain transport\n"));
896 ipw->imp.use_unix_transport = True;
897 } else if (!strcmp(lower, "x")) {
898 TRACE(("\tX transport\n"));
899 ipw->imp.use_x_transport = True;
900 }
901 }
902 }
903
904 /*- makeConverter: create converter record -*/
905 static int
906 makeConverter(w)
907 Widget w;
908 {
909 IMProtocolWidget ipw = (IMProtocolWidget)w;
910 char *locales[100];
911 int num_locales;
912 int size;
913 char *p;
914
915 TRACE(("IMProtocolWidget:makeConverter()\n"));
916
917 ipw->imp.converter.input_object_class = ipw->imp.input_object_class;
918 ipw->imp.converter.display_object_class = ipw->imp.display_object_class;
919
920 p = ipw->imp.locales;
921 num_locales = 0;
922 do {
923 char buf[256];
924 char *q = buf;
925
926 while (isspace(*p)) p++;
927 if (*p == '\0') break;
928
929 while (*p != '\0' && *p != ',' && !isspace(*p)) *q++ = *p++;
930 *q = '\0';
931 TRACE(("\tsupported locale: %s\n", buf));
932 locales[num_locales++] = XtNewString(buf);
933 while (isspace(*p)) p++;
934 if (*p == ',') p++;
935 } while (*p != '\0' && num_locales < 100);
936 TRACE(("\tnumber of supported locales: %d\n", num_locales));
937
938 if (num_locales == 0) return -1;
939 ipw->imp.converter.num_locales = num_locales;
940
941 size = sizeof(char *) * num_locales;
942 ipw->imp.converter.supported_locales = (char **)XtMalloc(size);
943 bcopy((char *)locales, (char *)ipw->imp.converter.supported_locales, size);
944 return 0;
945 }
946
947 /*- getTriggerKeys: parse conversion trigger key specification -*/
948 static void
949 getTriggerKeys(w)
950 Widget w;
951 {
952 IMProtocolWidget ipw = (IMProtocolWidget)w;
953 char *key_str;
954 IMTriggerKey keys[100];
955 int num_keys;
956 int c, n;
957 ICTriggerKey *ckeys, *ekeys;
958
959 TRACE(("IMProtocolWidget:getTriggerKeys()\n"));
960
961 key_str = ipw->imp.conversion_start_keys;
962 num_keys = 0;
963 TRACE(("\tstart keys: %s\n", key_str));
964
965 if (key_str != NULL) {
966 do {
967 char buf[256];
968 char *p = buf;
969 KeySym keysym;
970 long mods, chk_mods;
971
972 while ((c = *key_str++) != '\0' && c != '\n') {
973 *p++ = c;
974 }
975 *p = '\0';
976 if (ParseKeyEvent(buf, &keysym, &mods, &chk_mods)) {
977 TRACE(("\tkeysym: %08lx, modifiers: %04lx, check: %04lx\n",
978 keysym, mods, chk_mods));
979 keys[num_keys].keysym = keysym;
980 keys[num_keys].modifiers = mods;
981 keys[num_keys].check_modifiers = chk_mods;
982 num_keys++;
983 }
984 } while (c != '\0' && num_keys < 100);
985 }
986
987 n = ICGetTriggerKeysOfInputObjectClass(ipw->imp.input_object_class,
988 &ckeys);
989 for (ekeys = ckeys + n ;
990 ckeys < ekeys && num_keys < (sizeof(keys) / sizeof(IMTriggerKey)) ;
991 ckeys++) {
992 keys[num_keys].keysym = ckeys->keysym;
993 keys[num_keys].modifiers = ckeys->modifiers;
994 keys[num_keys].check_modifiers = ckeys->modifiermask;
995 num_keys++;
996 }
997
998 TRACE(("\tnumber of trigger keys: %d\n", num_keys));
999 ipw->imp.num_trigger_keys = num_keys;
1000
1001 if (num_keys > 0) {
1002 int size;
1003
1004 size = sizeof(IMTriggerKey) * num_keys;
1005 ipw->imp.trigger_keys = (IMTriggerKey *)XtMalloc(size);
1006 bcopy((char *)keys, (char *)ipw->imp.trigger_keys, size);
1007 } else {
1008 ipw->imp.trigger_keys = NULL;
1009 }
1010 }
1011
1012 /*- ioeCallback: callback procedure for X I/O error -*/
1013 static void
1014 ioeCallback(cldata)
1015 XPointer cldata;
1016 {
1017 IMProtocolWidget ipw = (IMProtocolWidget)cldata;
1018
1019 if (ipw->imp.unix_sock >= 0 && ipw->imp.unix_path != NULL) {
1020 (void)unlink(ipw->imp.unix_path);
1021 }
1022 }