📄 tkevent.c
字号:
} if (winPtr->mainPtr != NULL) { /* * Protect interpreter for this window from possible deletion * while we are dealing with the event for this window. Thus, * widget writers do not have to worry about protecting the * interpreter in their own code. */ interp = winPtr->mainPtr->interp; Tcl_Preserve((ClientData) interp); /* * Call focus-related code to look at FocusIn, FocusOut, Enter, * and Leave events; depending on its return value, ignore the * event. */ if ((mask & (FocusChangeMask|EnterWindowMask|LeaveWindowMask)) && !TkFocusFilterEvent(winPtr, eventPtr)) { Tcl_Release((ClientData) interp); return; } /* * Redirect KeyPress and KeyRelease events to the focus window, * or ignore them entirely if there is no focus window. */ if (mask & (KeyPressMask|KeyReleaseMask)) { winPtr->dispPtr->lastEventTime = eventPtr->xkey.time; winPtr = TkFocusKeyEvent(winPtr, eventPtr); if (winPtr == NULL) { Tcl_Release((ClientData) interp); return; } } /* * Call a grab-related procedure to do special processing on * pointer events. */ if (mask & (ButtonPressMask|ButtonReleaseMask|PointerMotionMask |EnterWindowMask|LeaveWindowMask)) { if (mask & (ButtonPressMask|ButtonReleaseMask)) { winPtr->dispPtr->lastEventTime = eventPtr->xbutton.time; } else if (mask & PointerMotionMask) { winPtr->dispPtr->lastEventTime = eventPtr->xmotion.time; } else { winPtr->dispPtr->lastEventTime = eventPtr->xcrossing.time; } if (TkPointerEvent(eventPtr, winPtr) == 0) { goto done; } } }#ifdef TK_USE_INPUT_METHODS /* * Pass the event to the input method(s), if there are any, and * discard the event if the input method(s) insist. Create the * input context for the window if it hasn't already been done * (XFilterEvent needs this context). */ if (!(winPtr->flags & TK_CHECKED_IC)) { if (winPtr->dispPtr->inputMethod != NULL) { winPtr->inputContext = XCreateIC( winPtr->dispPtr->inputMethod, XNInputStyle, XIMPreeditNothing|XIMStatusNothing, XNClientWindow, winPtr->window, XNFocusWindow, winPtr->window, NULL); } winPtr->flags |= TK_CHECKED_IC; } if (XFilterEvent(eventPtr, None)) { goto done; }#endif /* TK_USE_INPUT_METHODS */ /* * For events where it hasn't already been done, update the current * time in the display. */ if (eventPtr->type == PropertyNotify) { winPtr->dispPtr->lastEventTime = eventPtr->xproperty.time; } /* * There's a potential interaction here with Tk_DeleteEventHandler. * Read the documentation for pendingPtr. */ ip.eventPtr = eventPtr; ip.winPtr = winPtr; ip.nextHandler = NULL; ip.nextPtr = pendingPtr; pendingPtr = &ip; if (mask == 0) { if ((eventPtr->type == SelectionClear) || (eventPtr->type == SelectionRequest) || (eventPtr->type == SelectionNotify)) { TkSelEventProc((Tk_Window) winPtr, eventPtr); } else if ((eventPtr->type == ClientMessage) && (eventPtr->xclient.message_type == Tk_InternAtom((Tk_Window) winPtr, "WM_PROTOCOLS"))) { TkWmProtocolEventProc(winPtr, eventPtr); } } else { for (handlerPtr = winPtr->handlerList; handlerPtr != NULL; ) { if ((handlerPtr->mask & mask) != 0) { ip.nextHandler = handlerPtr->nextPtr; (*(handlerPtr->proc))(handlerPtr->clientData, eventPtr); handlerPtr = ip.nextHandler; } else { handlerPtr = handlerPtr->nextPtr; } } /* * Pass the event to the "bind" command mechanism. But, don't * do this for SubstructureNotify events. The "bind" command * doesn't support them anyway, and it's easier to filter out * these events here than in the lower-level procedures. */ if ((ip.winPtr != None) && (mask != SubstructureNotifyMask)) { TkBindEventProc(winPtr, eventPtr); } } pendingPtr = ip.nextPtr;done: /* * Release the interpreter for this window so that it can be potentially * deleted if requested. */ if (interp != (Tcl_Interp *) NULL) { Tcl_Release((ClientData) interp); }}/* *-------------------------------------------------------------- * * TkEventDeadWindow -- * * This procedure is invoked when it is determined that * a window is dead. It cleans up event-related information * about the window. * * Results: * None. * * Side effects: * Various things get cleaned up and recycled. * *-------------------------------------------------------------- */voidTkEventDeadWindow(winPtr) TkWindow *winPtr; /* Information about the window * that is being deleted. */{ register TkEventHandler *handlerPtr; register InProgress *ipPtr; /* * While deleting all the handlers, be careful to check for * Tk_HandleEvent being about to process one of the deleted * handlers. If it is, tell it to quit (all of the handlers * are being deleted). */ while (winPtr->handlerList != NULL) { handlerPtr = winPtr->handlerList; winPtr->handlerList = handlerPtr->nextPtr; for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) { if (ipPtr->nextHandler == handlerPtr) { ipPtr->nextHandler = NULL; } if (ipPtr->winPtr == winPtr) { ipPtr->winPtr = None; } } ckfree((char *) handlerPtr); }}/* *---------------------------------------------------------------------- * * TkCurrentTime -- * * Try to deduce the current time. "Current time" means the time * of the event that led to the current code being executed, which * means the time in the most recently-nested invocation of * Tk_HandleEvent. * * Results: * The return value is the time from the current event, or * CurrentTime if there is no current event or if the current * event contains no time. * * Side effects: * None. * *---------------------------------------------------------------------- */TimeTkCurrentTime(dispPtr) TkDisplay *dispPtr; /* Display for which the time is desired. */{ register XEvent *eventPtr; if (pendingPtr == NULL) { return dispPtr->lastEventTime; } eventPtr = pendingPtr->eventPtr; switch (eventPtr->type) { case ButtonPress: case ButtonRelease: return eventPtr->xbutton.time; case KeyPress: case KeyRelease: return eventPtr->xkey.time; case MotionNotify: return eventPtr->xmotion.time; case EnterNotify: case LeaveNotify: return eventPtr->xcrossing.time; case PropertyNotify: return eventPtr->xproperty.time; } return dispPtr->lastEventTime;}/* *---------------------------------------------------------------------- * * Tk_RestrictEvents -- * * This procedure is used to globally restrict the set of events * that will be dispatched. The restriction is done by filtering * all incoming X events through a procedure that determines * whether they are to be processed immediately, deferred, or * discarded. * * Results: * The return value is the previous restriction procedure in effect, * if there was one, or NULL if there wasn't. * * Side effects: * From now on, proc will be called to determine whether to process, * defer or discard each incoming X event. * *---------------------------------------------------------------------- */Tk_RestrictProc *Tk_RestrictEvents(proc, arg, prevArgPtr) Tk_RestrictProc *proc; /* Procedure to call for each incoming * event. */ ClientData arg; /* Arbitrary argument to pass to proc. */ ClientData *prevArgPtr; /* Place to store information about previous * argument. */{ Tk_RestrictProc *prev; prev = restrictProc; *prevArgPtr = restrictArg; restrictProc = proc; restrictArg = arg; return prev;}/* *---------------------------------------------------------------------- * * Tk_QueueWindowEvent -- * * Given an X-style window event, this procedure adds it to the * Tcl event queue at the given position. This procedure also * performs mouse motion event collapsing if possible. * * Results: * None. * * Side effects: * Adds stuff to the event queue, which will eventually be * processed. * *---------------------------------------------------------------------- */voidTk_QueueWindowEvent(eventPtr, position) XEvent *eventPtr; /* Event to add to queue. This * procedures copies it before adding * it to the queue. */ Tcl_QueuePosition position; /* Where to put it on the queue: * TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, * or TCL_QUEUE_MARK. */{ TkWindowEvent *wevPtr; TkDisplay *dispPtr; /* * Find our display structure for the event's display. */ for (dispPtr = tkDisplayList; ; dispPtr = dispPtr->nextPtr) { if (dispPtr == NULL) { return; } if (dispPtr->display == eventPtr->xany.display) { break; } } if ((dispPtr->delayedMotionPtr != NULL) && (position == TCL_QUEUE_TAIL)) { if ((eventPtr->type == MotionNotify) && (eventPtr->xmotion.window == dispPtr->delayedMotionPtr->event.xmotion.window)) { /* * The new event is a motion event in the same window as the * saved motion event. Just replace the saved event with the * new one. */ dispPtr->delayedMotionPtr->event = *eventPtr; return; } else if ((eventPtr->type != GraphicsExpose) && (eventPtr->type != NoExpose) && (eventPtr->type != Expose)) { /* * The new event may conflict with the saved motion event. Queue * the saved motion event now so that it will be processed before * the new event. */ Tcl_QueueEvent(&dispPtr->delayedMotionPtr->header, position); dispPtr->delayedMotionPtr = NULL; Tcl_CancelIdleCall(DelayedMotionProc, (ClientData) dispPtr); } } wevPtr = (TkWindowEvent *) ckalloc(sizeof(TkWindowEvent)); wevPtr->header.proc = WindowEventProc; wevPtr->event = *eventPtr; if ((eventPtr->type == MotionNotify) && (position == TCL_QUEUE_TAIL)) { /* * The new event is a motion event so don't queue it immediately; * save it around in case another motion event arrives that it can * be collapsed with. */ if (dispPtr->delayedMotionPtr != NULL) { panic("Tk_QueueWindowEvent found unexpected delayed motion event"); } dispPtr->delayedMotionPtr = wevPtr; Tcl_DoWhenIdle(DelayedMotionProc, (ClientData) dispPtr); } else { Tcl_QueueEvent(&wevPtr->header, position); }}/* *--------------------------------------------------------------------------- * * TkQueueEventForAllChildren -- * * Given an XEvent, recursively queue the event for this window and * all non-toplevel children of the given window. * * Results: * None. * * Side effects: * Events queued. * *--------------------------------------------------------------------------- */voidTkQueueEventForAllChildren(winPtr, eventPtr) TkWindow *winPtr; /* Window to which event is sent. */ XEvent *eventPtr; /* The event to be sent. */{ TkWindow *childPtr; eventPtr->xany.window = winPtr->window; Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_TAIL); childPtr = winPtr->childList; while (childPtr != NULL) { if (!Tk_IsTopLevel(childPtr)) { TkQueueEventForAllChildren(childPtr, eventPtr); } childPtr = childPtr->nextPtr; }}/* *---------------------------------------------------------------------- * * WindowEventProc -- * * This procedure is called by Tcl_DoOneEvent when a window event * reaches the front of the event queue. This procedure is responsible * for actually handling the event. * * Results: * Returns 1 if the event was handled, meaning it should be removed * from the queue. Returns 0 if the event was not handled, meaning * it should stay on the queue. The event isn't handled if the * TCL_WINDOW_EVENTS bit isn't set in flags, if a restrict proc * prevents the event from being handled. * * Side effects: * Whatever the event handlers for the event do. * *---------------------------------------------------------------------- */static intWindowEventProc(evPtr, flags) Tcl_Event *evPtr; /* Event to service. */ int flags; /* Flags that indicate what events to * handle, such as TCL_WINDOW_EVENTS. */{ TkWindowEvent *wevPtr = (TkWindowEvent *) evPtr; Tk_RestrictAction result; if (!(flags & TCL_WINDOW_EVENTS)) { return 0; } if (restrictProc != NULL) { result = (*restrictProc)(restrictArg, &wevPtr->event); if (result != TK_PROCESS_EVENT) { if (result == TK_DEFER_EVENT) { return 0; } else { /* * TK_DELETE_EVENT: return and say we processed the event, * even though we didn't do anything at all. */ return 1; } } } Tk_HandleEvent(&wevPtr->event); return 1;}/* *---------------------------------------------------------------------- * * DelayedMotionProc -- * * This procedure is invoked as an idle handler when a mouse motion * event has been delayed. It queues the delayed event so that it * will finally be serviced. * * Results: * None. * * Side effects: * The delayed mouse motion event gets added to the Tcl event * queue for servicing. * *---------------------------------------------------------------------- */static voidDelayedMotionProc(clientData) ClientData clientData; /* Pointer to display containing a delayed * motion event to be serviced. */{ TkDisplay *dispPtr = (TkDisplay *) clientData; if (dispPtr->delayedMotionPtr == NULL) { panic("DelayedMotionProc found no delayed mouse motion event"); } Tcl_QueueEvent(&dispPtr->delayedMotionPtr->header, TCL_QUEUE_TAIL); dispPtr->delayedMotionPtr = NULL;}/* *-------------------------------------------------------------- * * Tk_MainLoop -- * * Call Tcl_DoOneEvent over and over again in an infinite * loop as long as there exist any main windows. * * Results: * None. * * Side effects: * Arbitrary; depends on handlers for events. * *-------------------------------------------------------------- */voidTk_MainLoop(){ while (Tk_GetNumMainWindows() > 0) { Tcl_DoOneEvent(0); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -