Mercurial > kinput2.yaz
comparison lib/XimpProto.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 | 56c98768f86b 7a454839a6de |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:92745d501b9a |
---|---|
1 #ifndef lint | |
2 static char *rcsid = "$Id: XimpProto.c,v 1.49 1999/05/18 08:53:21 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/Xos.h> | |
22 #include <X11/IntrinsicP.h> | |
23 | |
24 /* this widget needs X11R5 header files... */ | |
25 #if defined(XlibSpecificationRelease) && XlibSpecificationRelease >= 5 | |
26 | |
27 #include <X11/StringDefs.h> | |
28 #include <X11/Xatom.h> | |
29 #include <X11/Xmu/Atoms.h> | |
30 #include <X11/Xmu/CharSet.h> | |
31 #include "XIMProto.h" | |
32 #include "XimpProtoP.h" | |
33 #include "ConvMgr.h" | |
34 #include "InputConv.h" | |
35 #include "OverConv.h" | |
36 #include "OffConv.h" | |
37 #include "OnConv.h" | |
38 #include "MyDispatch.h" | |
39 #include "AsyncErr.h" | |
40 #include "ParseKey.h" | |
41 | |
42 | |
43 #define DEBUG_VAR debug_XimpProtocol | |
44 #include "DebugPrint.h" | |
45 | |
46 | |
47 #define PROTOCOL_VERSION_STR "XIMP.3.5" | |
48 #define SERVER_NAME "kinput2" | |
49 #define SERVER_VERSION "1" | |
50 #define VENDOR_NAME "SRA" | |
51 | |
52 | |
53 #define PREEDIT_MASK (XIMP_PRE_AREA_MASK|XIMP_PRE_FG_MASK|XIMP_PRE_BG_MASK|\ | |
54 XIMP_PRE_COLORMAP_MASK|XIMP_PRE_BGPIXMAP_MASK|\ | |
55 XIMP_PRE_LINESP_MASK|XIMP_PRE_CURSOR_MASK|\ | |
56 XIMP_PRE_AREANEED_MASK|XIMP_PRE_SPOTL_MASK) | |
57 #define STATUS_MASK (XIMP_STS_AREA_MASK|XIMP_STS_FG_MASK|XIMP_STS_BG_MASK|\ | |
58 XIMP_STS_COLORMAP_MASK|XIMP_STS_BGPIXMAP_MASK|\ | |
59 XIMP_STS_LINESP_MASK|XIMP_STS_CURSOR_MASK|\ | |
60 XIMP_STS_AREANEED_MASK|XIMP_STS_WINDOW_MASK) | |
61 | |
62 #define MIN_LINE_SPACING 2 | |
63 #define MIN_AREA_WIDTH 16 | |
64 #define MIN_AREA_HEIGHT 10 | |
65 | |
66 | |
67 /*- resource table -*/ | |
68 static XtResource resources[] = { | |
69 #define offset(field) XtOffset(XimpProtocolWidget, ximp.field) | |
70 { XtNlocaleName, XtCLocaleName, XtRString, sizeof(String), | |
71 offset(localename), XtRImmediate, (XtPointer)NULL }, | |
72 { XtNserverName, XtCServerName, XtRString, sizeof(String), | |
73 offset(servername), XtRString, (XtPointer)SERVER_NAME }, | |
74 { XtNforceDefaultServer, XtCForceDefaultServer, XtRBoolean, sizeof(Boolean), | |
75 offset(forceDefaultServer), XtRImmediate, (XtPointer)False }, | |
76 { XtNconversionStartKeys, XtCConversionStartKeys, XtRString, sizeof(String), | |
77 offset(convkeys), XtRImmediate, (XtPointer)NULL }, | |
78 { XtNinputObjectClass, XtCClass, XtRPointer, sizeof(WidgetClass), | |
79 offset(inputObjClass), XtRImmediate, (XtPointer)NULL }, | |
80 { XtNdisplayObjectClass, XtCClass, XtRPointer, sizeof(WidgetClass), | |
81 offset(displayObjClass), XtRImmediate, (XtPointer)NULL }, | |
82 { XtNdefaultFontList, XtCFontList, XtRString, sizeof(String), | |
83 offset(defaultfontlist), XtRImmediate, (XtPointer)NULL }, | |
84 { XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel), | |
85 offset(foreground), XtRString, XtDefaultForeground }, | |
86 { XtNstatusWidth, XtCStatusWidth, XtRDimension, sizeof(Dimension), | |
87 offset(statuswidth), XtRImmediate, (XtPointer)0 }, | |
88 #undef offset | |
89 }; | |
90 | |
91 static void XimpMessageProc(); | |
92 static void SelectionRequestProc(); | |
93 static void SelectionClearProc(); | |
94 | |
95 /*- action table -*/ | |
96 static XtActionsRec actions[] = { | |
97 { "ximp-message", XimpMessageProc }, | |
98 { "selection-request", SelectionRequestProc }, | |
99 { "selection-clear", SelectionClearProc }, | |
100 }; | |
101 | |
102 /*- default translation -*/ | |
103 static char translations[] = | |
104 "<Message>_XIMP_PROTOCOL: ximp-message()\n\ | |
105 <SelReq>: selection-request()\n\ | |
106 <SelClr>: selection-clear()"; | |
107 | |
108 | |
109 /*- static function declarations -*/ | |
110 static void ClassInitialize(); | |
111 static void Initialize(); | |
112 static void Destroy(); | |
113 static void Realize(); | |
114 | |
115 static void getAtoms(); | |
116 static int ownSelection(); | |
117 | |
118 static ConvClient *findClient(); | |
119 static ConvClient *newClient(); | |
120 static Widget attachConverter(); | |
121 static void detachConverter(); | |
122 static void deleteClient(); | |
123 | |
124 static Boolean isCorrectClientEvent(); | |
125 static Boolean isCorrectWindowID(); | |
126 static void initializeError(); | |
127 static void checkLocale(); | |
128 static void fillInDefaultAttributes(); | |
129 static void computeAreaForStartup(); | |
130 static void computeAreaForQuery(); | |
131 static unsigned long makeConvAttributes(); | |
132 static void getFonts(); | |
133 | |
134 static void setProperty(); | |
135 static void setKeyProperty(); | |
136 static void getAttributes(); | |
137 static void getFocusProperty(); | |
138 static void getPreeditFontProperty(); | |
139 static void getStatusFontProperty(); | |
140 static void getPreeditProperty(); | |
141 static void getStatusProperty(); | |
142 static Boolean readProperty(); | |
143 static void setAttributes(); | |
144 static void setFocusProperty(); | |
145 static void setPreeditFontProperty(); | |
146 static void setStatusFontProperty(); | |
147 static void setPreeditProperty(); | |
148 static void setStatusProperty(); | |
149 static void writeProperty(); | |
150 | |
151 static void sendClientMessage8(); | |
152 static void sendClientMessage32(); | |
153 static void sendKeyEvent(); | |
154 static void sendErrorEvent(); | |
155 static void sendCreateRefusal(); | |
156 | |
157 static void fixCallback(); | |
158 static void fixProc(); | |
159 static void endCallback(); | |
160 static void endProc(); | |
161 static void unusedEventCallback(); | |
162 | |
163 static void ximpCreateMessageProc(); | |
164 static void ximpDestroyMessageProc(); | |
165 static void ximpBeginMessageProc(); | |
166 static void ximpEndMessageProc(); | |
167 static void ximpSetFocusMessageProc(); | |
168 static void ximpUnsetFocusMessageProc(); | |
169 static void ximpMoveMessageProc(); | |
170 static void ximpResetMessageProc(); | |
171 static void ximpSetValueMessageProc(); | |
172 static void ximpGetValueMessageProc(); | |
173 static void ximpKeyPressMessageProc(); | |
174 static void ximpExtensionMessageProc(); | |
175 | |
176 static void ClientDead(); | |
177 | |
178 static void preeditStartCallback(); | |
179 static void preeditDoneCallback(); | |
180 static void preeditDrawCallback(); | |
181 static void preeditCaretCallback(); | |
182 static void statusStartCallback(); | |
183 static void statusDoneCallback(); | |
184 static void statusDrawCallback(); | |
185 static void preeditStart(); | |
186 static void preeditDone(); | |
187 static void preeditDraw(); | |
188 static void preeditCaret(); | |
189 static void statusStart(); | |
190 static void statusDone(); | |
191 static void statusDraw(); | |
192 | |
193 /*- XimpProtocolClassRec -*/ | |
194 XimpProtocolClassRec ximpProtocolClassRec = { | |
195 { /* core fields */ | |
196 /* superclass */ (WidgetClass) &widgetClassRec, | |
197 /* class_name */ "XimpProtocol", | |
198 /* widget_size */ sizeof(XimpProtocolRec), | |
199 /* class_initialize */ ClassInitialize, | |
200 /* class_part_initialize */ NULL, | |
201 /* class_inited */ FALSE, | |
202 /* initialize */ Initialize, | |
203 /* initialize_hook */ NULL, | |
204 /* realize */ Realize, | |
205 /* actions */ actions, | |
206 /* num_actions */ XtNumber(actions), | |
207 /* resources */ resources, | |
208 /* num_resources */ XtNumber(resources), | |
209 /* xrm_class */ NULLQUARK, | |
210 /* compress_motion */ TRUE, | |
211 /* compress_exposure */ TRUE, | |
212 /* compress_enterleave */ TRUE, | |
213 /* visible_interest */ FALSE, | |
214 /* destroy */ Destroy, | |
215 /* resize */ NULL, | |
216 /* expose */ NULL, | |
217 /* set_values */ NULL, | |
218 /* set_values_hook */ NULL, | |
219 /* set_values_almost */ XtInheritSetValuesAlmost, | |
220 /* get_values_hook */ NULL, | |
221 /* accept_focus */ NULL, | |
222 /* version */ XtVersion, | |
223 /* callback_private */ NULL, | |
224 /* tm_table */ translations, | |
225 /* query_geometry */ XtInheritQueryGeometry, | |
226 /* display_accelerator */ XtInheritDisplayAccelerator, | |
227 /* extension */ NULL | |
228 }, | |
229 { /* ximpprotocol fields */ | |
230 /* ximp_dummy */ 0 | |
231 } | |
232 }; | |
233 | |
234 WidgetClass ximpProtocolWidgetClass = (WidgetClass)&ximpProtocolClassRec; | |
235 | |
236 static XimpInputStyle XimpStyles[] = { | |
237 { XIMPreeditPosition|XIMStatusArea, overthespot_style }, | |
238 { XIMPreeditPosition|XIMStatusNothing, overthespot_style }, | |
239 { XIMPreeditArea|XIMStatusArea, offthespot_style }, | |
240 { XIMPreeditCallbacks|XIMStatusCallbacks, onthespot_style }, | |
241 { XIMPreeditCallbacks|XIMStatusNothing, onthespot_style }, | |
242 { XIMPreeditNothing|XIMStatusNothing, separate_style }, | |
243 { 0 }, | |
244 }; | |
245 | |
246 /* | |
247 *+ Core class methods | |
248 */ | |
249 | |
250 /*- ClassInitialize: set supported locale list -*/ | |
251 static void | |
252 ClassInitialize() | |
253 { | |
254 } | |
255 | |
256 /*- Initialize: intern Atoms, get default fonts, etc. -*/ | |
257 /* ARGSUSED */ | |
258 static void | |
259 Initialize(req, new, args, num_args) | |
260 Widget req; | |
261 Widget new; | |
262 ArgList args; | |
263 Cardinal *num_args; | |
264 { | |
265 XimpProtocolWidget xpw = (XimpProtocolWidget)new; | |
266 | |
267 if (xpw->ximp.localename == NULL) { | |
268 initializeError(new, XtNlocaleName); | |
269 } else if (xpw->ximp.inputObjClass == NULL) { | |
270 initializeError(new, XtNinputObjectClass); | |
271 } else if (xpw->ximp.displayObjClass == NULL) { | |
272 initializeError(new, XtNdisplayObjectClass); | |
273 } | |
274 | |
275 checkLocale(xpw, xpw->ximp.localename); | |
276 xpw->ximp.localename = XtNewString(xpw->ximp.localename); | |
277 | |
278 xpw->ximp.servername = XtNewString(xpw->ximp.servername); | |
279 | |
280 xpw->ximp.clients = NULL; | |
281 xpw->ximp.freeclients = NULL; | |
282 xpw->ximp.icid = 1; | |
283 xpw->ximp.propid = 0; | |
284 xpw->ximp.callbackpropid = 0; | |
285 | |
286 if (xpw->ximp.defaultfontlist != NULL) { | |
287 TRACE(("enter default fontlist <%s> into cache\n", xpw->ximp.defaultfontlist)); | |
288 /* extract fonts from default font list and enter them into cache */ | |
289 xpw->ximp.defaultfontlist = XtNewString(xpw->ximp.defaultfontlist); | |
290 xpw->ximp.deffonts = FontBankGet(xpw->ximp.fontbank, | |
291 xpw->ximp.defaultfontlist, | |
292 &xpw->ximp.numdeffonts); | |
293 } else { | |
294 xpw->ximp.deffonts = NULL; | |
295 xpw->ximp.numdeffonts = 0; | |
296 } | |
297 | |
298 getAtoms(xpw); | |
299 } | |
300 | |
301 /*- Destroy: free allocated memory -*/ | |
302 static void | |
303 Destroy(w) | |
304 Widget w; | |
305 { | |
306 XimpProtocolWidget xpw = (XimpProtocolWidget)w; | |
307 ConvClient *client; | |
308 | |
309 XtFree(xpw->ximp.localename); | |
310 XtFree(xpw->ximp.servername); | |
311 if (xpw->ximp.defaultfontlist != NULL) XtFree(xpw->ximp.defaultfontlist); | |
312 | |
313 while (xpw->ximp.clients != NULL) { | |
314 statusDone(xpw->ximp.clients); | |
315 endProc(xpw->ximp.clients, False); | |
316 deleteClient(xpw->ximp.clients); | |
317 /* | |
318 * since deleteClient() removes the given client from client list | |
319 * and insert it in free list, following commented statement is | |
320 * not necessary. | |
321 * | |
322 * xpw->ximp.clients = xpw->ximp.clients->next; | |
323 */ | |
324 } | |
325 | |
326 /* | |
327 * now, all the clients are deleted and moved into free list. | |
328 */ | |
329 client = xpw->ximp.freeclients; | |
330 while (client != NULL) { | |
331 ConvClient *ccp = client; | |
332 client = client->next; | |
333 XtFree((char *)ccp); | |
334 } | |
335 | |
336 /* | |
337 * free cached fontlist | |
338 */ | |
339 if (xpw->ximp.numdeffonts > 0) { | |
340 FontBankFreeFonts(xpw->ximp.fontbank, | |
341 xpw->ximp.deffonts, | |
342 xpw->ximp.numdeffonts); | |
343 } | |
344 FontBankDestroy(xpw->ximp.fontbank); | |
345 } | |
346 | |
347 /*- Realize: own selection -*/ | |
348 static void | |
349 Realize(w, mask, value) | |
350 Widget w; | |
351 XtValueMask *mask; | |
352 XSetWindowAttributes *value; | |
353 { | |
354 XimpProtocolWidget xpw = (XimpProtocolWidget)w; | |
355 CoreWidgetClass super = (CoreWidgetClass)XtClass(w)->core_class.superclass; | |
356 | |
357 (*super->core_class.realize)(w, mask, value); | |
358 | |
359 setProperty(xpw); | |
360 | |
361 if (!ownSelection(xpw)) { | |
362 String params[1]; | |
363 Cardinal num_params; | |
364 | |
365 params[0] = XtClass(w)->core_class.class_name; | |
366 num_params = 1; | |
367 XtAppWarningMsg(XtWidgetToApplicationContext(w), | |
368 "selectionError", "ownSelection", "WidgetError", | |
369 "%s: can't own selection", params, &num_params); | |
370 | |
371 XtDestroyWidget(w); | |
372 } else { | |
373 DPRINT(("\tselection owner: 0x%lx (%ld)\n", XtWindow(w), XtWindow(w))); | |
374 } | |
375 } | |
376 | |
377 /* | |
378 *+ atom handling | |
379 */ | |
380 | |
381 /*- getAtoms: intern atoms -*/ | |
382 static void | |
383 getAtoms(xpw) | |
384 XimpProtocolWidget xpw; | |
385 { | |
386 Display *dpy = XtDisplay((Widget)xpw); | |
387 char buf[256]; | |
388 | |
389 #define MAKEATOM(s) XInternAtom(dpy, s, False) | |
390 (void)sprintf(buf, "_XIMP_%s", xpw->ximp.localename); | |
391 xpw->ximp.selAtom1 = MAKEATOM(buf); | |
392 (void)sprintf(buf, "_XIMP_%s@%s.%d", | |
393 xpw->ximp.localename, | |
394 xpw->ximp.servername, | |
395 DefaultScreen(XtDisplay((Widget)xpw))); | |
396 xpw->ximp.selAtom2 = MAKEATOM(buf); | |
397 | |
398 xpw->ximp.ctextAtom = XA_COMPOUND_TEXT(dpy); | |
399 | |
400 xpw->ximp.ximpVersionAtom = MAKEATOM("_XIMP_VERSION"); | |
401 xpw->ximp.ximpStyleAtom = MAKEATOM("_XIMP_STYLE"); | |
402 xpw->ximp.ximpKeysAtom = MAKEATOM("_XIMP_KEYS"); | |
403 xpw->ximp.ximpServerNameAtom = MAKEATOM("_XIMP_SERVERNAME"); | |
404 xpw->ximp.ximpServerVersionAtom = MAKEATOM("_XIMP_SERVERVERSION"); | |
405 xpw->ximp.ximpVendorNameAtom = MAKEATOM("_XIMP_VENDORNAME"); | |
406 xpw->ximp.ximpExtensionsAtom = MAKEATOM("_XIMP_EXTENSIONS"); | |
407 xpw->ximp.ximpProtocolAtom = MAKEATOM("_XIMP_PROTOCOL"); | |
408 xpw->ximp.ximpFocusAtom = MAKEATOM("_XIMP_FOCUS"); | |
409 xpw->ximp.ximpPreeditAtom = MAKEATOM("_XIMP_PREEDIT"); | |
410 xpw->ximp.ximpStatusAtom = MAKEATOM("_XIMP_STATUS"); | |
411 xpw->ximp.ximpPreeditFontAtom = MAKEATOM("_XIMP_PREEDITFONT"); | |
412 xpw->ximp.ximpStatusFontAtom = MAKEATOM("_XIMP_STATUSFONT"); | |
413 xpw->ximp.ximpExtXimpBackFrontAtom = MAKEATOM("_XIMP_EXT_XIMP_BACK_FRONT"); | |
414 xpw->ximp.ximpPreeditDrawDataAtom = MAKEATOM("_XIMP_PREEDIT_DRAW_DATA"); | |
415 xpw->ximp.ximpFeedbacksAtom = MAKEATOM("_XIMP_FEEDBACKS"); | |
416 | |
417 #undef MAKEATOM | |
418 } | |
419 | |
420 /*- ownSelection: own conversion selection -*/ | |
421 static int | |
422 ownSelection(xpw) | |
423 XimpProtocolWidget xpw; | |
424 { | |
425 Display *dpy = XtDisplay((Widget)xpw); | |
426 Window w = XtWindow((Widget)xpw); | |
427 | |
428 TRACE(("ximpProtocol:ownSelection()\n")); | |
429 | |
430 if (xpw->ximp.forceDefaultServer || | |
431 XGetSelectionOwner(dpy, xpw->ximp.selAtom1) == None) { | |
432 TRACE(("\tdefault server\n")); | |
433 XSetSelectionOwner(dpy, xpw->ximp.selAtom1, w, CurrentTime); | |
434 } | |
435 TRACE(("\tspecific server\n")); | |
436 XSetSelectionOwner(dpy, xpw->ximp.selAtom2, w, CurrentTime); | |
437 | |
438 return XGetSelectionOwner(dpy, xpw->ximp.selAtom2) == w; | |
439 } | |
440 | |
441 /* | |
442 *+ client data handling | |
443 */ | |
444 | |
445 /*- findClient: get clientdata of given client -*/ | |
446 static ConvClient * | |
447 findClient(xpw, id) | |
448 XimpProtocolWidget xpw; | |
449 int id; | |
450 { | |
451 register ConvClient *ccp = xpw->ximp.clients; | |
452 | |
453 while (ccp != NULL) { | |
454 if (ccp->id == id) return ccp; | |
455 ccp = ccp->next; | |
456 } | |
457 | |
458 return NULL; | |
459 } | |
460 | |
461 /*- newClient: get a clientdata for new client -*/ | |
462 static ConvClient * | |
463 newClient(xpw, client) | |
464 XimpProtocolWidget xpw; | |
465 Window client; | |
466 { | |
467 ConvClient *ccp; | |
468 | |
469 if (xpw->ximp.freeclients != NULL) { | |
470 /* get one from free list */ | |
471 ccp = xpw->ximp.freeclients; | |
472 xpw->ximp.freeclients = ccp->next; | |
473 } else { | |
474 char buf[30]; | |
475 | |
476 ccp = XtNew(ConvClient); | |
477 (void)sprintf(buf, "_XIMP_STRING_%d", xpw->ximp.propid++); | |
478 ccp->property = XInternAtom(XtDisplay((Widget)xpw), buf, False); | |
479 (void)sprintf(buf, "_XIMP_CALLBACKS_%d", xpw->ximp.callbackpropid++); | |
480 ccp->preeditdata = XInternAtom(XtDisplay((Widget)xpw), buf, False); | |
481 (void)sprintf(buf, "_XIMP_CALLBACKS_%d", xpw->ximp.callbackpropid++); | |
482 ccp->preedittext = XInternAtom(XtDisplay((Widget)xpw), buf, False); | |
483 (void)sprintf(buf, "_XIMP_CALLBACKS_%d", xpw->ximp.callbackpropid++); | |
484 ccp->preeditfeedback = XInternAtom(XtDisplay((Widget)xpw), buf, False); | |
485 (void)sprintf(buf, "_XIMP_CALLBACKS_%d", xpw->ximp.callbackpropid++); | |
486 ccp->statustext = XInternAtom(XtDisplay((Widget)xpw), buf, False); | |
487 (void)sprintf(buf, "_XIMP_CALLBACKS_%d", xpw->ximp.callbackpropid++); | |
488 ccp->statusfeedback = XInternAtom(XtDisplay((Widget)xpw), buf, False); | |
489 } | |
490 ccp->id = xpw->ximp.icid++; | |
491 | |
492 ccp->version = NULL; | |
493 ccp->style = separate_style; /* default */ | |
494 ccp->protocolwidget = (Widget)xpw; | |
495 ccp->conversion = NULL; | |
496 ccp->reqwin = client; | |
497 ccp->focuswin = client; /* default */ | |
498 ccp->xpattrs.fontlist = NULL; | |
499 ccp->xsattrs.fontlist = NULL; | |
500 ccp->xattrmask = 0L; | |
501 ccp->defaultsfilledin = False; | |
502 ccp->esm = ESMethodSelectFocus; /* default */ | |
503 ccp->fonts = NULL; | |
504 ccp->num_fonts = 0; | |
505 ccp->status_fonts = NULL; | |
506 ccp->num_status_fonts = 0; | |
507 ccp->resetting = False; | |
508 ccp->event = NULL; | |
509 ccp->ximstyle = XIMPreeditNothing|XIMStatusNothing; /* default */ | |
510 ccp->in_preedit = False; | |
511 ccp->in_status = False; | |
512 | |
513 ccp->next = xpw->ximp.clients; | |
514 xpw->ximp.clients = ccp; | |
515 | |
516 return ccp; | |
517 } | |
518 | |
519 /*- attachConverter: attach converter to the client -*/ | |
520 static Widget | |
521 attachConverter(ccp) | |
522 ConvClient *ccp; | |
523 { | |
524 WidgetClass class; | |
525 XimpProtocolWidget xpw = (XimpProtocolWidget)ccp->protocolwidget; | |
526 | |
527 TRACE(("attachConverter(client window=0x%lx)\n", ccp->reqwin)); | |
528 if (ccp->conversion != NULL) return ccp->conversion; | |
529 | |
530 if (ccp->style == overthespot_style) { | |
531 class = overTheSpotConversionWidgetClass; | |
532 } else if (ccp->style == onthespot_style) { | |
533 class = onTheSpotConversionWidgetClass; | |
534 } else if (ccp->style == offthespot_style) { | |
535 class = offTheSpotConversionWidgetClass; | |
536 } else { | |
537 class = separateConversionWidgetClass; | |
538 } | |
539 | |
540 ccp->conversion = CMGetConverter(XtParent(ccp->protocolwidget), | |
541 ccp->reqwin, class, | |
542 xpw->ximp.inputObjClass, | |
543 xpw->ximp.displayObjClass); | |
544 | |
545 return ccp->conversion; | |
546 } | |
547 | |
548 /*- detachConverter: detach converter from client -*/ | |
549 static void | |
550 detachConverter(ccp) | |
551 ConvClient *ccp; | |
552 { | |
553 TRACE(("detachConverter(client window=0x%lx)\n", ccp->reqwin)); | |
554 | |
555 XtRemoveCallback(ccp->conversion, XtNtextCallback, | |
556 fixCallback, (XtPointer)ccp); | |
557 XtRemoveCallback(ccp->conversion, XtNendCallback, | |
558 endCallback, (XtPointer)ccp); | |
559 XtRemoveCallback(ccp->conversion, XtNunusedEventCallback, | |
560 unusedEventCallback, (XtPointer)ccp); | |
561 if (ccp->style == onthespot_style) { | |
562 XtRemoveCallback(ccp->conversion, XtNpreeditStartCallback, | |
563 preeditStartCallback, (XtPointer)ccp); | |
564 XtRemoveCallback(ccp->conversion, XtNpreeditDoneCallback, | |
565 preeditDoneCallback, (XtPointer)ccp); | |
566 XtRemoveCallback(ccp->conversion, XtNpreeditDrawCallback, | |
567 preeditDrawCallback, (XtPointer)ccp); | |
568 XtRemoveCallback(ccp->conversion, XtNpreeditCaretCallback, | |
569 preeditCaretCallback, (XtPointer)ccp); | |
570 XtRemoveCallback(ccp->conversion, XtNstatusStartCallback, | |
571 statusStartCallback, (XtPointer)ccp); | |
572 XtRemoveCallback(ccp->conversion, XtNstatusDoneCallback, | |
573 statusDoneCallback, (XtPointer)ccp); | |
574 XtRemoveCallback(ccp->conversion, XtNstatusDrawCallback, | |
575 statusDrawCallback, (XtPointer)ccp); | |
576 } | |
577 | |
578 CMReleaseConverter(XtParent(ccp->protocolwidget), ccp->conversion); | |
579 ccp->conversion = NULL; | |
580 } | |
581 | |
582 /*- deleteClient: delete specified client -*/ | |
583 static void | |
584 deleteClient(client) | |
585 ConvClient *client; | |
586 { | |
587 XimpProtocolWidget xpw = (XimpProtocolWidget)client->protocolwidget; | |
588 ConvClient *ccp, *ccp0; | |
589 | |
590 TRACE(("deleteClient(client window=0x%lx)\n", client->reqwin)); | |
591 | |
592 if (client->conversion != NULL) detachConverter(client); | |
593 if (client->num_fonts > 0) { | |
594 FontBankFreeFonts(xpw->ximp.fontbank, | |
595 client->fonts, client->num_fonts); | |
596 } | |
597 if (client->num_status_fonts > 0) { | |
598 FontBankFreeFonts(xpw->ximp.fontbank, | |
599 client->status_fonts, client->num_status_fonts); | |
600 } | |
601 if (client->xpattrs.fontlist != NULL && | |
602 client->xpattrs.fontlist != xpw->ximp.defaultfontlist) { | |
603 XFree(client->xpattrs.fontlist); | |
604 } | |
605 if (client->xsattrs.fontlist != NULL) { | |
606 XFree(client->xsattrs.fontlist); | |
607 } | |
608 if (client->version != NULL) XtFree(client->version); | |
609 | |
610 for (ccp = xpw->ximp.clients, ccp0 = NULL; | |
611 ccp != NULL; | |
612 ccp0 = ccp, ccp = ccp->next) { | |
613 if (ccp == client) { | |
614 if (ccp0 == NULL) { | |
615 xpw->ximp.clients = ccp->next; | |
616 } else { | |
617 ccp0->next = ccp->next; | |
618 } | |
619 /* put it back to free list */ | |
620 client->next = xpw->ximp.freeclients; | |
621 xpw->ximp.freeclients = client; | |
622 return; | |
623 } | |
624 } | |
625 DPRINT(("deleteClient: cannot find the client in the client list!\n")); | |
626 } | |
627 | |
628 /* | |
629 *+ utility functions | |
630 */ | |
631 | |
632 /*- isCorrectClientEvent: is the event in correct format? -*/ | |
633 static Boolean | |
634 isCorrectClientEvent(xpw, event) | |
635 XimpProtocolWidget xpw; | |
636 XEvent *event; | |
637 { | |
638 XClientMessageEvent *ev = &(event->xclient); | |
639 | |
640 return (event->type == ClientMessage && | |
641 ev->window == XtWindow((Widget)xpw) && | |
642 ev->message_type == xpw->ximp.ximpProtocolAtom && | |
643 ev->format == 32); | |
644 } | |
645 | |
646 /*- isCorrectWindowID: is the given window ID valid? -*/ | |
647 static Boolean | |
648 isCorrectWindowID(w, window, widthp, heightp) | |
649 Widget w; | |
650 Window window; | |
651 Dimension *widthp; | |
652 Dimension *heightp; | |
653 { | |
654 XWindowAttributes attr; | |
655 int status; | |
656 XAEHandle h; | |
657 | |
658 h = XAESetIgnoreErrors(XtDisplay(w)); | |
659 status = XGetWindowAttributes(XtDisplay(w), window, &attr); | |
660 XAEUnset(h); | |
661 | |
662 if (status == 0) return False; | |
663 | |
664 if (widthp != NULL) *widthp = attr.width; | |
665 if (heightp != NULL) *heightp = attr.height; | |
666 return True; | |
667 } | |
668 | |
669 /*- initializeError: display error message when resource isn't specified -*/ | |
670 static void | |
671 initializeError(w, resname) | |
672 Widget w; | |
673 String resname; | |
674 { | |
675 String params[2]; | |
676 Cardinal num_params; | |
677 | |
678 params[0] = XtClass(w)->core_class.class_name; | |
679 params[1] = resname; | |
680 num_params = 2; | |
681 XtAppErrorMsg(XtWidgetToApplicationContext(w), | |
682 "initializeError", "noResource", "WidgetError", | |
683 "%s: resource %s must be specified at widget creation", | |
684 params, &num_params); | |
685 } | |
686 | |
687 /*- checkLocale: check specified locale is supported -*/ | |
688 static void | |
689 checkLocale(xpw, name) | |
690 XimpProtocolWidget xpw; | |
691 String name; | |
692 { | |
693 XimpProtocolWidgetClass class = (XimpProtocolWidgetClass)XtClass((Widget)xpw); | |
694 FontBank fontbank; | |
695 | |
696 TRACE(("checkLocale(localename=%s)\n", name)); | |
697 | |
698 fontbank = FontBankCreate(XtDisplay((Widget)xpw), name); | |
699 if (fontbank == NULL) { | |
700 /* not supported locale name */ | |
701 String params[2]; | |
702 Cardinal num_params; | |
703 | |
704 params[0] = class->core_class.class_name; | |
705 params[1] = name; | |
706 num_params = 2; | |
707 XtAppErrorMsg(XtWidgetToApplicationContext((Widget)xpw), | |
708 "initializeError", "localeNotSupported", "WidgetError", | |
709 "%s: specified locale %s is not supported (yet)", | |
710 params, &num_params); | |
711 } else { | |
712 xpw->ximp.fontbank = fontbank; | |
713 } | |
714 } | |
715 | |
716 /*- fillInDefaultAttributes: fill in unspecified attributes -*/ | |
717 static void | |
718 fillInDefaultAttributes(client) | |
719 ConvClient *client; | |
720 { | |
721 XimpProtocolWidget xpw = (XimpProtocolWidget)client->protocolwidget; | |
722 XimpPreEditAttributes *xpattr = &client->xpattrs; | |
723 XimpStatusAttributes *xsattr = &client->xsattrs; | |
724 unsigned long xmask = client->xattrmask; | |
725 | |
726 if (client->defaultsfilledin) return; | |
727 | |
728 /* | |
729 * Compute reasonable default values for the unspecified | |
730 * attributes except Area and AreaNeeded. | |
731 */ | |
732 TRACE(("fillInDefaultAttributes()\n")); | |
733 if (!(xmask & XIMP_FOCUS_WIN_MASK)) { | |
734 client->focuswin = client->reqwin; | |
735 client->focuswidth = client->reqwinwidth; | |
736 client->focusheight = client->reqwinheight; | |
737 } | |
738 | |
739 if (!(xmask & XIMP_PRE_FONT_MASK)) { | |
740 xpattr->fontlist = xpw->ximp.defaultfontlist; | |
741 getFonts(client, xpattr->fontlist, 1); | |
742 client->xattrmask |= XIMP_PRE_FONT_MASK; | |
743 } | |
744 if (!(xmask & XIMP_STS_FONT_MASK)) { | |
745 /* Default is same as preedit font */ | |
746 xsattr->fontlist = XtNewString(xpattr->fontlist); | |
747 getFonts(client, xsattr->fontlist, 0); | |
748 client->xattrmask |= XIMP_STS_FONT_MASK; | |
749 } | |
750 | |
751 if (!(xmask & XIMP_PRE_FG_MASK)) { | |
752 xpattr->foreground = xpw->ximp.foreground; | |
753 } | |
754 if (!(xmask & XIMP_PRE_BG_MASK)) { | |
755 xpattr->background = xpw->core.background_pixel; | |
756 } | |
757 if (!(xmask & XIMP_PRE_COLORMAP_MASK)) { | |
758 xpattr->colormap = xpw->core.colormap; | |
759 } | |
760 if (!(xmask & XIMP_PRE_BGPIXMAP_MASK)) { | |
761 xpattr->bgpixmap = None; | |
762 } | |
763 if (!(xmask & XIMP_PRE_LINESP_MASK)) { | |
764 Cardinal i; | |
765 XFontStruct *font; | |
766 int maxascent = 0, maxdescent = 0; | |
767 | |
768 for (i = 0; i < client->num_fonts; i++) { | |
769 font = client->fonts[i]; | |
770 if (maxascent < font->ascent) maxascent = font->ascent; | |
771 if (maxdescent < font->descent) maxdescent = font->descent; | |
772 } | |
773 xpattr->linespacing = maxascent + maxdescent; | |
774 } | |
775 if (!(xmask & XIMP_PRE_CURSOR_MASK)) { | |
776 xpattr->cursor = None; /* ie use parent's cursor */ | |
777 } | |
778 if (!(xmask & XIMP_PRE_SPOTL_MASK)) { | |
779 xpattr->spotx = xpattr->spoty = 0; | |
780 } | |
781 if (!(xmask & XIMP_STS_FG_MASK)) { | |
782 xsattr->foreground = xpattr->foreground; | |
783 } | |
784 if (!(xmask & XIMP_STS_BG_MASK)) { | |
785 xsattr->background = xpattr->background; | |
786 } | |
787 if (!(xmask & XIMP_STS_COLORMAP_MASK)) { | |
788 xsattr->colormap = xpattr->colormap; | |
789 } | |
790 if (!(xmask & XIMP_STS_BGPIXMAP_MASK)) { | |
791 xsattr->bgpixmap = xpattr->bgpixmap; | |
792 } | |
793 if (!(xmask & XIMP_STS_LINESP_MASK)) { | |
794 xsattr->linespacing = xpattr->linespacing; | |
795 } | |
796 if (!(xmask & XIMP_STS_CURSOR_MASK)) { | |
797 xsattr->cursor = xpattr->cursor; | |
798 } | |
799 if (!(xmask & XIMP_STS_WINDOW_MASK)) { | |
800 xsattr->statuswin = None; | |
801 } | |
802 | |
803 client->defaultsfilledin = True; | |
804 } | |
805 | |
806 /*- computeAreaForStartup: compute Area for conversion startup -*/ | |
807 static void | |
808 computeAreaForStartup(client) | |
809 ConvClient *client; | |
810 { | |
811 XimpPreEditAttributes *xpattr = &client->xpattrs; | |
812 XimpStatusAttributes *xsattr = &client->xsattrs; | |
813 unsigned long mask = client->xattrmask; | |
814 | |
815 TRACE(("computeAreaForStartup(client=0x%lx)\n", client->reqwin)); | |
816 | |
817 if (client->style == separate_style || | |
818 client->style == onthespot_style || | |
819 client->style == overthespot_style) { | |
820 /* | |
821 * These styles don't need status nor preedit area. | |
822 * The separate style simpley ignores them, and the | |
823 * over-the-spot style uses default value if not specified. | |
824 */ | |
825 return; | |
826 } | |
827 | |
828 if ((mask & XIMP_STS_AREA_MASK) && (mask & XIMP_PRE_AREA_MASK)) return; | |
829 | |
830 /* | |
831 * Compute default status/pre-edit area based on the AreaNeeded values. | |
832 */ | |
833 computeAreaForQuery(client); | |
834 | |
835 if (!(mask & XIMP_STS_AREA_MASK)) { | |
836 xsattr->areax = 0; | |
837 xsattr->areay = client->reqwinheight - xsattr->neededheight; | |
838 xsattr->areawidth = xsattr->neededwidth; | |
839 xsattr->areaheight = xsattr->neededheight; | |
840 } | |
841 if (!(mask & XIMP_PRE_AREA_MASK)) { | |
842 xpattr->areax = xsattr->areax + xsattr->areawidth; | |
843 xpattr->areay = client->reqwinheight - xpattr->neededheight; | |
844 xpattr->areawidth = xpattr->neededwidth; | |
845 xpattr->areaheight = xpattr->neededheight; | |
846 } | |
847 } | |
848 | |
849 /*- computeAreaForQuery: compute Area and AreaNeeded for query from clients -*/ | |
850 static void | |
851 computeAreaForQuery(client) | |
852 ConvClient *client; | |
853 { | |
854 XimpProtocolWidget xpw = (XimpProtocolWidget)client->protocolwidget; | |
855 XimpPreEditAttributes *xpattr = &client->xpattrs; | |
856 XimpStatusAttributes *xsattr = &client->xsattrs; | |
857 unsigned long mask = client->xattrmask; | |
858 int width, height; | |
859 int maxwidth, maxheight; | |
860 int fontheight; | |
861 | |
862 TRACE(("computeAreaForQuery(client=0x%lx)\n", client->reqwin)); | |
863 | |
864 if (client->style == overthespot_style || | |
865 client->style == offthespot_style) { | |
866 | |
867 /* | |
868 * Get the size of the request window again. | |
869 * The size was checked when XIMP_CREATE message was received, | |
870 * but it is possible that the size has changed since then. | |
871 */ | |
872 (void)isCorrectWindowID(client->protocolwidget, client->reqwin, | |
873 &client->reqwinwidth, &client->reqwinheight); | |
874 } | |
875 | |
876 /* | |
877 * Compute the dimensions of the status region. | |
878 */ | |
879 if (client->style == overthespot_style || | |
880 client->style == offthespot_style) { | |
881 | |
882 /* | |
883 * Compute AreaNeeded value. | |
884 */ | |
885 fontheight = xsattr->linespacing + 2; | |
886 maxwidth = maxheight = 0; | |
887 if (mask & XIMP_STS_AREANEED_MASK) { | |
888 maxwidth = xsattr->neededwidth; | |
889 maxheight = xsattr->neededheight; | |
890 TRACE(("\tstatus areaNeeded was: (%d,%d)\n", maxwidth, maxheight)); | |
891 } | |
892 | |
893 if (xpw->ximp.statuswidth > 0) { | |
894 width = xpw->ximp.statuswidth; | |
895 } else { | |
896 width = client->reqwinwidth / 5; /* wild guess */ | |
897 if (width < fontheight * 3) { | |
898 width = fontheight * 3; /* another wild guess */ | |
899 } | |
900 } | |
901 height = fontheight; | |
902 | |
903 if (maxwidth > 0 && width > maxwidth) width = maxwidth; | |
904 if (maxheight > 0 && height > maxheight) height = maxheight; | |
905 if (width < MIN_AREA_WIDTH) width = MIN_AREA_WIDTH; | |
906 if (height < MIN_AREA_HEIGHT) height = MIN_AREA_HEIGHT; | |
907 | |
908 xsattr->neededwidth = width; | |
909 xsattr->neededheight = height; | |
910 TRACE(("\tstatus areaNeeded is now: (%d, %d)\n", width, height)); | |
911 | |
912 /* | |
913 * If client has not specified the status area yet, | |
914 * supply default value. | |
915 */ | |
916 if (!(mask & XIMP_STS_AREA_MASK)) { | |
917 xsattr->areax = 0; | |
918 xsattr->areay = client->reqwinheight - xsattr->neededheight; | |
919 xsattr->areawidth = xsattr->neededwidth; | |
920 xsattr->areaheight = xsattr->neededheight; | |
921 } | |
922 } | |
923 | |
924 /* | |
925 * Compute the dimensions of the pre-edit region. | |
926 */ | |
927 if (client->style == offthespot_style) { | |
928 /* | |
929 * Compute AreaNeeded value. | |
930 */ | |
931 fontheight = xpattr->linespacing + 2; | |
932 maxwidth = maxheight = 0; | |
933 if (mask & XIMP_PRE_AREANEED_MASK) { | |
934 maxwidth = xpattr->neededwidth; | |
935 maxheight = xpattr->neededheight; | |
936 TRACE(("\tpreedit areaNeeded was: (%d,%d)\n", maxwidth, maxheight)); | |
937 } | |
938 | |
939 width = client->reqwinwidth - xsattr->neededwidth; | |
940 height = fontheight; | |
941 | |
942 if (maxwidth > 0 && width > maxwidth) width = maxwidth; | |
943 if (maxheight > 0 && height > maxheight) height = maxheight; | |
944 if (width < MIN_AREA_WIDTH) width = MIN_AREA_WIDTH; | |
945 if (height < MIN_AREA_HEIGHT) height = MIN_AREA_HEIGHT; | |
946 | |
947 xpattr->neededwidth = width; | |
948 xpattr->neededheight = height; | |
949 TRACE(("\tpreedit areaNeeded is now: (%d, %d)\n", width, height)); | |
950 | |
951 /* | |
952 * If client has not specified the status area yet, | |
953 * supply default value. | |
954 */ | |
955 if (!(mask & XIMP_PRE_AREA_MASK)) { | |
956 xpattr->areax = xsattr->neededwidth; | |
957 xpattr->areay = client->reqwinheight - xpattr->neededheight; | |
958 xpattr->areawidth = xpattr->neededwidth; | |
959 xpattr->areaheight = xpattr->neededheight; | |
960 } | |
961 } else if (client->style == overthespot_style) { | |
962 /* | |
963 * No need to calculate AreaNeeded value, which is | |
964 * ignored by the client. Just calculate default | |
965 * Area if not specified. | |
966 */ | |
967 if (!(mask & XIMP_PRE_AREA_MASK)) { | |
968 xpattr->areax = 0; | |
969 xpattr->areay = 0; | |
970 xpattr->areawidth = client->focuswidth; | |
971 xpattr->areaheight = client->focusheight; | |
972 } | |
973 } | |
974 } | |
975 | |
976 /*- makeConvAttributes: -*/ | |
977 static unsigned long | |
978 makeConvAttributes(client, attr) | |
979 ConvClient *client; | |
980 ConversionAttributes *attr; | |
981 { | |
982 XimpPreEditAttributes *xpattr = &client->xpattrs; | |
983 XimpStatusAttributes *xsattr = &client->xsattrs; | |
984 unsigned long xmask = client->xattrmask; | |
985 unsigned long mask; | |
986 | |
987 TRACE(("makeConvAttributes()\n")); | |
988 mask = 0L; | |
989 | |
990 /* focus window */ | |
991 attr->focuswindow = client->focuswin; | |
992 mask |= CAFocusWindow; | |
993 | |
994 if (client->style == overthespot_style || | |
995 client->style == offthespot_style) { | |
996 | |
997 /* client area */ | |
998 if (client->style == offthespot_style || | |
999 (xmask & XIMP_PRE_AREA_MASK)) { | |
1000 attr->clientarea.x = xpattr->areax; | |
1001 attr->clientarea.y = xpattr->areay; | |
1002 attr->clientarea.width = xpattr->areawidth; | |
1003 attr->clientarea.height = xpattr->areaheight; | |
1004 mask |= CAClientArea; | |
1005 } | |
1006 | |
1007 /* foreground/background */ | |
1008 attr->foreground = xpattr->foreground; | |
1009 attr->background = xpattr->background; | |
1010 mask |= CAColor; | |
1011 | |
1012 /* colormap */ | |
1013 if (xmask & XIMP_PRE_COLORMAP_MASK) { | |
1014 attr->colormap = xpattr->colormap; | |
1015 mask |= CAColormap; | |
1016 } | |
1017 | |
1018 /* background pixmap */ | |
1019 if (xmask & XIMP_PRE_BGPIXMAP_MASK) { | |
1020 attr->background_pixmap = xpattr->bgpixmap; | |
1021 mask |= CABackgroundPixmap; | |
1022 } | |
1023 | |
1024 /* line spacing */ | |
1025 if (xmask & XIMP_PRE_LINESP_MASK) { | |
1026 attr->linespacing = xpattr->linespacing; | |
1027 mask |= CALineSpacing; | |
1028 } | |
1029 | |
1030 /* cursor */ | |
1031 if (xmask & XIMP_PRE_CURSOR_MASK) { | |
1032 attr->cursor = xpattr->cursor; | |
1033 mask |= CACursor; | |
1034 } | |
1035 | |
1036 /* status area */ | |
1037 /* offTheSpotConversion doesn't allow status area left unspecified */ | |
1038 if (client->style == offthespot_style || | |
1039 (xmask & XIMP_STS_AREA_MASK)) { | |
1040 attr->statusarea.x = xsattr->areax; | |
1041 attr->statusarea.y = xsattr->areay; | |
1042 attr->statusarea.width = xsattr->areawidth; | |
1043 attr->statusarea.height = xsattr->areaheight; | |
1044 mask |= CAStatusArea; | |
1045 } | |
1046 | |
1047 /* font */ | |
1048 attr->fonts = client->fonts; | |
1049 attr->num_fonts = client->num_fonts; | |
1050 attr->status_fonts = client->status_fonts; | |
1051 attr->num_status_fonts = client->num_status_fonts; | |
1052 mask |= CAFonts|CAStatusFonts; | |
1053 } | |
1054 | |
1055 if (client->style == overthespot_style) { | |
1056 /* spot location */ | |
1057 if (xmask & XIMP_PRE_SPOTL_MASK) { | |
1058 attr->spotx = xpattr->spotx; | |
1059 attr->spoty = xpattr->spoty; | |
1060 mask |= CASpotLocation; | |
1061 } | |
1062 } | |
1063 return mask; | |
1064 } | |
1065 | |
1066 /*- getFonts: get fonts from specified fontnamelist -*/ | |
1067 static void | |
1068 getFonts(client, fontnamelist, preedit) | |
1069 ConvClient *client; | |
1070 String fontnamelist; | |
1071 int preedit; | |
1072 { | |
1073 XimpProtocolWidget xpw = (XimpProtocolWidget)client->protocolwidget; | |
1074 XFontStruct **fonts; | |
1075 int num_fonts; | |
1076 | |
1077 TRACE(("getFonts(%s)\n", preedit ? "preedit" : "status")); | |
1078 TRACE(("\tfontnamelist: %s\n", fontnamelist)); | |
1079 | |
1080 fonts = FontBankGet(xpw->ximp.fontbank, fontnamelist, &num_fonts); | |
1081 if (preedit) { | |
1082 client->fonts = fonts; | |
1083 client->num_fonts = num_fonts; | |
1084 } else { | |
1085 client->status_fonts = fonts; | |
1086 client->num_status_fonts = num_fonts; | |
1087 } | |
1088 } | |
1089 | |
1090 | |
1091 /* | |
1092 *+ property handling | |
1093 */ | |
1094 | |
1095 /*- setProperty: set information properties -*/ | |
1096 static void | |
1097 setProperty(xpw) | |
1098 XimpProtocolWidget xpw; | |
1099 { | |
1100 Display *dpy = XtDisplay((Widget)xpw); | |
1101 Window win = XtWindow((Widget)xpw); | |
1102 XimpInputStyle *xisp; | |
1103 unsigned long styles[20]; | |
1104 Cardinal nstyles; | |
1105 unsigned long extensions[10]; | |
1106 Cardinal nextensions; | |
1107 | |
1108 TRACE(("setProperty()\n")); | |
1109 | |
1110 #define SETPROPERTY(p, t, f, d, n) \ | |
1111 XChangeProperty(dpy, win, p, t, f, PropModeReplace, (unsigned char *)d, n) | |
1112 | |
1113 SETPROPERTY(xpw->ximp.ximpVersionAtom, XA_STRING, 8, | |
1114 PROTOCOL_VERSION_STR, strlen(PROTOCOL_VERSION_STR)); | |
1115 SETPROPERTY(xpw->ximp.ximpServerNameAtom, XA_STRING, 8, | |
1116 SERVER_NAME, strlen(xpw->ximp.servername)); | |
1117 SETPROPERTY(xpw->ximp.ximpServerVersionAtom, XA_STRING, 8, | |
1118 SERVER_VERSION, strlen(SERVER_VERSION)); | |
1119 SETPROPERTY(xpw->ximp.ximpVendorNameAtom, XA_STRING, 8, | |
1120 VENDOR_NAME, strlen(VENDOR_NAME)); | |
1121 | |
1122 for (xisp = XimpStyles, nstyles = 0; xisp->ximstyle != 0; | |
1123 xisp++, nstyles++) { | |
1124 styles[nstyles] = xisp->ximstyle; | |
1125 } | |
1126 SETPROPERTY(xpw->ximp.ximpStyleAtom, xpw->ximp.ximpStyleAtom, 32, | |
1127 styles, nstyles); | |
1128 | |
1129 nextensions = 0; | |
1130 extensions[nextensions++] = xpw->ximp.ximpExtXimpBackFrontAtom; | |
1131 SETPROPERTY(xpw->ximp.ximpExtensionsAtom, xpw->ximp.ximpExtensionsAtom, 32, | |
1132 extensions, nextensions); | |
1133 | |
1134 setKeyProperty(xpw); | |
1135 | |
1136 #undef SETPROPERTY | |
1137 } | |
1138 | |
1139 /*- setKeyProperty: set _XIM_KEYS property -*/ | |
1140 static void | |
1141 setKeyProperty(xpw) | |
1142 XimpProtocolWidget xpw; | |
1143 { | |
1144 long data[100]; /* enough */ | |
1145 char line[256]; /* enough */ | |
1146 Display *dpy = XtDisplay((Widget)xpw); | |
1147 int nkeys = 0; | |
1148 String p, q; | |
1149 int c, n; | |
1150 ICTriggerKey *keys, *ekeys; | |
1151 | |
1152 if ((p = xpw->ximp.convkeys) != NULL) { | |
1153 TRACE(("setKeyProperty(%s)\n", p)); | |
1154 do { | |
1155 KeySym keysym; | |
1156 long mods, chk_mods; | |
1157 | |
1158 q = line; | |
1159 while ((c = *p++) != '\0' && c != '\n') { | |
1160 *q++ = c; | |
1161 } | |
1162 *q = '\0'; | |
1163 if (ParseKeyEvent(line, &keysym, &mods, &chk_mods)) { | |
1164 data[nkeys * 3] = mods; | |
1165 data[nkeys * 3 + 1] = chk_mods; | |
1166 data[nkeys * 3 + 2] = keysym; | |
1167 nkeys++; | |
1168 } | |
1169 } while (c != '\0'); | |
1170 } | |
1171 | |
1172 n = ICGetTriggerKeysOfInputObjectClass(xpw->ximp.inputObjClass, &keys); | |
1173 for (ekeys = keys + n ; | |
1174 keys < ekeys && nkeys < (sizeof(data) / sizeof(long)) / 3 ; keys++) { | |
1175 data[nkeys * 3] = keys->modifiers; | |
1176 data[nkeys * 3 + 1] = keys->modifiermask; | |
1177 data[nkeys * 3 + 2] = keys->keysym; | |
1178 nkeys++; | |
1179 } | |
1180 | |
1181 XChangeProperty(dpy, XtWindow((Widget)xpw), xpw->ximp.ximpKeysAtom, | |
1182 xpw->ximp.ximpKeysAtom, 32, PropModeReplace, | |
1183 (unsigned char *)data, nkeys * 3); | |
1184 } | |
1185 | |
1186 /*- getVersionProperty: get _XIMP_VERSION property -*/ | |
1187 static void | |
1188 getVersionProperty(client) | |
1189 ConvClient *client; | |
1190 { | |
1191 XimpProtocolWidget xpw = (XimpProtocolWidget)client->protocolwidget; | |
1192 String data; | |
1193 unsigned long len; | |
1194 | |
1195 TRACE(("getVersionProperty()\n")); | |
1196 if (!readProperty(client, xpw->ximp.ximpVersionAtom, XA_STRING, 8, | |
1197 (unsigned char **)&data, &len)) { | |
1198 DPRINT(("can't read _XIMP_VERSION property\n")); | |
1199 client->version = NULL; | |
1200 return; | |
1201 } | |
1202 TRACE(("\tclient version is %s\n", data)); | |
1203 | |
1204 /* what to do? */ | |
1205 | |
1206 client->version = data; | |
1207 } | |
1208 | |
1209 /*- getAttributes: read properties and set conversion attributes -*/ | |
1210 static void | |
1211 getAttributes(client, mask) | |
1212 ConvClient *client; | |
1213 unsigned long mask; | |
1214 { | |
1215 if (mask & XIMP_FOCUS_WIN_MASK) { | |
1216 getFocusProperty(client); | |
1217 } | |
1218 if (mask & XIMP_PRE_FONT_MASK) { | |
1219 getPreeditFontProperty(client); | |
1220 } | |
1221 if (mask & XIMP_STS_FONT_MASK) { | |
1222 getStatusFontProperty(client); | |
1223 } | |
1224 if (mask & PREEDIT_MASK) { | |
1225 getPreeditProperty(client, mask & PREEDIT_MASK); | |
1226 } | |
1227 if (mask & STATUS_MASK) { | |
1228 getStatusProperty(client, mask & STATUS_MASK); | |
1229 } | |
1230 } | |
1231 | |
1232 /*- getFocusProperty: get _XIMP_FOCUS property -*/ | |
1233 static void | |
1234 getFocusProperty(client) | |
1235 ConvClient *client; | |
1236 { | |
1237 XimpProtocolWidget xpw = (XimpProtocolWidget)client->protocolwidget; | |
1238 unsigned char *data; | |
1239 unsigned long len; | |
1240 Window focus; | |
1241 Dimension w, h; | |
1242 | |
1243 TRACE(("getFocusProperty()\n")); | |
1244 if (!readProperty(client, xpw->ximp.ximpFocusAtom, XA_WINDOW, 32, | |
1245 &data, &len)) { | |
1246 DPRINT(("can't read _XIMP_FOCUS property\n")); | |
1247 return; | |
1248 } else if (len != 1) { | |
1249 DPRINT(("length of _XIMP_FOCUS property is not 1\n")); | |
1250 XtFree((char *)data); | |
1251 return; | |
1252 } | |
1253 | |
1254 focus = *(Window *)data; | |
1255 XtFree((char *)data); | |
1256 TRACE(("\tfocus window=0x%lx\n", focus)); | |
1257 | |
1258 if (!isCorrectWindowID((Widget)xpw, focus, &w, &h)) { | |
1259 DPRINT(("specified focus window doesn't exist\n")); | |
1260 sendErrorEvent(client, XIMP_BadFocusWindow); | |
1261 return; | |
1262 } | |
1263 | |
1264 client->focuswin = focus; | |
1265 client->focuswidth = w; | |
1266 client->focusheight = h; | |
1267 client->xattrmask |= XIMP_FOCUS_WIN_MASK; | |
1268 } | |
1269 | |
1270 /*- getPreeditFontProperty: get _XIMP_PREEDITFONT property -*/ | |
1271 static void | |
1272 getPreeditFontProperty(client) | |
1273 ConvClient *client; | |
1274 { | |
1275 XimpProtocolWidget xpw = (XimpProtocolWidget)client->protocolwidget; | |
1276 char *data; | |
1277 unsigned long len; | |
1278 | |
1279 TRACE(("getPreeditFontProperty()\n")); | |
1280 if (!readProperty(client, xpw->ximp.ximpPreeditFontAtom, XA_STRING, 8, | |
1281 (unsigned char **)&data, &len)) { | |
1282 DPRINT(("can't read _XIMP_PREEDITFONT property\n")); | |
1283 return; | |
1284 } | |
1285 | |
1286 if (client->xpattrs.fontlist != NULL) { | |
1287 if (!strcmp(data, client->xpattrs.fontlist)) { | |
1288 XtFree(data); | |
1289 return; | |
1290 } | |
1291 if (client->xpattrs.fontlist != xpw->ximp.defaultfontlist) { | |
1292 XtFree(client->xpattrs.fontlist); | |
1293 } | |
1294 } | |
1295 client->xpattrs.fontlist = data; | |
1296 client->xattrmask |= XIMP_PRE_FONT_MASK; | |
1297 | |
1298 /* extract fonts to be used */ | |
1299 getFonts(client, data, 1); | |
1300 } | |
1301 | |
1302 /*- getStatusFontProperty: get _XIMP_STATUSFONT property -*/ | |
1303 static void | |
1304 getStatusFontProperty(client) | |
1305 ConvClient *client; | |
1306 { | |
1307 XimpProtocolWidget xpw = (XimpProtocolWidget)client->protocolwidget; | |
1308 unsigned char *data; | |
1309 unsigned long len; | |
1310 | |
1311 TRACE(("getStatusFontProperty()\n")); | |
1312 if (!readProperty(client, xpw->ximp.ximpStatusFontAtom, XA_STRING, 8, | |
1313 &data, &len)) { | |
1314 DPRINT(("can't read _XIMP_STATUSFONT property\n")); | |
1315 return; | |
1316 } | |
1317 | |
1318 if (client->xsattrs.fontlist != NULL) { | |
1319 if (!strcmp(data, client->xsattrs.fontlist)) { | |
1320 XtFree(data); | |
1321 return; | |
1322 } | |
1323 if (client->xsattrs.fontlist != xpw->ximp.defaultfontlist) { | |
1324 XtFree(client->xsattrs.fontlist); | |
1325 } | |
1326 } | |
1327 client->xsattrs.fontlist = (String)data; | |
1328 client->xattrmask |= XIMP_STS_FONT_MASK; | |
1329 | |
1330 /* extract fonts to be used */ | |
1331 getFonts(client, data, 0); | |
1332 } | |
1333 | |
1334 /*- getPreeditProperty: get _XIMP_PREEDIT property -*/ | |
1335 static void | |
1336 getPreeditProperty(client, mask) | |
1337 ConvClient *client; | |
1338 unsigned long mask; | |
1339 { | |
1340 XimpProtocolWidget xpw = (XimpProtocolWidget)client->protocolwidget; | |
1341 XimpPreEditAttributes *xpattr = &client->xpattrs; | |
1342 unsigned long *data; | |
1343 unsigned long len; | |
1344 | |
1345 TRACE(("getPreeditProperty()\n")); | |
1346 if (!readProperty(client, xpw->ximp.ximpPreeditAtom, | |
1347 xpw->ximp.ximpPreeditAtom, 32, | |
1348 (unsigned char **)&data, &len)) { | |
1349 DPRINT(("can't read _XIMP_PREEDIT property\n")); | |
1350 return; | |
1351 } else if (len < 14) { | |
1352 DPRINT(("length of _XIMP_PREEDIT property is less than 14(%ld)\n",len)); | |
1353 XtFree((char *)data); | |
1354 return; | |
1355 } | |
1356 | |
1357 client->xattrmask |= mask; | |
1358 | |
1359 /* data[0]-data[3]: Area.{x,y,width,height} */ | |
1360 if (mask & XIMP_PRE_AREA_MASK) { | |
1361 xpattr->areax = data[0]; | |
1362 xpattr->areay = data[1]; | |
1363 xpattr->areawidth = data[2]; | |
1364 xpattr->areaheight = data[3]; | |
1365 if (xpattr->areawidth == 0 || xpattr->areaheight == 0) { | |
1366 client->xattrmask &= ~XIMP_PRE_AREA_MASK; | |
1367 DPRINT(("invalid area specified:\n")); | |
1368 } | |
1369 TRACE(("\tArea: (%ld,%ld)-(%ld,%ld)\n",data[0],data[1],data[2],data[3])); | |
1370 } | |
1371 /* data[4]: Foreground */ | |
1372 if (mask & XIMP_PRE_FG_MASK) { | |
1373 xpattr->foreground = data[4]; | |
1374 TRACE(("\tForeground: %ld\n", data[4])); | |
1375 } | |
1376 /* data[5]: Background */ | |
1377 if (mask & XIMP_PRE_BG_MASK) { | |
1378 xpattr->background = data[5]; | |
1379 TRACE(("\tBackground: %ld\n", data[5])); | |
1380 } | |
1381 /* data[6]: Colormap */ | |
1382 if (mask & XIMP_PRE_COLORMAP_MASK) { | |
1383 xpattr->colormap = data[6]; | |
1384 TRACE(("\tColormap: 0x%lx\n", data[6])); | |
1385 } | |
1386 /* data[7]: BackgroundPixmap */ | |
1387 if (mask & XIMP_PRE_BGPIXMAP_MASK) { | |
1388 xpattr->bgpixmap = data[7]; | |
1389 TRACE(("\tBackgroundPixmap: 0x%lx\n", data[7])); | |
1390 } | |
1391 /* data[8]: LineSpacing */ | |
1392 if (mask & XIMP_PRE_LINESP_MASK) { | |
1393 if (data[8] < MIN_LINE_SPACING) { | |
1394 client->xattrmask &= ~XIMP_PRE_LINESP_MASK; | |
1395 DPRINT(("specified line spacing is too small (%ld)\n", data[8])); | |
1396 } else { | |
1397 xpattr->linespacing = data[8]; | |
1398 TRACE(("\tLineSpacing: %ld\n", data[8])); | |
1399 } | |
1400 } | |
1401 /* data[9]: Cursor */ | |
1402 if (mask & XIMP_PRE_CURSOR_MASK) { | |
1403 xpattr->cursor = data[9]; | |
1404 TRACE(("\tCursor: 0x%lx\n", data[9])); | |
1405 } | |
1406 /* data[10]-data[11]: AreaNeeded.{width,height} */ | |
1407 if (mask & XIMP_PRE_AREANEED_MASK) { | |
1408 xpattr->neededwidth = data[10]; | |
1409 xpattr->neededheight = data[11]; | |
1410 TRACE(("\tAreaNeeded: %ld,%ld\n", data[10], data[11])); | |
1411 } | |
1412 /* data[12]-data[13]: SpotLocation.{x,y} */ | |
1413 if (mask & XIMP_PRE_SPOTL_MASK) { | |
1414 xpattr->spotx = data[12]; | |
1415 xpattr->spoty = data[13]; | |
1416 TRACE(("\tSpotLocation: %ld,%ld\n", data[12], data[13])); | |
1417 } | |
1418 | |
1419 XtFree((char *)data); | |
1420 } | |
1421 | |
1422 /*- getStatusProperty: get _XIMP_STATUS property -*/ | |
1423 static void | |
1424 getStatusProperty(client, mask) | |
1425 ConvClient *client; | |
1426 unsigned long mask; | |
1427 { | |
1428 XimpProtocolWidget xpw = (XimpProtocolWidget)client->protocolwidget; | |
1429 XimpStatusAttributes *xsattr = &client->xsattrs; | |
1430 unsigned long *data; | |
1431 unsigned long len; | |
1432 | |
1433 TRACE(("getStatusProperty()\n")); | |
1434 if (!readProperty(client, xpw->ximp.ximpStatusAtom, | |
1435 xpw->ximp.ximpStatusAtom, 32, | |
1436 (unsigned char **)&data, &len)) { | |
1437 DPRINT(("can't read _XIMP_STATUS property\n")); | |
1438 return; | |
1439 } else if (len < 12) { | |
1440 DPRINT(("length of _XIMP_STATUS property is less than 12(%ld)\n",len)); | |
1441 XtFree((char *)data); | |
1442 return; | |
1443 } | |
1444 | |
1445 client->xattrmask |= mask; | |
1446 | |
1447 /* data[0]-data[3]: Area.{x,y,width,height} */ | |
1448 if (mask & XIMP_STS_AREA_MASK) { | |
1449 xsattr->areax = data[0]; | |
1450 xsattr->areay = data[1]; | |
1451 xsattr->areawidth = data[2]; | |
1452 xsattr->areaheight = data[3]; | |
1453 if (xsattr->areawidth == 0 || xsattr->areaheight == 0) { | |
1454 client->xattrmask &= ~XIMP_STS_AREA_MASK; | |
1455 DPRINT(("invalid area specified:\n")); | |
1456 } | |
1457 TRACE(("\tArea: (%ld,%ld)-(%ld,%ld)\n", | |
1458 data[0],data[1],data[2],data[3])); | |
1459 } | |
1460 /* data[4]: Foreground */ | |
1461 if (mask & XIMP_STS_FG_MASK) { | |
1462 xsattr->foreground = data[4]; | |
1463 TRACE(("\tForeground: %ld\n", data[4])); | |
1464 } | |
1465 /* data[5]: Background */ | |
1466 if (mask & XIMP_STS_BG_MASK) { | |
1467 xsattr->background = data[5]; | |
1468 TRACE(("\tBackground: %ld\n", data[5])); | |
1469 } | |
1470 /* data[6]: Colormap */ | |
1471 if (mask & XIMP_STS_COLORMAP_MASK) { | |
1472 xsattr->colormap = data[6]; | |
1473 TRACE(("\tColormap: 0x%lx\n", data[6])); | |
1474 } | |
1475 /* data[7]: BackgroundPixmap */ | |
1476 if (mask & XIMP_STS_BGPIXMAP_MASK) { | |
1477 xsattr->bgpixmap = data[7]; | |
1478 TRACE(("\tBackgroundPixmap: 0x%lx\n", data[7])); | |
1479 } | |
1480 /* data[8]: LineSpacing */ | |
1481 if (mask & XIMP_STS_LINESP_MASK) { | |
1482 if (data[8] < MIN_LINE_SPACING) { | |
1483 client->xattrmask &= ~XIMP_STS_LINESP_MASK; | |
1484 DPRINT(("specified line spacing is too small (%ld)\n", data[8])); | |
1485 } else { | |
1486 xsattr->linespacing = data[8]; | |
1487 TRACE(("\tLineSpacing: %ld\n", data[8])); | |
1488 } | |
1489 } | |
1490 /* data[9]: Cursor */ | |
1491 if (mask & XIMP_STS_CURSOR_MASK) { | |
1492 xsattr->cursor = data[9]; | |
1493 TRACE(("\tCursor: 0x%lx\n", data[9])); | |
1494 } | |
1495 /* data[10]-data[11]: AreaNeeded.{width,height} */ | |
1496 if (mask & XIMP_STS_AREANEED_MASK) { | |
1497 xsattr->neededwidth = data[10]; | |
1498 xsattr->neededheight = data[11]; | |
1499 TRACE(("\tAreaNeeded: %ld,%ld\n", data[10], data[11])); | |
1500 } | |
1501 /* data[12]: StatusWindowID -- not suppoted by kinput2 */ | |
1502 if (len > 12 && (mask & XIMP_STS_WINDOW_MASK)) { | |
1503 xsattr->statuswin = None; /* ignore specified value */ | |
1504 TRACE(("\tStatusWindow(not supported): 0x%lx\n", data[12])); | |
1505 } | |
1506 | |
1507 XtFree((char *)data); | |
1508 } | |
1509 | |
1510 /*- readProperty: read specified property of the client window -*/ | |
1511 static Boolean | |
1512 readProperty(client, prop, type, format, datapp, lenp) | |
1513 ConvClient *client; | |
1514 Atom prop; | |
1515 Atom type; | |
1516 int format; | |
1517 unsigned char **datapp; | |
1518 unsigned long *lenp; | |
1519 { | |
1520 Atom realtype; | |
1521 int realformat; | |
1522 unsigned long bytesafter; | |
1523 | |
1524 *datapp = NULL; | |
1525 /* | |
1526 * generally, XGetWindowProperty can generate BadAtom, BadValue and | |
1527 * BadWindow errors. but in this case, none of those errors can occur. | |
1528 * atoms are valid, offset 0 won't cause BadValue, and window ID is | |
1529 * already validated. (strictly speaking, there's a chance of getting | |
1530 * BadWindow if the client window destroyed after it was validated. | |
1531 * let's forget it for a while :-) so we don't have to be careful to | |
1532 * errors. | |
1533 */ | |
1534 (void)XGetWindowProperty(XtDisplay(client->protocolwidget), | |
1535 client->reqwin, | |
1536 prop, 0L, 1000L, True, type, | |
1537 &realtype, &realformat, lenp, | |
1538 &bytesafter, datapp); | |
1539 if (realtype == None) { | |
1540 /* specified property doesn't exist */ | |
1541 sendErrorEvent(client, XIMP_BadProperty); | |
1542 return False; | |
1543 } else if (realtype != type) { | |
1544 /* wrong type */ | |
1545 sendErrorEvent(client, XIMP_BadPropertyType); | |
1546 return False; | |
1547 } else if (realformat != format) { | |
1548 /* wrong format */ | |
1549 if (*datapp != NULL) XtFree((char *)*datapp); | |
1550 *datapp = NULL; | |
1551 /* there's no XIMP_BadFormat error. use XIMP_BadPropertyType instead */ | |
1552 sendErrorEvent(client, XIMP_BadPropertyType); | |
1553 return False; | |
1554 } | |
1555 return True; | |
1556 } | |
1557 | |
1558 /*- setAttributes: set properties according to the conversion attributes -*/ | |
1559 static void | |
1560 setAttributes(client, mask) | |
1561 ConvClient *client; | |
1562 unsigned long mask; | |
1563 { | |
1564 if (mask & XIMP_FOCUS_WIN_MASK) { | |
1565 setFocusProperty(client); | |
1566 } | |
1567 if (mask & XIMP_PRE_FONT_MASK) { | |
1568 setPreeditFontProperty(client); | |
1569 } | |
1570 if (mask & XIMP_STS_FONT_MASK) { | |
1571 setStatusFontProperty(client); | |
1572 } | |
1573 if (mask & PREEDIT_MASK) { | |
1574 setPreeditProperty(client, mask); | |
1575 } | |
1576 if (mask & STATUS_MASK) { | |
1577 setStatusProperty(client, mask); | |
1578 } | |
1579 } | |
1580 | |
1581 /*- setFocusProperty: set _XIMP_FOCUS property -*/ | |
1582 static void | |
1583 setFocusProperty(client) | |
1584 ConvClient *client; | |
1585 { | |
1586 XimpProtocolWidget xpw = (XimpProtocolWidget)client->protocolwidget; | |
1587 | |
1588 TRACE(("setFocusProperty()\n")); | |
1589 writeProperty(client, xpw->ximp.ximpFocusAtom, XA_WINDOW, 32, | |
1590 (unsigned char *)&client->focuswin, 1); | |
1591 } | |
1592 | |
1593 /*- setPreeditFontProperty: set _XIMP_PREEDITFONT property -*/ | |
1594 static void | |
1595 setPreeditFontProperty(client) | |
1596 ConvClient *client; | |
1597 { | |
1598 XimpProtocolWidget xpw = (XimpProtocolWidget)client->protocolwidget; | |
1599 | |
1600 TRACE(("setPreeditFontProperty()\n")); | |
1601 writeProperty(client, xpw->ximp.ximpPreeditFontAtom, XA_STRING, 8, | |
1602 (unsigned char *)client->xpattrs.fontlist, | |
1603 strlen(client->xpattrs.fontlist)); | |
1604 } | |
1605 | |
1606 /*- setStatusFontProperty: set _XIMP_STATUSFONT property -*/ | |
1607 static void | |
1608 setStatusFontProperty(client) | |
1609 ConvClient *client; | |
1610 { | |
1611 XimpProtocolWidget xpw = (XimpProtocolWidget)client->protocolwidget; | |
1612 | |
1613 TRACE(("setStatusFontProperty()\n")); | |
1614 writeProperty(client, xpw->ximp.ximpStatusFontAtom, XA_STRING, 8, | |
1615 (unsigned char *)client->xsattrs.fontlist, | |
1616 strlen(client->xsattrs.fontlist)); | |
1617 } | |
1618 | |
1619 /*- setPreeditProperty: set _XIMP_PREEDIT property -*/ | |
1620 static void | |
1621 setPreeditProperty(client, mask) | |
1622 ConvClient *client; | |
1623 unsigned long mask; | |
1624 { | |
1625 XimpProtocolWidget xpw = (XimpProtocolWidget)client->protocolwidget; | |
1626 XimpPreEditAttributes *xpattr = &client->xpattrs; | |
1627 long data[14]; | |
1628 | |
1629 TRACE(("setPreeditProperty()\n")); | |
1630 | |
1631 /* data[0]-data[3]: Area.{x,y,width,height} */ | |
1632 if (mask & XIMP_PRE_AREA_MASK) { | |
1633 data[0] = xpattr->areax; | |
1634 data[1] = xpattr->areay; | |
1635 data[2] = xpattr->areawidth; | |
1636 data[3] = xpattr->areaheight; | |
1637 } | |
1638 /* data[4]: Foreground */ | |
1639 if (mask & XIMP_PRE_FG_MASK) { | |
1640 data[4] = xpattr->foreground; | |
1641 } | |
1642 /* data[5]: Background */ | |
1643 if (mask & XIMP_PRE_BG_MASK) { | |
1644 data[5] = xpattr->background; | |
1645 } | |
1646 /* data[6]: Colormap */ | |
1647 if (mask & XIMP_PRE_COLORMAP_MASK) { | |
1648 data[6] = xpattr->colormap; | |
1649 } | |
1650 /* data[7]: BackgroundPixmap */ | |
1651 if (mask & XIMP_PRE_BGPIXMAP_MASK) { | |
1652 data[7] = xpattr->bgpixmap; | |
1653 } | |
1654 /* data[8]: LineSpacing */ | |
1655 if (mask & XIMP_PRE_LINESP_MASK) { | |
1656 data[8] = xpattr->linespacing; | |
1657 } | |
1658 /* data[9]: Cursor */ | |
1659 if (mask & XIMP_PRE_CURSOR_MASK) { | |
1660 data[9] = xpattr->cursor; | |
1661 } | |
1662 /* data[10]-data[11]: AreaNeeded.{width,height} */ | |
1663 if (mask & XIMP_PRE_AREANEED_MASK) { | |
1664 data[10] = xpattr->neededwidth; | |
1665 data[11] = xpattr->neededheight; | |
1666 } | |
1667 /* data[12]-data[13]: SpotLocation.{x,y} */ | |
1668 if (mask & XIMP_PRE_SPOTL_MASK) { | |
1669 data[12] = xpattr->spotx; | |
1670 data[13] = xpattr->spoty; | |
1671 } | |
1672 | |
1673 writeProperty(client, xpw->ximp.ximpPreeditAtom, | |
1674 xpw->ximp.ximpPreeditAtom, 32, | |
1675 (unsigned char *)data, 14); | |
1676 } | |
1677 | |
1678 /*- setStautsProperty: set _XIMP_STATUS property -*/ | |
1679 static void | |
1680 setStatusProperty(client, mask) | |
1681 ConvClient *client; | |
1682 unsigned long mask; | |
1683 { | |
1684 XimpProtocolWidget xpw = (XimpProtocolWidget)client->protocolwidget; | |
1685 XimpStatusAttributes *xsattr = &client->xsattrs; | |
1686 long data[13]; | |
1687 | |
1688 TRACE(("setStatusProperty()\n")); | |
1689 | |
1690 /* data[0]-data[3]: Area.{x,y,width,height} */ | |
1691 if (mask & XIMP_STS_AREA_MASK) { | |
1692 data[0] = xsattr->areax = data[0]; | |
1693 data[1] = xsattr->areay = data[1]; | |
1694 data[2] = xsattr->areawidth = data[2]; | |
1695 data[3] = xsattr->areaheight = data[3]; | |
1696 } | |
1697 /* data[4]: Foreground */ | |
1698 if (mask & XIMP_STS_FG_MASK) { | |
1699 data[4] = xsattr->foreground; | |
1700 } | |
1701 /* data[5]: Background */ | |
1702 if (mask & XIMP_STS_BG_MASK) { | |
1703 data[5] = xsattr->background; | |
1704 } | |
1705 /* data[6]: Colormap */ | |
1706 if (mask & XIMP_STS_COLORMAP_MASK) { | |
1707 data[6] = xsattr->colormap; | |
1708 } | |
1709 /* data[7]: BackgroundPixmap */ | |
1710 if (mask & XIMP_STS_BGPIXMAP_MASK) { | |
1711 data[7] = xsattr->bgpixmap; | |
1712 } | |
1713 /* data[8]: LineSpacing */ | |
1714 if (mask & XIMP_STS_LINESP_MASK) { | |
1715 data[8] = xsattr->linespacing; | |
1716 } | |
1717 /* data[9]: Cursor */ | |
1718 if (mask & XIMP_STS_CURSOR_MASK) { | |
1719 data[9] = xsattr->cursor; | |
1720 } | |
1721 /* data[10]-data[11]: AreaNeeded.{width,height} */ | |
1722 if (mask & XIMP_STS_AREANEED_MASK) { | |
1723 data[10] = xsattr->neededwidth; | |
1724 data[11] = xsattr->neededheight; | |
1725 } | |
1726 /* data[12]: StatusWindowID -- not suppoted by kinput2 */ | |
1727 if (mask & XIMP_STS_WINDOW_MASK) { | |
1728 data[12] = xsattr->statuswin; | |
1729 } | |
1730 | |
1731 writeProperty(client, xpw->ximp.ximpStatusAtom, | |
1732 xpw->ximp.ximpStatusAtom, 32, | |
1733 (unsigned char *)data, 13); | |
1734 } | |
1735 | |
1736 /*- writeProperty: write specified property of the client window -*/ | |
1737 static void | |
1738 writeProperty(client, prop, type, format, datap, len) | |
1739 ConvClient *client; | |
1740 Atom prop; | |
1741 Atom type; | |
1742 int format; | |
1743 unsigned char *datap; | |
1744 int len; | |
1745 { | |
1746 /* | |
1747 * generally, XChangeWindowProperty can generate BadAlloc, BadAtom, | |
1748 * BadMatch, BadValue and BadWindow errors. but in this case, none of | |
1749 * those errors except BadAlloc can occur. atoms and values to be | |
1750 * specified are valid (at least if the program is correct :-), mode | |
1751 * PropModeReplace won't cause BadMatch, and window ID is already | |
1752 * validated. so, if we assume amount of memory is infinite :-), we | |
1753 * don't have to be careful to errors. | |
1754 */ | |
1755 (void)XChangeProperty(XtDisplay(client->protocolwidget), | |
1756 client->reqwin, prop, type, format, | |
1757 PropModeReplace, datap, len); | |
1758 } | |
1759 | |
1760 /* | |
1761 *+ event sending | |
1762 */ | |
1763 | |
1764 /*- sendClientMessage8: send a clientmessage event (format=8) -*/ | |
1765 static void | |
1766 sendClientMessage8(client, str, len) | |
1767 ConvClient *client; | |
1768 char *str; | |
1769 int len; | |
1770 { | |
1771 XimpProtocolWidget xpw = (XimpProtocolWidget)client->protocolwidget; | |
1772 XEvent event; | |
1773 | |
1774 event.xclient.type = ClientMessage; | |
1775 event.xclient.window = client->focuswin; | |
1776 event.xclient.message_type = xpw->ximp.ximpProtocolAtom; | |
1777 event.xclient.format = 8; | |
1778 | |
1779 /* client ID must be stored in network byte order (ie MSB first) */ | |
1780 event.xclient.data.b[0] = (client->id >> 24) & 0xff; | |
1781 event.xclient.data.b[1] = (client->id >> 16) & 0xff; | |
1782 event.xclient.data.b[2] = (client->id >> 8) & 0xff; | |
1783 event.xclient.data.b[3] = client->id & 0xff; | |
1784 | |
1785 event.xclient.data.b[4] = len; | |
1786 | |
1787 (void)strncpy(&event.xclient.data.b[5], str, 20 - 5); | |
1788 | |
1789 XSendEvent(XtDisplay((Widget)xpw), event.xclient.window, | |
1790 False, NoEventMask, &event); | |
1791 } | |
1792 | |
1793 /*- sendClientMessage32: send a clientmessage event (format=32) -*/ | |
1794 static void | |
1795 sendClientMessage32(client, type, l1, l2, l3, l4) | |
1796 ConvClient *client; | |
1797 int type; | |
1798 unsigned long l1, l2, l3, l4; | |
1799 { | |
1800 XimpProtocolWidget xpw = (XimpProtocolWidget)client->protocolwidget; | |
1801 XEvent event; | |
1802 | |
1803 event.xclient.type = ClientMessage; | |
1804 event.xclient.window = client->focuswin; | |
1805 event.xclient.message_type = xpw->ximp.ximpProtocolAtom; | |
1806 event.xclient.format = 32; | |
1807 event.xclient.data.l[0] = type; | |
1808 event.xclient.data.l[1] = l1; | |
1809 event.xclient.data.l[2] = l2; | |
1810 event.xclient.data.l[3] = l3; | |
1811 event.xclient.data.l[4] = l4; | |
1812 | |
1813 XSendEvent(XtDisplay((Widget)xpw), event.xclient.window, | |
1814 False, NoEventMask, &event); | |
1815 } | |
1816 | |
1817 /*- sendKeyEvent: send unused keypress event via clientmessage event -*/ | |
1818 static void | |
1819 sendKeyEvent(client, keyevent) | |
1820 ConvClient *client; | |
1821 XKeyEvent *keyevent; | |
1822 { | |
1823 TRACE(("sendKeyEvent()\n")); | |
1824 sendClientMessage32(client, XIMP_KEYPRESS, client->id, | |
1825 (unsigned long)keyevent->keycode, | |
1826 (unsigned long)keyevent->state, 0L); | |
1827 } | |
1828 | |
1829 /*- sendErrorEvent: send error event via clientmessage event -*/ | |
1830 static void | |
1831 sendErrorEvent(client, error) | |
1832 ConvClient *client; | |
1833 int error; | |
1834 { | |
1835 sendClientMessage32(client, XIMP_ERROR, client->id, | |
1836 client->event->serial, (unsigned long)error, 0L); | |
1837 } | |
1838 | |
1839 /*- sendCreateRefusal: send rejecting message to a CREATE request -*/ | |
1840 static void | |
1841 sendCreateRefusal(xpw, window) | |
1842 XimpProtocolWidget xpw; | |
1843 Window window; | |
1844 { | |
1845 XEvent event; | |
1846 | |
1847 event.xclient.type = ClientMessage; | |
1848 event.xclient.window = window; | |
1849 event.xclient.message_type = xpw->ximp.ximpProtocolAtom; | |
1850 event.xclient.format = 32; | |
1851 event.xclient.data.l[0] = XIMP_CREATE_RETURN; | |
1852 event.xclient.data.l[1] = 0L; | |
1853 event.xclient.data.l[2] = 0L; | |
1854 event.xclient.data.l[3] = 0L; | |
1855 event.xclient.data.l[4] = 0L; | |
1856 | |
1857 XSendEvent(XtDisplay((Widget)xpw), window, False, NoEventMask, &event); | |
1858 } | |
1859 | |
1860 /* | |
1861 *+ callback procedures | |
1862 */ | |
1863 | |
1864 /*- fixCallback: fix callback -*/ | |
1865 /* ARGSUSED */ | |
1866 static void | |
1867 fixCallback(w, client_data, call_data) | |
1868 Widget w; | |
1869 XtPointer client_data; | |
1870 XtPointer call_data; | |
1871 { | |
1872 CCTextCallbackArg *arg = (CCTextCallbackArg *)call_data; | |
1873 ConvClient *ccp = (ConvClient *)client_data; | |
1874 | |
1875 TRACE(("fixCallback(reqwin=0x%lx, length=%d)\n",ccp->reqwin, arg->length)); | |
1876 fixProc(ccp, arg); | |
1877 } | |
1878 | |
1879 /*- fixProc: do actual fix processing -*/ | |
1880 static void | |
1881 fixProc(client, arg) | |
1882 ConvClient *client; | |
1883 CCTextCallbackArg *arg; | |
1884 { | |
1885 XimpProtocolWidget xpw = (XimpProtocolWidget)client->protocolwidget; | |
1886 | |
1887 /* check encoding and format */ | |
1888 if (arg->encoding != xpw->ximp.ctextAtom || arg->format != 8) { | |
1889 /* | |
1890 * since every conversion object must support COMPOUND_TEXT, | |
1891 * it is a serious error. | |
1892 */ | |
1893 String params[2]; | |
1894 Cardinal num_params; | |
1895 | |
1896 params[0] = XtClass((Widget)xpw)->core_class.class_name; | |
1897 params[1] = xpw->ximp.inputObjClass->core_class.class_name; | |
1898 num_params = 2; | |
1899 | |
1900 XtAppErrorMsg(XtWidgetToApplicationContext(client->protocolwidget), | |
1901 "encodingError", "convertedString", "WidgetError", | |
1902 "%s: encoding of the converted string is not COMPOUND_STRING. check inputObject %s", | |
1903 params, &num_params); | |
1904 } | |
1905 | |
1906 /* | |
1907 * normaly, converted string can be sent to client either via | |
1908 * ClientMessage event or via property. | |
1909 * the strategy used here is as follows: | |
1910 * if the string is short enough to fit in a event, | |
1911 * use ClientMessage. else, use property. | |
1912 * however in case of reset, the string must be sent via property. | |
1913 */ | |
1914 #define MAX_BYTES_IN_A_EVENT (20 - 4 - 1) | |
1915 | |
1916 if (!client->resetting && arg->length <= MAX_BYTES_IN_A_EVENT) { | |
1917 TRACE(("\tsending string via event\n")); | |
1918 sendClientMessage8(client, arg->text, arg->length); | |
1919 } else { | |
1920 TRACE(("\tsending string via property\n")); | |
1921 XChangeProperty(XtDisplay((Widget)xpw), XtWindow((Widget)xpw), | |
1922 client->property, arg->encoding, arg->format, | |
1923 PropModeAppend, (unsigned char *)arg->text, arg->length); | |
1924 /* when resetting, XIMP_READPROP event should not be sent */ | |
1925 if (!client->resetting) { | |
1926 TRACE(("\tsending XIMP_READPROP message\n")); | |
1927 sendClientMessage32(client, XIMP_READPROP, | |
1928 client->id, client->property, 0L, 0L); | |
1929 } | |
1930 } | |
1931 #undef MAX_BYTES_IN_A_EVENT | |
1932 } | |
1933 | |
1934 /*- endCallback: conversion end callback -*/ | |
1935 /* ARGSUSED */ | |
1936 static void | |
1937 endCallback(w, client_data, call_data) | |
1938 Widget w; | |
1939 XtPointer client_data; | |
1940 XtPointer call_data; | |
1941 { | |
1942 ConvClient *ccp = (ConvClient *)client_data; | |
1943 int abort = (int)call_data; | |
1944 | |
1945 TRACE(("endCallback(reqwin=0x%lx,abort=%s)\n", ccp->reqwin, abort?"True":"False")); | |
1946 endProc(ccp, abort); | |
1947 } | |
1948 | |
1949 /*- endProc: conversion end processing -*/ | |
1950 static void | |
1951 endProc(client, abort) | |
1952 ConvClient *client; | |
1953 int abort; | |
1954 { | |
1955 if (client->conversion == NULL) return; | |
1956 | |
1957 preeditDone(client); | |
1958 | |
1959 if (!abort) { | |
1960 TRACE(("\tsending XIMP_PROCESS_END message\n")); | |
1961 sendClientMessage32(client, XIMP_PROCESS_END, | |
1962 client->id, 0L, 0L, 0L); | |
1963 } | |
1964 detachConverter(client); | |
1965 } | |
1966 | |
1967 /*- unusedEventCallback: unused key event callback -*/ | |
1968 /* ARGSUSED */ | |
1969 static void | |
1970 unusedEventCallback(w, client_data, call_data) | |
1971 Widget w; | |
1972 XtPointer client_data; | |
1973 XtPointer call_data; | |
1974 { | |
1975 ConvClient *ccp = (ConvClient *)client_data; | |
1976 XKeyEvent *ev = (XKeyEvent *)call_data; | |
1977 | |
1978 TRACE(("unusedEventCallback(reqwin=0x%lx)\n", ccp->reqwin)); | |
1979 sendKeyEvent(ccp, ev); | |
1980 } | |
1981 | |
1982 /* | |
1983 *+ ClientMessage event handler | |
1984 */ | |
1985 | |
1986 /*- ximpCreateMessageProc: XIMP_CREATE message handler -*/ | |
1987 static void | |
1988 ximpCreateMessageProc(xpw, ev) | |
1989 XimpProtocolWidget xpw; | |
1990 XClientMessageEvent *ev; | |
1991 { | |
1992 Window reqwin; | |
1993 XIMStyle inputstyle; | |
1994 unsigned long attrmask; | |
1995 ConvClient *client; | |
1996 XimpInputStyle *styles = XimpStyles; | |
1997 Dimension w, h; | |
1998 | |
1999 TRACE(("ximpCreateMessageProc(window=0x%lx)\n", ev->data.l[1])); | |
2000 | |
2001 reqwin = ev->data.l[1]; | |
2002 | |
2003 /* check validity of the client window ID */ | |
2004 if (!isCorrectWindowID((Widget)xpw, reqwin, &w, &h)) { | |
2005 DPRINT(("\tspecified window doesn't exist!\n")); | |
2006 return; | |
2007 } | |
2008 | |
2009 inputstyle = ev->data.l[2]; | |
2010 | |
2011 /* check specified input style */ | |
2012 while (styles->ximstyle != inputstyle) { | |
2013 if (styles->ximstyle == 0L) { | |
2014 /* | |
2015 * client is requesting an input style which kinput2 | |
2016 * doesn't support | |
2017 */ | |
2018 DPRINT(("\tclient wants unspported input style\n")); | |
2019 sendCreateRefusal(xpw, reqwin); | |
2020 return; | |
2021 } | |
2022 styles++; | |
2023 } | |
2024 | |
2025 #ifdef DEBUG | |
2026 if (DEBUG_CONDITION) { | |
2027 printf("\tinputstyle: Preedit"); | |
2028 if (styles->ximstyle & XIMPreeditArea) printf("Area"); | |
2029 if (styles->ximstyle & XIMPreeditCallbacks) printf("Callbacks"); | |
2030 if (styles->ximstyle & XIMPreeditPosition) printf("Position"); | |
2031 if (styles->ximstyle & XIMPreeditNothing) printf("Nothing"); | |
2032 if (styles->ximstyle & XIMPreeditNone) printf("None"); | |
2033 printf(", Status"); | |
2034 if (styles->ximstyle & XIMStatusArea) printf("Area"); | |
2035 if (styles->ximstyle & XIMStatusCallbacks) printf("Callbacks"); | |
2036 if (styles->ximstyle & XIMStatusNothing) printf("Nothing"); | |
2037 if (styles->ximstyle & XIMStatusNone) printf("None"); | |
2038 printf("\n"); | |
2039 } | |
2040 #endif | |
2041 client = newClient(xpw, reqwin); | |
2042 client->reqwinwidth = w; | |
2043 client->reqwinheight = h; | |
2044 client->event = ev; | |
2045 client->style = styles->cstyle; | |
2046 client->ximstyle = styles->ximstyle; | |
2047 | |
2048 attrmask = ev->data.l[3]; | |
2049 | |
2050 getVersionProperty(client); | |
2051 | |
2052 /* get conversion attributes */ | |
2053 getAttributes(client, attrmask); | |
2054 | |
2055 /* watch for client destroy */ | |
2056 MyAddEventHandler(XtDisplay((Widget)xpw), reqwin, | |
2057 DestroyNotify, StructureNotifyMask, | |
2058 ClientDead, (XtPointer)client); | |
2059 | |
2060 TRACE(("\tsending XIMP_CREATE_RETURN message\n")); | |
2061 sendClientMessage32(client, XIMP_CREATE_RETURN, client->id, 0L, 0L, 0L); | |
2062 | |
2063 statusStart(client); | |
2064 } | |
2065 | |
2066 /*- ximpDestroyMessageProc: XIMP_DESTROY message handler -*/ | |
2067 static void | |
2068 ximpDestroyMessageProc(xpw, ev) | |
2069 XimpProtocolWidget xpw; | |
2070 XClientMessageEvent *ev; | |
2071 { | |
2072 ConvClient *client; | |
2073 int id; | |
2074 | |
2075 TRACE(("ximpDestroyMessageProc()\n")); | |
2076 | |
2077 id = ev->data.l[1]; | |
2078 if ((client = findClient(xpw, id)) == NULL) { | |
2079 DPRINT(("\tinvalid ID\n")); | |
2080 return; | |
2081 } | |
2082 client->event = ev; | |
2083 | |
2084 MyRemoveEventHandler(XtDisplay((Widget)xpw), client->reqwin, DestroyNotify, | |
2085 ClientDead, (XtPointer)client); | |
2086 | |
2087 statusDone(client); | |
2088 if (client->conversion != NULL) { | |
2089 CControlEndConversion(client->conversion); | |
2090 endProc(client, False); | |
2091 } | |
2092 deleteClient(client); | |
2093 } | |
2094 | |
2095 /*- ximpBeginMessageProc: XIMP_BEGIN message handler -*/ | |
2096 static void | |
2097 ximpBeginMessageProc(xpw, ev) | |
2098 XimpProtocolWidget xpw; | |
2099 XClientMessageEvent *ev; | |
2100 { | |
2101 ConvClient *client; | |
2102 int id; | |
2103 ConversionAttributes attrs; | |
2104 unsigned long attrmask; | |
2105 | |
2106 TRACE(("ximpBeginMessageProc()\n")); | |
2107 | |
2108 id = ev->data.l[1]; | |
2109 if ((client = findClient(xpw, id)) == NULL) { | |
2110 DPRINT(("\tinvalid ID\n")); | |
2111 return; | |
2112 } | |
2113 client->event = ev; | |
2114 if (client->conversion != NULL) { | |
2115 /* already converting */ | |
2116 DPRINT(("\tclient already in conversion mode\n")); | |
2117 /* should we send XIMP_BadProtocol error event? */ | |
2118 return; | |
2119 } | |
2120 | |
2121 if (attachConverter(client) == NULL) { | |
2122 /* | |
2123 * since no appropriate error code is defined, | |
2124 * use BadAlloc... | |
2125 */ | |
2126 sendErrorEvent(client, XIMP_BadAlloc); | |
2127 /* | |
2128 * to let the client select key events again, | |
2129 * send XIMP_PROCESS_END message. | |
2130 */ | |
2131 sendClientMessage32(client, XIMP_PROCESS_END, | |
2132 client->id, 0L, 0L, 0L); | |
2133 return; | |
2134 } | |
2135 | |
2136 XtAddCallback(client->conversion, XtNtextCallback, | |
2137 fixCallback, (XtPointer)client); | |
2138 XtAddCallback(client->conversion, XtNendCallback, | |
2139 endCallback, (XtPointer)client); | |
2140 XtAddCallback(client->conversion, XtNunusedEventCallback, | |
2141 unusedEventCallback, (XtPointer)client); | |
2142 if (client->style == onthespot_style) { | |
2143 XtAddCallback(client->conversion, XtNpreeditStartCallback, | |
2144 preeditStartCallback, (XtPointer)client); | |
2145 XtAddCallback(client->conversion, XtNpreeditDoneCallback, | |
2146 preeditDoneCallback, (XtPointer)client); | |
2147 XtAddCallback(client->conversion, XtNpreeditDrawCallback, | |
2148 preeditDrawCallback, (XtPointer)client); | |
2149 XtAddCallback(client->conversion, XtNpreeditCaretCallback, | |
2150 preeditCaretCallback, (XtPointer)client); | |
2151 XtAddCallback(client->conversion, XtNstatusStartCallback, | |
2152 statusStartCallback, (XtPointer)client); | |
2153 XtAddCallback(client->conversion, XtNstatusDoneCallback, | |
2154 statusDoneCallback, (XtPointer)client); | |
2155 XtAddCallback(client->conversion, XtNstatusDrawCallback, | |
2156 statusDrawCallback, (XtPointer)client); | |
2157 } | |
2158 | |
2159 fillInDefaultAttributes(client); | |
2160 computeAreaForStartup(client); | |
2161 attrmask = makeConvAttributes(client, &attrs); | |
2162 | |
2163 /* start conversion */ | |
2164 XtVaSetValues(client->conversion, XtNeventSelectMethod, client->esm, NULL); | |
2165 CControlStartConversion(client->conversion, client->reqwin, | |
2166 attrmask, &attrs); | |
2167 | |
2168 TRACE(("\tsending XIMP_PROCESS_BEGIN message\n")); | |
2169 sendClientMessage32(client, XIMP_PROCESS_BEGIN, client->id, 0L, 0L, 0L); | |
2170 | |
2171 preeditStart(client); | |
2172 } | |
2173 | |
2174 /*- ximpEndMessageProc: XIMP_END message handler -*/ | |
2175 static void | |
2176 ximpEndMessageProc(xpw, ev) | |
2177 XimpProtocolWidget xpw; | |
2178 XClientMessageEvent *ev; | |
2179 { | |
2180 ConvClient *client; | |
2181 int id; | |
2182 | |
2183 TRACE(("ximpEndMessageProc()\n")); | |
2184 | |
2185 id = ev->data.l[1]; | |
2186 if ((client = findClient(xpw, id)) == NULL) { | |
2187 DPRINT(("\tinvalid ID\n")); | |
2188 return; | |
2189 } | |
2190 client->event = ev; | |
2191 if (client->conversion == NULL) { | |
2192 /* not converting now */ | |
2193 DPRINT(("\tclient isn't in conversion mode\n")); | |
2194 /* should we send XIMP_BadProtocol error event? */ | |
2195 return; | |
2196 } | |
2197 | |
2198 CControlEndConversion(client->conversion); | |
2199 endProc(client, False); | |
2200 } | |
2201 | |
2202 /*- ximpSetFocusMessageProc: XIMP_SETFOCUS message handler -*/ | |
2203 static void | |
2204 ximpSetFocusMessageProc(xpw, ev) | |
2205 XimpProtocolWidget xpw; | |
2206 XClientMessageEvent *ev; | |
2207 { | |
2208 ConvClient *client; | |
2209 int id; | |
2210 | |
2211 TRACE(("ximpSetFocusMessageProc()\n")); | |
2212 | |
2213 id = ev->data.l[1]; | |
2214 if ((client = findClient(xpw, id)) == NULL) { | |
2215 DPRINT(("\tinvalid ID\n")); | |
2216 return; | |
2217 } | |
2218 client->event = ev; | |
2219 /* what to do? */ | |
2220 | |
2221 statusStart(client); | |
2222 if (client->conversion != NULL) { | |
2223 CControlChangeFocus(client->conversion, 1); | |
2224 } | |
2225 } | |
2226 | |
2227 /*- ximpUnsetFocusMessageProc: XIMP_UNSETFOCUS message handler -*/ | |
2228 static void | |
2229 ximpUnsetFocusMessageProc(xpw, ev) | |
2230 XimpProtocolWidget xpw; | |
2231 XClientMessageEvent *ev; | |
2232 { | |
2233 ConvClient *client; | |
2234 int id; | |
2235 | |
2236 TRACE(("ximpUnsetFocusMessageProc()\n")); | |
2237 | |
2238 id = ev->data.l[1]; | |
2239 if ((client = findClient(xpw, id)) == NULL) { | |
2240 DPRINT(("\tinvalid ID\n")); | |
2241 return; | |
2242 } | |
2243 client->event = ev; | |
2244 /* what to do? */ | |
2245 | |
2246 if (client->conversion != NULL) { | |
2247 CControlChangeFocus(client->conversion, 0); | |
2248 } | |
2249 statusDone(client); | |
2250 } | |
2251 | |
2252 /*- ximpMoveMessageProc: XIMP_MOVE message handler -*/ | |
2253 static void | |
2254 ximpMoveMessageProc(xpw, ev) | |
2255 XimpProtocolWidget xpw; | |
2256 XClientMessageEvent *ev; | |
2257 { | |
2258 ConvClient *client; | |
2259 int id; | |
2260 ConversionAttributes attrs; | |
2261 | |
2262 TRACE(("ximpMoveMessageProc()\n")); | |
2263 | |
2264 id = ev->data.l[1]; | |
2265 if ((client = findClient(xpw, id)) == NULL) { | |
2266 DPRINT(("\tinvalid ID\n")); | |
2267 return; | |
2268 } | |
2269 client->event = ev; | |
2270 client->xpattrs.spotx = ev->data.l[2]; | |
2271 client->xpattrs.spoty = ev->data.l[3]; | |
2272 client->xattrmask |= XIMP_PRE_SPOTL_MASK; | |
2273 if (client->conversion != NULL) { | |
2274 attrs.spotx = client->xpattrs.spotx; | |
2275 attrs.spoty = client->xpattrs.spoty; | |
2276 CControlChangeAttributes(client->conversion, CASpotLocation, &attrs); | |
2277 } | |
2278 } | |
2279 | |
2280 /*- ximpResetMessageProc: XIMP_RESET message handler -*/ | |
2281 static void | |
2282 ximpResetMessageProc(xpw, ev) | |
2283 XimpProtocolWidget xpw; | |
2284 XClientMessageEvent *ev; | |
2285 { | |
2286 ConvClient *client; | |
2287 int id; | |
2288 Widget inputobj; | |
2289 | |
2290 TRACE(("ximpResetMessageProc()\n")); | |
2291 | |
2292 id = ev->data.l[1]; | |
2293 if ((client = findClient(xpw, id)) == NULL) { | |
2294 DPRINT(("\tinvalid ID\n")); | |
2295 return; | |
2296 } | |
2297 client->event = ev; | |
2298 client->resetting = True; | |
2299 | |
2300 if (client->conversion == NULL) { | |
2301 XChangeProperty(XtDisplay((Widget)xpw), XtWindow((Widget)xpw), | |
2302 client->property, xpw->ximp.ctextAtom, 8, | |
2303 PropModeAppend, (unsigned char *)"", 0); | |
2304 } else { | |
2305 /* | |
2306 * get input object by asking conversion widget of XtNinputObject | |
2307 * resource. however, it is not recommended since protocol widget | |
2308 * should interact with input object only through conversion | |
2309 * widget. | |
2310 */ | |
2311 CCTextCallbackArg arg; | |
2312 | |
2313 XtVaGetValues(client->conversion, XtNinputObject, &inputobj, NULL); | |
2314 arg.encoding = xpw->ximp.ctextAtom; | |
2315 if (ICGetConvertedString(inputobj, &arg.encoding, &arg.format, | |
2316 &arg.length, &arg.text) >= 0) { | |
2317 fixProc(client, &arg); | |
2318 } else { | |
2319 /* there's no string */ | |
2320 XChangeProperty(XtDisplay((Widget)xpw), XtWindow((Widget)xpw), | |
2321 client->property, xpw->ximp.ctextAtom, 8, | |
2322 PropModeAppend, (unsigned char *)"", 0); | |
2323 } | |
2324 ICClearConversion(inputobj); | |
2325 } | |
2326 | |
2327 TRACE(("\tsending XIMP_RESET_RETURN message\n")); | |
2328 sendClientMessage32(client, XIMP_RESET_RETURN, client->id, | |
2329 client->property, 0L, 0L); | |
2330 } | |
2331 | |
2332 /*- ximpSetValueMessageProc: XIMP_SETVALUE message handler -*/ | |
2333 static void | |
2334 ximpSetValueMessageProc(xpw, ev) | |
2335 XimpProtocolWidget xpw; | |
2336 XClientMessageEvent *ev; | |
2337 { | |
2338 ConvClient *client; | |
2339 unsigned long mask; | |
2340 ConversionAttributes attrs; | |
2341 unsigned long attrmask; | |
2342 int id; | |
2343 | |
2344 TRACE(("ximpSetValueMessageProc()\n")); | |
2345 | |
2346 id = ev->data.l[1]; | |
2347 if ((client = findClient(xpw, id)) == NULL) { | |
2348 DPRINT(("\tinvalid ID\n")); | |
2349 return; | |
2350 } | |
2351 mask = ev->data.l[2]; | |
2352 client->event = ev; | |
2353 getAttributes(client, mask); | |
2354 if (client->conversion != NULL) { | |
2355 attrmask = makeConvAttributes(client, &attrs); | |
2356 CControlChangeAttributes(client->conversion, attrmask, &attrs); | |
2357 } | |
2358 } | |
2359 | |
2360 /*- ximpChangeMessageProc: XIMP_CHANGE message handler -*/ | |
2361 static void | |
2362 ximpChangeMessageProc(xpw, ev) | |
2363 XimpProtocolWidget xpw; | |
2364 XClientMessageEvent *ev; | |
2365 { | |
2366 ConvClient *client; | |
2367 Atom atom; | |
2368 unsigned long mask; | |
2369 ConversionAttributes attrs; | |
2370 unsigned long attrmask; | |
2371 int id; | |
2372 | |
2373 TRACE(("ximpChangeMessageProc()\n")); | |
2374 | |
2375 id = ev->data.l[1]; | |
2376 if ((client = findClient(xpw, id)) == NULL) { | |
2377 DPRINT(("\tinvalid ID\n")); | |
2378 return; | |
2379 } | |
2380 atom = (Atom)ev->data.l[2]; | |
2381 | |
2382 if (atom == xpw->ximp.ximpFocusAtom) { | |
2383 mask = XIMP_FOCUS_WIN_MASK; | |
2384 } else if (atom == xpw->ximp.ximpPreeditAtom) { | |
2385 mask = PREEDIT_MASK; | |
2386 } else if (atom == xpw->ximp.ximpStatusAtom) { | |
2387 mask = STATUS_MASK; | |
2388 } else if (atom == xpw->ximp.ximpPreeditFontAtom) { | |
2389 mask = XIMP_PRE_FONT_MASK; | |
2390 } else if (atom == xpw->ximp.ximpStatusFontAtom) { | |
2391 mask = XIMP_STS_FONT_MASK; | |
2392 } else { | |
2393 /* invalid property name */ | |
2394 sendErrorEvent(client, XIMP_BadProperty); | |
2395 return; | |
2396 } | |
2397 | |
2398 client->event = ev; | |
2399 getAttributes(client, mask); | |
2400 if (client->conversion != NULL) { | |
2401 attrmask = makeConvAttributes(client, &attrs); | |
2402 CControlChangeAttributes(client->conversion, attrmask, &attrs); | |
2403 } | |
2404 } | |
2405 | |
2406 /*- ximpGetValueMessageProc: XIMP_GETVALUE message handler -*/ | |
2407 static void | |
2408 ximpGetValueMessageProc(xpw, ev) | |
2409 XimpProtocolWidget xpw; | |
2410 XClientMessageEvent *ev; | |
2411 { | |
2412 ConvClient *client; | |
2413 unsigned long mask; | |
2414 int id; | |
2415 | |
2416 TRACE(("ximpGetValueMessageProc()\n")); | |
2417 | |
2418 id = ev->data.l[1]; | |
2419 if ((client = findClient(xpw, id)) == NULL) { | |
2420 DPRINT(("\tinvalid ID\n")); | |
2421 return; | |
2422 } | |
2423 mask = ev->data.l[2]; | |
2424 client->event = ev; | |
2425 | |
2426 fillInDefaultAttributes(client); | |
2427 computeAreaForQuery(client); | |
2428 setAttributes(client, mask); | |
2429 | |
2430 TRACE(("\tsending XIMP_GETVALUE_RETURN message\n")); | |
2431 sendClientMessage32(client, XIMP_GETVALUE_RETURN, client->id, 0L, 0L, 0L); | |
2432 } | |
2433 | |
2434 /*- ximpKeyPressMessageProc: XIMP_KEYPRESS message handler -*/ | |
2435 static void | |
2436 ximpKeyPressMessageProc(xpw, ev) | |
2437 XimpProtocolWidget xpw; | |
2438 XClientMessageEvent *ev; | |
2439 { | |
2440 ConvClient *client; | |
2441 int id; | |
2442 XKeyEvent keyevent; | |
2443 | |
2444 TRACE(("ximpKeyPressMessageProc()\n")); | |
2445 | |
2446 id = ev->data.l[1]; | |
2447 if ((client = findClient(xpw, id)) == NULL) { | |
2448 DPRINT(("\tinvalid ID\n")); | |
2449 return; | |
2450 } | |
2451 client->event = ev; | |
2452 | |
2453 if (client->conversion == NULL) return; | |
2454 | |
2455 /* make a fake keypress event */ | |
2456 keyevent.type = KeyPress; | |
2457 keyevent.serial = ev->serial; | |
2458 keyevent.send_event = True; | |
2459 keyevent.display = ev->display; | |
2460 keyevent.window = client->focuswin; | |
2461 keyevent.root = DefaultRootWindow(ev->display); | |
2462 /* hope conversion object won't check this field */ | |
2463 keyevent.subwindow = None; | |
2464 /* hope conversion object won't check this field */ | |
2465 keyevent.time = 0; /* hope conversion object won't check this field */ | |
2466 keyevent.x = 0; | |
2467 keyevent.y = 0; | |
2468 keyevent.x_root = 0; | |
2469 keyevent.y_root = 0; | |
2470 keyevent.state = ev->data.l[3]; | |
2471 keyevent.keycode = ev->data.l[2]; | |
2472 keyevent.same_screen = True; | |
2473 | |
2474 /* call action routine */ | |
2475 XtCallActionProc(client->conversion, "to-inputobj", (XEvent *)&keyevent, | |
2476 (String *)NULL, (Cardinal)0); | |
2477 } | |
2478 | |
2479 /*- ximpExtensionMessageProc: XIMP_Extension message handler -*/ | |
2480 static void | |
2481 ximpExtensionMessageProc(xpw, ev) | |
2482 XimpProtocolWidget xpw; | |
2483 XClientMessageEvent *ev; | |
2484 { | |
2485 ConvClient *client; | |
2486 Atom extatom; | |
2487 int id; | |
2488 | |
2489 TRACE(("ximpExtensionMessageProc()\n")); | |
2490 | |
2491 id = ev->data.l[1]; | |
2492 if ((client = findClient(xpw, id)) == NULL) { | |
2493 DPRINT(("\tinvalid ID\n")); | |
2494 return; | |
2495 } | |
2496 extatom = ev->data.l[2]; /* extension name */ | |
2497 client->event = ev; | |
2498 | |
2499 if (extatom == xpw->ximp.ximpExtXimpBackFrontAtom) { | |
2500 TRACE(("\t_XIMP_EXT_XIMP_BACK_FRONT extension -- ")); | |
2501 if (client->conversion != NULL) { | |
2502 /* invalid */ | |
2503 DPRINT(("invalid (now in conversion mode)\n")); | |
2504 return; | |
2505 } | |
2506 if (ev->data.l[3] != 0) { | |
2507 /* backend method */ | |
2508 TRACE(("backend\n")); | |
2509 client->esm = ESMethodNone; | |
2510 } else { | |
2511 TRACE(("frontend\n")); | |
2512 client->esm = ESMethodSelectFocus; | |
2513 } | |
2514 } else { | |
2515 DPRINT(("\tunknown extension atom -- %ld", extatom)); | |
2516 sendErrorEvent(client, XIMP_BadAtom); | |
2517 } | |
2518 } | |
2519 | |
2520 /*- XimpMessageProc: _XIMP_PROTOCOL message event handler -*/ | |
2521 /* ARGSUSED */ | |
2522 static void | |
2523 XimpMessageProc(w, event, args, num_args) | |
2524 Widget w; | |
2525 XEvent *event; | |
2526 String *args; | |
2527 Cardinal *num_args; | |
2528 { | |
2529 XimpProtocolWidget xpw = (XimpProtocolWidget)w; | |
2530 XClientMessageEvent *ev = &event->xclient; | |
2531 ConvClient *client; | |
2532 | |
2533 TRACE(("XimpMessageProc()\n")); | |
2534 /* is it a correct event? */ | |
2535 if (!isCorrectClientEvent(xpw, event)) { | |
2536 /*ignore */ | |
2537 DPRINT(("got invalid clientmessage event.\n")); | |
2538 return; | |
2539 } | |
2540 switch((int)ev->data.l[0]) { | |
2541 case XIMP_CREATE: ximpCreateMessageProc(xpw, ev); break; | |
2542 case XIMP_DESTROY: ximpDestroyMessageProc(xpw, ev); break; | |
2543 case XIMP_BEGIN: ximpBeginMessageProc(xpw, ev); break; | |
2544 case XIMP_END: ximpEndMessageProc(xpw, ev); break; | |
2545 case XIMP_SETFOCUS: ximpSetFocusMessageProc(xpw, ev); break; | |
2546 case XIMP_UNSETFOCUS: ximpUnsetFocusMessageProc(xpw, ev); break; | |
2547 case XIMP_KEYPRESS: ximpKeyPressMessageProc(xpw, ev); break; | |
2548 case XIMP_SETVALUE: ximpSetValueMessageProc(xpw, ev); break; | |
2549 case XIMP_CHANGE: ximpChangeMessageProc(xpw, ev); break; | |
2550 case XIMP_GETVALUE: ximpGetValueMessageProc(xpw, ev); break; | |
2551 case XIMP_MOVE: ximpMoveMessageProc(xpw, ev); break; | |
2552 case XIMP_RESET: ximpResetMessageProc(xpw, ev); break; | |
2553 case XIMP_EXTENSION: ximpExtensionMessageProc(xpw, ev); break; | |
2554 case XIMP_PREEDITSTART_RETURN: break; | |
2555 case XIMP_PREEDITCARET_RETURN: break; | |
2556 default: | |
2557 DPRINT(("\tunknown command code (%ld) ignored\n", ev->data.l[0])); | |
2558 /* assume ev->data.l[1] contains ICID */ | |
2559 if ((client = findClient(xpw, (int)ev->data.l[1])) != NULL) { | |
2560 client->event = ev; | |
2561 sendErrorEvent(client, XIMP_BadProtocol); | |
2562 } | |
2563 break; | |
2564 } | |
2565 } | |
2566 | |
2567 /* | |
2568 *+ other event handler | |
2569 */ | |
2570 | |
2571 /*- SelectionRequestProc: SelectionRequest event handler -*/ | |
2572 /*ARGSUSED*/ | |
2573 static void | |
2574 SelectionRequestProc(w, event, args, num_args) | |
2575 Widget w; | |
2576 XEvent *event; | |
2577 String *args; /* not used */ | |
2578 Cardinal *num_args; /* not used */ | |
2579 { | |
2580 XSelectionRequestEvent *ev = &(event->xselectionrequest); | |
2581 XEvent repl; | |
2582 String params[1]; | |
2583 Cardinal num_params; | |
2584 | |
2585 repl.xselection.type = SelectionNotify; | |
2586 repl.xselection.requestor = ev->requestor; | |
2587 repl.xselection.selection = ev->selection; | |
2588 repl.xselection.target = ev->target; | |
2589 repl.xselection.property = None; | |
2590 repl.xselection.time = ev->time; | |
2591 | |
2592 params[0] = XtClass(w)->core_class.class_name; | |
2593 num_params = 1; | |
2594 XtAppWarningMsg(XtWidgetToApplicationContext(w), | |
2595 "selectionError", "SelectionRequest", "WidgetError", | |
2596 "%s: SelectionRequest event received", | |
2597 params, &num_params); | |
2598 | |
2599 XSendEvent(ev->display, ev->requestor, False, NoEventMask, &repl); | |
2600 } | |
2601 | |
2602 /*- SelectionClearProc: SelectionClear event handler -*/ | |
2603 /* ARGSUSED */ | |
2604 static void | |
2605 SelectionClearProc(w, event, args, num_args) | |
2606 Widget w; | |
2607 XEvent *event; | |
2608 String *args; | |
2609 Cardinal *num_args; | |
2610 { | |
2611 XimpProtocolWidget xpw = (XimpProtocolWidget)w; | |
2612 XSelectionClearEvent *ev = (XSelectionClearEvent *)event; | |
2613 ConvClient *ccp; | |
2614 String params[1]; | |
2615 Cardinal num_params; | |
2616 | |
2617 /* Selection owner changed */ | |
2618 | |
2619 if (ev->selection == xpw->ximp.selAtom1) { | |
2620 /* someone has become a new default server */ | |
2621 xpw->ximp.selAtom1 = None; | |
2622 return; | |
2623 } else if (ev->selection != xpw->ximp.selAtom2) { | |
2624 TRACE(("XimpProtocol:SelectionClearProc() SelectionClear event for unknown selection received\n")); | |
2625 return; | |
2626 } | |
2627 | |
2628 /* | |
2629 * send ConversionEnd event to the clients before exit | |
2630 */ | |
2631 for (ccp = xpw->ximp.clients; ccp; ccp = ccp->next) { | |
2632 if (ccp->reqwin != None) { | |
2633 statusDone(ccp); | |
2634 endProc(ccp, False); | |
2635 } | |
2636 } | |
2637 | |
2638 params[0] = XtClass(w)->core_class.class_name; | |
2639 num_params = 1; | |
2640 XtAppWarningMsg(XtWidgetToApplicationContext(w), | |
2641 "selectionError", "SelectionClear", "WidgetError", | |
2642 "%s: SelectionClear event received", | |
2643 params, &num_params); | |
2644 | |
2645 XtDestroyWidget(w); | |
2646 } | |
2647 | |
2648 /*- ClientDead: DestroyNotify event handler -*/ | |
2649 static void | |
2650 ClientDead(ev, data) | |
2651 XEvent *ev; | |
2652 XtPointer data; | |
2653 { | |
2654 ConvClient *ccp = (ConvClient *)data; | |
2655 | |
2656 TRACE(("ClientDead(window=0x%lx)\n", ev->xdestroywindow.window)); | |
2657 if (ev->type != DestroyNotify || | |
2658 ev->xdestroywindow.window != ccp->reqwin) return; | |
2659 | |
2660 MyRemoveAllEventHandler(ev->xany.display, ccp->reqwin); | |
2661 deleteClient(ccp); | |
2662 } | |
2663 | |
2664 /* | |
2665 *+ on-the-spot callback procedures | |
2666 */ | |
2667 | |
2668 /*- preeditStartCallback: preedit start -*/ | |
2669 /* ARGSUSED */ | |
2670 static void | |
2671 preeditStartCallback(w, client_data, call_data) | |
2672 Widget w; | |
2673 XtPointer client_data; | |
2674 XtPointer call_data; | |
2675 { | |
2676 ConvClient *ccp = (ConvClient *)client_data; | |
2677 TRACE(("preeditStartCallback(reqwin=0x%lx)\n", ccp->reqwin)); | |
2678 preeditStart(ccp); | |
2679 } | |
2680 | |
2681 /*- preeditDoneCallback: preedit done -*/ | |
2682 /* ARGSUSED */ | |
2683 static void | |
2684 preeditDoneCallback(w, client_data, call_data) | |
2685 Widget w; | |
2686 XtPointer client_data; | |
2687 XtPointer call_data; | |
2688 { | |
2689 ConvClient *ccp = (ConvClient *)client_data; | |
2690 TRACE(("preeditDoneCallback(reqwin=0x%lx)\n", ccp->reqwin)); | |
2691 preeditDone(ccp); | |
2692 } | |
2693 | |
2694 /*- preeditDrawCallback: preedit draw -*/ | |
2695 /* ARGSUSED */ | |
2696 static void | |
2697 preeditDrawCallback(w, client_data, call_data) | |
2698 Widget w; | |
2699 XtPointer client_data; | |
2700 XtPointer call_data; | |
2701 { | |
2702 ConvClient *ccp = (ConvClient *)client_data; | |
2703 OCCPreeditDrawArg *arg = (OCCPreeditDrawArg *)call_data; | |
2704 TRACE(("preeditDrawCallback(reqwin=0x%lx, length=%d)\n", ccp->reqwin, arg->text_length)); | |
2705 preeditDraw(ccp, arg); | |
2706 } | |
2707 | |
2708 /*- preeditCaretCallback: preedit caret -*/ | |
2709 /* ARGSUSED */ | |
2710 static void | |
2711 preeditCaretCallback(w, client_data, call_data) | |
2712 Widget w; | |
2713 XtPointer client_data; | |
2714 XtPointer call_data; | |
2715 { | |
2716 ConvClient *ccp = (ConvClient *)client_data; | |
2717 int caret = (int)call_data; | |
2718 TRACE(("preeditCaretCallback(reqwin=0x%lx, caret=%d)\n",ccp->reqwin,caret)); | |
2719 preeditCaret(ccp, caret); | |
2720 } | |
2721 | |
2722 /*- statusStartCallback: status start -*/ | |
2723 /* ARGSUSED */ | |
2724 static void | |
2725 statusStartCallback(w, client_data, call_data) | |
2726 Widget w; | |
2727 XtPointer client_data; | |
2728 XtPointer call_data; | |
2729 { | |
2730 ConvClient *ccp = (ConvClient *)client_data; | |
2731 TRACE(("statusStartCallback(reqwin=0x%lx)\n", ccp->reqwin)); | |
2732 statusStart(ccp); | |
2733 } | |
2734 | |
2735 /*- statusDoneCallback: status done -*/ | |
2736 /* ARGSUSED */ | |
2737 static void | |
2738 statusDoneCallback(w, client_data, call_data) | |
2739 Widget w; | |
2740 XtPointer client_data; | |
2741 XtPointer call_data; | |
2742 { | |
2743 ConvClient *ccp = (ConvClient *)client_data; | |
2744 TRACE(("statusDoneCallback(reqwin=0x%lx)\n", ccp->reqwin)); | |
2745 statusDone(ccp); | |
2746 } | |
2747 | |
2748 /*- statusDrawCallback: status draw -*/ | |
2749 /* ARGSUSED */ | |
2750 static void | |
2751 statusDrawCallback(w, client_data, call_data) | |
2752 Widget w; | |
2753 XtPointer client_data; | |
2754 XtPointer call_data; | |
2755 { | |
2756 ConvClient *ccp = (ConvClient *)client_data; | |
2757 OCCPreeditDrawArg *arg = (OCCPreeditDrawArg *)call_data; | |
2758 TRACE(("statusDrawCallback(reqwin=0x%lx, length=%d)\n", ccp->reqwin, arg->text_length)); | |
2759 statusDraw(ccp, arg); | |
2760 } | |
2761 | |
2762 /*- preeditStart: do preedit start -*/ | |
2763 static void | |
2764 preeditStart(client) | |
2765 ConvClient *client; | |
2766 { | |
2767 TRACE(("preeditStart(reqwin=0x%lx)\n", client->reqwin)); | |
2768 if (!(client->ximstyle & XIMPreeditCallbacks)) | |
2769 return; | |
2770 if (!client->in_preedit) { | |
2771 TRACE(("\tsending XIMP_PREEDITSTART message\n")); | |
2772 sendClientMessage32(client, XIMP_PREEDITSTART, client->id, 0L, 0L, 0L); | |
2773 client->in_preedit = True; | |
2774 } | |
2775 } | |
2776 | |
2777 /*- preeditDone: do preedit done -*/ | |
2778 static void | |
2779 preeditDone(client) | |
2780 ConvClient *client; | |
2781 { | |
2782 TRACE(("preeditDone(reqwin=0x%lx)\n", client->reqwin)); | |
2783 if (!(client->ximstyle & XIMPreeditCallbacks)) | |
2784 return; | |
2785 if (client->in_preedit) { | |
2786 TRACE(("\tsending XIMP_PREEDITDONE message\n")); | |
2787 sendClientMessage32(client, XIMP_PREEDITDONE, client->id, 0L, 0L, 0L); | |
2788 client->in_preedit = False; | |
2789 } | |
2790 } | |
2791 | |
2792 /*- preeditDraw: do actual preedit draw -*/ | |
2793 static void | |
2794 preeditDraw(client, data) | |
2795 ConvClient *client; | |
2796 OCCPreeditDrawArg *data; | |
2797 { | |
2798 XimpProtocolWidget xpw = (XimpProtocolWidget)client->protocolwidget; | |
2799 Display *xd = XtDisplay((Widget)xpw); | |
2800 Window xw = XtWindow((Widget)xpw); | |
2801 unsigned long *feedbacks; | |
2802 Boolean allsamefb; | |
2803 int i; | |
2804 | |
2805 if (!(client->ximstyle & XIMPreeditCallbacks)) | |
2806 return; | |
2807 | |
2808 preeditStart(client); | |
2809 | |
2810 /* check encoding and format */ | |
2811 if (data->encoding != xpw->ximp.ctextAtom || data->format != 8) { | |
2812 /* | |
2813 * since every conversion object must support COMPOUND_TEXT, | |
2814 * it is a serious error. | |
2815 */ | |
2816 String params[2]; | |
2817 Cardinal num_params; | |
2818 | |
2819 params[0] = XtClass((Widget)xpw)->core_class.class_name; | |
2820 params[1] = xpw->ximp.inputObjClass->core_class.class_name; | |
2821 num_params = 2; | |
2822 | |
2823 XtAppErrorMsg(XtWidgetToApplicationContext(client->protocolwidget), | |
2824 "encodingError", "preeditString", "WidgetError", | |
2825 "%s: encoding of the preedit string is not COMPOUND_STRING. check inputObject %s", | |
2826 params, &num_params); | |
2827 } | |
2828 | |
2829 feedbacks = data->attrs; | |
2830 allsamefb = True; | |
2831 if (data->attrs_length > 0) { | |
2832 unsigned long check = data->attrs[0]; | |
2833 for (i = 0; i < data->attrs_length; i++) { | |
2834 if (feedbacks[i] != check) allsamefb = False; | |
2835 } | |
2836 } | |
2837 | |
2838 #define MAX_BYTES_IN_A_EVENT (20 - 4 - 1) | |
2839 if (data->text_length <= MAX_BYTES_IN_A_EVENT) { | |
2840 if (!allsamefb) { | |
2841 TRACE(("\tsending feedbacks via property\n")); | |
2842 XChangeProperty(xd, xw, client->preeditfeedback, | |
2843 xpw->ximp.ximpFeedbacksAtom, 32, PropModeAppend, | |
2844 (unsigned char *)feedbacks, data->attrs_length); | |
2845 } | |
2846 if (!client->resetting) { | |
2847 unsigned long fb = (data->attrs_length > 0 ? feedbacks[0] : 0); | |
2848 int status = 0; | |
2849 | |
2850 if (data->text_length == 0) | |
2851 status |= 0x1; /* no_text */ | |
2852 if (data->attrs_length == 0) | |
2853 status |= 0x2; /* no_feedback */ | |
2854 if (!allsamefb) | |
2855 status |= 0x4; /* feedbacks_via_property */ | |
2856 | |
2857 TRACE(("\tsending XIMP_PREEDITDRAW_CM message\n")); | |
2858 sendClientMessage32( | |
2859 client, XIMP_PREEDITDRAW_CM, client->id, | |
2860 (status << 16) | (data->caret & 0xffff), | |
2861 (data->chg_first << 16) | (data->chg_length & 0xffff), | |
2862 (allsamefb ? fb : client->preeditfeedback)); | |
2863 | |
2864 if (data->text_length > 0) { | |
2865 TRACE(("\tsending string via event\n")); | |
2866 sendClientMessage8(client, data->text, data->text_length); | |
2867 } | |
2868 } | |
2869 } | |
2870 else { | |
2871 long atoms[3]; | |
2872 atoms[0] = data->caret; | |
2873 atoms[1] = data->chg_first; | |
2874 atoms[2] = data->chg_length; | |
2875 TRACE(("\tsending preedit data via property\n")); | |
2876 XChangeProperty(xd, xw, client->preeditdata, | |
2877 xpw->ximp.ximpPreeditDrawDataAtom, 32, PropModeAppend, | |
2878 (unsigned char *)atoms, 3); | |
2879 TRACE(("\tsending string via property\n")); | |
2880 XChangeProperty(xd, xw, client->preedittext, | |
2881 data->encoding, data->format, PropModeAppend, | |
2882 (unsigned char *)data->text, data->text_length); | |
2883 TRACE(("\tsending feedbacks via property\n")); | |
2884 XChangeProperty(xd, xw, client->preeditfeedback, | |
2885 xpw->ximp.ximpFeedbacksAtom, 32, PropModeAppend, | |
2886 (unsigned char *)feedbacks, data->attrs_length); | |
2887 if (!client->resetting) { | |
2888 TRACE(("\tsending XIMP_PREEDITDRAW message\n")); | |
2889 sendClientMessage32(client, XIMP_PREEDITDRAW, client->id, | |
2890 client->preeditdata, client->preedittext, | |
2891 client->preeditfeedback); | |
2892 } | |
2893 } | |
2894 #undef MAX_BYTES_IN_A_EVENT | |
2895 } | |
2896 | |
2897 /*- preeditCaret: do actual preedit caret -*/ | |
2898 static void | |
2899 preeditCaret(client, caret) | |
2900 ConvClient *client; | |
2901 int caret; | |
2902 { | |
2903 XimpProtocolWidget xpw = (XimpProtocolWidget)client->protocolwidget; | |
2904 | |
2905 TRACE(("\tsending XIMP_PREEDITCARET message\n")); | |
2906 if (!(client->ximstyle & XIMPreeditCallbacks)) | |
2907 return; | |
2908 sendClientMessage32(client, XIMP_PREEDITCARET, client->id, | |
2909 caret, (long)XIMAbsolutePosition, (long)XIMPrimary); | |
2910 } | |
2911 | |
2912 /*- statusStart: do status start -*/ | |
2913 static void | |
2914 statusStart(client) | |
2915 ConvClient *client; | |
2916 { | |
2917 TRACE(("statusStart(reqwin=0x%lx)\n", client->reqwin)); | |
2918 if (!(client->ximstyle & XIMStatusCallbacks)) | |
2919 return; | |
2920 if (!client->in_status) { | |
2921 TRACE(("\tsending XIMP_STATUSSTART message\n")); | |
2922 sendClientMessage32(client, XIMP_STATUSSTART, client->id, 0L, 0L, 0L); | |
2923 client->in_status = True; | |
2924 } | |
2925 } | |
2926 | |
2927 /*- statusDone: do status done -*/ | |
2928 static void | |
2929 statusDone(client) | |
2930 ConvClient *client; | |
2931 { | |
2932 TRACE(("statusDone(reqwin=0x%lx)\n", client->reqwin)); | |
2933 if (!(client->ximstyle & XIMStatusCallbacks)) | |
2934 return; | |
2935 if (client->in_status) { | |
2936 TRACE(("\tsending XIMP_STATUSDONE message\n")); | |
2937 sendClientMessage32(client, XIMP_STATUSDONE, client->id, 0L, 0L, 0L); | |
2938 client->in_status = False; | |
2939 } | |
2940 } | |
2941 | |
2942 /*- statusDraw: do actual status draw -*/ | |
2943 static void | |
2944 statusDraw(client, data) | |
2945 ConvClient *client; | |
2946 OCCPreeditDrawArg *data; | |
2947 { | |
2948 XimpProtocolWidget xpw = (XimpProtocolWidget)client->protocolwidget; | |
2949 Display *xd = XtDisplay((Widget)xpw); | |
2950 Window xw = XtWindow((Widget)xpw); | |
2951 int type = 0; /* text type */ | |
2952 | |
2953 if (!(client->ximstyle & XIMStatusCallbacks)) | |
2954 return; | |
2955 | |
2956 statusStart(client); | |
2957 | |
2958 /* check encoding and format */ | |
2959 if (data->encoding != xpw->ximp.ctextAtom || data->format != 8) { | |
2960 /* | |
2961 * since every conversion object must support COMPOUND_TEXT, | |
2962 * it is a serious error. | |
2963 */ | |
2964 String params[2]; | |
2965 Cardinal num_params; | |
2966 | |
2967 params[0] = XtClass((Widget)xpw)->core_class.class_name; | |
2968 params[1] = xpw->ximp.inputObjClass->core_class.class_name; | |
2969 num_params = 2; | |
2970 | |
2971 XtAppErrorMsg(XtWidgetToApplicationContext(client->protocolwidget), | |
2972 "encodingError", "statusString", "WidgetError", | |
2973 "%s: encoding of the status string is not COMPOUND_STRING. check inputObject %s", | |
2974 params, &num_params); | |
2975 } | |
2976 | |
2977 #define MAX_BYTES_IN_A_EVENT (20 - 4 - 1) | |
2978 if (data->text_length <= MAX_BYTES_IN_A_EVENT) { | |
2979 int feedback = 0; | |
2980 if (!client->resetting) { | |
2981 TRACE(("\tsending XIMP_STATUSDRAW_CM message\n")); | |
2982 sendClientMessage32(client, XIMP_STATUSDRAW_CM, client->id, | |
2983 type, feedback, 0L); | |
2984 TRACE(("\tsending string via event\n")); | |
2985 sendClientMessage8(client, data->text, data->text_length); | |
2986 } | |
2987 } | |
2988 else { | |
2989 int i; | |
2990 int *feedbacks = (int *)XtMalloc(data->attrs_length * sizeof(int)); | |
2991 for (i = 0; i < data->attrs_length; i++) feedbacks[i] = 0; | |
2992 TRACE(("\tsending string via property\n")); | |
2993 XChangeProperty(xd, xw, client->statustext, | |
2994 data->encoding, data->format, PropModeAppend, | |
2995 (unsigned char *)data->text, data->text_length); | |
2996 TRACE(("\tsending feedbacks via property\n")); | |
2997 XChangeProperty(xd, xw, client->statusfeedback, | |
2998 xpw->ximp.ximpFeedbacksAtom, 32, PropModeAppend, | |
2999 (unsigned char *)feedbacks, data->attrs_length); | |
3000 if (!client->resetting) { | |
3001 TRACE(("\tsending XIMP_STATUSDRAW message\n")); | |
3002 sendClientMessage32(client, XIMP_STATUSDRAW, client->id, | |
3003 type, client->statustext, | |
3004 client->statusfeedback); | |
3005 } | |
3006 /* feedbacks を free しておく */ | |
3007 XtFree((char *)feedbacks); | |
3008 } | |
3009 #undef MAX_BYTES_IN_A_EVENT | |
3010 } | |
3011 | |
3012 | |
3013 #endif /* defined(XlibSpecificationRelease) && XlibSpecificationRelease >= 5 */ |