summaryrefslogtreecommitdiffstats
path: root/unix/tkUnixFocus.c
diff options
context:
space:
mode:
Diffstat (limited to 'unix/tkUnixFocus.c')
-rw-r--r--unix/tkUnixFocus.c149
1 files changed, 149 insertions, 0 deletions
diff --git a/unix/tkUnixFocus.c b/unix/tkUnixFocus.c
new file mode 100644
index 0000000..5c1a4f6
--- /dev/null
+++ b/unix/tkUnixFocus.c
@@ -0,0 +1,149 @@
+/*
+ * tkUnixFocus.c --
+ *
+ * This file contains platform specific procedures that manage
+ * focus for Tk.
+ *
+ * Copyright (c) 1997 Sun Microsystems, Inc.
+ *
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
+ * SCCS: @(#) tkUnixFocus.c 1.9 97/10/31 09:54:04
+ */
+
+#include "tkInt.h"
+#include "tkPort.h"
+#include "tkUnixInt.h"
+
+extern int tclFocusDebug;
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkpChangeFocus --
+ *
+ * This procedure is invoked to move the official X focus from
+ * one window to another.
+ *
+ * Results:
+ * The return value is the serial number of the command that
+ * changed the focus. It may be needed by the caller to filter
+ * out focus change events that were queued before the command.
+ * If the procedure doesn't actually change the focus then
+ * it returns 0.
+ *
+ * Side effects:
+ * The official X focus window changes; the application's focus
+ * window isn't changed by this procedure.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TkpChangeFocus(winPtr, force)
+ TkWindow *winPtr; /* Window that is to receive the X focus. */
+ int force; /* Non-zero means claim the focus even
+ * if it didn't originally belong to
+ * topLevelPtr's application. */
+{
+ TkDisplay *dispPtr = winPtr->dispPtr;
+ Tk_ErrorHandler errHandler;
+ Window window, root, parent, *children;
+ unsigned int numChildren, serial;
+ TkWindow *winPtr2;
+ int dummy;
+
+ /*
+ * Don't set the X focus to a window that's marked
+ * override-redirect. This is a hack to avoid problems with menus
+ * under olvwm: if we move the focus then the focus can get lost
+ * during keyboard traversal. Fortunately, we don't really need to
+ * move the focus for menus: events will still find their way to the
+ * focus window, and menus aren't decorated anyway so the window
+ * manager doesn't need to hear about the focus change in order to
+ * redecorate the menu.
+ */
+
+ serial = 0;
+ if (winPtr->atts.override_redirect) {
+ return serial;
+ }
+
+ /*
+ * Check to make sure that the focus is still in one of the windows
+ * of this application or one of their descendants. Furthermore,
+ * grab the server to make sure that the focus doesn't change in the
+ * middle of this operation.
+ */
+
+ XGrabServer(dispPtr->display);
+ if (!force) {
+ /*
+ * Find the focus window, then see if it or one of its ancestors
+ * is a window in our application (it's possible that the focus
+ * window is in an embedded application, which may or may not be
+ * in the same process.
+ */
+
+ XGetInputFocus(dispPtr->display, &window, &dummy);
+ while (1) {
+ winPtr2 = (TkWindow *) Tk_IdToWindow(dispPtr->display, window);
+ if ((winPtr2 != NULL) && (winPtr2->mainPtr == winPtr->mainPtr)) {
+ break;
+ }
+ if ((window == PointerRoot) || (window == None)) {
+ goto done;
+ }
+ XQueryTree(dispPtr->display, window, &root, &parent, &children,
+ &numChildren);
+ if (children != NULL) {
+ XFree((void *) children);
+ }
+ if (parent == root) {
+ goto done;
+ }
+ window = parent;
+ }
+ }
+
+ /*
+ * Tell X to change the focus. Ignore errors that occur when changing
+ * the focus: it is still possible that the window we're focussing
+ * to could have gotten unmapped, which will generate an error.
+ */
+
+ errHandler = Tk_CreateErrorHandler(dispPtr->display, -1, -1, -1,
+ (Tk_ErrorProc *) NULL, (ClientData) NULL);
+ if (winPtr->window == None) {
+ panic("ChangeXFocus got null X window");
+ }
+ XSetInputFocus(dispPtr->display, winPtr->window, RevertToParent,
+ CurrentTime);
+ Tk_DeleteErrorHandler(errHandler);
+
+ /*
+ * Remember the current serial number for the X server and issue
+ * a dummy server request. This marks the position at which we
+ * changed the focus, so we can distinguish FocusIn and FocusOut
+ * events on either side of the mark.
+ */
+
+ serial = NextRequest(winPtr->display);
+ XNoOp(winPtr->display);
+
+ done:
+ XUngrabServer(dispPtr->display);
+
+ /*
+ * After ungrabbing the server, it's important to flush the output
+ * immediately so that the server sees the ungrab command. Otherwise
+ * we might do something else that needs to communicate with the
+ * server (such as invoking a subprocess that needs to do I/O to
+ * the screen); if the ungrab command is still sitting in our
+ * output buffer, we could deadlock.
+ */
+
+ XFlush(dispPtr->display);
+ return serial;
+}