1 /*
2 * tkUnixEvent.c --
3 *
4 * This file implements an event source for X displays for the UNIX
5 * version of Tk.
6 *
7 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
8 *
9 * See the file "license.terms" for information on usage and redistribution of
10 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 */
12
13 #include "tkUnixInt.h"
14 #include <signal.h>
15 #ifdef HAVE_XKBKEYCODETOKEYSYM
16 # include <X11/XKBlib.h>
17 #else
18 # define XkbOpenDisplay(D,V,E,M,m,R) (((void)D),((void)V),((void)E),((void)M),((void)m),((void)R),(NULL))
19 #endif
20
21 /*
22 * The following static indicates whether this module has been initialized in
23 * the current thread.
24 */
25
26 typedef struct {
27 int initialized;
28 } ThreadSpecificData;
29 static Tcl_ThreadDataKey dataKey;
30
31 /*
32 * Prototypes for functions that are referenced only in this file:
33 */
34
35 static void DisplayCheckProc(ClientData clientData, int flags);
36 static void DisplayExitHandler(ClientData clientData);
37 static void DisplayFileProc(ClientData clientData, int flags);
38 static void DisplaySetupProc(ClientData clientData, int flags);
39 static void TransferXEventsToTcl(Display *display);
40 #ifdef TK_USE_INPUT_METHODS
41 static void InstantiateIMCallback(Display *, XPointer client_data, XPointer call_data);
42 static void DestroyIMCallback(XIM im, XPointer client_data, XPointer call_data);
43 static void OpenIM(TkDisplay *dispPtr);
44 #endif
45
46 /*
47 *----------------------------------------------------------------------
48 *
49 * TkCreateXEventSource --
50 *
51 * This function is called during Tk initialization to create the event
52 * source for X Window events.
53 *
54 * Results:
55 * None.
56 *
57 * Side effects:
58 * A new event source is created.
59 *
60 *----------------------------------------------------------------------
61 */
62
63 void
TkCreateXEventSource(void)64 TkCreateXEventSource(void)
65 {
66 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
67 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
68
69 if (!tsdPtr->initialized) {
70 tsdPtr->initialized = 1;
71 Tcl_CreateEventSource(DisplaySetupProc, DisplayCheckProc, NULL);
72 TkCreateExitHandler(DisplayExitHandler, NULL);
73 }
74 }
75
76 /*
77 *----------------------------------------------------------------------
78 *
79 * DisplayExitHandler --
80 *
81 * This function is called during finalization to clean up the display
82 * module.
83 *
84 * Results:
85 * None.
86 *
87 * Side effects:
88 * None.
89 *
90 *----------------------------------------------------------------------
91 */
92
93 static void
DisplayExitHandler(ClientData clientData)94 DisplayExitHandler(
95 ClientData clientData) /* Not used. */
96 {
97 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
98 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
99
100 Tcl_DeleteEventSource(DisplaySetupProc, DisplayCheckProc, NULL);
101 tsdPtr->initialized = 0;
102 }
103
104 /*
105 *----------------------------------------------------------------------
106 *
107 * TkpOpenDisplay --
108 *
109 * Allocates a new TkDisplay, opens the X display, and establishes the
110 * file handler for the connection.
111 *
112 * Results:
113 * A pointer to a Tk display structure.
114 *
115 * Side effects:
116 * Opens a display.
117 *
118 *----------------------------------------------------------------------
119 */
120
121 TkDisplay *
TkpOpenDisplay(const char * displayNameStr)122 TkpOpenDisplay(
123 const char *displayNameStr)
124 {
125 TkDisplay *dispPtr;
126 Display *display;
127 int event = 0;
128 int error = 0;
129 int major = 1;
130 int minor = 0;
131 int reason = 0;
132 unsigned int use_xkb = 0;
133 /* Disabled, until we have a better test. See [Bug 3613668] */
134 #if 0 && defined(XKEYCODETOKEYSYM_IS_DEPRECATED) && defined(TCL_THREADS)
135 static int xinited = 0;
136 static Tcl_Mutex xinitMutex = NULL;
137
138 if (!xinited) {
139 Tcl_MutexLock(&xinitMutex);
140 if (!xinited) {
141 /* Necessary for threaded apps, of no consequence otherwise */
142 /* need only be called once, but must be called before *any* */
143 /* Xlib call is made. If xinitMutex is still NULL after the */
144 /* Tcl_MutexLock call, Tcl was compiled without threads so */
145 /* we cannot use XInitThreads() either. */
146 if (xinitMutex != NULL){
147 XInitThreads();
148 }
149 xinited = 1;
150 }
151 Tcl_MutexUnlock(&xinitMutex);
152 }
153 #endif
154
155 /*
156 ** Bug [3607830]: Before using Xkb, it must be initialized and confirmed
157 ** that the serve supports it. The XkbOpenDisplay call
158 ** will perform this check and return NULL if the extension
159 ** is not supported.
160 **
161 ** Work around un-const-ified Xkb headers using (char *) cast.
162 */
163 display = XkbOpenDisplay((char *)displayNameStr, &event, &error, &major,
164 &minor, &reason);
165
166 if (display == NULL) {
167 /*fprintf(stderr,"event=%d error=%d major=%d minor=%d reason=%d\nDisabling xkb\n",
168 event, error, major, minor, reason);*/
169 display = XOpenDisplay(displayNameStr);
170 } else {
171 use_xkb = TK_DISPLAY_USE_XKB;
172 /*fprintf(stderr, "Using xkb %d.%d\n", major, minor);*/
173 }
174
175 if (display == NULL) {
176 return NULL;
177 }
178 dispPtr = ckalloc(sizeof(TkDisplay));
179 memset(dispPtr, 0, sizeof(TkDisplay));
180 dispPtr->display = display;
181 dispPtr->flags |= use_xkb;
182 #ifdef TK_USE_INPUT_METHODS
183 OpenIM(dispPtr);
184 XRegisterIMInstantiateCallback(dispPtr->display, NULL, NULL, NULL,
185 InstantiateIMCallback, (XPointer) dispPtr);
186 #endif
187 Tcl_CreateFileHandler(ConnectionNumber(display), TCL_READABLE,
188 DisplayFileProc, dispPtr);
189
190 /*
191 * Observed weird WidthMMOfScreen() in X on Wayland on a
192 * Fedora 30/i386 running in a VM. Fallback to 75 dpi,
193 * otherwise many other strange things may happen later.
194 * See: [https://core.tcl-lang.org/tk/tktview?name=a01b6f7227]
195 */
196 if (WidthMMOfScreen(DefaultScreenOfDisplay(display)) <= 0) {
197 int mm;
198
199 mm = WidthOfScreen(DefaultScreenOfDisplay(display)) * (25.4 / 75.0);
200 WidthMMOfScreen(DefaultScreenOfDisplay(display)) = mm;
201 }
202 if (HeightMMOfScreen(DefaultScreenOfDisplay(display)) <= 0) {
203 int mm;
204
205 mm = HeightOfScreen(DefaultScreenOfDisplay(display)) * (25.4 / 75.0);
206 HeightMMOfScreen(DefaultScreenOfDisplay(display)) = mm;
207 }
208
209 /*
210 * Key map info must be available immediately, because of "send event".
211 */
212 TkpInitKeymapInfo(dispPtr);
213
214 return dispPtr;
215 }
216
217 /*
218 *----------------------------------------------------------------------
219 *
220 * TkpCloseDisplay --
221 *
222 * Cancels notifier callbacks and closes a display.
223 *
224 * Results:
225 * None.
226 *
227 * Side effects:
228 * Deallocates the displayPtr and unix-specific resources.
229 *
230 *----------------------------------------------------------------------
231 */
232
233 void
TkpCloseDisplay(TkDisplay * dispPtr)234 TkpCloseDisplay(
235 TkDisplay *dispPtr)
236 {
237 TkSendCleanup(dispPtr);
238
239 TkWmCleanup(dispPtr);
240
241 #ifdef TK_USE_INPUT_METHODS
242 if (dispPtr->inputXfs) {
243 XFreeFontSet(dispPtr->display, dispPtr->inputXfs);
244 }
245 if (dispPtr->inputMethod) {
246 XCloseIM(dispPtr->inputMethod);
247 }
248 #endif
249
250 if (dispPtr->display != 0) {
251 Tcl_DeleteFileHandler(ConnectionNumber(dispPtr->display));
252 (void) XSync(dispPtr->display, False);
253 (void) XCloseDisplay(dispPtr->display);
254 }
255 }
256
257 /*
258 *----------------------------------------------------------------------
259 *
260 * TkClipCleanup --
261 *
262 * This function is called to cleanup resources associated with claiming
263 * clipboard ownership and for receiving selection get results. This
264 * function is called in tkWindow.c. This has to be called by the display
265 * cleanup function because we still need the access display elements.
266 *
267 * Results:
268 * None.
269 *
270 * Side effects:
271 * Resources are freed - the clipboard may no longer be used.
272 *
273 *----------------------------------------------------------------------
274 */
275
276 void
TkClipCleanup(TkDisplay * dispPtr)277 TkClipCleanup(
278 TkDisplay *dispPtr) /* Display associated with clipboard */
279 {
280 if (dispPtr->clipWindow != NULL) {
281 Tk_DeleteSelHandler(dispPtr->clipWindow, dispPtr->clipboardAtom,
282 dispPtr->applicationAtom);
283 Tk_DeleteSelHandler(dispPtr->clipWindow, dispPtr->clipboardAtom,
284 dispPtr->windowAtom);
285
286 Tk_DestroyWindow(dispPtr->clipWindow);
287 Tcl_Release(dispPtr->clipWindow);
288 dispPtr->clipWindow = NULL;
289 }
290 }
291
292 /*
293 *----------------------------------------------------------------------
294 *
295 * DisplaySetupProc --
296 *
297 * This function implements the setup part of the UNIX X display event
298 * source. It is invoked by Tcl_DoOneEvent before entering the notifier
299 * to check for events on all displays.
300 *
301 * Results:
302 * None.
303 *
304 * Side effects:
305 * If data is queued on a display inside Xlib, then the maximum block
306 * time will be set to 0 to ensure that the notifier returns control to
307 * Tcl even if there is no more data on the X connection.
308 *
309 *----------------------------------------------------------------------
310 */
311
312 static void
DisplaySetupProc(ClientData clientData,int flags)313 DisplaySetupProc(
314 ClientData clientData, /* Not used. */
315 int flags)
316 {
317 TkDisplay *dispPtr;
318 static Tcl_Time blockTime = { 0, 0 };
319
320 if (!(flags & TCL_WINDOW_EVENTS)) {
321 return;
322 }
323
324 for (dispPtr = TkGetDisplayList(); dispPtr != NULL;
325 dispPtr = dispPtr->nextPtr) {
326 /*
327 * Flush the display. If data is pending on the X queue, set the block
328 * time to zero. This ensures that we won't block in the notifier if
329 * there is data in the X queue, but not on the server socket.
330 */
331
332 XFlush(dispPtr->display);
333 if (QLength(dispPtr->display) > 0) {
334 Tcl_SetMaxBlockTime(&blockTime);
335 }
336 }
337 }
338
339 /*
340 *----------------------------------------------------------------------
341 *
342 * TransferXEventsToTcl --
343 *
344 * Transfer events from the X event queue to the Tk event queue.
345 *
346 * Results:
347 * None.
348 *
349 * Side effects:
350 * Moves queued X events onto the Tcl event queue.
351 *
352 *----------------------------------------------------------------------
353 */
354
355 static void
TransferXEventsToTcl(Display * display)356 TransferXEventsToTcl(
357 Display *display)
358 {
359 union {
360 int type;
361 XEvent x;
362 TkKeyEvent k;
363 } event;
364 Window w;
365 TkDisplay *dispPtr = NULL;
366
367 /*
368 * Transfer events from the X event queue to the Tk event queue after XIM
369 * event filtering. KeyPress and KeyRelease events need special treatment
370 * so that they get directed according to Tk's focus rules during XIM
371 * handling. Theoretically they can go to the wrong place still (if
372 * there's a focus change in the queue) but if we push the handling off
373 * until Tk_HandleEvent then many input methods actually cease to work
374 * correctly. Most of the time, Tk processes its event queue fast enough
375 * for this to not be an issue anyway. [Bug 1924761]
376 */
377
378 while (QLength(display) > 0) {
379 XNextEvent(display, &event.x);
380 if (event.type > MappingNotify) {
381 continue;
382 }
383 w = None;
384 if (event.type == KeyPress || event.type == KeyRelease) {
385 for (dispPtr = TkGetDisplayList(); ; dispPtr = dispPtr->nextPtr) {
386 if (dispPtr == NULL) {
387 break;
388 } else if (dispPtr->display == event.x.xany.display) {
389 if (dispPtr->focusPtr != NULL) {
390 w = dispPtr->focusPtr->window;
391 }
392 break;
393 }
394 }
395 }
396 if (XFilterEvent(&event.x, w)) {
397 continue;
398 }
399 if (event.type == KeyPress || event.type == KeyRelease) {
400 event.k.charValuePtr = NULL;
401 event.k.charValueLen = 0;
402 event.k.keysym = NoSymbol;
403
404 /*
405 * Force the calling of the input method engine now. The results
406 * from it will be cached in the event so that they don't get lost
407 * (to a race condition with other XIM-handled key events) between
408 * entering the event queue and getting serviced. [Bug 1924761]
409 */
410
411 #ifdef TK_USE_INPUT_METHODS
412 if (event.type == KeyPress && dispPtr &&
413 (dispPtr->flags & TK_DISPLAY_USE_IM)) {
414 if (dispPtr->focusPtr && dispPtr->focusPtr->inputContext) {
415 Tcl_DString ds;
416
417 Tcl_DStringInit(&ds);
418 (void) TkpGetString(dispPtr->focusPtr, &event.x, &ds);
419 Tcl_DStringFree(&ds);
420 }
421 }
422 #endif
423 }
424 Tk_QueueWindowEvent(&event.x, TCL_QUEUE_TAIL);
425 }
426 }
427
428 /*
429 *----------------------------------------------------------------------
430 *
431 * DisplayCheckProc --
432 *
433 * This function checks for events sitting in the X event queue.
434 *
435 * Results:
436 * None.
437 *
438 * Side effects:
439 * Moves queued events onto the Tcl event queue.
440 *
441 *----------------------------------------------------------------------
442 */
443
444 static void
DisplayCheckProc(ClientData clientData,int flags)445 DisplayCheckProc(
446 ClientData clientData, /* Not used. */
447 int flags)
448 {
449 TkDisplay *dispPtr;
450
451 if (!(flags & TCL_WINDOW_EVENTS)) {
452 return;
453 }
454
455 for (dispPtr = TkGetDisplayList(); dispPtr != NULL;
456 dispPtr = dispPtr->nextPtr) {
457 XFlush(dispPtr->display);
458 TransferXEventsToTcl(dispPtr->display);
459 }
460 }
461
462 /*
463 *----------------------------------------------------------------------
464 *
465 * DisplayFileProc --
466 *
467 * This function implements the file handler for the X connection.
468 *
469 * Results:
470 * None.
471 *
472 * Side effects:
473 * Makes entries on the Tcl event queue for all the events available from
474 * all the displays.
475 *
476 *----------------------------------------------------------------------
477 */
478
479 static void
DisplayFileProc(ClientData clientData,int flags)480 DisplayFileProc(
481 ClientData clientData, /* The display pointer. */
482 int flags) /* Should be TCL_READABLE. */
483 {
484 TkDisplay *dispPtr = (TkDisplay *) clientData;
485 Display *display = dispPtr->display;
486 int numFound;
487
488 XFlush(display);
489 numFound = XEventsQueued(display, QueuedAfterReading);
490 if (numFound == 0) {
491 /*
492 * Things are very tricky if there aren't any events readable at this
493 * point (after all, there was supposedly data available on the
494 * connection). A couple of things could have occurred:
495 *
496 * One possibility is that there were only error events in the input
497 * from the server. If this happens, we should return (we don't want
498 * to go to sleep in XNextEvent below, since this would block out
499 * other sources of input to the process).
500 *
501 * Another possibility is that our connection to the server has been
502 * closed. This will not necessarily be detected in XEventsQueued (!!)
503 * so if we just return then there will be an infinite loop. To detect
504 * such an error, generate a NoOp protocol request to exercise the
505 * connection to the server, then return. However, must disable
506 * SIGPIPE while sending the request, or else the process will die
507 * from the signal and won't invoke the X error function to print a
508 * nice (?!) message.
509 */
510
511 void (*oldHandler)(int);
512
513 oldHandler = (void (*)(int)) signal(SIGPIPE, SIG_IGN);
514 XNoOp(display);
515 XFlush(display);
516 (void) signal(SIGPIPE, oldHandler);
517 }
518
519 TransferXEventsToTcl(display);
520 }
521
522 /*
523 *----------------------------------------------------------------------
524 *
525 * TkUnixDoOneXEvent --
526 *
527 * This routine waits for an X event to be processed or for a timeout to
528 * occur. The timeout is specified as an absolute time. This routine is
529 * called when Tk needs to wait for a particular X event without letting
530 * arbitrary events be processed. The caller will typically call
531 * Tk_RestrictEvents to set up an event filter before calling this
532 * routine. This routine will service at most one event per invocation.
533 *
534 * Results:
535 * Returns 0 if the timeout has expired, otherwise returns 1.
536 *
537 * Side effects:
538 * Can invoke arbitrary Tcl scripts.
539 *
540 *----------------------------------------------------------------------
541 */
542
543 int
TkUnixDoOneXEvent(Tcl_Time * timePtr)544 TkUnixDoOneXEvent(
545 Tcl_Time *timePtr) /* Specifies the absolute time when the call
546 * should time out. */
547 {
548 TkDisplay *dispPtr;
549 static fd_mask readMask[MASK_SIZE];
550 struct timeval blockTime, *timeoutPtr;
551 Tcl_Time now;
552 int fd, index, numFound, numFdBits = 0;
553 fd_mask bit, *readMaskPtr = readMask;
554
555 /*
556 * Look for queued events first.
557 */
558
559 if (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {
560 return 1;
561 }
562
563 /*
564 * Compute the next block time and check to see if we have timed out. Note
565 * that HP-UX defines tv_sec to be unsigned so we have to be careful in
566 * our arithmetic.
567 */
568
569 if (timePtr) {
570 Tcl_GetTime(&now);
571 blockTime.tv_sec = timePtr->sec;
572 blockTime.tv_usec = timePtr->usec - now.usec;
573 if (blockTime.tv_usec < 0) {
574 now.sec += 1;
575 blockTime.tv_usec += 1000000;
576 }
577 if (blockTime.tv_sec < now.sec) {
578 blockTime.tv_sec = 0;
579 blockTime.tv_usec = 0;
580 } else {
581 blockTime.tv_sec -= now.sec;
582 }
583 timeoutPtr = &blockTime;
584 } else {
585 timeoutPtr = NULL;
586 }
587
588 /*
589 * Set up the select mask for all of the displays. If a display has data
590 * pending, then we want to poll instead of blocking.
591 */
592
593 memset(readMask, 0, MASK_SIZE*sizeof(fd_mask));
594 for (dispPtr = TkGetDisplayList(); dispPtr != NULL;
595 dispPtr = dispPtr->nextPtr) {
596 XFlush(dispPtr->display);
597 if (QLength(dispPtr->display) > 0) {
598 blockTime.tv_sec = 0;
599 blockTime.tv_usec = 0;
600 }
601 fd = ConnectionNumber(dispPtr->display);
602 index = fd/(NBBY*sizeof(fd_mask));
603 bit = ((fd_mask)1) << (fd%(NBBY*sizeof(fd_mask)));
604 readMask[index] |= bit;
605 if (numFdBits <= fd) {
606 numFdBits = fd+1;
607 }
608 }
609
610 numFound = select(numFdBits, (SELECT_MASK *) readMaskPtr, NULL, NULL,
611 timeoutPtr);
612 if (numFound <= 0) {
613 /*
614 * Some systems don't clear the masks after an error, so we have to do
615 * it here.
616 */
617
618 memset(readMask, 0, MASK_SIZE*sizeof(fd_mask));
619 }
620
621 /*
622 * Process any new events on the display connections.
623 */
624
625 for (dispPtr = TkGetDisplayList(); dispPtr != NULL;
626 dispPtr = dispPtr->nextPtr) {
627 fd = ConnectionNumber(dispPtr->display);
628 index = fd/(NBBY*sizeof(fd_mask));
629 bit = ((fd_mask)1) << (fd%(NBBY*sizeof(fd_mask)));
630 if ((readMask[index] & bit) || (QLength(dispPtr->display) > 0)) {
631 DisplayFileProc(dispPtr, TCL_READABLE);
632 }
633 }
634 if (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {
635 return 1;
636 }
637
638 /*
639 * Check to see if we timed out.
640 */
641
642 if (timePtr) {
643 Tcl_GetTime(&now);
644 if ((now.sec > timePtr->sec) || ((now.sec == timePtr->sec)
645 && (now.usec > timePtr->usec))) {
646 return 0;
647 }
648 }
649
650 /*
651 * We had an event but we did not generate a Tcl event from it. Behave as
652 * though we dealt with it. (JYL&SS)
653 */
654
655 return 1;
656 }
657
658 /*
659 *----------------------------------------------------------------------
660 *
661 * TkpSync --
662 *
663 * This routine ensures that all pending X requests have been seen by the
664 * server, and that any pending X events have been moved onto the Tk
665 * event queue.
666 *
667 * Results:
668 * None.
669 *
670 * Side effects:
671 * Places new events on the Tk event queue.
672 *
673 *----------------------------------------------------------------------
674 */
675
676 void
TkpSync(Display * display)677 TkpSync(
678 Display *display) /* Display to sync. */
679 {
680 XSync(display, False);
681
682 /*
683 * Transfer events from the X event queue to the Tk event queue.
684 */
685
686 TransferXEventsToTcl(display);
687 }
688 #ifdef TK_USE_INPUT_METHODS
689
690 static void
InstantiateIMCallback(Display * display,XPointer client_data,XPointer call_data)691 InstantiateIMCallback(
692 Display *display,
693 XPointer client_data,
694 XPointer call_data)
695 {
696 TkDisplay *dispPtr;
697
698 dispPtr = (TkDisplay *) client_data;
699 OpenIM(dispPtr);
700 XUnregisterIMInstantiateCallback(dispPtr->display, NULL, NULL, NULL,
701 InstantiateIMCallback, (XPointer) dispPtr);
702 }
703
704 static void
DestroyIMCallback(XIM im,XPointer client_data,XPointer call_data)705 DestroyIMCallback(
706 XIM im,
707 XPointer client_data,
708 XPointer call_data)
709 {
710 TkDisplay *dispPtr;
711
712 dispPtr = (TkDisplay *) client_data;
713 dispPtr->inputMethod = NULL;
714 ++dispPtr->ximGeneration;
715 XRegisterIMInstantiateCallback(dispPtr->display, NULL, NULL, NULL,
716 InstantiateIMCallback, (XPointer) dispPtr);
717 }
718
719 /*
720 *--------------------------------------------------------------
721 *
722 * OpenIM --
723 *
724 * Tries to open an X input method associated with the given display.
725 *
726 * Results:
727 * Stores the input method in dispPtr->inputMethod; if there isn't a
728 * suitable input method, then NULL is stored in dispPtr->inputMethod.
729 *
730 * Side effects:
731 * An input method gets opened.
732 *
733 *--------------------------------------------------------------
734 */
735
736 static void
OpenIM(TkDisplay * dispPtr)737 OpenIM(
738 TkDisplay *dispPtr) /* Tk's structure for the display. */
739 {
740 int i;
741 XIMStyles *stylePtr;
742 XIMStyle bestStyle = 0;
743
744 if (XSetLocaleModifiers("") == NULL) {
745 return;
746 }
747
748 ++dispPtr->ximGeneration;
749 dispPtr->inputMethod = XOpenIM(dispPtr->display, NULL, NULL, NULL);
750 if (dispPtr->inputMethod == NULL) {
751 return;
752 }
753
754 /* Require X11R6 */
755 {
756 XIMCallback destroy_cb;
757
758 destroy_cb.callback = DestroyIMCallback;
759 destroy_cb.client_data = (XPointer) dispPtr;
760 if (XSetIMValues(dispPtr->inputMethod, XNDestroyCallback,
761 &destroy_cb, NULL))
762 goto error;
763 }
764
765 if ((XGetIMValues(dispPtr->inputMethod, XNQueryInputStyle, &stylePtr,
766 NULL) != NULL) || (stylePtr == NULL)) {
767 goto error;
768 }
769
770 /*
771 * Select the best input style supported by both the IM and Tk.
772 */
773 for (i = 0; i < stylePtr->count_styles; i++) {
774 XIMStyle thisStyle = stylePtr->supported_styles[i];
775 if (thisStyle == (XIMPreeditPosition | XIMStatusNothing)) {
776 bestStyle = thisStyle;
777 break;
778 } else if (thisStyle == (XIMPreeditNothing | XIMStatusNothing)) {
779 bestStyle = thisStyle;
780 }
781 }
782 XFree(stylePtr);
783 if (bestStyle == 0) {
784 goto error;
785 }
786
787 dispPtr->inputStyle = bestStyle;
788
789 /*
790 * Create an XFontSet for preedit area.
791 */
792 if (dispPtr->inputStyle & XIMPreeditPosition) {
793 char **missing_list;
794 int missing_count;
795 char *def_string;
796
797 dispPtr->inputXfs = XCreateFontSet(dispPtr->display,
798 "-*-*-*-R-Normal--14-130-75-75-*-*",
799 &missing_list, &missing_count, &def_string);
800 if (missing_count > 0) {
801 XFreeStringList(missing_list);
802 }
803 }
804
805 return;
806
807 error:
808 if (dispPtr->inputMethod) {
809 XCloseIM(dispPtr->inputMethod);
810 dispPtr->inputMethod = NULL;
811 ++dispPtr->ximGeneration;
812 }
813 }
814 #endif /* TK_USE_INPUT_METHODS */
815
816 void
TkpWarpPointer(TkDisplay * dispPtr)817 TkpWarpPointer(
818 TkDisplay *dispPtr)
819 {
820 Window w; /* Which window to warp relative to. */
821
822 if (dispPtr->warpWindow != NULL) {
823 w = Tk_WindowId(dispPtr->warpWindow);
824 } else {
825 w = RootWindow(dispPtr->display,
826 Tk_ScreenNumber(dispPtr->warpMainwin));
827 }
828 XWarpPointer(dispPtr->display, None, w, 0, 0, 0, 0,
829 (int) dispPtr->warpX, (int) dispPtr->warpY);
830 }
831
832 /*
833 * Local Variables:
834 * mode: c
835 * c-basic-offset: 4
836 * fill-column: 78
837 * End:
838 */
839