Mercurial > kinput2.yaz
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 } |