1/* 2 * tkUnixFocus.c -- 3 * 4 * This file contains platform specific functions that manage focus for 5 * Tk. 6 * 7 * Copyright (c) 1997 Sun Microsystems, Inc. 8 * 9 * See the file "license.terms" for information on usage and redistribution 10 * of this file, and for a DISCLAIMER OF ALL WARRANTIES. 11 * 12 * RCS: @(#) $Id$ 13 */ 14 15#include "tkUnixInt.h" 16 17 18/* 19 *---------------------------------------------------------------------- 20 * 21 * TkpChangeFocus -- 22 * 23 * This function is invoked to move the official X focus from one window 24 * to another. 25 * 26 * Results: 27 * The return value is the serial number of the command that changed the 28 * focus. It may be needed by the caller to filter out focus change 29 * events that were queued before the command. If the function doesn't 30 * actually change the focus then it returns 0. 31 * 32 * Side effects: 33 * The official X focus window changes; the application's focus window 34 * isn't changed by this function. 35 * 36 *---------------------------------------------------------------------- 37 */ 38 39int 40TkpChangeFocus( 41 TkWindow *winPtr, /* Window that is to receive the X focus. */ 42 int force) /* Non-zero means claim the focus even if it 43 * didn't originally belong to topLevelPtr's 44 * application. */ 45{ 46 TkDisplay *dispPtr = winPtr->dispPtr; 47 Tk_ErrorHandler errHandler; 48 Window window, root, parent, *children; 49 unsigned int numChildren, serial; 50 TkWindow *winPtr2; 51 int dummy; 52 53 /* 54 * Don't set the X focus to a window that's marked override-redirect. 55 * This is a hack to avoid problems with menus under olvwm: if we move 56 * the focus then the focus can get lost during keyboard traversal. 57 * Fortunately, we don't really need to move the focus for menus: events 58 * will still find their way to the focus window, and menus aren't 59 * decorated anyway so the window manager doesn't need to hear about the 60 * focus change in order to redecorate the menu. 61 */ 62 63 serial = 0; 64 if (winPtr->atts.override_redirect) { 65 return serial; 66 } 67 68 /* 69 * Check to make sure that the focus is still in one of the windows of 70 * this application or one of their descendants. Furthermore, grab the 71 * server to make sure that the focus doesn't change in the middle of this 72 * operation. 73 */ 74 75 XGrabServer(dispPtr->display); 76 if (!force) { 77 /* 78 * Find the focus window, then see if it or one of its ancestors is a 79 * window in our application (it's possible that the focus window is 80 * in an embedded application, which may or may not be in the same 81 * process. 82 */ 83 84 XGetInputFocus(dispPtr->display, &window, &dummy); 85 while (1) { 86 winPtr2 = (TkWindow *) Tk_IdToWindow(dispPtr->display, window); 87 if ((winPtr2 != NULL) && (winPtr2->mainPtr == winPtr->mainPtr)) { 88 break; 89 } 90 if ((window == PointerRoot) || (window == None)) { 91 goto done; 92 } 93 XQueryTree(dispPtr->display, window, &root, &parent, &children, 94 &numChildren); 95 if (children != NULL) { 96 XFree((void *) children); 97 } 98 if (parent == root) { 99 goto done; 100 } 101 window = parent; 102 } 103 } 104 105 /* 106 * Tell X to change the focus. Ignore errors that occur when changing the 107 * focus: it is still possible that the window we're focussing to could 108 * have gotten unmapped, which will generate an error. 109 */ 110 111 errHandler = Tk_CreateErrorHandler(dispPtr->display, -1,-1,-1, NULL,NULL); 112 if (winPtr->window == None) { 113 Tcl_Panic("ChangeXFocus got null X window"); 114 } 115 XSetInputFocus(dispPtr->display, winPtr->window, RevertToParent, 116 CurrentTime); 117 Tk_DeleteErrorHandler(errHandler); 118 119 /* 120 * Remember the current serial number for the X server and issue a dummy 121 * server request. This marks the position at which we changed the focus, 122 * so we can distinguish FocusIn and FocusOut events on either side of the 123 * mark. 124 */ 125 126 serial = NextRequest(winPtr->display); 127 XNoOp(winPtr->display); 128 129 done: 130 XUngrabServer(dispPtr->display); 131 132 /* 133 * After ungrabbing the server, it's important to flush the output 134 * immediately so that the server sees the ungrab command. Otherwise we 135 * might do something else that needs to communicate with the server (such 136 * as invoking a subprocess that needs to do I/O to the screen); if the 137 * ungrab command is still sitting in our output buffer, we could 138 * deadlock. 139 */ 140 141 XFlush(dispPtr->display); 142 return serial; 143} 144 145/* 146 * Local Variables: 147 * mode: c 148 * c-basic-offset: 4 149 * fill-column: 78 150 * End: 151 */ 152