📄 tkgrab.c
字号:
TkDisplay *dispPtr = winPtr->dispPtr; if (dispPtr->eventualGrabWinPtr == winPtr) { /* * Grab window was deleted. Release the grab. */ Tk_Ungrab((Tk_Window) dispPtr->eventualGrabWinPtr); } else if (dispPtr->buttonWinPtr == winPtr) { ReleaseButtonGrab(dispPtr); } if (dispPtr->serverWinPtr == winPtr) { if (winPtr->flags & TK_TOP_LEVEL) { dispPtr->serverWinPtr = NULL; } else { dispPtr->serverWinPtr = winPtr->parentPtr; } } if (dispPtr->grabWinPtr == winPtr) { dispPtr->grabWinPtr = NULL; }}/* *---------------------------------------------------------------------- * * EatGrabEvents -- * * This procedure is called to eliminate any Enter, Leave, * FocusIn, or FocusOut events in the event queue for a * display that have mode NotifyGrab or NotifyUngrab and * have a serial number no less than a given value and are not * generated by the grab module. * * Results: * None. * * Side effects: * DispPtr's display gets sync-ed, and some of the events get * removed from the Tk event queue. * *---------------------------------------------------------------------- */static voidEatGrabEvents(dispPtr, serial) TkDisplay *dispPtr; /* Display from which to consume events. */ unsigned int serial; /* Only discard events that have a serial * number at least this great. */{ Tk_RestrictProc *oldProc; GrabInfo info; ClientData oldArg, dummy; info.display = dispPtr->display; info.serial = serial; TkpSync(info.display); oldProc = Tk_RestrictEvents(GrabRestrictProc, (ClientData)&info, &oldArg); while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) { } Tk_RestrictEvents(oldProc, oldArg, &dummy);}/* *---------------------------------------------------------------------- * * GrabRestrictProc -- * * A Tk_RestrictProc used by EatGrabEvents to eliminate any * Enter, Leave, FocusIn, or FocusOut events in the event queue * for a display that has mode NotifyGrab or NotifyUngrab and * have a serial number no less than a given value. * * Results: * Returns either TK_DISCARD_EVENT or TK_DEFER_EVENT. * * Side effects: * None. * *---------------------------------------------------------------------- */static Tk_RestrictActionGrabRestrictProc(arg, eventPtr) ClientData arg; XEvent *eventPtr;{ GrabInfo *info = (GrabInfo *) arg; int mode, diff; /* * The diff caculation is trickier than it may seem. Don't forget * that serial numbers can wrap around, so can't compare the two * serial numbers directly. */ diff = eventPtr->xany.serial - info->serial; if ((eventPtr->type == EnterNotify) || (eventPtr->type == LeaveNotify)) { mode = eventPtr->xcrossing.mode; } else if ((eventPtr->type == FocusIn) || (eventPtr->type == FocusOut)) { mode = eventPtr->xfocus.mode; } else { mode = NotifyNormal; } if ((info->display != eventPtr->xany.display) || (mode == NotifyNormal) || (diff < 0)) { return TK_DEFER_EVENT; } else { return TK_DISCARD_EVENT; }}/* *---------------------------------------------------------------------- * * QueueGrabWindowChange -- * * This procedure queues a special event in the Tcl event queue, * which will cause the "grabWinPtr" field for the display to get * modified when the event is processed. This is needed to make * sure that the grab window changes at the proper time relative * to grab-related enter and leave events that are also in the * queue. In particular, this approach works even when multiple * grabs and ungrabs happen back-to-back. * * Results: * None. * * Side effects: * DispPtr->grabWinPtr will be modified later (by GrabWinEventProc) * when the event is removed from the grab event queue. * *---------------------------------------------------------------------- */static voidQueueGrabWindowChange(dispPtr, grabWinPtr) TkDisplay *dispPtr; /* Display on which to change the grab * window. */ TkWindow *grabWinPtr; /* Window that is to become the new grab * window (may be NULL). */{ NewGrabWinEvent *grabEvPtr; grabEvPtr = (NewGrabWinEvent *) ckalloc(sizeof(NewGrabWinEvent)); grabEvPtr->header.proc = GrabWinEventProc; grabEvPtr->dispPtr = dispPtr; if (grabWinPtr == NULL) { grabEvPtr->grabWindow = None; } else { grabEvPtr->grabWindow = grabWinPtr->window; } Tcl_QueueEvent(&grabEvPtr->header, TCL_QUEUE_MARK); dispPtr->eventualGrabWinPtr = grabWinPtr;}/* *---------------------------------------------------------------------- * * GrabWinEventProc -- * * This procedure is invoked as a handler for Tcl_Events of type * NewGrabWinEvent. It updates the current grab window field in * a display. * * Results: * Returns 1 if the event was processed, 0 if it should be deferred * for processing later. * * Side effects: * The grabWinPtr field is modified in the display associated with * the event. * *---------------------------------------------------------------------- */static intGrabWinEventProc(evPtr, flags) Tcl_Event *evPtr; /* Event of type NewGrabWinEvent. */ int flags; /* Flags argument to Tk_DoOneEvent: indicates * what kinds of events are being processed * right now. */{ NewGrabWinEvent *grabEvPtr = (NewGrabWinEvent *) evPtr; grabEvPtr->dispPtr->grabWinPtr = (TkWindow *) Tk_IdToWindow( grabEvPtr->dispPtr->display, grabEvPtr->grabWindow); return 1;}/* *---------------------------------------------------------------------- * * FindCommonAncestor -- * * Given two windows, this procedure finds their least common * ancestor and also computes how many levels up this ancestor * is from each of the original windows. * * Results: * If the windows are in different applications or top-level * windows, then NULL is returned and *countPtr1 and *countPtr2 * are set to the depths of the two windows in their respective * top-level windows (1 means the window is a top-level, 2 means * its parent is a top-level, and so on). Otherwise, the return * value is a pointer to the common ancestor and the counts are * set to the distance of winPtr1 and winPtr2 from this ancestor * (1 means they're children, 2 means grand-children, etc.). * * Side effects: * None. * *---------------------------------------------------------------------- */static TkWindow *FindCommonAncestor(winPtr1, winPtr2, countPtr1, countPtr2) TkWindow *winPtr1; /* First window. May be NULL. */ TkWindow *winPtr2; /* Second window. May be NULL. */ int *countPtr1; /* Store nesting level of winPtr1 within * common ancestor here. */ int *countPtr2; /* Store nesting level of winPtr2 within * common ancestor here. */{ register TkWindow *winPtr; TkWindow *ancestorPtr; int count1, count2, i; /* * Mark winPtr1 and all of its ancestors with a special flag bit. */ if (winPtr1 != NULL) { for (winPtr = winPtr1; winPtr != NULL; winPtr = winPtr->parentPtr) { winPtr->flags |= TK_GRAB_FLAG; if (winPtr->flags & TK_TOP_LEVEL) { break; } } } /* * Search upwards from winPtr2 until an ancestor of winPtr1 is * found or a top-level window is reached. */ winPtr = winPtr2; count2 = 0; ancestorPtr = NULL; if (winPtr2 != NULL) { for (; winPtr != NULL; count2++, winPtr = winPtr->parentPtr) { if (winPtr->flags & TK_GRAB_FLAG) { ancestorPtr = winPtr; break; } if (winPtr->flags & TK_TOP_LEVEL) { count2++; break; } } } /* * Search upwards from winPtr1 again, clearing the flag bits and * remembering how many levels up we had to go. */ if (winPtr1 == NULL) { count1 = 0; } else { count1 = -1; for (i = 0, winPtr = winPtr1; winPtr != NULL; i++, winPtr = winPtr->parentPtr) { winPtr->flags &= ~TK_GRAB_FLAG; if (winPtr == ancestorPtr) { count1 = i; } if (winPtr->flags & TK_TOP_LEVEL) { if (count1 == -1) { count1 = i+1; } break; } } } *countPtr1 = count1; *countPtr2 = count2; return ancestorPtr;}/* *---------------------------------------------------------------------- * * TkPositionInTree -- * * Compute where the given window is relative to a particular * subtree of the window hierarchy. * * Results: * * Returns TK_GRAB_IN_TREE if the window is contained in the * subtree. Returns TK_GRAB_ANCESTOR if the window is an * ancestor of the subtree, in the same toplevel. Otherwise * it returns TK_GRAB_EXCLUDED. * * Side effects: * None. * *---------------------------------------------------------------------- */intTkPositionInTree(winPtr, treePtr) TkWindow *winPtr; /* Window to be checked. */ TkWindow *treePtr; /* Root of tree to compare against. */{ TkWindow *winPtr2; for (winPtr2 = winPtr; winPtr2 != treePtr; winPtr2 = winPtr2->parentPtr) { if (winPtr2 == NULL) { for (winPtr2 = treePtr; winPtr2 != NULL; winPtr2 = winPtr2->parentPtr) { if (winPtr2 == winPtr) { return TK_GRAB_ANCESTOR; } if (winPtr2->flags & TK_TOP_LEVEL) { break; } } return TK_GRAB_EXCLUDED; } } return TK_GRAB_IN_TREE;}/* *---------------------------------------------------------------------- * * TkGrabState -- * * Given a window, this procedure returns a value that indicates * the grab state of the application relative to the window. * * Results: * The return value is one of three things: * TK_GRAB_NONE - no grab is in effect. * TK_GRAB_IN_TREE - there is a grab in effect, and winPtr * is in the grabbed subtree. * TK_GRAB_ANCESTOR - there is a grab in effect; winPtr is * an ancestor of the grabbed window, in * the same toplevel. * TK_GRAB_EXCLUDED - there is a grab in effect; winPtr is * outside the tree of the grab and is not * an ancestor of the grabbed window in the * same toplevel. * * Side effects: * None. * *---------------------------------------------------------------------- */intTkGrabState(winPtr) TkWindow *winPtr; /* Window for which grab information is * needed. */{ TkWindow *grabWinPtr = winPtr->dispPtr->grabWinPtr; if (grabWinPtr == NULL) { return TK_GRAB_NONE; } if ((winPtr->mainPtr != grabWinPtr->mainPtr) && !(winPtr->dispPtr->grabFlags & GRAB_GLOBAL)) { return TK_GRAB_NONE; } return TkPositionInTree(winPtr, grabWinPtr);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -