📄 tkfocus.c
字号:
/* * tkFocus.c -- * * This file contains procedures that manage the input * focus for Tk. * * Copyright (c) 1990-1994 The Regents of the University of California. * Copyright (c) 1994-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: @(#) tkFocus.c 1.48 97/10/31 09:55:22 */#include "tkInt.h"#include "tkPort.h"/* * For each top-level window that has ever received the focus, there * is a record of the following type: */typedef struct TkToplevelFocusInfo { TkWindow *topLevelPtr; /* Information about top-level window. */ TkWindow *focusWinPtr; /* The next time the focus comes to this * top-level, it will be given to this * window. */ struct TkToplevelFocusInfo *nextPtr; /* Next in list of all toplevel focus records * for a given application. */} ToplevelFocusInfo;/* * One of the following structures exists for each display used by * each application. These are linked together from the TkMainInfo * structure. These structures are needed because it isn't * sufficient to store a single piece of focus information in each * display or in each application: we need the cross-product. * There needs to be separate information for each display, because * it's possible to have multiple focus windows active simultaneously * on different displays. There also needs to be separate information * for each application, because of embedding: if an embedded * application has the focus, its container application also has * the focus. Thus we keep a list of structures for each application: * the same display can appear in structures for several applications * at once. */typedef struct TkDisplayFocusInfo { TkDisplay *dispPtr; /* Display that this information pertains * to. */ struct TkWindow *focusWinPtr; /* Window that currently has the focus for * this application on this display, or NULL * if none. */ struct TkWindow *focusOnMapPtr; /* This points to a toplevel window that is * supposed to receive the X input focus as * soon as it is mapped (needed to handle the * fact that X won't allow the focus on an * unmapped window). NULL means no delayed * focus op in progress for this display. */ int forceFocus; /* Associated with focusOnMapPtr: non-zero * means claim the focus even if some other * application currently has it. */ unsigned long focusSerial; /* Serial number of last request this * application made to change the focus on * this display. Used to identify stale * focus notifications coming from the * X server. */ struct TkDisplayFocusInfo *nextPtr; /* Next in list of all display focus * records for a given application. */} DisplayFocusInfo;/* * Global used for debugging. */int tclFocusDebug = 0;/* * The following magic value is stored in the "send_event" field of * FocusIn and FocusOut events that are generated in this file. This * allows us to separate "real" events coming from the server from * those that we generated. */#define GENERATED_EVENT_MAGIC ((Bool) 0x547321ac)/* * Forward declarations for procedures defined in this file: */static DisplayFocusInfo *FindDisplayFocusInfo _ANSI_ARGS_((TkMainInfo *mainPtr, TkDisplay *dispPtr));static void FocusMapProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr));static void GenerateFocusEvents _ANSI_ARGS_((TkWindow *sourcePtr, TkWindow *destPtr));static void SetFocus _ANSI_ARGS_((TkWindow *winPtr, int force));/* *-------------------------------------------------------------- * * Tk_FocusCmd -- * * This procedure is invoked to process the "focus" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */intTk_FocusCmd(clientData, interp, argc, argv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */{ Tk_Window tkwin = (Tk_Window) clientData; TkWindow *winPtr = (TkWindow *) clientData; TkWindow *newPtr, *focusWinPtr, *topLevelPtr; ToplevelFocusInfo *tlFocusPtr; char c; size_t length; /* * If invoked with no arguments, just return the current focus window. */ if (argc == 1) { focusWinPtr = TkGetFocusWin(winPtr); if (focusWinPtr != NULL) { interp->result = focusWinPtr->pathName; } return TCL_OK; } /* * If invoked with a single argument beginning with "." then focus * on that window. */ if (argc == 2) { if (argv[1][0] == 0) { return TCL_OK; } if (argv[1][0] == '.') { newPtr = (TkWindow *) Tk_NameToWindow(interp, argv[1], tkwin); if (newPtr == NULL) { return TCL_ERROR; } if (!(newPtr->flags & TK_ALREADY_DEAD)) { SetFocus(newPtr, 0); } return TCL_OK; } } length = strlen(argv[1]); c = argv[1][1]; if ((c == 'd') && (strncmp(argv[1], "-displayof", length) == 0)) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " -displayof window\"", (char *) NULL); return TCL_ERROR; } newPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin); if (newPtr == NULL) { return TCL_ERROR; } newPtr = TkGetFocusWin(newPtr); if (newPtr != NULL) { interp->result = newPtr->pathName; } } else if ((c == 'f') && (strncmp(argv[1], "-force", length) == 0)) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " -force window\"", (char *) NULL); return TCL_ERROR; } if (argv[2][0] == 0) { return TCL_OK; } newPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin); if (newPtr == NULL) { return TCL_ERROR; } SetFocus(newPtr, 1); } else if ((c == 'l') && (strncmp(argv[1], "-lastfor", length) == 0)) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " -lastfor window\"", (char *) NULL); return TCL_ERROR; } newPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin); if (newPtr == NULL) { return TCL_ERROR; } for (topLevelPtr = newPtr; topLevelPtr != NULL; topLevelPtr = topLevelPtr->parentPtr) { if (topLevelPtr->flags & TK_TOP_LEVEL) { for (tlFocusPtr = newPtr->mainPtr->tlFocusPtr; tlFocusPtr != NULL; tlFocusPtr = tlFocusPtr->nextPtr) { if (tlFocusPtr->topLevelPtr == topLevelPtr) { interp->result = tlFocusPtr->focusWinPtr->pathName; return TCL_OK; } } interp->result = topLevelPtr->pathName; return TCL_OK; } } } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": must be -displayof, -force, or -lastfor", (char *) NULL); return TCL_ERROR; } return TCL_OK;}/* *-------------------------------------------------------------- * * TkFocusFilterEvent -- * * This procedure is invoked by Tk_HandleEvent when it encounters * a FocusIn, FocusOut, Enter, or Leave event. * * Results: * A return value of 1 means that Tk_HandleEvent should process * the event normally (i.e. event handlers should be invoked). * A return value of 0 means that this event should be ignored. * * Side effects: * Additional events may be generated, and the focus may switch. * *-------------------------------------------------------------- */intTkFocusFilterEvent(winPtr, eventPtr) TkWindow *winPtr; /* Window that focus event is directed to. */ XEvent *eventPtr; /* FocusIn, FocusOut, Enter, or Leave * event. */{ /* * Design notes: the window manager and X server work together to * transfer the focus among top-level windows. This procedure takes * care of transferring the focus from a top-level or wrapper window * to the actual window within that top-level that has the focus. * We do this by synthesizing X events to move the focus around. * None of the FocusIn and FocusOut events generated by X are ever * used outside of this procedure; only the synthesized events get * through to the rest of the application. At one point (e.g. * Tk4.0b1) Tk used to call X to move the focus from a top-level to * one of its descendants, then just pass through the events * generated by X. This approach didn't work very well, for a * variety of reasons. For example, if X generates the events they * go at the back of the event queue, which could cause problems if * other things have already happened, such as moving the focus to * yet another window. */ ToplevelFocusInfo *tlFocusPtr; DisplayFocusInfo *displayFocusPtr; TkDisplay *dispPtr = winPtr->dispPtr; TkWindow *newFocusPtr; int retValue, delta; /* * If this was a generated event, just turn off the generated * flag and pass the event through to Tk bindings. */ if (eventPtr->xfocus.send_event == GENERATED_EVENT_MAGIC) { eventPtr->xfocus.send_event = 0; return 1; } /* * Check for special events generated by embedded applications to * request the input focus. If this is one of those events, make * the change in focus and return without any additional processing * of the event (note: the "detail" field of the event indicates * whether to claim the focus even if we don't already have it). */ if ((eventPtr->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS) && (eventPtr->type == FocusIn)) { SetFocus(winPtr, eventPtr->xfocus.detail); return 0; } /* * This was not a generated event. We'll return 1 (so that the * event will be processed) if it's an Enter or Leave event, and * 0 (so that the event won't be processed) if it's a FocusIn or * FocusOut event. */ retValue = 0; displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr); if (eventPtr->type == FocusIn) { /* * Skip FocusIn events that cause confusion * NotifyVirtual and NotifyNonlinearVirtual - Virtual events occur * on windows in between the origin and destination of the * focus change. For FocusIn we may see this when focus * goes into an embedded child. We don't care about this, * although we may end up getting a NotifyPointer later. * NotifyInferior - focus is coming to us from an embedded child. * When focus is on an embeded focus, we still think we have * the focus, too, so this message doesn't change our state. * NotifyPointerRoot - should never happen because this is sent * to the root window. * * Interesting FocusIn events are * NotifyAncestor - focus is coming from our parent, probably the root. * NotifyNonlinear - focus is coming from a different branch, probably * another toplevel. * NotifyPointer - implicit focus because of the mouse position. * This is only interesting on toplevels, when it means that the * focus has been set to the root window but the mouse is over
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -