1 /*
2 * Motif
3 *
4 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
5 *
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
16 * details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
22 */
23 /*
24 * HISTORY
25 */
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30
31 #ifdef REV_INFO
32 #ifndef lint
33 static char rcsid[] = "$TOG: XmIm.c /main/28 1997/10/13 14:57:31 cshi $"
34 #endif
35 #endif
36
37 #include <stdio.h>
38 #include <Xm/DisplayP.h>
39 #include <Xm/DrawP.h>
40 #include <Xm/PrimitiveP.h>
41 #include <Xm/VendorSEP.h>
42 #include <Xm/VendorSP.h>
43 #include <Xm/XmosP.h> /* for bzero */
44 #include "BaseClassI.h"
45 #include "MessagesI.h"
46 #include "XmI.h"
47 #include "XmImI.h"
48 #include <X11/Xlib.h>
49
50 #define FIX_1534
51
52 # include <stdarg.h>
53 # define Va_start(a,b) va_start(a,b)
54
55 #define FIX_1510
56 #define FIX_1129
57 #define FIX_1196
58
59 #ifdef NO_XICPROC
60 typedef Bool (*XICProc)( XIC, XPointer, XPointer);
61 #endif
62
63 /* Data structures:
64 * While multiple XIMs are not currently supported, some thought
65 * was given to how they might be implemented. Currently both
66 * XmImDisplayInfo and XmImShellInfo contain per-XIM fields. Also the
67 * locale and XmNinputMethod are implicit in the XmImDisplayInfo.
68 * The back-pointer for the original source of shared XICs is perhaps
69 * overly general, but will ease XmPER_MANAGER sharing if implemented.
70 *
71 * If an XIC is shared among several widgets, all will reference a
72 * single XmImXICInfo.
73 */
74
75 typedef struct _XmImRefRec {
76 Cardinal num_refs; /* Number of referencing widgets. */
77 Cardinal max_refs; /* Maximum length of refs array. */
78 Widget* refs; /* Array of referencing widgets. */
79 XtPointer **callbacks;
80 } XmImRefRec, *XmImRefInfo;
81
82 typedef struct _PreeditBufferRec {
83 unsigned short length;
84 wchar_t *text;
85 XIMFeedback *feedback;
86 int caret;
87 XIMCaretStyle style;
88 } PreeditBufferRec, *PreeditBuffer;
89
90 typedef struct _XmImXICRec {
91 struct _XmImXICRec *next; /* Links all have the same XIM. */
92 XIC xic; /* The XIC. */
93 Window focus_window; /* Cached information about the XIC. */
94 XIMStyle input_style; /* ...ditto... */
95 int status_width; /* ...ditto... */
96 int preedit_width; /* ...ditto... */
97 int sp_height; /* ...ditto... */
98 Boolean has_focus; /* Does this XIC have keyboard focus. */
99 Boolean anonymous; /* Do we have exclusive rights to this XIC. */
100 XmImRefRec widget_refs; /* Widgets referencing this XIC. */
101 struct _XmImXICRec **source; /* Original source of shared XICs. */
102 PreeditBuffer preedit_buffer;
103 } XmImXICRec, *XmImXICInfo;
104
105 typedef struct _XmImShellRec {
106 /* per-Shell fields. */
107 Widget im_widget; /* Dummy widget to make intrinsics behave. */
108 Widget current_widget; /* Widget whose visual we're matching. */
109
110 /* per <Shell,XIM> fields. */
111 XmImXICInfo shell_xic; /* For PER_SHELL sharing policy. */
112 XmImXICInfo iclist; /* All known XICs for this <XIM,Shell>. */
113 } XmImShellRec, *XmImShellInfo;
114
115 typedef struct {
116 /* per-Display fields. */
117 XContext current_xics; /* Map widget -> current XmImXICInfo. */
118
119 /* per-XIM fields. */
120 XIM xim; /* The XIM. */
121 XIMStyles *styles; /* XNQueryInputStyle result. */
122 XmImRefRec shell_refs; /* Shells referencing this XIM. */
123 } XmImDisplayRec, *XmImDisplayInfo;
124
125
126 /*
127 * Although the current implementation of XVaNestedList is similar
128 * to an Xt ArgList, this is not guaranteed by the spec. The only
129 * approved interface for creating XVaNestedLists takes pairs of
130 * (char*, XPointer) paramters.
131 */
132 typedef struct {
133 char *name;
134 XPointer value;
135 } VaArg;
136
137 typedef struct {
138 Cardinal count;
139 Cardinal max;
140 VaArg *args;
141 } VaArgListRec, *VaArgList;
142
143
144 /******** Static Function Declarations ********/
145
146 static int add_sp(String name,
147 XPointer value,
148 VaArgList slp,
149 VaArgList plp,
150 VaArgList vlp);
151 static int add_p(String name,
152 XPointer value,
153 VaArgList slp,
154 VaArgList plp,
155 VaArgList vlp);
156 static int add_fs(String name,
157 XPointer value,
158 VaArgList slp,
159 VaArgList plp,
160 VaArgList vlp);
161 static int add_bgpxmp(String name,
162 XPointer value,
163 VaArgList slp,
164 VaArgList plp,
165 VaArgList vlp);
166
167 static XIMStyle check_style(XIMStyles *styles,
168 XIMStyle preedit_style,
169 XIMStyle status_style);
170 static int ImGetGeo(Widget vw,
171 XmImXICInfo this_icp );
172 static void ImSetGeo(Widget vw,
173 XmImXICInfo this_icp );
174 static void ImGeoReq(Widget vw);
175 static XFontSet extract_fontset(XmFontList fl);
176 static XmImDisplayInfo get_xim_info(Widget w);
177 static XtPointer* get_im_info_ptr(Widget w,
178 Boolean create);
179 static XmImShellInfo get_im_info(Widget w,
180 Boolean create);
181 static void draw_separator(Widget vw);
182 static void null_proc(Widget w,
183 XtPointer ptr,
184 XEvent *ev,
185 Boolean *b);
186 static void ImCountVaList(va_list var,
187 int *total_count);
188 static ArgList ImCreateArgList(va_list var,
189 int total_count);
190
191 static XmImXICInfo create_xic_info(Widget shell,
192 XmImDisplayInfo xim_info,
193 XmImShellInfo im_info,
194 #if NeedWidePrototypes
195 unsigned int input_policy);
196 #else
197 XmInputPolicy input_policy);
198 #endif /*NeedWidePrototypes*/
199 static XmImXICInfo recreate_xic_info(XIC xic,
200 Widget shell,
201 XmImDisplayInfo xim_info,
202 XmImShellInfo im_info);
203 static void set_values(Widget w,
204 ArgList args,
205 Cardinal num_args,
206 #if NeedWidePrototypes
207 unsigned int policy);
208 #else
209 XmInputPolicy policy);
210 #endif /*NeedWidePrototypes*/
211
212 static XmImXICInfo get_current_xic(XmImDisplayInfo xim_info,
213 Widget widget);
214 static void set_current_xic(XmImXICInfo xic_info,
215 XmImDisplayInfo xim_info,
216 Widget widget);
217 static void unset_current_xic(XmImXICInfo xic_info,
218 XmImShellInfo im_info,
219 XmImDisplayInfo xim_info,
220 Widget widget);
221
222 static Cardinal add_ref(XmImRefInfo refs,
223 Widget widget);
224 static Cardinal remove_ref(XmImRefInfo refs,
225 Widget widget);
226
227 static XVaNestedList VaCopy(VaArgList list);
228 static void VaSetArg(VaArgList list,
229 char *name,
230 XPointer value);
231
232 static int ImPreeditStartCallback(XIC xic,
233 XPointer client_data,
234 XPointer call_data);
235 static void ImPreeditDoneCallback(XIC xic,
236 XPointer client_data,
237 XPointer call_data);
238 static void ImPreeditDrawCallback(XIC xic,
239 XPointer client_data,
240 XPointer call_data);
241 static void ImPreeditCaretCallback(XIC xic,
242 XPointer client_data,
243 XPointer call_data);
244 static void ImFreePreeditBuffer(PreeditBuffer pb);
245 static void set_callback_values(Widget w,
246 String name,
247 XIMCallback *value,
248 VaArgList vlp,
249 XmInputPolicy input_policy);
250 static void regist_real_callback(Widget w,
251 XIMProc call,
252 int swc);
253 static XICProc get_real_callback(Widget w,
254 int swc,
255 Widget *real_widget);
256 static void move_preedit_string(XmImXICInfo icp,
257 Widget wfrom,
258 Widget wto);
259
260 /******** End Static Function Declarations ********/
261
262
263 typedef int (*XmImResLProc)(String, XPointer,
264 VaArgList, VaArgList, VaArgList);
265
266
267 typedef struct {
268 String xmstring;
269 String xstring;
270 XrmName xrmname;
271 XmImResLProc proc;
272 } XmImResListRec;
273
274 static XmImResListRec XmImResList[] = {
275 {XmNbackground, XNBackground, NULLQUARK, add_sp},
276 {XmNforeground, XNForeground, NULLQUARK, add_sp},
277 {XmNbackgroundPixmap, XNBackgroundPixmap, NULLQUARK, add_bgpxmp},
278 {XmNspotLocation, XNSpotLocation, NULLQUARK, add_p},
279 {XmNfontList, XNFontSet, NULLQUARK, add_fs},
280 {XmNrenderTable, XNFontSet, NULLQUARK, add_fs},
281 {XmNlineSpace, XNLineSpace, NULLQUARK, add_sp},
282 {XmNarea, XNArea, NULLQUARK, add_p},
283 {XmNpreeditStartCallback, XNPreeditStartCallback, NULLQUARK, NULL},
284 {XmNpreeditDoneCallback, XNPreeditDoneCallback, NULLQUARK, NULL},
285 {XmNpreeditDrawCallback, XNPreeditDrawCallback, NULLQUARK, NULL},
286 {XmNpreeditCaretCallback, XNPreeditCaretCallback, NULLQUARK, NULL},
287 };
288
289 #define OVERTHESPOT "overthespot"
290 #define OFFTHESPOT "offthespot"
291 #define ROOT "root"
292 #define ONTHESPOT "onthespot"
293
294 #define PREEDIT_START 0
295 #define PREEDIT_DONE 1
296 #define PREEDIT_DRAW 2
297 #define PREEDIT_CARET 3
298
299 #define SEPARATOR_HEIGHT 2
300
301 #define GEO_CHG 0x1
302 #define BG_CHG 0x2
303
304 #define MSG1 _XmMMsgXmIm_0000
305
306 /*ARGSUSED*/
307 void
XmImRegister(Widget w,unsigned int reserved)308 XmImRegister(Widget w,
309 unsigned int reserved) /* unused */
310 {
311 Widget p;
312 XmImShellInfo im_info;
313 XmImDisplayInfo xim_info;
314 XmInputPolicy input_policy = XmINHERIT_POLICY;
315
316 _XmWidgetToAppContext(w);
317
318 _XmAppLock(app);
319 /* Find the enclosing shell. */
320 p = XtParent(w);
321 while (!XtIsShell(p))
322 p = XtParent(p);
323
324 /* Lookup or create per-shell IM info and an XIM. */
325 if (((xim_info = get_xim_info(p)) == NULL) ||
326 (xim_info->xim == NULL)) {
327 _XmAppUnlock(app);
328 return;
329 }
330 if ((im_info = get_im_info(p, True)) == NULL) {
331 _XmAppUnlock(app);
332 return;
333 }
334
335 /* Check that this widget doesn't already have a current XIC. */
336 if (get_current_xic(xim_info, w) != NULL) {
337 _XmAppUnlock(app);
338 return;
339 }
340
341 /* See if this widget will be sharing an existing XIC. */
342 XtVaGetValues(p, XmNinputPolicy, &input_policy, NULL);
343 switch (input_policy)
344 {
345 case XmPER_SHELL:
346 if (im_info->shell_xic == NULL)
347 (void) create_xic_info(p, xim_info, im_info, input_policy);
348 set_current_xic(im_info->shell_xic, xim_info, w);
349 break;
350
351 case XmPER_WIDGET:
352 set_current_xic(create_xic_info(p, xim_info, im_info, input_policy),
353 xim_info, w);
354 break;
355
356 case XmINHERIT_POLICY:
357 break;
358
359 default:
360 assert(False);
361 }
362 _XmAppUnlock(app);
363 }
364
365 void
XmImUnregister(Widget w)366 XmImUnregister(Widget w)
367 {
368 register XmImDisplayInfo xim_info;
369 register XmImShellInfo im_info;
370 register XmImXICInfo xic_info;
371 XtAppContext app;
372
373 /* Punt if insufficient information was provided. */
374 if (w == NULL)
375 return;
376
377 app = XtWidgetToApplicationContext(w);
378 _XmAppLock(app);
379 /* Locate this record. */
380 xim_info = get_xim_info(w);
381 if ((xic_info = get_current_xic(xim_info, w)) == NULL) {
382 _XmAppUnlock(app);
383 return;
384 }
385 if ((im_info = get_im_info(w, False)) == NULL) {
386 _XmAppUnlock(app);
387 return;
388 }
389
390 /* Unregister this record. */
391 unset_current_xic(xic_info, im_info, xim_info, w);
392
393 if (im_info->iclist == NULL) {
394 Widget vw = XtParent(w);
395 while (!XtIsShell(vw)) vw = XtParent(vw);
396 ImGeoReq(vw);
397 }
398 _XmAppUnlock(app);
399 }
400
401 void
XmImSetFocusValues(Widget w,ArgList args,Cardinal num_args)402 XmImSetFocusValues(Widget w,
403 ArgList args,
404 Cardinal num_args)
405 {
406 register XmImXICInfo xic_info;
407 Widget p;
408 Pixel fg, bg;
409 XmFontList fl=NULL;
410 XFontSet fs=NULL;
411 XmVendorShellExtObject ve;
412 XmWidgetExtData extData;
413 XmImShellInfo im_info;
414 XVaNestedList list;
415 Window wind;
416 XmInputPolicy input_policy;
417 _XmWidgetToAppContext(w);
418
419 _XmAppLock(app);
420 p = w;
421 while (!XtIsShell(p))
422 p = XtParent(p);
423
424 if ((xic_info = get_current_xic(get_xim_info(p), w)) == NULL) {
425 _XmAppUnlock(app);
426 return;
427 }
428
429 wind = xic_info->focus_window;
430 xic_info->focus_window = XtWindow(w);
431
432 set_values(w, args, num_args, XmINHERIT_POLICY);
433
434 if (wind != XtWindow(w)) {
435 /* Safe, since we have a window - so it's no gadget */
436 XtVaGetValues(w, XmNbackground, &bg, NULL);
437 XtVaGetValues(w, XmNforeground, &fg, NULL);
438 XtVaGetValues(w, XmNfontList, &fl, NULL);
439 if (fl) fs = extract_fontset(fl);
440 if (fs)
441 list = XVaCreateNestedList(0,
442 XNBackground, bg,
443 XNForeground, fg,
444 XNFontSet, fs, NULL);
445 else
446 list = XVaCreateNestedList(0,
447 XNBackground, bg,
448 XNForeground, fg, NULL);
449 XSetICValues(xic_info->xic,
450 XNFocusWindow, XtWindow(w),
451 XNStatusAttributes, list,
452 XNPreeditAttributes, list,
453 NULL);
454 XFree(list);
455
456 if (xic_info->input_style & XIMPreeditCallbacks) {
457 XtVaGetValues(p, XmNinputPolicy, &input_policy, NULL);
458 if (input_policy == XmPER_SHELL && wind)
459 move_preedit_string(xic_info,
460 XtWindowToWidget(XtDisplay(w), wind), w);
461 }
462 }
463 XSetICFocus(xic_info->xic);
464 xic_info->has_focus = True;
465
466 extData = _XmGetWidgetExtData((Widget)p, XmSHELL_EXTENSION);
467 if (extData)
468 {
469 ve = (XmVendorShellExtObject) extData->widget;
470
471 if (ve->vendor.im_height)
472 {
473 im_info = (XmImShellInfo)ve->vendor.im_info;
474 im_info->current_widget = w;
475 XtVaGetValues(w, XmNbackground, &bg, NULL);
476 XtVaSetValues(p, XmNbackground, bg, NULL);
477 #ifdef FIX_1129
478 ImGeoReq(p);
479 #endif
480 draw_separator(p);
481 }
482 }
483 _XmAppUnlock(app);
484 }
485
486 void
XmImSetValues(Widget w,ArgList args,Cardinal num_args)487 XmImSetValues(Widget w,
488 ArgList args,
489 Cardinal num_args )
490 {
491 _XmWidgetToAppContext(w);
492 _XmAppLock(app);
493 set_values(w, args, num_args, XmINHERIT_POLICY);
494 _XmAppUnlock(app);
495 }
496
497 void
XmImUnsetFocus(Widget w)498 XmImUnsetFocus(Widget w)
499 {
500 register XmImXICInfo xic_info;
501 _XmWidgetToAppContext(w);
502
503 _XmAppLock(app);
504 if ((xic_info = get_current_xic(get_xim_info(w), w)) == NULL) {
505 _XmAppUnlock(app);
506 return;
507 }
508
509 if (xic_info->xic)
510 XUnsetICFocus(xic_info->xic);
511 xic_info->has_focus = False;
512 _XmAppUnlock(app);
513 }
514
515 XIM
XmImGetXIM(Widget w)516 XmImGetXIM(Widget w)
517 {
518 XmImDisplayInfo xim_info;
519 _XmWidgetToAppContext(w);
520
521 _XmAppLock(app);
522 xim_info = get_xim_info(w);
523 if (xim_info != NULL) {
524 _XmAppUnlock(app);
525 return xim_info->xim;
526 }
527 else {
528 _XmAppUnlock(app);
529 return NULL;
530 }
531 }
532
533 void
XmImCloseXIM(Widget w)534 XmImCloseXIM(Widget w)
535 {
536 XmDisplay xmDisplay;
537 XmImDisplayInfo xim_info;
538 Widget shell;
539 XmVendorShellExtObject ve;
540 XmWidgetExtData extData;
541 int height, base_height;
542 Arg args[1];
543 XtWidgetGeometry my_request;
544 _XmWidgetToAppContext(w);
545
546 _XmAppLock(app);
547 /* Allow (xim_info->xim == NULL) so we can reset the "failed" flag. */
548 if ((xim_info = get_xim_info(w)) == NULL) {
549 _XmAppUnlock(app);
550 return;
551 }
552
553 /* Remove all references to all XICs */
554 while (xim_info->shell_refs.refs != NULL)
555 {
556 shell = xim_info->shell_refs.refs[0];
557 _XmImFreeShellData(shell, get_im_info_ptr(shell, False));
558 assert((xim_info->shell_refs.refs == NULL) ||
559 (xim_info->shell_refs.refs[0] != shell));
560 }
561
562 shell = w;
563 while (!XtIsShell(shell))
564 shell = XtParent(shell);
565
566 extData = _XmGetWidgetExtData((Widget)shell, XmSHELL_EXTENSION);
567 if (extData) {
568 ve = (XmVendorShellExtObject) extData->widget;
569 height = ve->vendor.im_height;
570
571 if (height != 0){
572 XtSetArg(args[0], XtNbaseHeight, &base_height);
573 XtGetValues(shell, args, 1);
574 if (base_height > 0){
575 base_height -= height;
576 XtSetArg(args[0], XtNbaseHeight, base_height);
577 XtSetValues(shell, args, 1);
578 }
579 if(!(XtIsRealized(shell)))
580 shell->core.height -= height;
581 else {
582 my_request.height = shell->core.height - height;
583 my_request.request_mode = CWHeight;
584 XtMakeGeometryRequest(shell, &my_request, NULL);
585 }
586 ve->vendor.im_height = 0;
587 }
588 }
589
590 /* Close the XIM. */
591 if (xim_info->xim != NULL)
592 {
593 XCloseIM(xim_info->xim);
594 xim_info->xim = NULL;
595 }
596
597 XFree(xim_info->styles);
598 xim_info->styles = NULL;
599
600 xmDisplay = (XmDisplay) XmGetXmDisplay(XtDisplay(w));
601 xmDisplay->display.xmim_info = NULL;
602 XtFree((char *) xim_info);
603 _XmAppUnlock(app);
604 }
605
606 int
XmImMbLookupString(Widget w,XKeyPressedEvent * event,char * buf,int nbytes,KeySym * keysym,int * status)607 XmImMbLookupString(Widget w,
608 XKeyPressedEvent *event,
609 char *buf,
610 int nbytes,
611 KeySym *keysym,
612 int *status )
613 {
614 register XmImXICInfo icp;
615 int ret_val;
616 _XmWidgetToAppContext(w);
617
618 _XmAppLock(app);
619 if ((icp = get_current_xic(get_xim_info(w), w)) == NULL ||
620 icp->xic == NULL)
621 {
622 if (status)
623 *status = XLookupBoth;
624 ret_val = XLookupString(event, buf, nbytes, keysym, 0);
625 _XmAppUnlock(app);
626 return ret_val;
627 }
628
629 ret_val = XmbLookupString( icp->xic, event, buf, nbytes,
630 keysym, status );
631 _XmAppUnlock(app);
632 return ret_val;
633 }
634
635 XIC
XmImGetXIC(Widget w,unsigned int input_policy,ArgList args,Cardinal num_args)636 XmImGetXIC(Widget w,
637 #if NeedWidePrototypes
638 unsigned int input_policy,
639 #else
640 XmInputPolicy input_policy,
641 #endif /*NeedWidePrototypes*/
642 ArgList args,
643 Cardinal num_args)
644 {
645 XmImDisplayInfo xim_info;
646 XmImShellInfo im_info;
647 XmImXICInfo xic_info;
648 Widget shell;
649 _XmWidgetToAppContext(w);
650
651 _XmAppLock(app);
652 xim_info = get_xim_info(w);
653 im_info = get_im_info(w, True);
654 xic_info = get_current_xic(xim_info, w);
655
656 if ((xim_info == NULL) || (xim_info->xim == NULL)) {
657 _XmAppUnlock(app);
658 return NULL;
659 }
660
661 /* Find the enclosing shell. */
662 shell = w;
663 while (!XtIsShell(shell))
664 shell = XtParent(shell);
665
666 /* Resolve the true input policy. */
667 if (input_policy == XmINHERIT_POLICY)
668 XtVaGetValues(shell, XmNinputPolicy, &input_policy, NULL);
669
670 /* If there is already a current XIC, we may want to unregister it. */
671 switch (input_policy)
672 {
673 case XmPER_SHELL:
674 if ((xic_info != NULL) && (im_info->shell_xic != xic_info))
675 {
676 unset_current_xic(xic_info, im_info, xim_info, w);
677 xic_info = NULL;
678 }
679 break;
680
681 case XmPER_WIDGET:
682 if (xic_info != NULL)
683 {
684 unset_current_xic(xic_info, im_info, xim_info, w);
685 xic_info = NULL;
686 }
687 break;
688
689 default:
690 assert(False);
691 }
692
693 /* Register an XIC with the desired input policy. */
694 if (xic_info == NULL)
695 {
696 xic_info = create_xic_info(shell, xim_info, im_info, input_policy);
697 set_current_xic(xic_info, xim_info, w);
698 }
699
700 /* Set the values, which creates an XIC. */
701 set_values(w, args, num_args, input_policy);
702
703 /* Return the current XIC. */
704 if (xic_info != NULL) {
705 _XmAppUnlock(app);
706 return xic_info->xic;
707 }
708 _XmAppUnlock(app);
709 return NULL;
710 }
711
712 XIC
XmImSetXIC(Widget widget,XIC xic)713 XmImSetXIC(Widget widget,
714 XIC xic)
715 {
716 XmImDisplayInfo xim_info;
717 XmImShellInfo im_info;
718 XmImXICInfo xic_info;
719 Widget shell;
720 _XmWidgetToAppContext(widget);
721
722 _XmAppLock(app);
723 xim_info = get_xim_info(widget);
724 im_info = get_im_info(widget, True);
725 xic_info = get_current_xic(xim_info, widget);
726 if ((xim_info == NULL) || (xim_info->xim == NULL)) {
727 _XmAppUnlock(app);
728 return NULL;
729 }
730
731 /* This may be a simple query. */
732 if (xic == NULL)
733 {
734 /* No XIC is registered for this widget. */
735 if (xic_info == NULL) {
736 _XmAppUnlock(app);
737 return NULL;
738 }
739
740 /* Force creation of the XIC. */
741 if (xic_info->xic == NULL)
742 set_values(widget, NULL, 0, XmINHERIT_POLICY);
743
744 _XmAppUnlock(app);
745 return xic_info->xic;
746 }
747
748 /* We don't support multiple IMs. */
749 if (XIMOfIC(xic) != xim_info->xim) {
750 _XmAppUnlock(app);
751 return NULL;
752 }
753
754 /* Unregister the current XIC. */
755 if (xic_info != NULL)
756 {
757 /* Setting the current XIC to itself is a no-op. */
758 if (xic_info->xic == xic) {
759 _XmAppUnlock(app);
760 return xic;
761 }
762
763 unset_current_xic(xic_info, im_info, xim_info, widget);
764 xic_info = NULL;
765 }
766
767 /* Find the enclosing shell. */
768 shell = widget;
769 while (!XtIsShell(shell))
770 shell = XtParent(shell);
771
772 /* Get or create xic_info for this xic. */
773 xic_info = recreate_xic_info(xic, shell, xim_info, im_info);
774
775 /* Make this the current XIC for this widget. */
776 set_current_xic(xic_info, xim_info, widget);
777
778 _XmAppUnlock(app);
779 return xic;
780 }
781
782 void
XmImFreeXIC(Widget w,XIC context)783 XmImFreeXIC(Widget w,
784 XIC context)
785 {
786 register int index;
787 register XmImDisplayInfo xim_info;
788 register XmImShellInfo im_info;
789 register XmImXICInfo xic_info;
790 XtAppContext app;
791
792 /* Punt if insufficient information was provided. */
793 if (w == NULL)
794 return;
795
796 app = XtWidgetToApplicationContext(w);
797 _XmAppLock(app);
798 /* Locate this record. */
799 xim_info = get_xim_info(w);
800 if ((xic_info = get_current_xic(xim_info, w)) == NULL) {
801 _XmAppUnlock(app);
802 return;
803 }
804 if ((im_info = get_im_info(w, False)) == NULL) {
805 _XmAppUnlock(app);
806 return;
807 }
808 if ((context != NULL) && (xic_info->xic != context)) {
809 _XmAppUnlock(app);
810 return;
811 }
812
813 /* Remove all references. */
814 index = xic_info->widget_refs.num_refs;
815 while (--index >= 0)
816 unset_current_xic(xic_info, im_info, xim_info,
817 xic_info->widget_refs.refs[index]);
818 _XmAppUnlock(app);
819 }
820
821 /*********************
822 * Private Functions *
823 *********************/
824
825 /* Free a VendorShellExt's im_info field. */
826 void
_XmImFreeShellData(Widget widget,XtPointer * data)827 _XmImFreeShellData(Widget widget,
828 XtPointer* data)
829 {
830 XmImShellInfo im_info;
831 XmImDisplayInfo xim_info;
832 XmImXICInfo xic_info;
833 Widget reference;
834
835 if ((data == NULL) ||
836 (im_info = (XmImShellInfo) *data) == NULL)
837 return;
838
839 /* Ignore (xim_info->xim == NULL), since it is immaterial here. */
840 xim_info = get_xim_info(widget);
841 if (xim_info == NULL)
842 return;
843
844 /* Remove any dangling references. */
845 while (im_info->iclist != NULL)
846 {
847 xic_info = im_info->iclist;
848 reference = xic_info->widget_refs.refs[0];
849 unset_current_xic(xic_info, im_info, xim_info, reference);
850 assert((xic_info != im_info->iclist) ||
851 (reference != xic_info->widget_refs.refs[0]));
852 }
853 assert(im_info->shell_xic == NULL);
854
855 /* Delete the dummy widget. */
856 #ifdef FIX_1534
857 if (im_info->im_widget != NULL &&
858 !widget->core.being_destroyed)
859 #else
860 if (im_info->im_widget != NULL)
861 #endif
862 {
863 XtDestroyWidget(im_info->im_widget);
864 im_info->im_widget = NULL;
865 }
866
867 /* Remove this shell as a reference to the XIM. */
868 (void) remove_ref(&xim_info->shell_refs, widget);
869
870 /* Delete the data. */
871 XtFree((char *) im_info);
872 *data = NULL;
873 }
874
875 void
_XmImChangeManaged(Widget vw)876 _XmImChangeManaged(
877 Widget vw )
878 {
879 XmVendorShellExtObject ve;
880 XmWidgetExtData extData;
881 register int height, old_height;
882
883 extData = _XmGetWidgetExtData((Widget)vw, XmSHELL_EXTENSION);
884 if (extData) {
885 ve = (XmVendorShellExtObject) extData->widget;
886
887 old_height = ve->vendor.im_height;
888
889 height = ImGetGeo(vw, NULL);
890 if (!ve->vendor.im_vs_height_set) {
891 Arg args[1];
892 int base_height;
893 XtSetArg(args[0], XtNbaseHeight, &base_height);
894 XtGetValues(vw, args, 1);
895 if (base_height > 0) {
896 base_height += (height - old_height);
897 XtSetArg(args[0], XtNbaseHeight, base_height);
898 XtSetValues(vw, args, 1);
899 }
900 vw->core.height += (height - old_height);
901 }
902 }
903 }
904
905 void
_XmImRealize(Widget vw)906 _XmImRealize(
907 Widget vw )
908 {
909 XmImXICInfo icp;
910 Pixel bg;
911 XmVendorShellExtObject ve;
912 XmWidgetExtData extData;
913 XmImShellInfo im_info;
914 XmImDisplayInfo xim_info;
915
916 xim_info = get_xim_info(vw);
917 im_info = get_im_info(vw, False);
918
919 if ((xim_info == NULL) ||
920 (im_info == NULL) ||
921 (im_info->iclist == NULL))
922 return;
923
924 /* We need to synchronize here to make sure the server has created
925 * the client window before the input server attempts to reparent
926 * any windows to it
927 */
928 XSync(XtDisplay(vw), False);
929
930 for (icp = im_info->iclist; icp != NULL; icp = icp->next)
931 {
932 if (!icp->xic) continue;
933 XSetICValues(icp->xic, XNClientWindow, XtWindow(vw), NULL);
934 }
935
936 extData = _XmGetWidgetExtData((Widget)vw, XmSHELL_EXTENSION);
937 if (extData)
938 ve = (XmVendorShellExtObject) extData->widget;
939 else
940 ve = NULL;
941 if (ve && ve->vendor.im_height == 0) {
942 ShellWidget shell = (ShellWidget)(vw);
943 Boolean resize = shell->shell.allow_shell_resize;
944
945 if (!resize) shell->shell.allow_shell_resize = True;
946 ImGeoReq(vw);
947 if (!resize) shell->shell.allow_shell_resize = False;
948 } else
949 ImSetGeo(vw, NULL);
950
951 /* For some reason we need to wait till now before we set the
952 * initial background pixmap.
953 */
954 if (ve && ve->vendor.im_height && im_info->current_widget)
955 {
956 XtVaGetValues(im_info->current_widget, XmNbackground, &bg, NULL);
957 XtVaSetValues(vw, XmNbackground, bg, NULL);
958 }
959 }
960
961 void
_XmImResize(Widget vw)962 _XmImResize(
963 Widget vw )
964 {
965 ImGetGeo(vw, NULL);
966 ImSetGeo(vw, NULL);
967 }
968
969 void
_XmImRedisplay(Widget vw)970 _XmImRedisplay(
971 Widget vw )
972 {
973 XmVendorShellExtObject ve;
974 XmWidgetExtData extData;
975
976 if ((extData = _XmGetWidgetExtData((Widget)vw, XmSHELL_EXTENSION)) == NULL)
977 return;
978
979 ve = (XmVendorShellExtObject) extData->widget;
980
981 if (ve->vendor.im_height == 0)
982 return;
983
984 draw_separator(vw);
985 }
986
987 /********************
988 * Static functions *
989 ********************/
990
991 /* Locate an XmImXICInfo struct for an existing XIC. */
992 static XmImXICInfo
recreate_xic_info(XIC xic,Widget shell,XmImDisplayInfo xim_info,XmImShellInfo im_info)993 recreate_xic_info(XIC xic,
994 Widget shell,
995 XmImDisplayInfo xim_info,
996 XmImShellInfo im_info)
997 {
998 Cardinal index;
999 XmImXICInfo xic_info;
1000 assert(xic != NULL);
1001
1002 /* Search for an existing record in this shell's im_info. */
1003 for (xic_info = im_info->iclist;
1004 xic_info != NULL;
1005 xic_info = xic_info->next)
1006 {
1007 if (xic_info->xic == xic)
1008 return xic_info;
1009 }
1010
1011 /* Search for an existing record in another shell's im_info? */
1012 for (index = 0; index < xim_info->shell_refs.num_refs; index++)
1013 if (shell != xim_info->shell_refs.refs[index])
1014 {
1015 XmImShellInfo tmp_info =
1016 get_im_info(xim_info->shell_refs.refs[index], False);
1017 assert(tmp_info != NULL);
1018
1019 for (xic_info = tmp_info->iclist;
1020 xic_info != NULL;
1021 xic_info = xic_info->next)
1022 {
1023 if (xic_info->xic == xic)
1024 return xic_info;
1025 }
1026 }
1027
1028 /* This XIC must have been created by the application directly. */
1029 xic_info = XtNew(XmImXICRec);
1030 bzero((char*) xic_info, sizeof(XmImXICRec));
1031 (void) XGetICValues(xic, XNInputStyle, &xic_info->input_style, NULL);
1032 xic_info->next = im_info->iclist;
1033 im_info->iclist = xic_info;
1034
1035 if (XtIsRealized (shell))
1036 {
1037 /* If client_window hasn't been set already, set it now. */
1038 (void) XSetICValues(xic, XNClientWindow, XtWindow(shell), NULL);
1039
1040 /* Update cached geometry fields */
1041 ImGetGeo(shell, xic_info);
1042 ImSetGeo(shell, xic_info);
1043 }
1044
1045 return xic_info;
1046 }
1047
1048 /* Attempt to create an XmImXICInfo struct. Return it or NULL. */
1049 static XmImXICInfo
create_xic_info(Widget shell,XmImDisplayInfo xim_info,XmImShellInfo im_info,unsigned int input_policy)1050 create_xic_info(Widget shell,
1051 XmImDisplayInfo xim_info,
1052 XmImShellInfo im_info,
1053 #if NeedWidePrototypes
1054 unsigned int input_policy)
1055 #else
1056 XmInputPolicy input_policy)
1057 #endif /*NeedWidePrototypes*/
1058 {
1059 XIMStyle style = 0;
1060 char tmp[BUFSIZ];
1061 char *cp = NULL;
1062 char *tp = NULL;
1063 char *cpend = NULL;
1064 register XIMStyles *styles;
1065 XmImXICInfo xic_info;
1066
1067 /* Determine the input style to be used for this XIC. */
1068 styles = xim_info->styles;
1069 XtVaGetValues(shell, XmNpreeditType, &cp, NULL);
1070
1071 if (cp != NULL)
1072 {
1073 /* Parse for the successive commas */
1074 cp = strcpy(tmp,cp);
1075 cpend = &tmp[strlen(tmp)];
1076 assert(strlen(tmp) < BUFSIZ);
1077 while((style == 0) && (cp < cpend))
1078 {
1079 tp = strchr(cp,',');
1080 if (tp)
1081 *tp = 0;
1082 else
1083 tp = cpend;
1084
1085 /* Look for an acceptable supported style. */
1086 if (XmeNamesAreEqual(cp, OVERTHESPOT))
1087 style = check_style(styles, XIMPreeditPosition,
1088 XIMStatusArea|XIMStatusNothing|XIMStatusNone);
1089 else if (XmeNamesAreEqual(cp, OFFTHESPOT))
1090 style = check_style(styles, XIMPreeditArea,
1091 XIMStatusArea|XIMStatusNothing|XIMStatusNone);
1092 else if (XmeNamesAreEqual(cp, ROOT))
1093 style = check_style(styles, XIMPreeditNothing,
1094 XIMStatusNothing|XIMStatusNone);
1095 else if (XmeNamesAreEqual(cp, ONTHESPOT))
1096 style = check_style(styles, XIMPreeditCallbacks,
1097 XIMStatusArea|XIMStatusNothing|XIMStatusNone);
1098
1099 cp = tp+1;
1100 }
1101 }
1102 if (style == 0)
1103 {
1104 /* Try for a fallback style, or give up and use XLookupString. */
1105 if ((style = check_style(styles, XIMPreeditNone, XIMStatusNone)) == 0)
1106 return NULL;
1107 }
1108
1109 /* We need to create this widget whenever there is a non-simple
1110 * input method in order to stop the intrinsics from calling
1111 * XMapSubwindows, thereby improperly mapping input method
1112 * windows which have been made children of the client or
1113 * focus windows.
1114 */
1115 if ((im_info->im_widget == NULL) &&
1116 (style & (XIMStatusArea | XIMPreeditArea | XIMPreeditPosition)))
1117 im_info->im_widget =
1118 XtVaCreateWidget("xmim_wrapper", coreWidgetClass,
1119 shell, XmNwidth, 10, XmNheight, 10, NULL);
1120
1121 /* Create the XIC info record. */
1122 xic_info = XtNew(XmImXICRec);
1123 bzero((char*) xic_info, sizeof(XmImXICRec));
1124 xic_info->input_style = style;
1125 xic_info->anonymous = True;
1126 xic_info->preedit_buffer = XtNew(PreeditBufferRec);
1127 bzero((char *) xic_info->preedit_buffer, sizeof(PreeditBufferRec));
1128
1129 xic_info->next = im_info->iclist;
1130 im_info->iclist = xic_info;
1131
1132 /* Setup sharing for this XIC. */
1133 switch (input_policy)
1134 {
1135 case XmPER_SHELL:
1136 assert (im_info->shell_xic == NULL);
1137 im_info->shell_xic = xic_info;
1138 im_info->shell_xic->source = &im_info->shell_xic;
1139 break;
1140
1141 case XmPER_WIDGET:
1142 break;
1143
1144 case XmINHERIT_POLICY:
1145 break;
1146
1147 default:
1148 assert(False);
1149 }
1150
1151 return xic_info;
1152 }
1153
1154
1155 #define IsCallback(name) \
1156 if (name == XrmStringToName(XmNpreeditStartCallback) || \
1157 name == XrmStringToName(XmNpreeditDoneCallback) || \
1158 name == XrmStringToName(XmNpreeditDrawCallback) || \
1159 name == XrmStringToName(XmNpreeditCaretCallback))
1160
1161
1162 static void
set_values(Widget w,ArgList args,Cardinal num_args,unsigned int input_policy)1163 set_values(Widget w,
1164 ArgList args,
1165 Cardinal num_args,
1166 #if NeedWidePrototypes
1167 unsigned int input_policy )
1168 #else
1169 XmInputPolicy input_policy )
1170 #endif /*NeedWidePrototypes*/
1171 {
1172 register XmImXICInfo icp;
1173 XmImDisplayInfo xim_info;
1174 XmImResListRec *rlp;
1175 register int i, j;
1176 register ArgList argp = args;
1177 VaArgListRec status_vlist, preedit_vlist, xic_vlist;
1178 XVaNestedList va_slist, va_plist, va_vlist;
1179 XrmName name, area_name = XrmStringToName(XmNarea);
1180 Widget p;
1181 XmImShellInfo im_info;
1182 int flags = 0;
1183 Pixel bg;
1184 char *ret;
1185 unsigned long mask = 0;
1186 Boolean unrecognized = False;
1187
1188 p = w;
1189 while (!XtIsShell(p))
1190 p = XtParent(p);
1191
1192 xim_info = get_xim_info(p);
1193 if ((icp = get_current_xic(xim_info, w)) == NULL)
1194 return;
1195
1196 im_info = get_im_info(p, False);
1197 assert(im_info != NULL);
1198
1199 if (!XtIsRealized(p)) {
1200 /* If vendor widget not realized, then the current info
1201 * is that for the last widget to set values.
1202 */
1203 im_info->current_widget = w;
1204 }
1205
1206 if (icp->xic &&
1207 icp->focus_window && icp->focus_window != XtWindow(w))
1208 return;
1209
1210 bzero((char*) &status_vlist, sizeof(VaArgListRec));
1211 bzero((char*) &preedit_vlist, sizeof(VaArgListRec));
1212 bzero((char*) &xic_vlist, sizeof(VaArgListRec));
1213 for (i = num_args; i > 0; i--, argp++) {
1214 name = XrmStringToName(argp->name);
1215 if (name == area_name && !(icp->input_style & XIMPreeditPosition))
1216 continue;
1217
1218 IsCallback(name){
1219 if (icp->input_style & XIMPreeditCallbacks){
1220 set_callback_values(w, argp->name, (XIMCallback *)(argp->value),
1221 &preedit_vlist, input_policy);
1222 continue;
1223 } else
1224 continue;
1225 }
1226
1227 _XmProcessLock();
1228 for (rlp = XmImResList, j = XtNumber(XmImResList); j != 0; j--, rlp++) {
1229 if (rlp->xrmname == name) {
1230 flags |= (*rlp->proc)(rlp->xstring, (XPointer) argp->value,
1231 &status_vlist, &preedit_vlist, &xic_vlist);
1232 break;
1233 }
1234 }
1235 _XmProcessUnlock();
1236 if (j == 0) {
1237 /* Simply pass unrecognized values along */
1238 VaSetArg(&xic_vlist, argp->name, (XPointer) argp->value);
1239 unrecognized = True;
1240 }
1241 }
1242
1243 /* We do not create the IC until the initial data is ready to be passed */
1244 assert(xim_info != NULL);
1245 if (icp->xic == NULL) {
1246 if (XtIsRealized(p)) {
1247 XSync(XtDisplay(p), False);
1248 VaSetArg(&xic_vlist, XNClientWindow, (XPointer) XtWindow(p));
1249 }
1250 if (icp->focus_window) {
1251 VaSetArg(&xic_vlist, XNFocusWindow, (XPointer) icp->focus_window);
1252 }
1253 VaSetArg(&xic_vlist, XNInputStyle, (XPointer) icp->input_style);
1254
1255 va_plist = VaCopy(&preedit_vlist);
1256 if (va_plist)
1257 VaSetArg(&xic_vlist, XNPreeditAttributes, (XPointer)va_plist);
1258 va_slist = VaCopy(&status_vlist);
1259 if (va_slist)
1260 VaSetArg(&xic_vlist, XNStatusAttributes, (XPointer)va_slist);
1261 va_vlist = VaCopy(&xic_vlist);
1262
1263 if (va_vlist)
1264 {
1265 icp->xic = XCreateIC(xim_info->xim, XNVaNestedList, va_vlist, NULL);
1266 #ifdef FIX_1510
1267 if (icp->xic == NULL)
1268 {
1269 icp->input_style = XIMPreeditNothing | XIMStatusNothing;
1270 icp->xic = XCreateIC(xim_info->xim, XNInputStyle, icp->input_style,
1271 XNClientWindow, XtWindow(p), XNFocusWindow, XtWindow(p), NULL);
1272 }
1273 #endif
1274 }
1275 else
1276 icp->xic = XCreateIC(xim_info->xim, NULL);
1277
1278 if (va_vlist) XFree(va_vlist);
1279 if (va_plist) XFree(va_plist);
1280 if (va_slist) XFree(va_slist);
1281 if (preedit_vlist.args) XtFree((char *)preedit_vlist.args);
1282 if (status_vlist.args) XtFree((char *)status_vlist.args);
1283 if (xic_vlist.args) XtFree((char *)xic_vlist.args);
1284
1285 if (icp->xic == NULL) {
1286 unset_current_xic(icp, im_info, xim_info, w);
1287 return;
1288 }
1289 XGetICValues(icp->xic, XNFilterEvents, &mask, NULL);
1290 if (mask) {
1291 XtAddEventHandler(p, (EventMask)mask, False, null_proc, NULL);
1292 }
1293 if (XtIsRealized(p)) {
1294 #ifdef FIX_1129
1295 im_info->current_widget = w;
1296 #endif
1297 if (XmIsDialogShell(p)) {
1298 for (i = 0;
1299 i < ((CompositeWidget)p)->composite.num_children;
1300 i++)
1301 if (XtIsManaged(((CompositeWidget)p)->composite.children[i])) {
1302 ImGeoReq(p);
1303 break;
1304 }
1305 } else
1306 ImGeoReq(p);
1307 #ifndef FIX_1129
1308 im_info->current_widget = w;
1309 #endif
1310 }
1311 /* Is this new XIC supposed to be shared? */
1312 switch (input_policy)
1313 {
1314 case XmPER_SHELL:
1315 assert(im_info->shell_xic == NULL);
1316 im_info->shell_xic = icp;
1317 break;
1318
1319 case XmPER_WIDGET:
1320 break;
1321 default:
1322 assert(False);
1323 }
1324 } else {
1325 /* Try to modify the existing XIC. */
1326 va_plist = VaCopy(&preedit_vlist);
1327 if (va_plist)
1328 VaSetArg(&xic_vlist, XNPreeditAttributes, (XPointer)va_plist);
1329 va_slist = VaCopy(&status_vlist);
1330 if (va_slist)
1331 VaSetArg(&xic_vlist, XNStatusAttributes, (XPointer)va_slist);
1332 va_vlist = VaCopy(&xic_vlist);
1333
1334 if (va_vlist)
1335 ret = XSetICValues(icp->xic, XNVaNestedList, va_vlist, NULL);
1336 else
1337 ret = NULL;
1338
1339 if (va_vlist) XFree(va_vlist);
1340 if (va_plist) XFree(va_plist);
1341 if (va_slist) XFree(va_slist);
1342 if (preedit_vlist.args) XtFree((char *)preedit_vlist.args);
1343 if (status_vlist.args) XtFree((char *)status_vlist.args);
1344 if (xic_vlist.args) XtFree((char *)xic_vlist.args);
1345
1346 /* ??? Both a write-once and an unrecognized arg might be present. */
1347 if ((ret != NULL) && unrecognized) {
1348 unsigned long status_bg, status_fg;
1349 unsigned long preedit_bg, preedit_fg;
1350
1351 /* ??? This code assumes that the XIM hasn't changed. */
1352 assert(XIMOfIC(icp->xic) == xim_info->xim);
1353
1354 /* We do this in case an input method does not support
1355 * change of some value, but does allow it to be set on
1356 * create. If however the value is not one of the
1357 * standard values, this im may not support it so we
1358 * should ignore it.
1359 */
1360
1361 va_slist = XVaCreateNestedList(0,
1362 XNBackground, &status_bg,
1363 XNForeground, &status_fg,
1364 NULL);
1365 va_plist = XVaCreateNestedList(0,
1366 XNBackground, &preedit_bg,
1367 XNForeground, &preedit_fg,
1368 NULL);
1369 XGetICValues(icp->xic,
1370 XNStatusAttributes, va_slist,
1371 XNPreeditAttributes, va_plist,
1372 NULL);
1373 XFree(va_slist);
1374 XFree(va_plist);
1375
1376 if (icp->anonymous)
1377 XDestroyIC(icp->xic);
1378 icp->anonymous = TRUE;
1379 icp->xic = NULL;
1380
1381 VaSetArg(&status_vlist, XNBackground, (XPointer) status_bg);
1382 VaSetArg(&status_vlist, XNForeground, (XPointer) status_fg);
1383
1384 VaSetArg(&preedit_vlist, XNBackground, (XPointer) preedit_bg);
1385 VaSetArg(&preedit_vlist, XNForeground, (XPointer) preedit_fg);
1386
1387 if (XtIsRealized(p)) {
1388 XSync(XtDisplay(p), False);
1389 VaSetArg(&xic_vlist, XNClientWindow, (XPointer) XtWindow(p));
1390 }
1391 if (icp->focus_window) {
1392 VaSetArg(&xic_vlist, XNFocusWindow, (XPointer)icp->focus_window);
1393 }
1394 VaSetArg(&xic_vlist, XNInputStyle, (XPointer) icp->input_style);
1395
1396 va_plist = VaCopy(&preedit_vlist);
1397 if (va_plist)
1398 VaSetArg(&xic_vlist, XNPreeditAttributes, (XPointer)va_plist);
1399 va_slist = VaCopy(&status_vlist);
1400 if (va_slist)
1401 VaSetArg(&xic_vlist, XNStatusAttributes, (XPointer)va_slist);
1402 va_vlist = VaCopy(&xic_vlist);
1403
1404 if (va_vlist)
1405 {
1406 icp->xic = XCreateIC(xim_info->xim, XNVaNestedList, va_vlist, NULL);
1407 #ifdef FIX_1510
1408 if (icp->xic == NULL)
1409 {
1410 icp->input_style = XIMPreeditNothing | XIMStatusNothing;
1411 icp->xic = XCreateIC(xim_info->xim, XNInputStyle, icp->input_style,
1412 XNClientWindow, XtWindow(p), XNFocusWindow, XtWindow(p), NULL);
1413 }
1414 #endif
1415 }
1416 else
1417 icp->xic = XCreateIC(xim_info->xim, NULL);
1418
1419 if (va_vlist) XFree(va_vlist);
1420 if (va_plist) XFree(va_plist);
1421 if (va_slist) XFree(va_slist);
1422 if (preedit_vlist.args) XtFree((char *)preedit_vlist.args);
1423 if (status_vlist.args) XtFree((char *)status_vlist.args);
1424 if (xic_vlist.args) XtFree((char *)xic_vlist.args);
1425
1426 if (icp->xic == NULL) {
1427 unset_current_xic(icp, im_info, xim_info, w);
1428 return;
1429 }
1430 ImGeoReq(p);
1431 if (icp->has_focus)
1432 XSetICFocus(icp->xic);
1433 return;
1434 }
1435 if (flags & GEO_CHG) {
1436 ImGeoReq(p);
1437 if (icp->has_focus)
1438 XSetICFocus(icp->xic);
1439 }
1440 }
1441
1442 /* Since we do not know whether a set values may have been done
1443 * on top shadow or bottom shadow (used for the separator), we
1444 * will redraw the separator in order to keep the visuals in sync
1445 * with the current text widget. Also repaint background if needed.
1446 */
1447 if ((im_info->current_widget == w) && (flags & BG_CHG)) {
1448 XtVaGetValues(w, XmNbackground, &bg, NULL);
1449 XtVaSetValues(p, XmNbackground, bg, NULL);
1450 }
1451 }
1452
1453
1454 static void
ImFreePreeditBuffer(PreeditBuffer pb)1455 ImFreePreeditBuffer(PreeditBuffer pb)
1456 {
1457 if (pb->text) XtFree((char *)pb->text);
1458 if (pb->feedback) XtFree((char *)pb->feedback);
1459 XtFree((char *)pb);
1460 }
1461
1462
1463 static int
ImPreeditStartCallback(XIC xic,XPointer client_data,XPointer call_data)1464 ImPreeditStartCallback(XIC xic,
1465 XPointer client_data,
1466 XPointer call_data)
1467 {
1468 XICProc proc;
1469 Widget real = NULL;
1470
1471 if (!client_data){
1472 assert(False);
1473 }
1474
1475 proc = get_real_callback((Widget)client_data, PREEDIT_START, &real);
1476 if (proc)
1477 (*proc)(xic, (XPointer)real, call_data);
1478
1479 return (-1);
1480 }
1481
1482 static void
ImPreeditDoneCallback(XIC xic,XPointer client_data,XPointer call_data)1483 ImPreeditDoneCallback(XIC xic,
1484 XPointer client_data,
1485 XPointer call_data)
1486 {
1487 XICProc proc;
1488 Widget w = (Widget)client_data;
1489 XmImShellInfo im_info;
1490 XmImXICInfo icp;
1491 Widget real = NULL;
1492
1493 if (!client_data){
1494 assert(False);
1495 }
1496
1497 if ((im_info = get_im_info(w, False)) == NULL)
1498 return;
1499 if ((icp = im_info->shell_xic) == NULL)
1500 return;
1501
1502 proc = get_real_callback((Widget)client_data, PREEDIT_DONE, &real);
1503 if (proc)
1504 (*proc)(xic, (XPointer)real, call_data);
1505
1506 if (icp->preedit_buffer->text)
1507 XtFree((char *)icp->preedit_buffer->text);
1508 if (icp->preedit_buffer->feedback)
1509 XtFree((char *)icp->preedit_buffer->feedback);
1510 bzero((char *)icp->preedit_buffer, sizeof(PreeditBufferRec));
1511 }
1512
1513 static void
ImPreeditDrawCallback(XIC xic,XPointer client_data,XPointer call_data)1514 ImPreeditDrawCallback(XIC xic,
1515 XPointer client_data,
1516 XPointer call_data)
1517 {
1518 XICProc proc;
1519 Widget w = (Widget)client_data;
1520 XmImShellInfo im_info;
1521 XmImXICInfo icp;
1522 PreeditBuffer pb;
1523 XIMText *text;
1524 XIMPreeditDrawCallbackStruct *data =
1525 (XIMPreeditDrawCallbackStruct *) call_data;
1526 int from=0, to=0, ml=0;
1527 wchar_t *wchar;
1528 Widget real = NULL;
1529
1530 if (!client_data){
1531 assert(False);
1532 }
1533
1534 /* update the preedit buffer */
1535 if ((im_info = get_im_info(w, False)) == NULL)
1536 return;
1537 if ((icp = im_info->shell_xic) == NULL)
1538 return;
1539
1540 pb = icp->preedit_buffer;
1541 pb->caret = data->caret;
1542 text = data->text;
1543
1544 if ((int)data->chg_length > (int)pb->length)
1545 data->chg_length = pb->length;
1546
1547 if (data->text) { /* text field is non-NULL */
1548
1549 if (data->chg_length > 0) { /* replace */
1550 if ((int)text->length > (int)data->chg_length) {
1551 pb->text = (wchar_t *)
1552 XtRealloc((char *)pb->text, (pb->length - data->chg_length +
1553 text->length + 1) * sizeof(wchar_t));
1554 pb->feedback = (XIMFeedback *)
1555 XtRealloc((char *)pb->feedback, (pb->length - data->chg_length +
1556 text->length + 1) *sizeof(XIMFeedback));
1557 }
1558 from = data->chg_first + data->chg_length;
1559 to = data->chg_first + text->length;
1560 ml = pb->length - from;
1561 }
1562 else if (data->chg_length == 0) { /* insert */
1563 /* do we really need to change anything? */
1564 if (data->text->length) {
1565 pb->text = (wchar_t *)
1566 XtRealloc((char *)pb->text, (pb->length + text->length +1)
1567 * sizeof(wchar_t));
1568 pb->feedback = (XIMFeedback *)
1569 XtRealloc((char *)pb->feedback, (pb->length + text->length +1)
1570 * sizeof(XIMFeedback));
1571 from = data->chg_first;
1572 to = data->chg_first + text->length;
1573 ml = pb->length - from;
1574 }
1575 }
1576
1577 /*
1578 ** if preedit buffer changed, then we munge it,
1579 ** otherwise we just leave it alone
1580 */
1581 if (from || to || ml) {
1582
1583 /* convert multibyte to wide char */
1584 wchar = (wchar_t *)XtMalloc ((text->length +1) * sizeof(wchar_t));
1585 if (text->encoding_is_wchar)
1586 memcpy(wchar, text->string.wide_char, text->length * sizeof(wchar_t));
1587 else
1588 mbstowcs(wchar, text->string.multi_byte, text->length + 1);
1589
1590 /* make change */
1591 memmove((char *)pb->text + to * sizeof(wchar_t),
1592 (char *)pb->text + from * sizeof(wchar_t),
1593 ml * sizeof(wchar_t));
1594 memmove((char *)pb->feedback + to * sizeof(XIMFeedback),
1595 (char *)pb->feedback + from * sizeof(XIMFeedback),
1596 ml * sizeof(XIMFeedback));
1597
1598 memmove((char *)pb->text + data->chg_first * sizeof(wchar_t),
1599 (char *)wchar,
1600 text->length * sizeof(wchar_t));
1601
1602 /* feedback may be NULL, check for it */
1603 if (text->feedback)
1604 memmove((char *)pb->feedback + data->chg_first * sizeof(XIMFeedback),
1605 (char *)text->feedback,
1606 text->length * sizeof(XIMFeedback));
1607
1608 pb->length = pb->length + text->length - data->chg_length;
1609 bzero((char *)pb->text + pb->length * sizeof(wchar_t),
1610 sizeof(wchar_t));
1611 bzero((char *)pb->feedback + pb->length * sizeof(XIMFeedback),
1612 sizeof(XIMFeedback));
1613
1614 XtFree((char *) wchar);
1615 }
1616 }
1617 else { /* text field is NULL, delete */
1618 from = data->chg_first + data->chg_length;
1619 to = data->chg_first;
1620 ml = pb->length - from;
1621 memmove((char *)pb->text + to * sizeof(wchar_t),
1622 (char *)pb->text + from * sizeof(wchar_t),
1623 ml * sizeof(wchar_t));
1624 memmove((char *)pb->feedback + to * sizeof(XIMFeedback),
1625 (char *)pb->feedback + from * sizeof(XIMFeedback),
1626 ml * sizeof(XIMFeedback));
1627
1628 pb->length = pb->length - data->chg_length;
1629 bzero((char *)pb->text + pb->length * sizeof(wchar_t),
1630 data->chg_length * sizeof(wchar_t));
1631 bzero((char *)pb->feedback + pb->length * sizeof(XIMFeedback),
1632 data->chg_length * sizeof(XIMFeedback));
1633 }
1634
1635 proc = get_real_callback((Widget)client_data, PREEDIT_DRAW, &real);
1636 if (proc)
1637 (*proc)(xic, (XPointer)real, call_data);
1638 }
1639
1640 static void
ImPreeditCaretCallback(XIC xic,XPointer client_data,XPointer call_data)1641 ImPreeditCaretCallback(XIC xic,
1642 XPointer client_data,
1643 XPointer call_data)
1644 {
1645 XICProc proc;
1646 Widget w = (Widget)client_data;
1647 XmImShellInfo im_info;
1648 XmImXICInfo icp;
1649 PreeditBuffer pb;
1650 XIMPreeditCaretCallbackStruct *data =
1651 (XIMPreeditCaretCallbackStruct *) call_data;
1652 Widget real = NULL;
1653
1654 if (!client_data){
1655 assert(False);
1656 }
1657
1658 /* update the preedit buffer */
1659 if ((im_info = get_im_info(w, False)) == NULL)
1660 return;
1661 if ((icp = im_info->shell_xic) == NULL)
1662 return;
1663
1664 pb = icp->preedit_buffer;
1665 pb->style = data->style;
1666
1667 switch (data->direction) {
1668 case XIMForwardChar:
1669 pb->caret = pb->caret + 1;
1670 break;
1671 case XIMBackwardChar:
1672 pb->caret = pb->caret - 1;
1673 break;
1674 case XIMAbsolutePosition:
1675 pb->caret = data->position;
1676 break;
1677 default:
1678 break;
1679 }
1680
1681 proc = get_real_callback((Widget)client_data, PREEDIT_CARET, &real);
1682 if (proc)
1683 (*proc)(xic, (XPointer)real, call_data);
1684 }
1685
1686 static XICProc
get_real_callback(Widget w,int swc,Widget * real_widget)1687 get_real_callback(Widget w,
1688 int swc,
1689 Widget *real_widget)
1690 {
1691 XmImShellInfo im_info;
1692 XmImXICInfo icp;
1693 int i, target;
1694 XmImRefRec refs;
1695
1696 if ((im_info = get_im_info(w, False)) == NULL)
1697 return (XICProc)NULL;
1698 if ((icp = im_info->shell_xic) == NULL)
1699 return (XICProc)NULL;
1700
1701 if (*real_widget == NULL)
1702 *real_widget = XtWindowToWidget(XtDisplay(w), icp->focus_window);
1703
1704 refs = icp->widget_refs;
1705 target = refs.num_refs;
1706 for (i = 0; i < refs.num_refs; i++){
1707 if (refs.refs[i] == *real_widget){
1708 target = i;
1709 break;
1710 }
1711 }
1712 if (target == refs.num_refs){
1713 assert(False);
1714 }
1715
1716 if (refs.callbacks[target])
1717 return (XICProc)refs.callbacks[target][swc];
1718 else
1719 return (XICProc)NULL;
1720 }
1721
1722 static void
regist_real_callback(Widget w,XIMProc call,int swc)1723 regist_real_callback(Widget w,
1724 XIMProc call,
1725 int swc)
1726 {
1727 Widget p;
1728 register XmImXICInfo icp;
1729 XmImDisplayInfo xim_info;
1730 XmImRefRec refs;
1731 int i, target = 0;
1732
1733 p = w;
1734 while (!XtIsShell(p))
1735 {
1736 p = XtParent(p);
1737 }
1738
1739 xim_info = get_xim_info(p);
1740 if ((icp = get_current_xic(xim_info, w)) == NULL)
1741 {
1742 return;
1743 }
1744
1745 refs = icp->widget_refs;
1746
1747 for (i = 0; i < refs.num_refs; i++)
1748 {
1749 if (refs.refs[i] == w)
1750 {
1751 target = i;
1752 break;
1753 }
1754 }
1755
1756 if (!refs.callbacks[target])
1757 refs.callbacks[target] = (XtPointer *)XtMalloc(4 * sizeof(XtPointer));
1758
1759 refs.callbacks[target][swc] = (XtPointer)call;
1760 }
1761
1762 static int
NameToSwitch(String name)1763 NameToSwitch(String name)
1764 {
1765
1766 if (!strcmp(name, XmNpreeditStartCallback))
1767 return PREEDIT_START;
1768 if (!strcmp(name, XmNpreeditDoneCallback))
1769 return PREEDIT_DONE;
1770 if (!strcmp(name, XmNpreeditDrawCallback))
1771 return PREEDIT_DRAW;
1772 if (!strcmp(name, XmNpreeditCaretCallback))
1773 return PREEDIT_CARET;
1774
1775 return 100;
1776 }
1777
1778 static void
set_callback_values(Widget w,String name,XIMCallback * value,VaArgList vlp,XmInputPolicy input_policy)1779 set_callback_values(Widget w,
1780 String name,
1781 XIMCallback *value,
1782 VaArgList vlp,
1783 XmInputPolicy input_policy)
1784 {
1785 XIMProc call = value->callback;
1786 int s = NameToSwitch(name);
1787 XmInputPolicy ip = input_policy;
1788 Widget p =NULL;
1789
1790 if (input_policy == XmINHERIT_POLICY){
1791 p = w;
1792 while (!XtIsShell(p))
1793 p = XtParent(p);
1794 XtVaGetValues(p, XmNinputPolicy, &ip, NULL);
1795 }
1796
1797 switch (s) {
1798 case PREEDIT_START :
1799 if (ip == XmPER_SHELL){
1800 call = value->callback;
1801 regist_real_callback(w, call, s);
1802 value->client_data = (XPointer)p;
1803 value->callback = (XIMProc) ImPreeditStartCallback;
1804 VaSetArg(vlp, XNPreeditStartCallback, (XPointer)value);
1805 } else
1806 VaSetArg(vlp, XNPreeditStartCallback, (XPointer)value);
1807 break;
1808
1809 case PREEDIT_DONE :
1810 if (ip == XmPER_SHELL){
1811 call = value->callback;
1812 regist_real_callback(w, call, s);
1813 value->client_data = (XPointer)p;
1814 value->callback = (XIMProc) ImPreeditDoneCallback;
1815 VaSetArg(vlp, XNPreeditDoneCallback, (XPointer)value);
1816 } else
1817 VaSetArg(vlp, XNPreeditDoneCallback, (XPointer)value);
1818 break;
1819
1820 case PREEDIT_DRAW :
1821 if (ip == XmPER_SHELL){
1822 call = value->callback;
1823 regist_real_callback(w, call, s);
1824 value->client_data = (XPointer)p;
1825 value->callback = (XIMProc) ImPreeditDrawCallback;
1826 VaSetArg(vlp, XNPreeditDrawCallback, (XPointer)value);
1827 } else
1828 VaSetArg(vlp, XNPreeditDrawCallback, (XPointer)value);
1829 break;
1830
1831 case PREEDIT_CARET :
1832 if (ip == XmPER_SHELL){
1833 call = value->callback;
1834 regist_real_callback(w, call, s);
1835 value->client_data = (XPointer)p;
1836 value->callback = (XIMProc) ImPreeditCaretCallback;
1837 VaSetArg(vlp, XNPreeditCaretCallback, (XPointer)value);
1838 } else
1839 VaSetArg(vlp, XNPreeditCaretCallback, (XPointer)value);
1840 break;
1841
1842 default :
1843 assert(False);
1844 }
1845 }
1846
1847
1848 static void
move_preedit_string(XmImXICInfo icp,Widget wfrom,Widget wto)1849 move_preedit_string(XmImXICInfo icp,
1850 Widget wfrom,
1851 Widget wto)
1852 {
1853 PreeditBuffer pb = icp->preedit_buffer;
1854 XIMPreeditDrawCallbackStruct draw_data;
1855 XIMText text;
1856 XICProc proc;
1857
1858 proc = get_real_callback(wfrom, PREEDIT_DONE, &wfrom);
1859 if (proc)
1860 (*proc)(icp->xic, (XPointer)wfrom, NULL);
1861
1862 proc = get_real_callback(wto, PREEDIT_START, &wto);
1863 if (proc)
1864 (*proc)(icp->xic, (XPointer)wto, NULL);
1865
1866 if (pb->length == 0)
1867 return;
1868
1869 draw_data.caret = pb->caret;
1870 draw_data.chg_first = 0;
1871 draw_data.chg_length = 0;
1872 text.length = pb->length;
1873 text.feedback = pb->feedback;
1874 text.encoding_is_wchar = True;
1875 text.string.wide_char = pb->text;
1876 draw_data.text = &text;
1877 proc = get_real_callback(wto, PREEDIT_DRAW, &wto);
1878 if (proc)
1879 (*proc)(icp->xic, (XPointer)wto, (XPointer)&draw_data);
1880 }
1881
1882
1883
1884 /*ARGSUSED*/
1885 static int
add_sp(String name,XPointer value,VaArgList slp,VaArgList plp,VaArgList vlp)1886 add_sp(String name,
1887 XPointer value,
1888 VaArgList slp,
1889 VaArgList plp,
1890 VaArgList vlp ) /* unused */
1891 {
1892 VaSetArg(slp, name, value);
1893 VaSetArg(plp, name, value);
1894
1895 return BG_CHG;
1896 }
1897
1898 /*ARGSUSED*/
1899 static int
add_p(String name,XPointer value,VaArgList slp,VaArgList plp,VaArgList vlp)1900 add_p(String name,
1901 XPointer value,
1902 VaArgList slp, /* unused */
1903 VaArgList plp,
1904 VaArgList vlp ) /* unused */
1905 {
1906 VaSetArg(plp, name, value);
1907
1908 return 0;
1909 }
1910
1911
1912 /*ARGSUSED*/
1913 static int
add_fs(String name,XPointer value,VaArgList slp,VaArgList plp,VaArgList vlp)1914 add_fs(String name,
1915 XPointer value,
1916 VaArgList slp,
1917 VaArgList plp,
1918 VaArgList vlp ) /* unused */
1919 {
1920 XFontSet fs;
1921
1922 if ( (fs = extract_fontset((XmFontList)value)) == NULL)
1923 return 0;
1924
1925 VaSetArg(slp, name, (XPointer) fs);
1926 VaSetArg(plp, name, (XPointer) fs);
1927
1928 return GEO_CHG;
1929 }
1930
1931 static int
add_bgpxmp(String name,XPointer value,VaArgList slp,VaArgList plp,VaArgList vlp)1932 add_bgpxmp(String name,
1933 XPointer value,
1934 VaArgList slp,
1935 VaArgList plp,
1936 VaArgList vlp )
1937 {
1938 if ( (Pixmap)value == XtUnspecifiedPixmap )
1939 return 0;
1940
1941 return add_sp( name, value, slp, plp, vlp );
1942 }
1943
1944 static XIMStyle
check_style(XIMStyles * styles,XIMStyle preedit_style,XIMStyle status_style)1945 check_style(XIMStyles *styles,
1946 XIMStyle preedit_style,
1947 XIMStyle status_style )
1948 {
1949 register int i;
1950
1951 /* Is this preedit & status style combination supported? */
1952 for (i=0; i < (int) styles->count_styles; i++)
1953 {
1954 if ((styles->supported_styles[i] & preedit_style) &&
1955 (styles->supported_styles[i] & status_style))
1956 return styles->supported_styles[i];
1957 }
1958 return 0;
1959 }
1960
1961
1962 /* if this_icp is non-null, operations will only be performed on the
1963 corresponding IC. (Basically disables looping) */
1964
1965 static int
ImGetGeo(Widget vw,XmImXICInfo this_icp)1966 ImGetGeo(Widget vw,
1967 XmImXICInfo this_icp )
1968 {
1969 XmImXICInfo icp;
1970 XmVendorShellExtObject ve;
1971 XmWidgetExtData extData;
1972 int height = 0;
1973 XRectangle rect;
1974 XRectangle *rp;
1975 XmImShellInfo im_info;
1976 XVaNestedList set_list, get_list;
1977
1978 extData = _XmGetWidgetExtData((Widget)vw, XmSHELL_EXTENSION);
1979 if (extData)
1980 ve = (XmVendorShellExtObject) extData->widget;
1981 else
1982 ve = NULL;
1983
1984 im_info = get_im_info(vw, False);
1985
1986 if (ve && ((im_info == NULL) || (im_info->iclist == NULL))) {
1987 ve->vendor.im_height = 0;
1988 return 0;
1989 }
1990
1991 set_list = XVaCreateNestedList(0, XNAreaNeeded, (XPointer) &rect, NULL);
1992 get_list = XVaCreateNestedList(0, XNAreaNeeded, (XPointer) &rp, NULL);
1993
1994 for (icp = this_icp ? this_icp : im_info->iclist;
1995 icp != NULL;
1996 icp = icp->next) {
1997 if (icp->xic) {
1998 if (icp->input_style & XIMStatusArea) {
1999 rect.width = vw->core.width;
2000 rect.height = 0;
2001
2002 XSetICValues(icp->xic, XNStatusAttributes, set_list, NULL);
2003 XGetICValues(icp->xic, XNStatusAttributes, get_list, NULL);
2004
2005 if ((int) rp->height > height)
2006 height = rp->height;
2007
2008 icp->status_width = MIN(rp->width, vw->core.width);
2009 icp->sp_height = rp->height;
2010 XFree(rp);
2011 }
2012 if (icp->input_style & XIMPreeditArea) {
2013 rect.width = vw->core.width;
2014 rect.height = 0;
2015
2016 XSetICValues(icp->xic, XNPreeditAttributes, set_list, NULL);
2017 XGetICValues(icp->xic, XNPreeditAttributes, get_list, NULL);
2018
2019 if ((int) rp->height > height)
2020 height = rp->height;
2021
2022 icp->preedit_width = MIN((int) rp->width,
2023 (int) (vw->core.width - icp->status_width));
2024 if (icp->sp_height < (int) rp->height)
2025 icp->sp_height = rp->height;
2026 XFree(rp);
2027 }
2028 }
2029
2030 if (this_icp)
2031 break;
2032 }
2033
2034 XFree(set_list);
2035 XFree(get_list);
2036
2037 if (height)
2038 height += SEPARATOR_HEIGHT;
2039
2040 if (ve)
2041 ve->vendor.im_height = height;
2042 return height;
2043 }
2044
2045
2046 /* if this_icp is non-null, operations will only be performed on the
2047 corresponding IC. (Basically disables looping) */
2048
2049 static void
ImSetGeo(Widget vw,XmImXICInfo this_icp)2050 ImSetGeo(Widget vw,
2051 XmImXICInfo this_icp )
2052 {
2053 XmVendorShellExtObject ve;
2054 XmWidgetExtData extData;
2055 register XmImXICInfo icp;
2056 XRectangle rect_status;
2057 XRectangle rect_preedit;
2058 XmImShellInfo im_info;
2059 XVaNestedList va_slist, va_plist;
2060 unsigned long use_slist, use_plist;
2061
2062 im_info = get_im_info(vw, False);
2063 if ((im_info == NULL) || (im_info->iclist == NULL))
2064 return;
2065
2066 extData = _XmGetWidgetExtData((Widget)vw, XmSHELL_EXTENSION);
2067 if (!extData) return;
2068 ve = (XmVendorShellExtObject) extData->widget;
2069
2070 if (ve->vendor.im_height == 0)
2071 return;
2072
2073 va_slist = XVaCreateNestedList(0, XNArea, &rect_status, NULL);
2074 va_plist = XVaCreateNestedList(0, XNArea, &rect_preedit, NULL);
2075
2076 for (icp = this_icp ? this_icp : im_info->iclist;
2077 icp != NULL;
2078 icp = icp->next)
2079 {
2080 if ((use_slist = (icp->input_style & XIMStatusArea)) != 0)
2081 {
2082 rect_status.x = 0;
2083 rect_status.y = vw->core.height - icp->sp_height;
2084 rect_status.width = icp->status_width;
2085 rect_status.height = icp->sp_height;
2086 }
2087
2088 if ((use_plist = (icp->input_style & XIMPreeditArea)) != 0)
2089 {
2090 rect_preedit.x = icp->status_width;
2091 rect_preedit.y = vw->core.height - icp->sp_height;
2092 rect_preedit.width = icp->preedit_width;
2093 rect_preedit.height = icp->sp_height;
2094 } else if ((use_plist = (icp->input_style & XIMPreeditPosition)) != 0)
2095 {
2096 unsigned int margin;
2097 #ifdef FIX_1129
2098 /*
2099 * im_info->current_widget can contains NULL,
2100 * for example, when widget having XIC focus is disposed.
2101 * Thus, we should check this and avoid dereferencing NULL pointer.
2102 */
2103 if (im_info->current_widget == NULL)
2104 break;
2105 #endif
2106 margin = ((XmPrimitiveWidget)im_info->current_widget)
2107 ->primitive.shadow_thickness
2108 + ((XmPrimitiveWidget)im_info->current_widget)
2109 ->primitive.highlight_thickness;
2110
2111 rect_preedit.width = MIN(icp->preedit_width,
2112 XtWidth(im_info->current_widget) - 2*margin);
2113 rect_preedit.height = MIN(icp->sp_height,
2114 XtHeight(im_info->current_widget) - 2*margin);
2115 }
2116
2117 if (use_slist && use_plist)
2118 XSetICValues(icp->xic,
2119 XNStatusAttributes, va_slist,
2120 XNPreeditAttributes, va_plist,
2121 NULL);
2122 else if (use_slist)
2123 XSetICValues(icp->xic,
2124 XNStatusAttributes, va_slist,
2125 NULL);
2126 else if (use_plist)
2127 XSetICValues(icp->xic,
2128 XNPreeditAttributes, va_plist,
2129 NULL);
2130
2131 if (this_icp)
2132 break;
2133 }
2134
2135 XFree(va_slist);
2136 XFree(va_plist);
2137 }
2138
2139 static void
ImGeoReq(Widget vw)2140 ImGeoReq(Widget vw )
2141 {
2142 XmVendorShellExtObject ve;
2143 XmWidgetExtData extData;
2144 XtWidgetGeometry my_request;
2145 int old_height;
2146 int delta_height;
2147 ShellWidget shell = (ShellWidget)(vw);
2148
2149 if (!(shell->shell.allow_shell_resize) && XtIsRealized(vw))
2150 return;
2151
2152 extData = _XmGetWidgetExtData(vw, XmSHELL_EXTENSION);
2153 if (!extData) return;
2154 ve = (XmVendorShellExtObject) extData->widget;
2155
2156 old_height = ve->vendor.im_height;
2157 ImGetGeo(vw, NULL);
2158 if ((delta_height = ve->vendor.im_height - old_height) != 0)
2159 {
2160 int base_height;
2161 Arg args[1];
2162 XtSetArg(args[0], XtNbaseHeight, &base_height);
2163 XtGetValues(vw, args, 1);
2164 if (base_height > 0) {
2165 base_height += delta_height;
2166 XtSetArg(args[0], XtNbaseHeight, base_height);
2167 XtSetValues(vw, args, 1);
2168 }
2169 my_request.height = vw->core.height + delta_height;
2170 my_request.request_mode = CWHeight;
2171 XtMakeGeometryRequest(vw, &my_request, NULL);
2172 }
2173 ImSetGeo(vw, NULL);
2174 }
2175
2176 static XFontSet
extract_fontset(XmFontList fl)2177 extract_fontset(
2178 XmFontList fl )
2179 {
2180 XmFontContext context;
2181 XmFontListEntry next_entry;
2182 XmFontType type_return;
2183 XtPointer tmp_font;
2184 XFontSet first_fs = NULL;
2185 char *font_tag = NULL;
2186
2187 if (!XmFontListInitFontContext(&context, fl))
2188 return NULL;
2189
2190 do {
2191 next_entry = XmFontListNextEntry(context);
2192 if (next_entry)
2193 {
2194 tmp_font = XmFontListEntryGetFont(next_entry, &type_return);
2195 if (type_return == XmFONT_IS_FONTSET)
2196 {
2197 font_tag = XmFontListEntryGetTag(next_entry);
2198 if (!strcmp(font_tag, XmFONTLIST_DEFAULT_TAG))
2199 {
2200 XmFontListFreeFontContext(context);
2201 if (font_tag) XtFree(font_tag);
2202 return (XFontSet)tmp_font;
2203 }
2204 if (font_tag) XtFree(font_tag);
2205 if (first_fs == NULL)
2206 first_fs = (XFontSet)tmp_font;
2207 }
2208 }
2209 } while (next_entry);
2210
2211 XmFontListFreeFontContext(context);
2212 return first_fs;
2213 }
2214
2215 /* Fetch (creating if necessary) the Display's xmim_info. */
2216 static XmImDisplayInfo
get_xim_info(Widget widget)2217 get_xim_info(Widget widget)
2218 {
2219 XmDisplay xmDisplay;
2220 char tmp[BUFSIZ];
2221 char *cp = NULL;
2222 XmImDisplayInfo xim_info;
2223 String name, w_class;
2224 Display *dpy;
2225 Widget shell;
2226
2227 if (widget == NULL)
2228 return NULL;
2229
2230 /* Find the parent shell. */
2231 shell = widget;
2232 while (!XtIsShell(shell))
2233 shell = XtParent(shell);
2234
2235 dpy = XtDisplay(shell);
2236 xmDisplay = (XmDisplay) XmGetXmDisplay(dpy);
2237 xim_info = (XmImDisplayInfo)xmDisplay->display.xmim_info;
2238
2239 /* If this is a simple lookup we're done. */
2240 if (xim_info != NULL)
2241 return xim_info;
2242
2243 /* Create a record so that we only try XOpenIM() once. */
2244 xim_info = XtNew(XmImDisplayRec);
2245 bzero((char*) xim_info, sizeof(XmImDisplayRec));
2246 xmDisplay->display.xmim_info = (XtPointer)xim_info;
2247
2248 /* Setup any specified locale modifiers. */
2249 XtVaGetValues(shell, XmNinputMethod, &cp, NULL);
2250 if (cp != NULL)
2251 {
2252 strcpy(tmp,"@im=");
2253 strcat(tmp,cp);
2254 assert(strlen(tmp) < BUFSIZ);
2255 XSetLocaleModifiers(tmp);
2256 }
2257
2258 XtGetApplicationNameAndClass(dpy, &name, &w_class);
2259
2260 /* Try to open the input method. */
2261 xim_info->xim = XOpenIM(dpy, XtDatabase(dpy), name, w_class);
2262 if (xim_info->xim == NULL)
2263 {
2264 #ifdef XOPENIM_WARNING
2265 /* Generate a warning if XOpenIM was supposed to work. */
2266 /* Use the WMShell's XmNtitleEncoding as a shibboleth. */
2267 Atom encoding = (Atom) 0;
2268 XtVaGetValues(shell, XmNtitleEncoding, &encoding, NULL);
2269 if (encoding != XA_STRING)
2270 XmeWarning ((Widget)widget, MSG1);
2271 #endif
2272
2273 /* Leave the null xim_info attached to the display so we only */
2274 /* print the warning message once. */
2275 return xim_info;
2276 }
2277
2278 /* Lookup the styles this input method supports. */
2279 if (XGetIMValues(xim_info->xim,
2280 XNQueryInputStyle, &xim_info->styles, NULL) != NULL)
2281 {
2282 XCloseIM(xim_info->xim);
2283 xim_info->xim = NULL;
2284 XmeWarning ((Widget)widget, MSG1);
2285 return xim_info;
2286 }
2287
2288 /* Initialize the list of xrm names */
2289 {
2290 XmImResListRec *rlp;
2291 register int i;
2292
2293 _XmProcessLock();
2294 for (rlp = XmImResList, i = XtNumber(XmImResList);
2295 i != 0;
2296 i--, rlp++)
2297 rlp->xrmname = XrmStringToName(rlp->xmstring);
2298 _XmProcessUnlock();
2299 }
2300
2301 return xim_info;
2302 }
2303
2304 static XtPointer*
get_im_info_ptr(Widget w,Boolean create)2305 get_im_info_ptr(Widget w,
2306 Boolean create)
2307 {
2308 Widget p;
2309 XmVendorShellExtObject ve;
2310 XmWidgetExtData extData;
2311 XmImShellInfo im_info;
2312 XmImDisplayInfo xim_info;
2313
2314 if (w == NULL)
2315 return NULL;
2316
2317 p = w;
2318 while (!XtIsShell(p))
2319 p = XtParent(p);
2320
2321 /* Check extension data since app could be attempting to create
2322 * a text widget as child of menu shell. This is illegal, and will
2323 * be detected later, but check here so we don't core dump.
2324 */
2325 if ((extData = _XmGetWidgetExtData((Widget)p, XmSHELL_EXTENSION)) == NULL)
2326 return NULL;
2327
2328 ve = (XmVendorShellExtObject) extData->widget;
2329
2330 if ((ve->vendor.im_info == NULL) && create)
2331 {
2332 im_info = XtNew(XmImShellRec);
2333 bzero((char*) im_info, sizeof(XmImShellRec));
2334 ve->vendor.im_info = (XtPointer)im_info;
2335
2336 xim_info = get_xim_info(p);
2337 (void) add_ref(&xim_info->shell_refs, p);
2338 }
2339
2340 return &ve->vendor.im_info;
2341 }
2342
2343 static XmImShellInfo
get_im_info(Widget w,Boolean create)2344 get_im_info(Widget w,
2345 Boolean create)
2346 {
2347 XmImShellInfo* ptr = (XmImShellInfo *) get_im_info_ptr(w, create);
2348 if (ptr != NULL)
2349 return *ptr;
2350 else
2351 return NULL;
2352 }
2353
2354 static void
draw_separator(Widget vw)2355 draw_separator(Widget vw )
2356 {
2357 XmPrimitiveWidget pw;
2358 XmVendorShellExtObject ve;
2359 XmWidgetExtData extData;
2360 XmImShellInfo im_info;
2361
2362 extData = _XmGetWidgetExtData((Widget)vw, XmSHELL_EXTENSION);
2363 if (!extData) return;
2364 ve = (XmVendorShellExtObject) extData->widget;
2365 if ((im_info = (XmImShellInfo)ve->vendor.im_info) == NULL)
2366 return;
2367 pw = (XmPrimitiveWidget)im_info->current_widget;
2368 if (!pw || !XmIsPrimitive(pw))
2369 return;
2370
2371 XmeDrawSeparator(XtDisplay(vw), XtWindow(vw),
2372 pw->primitive.top_shadow_GC,
2373 pw->primitive.bottom_shadow_GC,
2374 0,
2375 0,
2376 vw->core.height - ve->vendor.im_height,
2377 vw->core.width,
2378 SEPARATOR_HEIGHT,
2379 SEPARATOR_HEIGHT,
2380 0, /* separator.margin */
2381 XmHORIZONTAL, /* separator.orientation */
2382 XmSHADOW_ETCHED_IN); /* separator.separator_type */
2383 }
2384
2385 /*ARGSUSED*/
2386 static void
null_proc(Widget w,XtPointer ptr,XEvent * ev,Boolean * b)2387 null_proc(Widget w, /* unused */
2388 XtPointer ptr, /* unused */
2389 XEvent *ev, /* unused */
2390 Boolean *b ) /* unused */
2391 {
2392 /* This function does nothing. It is only there to allow the
2393 * event mask required by the input method to be added to
2394 * the client window.
2395 */
2396 }
2397
2398 /* The following section contains the varargs functions */
2399
2400
2401 /*VARARGS*/
2402 void
XmImVaSetFocusValues(Widget w,...)2403 XmImVaSetFocusValues(Widget w,
2404 ... )
2405 {
2406 va_list var;
2407 int total_count;
2408 ArgList args;
2409 _XmWidgetToAppContext(w);
2410
2411 _XmAppLock(app);
2412 Va_start(var,w);
2413 ImCountVaList(var, &total_count);
2414 va_end(var);
2415
2416 Va_start(var,w);
2417 args = ImCreateArgList(var, total_count);
2418 va_end(var);
2419
2420 XmImSetFocusValues(w, args, total_count);
2421 XtFree((char *)args);
2422 _XmAppUnlock(app);
2423 }
2424
2425 /*VARARGS*/
2426 void
XmImVaSetValues(Widget w,...)2427 XmImVaSetValues(Widget w,
2428 ... )
2429 {
2430 va_list var;
2431 int total_count;
2432 ArgList args;
2433 _XmWidgetToAppContext(w);
2434
2435 _XmAppLock(app);
2436 Va_start(var,w);
2437 ImCountVaList(var, &total_count);
2438 va_end(var);
2439
2440 Va_start(var,w);
2441 args = ImCreateArgList(var, total_count);
2442 va_end(var);
2443
2444 XmImSetValues(w, args, total_count);
2445 XtFree((char *)args);
2446 _XmAppUnlock(app);
2447 }
2448
2449
2450 static void
ImCountVaList(va_list var,int * total_count)2451 ImCountVaList(va_list var,
2452 int *total_count )
2453 {
2454 String attr;
2455
2456 *total_count = 0;
2457
2458 for(attr = va_arg(var, String); attr != NULL; attr = va_arg(var, String))
2459 {
2460 (void) va_arg(var, XPointer);
2461 ++(*total_count);
2462 }
2463 }
2464
2465 static ArgList
ImCreateArgList(va_list var,int total_count)2466 ImCreateArgList(va_list var,
2467 int total_count )
2468 {
2469 ArgList args = (ArgList)XtCalloc(total_count, sizeof(Arg));
2470 register int i;
2471
2472 assert(args || (total_count == 0));
2473 for (i = 0; i < total_count; i++)
2474 {
2475 args[i].name = va_arg(var,String);
2476 args[i].value = (XtArgVal)va_arg(var,XPointer);
2477 }
2478
2479 return args;
2480 }
2481
2482 /* Return the current xic info for a widget, or NULL. */
2483 static XmImXICInfo
get_current_xic(XmImDisplayInfo xim_info,Widget widget)2484 get_current_xic(XmImDisplayInfo xim_info,
2485 Widget widget)
2486 {
2487 XmImXICInfo xic_info;
2488
2489 if ((xim_info == NULL) ||
2490 (xim_info->current_xics == (XContext) 0))
2491 return NULL;
2492
2493 if (XFindContext(XtDisplay(widget), (XID) widget,
2494 xim_info->current_xics, (XPointer*) &xic_info) != 0)
2495 return NULL;
2496 else
2497 return xic_info;
2498 }
2499
2500 /* Set the current XIC for an unregistered widget. */
2501 static void
set_current_xic(XmImXICInfo xic_info,XmImDisplayInfo xim_info,Widget widget)2502 set_current_xic(XmImXICInfo xic_info,
2503 XmImDisplayInfo xim_info,
2504 Widget widget)
2505 {
2506 if (xic_info == NULL)
2507 return;
2508
2509 /* Record this widget as a reference to this XIC. */
2510 (void) add_ref(&xic_info->widget_refs, widget);
2511
2512 /* Set the current XIC for this widget. */
2513 if (xim_info->current_xics == (XContext) NULL)
2514 xim_info->current_xics = XUniqueContext();
2515 (void) XSaveContext(XtDisplay(widget), (XID) widget,
2516 xim_info->current_xics, (XPointer) xic_info);
2517 }
2518
2519 /* Unset the current XIC for a widget, freeing data as necesary. */
2520 static void
unset_current_xic(XmImXICInfo xic_info,XmImShellInfo im_info,XmImDisplayInfo xim_info,Widget widget)2521 unset_current_xic(XmImXICInfo xic_info,
2522 XmImShellInfo im_info,
2523 XmImDisplayInfo xim_info,
2524 Widget widget)
2525 {
2526 /* Remove the current xic for this widget. */
2527 assert(xim_info->current_xics != (XContext) 0);
2528 (void) XDeleteContext(XtDisplay(widget), (XID) widget,
2529 xim_info->current_xics);
2530 #ifdef FIX_1196
2531 if (im_info->current_widget == widget)
2532 im_info->current_widget = NULL;
2533 #endif
2534 /* Remove this widget as a reference to this XIC. */
2535 if (remove_ref(&xic_info->widget_refs, widget) == 0)
2536 {
2537 /* Remove this xic_info from the master list. */
2538 XmImXICInfo *ptr;
2539 for (ptr = &(im_info->iclist); *ptr != NULL; ptr = &((*ptr)->next))
2540 if (*ptr == xic_info)
2541 {
2542 *ptr = xic_info->next;
2543 break;
2544 }
2545 #ifndef FIX_1196
2546 if (im_info->current_widget == widget)
2547 im_info->current_widget = NULL;
2548 #endif
2549 /* Don't let anyone share this XIC. */
2550 if (xic_info->source != NULL)
2551 *(xic_info->source) = NULL;
2552
2553 /* Destroy the XIC */
2554 if ((xic_info->anonymous) && (xic_info->xic != NULL))
2555 XDestroyIC(xic_info->xic);
2556
2557 ImFreePreeditBuffer (xic_info->preedit_buffer);
2558 XtFree((char *) xic_info);
2559 }
2560 }
2561
2562 /* Add a widget to a list of references. */
2563 static Cardinal
add_ref(XmImRefInfo refs,Widget widget)2564 add_ref(XmImRefInfo refs,
2565 Widget widget)
2566 {
2567 #ifdef DEBUG
2568 /* Verify that we don't already have a reference. */
2569 register Cardinal index;
2570 for (index = 0; index < refs->num_refs; index++)
2571 assert(refs->refs[index] != widget);
2572 #endif
2573
2574 /* Make room in the array. */
2575 if (refs->num_refs == refs->max_refs)
2576 {
2577 if (refs->max_refs == 0)
2578 refs->max_refs = 10;
2579 else
2580 refs->max_refs += (refs->max_refs / 2);
2581
2582 refs->refs = (Widget*) XtRealloc((char *) refs->refs,
2583 refs->max_refs * sizeof(Widget));
2584 refs->callbacks = (XtPointer **) XtRealloc((char *) refs->callbacks,
2585 refs->max_refs * sizeof(XtPointer *));
2586 }
2587 assert(refs->num_refs < refs->max_refs);
2588
2589 refs->callbacks[refs->num_refs] = NULL;
2590
2591 /* Insert this reference. */
2592 refs->refs[refs->num_refs++] = widget;
2593
2594 return refs->num_refs;
2595 }
2596
2597 /* Remove a widget from a list of references. */
2598 static Cardinal
remove_ref(XmImRefInfo refs,Widget widget)2599 remove_ref(XmImRefInfo refs,
2600 Widget widget)
2601 {
2602 /* Is this the last reference? */
2603 refs->num_refs--;
2604 if (refs->num_refs > 0)
2605 {
2606 /* Just remove this reference. */
2607 int index = 0;
2608 while (index <= refs->num_refs) {
2609 if (refs->refs[index] == widget)
2610 {
2611 refs->refs[index] = refs->refs[refs->num_refs];
2612 refs->refs[refs->num_refs] = NULL;
2613 XtFree((char *)refs->callbacks[index]);
2614 refs->callbacks[index] = refs->callbacks[refs->num_refs];
2615 refs->callbacks[refs->num_refs] = NULL;
2616
2617 break;
2618 }
2619 index++;
2620 }
2621
2622 /* Free some storage from the array? */
2623 if ((refs->num_refs * 3 < refs->max_refs) &&
2624 (refs->max_refs >= 20))
2625 {
2626 refs->max_refs /= 2;
2627 refs->refs = (Widget*) XtRealloc((char *) refs->refs,
2628 refs->max_refs * sizeof(Widget));
2629 refs->callbacks = (XtPointer **) XtRealloc((char *) refs->callbacks,
2630 refs->max_refs * sizeof(XtPointer *));
2631 }
2632 }
2633 else
2634 {
2635 /* Free the references array. */
2636 XtFree((char *) refs->refs);
2637 refs->refs = NULL;
2638 XtFree((char *) refs->callbacks[0]);
2639 XtFree((char *) refs->callbacks);
2640 refs->callbacks = NULL;
2641 refs->max_refs = 0;
2642 }
2643
2644 return refs->num_refs;
2645 }
2646
2647 /* Convert a VaArgList into a true XVaNestedList. */
2648 static XVaNestedList
VaCopy(VaArgList list)2649 VaCopy(VaArgList list)
2650 {
2651 /* This is ugly, but it's a legal way to construct a nested */
2652 /* list whose length is unknown at compile time. If MAXARGS is */
2653 /* increased more parameter pairs should be added below. A */
2654 /* recursive approach would leak memory. */
2655 register Cardinal count = list->count;
2656 register VaArg *args = list->args;
2657
2658 #define VA_NAME(index) (index < count ? args[index].name : NULL)
2659 #define VA_VALUE(index) (index < count ? args[index].value : NULL)
2660
2661 assert(count <= 10);
2662 return XVaCreateNestedList(0,
2663 VA_NAME(0), VA_VALUE(0),
2664 VA_NAME(1), VA_VALUE(1),
2665 VA_NAME(2), VA_VALUE(2),
2666 VA_NAME(3), VA_VALUE(3),
2667 VA_NAME(4), VA_VALUE(4),
2668 VA_NAME(5), VA_VALUE(5),
2669 VA_NAME(6), VA_VALUE(6),
2670 VA_NAME(7), VA_VALUE(7),
2671 VA_NAME(8), VA_VALUE(8),
2672 VA_NAME(9), VA_VALUE(9),
2673 NULL);
2674
2675 #undef VA_NAME
2676 #undef VA_VALUE
2677 }
2678
2679 static void
VaSetArg(VaArgList list,char * name,XPointer value)2680 VaSetArg(VaArgList list,
2681 char *name,
2682 XPointer value)
2683 {
2684 if (list->max <= list->count)
2685 {
2686 list->max += 10;
2687 list->args = (VaArg*) XtRealloc((char*) list->args,
2688 list->max * sizeof(VaArg));
2689 }
2690
2691 list->args[list->count].name = name;
2692 list->args[list->count].value = value;
2693 list->count++;
2694 }
2695
2696
2697 void
XmImMbResetIC(Widget w,char ** mb)2698 XmImMbResetIC(
2699 Widget w,
2700 char **mb)
2701 {
2702 register XmImXICInfo icp;
2703 _XmWidgetToAppContext(w);
2704
2705 _XmAppLock(app);
2706
2707 *mb = NULL;
2708
2709 if ((icp = get_current_xic(get_xim_info(w), w)) == NULL ||
2710 icp->xic == NULL) {
2711 _XmAppUnlock(app);
2712 return;
2713 }
2714
2715 if (!(icp->input_style & XIMPreeditCallbacks)) {
2716 _XmAppUnlock(app);
2717 return;
2718 }
2719
2720 *mb = XmbResetIC(icp->xic);
2721 _XmAppUnlock(app);
2722 }
2723
2724 XIMResetState
XmImGetXICResetState(Widget w)2725 XmImGetXICResetState(Widget w)
2726 {
2727 XmImXICInfo icp;
2728 XIMResetState state = XIMInitialState;
2729 icp = get_current_xic(get_xim_info(w), w);
2730 if (icp != NULL && icp->xic != NULL)
2731 XGetICValues(icp->xic, XNResetState, &state, NULL);
2732 return state;
2733 }
2734