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 */