comparison lib/KIProto.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 7a454839a6de
comparison
equal deleted inserted replaced
-1:000000000000 0:92745d501b9a
1 #ifndef lint
2 static char *rcsid = "$Id: KIProto.c,v 1.49 1999/01/07 03:12:57 ishisone Exp $";
3 #endif
4 /*-
5 * Copyright (c) 1991 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 #include <X11/IntrinsicP.h>
22 #include <X11/StringDefs.h>
23 #include <X11/Xatom.h>
24 #include <X11/Xmu/Atoms.h>
25 #include <X11/Xmu/CharSet.h>
26 #include "KIProtoP.h"
27 #include "ConvMgr.h"
28 #include "OverConv.h"
29 #include "OffConv.h"
30 #include "ConvDisp.h"
31 #include "MyDispatch.h"
32 #include "CachedFont.h"
33 #include "ConvProto.h"
34 #include "AsyncErr.h"
35
36 #define DEBUG_VAR debug_KinputProtocol
37 #include "DebugPrint.h"
38
39 #define JINPUT_PROTOCOL_VERSION 0x20000L /* version 2 */
40
41 #define XLC_AUTO_REPLACE 1
42 #define XLC_ALL_INFORMATION 2
43 #define XLC_FRAME_INFORMATION 4
44 #define XLC_OFFSET_INFORMATION 8
45
46 /*- resource table -*/
47 static XtResource resources[] = {
48 #define offset(field) XtOffset(KinputProtocolWidget, kinput.field)
49 { XtNlanguage, XtCLanguage, XtRString, sizeof(String),
50 offset(language), XtRString, (XtPointer)NULL },
51 { XtNinputObjectClass, XtCClass, XtRPointer, sizeof(WidgetClass),
52 offset(inputObjClass), XtRImmediate, (XtPointer)NULL },
53 { XtNdisplayObjectClass, XtCClass, XtRPointer, sizeof(WidgetClass),
54 offset(displayObjClass), XtRImmediate, (XtPointer)NULL },
55 { XtNbackwardCompatible, XtCBackwardCompatible, XtRBoolean, sizeof(Boolean),
56 offset(backward_compatible), XtRString, (XtPointer)"False" },
57 { XtNxlcConversionStartKey, XtCXlcConversionStartKey, XtRString, sizeof(String),
58 offset(xlcstartkey), XtRString, (XtPointer)NULL },
59 #undef offset
60 };
61
62 static void ConversionRequestProc();
63 static void ConversionEndRequestProc();
64 static void ConversionOpenRequestProc();
65 static void ConversionCloseRequestProc();
66 static void ConversionCloseProc();
67 static void ConversionXYNotifyProc();
68 static void ConversionColorNotifyProc();
69 static void ConversionFontsNotifyProc();
70 static void ConversionAttributeNotifyProc();
71 static void SelectionRequestProc();
72 static void SelectionClearProc();
73 static void XlcOnTheSpotChangedProc();
74
75 /*- action table -*/
76 static XtActionsRec actions[] = {
77 { "conversion-request", ConversionRequestProc },
78 { "conversion-end-request", ConversionEndRequestProc },
79 { "conversion-open-request", ConversionOpenRequestProc },
80 { "conversion-close-request", ConversionCloseRequestProc },
81 { "conversion-close", ConversionCloseProc },
82 { "conversion-xy-notify", ConversionXYNotifyProc },
83 { "conversion-color-notify", ConversionColorNotifyProc },
84 { "conversion-fonts-notify", ConversionFontsNotifyProc },
85 { "conversion-attribute-notify", ConversionAttributeNotifyProc },
86 { "xlc-on-the-spot-changed", XlcOnTheSpotChangedProc },
87 { "selection-request", SelectionRequestProc },
88 { "selection-clear", SelectionClearProc },
89 };
90
91 /*- default translation -*/
92 static char translations[] =
93 "<Message>CONVERSION_REQUEST: conversion-request()\n\
94 <Message>CONVERSION_END_REQUEST: conversion-end-request()\n\
95 <Message>CONVERSION_OPEN_REQUEST: conversion-open-request()\n\
96 <Message>CONVERSION_CLOSE_REQUEST: conversion-close-request()\n\
97 <Message>CONVERSION_CLOSE: conversion-close()\n\
98 <Message>CONVERSION_XY_NOTIFY: conversion-xy-notify()\n\
99 <Message>CONVERSION_COLOR_NOTIFY: conversion-color-notify()\n\
100 <Message>CONVERSION_FONTS_NOTIFY: conversion-fonts-notify()\n\
101 <Message>CONVERSION_ATTRIBUTE_NOTIFY: conversion-attribute-notify()\n\
102 <Prop>_XLC_ON_THE_SPOT: xlc-on-the-spot-changed()\n\
103 <SelReq>: selection-request()\n\
104 <SelClr>: selection-clear()";
105
106 /*- static function declarations -*/
107 static void Initialize(), Destroy();
108 static void Realize();
109 static Boolean SetValues();
110
111 static void getAtoms();
112 static Boolean ownSelection();
113
114 static ConvClient *findClient();
115 static ConvClient *newClient();
116 static Widget attachConverter();
117 static void detachConverter();
118 static void jinputDetach();
119 static void deleteClient();
120
121 static Boolean isCorrectClientEvent();
122 static Boolean isCorrectWindowID();
123
124 static void myStartConversion();
125 static void myChangeAttributes();
126
127 static void getJinputInitialProperty();
128 static void jinputSendReq();
129 static void jinputFreeResources();
130 static void kinput2FreeResources();
131 static void xlcFreeResources();
132 static void setAttribute();
133 static int getFontsByFontAtoms();
134 static int safeGetAttributeProperty();
135 static void getAttributeFromProperty1();
136 static void getAttributeFromProperty();
137 static void getAttributeFromEvent();
138 static ConvClient *getXlcDataFromProperty();
139 static void initializeError();
140 static int parseKeyEvent();
141 static char *mystrstr();
142 static void getDefaultFontHeight();
143
144 static void setJinputProperty();
145 static void setKinput2Property();
146 static void setXlcProperty();
147 static void setXlcStatusProperty();
148 static void setXlcBCKey();
149
150 static void sendClientMessage();
151 static void sendNegativeConversionNotify();
152 static void sendConversionNotify();
153 static void sendNegativeConversionOpenNotify();
154 static void sendConversionOpenNotify();
155 static void sendColorRequest();
156 static void sendFontRequest();
157 static void sendXYRequest();
158
159 static void fixCallback();
160 static void fixProc();
161 static void jinputFix();
162 static void endCallback();
163 static void endProc();
164 static void jinputEnd();
165 static void jinputNewTextCallback();
166 static void xlcEnd();
167
168 static void ClientDead();
169
170 /*- KinputProtocolClassRec -*/
171 KinputProtocolClassRec kinputProtocolClassRec = {
172 { /* core fields */
173 /* superclass */ (WidgetClass) &widgetClassRec,
174 /* class_name */ "KinputProtocol",
175 /* widget_size */ sizeof(KinputProtocolRec),
176 /* class_initialize */ NULL,
177 /* class_part_initialize */ NULL,
178 /* class_inited */ FALSE,
179 /* initialize */ Initialize,
180 /* initialize_hook */ NULL,
181 /* realize */ Realize,
182 /* actions */ actions,
183 /* num_actions */ XtNumber(actions),
184 /* resources */ resources,
185 /* num_resources */ XtNumber(resources),
186 /* xrm_class */ NULLQUARK,
187 /* compress_motion */ TRUE,
188 /* compress_exposure */ TRUE,
189 /* compress_enterleave */ TRUE,
190 /* visible_interest */ FALSE,
191 /* destroy */ Destroy,
192 /* resize */ NULL,
193 /* expose */ NULL,
194 /* set_values */ SetValues,
195 /* set_values_hook */ NULL,
196 /* set_values_almost */ XtInheritSetValuesAlmost,
197 /* get_values_hook */ NULL,
198 /* accept_focus */ NULL,
199 /* version */ XtVersion,
200 /* callback_private */ NULL,
201 /* tm_table */ translations,
202 /* query_geometry */ XtInheritQueryGeometry,
203 /* display_accelerator */ XtInheritDisplayAccelerator,
204 /* extension */ NULL
205 },
206 { /* kinputprotocol fields */
207 /* empty */ 0
208 }
209 };
210
211 WidgetClass kinputProtocolWidgetClass = (WidgetClass)&kinputProtocolClassRec;
212
213 /*
214 *+ Core class methods
215 */
216
217 /*- Initialize: intern Atoms -*/
218 /* ARGSUSED */
219 static void
220 Initialize(req, new, args, num_args)
221 Widget req;
222 Widget new;
223 ArgList args;
224 Cardinal *num_args;
225 {
226 KinputProtocolWidget kpw = (KinputProtocolWidget)new;
227
228 if (kpw->kinput.language == NULL) {
229 initializeError(new, XtNlanguage);
230 } else if (kpw->kinput.inputObjClass == NULL) {
231 initializeError(new, XtNinputObjectClass);
232 } else if (kpw->kinput.displayObjClass == NULL) {
233 initializeError(new, XtNdisplayObjectClass);
234 }
235 kpw->kinput.language = XtNewString(kpw->kinput.language);
236 kpw->kinput.clients = (ConvClient *)NULL;
237 getDefaultFontHeight(kpw);
238 getAtoms(kpw);
239 }
240
241 /*- Destroy: free allocated memory -*/
242 static void
243 Destroy(w)
244 Widget w;
245 {
246 KinputProtocolWidget kpw = (KinputProtocolWidget)w;
247
248 XtFree(kpw->kinput.language);
249 }
250
251 /*- Realize: own selection -*/
252 static void
253 Realize(w, mask, value)
254 Widget w;
255 XtValueMask *mask;
256 XSetWindowAttributes *value;
257 {
258 KinputProtocolWidget kpw = (KinputProtocolWidget)w;
259 CoreWidgetClass super = (CoreWidgetClass)XtClass(w)->core_class.superclass;
260
261 (*super->core_class.realize)(w, mask, value);
262
263 setJinputProperty(kpw);
264 setKinput2Property(kpw);
265 setXlcProperty(kpw);
266
267 if (!ownSelection(kpw)) {
268 String params[1];
269 Cardinal num_params;
270
271 params[0] = XtClass(w)->core_class.class_name;
272 num_params = 1;
273 XtAppWarningMsg(XtWidgetToApplicationContext(w),
274 "selectionError", "ownSelection", "WidgetError",
275 "%s: can't own selection", params, &num_params);
276
277 XtDestroyWidget(w);
278 } else {
279 CMPrepareConverter(XtParent(w), XtScreen(w),
280 separateConversionWidgetClass,
281 kpw->kinput.inputObjClass,
282 kpw->kinput.displayObjClass);
283 }
284 }
285
286 /*- SetValues: not implemented yet -*/
287 /* ARGSUSED */
288 static Boolean
289 SetValues(cur, req, wid, args, num_args)
290 Widget cur;
291 Widget req;
292 Widget wid;
293 ArgList args;
294 Cardinal *num_args;
295 {
296 #ifdef notdef
297 KinputProtocolWidget old = (KinputProtocolWidget)cur;
298 KinputProtocolWidget new = (KinputProtocolWidget)wid;
299 Boolean redisplay = False;
300 #endif
301
302 return False;
303 }
304
305 /*
306 *+ atom handling
307 */
308
309 /*- getAtoms: intern atoms -*/
310 static void
311 getAtoms(kpw)
312 KinputProtocolWidget kpw;
313 {
314 Display *dpy = XtDisplay((Widget)kpw);
315 char buf[256];
316
317 (void)sprintf(buf, "_%s_CONVERSION", kpw->kinput.language);
318 kpw->kinput.convAtom = XInternAtom(dpy, buf, False);
319 if (kpw->kinput.backward_compatible) {
320 (void)sprintf(buf, "%s_CONVERSION", kpw->kinput.language);
321 kpw->kinput.oldConvAtom = XInternAtom(dpy, buf, False);
322 } else {
323 kpw->kinput.oldConvAtom = None;
324 }
325
326 kpw->kinput.ctextAtom = XA_COMPOUND_TEXT(dpy);
327
328 #define MAKEATOM(s) XInternAtom(dpy, s, False)
329
330 kpw->kinput.convStringAtom = MAKEATOM("CONVERSION_STRING");
331 kpw->kinput.convNotifyAtom = MAKEATOM("CONVERSION_NOTIFY");
332 kpw->kinput.convEndAtom = MAKEATOM("CONVERSION_END");
333
334 (void)sprintf(buf, "%s_CONVERSION_VERSION", kpw->kinput.language);
335 kpw->kinput.convVersionAtom = XInternAtom(dpy, buf, False);
336 kpw->kinput.convInitialTypeAtom = MAKEATOM("CONVERSION_INITIAL_TYPE");
337 kpw->kinput.convOpenNotifyAtom = MAKEATOM("CONVERSION_OPEN_NOTIFY");
338 kpw->kinput.convXYRequestAtom = MAKEATOM("CONVERSION_XY_REQUEST");
339 kpw->kinput.convFontsRequestAtom = MAKEATOM("CONVERSION_FONTS_REQUEST");
340 kpw->kinput.convColorRequestAtom = MAKEATOM("CONVERSION_COLOR_REQUEST");
341 kpw->kinput.convCloseNotifyAtom = MAKEATOM("CONVERSION_CLOSE_NOTIFY");
342 kpw->kinput.convAttributeAtom = MAKEATOM("CONVERSION_ATTRIBUTE");
343 kpw->kinput.xlcStatusAtom = MAKEATOM("_XLC_STATUS");
344 kpw->kinput.xlcOnTheSpotAtom = MAKEATOM("_XLC_ON_THE_SPOT");
345 kpw->kinput.xlcBcModifierAtom = MAKEATOM("_XLC_BC_MODIFIER");
346 kpw->kinput.xlcBcKeycodeAtom = MAKEATOM("_XLC_BC_KEYCODE");
347
348 /*
349 * some of the clients who speak Xlc protocol check the existence
350 * of atom "CONVERSION_REQUEST" before starting conversion.
351 * so make it at initialization time.
352 */
353 (void)MAKEATOM("CONVERSION_REQUEST");
354
355 #undef MAKEATOM
356 }
357
358 /*- ownSelection: own conversion selection -*/
359 static Boolean
360 ownSelection(kpw)
361 KinputProtocolWidget kpw;
362 {
363 Display *dpy = XtDisplay((Widget)kpw);
364 Window w = XtWindow((Widget)kpw);
365 Boolean res;
366
367 TRACE(("kinputProtocol:ownSelection()\n"));
368 XSetSelectionOwner(dpy, kpw->kinput.convAtom, w, CurrentTime);
369 /* $B0l1~(B SetSelectionOwner $B$7$?8e(B GetSelectionOwner $B$7$F$_$F3N$+$a$k(B */
370 res = XGetSelectionOwner(XtDisplay((Widget)kpw), kpw->kinput.convAtom) == w;
371
372 if (kpw->kinput.backward_compatible) {
373 XSetSelectionOwner(dpy, kpw->kinput.oldConvAtom, w, CurrentTime);
374 }
375
376 return res;
377 }
378
379 /*
380 *+ client data handling
381 */
382
383 /*- findClient: get clientdata of given client -*/
384 static ConvClient *
385 findClient(kpw, client)
386 KinputProtocolWidget kpw;
387 Window client;
388 {
389 register ConvClient *ccp = kpw->kinput.clients;
390
391 while (ccp != NULL) {
392 if (ccp->reqwin == client) return ccp;
393 ccp = ccp->next;
394 }
395
396 return NULL;
397 }
398
399 /*- newClient: get a clientdata for new client -*/
400 static ConvClient *
401 newClient(kpw, client, selection)
402 KinputProtocolWidget kpw;
403 Window client;
404 Atom selection;
405 {
406 ConvClient *ccp;
407
408 ccp = XtNew(ConvClient);
409 ccp->protocol = unresolved_protocol;
410 ccp->style = separate_style; /* default */
411 ccp->protocolwidget = (Widget)kpw;
412 ccp->conversion = NULL;
413 ccp->reqwin = client;
414 ccp->selection = selection;
415 ccp->target = None;
416 ccp->property = None;
417 ccp->esm = ESMethodNone;
418 ccp->data = NULL;
419 ccp->attrmask = 0L;
420 ccp->validattrmask = 0L;
421 ccp->start_proc = NULL;
422 ccp->detach_proc = NULL;
423 ccp->fix_proc = NULL;
424 ccp->end_proc = NULL;
425 ccp->free_resources = NULL;
426
427 ccp->next = kpw->kinput.clients;
428 kpw->kinput.clients = ccp;
429
430 return ccp;
431 }
432
433 /*- attachConverter: attach converter to the client -*/
434 static Widget
435 attachConverter(ccp)
436 ConvClient *ccp;
437 {
438 WidgetClass class;
439 KinputProtocolWidget kpw = (KinputProtocolWidget)ccp->protocolwidget;
440
441 if (ccp->conversion != NULL) return ccp->conversion;
442
443 if (ccp->protocol == unresolved_protocol) {
444 ccp->protocol = kinput1_protocol;
445 ccp->style = separate_style;
446 }
447
448 if (ccp->style == overthespot_style) {
449 class = overTheSpotConversionWidgetClass;
450 } else if (ccp->style == offthespot_style) {
451 class = offTheSpotConversionWidgetClass;
452 } else {
453 class = separateConversionWidgetClass;
454 }
455
456 ccp->conversion = CMGetConverter(XtParent(ccp->protocolwidget),
457 ccp->reqwin, class,
458 kpw->kinput.inputObjClass,
459 kpw->kinput.displayObjClass);
460
461 return ccp->conversion;
462 }
463
464 /*- detachConverter: detach converter from client -*/
465 static void
466 detachConverter(ccp)
467 ConvClient *ccp;
468 {
469 TRACE(("detachConverter(window=0x%lx)\n", ccp->reqwin));
470
471 XtRemoveCallback(ccp->conversion, XtNtextCallback,
472 fixCallback, (XtPointer)ccp);
473 XtRemoveCallback(ccp->conversion, XtNendCallback,
474 endCallback, (XtPointer)ccp);
475
476 /* call additional detach proc */
477 if (ccp->detach_proc != NULL) (*ccp->detach_proc)(ccp);
478
479 CMReleaseConverter(XtParent(ccp->protocolwidget), ccp->conversion);
480 ccp->conversion = NULL;
481 }
482
483 /*- jinputDetach: jinput protocol specific detach processing -*/
484 static void
485 jinputDetach(client)
486 ConvClient *client;
487 {
488 XtRemoveCallback(client->conversion, XtNnewTextCallback,
489 jinputNewTextCallback, (XtPointer)client);
490 }
491
492 /*- deleteClient: delete specified client -*/
493 static void
494 deleteClient(client)
495 ConvClient *client;
496 {
497 KinputProtocolWidget kpw = (KinputProtocolWidget)client->protocolwidget;
498 ConvClient *ccp, *ccp0;
499
500 TRACE(("deleteClient(window=0x%lx)\n", client->reqwin));
501 if (client->conversion != NULL) detachConverter(client);
502 if (client->free_resources != NULL) (*client->free_resources)(client);
503
504 for (ccp = kpw->kinput.clients, ccp0 = NULL;
505 ccp != NULL;
506 ccp0 = ccp, ccp = ccp->next) {
507 if (ccp == client) {
508 if (ccp0 == NULL) {
509 kpw->kinput.clients = ccp->next;
510 } else {
511 ccp0->next = ccp->next;
512 }
513 XtFree((char *)client);
514 return;
515 }
516 }
517 DPRINT(("deleteClient: cannot find the client in the client list!\n"));
518 }
519
520 /*
521 *+ utility functions
522 */
523
524 /*- isCorrectClientEvent: is the event in correct format? -*/
525 static Boolean
526 isCorrectClientEvent(kpw, event)
527 KinputProtocolWidget kpw;
528 XEvent *event;
529 {
530 XClientMessageEvent *ev = &(event->xclient);
531 Atom atom = (Atom)ev->data.l[0];
532
533 return (ev->window == XtWindow((Widget)kpw) &&
534 ev->format == 32 &&
535 (atom == kpw->kinput.convAtom ||
536 kpw->kinput.backward_compatible && atom == kpw->kinput.oldConvAtom));
537 }
538
539 /*- isCorrectWindowID: is the given window ID valid? -*/
540 static Boolean
541 isCorrectWindowID(w, window)
542 Widget w;
543 Window window;
544 {
545 int status;
546 Window root;
547 int x, y;
548 unsigned int width, height, bwidth, depth;
549 XAEHandle h;
550
551 /*
552 * previous version uses XGetWindowAttributes(), which
553 * issues both GetWindowAttributes and GetGeometry request.
554 * since it is a bit inefficient to issue two requests just
555 * for checking if a window exists, I've changed to use
556 * XGetGeometry which issues only GetGeometry.
557 */
558 h = XAESetIgnoreErrors(XtDisplay(w));
559 status = XGetGeometry(XtDisplay(w), window, &root, &x, &y,
560 &width, &height, &bwidth, &depth);
561 XAEUnset(h);
562 return status == 0 ? False : True;
563 }
564
565 /*- myStartConversion: custom version of CControlStartConversion -*/
566 static void
567 myStartConversion(w, clwin, mask, attrs)
568 Widget w;
569 Window clwin;
570 unsigned long mask;
571 ConversionAttributes *attrs;
572 {
573 if (mask & CAFonts) {
574 mask |= CAStatusFonts;
575 attrs->status_fonts = attrs->fonts;
576 attrs->num_status_fonts = attrs->num_fonts;
577 } else {
578 mask &= ~CAStatusFonts;
579 }
580 CControlStartConversion(w, clwin, mask, attrs);
581 }
582
583 /*- myChangeAttributes: custom version of CControlChangeAttributes -*/
584 static void
585 myChangeAttributes(w, mask, attrs)
586 Widget w;
587 unsigned long mask;
588 ConversionAttributes *attrs;
589 {
590 if (mask & CAFonts) {
591 mask |= CAStatusFonts;
592 attrs->status_fonts = attrs->fonts;
593 attrs->num_status_fonts = attrs->num_fonts;
594 } else {
595 mask &= ~CAStatusFonts;
596 }
597 CControlChangeAttributes(w, mask, attrs);
598 }
599
600 /*- getJinputInitialProperty: get property for jinput protocol and set data -*/
601 static void
602 getJinputInitialProperty(kpw, ccp, prop, reqtype)
603 KinputProtocolWidget kpw;
604 ConvClient *ccp;
605 Atom prop;
606 Atom reqtype;
607 {
608 Atom type;
609 int format;
610 unsigned long nitems;
611 long *data;
612 unsigned long bytesafter;
613 JinputData *jdp = (JinputData *)ccp->data;
614
615 XGetWindowProperty(XtDisplay((Widget)kpw), ccp->reqwin, prop, 0L, 11L,
616 False, reqtype, &type, &format, &nitems,
617 &bytesafter, (unsigned char **)&data);
618
619 if (type != reqtype) {
620 DPRINT(("getJinputInitialProperty(): unknown property type (%ld)\n", type));
621 return;
622 }
623
624 /* data[0]: version number */
625 if (data[0] != JINPUT_PROTOCOL_VERSION) {
626 DPRINT(("getJinputInitialProperty(): unknown version (0x%lx)\n", data[0]));
627 return;
628 }
629 /* data[1]: requestor window */
630 if (data[1] != ccp->reqwin) {
631 return;
632 }
633 /* data[2]: preedit type */
634 if (data[2] == 3) {
635 /* over-the-spot */
636 ccp->style = overthespot_style;
637 } else {
638 ccp->style = separate_style;
639 }
640 /* data[3]: fold mode (ignore) */
641 /* data[4]: clip mode (ignore) */
642 /* data[5]: multi color mode */
643 if (data[5] == 0) {
644 /* fixed color */
645 ccp->attrmask |= CAColor;
646 /* data[6]: background */
647 ccp->attrs.background = data[6];
648 /* data[7]: foreground */
649 ccp->attrs.foreground = data[7];
650 } else {
651 /* query */
652 DPRINT(("getJinputInitialProperty(): multi-color mode\n"));
653 jdp->state |= JINPUT_MULTI_COLOR;
654 }
655 /* data[8]: multi font mode */
656 if (data[8] == 0) {
657 ccp->attrmask |= CAFonts;
658 ccp->attrs.num_fonts = 2;
659 ccp->attrs.fonts = (XFontStruct **)XtMalloc(sizeof(XFontStruct *) * 2);
660 /* data[9]: font1 */
661 ccp->attrs.fonts[0] = XQueryFont(XtDisplay((Widget)kpw),
662 (XID)data[9]); /* should make it safe */
663 /* data[10]: font2 */
664 ccp->attrs.fonts[1] = XQueryFont(XtDisplay((Widget)kpw),
665 (XID)data[10]);
666 } else {
667 /* query */
668 TRACE(("getJinputInitialProperty(): multi-font mode\n"));
669 jdp->state |= JINPUT_MULTI_FONT;
670 }
671 }
672
673 /*- jinputSendReq: jinput protocol specific startup processing -*/
674 static void
675 jinputSendReq(client)
676 ConvClient *client;
677 {
678 JinputData *jdp = (JinputData *)client->data;
679
680 XtAddCallback(client->conversion, XtNnewTextCallback,
681 jinputNewTextCallback, (XtPointer)client);
682
683 if (jdp->state & JINPUT_MULTI_COLOR) sendColorRequest(client);
684 if (jdp->state & JINPUT_MULTI_FONT) sendFontRequest(client);
685 if (client->style != separate_style) sendXYRequest(client);
686 }
687
688 /*- jinputFreeResources: free resources for jinput protocol client -*/
689 static void
690 jinputFreeResources(client)
691 ConvClient *client;
692 {
693 XtFree(client->data);
694 if (client->attrmask & CAFonts) {
695 /* free fonts */
696 XFreeFontInfo((char **)NULL, client->attrs.fonts[0], 1);
697 XFreeFontInfo((char **)NULL, client->attrs.fonts[1], 1);
698 XtFree((char *)client->attrs.fonts);
699 }
700 }
701
702 /*- xlcFreeResources: free resources for xlc protocol client -*/
703 static void
704 xlcFreeResources(client)
705 ConvClient *client;
706 {
707 if (client->validattrmask & CAFonts) {
708 /* free fonts */
709 XFreeFontInfo((char **)NULL, client->attrs.fonts[0], 1);
710 XFreeFontInfo((char **)NULL, client->attrs.fonts[1], 1);
711 XtFree((char *)client->attrs.fonts);
712 }
713 }
714
715 /*- kinput2FreeResources: free resources for kinput2 protocol client -*/
716 static void
717 kinput2FreeResources(client)
718 ConvClient *client;
719 {
720 if (client->attrmask & CAFonts) { /* free fonts */
721 Cardinal i;
722 for (i = 0; i < client->attrs.num_fonts; i++) {
723 CachedFreeFont(XtDisplay(client->protocolwidget),
724 client->attrs.fonts[i]);
725 }
726 XtFree((char *)client->attrs.fonts);
727 }
728 }
729
730 struct proprec {
731 Atom prop;
732 struct proprec *prev;
733 };
734
735 /*- setAttribute: set conversion attribute (kinput2 only) -*/
736 static void
737 setAttribute(client, data, precp, fromevent)
738 ConvClient *client;
739 unsigned long *data;
740 struct proprec *precp; /* to prevent possible inifinite loop */
741 Boolean fromevent;
742 {
743 int code = CODE_OF_ATTR(*data);
744 int len = LENGTH_OF_ATTR(*data);
745
746 #define CHECK_LENGTH(num, name) \
747 if (len != num) { DPRINT(("\tlength of %s attribute is wrong\n", name)); break; }
748
749 TRACE(("setAttribute()\n"));
750 data++;
751 switch (code) {
752 case CONVATTR_NONE:
753 TRACE(("\tNone:\n"));
754 break;
755 case CONVATTR_INDIRECT:
756 CHECK_LENGTH(1, "IndirectAttribute");
757 TRACE(("\tIndirectAttribute:\n"));
758 getAttributeFromProperty1(client, data[0], precp, fromevent);
759 break;
760 case CONVATTR_FOCUS_WINDOW:
761 CHECK_LENGTH(1, "FocusWindow");
762 client->attrmask |= CAFocusWindow;
763 client->attrs.focuswindow = data[0];
764 TRACE(("\tFocusWindow: 0x%lx\n", data[0]));
765 break;
766 case CONVATTR_SPOT_LOCATION:
767 CHECK_LENGTH(1, "SpotLocation");
768 client->attrmask |= CASpotLocation;
769 client->attrs.spotx = UPPER16S(data[0]);
770 client->attrs.spoty = LOWER16S(data[0]);
771 TRACE(("\tSpotLocation: x=%d, y=%d\n", client->attrs.spotx, client->attrs.spoty));
772 break;
773 case CONVATTR_CLIENT_AREA:
774 CHECK_LENGTH(2, "ClientArea");
775 client->attrmask |= CAClientArea;
776 client->attrs.clientarea.x = UPPER16S(data[0]);
777 client->attrs.clientarea.y = LOWER16S(data[0]);
778 client->attrs.clientarea.width = UPPER16U(data[1]);
779 client->attrs.clientarea.height = LOWER16U(data[1]);
780 TRACE(("\tClientArea: %d,%d-%d,%d\n", client->attrs.clientarea.x,client->attrs.clientarea.y,client->attrs.clientarea.width,client->attrs.clientarea.height));
781 break;
782 case CONVATTR_STATUS_AREA:
783 CHECK_LENGTH(2, "StatusArea");
784 client->attrmask |= CAStatusArea;
785 client->attrs.statusarea.x = UPPER16S(data[0]);
786 client->attrs.statusarea.y = LOWER16S(data[0]);
787 client->attrs.statusarea.width = UPPER16U(data[1]);
788 client->attrs.statusarea.height = LOWER16U(data[1]);
789 TRACE(("\tStatusArea: %d,%d-%d,%d\n", client->attrs.statusarea.x,client->attrs.statusarea.y,client->attrs.statusarea.width,client->attrs.statusarea.height));
790 break;
791 case CONVATTR_COLORMAP:
792 CHECK_LENGTH(1, "Colormap");
793 client->attrmask |= CAColormap;
794 client->attrs.colormap = data[0];
795 TRACE(("\tColormap: 0x%lx\n", data[0]));
796 break;
797 case CONVATTR_COLOR:
798 CHECK_LENGTH(2, "Color");
799 client->attrmask |= CAColor;
800 client->attrs.foreground = data[0];
801 client->attrs.background = data[1];
802 TRACE(("\tColor: fg=%ld,bg=%ld\n", data[0], data[1]));
803 break;
804 case CONVATTR_BACKGROUND_PIXMAP:
805 CHECK_LENGTH(1, "BackgroundPixmap");
806 client->attrmask |= CABackgroundPixmap;
807 client->attrs.background_pixmap = data[0];
808 TRACE(("\tBackgroundPixmap: 0x%lx\n", data[0]));
809 break;
810 case CONVATTR_LINE_SPACING:
811 CHECK_LENGTH(1, "LineSpacing");
812 client->attrmask |= CALineSpacing;
813 client->attrs.linespacing = data[0];
814 TRACE(("\tLineSpacing: %ld\n", data[0]));
815 break;
816 case CONVATTR_FONT_ATOMS:
817 if (len < 1) {
818 DPRINT(("length of FontAtoms attribute is less than 1\n"));
819 break;
820 }
821 if (client->attrmask & CAFonts) {
822 /* fonts set more than once -- free previously specified fonts */
823 Cardinal i;
824 for (i = 0; i < client->attrs.num_fonts; i++) {
825 CachedFreeFont(XtDisplay(client->protocolwidget),
826 client->attrs.fonts[i]);
827 }
828 XtFree((char *)client->attrs.fonts);
829 }
830 client->attrmask |= CAFonts;
831 client->attrs.num_fonts =
832 getFontsByFontAtoms(XtDisplay(client->protocolwidget),
833 (Atom *)data, (Cardinal)len,
834 &client->attrs.fonts);
835 break;
836 case CONVATTR_CURSOR:
837 CHECK_LENGTH(1, "Cursor");
838 client->attrmask |= CACursor;
839 client->attrs.cursor = data[0];
840 TRACE(("\tCursor: 0x%lx\n", data[0]));
841 break;
842 case CONVATTR_INPUT_STYLE:
843 if (fromevent) {
844 DPRINT(("InputStyle can't change during conversion\n"));
845 break;
846 }
847 CHECK_LENGTH(1, "InputStyle");
848 if (data[0] == CONVARG_OVERTHESPOT) {
849 client->style = overthespot_style;
850 } else if (data[0] == CONVARG_OFFTHESPOT) {
851 client->style = offthespot_style;
852 } else {
853 client->style = separate_style;
854 }
855 TRACE(("\tInputStyle: %ld\n", data[0]));
856 break;
857 case CONVATTR_EVENT_CAPTURE_METHOD:
858 if (fromevent) {
859 DPRINT(("EventCaptureMethod can't change during conversion\n"));
860 break;
861 }
862 CHECK_LENGTH(1, "EventCaptureMethod");
863 if (data[0] == CONVARG_NONE) {
864 client->esm = ESMethodNone;
865 } else if (data[0] == CONVARG_SELECT_FOCUS_WINDOW) {
866 client->esm = ESMethodSelectFocus;
867 } else {
868 client->esm = ESMethodInputOnly;
869 }
870 TRACE(("\tEventCaptureMethod: %ld\n", data[0]));
871 break;
872 case CONVATTR_USE_EXTENSION:
873 if (fromevent) {
874 DPRINT(("UseExtension must be specified at conversion startup\n"));
875 break;
876 }
877 TRACE(("\tUseExtension: not supported\n"));
878 break;
879 default:
880 if (code > 255) {
881 /* private extension code */
882 DPRINT(("\tPrivateExtension (code=%d): not supported\n", code));
883 }
884 }
885 #undef CHECK_LENGTH
886 }
887
888 /*- getFontsByFontAtoms: get fonts from 'FONT' atom list (kinput2 only) -*/
889 static int
890 getFontsByFontAtoms(dpy, atoms, len, fontsp)
891 Display *dpy;
892 Atom *atoms;
893 Cardinal len;
894 XFontStruct *** fontsp;
895 {
896 XFontStruct **fonts;
897 Cardinal nf, i;
898
899 fonts = (XFontStruct **)XtMalloc(sizeof(XFontStruct *) * len);
900 for (nf = 0, i = 0; i < len; i++) {
901 if ((fonts[nf] = CachedLoadQueryFontByProp(dpy, atoms[i])) == NULL) {
902 TRACE(("\tcan't load font (atom=%ld)\n", atoms[i]));
903 } else {
904 TRACE(("\tfont loaded (atom=%ld)\n", atoms[i]));
905 nf++;
906 }
907 }
908
909 *fontsp = fonts;
910 return nf;
911 }
912
913 /*- safeGetAttributeProperty: get attribute property safely -*/
914 static int
915 safeGetAttributeProperty(client, prop, data)
916 ConvClient *client;
917 Atom prop;
918 unsigned long **data;
919 {
920 KinputProtocolWidget kpw = (KinputProtocolWidget)client->protocolwidget;
921 int err;
922 Atom type;
923 int format;
924 unsigned long nitems;
925 unsigned long bytesafter;
926 XAEHandle h;
927
928 *data = NULL;
929
930 h = XAESetIgnoreErrors(XtDisplay((Widget)kpw));
931 err = XGetWindowProperty(XtDisplay((Widget)kpw), client->reqwin, prop,
932 0L, 1000L, False,
933 kpw->kinput.convAttributeAtom,
934 &type, &format, &nitems,
935 &bytesafter, (unsigned char **)data);
936 XAEUnset(h);
937
938 if (err) {
939 DPRINT(("\tcan't get property value. bad property (0x%lx)?\n", prop));
940 return 0;
941 }else if (format != 32 || type != kpw->kinput.convAttributeAtom) {
942 DPRINT(("\twrong format or type\n"));
943 if (*data != NULL) XtFree((char *)*data);
944 return 0;
945 }
946
947 TRACE(("safeGetAttributeProperty(): returns %ld\n", nitems));
948 return nitems;
949 }
950
951 /*- getAttributeFromProperty1: get and set attribute data (kinput2 only) -*/
952 static void
953 getAttributeFromProperty1(client, prop, precp, fromevent)
954 ConvClient *client;
955 Atom prop;
956 struct proprec *precp;
957 Boolean fromevent;
958 {
959 unsigned long *data, *datap;
960 int nitems;
961 struct proprec prec;
962
963 prec.prop = prop;
964 prec.prev = precp;
965
966 /* try to detect loop */
967 while (precp != NULL) {
968 if (precp->prop == prop) {
969 DPRINT(("loop detected. property=0x%lx\n", prop));
970 return;
971 }
972 precp = precp->prev;
973 }
974
975 data = NULL;
976 if ((nitems = safeGetAttributeProperty(client, prop, &data)) <= 0) {
977 return;
978 }
979
980 datap = data;
981 while (nitems > 0) {
982 int alen = LENGTH_OF_ATTR(datap[0]) + 1; /* 1 is for the header */
983
984 if (alen > nitems) break;
985 setAttribute(client, datap, &prec, fromevent);
986 nitems -= alen;
987 datap += alen;
988 }
989 XtFree((char *)data);
990 }
991
992 /*- getAttributeFromProperty: get and set attribute data (kinput2 only) -*/
993 static void
994 getAttributeFromProperty(client, prop)
995 ConvClient *client;
996 Atom prop;
997 {
998 TRACE(("getAttributeFromProperty(reqwin=0x%lx, prop=%ld)\n", client->reqwin, prop));
999 getAttributeFromProperty1(client, prop, (struct proprec *)NULL, False);
1000 }
1001
1002 /*- getAttributeFromEvent: set attribute data specified in an event (kinput2 only) -*/
1003 static void
1004 getAttributeFromEvent(client, ev)
1005 ConvClient *client;
1006 XEvent *ev;
1007 {
1008 XClientMessageEvent *event = &(ev->xclient);
1009 unsigned long *data;
1010 int alen;
1011
1012 TRACE(("getAttributeFromEvent(client=0x%lx)\n", client->reqwin));
1013
1014 data = (unsigned long *)&(event->data.l[2]);
1015 alen = LENGTH_OF_ATTR(data[0]);
1016 if (alen >= 3) return;
1017
1018 setAttribute(client, data, (struct proprec *)NULL, True);
1019 }
1020
1021 /*- getXlcDataFromProperty: get and set attribute data (xlc only) -*/
1022 static ConvClient *
1023 getXlcDataFromProperty(kpw, client, initial)
1024 KinputProtocolWidget kpw;
1025 ConvClient *client;
1026 Boolean initial;
1027 {
1028 unsigned long *data;
1029 Atom type;
1030 int format;
1031 unsigned long nitems;
1032 unsigned long bytesafter;
1033 int flag;
1034 int err;
1035
1036 TRACE(("getXlcDataFromProperty(initial=%d)\n", initial));
1037 data = NULL;
1038 err = XGetWindowProperty(XtDisplay((Widget)kpw), XtWindow((Widget)kpw),
1039 kpw->kinput.xlcOnTheSpotAtom,
1040 0L, 1000L, True,
1041 kpw->kinput.xlcOnTheSpotAtom,
1042 &type, &format, &nitems,
1043 &bytesafter, (unsigned char **)&data);
1044
1045 if (err) {
1046 DPRINT(("\tcan't get property value\n"));
1047 return NULL;
1048 } else if (/* format != 32 || */ type != kpw->kinput.xlcOnTheSpotAtom) {
1049 DPRINT(("\twrong format(%d) or type(%ld)\n", format, type));
1050 if (data != NULL) XtFree((char *)data);
1051 return NULL;
1052 } else if (nitems < 17) {
1053 /* it seems that the current implementation of Xlc library
1054 * (client-side library for XLC protocol) has a bug.
1055 * it seems to set number of bytes instead of number of items
1056 * when calling XChangeProperty().
1057 */
1058 DPRINT(("\twrong length (%ld)\n", nitems));
1059 return NULL;
1060 }
1061
1062 if (client == NULL) {
1063 if ((client = findClient(kpw, (Window)data[1])) == NULL) {
1064 TRACE(("\tcreate new client rec. for the window ID\n"));
1065 /* check validity of the client window ID */
1066 if (!isCorrectWindowID(kpw, (Window)data[1])) {
1067 DPRINT(("getXlcDataFromProperty(): client window doesn't exist\n"));
1068 return NULL;
1069 }
1070 client = newClient(kpw, (Window)data[1], None);
1071 client->protocol = xlc_protocol;
1072 client->style = overthespot_style;
1073 client->esm = ESMethodInputOnly;
1074 client->end_proc = xlcEnd;
1075 client->free_resources = xlcFreeResources;
1076 MyAddEventHandler(XtDisplay((Widget)kpw), client->reqwin,
1077 DestroyNotify, StructureNotifyMask,
1078 ClientDead, (XtPointer)client);
1079 initial = True;
1080 }
1081 } else {
1082 if (data[1] != client->reqwin) {
1083 DPRINT(("\twindow ID isn't the requestor window ID\n"));
1084 return NULL;
1085 }
1086 }
1087 TRACE(("\t%ld items read\n", nitems));
1088
1089 flag = data[0];
1090 if (flag & XLC_AUTO_REPLACE) {
1091 /* set auto spot forwarding */
1092 /* XXX */
1093 TRACE(("\tauto spot forwarding\n"));
1094 }
1095 if (flag & XLC_ALL_INFORMATION) {
1096 /* foreground / background colors */
1097 if (!initial &&
1098 (client->validattrmask & CAColor) &&
1099 client->attrs.foreground == data[5] &&
1100 client->attrs.background == data[6]) {
1101 client->attrmask &= ~CAColor;
1102 } else {
1103 client->attrs.foreground = data[5];
1104 client->attrs.background = data[6];
1105 client->attrmask |= CAColor;
1106 }
1107 client->validattrmask |= CAColor;
1108 TRACE(("\tColor: fg=%ld,bg=%ld\n", data[5], data[6]));
1109
1110 /* fonts */
1111 if (data[7] == 0L || data[8] == 0L) {
1112 /* invalid */
1113 if (client->validattrmask & CAFonts) {
1114 XFreeFontInfo((char **)NULL, client->attrs.fonts[0], 1);
1115 XFreeFontInfo((char **)NULL, client->attrs.fonts[2], 1);
1116 XFree((char *)client->attrs.fonts);
1117 client->validattrmask &= ~CAFonts;
1118 }
1119 client->attrmask &= ~CAFonts;
1120 } else {
1121 if (!initial &&
1122 (client->validattrmask & CAFonts) &&
1123 client->attrs.fonts[0]->fid == data[7] &&
1124 client->attrs.fonts[1]->fid == data[8]) {
1125 client->attrmask &= ~CAFonts;
1126 } else if (client->validattrmask & CAFonts) {
1127 if (client->attrs.fonts[0]->fid != data[7]) {
1128 XFreeFontInfo((char **)NULL, client->attrs.fonts[0], 1);
1129 client->attrs.fonts[0] = XQueryFont(XtDisplay((Widget)kpw),
1130 (XID)data[7]);
1131 }
1132 if (client->attrs.fonts[1]->fid != data[8]) {
1133 XFreeFontInfo((char **)NULL, client->attrs.fonts[1], 1);
1134 client->attrs.fonts[1] = XQueryFont(XtDisplay((Widget)kpw),
1135 (XID)data[8]);
1136 }
1137 client->attrmask |= CAFonts;
1138 } else {
1139 client->attrs.num_fonts = 2;
1140 client->attrs.fonts =
1141 (XFontStruct **)XtMalloc(sizeof(XFontStruct *) * 2);
1142 client->attrs.fonts[0] = XQueryFont(XtDisplay((Widget)kpw),
1143 (XID)data[7]);
1144 client->attrs.fonts[1] = XQueryFont(XtDisplay((Widget)kpw),
1145 (XID)data[8]);
1146 client->attrmask |= CAFonts;
1147 }
1148 client->validattrmask |= CAFonts;
1149 TRACE(("\tFonts: 0x%lx, 0x%lx\n", data[7], data[8]));
1150 }
1151 }
1152 if (flag & (XLC_ALL_INFORMATION | XLC_FRAME_INFORMATION)) {
1153 /* frame (client area) */
1154 if (!initial &&
1155 (client->validattrmask & CAClientArea) &&
1156 client->attrs.clientarea.x == data[10] &&
1157 client->attrs.clientarea.y == data[11] &&
1158 client->attrs.clientarea.width == data[12] &&
1159 client->attrs.clientarea.height == data[13]) {
1160 client->attrmask &= ~CAClientArea;
1161 } else {
1162 client->attrs.clientarea.x = data[10];
1163 client->attrs.clientarea.y = data[11];
1164 client->attrs.clientarea.width = data[12];
1165 client->attrs.clientarea.height = data[13];
1166 if (data[12] == 0 || data[13] == 0) {
1167 client->attrmask &= ~CAClientArea;
1168 } else {
1169 client->attrmask |= CAClientArea;
1170 }
1171 }
1172 client->validattrmask |= CAClientArea;
1173 TRACE(("\tClientArea: %ld,%ld-%ld,%ld\n",
1174 data[10],data[11],data[12],data[13]));
1175 }
1176 if (flag & (XLC_ALL_INFORMATION | XLC_FRAME_INFORMATION | XLC_OFFSET_INFORMATION)) {
1177 /* spot location */
1178 client->attrmask |= CASpotLocation; /* always set spot location */
1179 client->attrs.spotx = data[14];
1180 client->attrs.spoty = data[15] +
1181 ((client->validattrmask & CAFonts) ?
1182 client->attrs.fonts[0]->ascent : kpw->kinput.defaultascent);
1183 client->validattrmask |= CASpotLocation;
1184 TRACE(("\tSpotLocation: x=%ld, y=%ld\n", data[14], data[15]));
1185
1186 /* line spacing */
1187 if (!initial &&
1188 (client->validattrmask & CALineSpacing) &&
1189 client->attrs.linespacing == data[16]) {
1190 client->attrmask &= ~CALineSpacing;
1191 } else {
1192 client->attrmask |= CALineSpacing;
1193 client->attrs.linespacing = data[16];
1194 }
1195 client->validattrmask |= CALineSpacing;
1196 TRACE(("\tLineSpacing: %ld\n", data[16]));
1197 }
1198
1199 XtFree((char *)data);
1200 return client;
1201 }
1202
1203 /*- initializeError: display error message when resource isn't specified -*/
1204 static void
1205 initializeError(w, resname)
1206 Widget w;
1207 String resname;
1208 {
1209 String params[2];
1210 Cardinal num_params;
1211
1212 params[0] = XtClass(w)->core_class.class_name;
1213 params[1] = resname;
1214 num_params = 2;
1215 XtAppErrorMsg(XtWidgetToApplicationContext(w),
1216 "initializeError", "noResource", "WidgetError",
1217 "%s: resource %s must be specified at widget creation",
1218 params, &num_params);
1219 }
1220
1221 /*- parseKeyEvent: parses key event description and get keycode and modmask -*/
1222 static int
1223 parseKeyEvent(dpy, s, codep, modmaskp)
1224 Display *dpy;
1225 char *s;
1226 long *codep;
1227 long *modmaskp;
1228 {
1229 char *mod, *key;
1230 char *p;
1231 KeySym keysym;
1232 char buf[128];
1233
1234 /*
1235 * keyevent description (stored in argument 's') must be of the
1236 * following format:
1237 * modifier-list<Key>keysym
1238 * modifier-list is a combination of:
1239 * Ctrl, Shift, Lock, Meta, Alt, Mod1, Mod2, Mod3, Mod4, Mod5
1240 */
1241
1242 strcpy(buf, s);
1243
1244 /* find "<Key>" */
1245 if ((p = mystrstr(buf, "<Key>")) != NULL) {
1246 key = p + 5; /* p + strlen("<Key>") */
1247 } else if ((p = mystrstr(buf, "<KeyPress>")) != NULL) {
1248 key = p + 10; /* p + strlen("<KeyPress>") */
1249 } else if ((p = mystrstr(buf, "<KeyDown>")) != NULL) {
1250 key = p + 9; /* p + strlen("<KeyDown>") */
1251 } else {
1252 return 0;
1253 }
1254 mod = buf;
1255 *p = '\0';
1256
1257 /* get modifier mask */
1258 *modmaskp = 0;
1259 if (mystrstr(mod, "Shift")) *modmaskp |= ShiftMask;
1260 if (mystrstr(mod, "Lock")) *modmaskp |= LockMask;
1261 if (mystrstr(mod, "Ctrl")) *modmaskp |= ControlMask;
1262 if (mystrstr(mod, "Mod1")) *modmaskp |= Mod1Mask;
1263 if (mystrstr(mod, "Mod2")) *modmaskp |= Mod2Mask;
1264 if (mystrstr(mod, "Mod3")) *modmaskp |= Mod3Mask;
1265 if (mystrstr(mod, "Mod4")) *modmaskp |= Mod4Mask;
1266 if (mystrstr(mod, "Mod5")) *modmaskp |= Mod5Mask;
1267 if (mystrstr(mod, "Meta")) *modmaskp |= Mod1Mask;
1268 if (mystrstr(mod, "Alt")) *modmaskp |= Mod1Mask;
1269
1270 /* get keycode */
1271 if ((keysym = XStringToKeysym(key)) == NoSymbol) return 0;
1272 if ((*codep = (long)XKeysymToKeycode(dpy, keysym)) == 0) return 0;
1273 return 1;
1274 }
1275
1276 /*- mystrstr: not-so-good implementaion of ANSI strstr() -*/
1277 static char *
1278 mystrstr(s1, s2)
1279 char *s1;
1280 char *s2;
1281 {
1282 char *p, *q;
1283
1284 while (*(p = s1++) != '\0') {
1285 q = s2;
1286 do {
1287 if (*q == '\0') return s1 - 1;
1288 } while (*p++ == *q++);
1289 }
1290 return NULL;
1291 }
1292
1293 /*- getDefaultFontHeight: get default font ascent (for xlc protocol) -*/
1294 static void
1295 getDefaultFontHeight(kpw)
1296 KinputProtocolWidget kpw;
1297 {
1298 Widget obj;
1299
1300 obj = XtCreateWidget("displayObj", kpw->kinput.displayObjClass,
1301 (Widget)kpw, NULL, 0);
1302 (void)CDLineHeight(obj, &kpw->kinput.defaultascent);
1303 XtDestroyWidget(obj);
1304 }
1305
1306 /*
1307 *+ property handling
1308 */
1309
1310 /*- setJinputProperty: set version property for jinput protocol -*/
1311 static void
1312 setJinputProperty(kpw)
1313 KinputProtocolWidget kpw;
1314 {
1315 long version;
1316
1317 version = JINPUT_PROTOCOL_VERSION;
1318 XChangeProperty(XtDisplay((Widget)kpw), XtWindow((Widget)kpw),
1319 kpw->kinput.convVersionAtom, XA_INTEGER, 32,
1320 PropModeReplace, (unsigned char *)&version, 1);
1321 }
1322
1323 /*- setKinput2Property: set version property for kinput2 protocol -*/
1324 static void
1325 setKinput2Property(kpw)
1326 KinputProtocolWidget kpw;
1327 {
1328 Display *dpy = XtDisplay((Widget)kpw);
1329 Atom property;
1330 Atom type;
1331 unsigned long profile[10];
1332
1333 property = XInternAtom(dpy, CONVERSION_PROFILE, False);
1334 type = XInternAtom(dpy, CONVERSION_ATTRIBUTE_TYPE, False);
1335
1336 profile[0] = CONV_ATTR(CONVPROF_PROTOCOL_VERSION, 1);
1337 profile[1] = XInternAtom(dpy, PROTOCOL_VERSION, False);
1338 profile[2] = CONV_ATTR(CONVPROF_SUPPORTED_STYLES, 1);
1339 profile[3] = CONVARG_ROOTWINDOW|CONVARG_OFFTHESPOT|CONVARG_OVERTHESPOT;
1340
1341 XChangeProperty(dpy, XtWindow((Widget)kpw),
1342 property, type, 32, PropModeReplace,
1343 (unsigned char *)profile, 4);
1344 }
1345
1346 /*- setXlcProperty: set initial status property for xlc protocol -*/
1347 static void
1348 setXlcProperty(kpw)
1349 KinputProtocolWidget kpw;
1350 {
1351 setXlcStatusProperty(kpw, 0);
1352 setXlcBCKey(kpw);
1353 }
1354
1355 /*- setXlcStatusProperty: set status property for xlc protocol -*/
1356 static void
1357 setXlcStatusProperty(kpw, status)
1358 KinputProtocolWidget kpw;
1359 int status;
1360 {
1361 XChangeProperty(XtDisplay((Widget)kpw), XtWindow((Widget)kpw),
1362 kpw->kinput.xlcStatusAtom, XA_INTEGER, 32,
1363 PropModeReplace, (unsigned char *)&status, 1);
1364 }
1365
1366 /*- setXlcBCKey: set conversion start key code property for xlc protocol -*/
1367 static void
1368 setXlcBCKey(kpw)
1369 KinputProtocolWidget kpw;
1370 {
1371 long code;
1372 long mask;
1373
1374 if (kpw->kinput.xlcstartkey == NULL) return;
1375 if (parseKeyEvent(XtDisplay((Widget)kpw), kpw->kinput.xlcstartkey,
1376 &code, &mask) == 0) {
1377 String params[1];
1378 Cardinal num_params;
1379
1380 params[0] = XtClass((Widget)kpw)->core_class.class_name;
1381 num_params = 1;
1382 XtAppWarningMsg(XtWidgetToApplicationContext((Widget)kpw),
1383 "parseError", XtNxlcConversionStartKey, "WidgetError",
1384 "%s: can't parse coversion start key string",
1385 params, &num_params);
1386 return;
1387 }
1388
1389 TRACE(("setXlcBCKey(): keycode=%ld, mask=0x%lx\n", code, mask));
1390
1391 XChangeProperty(XtDisplay((Widget)kpw), XtWindow((Widget)kpw),
1392 kpw->kinput.xlcBcModifierAtom, XA_INTEGER, 32,
1393 PropModeReplace, (unsigned char *)&mask, 1);
1394 XChangeProperty(XtDisplay((Widget)kpw), XtWindow((Widget)kpw),
1395 kpw->kinput.xlcBcKeycodeAtom, XA_INTEGER, 32,
1396 PropModeReplace, (unsigned char *)&code, 1);
1397 }
1398
1399 /*
1400 *+ event sending
1401 */
1402
1403 /*- sendClientMessage: send a clientmessage event -*/
1404 static void
1405 sendClientMessage(dpy, window, type, l0, l1, l2, l3, l4)
1406 Display *dpy;
1407 Window window;
1408 Atom type;
1409 long l0, l1, l2, l3, l4;
1410 {
1411 XEvent event;
1412
1413 event.xclient.type = ClientMessage;
1414 event.xclient.window = window;
1415 event.xclient.message_type = type;
1416 event.xclient.format = 32;
1417 event.xclient.data.l[0] = l0;
1418 event.xclient.data.l[1] = l1;
1419 event.xclient.data.l[2] = l2;
1420 event.xclient.data.l[3] = l3;
1421 event.xclient.data.l[4] = l4;
1422
1423 XSendEvent(dpy, window, False, NoEventMask, &event);
1424 }
1425
1426 /*- sendNegativeConversionNotify: send negative conversion-notify event -*/
1427 static void
1428 sendNegativeConversionNotify(kpw, window, selection)
1429 KinputProtocolWidget kpw;
1430 Window window;
1431 Atom selection;
1432 {
1433 TRACE(("sendNegativeConversionNotify(window=0x%lx)\n", window));
1434 sendClientMessage(XtDisplay((Widget)kpw), window,
1435 kpw->kinput.convNotifyAtom,
1436 (long)selection, (long)None, 0L, 0L, 0L);
1437 }
1438
1439 /*- sendConversionNotify: send conversion-notify event -*/
1440 static void
1441 sendConversionNotify(ccp)
1442 ConvClient *ccp;
1443 {
1444 KinputProtocolWidget kpw = (KinputProtocolWidget)ccp->protocolwidget;
1445 long l4;
1446
1447 TRACE(("sendConversionNotify(reqwin=0x%lx)\n", ccp->reqwin));
1448 if (ccp->protocol == xlc_protocol) {
1449 l4 = (long)kpw->kinput.xlcOnTheSpotAtom;
1450 } else {
1451 l4 = 0L;
1452 }
1453 sendClientMessage(XtDisplay((Widget)kpw), ccp->reqwin,
1454 kpw->kinput.convNotifyAtom,
1455 (long)ccp->selection, (long)ccp->target,
1456 (long)ccp->property, (long)XtWindow(ccp->conversion),
1457 l4);
1458 }
1459
1460 /*- sendNegativeConversionOpenNotify: send negative conversion-open-notify event -*/
1461 static void
1462 sendNegativeConversionOpenNotify(kpw, window, selection)
1463 KinputProtocolWidget kpw;
1464 Window window;
1465 Atom selection;
1466 {
1467 TRACE(("sendNegativeConversionOpenNotify(window=0x%lx)\n", window));
1468 sendClientMessage(XtDisplay((Widget)kpw), window,
1469 kpw->kinput.convOpenNotifyAtom,
1470 (long)selection, 0L, (long)XtWindow(kpw), 0L, 0L);
1471 }
1472
1473 /*- sendConversionOpenNotify: send conversion-open-notify event -*/
1474 static void
1475 sendConversionOpenNotify(ccp)
1476 ConvClient *ccp;
1477 {
1478 KinputProtocolWidget kpw = (KinputProtocolWidget)ccp->protocolwidget;
1479
1480 TRACE(("sendConversionOpenNotify(reqwin=0x%lx)\n", ccp->reqwin));
1481 sendClientMessage(XtDisplay((Widget)kpw), ccp->reqwin,
1482 kpw->kinput.convOpenNotifyAtom,
1483 (long)ccp->selection, JINPUT_PROTOCOL_VERSION,
1484 (long)XtWindow((Widget)kpw), 1L, 0L);
1485 }
1486
1487 /*- sendColorRequest: send color-request event (jinput only) -*/
1488 static void
1489 sendColorRequest(ccp)
1490 ConvClient *ccp;
1491 {
1492 KinputProtocolWidget kpw = (KinputProtocolWidget)ccp->protocolwidget;
1493
1494 TRACE(("sendColorRequest(reqwin=0x%lx)\n", ccp->reqwin));
1495 sendClientMessage(XtDisplay((Widget)kpw), ccp->reqwin,
1496 kpw->kinput.convColorRequestAtom,
1497 (long)ccp->selection, JINPUT_PROTOCOL_VERSION,
1498 (long)XtWindow((Widget)kpw), 0L, 0L);
1499 }
1500
1501 /*- sendFontRequest: send font-request event (jinput only) -*/
1502 static void
1503 sendFontRequest(ccp)
1504 ConvClient *ccp;
1505 {
1506 KinputProtocolWidget kpw = (KinputProtocolWidget)ccp->protocolwidget;
1507
1508 TRACE(("sendFontRequest(reqwin=0x%lx)\n", ccp->reqwin));
1509 sendClientMessage(XtDisplay((Widget)kpw), ccp->reqwin,
1510 kpw->kinput.convFontsRequestAtom,
1511 (long)ccp->selection, JINPUT_PROTOCOL_VERSION,
1512 (long)XtWindow((Widget)kpw), 0L, 0L);
1513 }
1514
1515 /*- sendXYRequest: send XY-request event (jinput only) -*/
1516 static void
1517 sendXYRequest(ccp)
1518 ConvClient *ccp;
1519 {
1520 KinputProtocolWidget kpw = (KinputProtocolWidget)ccp->protocolwidget;
1521
1522 TRACE(("sendXYRequest(reqwin=0x%lx)\n", ccp->reqwin));
1523 sendClientMessage(XtDisplay((Widget)kpw), ccp->reqwin,
1524 kpw->kinput.convXYRequestAtom,
1525 (long)ccp->selection, JINPUT_PROTOCOL_VERSION,
1526 (long)XtWindow((Widget)kpw), 0L, 0L);
1527 }
1528
1529 /*
1530 *+ callback procedures
1531 */
1532
1533 /*- fixCallback: fix callback -*/
1534 /* ARGSUSED */
1535 static void
1536 fixCallback(w, client_data, call_data)
1537 Widget w;
1538 XtPointer client_data;
1539 XtPointer call_data;
1540 {
1541 CCTextCallbackArg *arg = (CCTextCallbackArg *)call_data;
1542 ConvClient *ccp = (ConvClient *)client_data;
1543
1544 TRACE(("fixCallback(reqwin=0x%lx, length=%d)\n",ccp->reqwin, arg->length));
1545 fixProc(ccp, arg);
1546 }
1547
1548 /*- fixProc: do actual fix processing -*/
1549 static void
1550 fixProc(client, arg)
1551 ConvClient *client;
1552 CCTextCallbackArg *arg;
1553 {
1554 /* Property $B$K7k2L$r%;%C%H$9$k(B */
1555 XChangeProperty(XtDisplay(client->conversion), client->reqwin,
1556 client->property, arg->encoding, arg->format,
1557 PropModeAppend, (unsigned char *)arg->text, arg->length);
1558
1559 /* call protocol dependent proc */
1560 if (client->fix_proc != NULL) (*client->fix_proc)(client, arg);
1561 }
1562
1563 /*- jinputFix: jinput protocol specific fix processing -*/
1564 static void
1565 jinputFix(client)
1566 ConvClient *client;
1567 {
1568 JinputData *jdp = (JinputData *)client->data;
1569
1570 /* spotlocation information is no longer valid */
1571 client->attrmask &= ~CASpotLocation;
1572
1573 if (jdp->state & JINPUT_MULTI_COLOR) sendColorRequest(client);
1574 if (jdp->state & JINPUT_MULTI_FONT) sendFontRequest(client);
1575 if (client->style != separate_style) sendXYRequest(client);
1576 }
1577
1578 /*- endCallback: conversion end callback -*/
1579 /* ARGSUSED */
1580 static void
1581 endCallback(w, client_data, call_data)
1582 Widget w;
1583 XtPointer client_data;
1584 XtPointer call_data;
1585 {
1586 ConvClient *ccp = (ConvClient *)client_data;
1587 int abort = (int)call_data;
1588
1589 TRACE(("endCallback(reqwin=0x%lx,abort=%s)\n", ccp->reqwin, abort?"True":"False"));
1590 endProc(ccp, abort);
1591 }
1592
1593 /*- endProc: conversion end processing -*/
1594 static void
1595 endProc(client, abort)
1596 ConvClient *client;
1597 int abort;
1598 {
1599 KinputProtocolWidget kpw = (KinputProtocolWidget)client->protocolwidget;
1600
1601 if (!abort) {
1602 /* $B%/%i%$%"%s%H$K(B ClientMessage $B$rAw$C$FCN$i$;$k(B
1603 * $B%$%Y%s%H$N%U%)!<%^%C%H$O!"(B
1604 * window: requestor window
1605 * message_type: "CONVERSION_END"
1606 * format: 32
1607 * data.l[0]: selection
1608 * data.l[1]: selection-owner window
1609 */
1610 sendClientMessage(XtDisplay((Widget)kpw), client->reqwin,
1611 kpw->kinput.convEndAtom,
1612 (long)client->selection, (long)XtWindow((Widget)kpw),
1613 0L, 0L, 0L);
1614 }
1615 if (client->conversion != NULL) {
1616 XtRemoveCallback(client->conversion, XtNtextCallback,
1617 fixCallback, (XtPointer)client);
1618 XtRemoveCallback(client->conversion, XtNendCallback,
1619 endCallback, (XtPointer)client);
1620 }
1621
1622 /* call protocol dependent proc */
1623 if (client->end_proc != NULL) {
1624 (*client->end_proc)(client, abort);
1625 } else {
1626 deleteClient(client);
1627 }
1628 }
1629
1630 /*- jinputEnd: jinput specific conversion end processing -*/
1631 /* ARGSUSED */
1632 static void
1633 jinputEnd(client, abort)
1634 ConvClient *client;
1635 Boolean abort; /* UNUSED */
1636 {
1637 /* don't delete client until CONVERSION_CLOSE_REQUEST or client dead */
1638 detachConverter(client);
1639
1640 client->attrmask &= ~CASpotLocation;
1641 }
1642
1643 /*- jinputNewTextCallback: jinput protocol specific new text callback -*/
1644 /* ARGSUSED */
1645 static void
1646 jinputNewTextCallback(w, client_data, call_data)
1647 Widget w;
1648 XtPointer client_data;
1649 XtPointer call_data;
1650 {
1651 ConvClient *ccp = (ConvClient *)client_data;
1652
1653 TRACE(("jinputNewTextCallback(reqwin=0x%lx)\n",ccp->reqwin));
1654 if (ccp->style != separate_style) sendXYRequest(ccp);
1655 }
1656
1657 /*- xlcEnd: xlc specific conversion end processing -*/
1658 /* ARGSUSED */
1659 static void
1660 xlcEnd(client, abort)
1661 ConvClient *client;
1662 Boolean abort; /* UNUSED */
1663 {
1664 /* don't delete client until CONVERSION_CLOSE or client dead */
1665 detachConverter(client);
1666
1667 client->attrmask &= ~CASpotLocation;
1668 }
1669
1670 /*
1671 *+ ClientMessage event handler
1672 */
1673
1674 /*- ConversionOpenRequestProc: CONVERSION_OPEN_REQUEST event handler -*/
1675 /* ARGSUSED */
1676 static void
1677 ConversionOpenRequestProc(w, event, args, num_args)
1678 Widget w;
1679 XEvent *event;
1680 String *args;
1681 Cardinal *num_args;
1682 {
1683 KinputProtocolWidget kpw = (KinputProtocolWidget)w;
1684 XClientMessageEvent *ev = &event->xclient;
1685 int version;
1686 Window reqwin;
1687 Atom convatom;
1688 Atom initproperty;
1689 Atom initpropertytype;
1690 ConvClient *ccp;
1691 JinputData *jdp;
1692
1693 TRACE(("ConversionOpenRequestProc(window=0x%lx)\n", ev->data.l[2]));
1694 /* is it a correct event? */
1695 if (!isCorrectClientEvent(kpw, event)) {
1696 /*ignore */
1697 DPRINT(("got invalid clientmessage event.\n"));
1698 return;
1699 }
1700
1701 convatom = (Atom)ev->data.l[0];
1702 version = ev->data.l[1];
1703 reqwin = (Window)ev->data.l[2];
1704 initproperty = ev->data.l[3];
1705 initpropertytype = ev->data.l[4];
1706
1707 /* check the protocol version & initial property type */
1708 /* also check if the client already opened connection */
1709 if (version != JINPUT_PROTOCOL_VERSION ||
1710 initpropertytype != kpw->kinput.convInitialTypeAtom ||
1711 findClient(kpw, reqwin) != NULL) {
1712 DPRINT(("ConversionOpenRequestProc(): open denied\n"));
1713 sendNegativeConversionOpenNotify(kpw, reqwin, convatom);
1714 return;
1715 }
1716 /* check validity of the client window ID */
1717 if (!isCorrectWindowID(w, reqwin)) {
1718 DPRINT(("ConversionOpenRequestProc(): requestor window doesn't exist\n"));
1719 /* nothing to do */
1720 return;
1721 }
1722
1723 ccp = newClient(kpw, reqwin, convatom);
1724 ccp->protocol = jinput_protocol;
1725 ccp->esm = ESMethodInputOnly;
1726 ccp->start_proc = jinputSendReq;
1727 ccp->detach_proc = jinputDetach;
1728 ccp->fix_proc = jinputFix;
1729 ccp->end_proc = jinputEnd;
1730 ccp->free_resources = jinputFreeResources;
1731 jdp = XtNew(JinputData);
1732 jdp->state = 0;
1733 ccp->data = (XtPointer)jdp;
1734
1735 getJinputInitialProperty(kpw, ccp, initproperty, initpropertytype);
1736
1737 /* watch for client destroy */
1738 MyAddEventHandler(XtDisplay(w), reqwin, DestroyNotify, StructureNotifyMask,
1739 ClientDead, (XtPointer)ccp);
1740
1741 sendConversionOpenNotify(ccp);
1742 }
1743
1744 /*- ConversionRequestProc: CONVERSION_REQUEST event handler -*/
1745 /* ARGSUSED */
1746 static void
1747 ConversionRequestProc(w, event, args, num_args)
1748 Widget w;
1749 XEvent *event;
1750 String *args;
1751 Cardinal *num_args;
1752 {
1753 KinputProtocolWidget kpw = (KinputProtocolWidget)w;
1754 XClientMessageEvent *ev = &event->xclient;
1755 Window reqwin;
1756 Atom convatom;
1757 Atom prop;
1758 ConvClient *ccp;
1759
1760 TRACE(("ConversionRequestProc(window=0x%lx)\n", ev->data.l[1]));
1761 /* is it a correct event? */
1762 if (!isCorrectClientEvent(kpw, event)) {
1763 /*ignore */
1764 DPRINT(("got invalid clientmessage event.\n"));
1765 return;
1766 }
1767
1768 convatom = (Atom)ev->data.l[0];
1769 reqwin = (Window)ev->data.l[1];
1770 prop = (Atom)ev->data.l[4];
1771 TRACE(("\tatom=0x%lx, reqwin=0x%lx\n", convatom, reqwin));
1772
1773 if ((ccp = findClient(kpw, reqwin)) == NULL) {
1774 /* check validity of the client window ID */
1775 if (!isCorrectWindowID(w, reqwin)) {
1776 DPRINT(("ConversionRequestProc(): requestor window doesn't exist\n"));
1777 /* nothing to do */
1778 return;
1779 }
1780 ccp = newClient(kpw, reqwin, convatom);
1781 if (prop == kpw->kinput.xlcOnTheSpotAtom) {
1782 /* xlc protocol */
1783 TRACE(("\txlc protocol\n"));
1784 if (getXlcDataFromProperty(kpw, ccp, True)) {
1785 ccp->protocol = xlc_protocol;
1786 ccp->style = overthespot_style;
1787 ccp->esm = ESMethodInputOnly;
1788 ccp->end_proc = xlcEnd;
1789 ccp->free_resources = xlcFreeResources;
1790 MyAddEventHandler(XtDisplay(w), reqwin,
1791 DestroyNotify, StructureNotifyMask,
1792 ClientDead, (XtPointer)ccp);
1793 } else {
1794 TRACE(("\tchanged to kinput protocol\n"));
1795 ccp->protocol = kinput1_protocol;
1796 ccp->style = separate_style;
1797 ccp->esm = ESMethodInputOnly;
1798 }
1799 } else if (prop != None) {
1800 /* kinput2 protocol */
1801 TRACE(("\tkinput2 protocol\n"));
1802 ccp->protocol = kinput2_protocol;
1803 ccp->style = separate_style;
1804 ccp->esm = ESMethodInputOnly;
1805 ccp->free_resources = kinput2FreeResources;
1806 /* ccp->fix_proc = sendKeyCode0 */
1807 getAttributeFromProperty(ccp, prop);
1808 } else {
1809 /* old protocol */
1810 ccp->protocol = kinput1_protocol;
1811 ccp->style = separate_style;
1812 ccp->esm = ESMethodInputOnly;
1813 }
1814 } else if (ccp->conversion != NULL) {
1815 /* now converting */
1816 if (ccp->protocol == xlc_protocol) {
1817 /*
1818 * xlc protocol uses CONVERSION_REQUEST event to notify
1819 * the frontend of changing conversion attribute
1820 */
1821 return;
1822 }
1823 sendNegativeConversionNotify(kpw, reqwin, convatom);
1824 return;
1825 } else if (ccp->protocol == xlc_protocol) {
1826 if (prop == kpw->kinput.xlcOnTheSpotAtom) {
1827 /* reread property before starting conversion */
1828 (void)getXlcDataFromProperty(kpw, ccp, False);
1829 }
1830 }
1831
1832 /* set convatom */
1833 if (ccp->selection == None) ccp->selection = convatom;
1834
1835 if (attachConverter(ccp) == NULL) {
1836 sendNegativeConversionNotify(kpw, reqwin, convatom);
1837 return;
1838 }
1839
1840 /* set target type (ignore client's request) */
1841 ccp->target = kpw->kinput.ctextAtom;
1842
1843 /* use default property if not specified */
1844 if ((ccp->property = ev->data.l[3]) == None) {
1845 ccp->property = kpw->kinput.convStringAtom;
1846 }
1847
1848 XtAddCallback(ccp->conversion, XtNtextCallback,
1849 fixCallback, (XtPointer)ccp);
1850 XtAddCallback(ccp->conversion, XtNendCallback,
1851 endCallback, (XtPointer)ccp);
1852
1853 /* startup the conversion window */
1854 XtVaSetValues(ccp->conversion, XtNeventSelectMethod, ccp->esm, NULL);
1855 myStartConversion(ccp->conversion, ccp->reqwin,
1856 ccp->attrmask, &ccp->attrs);
1857
1858 /* send ConversionNotify to the client */
1859 sendConversionNotify(ccp);
1860
1861 if (ccp->start_proc != NULL) (*ccp->start_proc)(ccp);
1862 }
1863
1864 /*- ConversionEndRequestProc: CONVERSION_END_REQUEST event handler -*/
1865 /* ARGSUSED */
1866 static void
1867 ConversionEndRequestProc(w, event, args, num_args)
1868 Widget w;
1869 XEvent *event;
1870 String *args;
1871 Cardinal *num_args;
1872 {
1873 KinputProtocolWidget kpw = (KinputProtocolWidget)w;
1874 XClientMessageEvent *ev = &event->xclient;
1875 Window reqwin;
1876 ConvClient *ccp;
1877
1878 TRACE(("ConversionEndRequestProc(window=0x%lx)\n", ev->data.l[1]));
1879 /* is it a correct event? */
1880 if (!isCorrectClientEvent(kpw, event)) {
1881 /*ignore */
1882 DPRINT(("got invalid clientmessage event.\n"));
1883 return;
1884 }
1885
1886 reqwin = (Window)ev->data.l[1];
1887 if ((ccp = findClient(kpw, reqwin)) == NULL) {
1888 /* request from unknown client. just ignore */
1889 DPRINT(("got conversion end request from unknown window\n"));
1890 return;
1891 }
1892
1893 if (ccp->conversion != NULL) {
1894 CControlEndConversion(ccp->conversion);
1895 endProc(ccp, False);
1896 }
1897 }
1898
1899 /*- ConversionCloseRequestProc: CONVERSION_CLOSE_REQUEST event handler (jinput only) -*/
1900 /* ARGSUSED */
1901 static void
1902 ConversionCloseRequestProc(w, event, args, num_args)
1903 Widget w;
1904 XEvent *event;
1905 String *args;
1906 Cardinal *num_args;
1907 {
1908 KinputProtocolWidget kpw = (KinputProtocolWidget)w;
1909 XClientMessageEvent *ev = &event->xclient;
1910 Window reqwin;
1911 ConvClient *ccp;
1912
1913 TRACE(("ConversionCloseRequestProc(window=0x%lx)\n", ev->data.l[2]));
1914 /* is it a correct event? */
1915 if (!isCorrectClientEvent(kpw, event)) {
1916 /*ignore */
1917 DPRINT(("got invalid clientmessage event.\n"));
1918 return;
1919 }
1920 if (ev->data.l[1] != JINPUT_PROTOCOL_VERSION) {
1921 /* wrong version number */
1922 DPRINT(("ConversionCloseRequestProc(): unknown version number (0x%lx)\n", ev->data.l[1]));
1923 return;
1924 }
1925 reqwin = ev->data.l[2];
1926 if ((ccp = findClient(kpw, reqwin)) == NULL) {
1927 /* request from unknown client. just ignore */
1928 DPRINT(("got conversion end request from unknown window\n"));
1929 return;
1930 }
1931 if (ccp->protocol != jinput_protocol) {
1932 DPRINT(("got jinput-specific event from a client that use other protocol\n"));
1933 return;
1934 }
1935
1936 MyRemoveEventHandler(XtDisplay(w), reqwin, DestroyNotify,
1937 ClientDead, (XtPointer)ccp);
1938
1939 deleteClient(ccp);
1940 }
1941
1942 /*- ConversionXYNotifyProc: CONVERSION_XY_NOTIFY event handler (jinput only) -*/
1943 /* ARGSUSED */
1944 static void
1945 ConversionXYNotifyProc(w, event, args, num_args)
1946 Widget w;
1947 XEvent *event;
1948 String *args;
1949 Cardinal *num_args;
1950 {
1951 KinputProtocolWidget kpw = (KinputProtocolWidget)w;
1952 XClientMessageEvent *ev = &event->xclient;
1953 Window reqwin;
1954 ConvClient *ccp;
1955 JinputData *jdp;
1956
1957 TRACE(("ConversionXYNotifyProc(window=0x%lx)\n", ev->data.l[2]));
1958 /* is it a correct event? */
1959 if (!isCorrectClientEvent(kpw, event)) {
1960 /*ignore */
1961 DPRINT(("got invalid clientmessage event.\n"));
1962 return;
1963 }
1964 if (ev->data.l[1] != JINPUT_PROTOCOL_VERSION) {
1965 /* wrong version number */
1966 DPRINT(("ConversionXYNotifyProc(): unknown version number (0x%lx)\n", ev->data.l[1]));
1967 return;
1968 }
1969 reqwin = ev->data.l[2];
1970 if ((ccp = findClient(kpw, reqwin)) == NULL) {
1971 /* request from unknown client. just ignore */
1972 DPRINT(("got conversion end request from unknown window\n"));
1973 return;
1974 }
1975 if (ccp->protocol != jinput_protocol) {
1976 DPRINT(("got jinput-specific event from a client that use other protocol\n"));
1977 return;
1978 }
1979 jdp = (JinputData *)ccp->data;
1980 jdp->rawspotx = ev->data.l[3];
1981 jdp->rawspoty = ev->data.l[4];
1982
1983 ccp->attrmask |= CASpotLocation;
1984 ccp->attrs.spotx = jdp->rawspotx;
1985 ccp->attrs.spoty = jdp->rawspoty +
1986 ((ccp->attrmask & CAFonts) ? ccp->attrs.fonts[0]->ascent : 0);
1987
1988 if (ccp->conversion != NULL) {
1989 myChangeAttributes(ccp->conversion, CASpotLocation, &ccp->attrs);
1990 }
1991 }
1992
1993 /*- ConversionColorNotifyProc: CONVERSION_COLOR_NOTIFY event handler (jinput only) -*/
1994 /* ARGSUSED */
1995 static void
1996 ConversionColorNotifyProc(w, event, args, num_args)
1997 Widget w;
1998 XEvent *event;
1999 String *args;
2000 Cardinal *num_args;
2001 {
2002 KinputProtocolWidget kpw = (KinputProtocolWidget)w;
2003 XClientMessageEvent *ev = &event->xclient;
2004 Window reqwin;
2005 ConvClient *ccp;
2006
2007 TRACE(("ConversionColorNotifyProc(window=0x%lx)\n", ev->data.l[2]));
2008 /* is it a correct event? */
2009 if (!isCorrectClientEvent(kpw, event)) {
2010 /*ignore */
2011 DPRINT(("got invalid clientmessage event.\n"));
2012 return;
2013 }
2014 if (ev->data.l[1] != JINPUT_PROTOCOL_VERSION) {
2015 /* wrong version number */
2016 DPRINT(("ConversionColorNotifyProc(): unknown version number (0x%lx)\n", ev->data.l[1]));
2017 return;
2018 }
2019 reqwin = ev->data.l[2];
2020 if ((ccp = findClient(kpw, reqwin)) == NULL) {
2021 /* request from unknown client. just ignore */
2022 DPRINT(("got conversion end request from unknown window\n"));
2023 return;
2024 }
2025 if (ccp->protocol != jinput_protocol) {
2026 DPRINT(("got jinput-specific event from a client that use other protocol\n"));
2027 return;
2028 }
2029 ccp->attrmask |= CAColor;
2030 ccp->attrs.background = ev->data.l[3];
2031 ccp->attrs.foreground = ev->data.l[4];
2032
2033 if (ccp->conversion != NULL) {
2034 myChangeAttributes(ccp->conversion, CAColor, &ccp->attrs);
2035 }
2036 }
2037
2038 /*- ConversionFontsNotifyProc: CONVERSION_FONTS_NOTIFY event handler (jinput only) -*/
2039 /* ARGSUSED */
2040 static void
2041 ConversionFontsNotifyProc(w, event, args, num_args)
2042 Widget w;
2043 XEvent *event;
2044 String *args;
2045 Cardinal *num_args;
2046 {
2047 KinputProtocolWidget kpw = (KinputProtocolWidget)w;
2048 XClientMessageEvent *ev = &event->xclient;
2049 Window reqwin;
2050 ConvClient *ccp;
2051 unsigned long attrmask;
2052
2053 TRACE(("ConversionFontsNotifyProc(window=0x%lx)\n", ev->data.l[2]));
2054 /* is it a correct event? */
2055 if (!isCorrectClientEvent(kpw, event)) {
2056 /*ignore */
2057 DPRINT(("got invalid clientmessage event.\n"));
2058 return;
2059 }
2060 if (ev->data.l[1] != JINPUT_PROTOCOL_VERSION) {
2061 /* wrong version number */
2062 DPRINT(("ConversionFontsNotifyProc(): unknown version number (0x%lx)\n", ev->data.l[1]));
2063 return;
2064 }
2065 reqwin = ev->data.l[2];
2066 if ((ccp = findClient(kpw, reqwin)) == NULL) {
2067 /* request from unknown client. just ignore */
2068 DPRINT(("got conversion end request from unknown window\n"));
2069 return;
2070 }
2071 if (ccp->protocol != jinput_protocol) {
2072 DPRINT(("got jinput-specific event from a client that use other protocol\n"));
2073 return;
2074 }
2075
2076 attrmask = CAFonts;
2077 if (ccp->attrmask & CAFonts) {
2078 if (ccp->attrs.fonts[0]->fid != ev->data.l[3]) {
2079 XFreeFontInfo((char **)NULL, ccp->attrs.fonts[0], 1);
2080 ccp->attrs.fonts[0] = XQueryFont(XtDisplay((Widget)kpw),
2081 (XID)ev->data.l[3]);
2082 }
2083 if (ccp->attrs.fonts[1]->fid != ev->data.l[4]) {
2084 XFreeFontInfo((char **)NULL, ccp->attrs.fonts[1], 1);
2085 ccp->attrs.fonts[1] = XQueryFont(XtDisplay((Widget)kpw),
2086 (XID)ev->data.l[4]);
2087 }
2088 } else {
2089 ccp->attrmask |= CAFonts;
2090 ccp->attrs.num_fonts = 2;
2091 ccp->attrs.fonts = (XFontStruct **)XtMalloc(sizeof(XFontStruct *) * 2);
2092 ccp->attrs.fonts[0] = XQueryFont(XtDisplay((Widget)kpw),
2093 (XID)ev->data.l[3]);
2094 ccp->attrs.fonts[1] = XQueryFont(XtDisplay((Widget)kpw),
2095 (XID)ev->data.l[4]);
2096 }
2097 if (ccp->attrmask & CASpotLocation) {
2098 JinputData *jdp = (JinputData *)ccp->data;
2099 ccp->attrs.spotx = jdp->rawspotx;
2100 ccp->attrs.spoty = jdp->rawspoty + ccp->attrs.fonts[0]->ascent;
2101 attrmask |= CASpotLocation;
2102 }
2103
2104 if (ccp->conversion != NULL) {
2105 myChangeAttributes(ccp->conversion, attrmask, &ccp->attrs);
2106 }
2107 }
2108
2109 /*- ConversionAttributeNotifyProc: CONVERSION_ATTRIBUTE_NOTIFY event handler (kinput2 only) -*/
2110 /* ARGSUSED */
2111 static void
2112 ConversionAttributeNotifyProc(w, event, args, num_args)
2113 Widget w;
2114 XEvent *event;
2115 String *args;
2116 Cardinal *num_args;
2117 {
2118 KinputProtocolWidget kpw = (KinputProtocolWidget)w;
2119 XClientMessageEvent *ev = &event->xclient;
2120 Window reqwin;
2121 ConvClient *ccp;
2122 XFontStruct **fonts;
2123 Cardinal nfonts;
2124
2125 TRACE(("ConversionAttributeNotifyProc(window=0x%lx)\n", ev->data.l[1]));
2126 /* is it a correct event? */
2127 if (!isCorrectClientEvent(kpw, event)) {
2128 /*ignore */
2129 DPRINT(("got invalid clientmessage event.\n"));
2130 return;
2131 }
2132
2133 reqwin = (Window)ev->data.l[1];
2134 TRACE(("\treqwin=0x%lx\n", reqwin));
2135
2136 if ((ccp = findClient(kpw, reqwin)) == NULL) {
2137 /* request from unknown client. just ignore */
2138 DPRINT(("got conversion attribute request from unknown window\n"));
2139 return;
2140 } else if (ccp->protocol != kinput2_protocol) {
2141 DPRINT(("get conversion attribute request from a client that doesn't use kinput2 protocol\n"));
2142 return;
2143 } else if (ccp->conversion == NULL) {
2144 /* not converting (this should not happen) */
2145 DPRINT(("got conversion attribute request before conversion start\n"));
2146 return;
2147 }
2148
2149 /*
2150 * special treat for fonts -- because if they are changed,
2151 * you should release old fonts.
2152 */
2153 if (ccp->attrmask & CAFonts) {
2154 fonts = ccp->attrs.fonts;
2155 nfonts = ccp->attrs.num_fonts;
2156 } else {
2157 fonts = NULL;
2158 nfonts = 0;
2159 }
2160
2161 ccp->attrmask = 0L;
2162 getAttributeFromEvent(ccp, event);
2163
2164 /* change it */
2165 myChangeAttributes(ccp->conversion, ccp->attrmask, &ccp->attrs);
2166
2167 if (ccp->attrmask & CAFonts) {
2168 if (fonts != NULL) {
2169 /* fonts changed -- free old fonts */
2170 Cardinal i;
2171 for (i = 0; i < nfonts; i++) {
2172 CachedFreeFont(XtDisplay(w), fonts[i]);
2173 }
2174 XtFree((char *)fonts);
2175 }
2176 } else {
2177 /* restore fonts data */
2178 ccp->attrmask = CAFonts;
2179 ccp->attrs.fonts = fonts;
2180 ccp->attrs.num_fonts = nfonts;
2181 }
2182 }
2183
2184 /*- ConversionCloseProc: CONVERSION_CLOSE event handler (xlc only) -*/
2185 /* ARGSUSED */
2186 static void
2187 ConversionCloseProc(w, event, args, num_args)
2188 Widget w;
2189 XEvent *event;
2190 String *args;
2191 Cardinal *num_args;
2192 {
2193 KinputProtocolWidget kpw = (KinputProtocolWidget)w;
2194 XClientMessageEvent *ev = &event->xclient;
2195 Window reqwin;
2196 ConvClient *ccp;
2197
2198 TRACE(("ConversionCloseProc(window=0x%lx)\n", ev->data.l[2]));
2199 /* is it a correct event? */
2200 if (!isCorrectClientEvent(kpw, event)) {
2201 /*ignore */
2202 DPRINT(("got invalid clientmessage event.\n"));
2203 return;
2204 }
2205 reqwin = ev->data.l[1];
2206 if ((ccp = findClient(kpw, reqwin)) == NULL) {
2207 /* request from unknown client. just ignore */
2208 DPRINT(("got conversion end from unknown window\n"));
2209 return;
2210 }
2211
2212 if (ccp->protocol != xlc_protocol && ccp->protocol != kinput1_protocol) {
2213 /*
2214 * Only XLC protocol uses this event (CONVERSION_CLOSE ClientMessage),
2215 * so the checking for kinput1 protocol seems to be unnecessary.
2216 * ...Wrong. A client using kinput1 protocol and a client using
2217 * XLC protocol with off-the-spot mode can't be distinguishable
2218 * until you get this event.
2219 */
2220 DPRINT(("got xlc-specific event from a client that use other protocol\n"));
2221 return;
2222 }
2223
2224 MyRemoveEventHandler(XtDisplay(w), reqwin, DestroyNotify,
2225 ClientDead, (XtPointer)ccp);
2226 if (ccp->conversion != NULL) {
2227 CControlEndConversion(ccp->conversion);
2228 endProc(ccp, False);
2229 }
2230 if (ccp->protocol == xlc_protocol) deleteClient(ccp);
2231 }
2232
2233 /*
2234 *+ other event handler
2235 */
2236
2237 /*- XlcOnTheSpotChangedProc: ProptyNotify of "_XLC_ON_THE_SPOT" handler -*/
2238 /* ARGSUSED */
2239 static void
2240 XlcOnTheSpotChangedProc(w, event, args, num_args)
2241 Widget w;
2242 XEvent *event;
2243 String *args; /* not used */
2244 Cardinal *num_args; /* not used */
2245 {
2246 KinputProtocolWidget kpw = (KinputProtocolWidget)w;
2247 XPropertyEvent *ev = &(event->xproperty);
2248 ConvClient *client;
2249
2250 TRACE(("XlcOnTheSpotChangedProc(window=0x%lx)\n", ev->window));
2251
2252 if (ev->window != XtWindow(w) ||
2253 ev->atom != kpw->kinput.xlcOnTheSpotAtom) {
2254 DPRINT(("\tgot invalid PropertyNotify event.\n"));
2255 return;
2256 } else if (ev->state != PropertyNewValue) {
2257 return;
2258 }
2259 client = getXlcDataFromProperty(kpw, (ConvClient *)NULL, False);
2260 if (client == NULL) return;
2261
2262 if (client->conversion != NULL) {
2263 myChangeAttributes(client->conversion,
2264 client->attrmask, &client->attrs);
2265 }
2266 }
2267
2268 /*- SelectionRequestProc: SelectionRequest event handler -*/
2269 /*ARGSUSED*/
2270 static void
2271 SelectionRequestProc(w, event, args, num_args)
2272 Widget w;
2273 XEvent *event;
2274 String *args; /* not used */
2275 Cardinal *num_args; /* not used */
2276 {
2277 XSelectionRequestEvent *ev = &(event->xselectionrequest);
2278 XEvent repl;
2279 String params[1];
2280 Cardinal num_params;
2281
2282 repl.xselection.type = SelectionNotify;
2283 repl.xselection.requestor = ev->requestor;
2284 repl.xselection.selection = ev->selection;
2285 repl.xselection.target = ev->target;
2286 repl.xselection.property = None;
2287 repl.xselection.time = ev->time;
2288
2289 params[0] = XtClass(w)->core_class.class_name;
2290 num_params = 1;
2291 XtAppWarningMsg(XtWidgetToApplicationContext(w),
2292 "selectionError", "SelectionRequest", "WidgetError",
2293 "%s: SelectionRequest event received",
2294 params, &num_params);
2295
2296 XSendEvent(ev->display, ev->requestor, False, NoEventMask, &repl);
2297 }
2298
2299 /*- SelectionClearProc: SelectionClear event handler -*/
2300 /* ARGSUSED */
2301 static void
2302 SelectionClearProc(w, event, args, num_args)
2303 Widget w;
2304 XEvent *event;
2305 String *args;
2306 Cardinal *num_args;
2307 {
2308 KinputProtocolWidget kpw = (KinputProtocolWidget)w;
2309 ConvClient *ccp;
2310 String params[1];
2311 Cardinal num_params;
2312
2313 /* Selection owner changed. kill myself */
2314
2315 /*
2316 * send ConversionEnd event to the clients before exit
2317 */
2318 for (ccp = kpw->kinput.clients; ccp; ccp = ccp->next) {
2319 if (ccp->reqwin != None) {
2320 if (ccp->conversion != NULL) {
2321 CControlEndConversion(ccp->conversion);
2322 }
2323 endProc(ccp, False);
2324 }
2325 }
2326
2327 params[0] = XtClass(w)->core_class.class_name;
2328 num_params = 1;
2329 XtAppWarningMsg(XtWidgetToApplicationContext(w),
2330 "selectionError", "SelectionClear", "WidgetError",
2331 "%s: SelectionClear event received",
2332 params, &num_params);
2333
2334 XtDestroyWidget(w);
2335 }
2336
2337 /*- ClientDead: DestroyNotify event handler (jinput and xlc) -*/
2338 static void
2339 ClientDead(ev, data)
2340 XEvent *ev;
2341 XtPointer data;
2342 {
2343 ConvClient *ccp = (ConvClient *)data;
2344
2345 TRACE(("ClientDead(window=0x%lx)\n", ev->xdestroywindow.window));
2346 if (ev->type != DestroyNotify ||
2347 ev->xdestroywindow.window != ccp->reqwin) return;
2348
2349 MyRemoveAllEventHandler(ev->xany.display, ccp->reqwin);
2350 deleteClient(ccp);
2351 }