diff options
Diffstat (limited to 'tk8.6/generic/tkEvent.c')
-rw-r--r-- | tk8.6/generic/tkEvent.c | 2147 |
1 files changed, 0 insertions, 2147 deletions
diff --git a/tk8.6/generic/tkEvent.c b/tk8.6/generic/tkEvent.c deleted file mode 100644 index 95aeda1..0000000 --- a/tk8.6/generic/tkEvent.c +++ /dev/null @@ -1,2147 +0,0 @@ -/* - * tkEvent.c -- - * - * This file provides basic low-level facilities for managing X events in - * Tk. - * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * Copyright (c) 1998-2000 Ajuba Solutions. - * Copyright (c) 2004 George Peter Staplin - * - * See the file "license.terms" for information on usage and redistribution of - * this file, and for a DISCLAIMER OF ALL WARRANTIES. - */ - -#include "tkInt.h" - -/* - * There's a potential problem if a handler is deleted while it's current - * (i.e. its function is executing), since Tk_HandleEvent will need to read - * the handler's "nextPtr" field when the function returns. To handle this - * problem, structures of the type below indicate the next handler to be - * processed for any (recursively nested) dispatches in progress. The - * nextHandler fields get updated if the handlers pointed to are deleted. - * Tk_HandleEvent also needs to know if the entire window gets deleted; the - * winPtr field is set to zero if that particular window gets deleted. - */ - -typedef struct InProgress { - XEvent *eventPtr; /* Event currently being handled. */ - TkWindow *winPtr; /* Window for event. Gets set to None if - * window is deleted while event is being - * handled. */ - TkEventHandler *nextHandler;/* Next handler in search. */ - struct InProgress *nextPtr; /* Next higher nested search. */ -} InProgress; - -/* - * For each call to Tk_CreateGenericHandler or Tk_CreateClientMessageHandler, - * an instance of the following structure will be created. All of the active - * handlers are linked into a list. - */ - -typedef struct GenericHandler { - Tk_GenericProc *proc; /* Function to dispatch on all X events. */ - ClientData clientData; /* Client data to pass to function. */ - int deleteFlag; /* Flag to set when this handler is - * deleted. */ - struct GenericHandler *nextPtr; - /* Next handler in list of all generic - * handlers, or NULL for end of list. */ -} GenericHandler; - -/* - * There's a potential problem if Tk_HandleEvent is entered recursively. A - * handler cannot be deleted physically until we have returned from calling - * it. Otherwise, we're looking at unallocated memory in advancing to its - * `next' entry. We deal with the problem by using the `delete flag' and - * deleting handlers only when it's known that there's no handler active. - */ - -/* - * The following structure is used for queueing X-style events on the Tcl - * event queue. - */ - -typedef struct TkWindowEvent { - Tcl_Event header; /* Standard information for all events. */ - XEvent event; /* The X event. */ -} TkWindowEvent; - -/* - * Array of event masks corresponding to each X event: - */ - -static const unsigned long realEventMasks[MappingNotify+1] = { - 0, - 0, - KeyPressMask, /* KeyPress */ - KeyReleaseMask, /* KeyRelease */ - ButtonPressMask, /* ButtonPress */ - ButtonReleaseMask, /* ButtonRelease */ - PointerMotionMask|PointerMotionHintMask|ButtonMotionMask - |Button1MotionMask|Button2MotionMask|Button3MotionMask - |Button4MotionMask|Button5MotionMask, - /* MotionNotify */ - EnterWindowMask, /* EnterNotify */ - LeaveWindowMask, /* LeaveNotify */ - FocusChangeMask, /* FocusIn */ - FocusChangeMask, /* FocusOut */ - KeymapStateMask, /* KeymapNotify */ - ExposureMask, /* Expose */ - ExposureMask, /* GraphicsExpose */ - ExposureMask, /* NoExpose */ - VisibilityChangeMask, /* VisibilityNotify */ - SubstructureNotifyMask, /* CreateNotify */ - StructureNotifyMask, /* DestroyNotify */ - StructureNotifyMask, /* UnmapNotify */ - StructureNotifyMask, /* MapNotify */ - SubstructureRedirectMask, /* MapRequest */ - StructureNotifyMask, /* ReparentNotify */ - StructureNotifyMask, /* ConfigureNotify */ - SubstructureRedirectMask, /* ConfigureRequest */ - StructureNotifyMask, /* GravityNotify */ - ResizeRedirectMask, /* ResizeRequest */ - StructureNotifyMask, /* CirculateNotify */ - SubstructureRedirectMask, /* CirculateRequest */ - PropertyChangeMask, /* PropertyNotify */ - 0, /* SelectionClear */ - 0, /* SelectionRequest */ - 0, /* SelectionNotify */ - ColormapChangeMask, /* ColormapNotify */ - 0, /* ClientMessage */ - 0 /* Mapping Notify */ -}; - -static const unsigned long virtualEventMasks[TK_LASTEVENT-VirtualEvent] = { - VirtualEventMask, /* VirtualEvents */ - ActivateMask, /* ActivateNotify */ - ActivateMask, /* DeactivateNotify */ - MouseWheelMask /* MouseWheelEvent */ -}; - -/* - * For each exit handler created with a call to TkCreateExitHandler or - * TkCreateThreadExitHandler there is a structure of the following type: - */ - -typedef struct ExitHandler { - Tcl_ExitProc *proc; /* Function to call when process exits. */ - ClientData clientData; /* One word of information to pass to proc. */ - struct ExitHandler *nextPtr;/* Next in list of all exit handlers for this - * application, or NULL for end of list. */ -} ExitHandler; - -/* - * The structure below is used to store Data for the Event module that must be - * kept thread-local. The "dataKey" is used to fetch the thread-specific - * storage for the current thread. - */ - -typedef struct ThreadSpecificData { - int handlersActive; /* The following variable has a non-zero value - * when a handler is active. */ - InProgress *pendingPtr; /* Topmost search in progress, or NULL if - * none. */ - - /* - * List of generic handler records. - */ - - GenericHandler *genericList;/* First handler in the list, or NULL. */ - GenericHandler *lastGenericPtr; - /* Last handler in list. */ - - /* - * List of client message handler records. - */ - - GenericHandler *cmList; /* First handler in the list, or NULL. */ - GenericHandler *lastCmPtr; /* Last handler in list. */ - - /* - * If someone has called Tk_RestrictEvents, the information below keeps - * track of it. - */ - - Tk_RestrictProc *restrictProc; - /* Function to call. NULL means no - * restrictProc is currently in effect. */ - ClientData restrictArg; /* Argument to pass to restrictProc. */ - ExitHandler *firstExitPtr; /* First in list of all exit handlers for this - * thread. */ - int inExit; /* True when this thread is exiting. This is - * used as a hack to decide to close the - * standard channels. */ -} ThreadSpecificData; -static Tcl_ThreadDataKey dataKey; - -/* - * There are both per-process and per-thread exit handlers. The first list is - * controlled by a mutex. The other is in thread local storage. - */ - -static ExitHandler *firstExitPtr = NULL; - /* First in list of all exit handlers for - * application. */ -TCL_DECLARE_MUTEX(exitMutex) - -/* - * Prototypes for functions that are only referenced locally within this file. - */ - -static void CleanUpTkEvent(XEvent *eventPtr); -static void DelayedMotionProc(ClientData clientData); -static int GetButtonMask(unsigned int Button); -static unsigned long GetEventMaskFromXEvent(XEvent *eventPtr); -static TkWindow * GetTkWindowFromXEvent(XEvent *eventPtr); -static void InvokeClientMessageHandlers(ThreadSpecificData *tsdPtr, - Tk_Window tkwin, XEvent *eventPtr); -static int InvokeFocusHandlers(TkWindow **winPtrPtr, - unsigned long mask, XEvent *eventPtr); -static int InvokeGenericHandlers(ThreadSpecificData *tsdPtr, - XEvent *eventPtr); -static int InvokeMouseHandlers(TkWindow *winPtr, - unsigned long mask, XEvent *eventPtr); -static Window ParentXId(Display *display, Window w); -static int RefreshKeyboardMappingIfNeeded(XEvent *eventPtr); -static int TkXErrorHandler(ClientData clientData, - XErrorEvent *errEventPtr); -static void UpdateButtonEventState(XEvent *eventPtr); -static int WindowEventProc(Tcl_Event *evPtr, int flags); -#ifdef TK_USE_INPUT_METHODS -static void CreateXIC(TkWindow *winPtr); -#endif /* TK_USE_INPUT_METHODS */ - -/* - *---------------------------------------------------------------------- - * - * InvokeFocusHandlers -- - * - * Call focus-related code to look at FocusIn, FocusOut, Enter, and Leave - * events; depending on its return value, ignore the event. - * - * Results: - * 0 further processing can be done on the event. - * 1 we are done with the event passed. - * - * Side effects: - * The *winPtrPtr in the caller may be changed to the TkWindow for the - * window with focus. - * - *---------------------------------------------------------------------- - */ - -static int -InvokeFocusHandlers( - TkWindow **winPtrPtr, - unsigned long mask, - XEvent *eventPtr) -{ - if ((mask & (FocusChangeMask|EnterWindowMask|LeaveWindowMask)) - && (TkFocusFilterEvent(*winPtrPtr, eventPtr) == 0)) { - return 1; - } - - /* - * Only key-related events are directed according to the focus. - */ - - if (mask & (KeyPressMask|KeyReleaseMask)) { - (*winPtrPtr)->dispPtr->lastEventTime = eventPtr->xkey.time; - *winPtrPtr = TkFocusKeyEvent(*winPtrPtr, eventPtr); - if (*winPtrPtr == NULL) { - return 1; - } - } - - return 0; -} - -/* - *---------------------------------------------------------------------- - * - * InvokeMouseHandlers -- - * - * Call a grab-related function to do special processing on pointer - * events. - * - * Results: - * 0 further processing can be done on the event. - * 1 we are done with the event passed. - * - * Side effects: - * New events may be queued from TkPointerEvent and grabs may be added - * and/or removed. The eventPtr may be changed by TkPointerEvent in some - * cases. - * - *---------------------------------------------------------------------- - */ - -static int -InvokeMouseHandlers( - TkWindow *winPtr, - unsigned long mask, - XEvent *eventPtr) -{ - 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) { - /* - * The event should be ignored to make grab work correctly (as the - * comment for TkPointerEvent states). - */ - - return 1; - } - } - - return 0; -} - -/* - *---------------------------------------------------------------------- - * - * CreateXIC -- - * - * Create the X input context for our winPtr. - * XIM is only ever enabled on Unix. - * - *---------------------------------------------------------------------- - */ - -#ifdef TK_USE_INPUT_METHODS -static void -CreateXIC( - TkWindow *winPtr) -{ - TkDisplay *dispPtr = winPtr->dispPtr; - long im_event_mask = 0L; - const char *preedit_attname = NULL; - XVaNestedList preedit_attlist = NULL; - - if (dispPtr->inputStyle & XIMPreeditPosition) { - XPoint spot = {0, 0}; - - preedit_attname = XNPreeditAttributes; - preedit_attlist = XVaCreateNestedList(0, - XNSpotLocation, &spot, - XNFontSet, dispPtr->inputXfs, - NULL); - } - - winPtr->inputContext = XCreateIC(dispPtr->inputMethod, - XNInputStyle, dispPtr->inputStyle, - XNClientWindow, winPtr->window, - XNFocusWindow, winPtr->window, - preedit_attname, preedit_attlist, - NULL); - - if (preedit_attlist) { - XFree(preedit_attlist); - } - - - if (winPtr->inputContext == NULL) { - /* XCreateIC failed. */ - return; - } - - /* - * Adjust the window's event mask if the IM requires it. - */ - XGetICValues(winPtr->inputContext, XNFilterEvents, &im_event_mask, NULL); - if ((winPtr->atts.event_mask & im_event_mask) != im_event_mask) { - winPtr->atts.event_mask |= im_event_mask; - XSelectInput(winPtr->display, winPtr->window, winPtr->atts.event_mask); - } -} -#endif - -/* - *---------------------------------------------------------------------- - * - * GetTkWindowFromXEvent -- - * - * Attempt to find which TkWindow is associated with an event. If it - * fails we attempt to get the TkWindow from the parent for a property - * notification. - * - * Results: - * The TkWindow associated with the event or NULL. - * - * Side effects: - * TkSelPropProc may influence selection on windows not known to Tk. - * - *---------------------------------------------------------------------- - */ - -static TkWindow * -GetTkWindowFromXEvent( - XEvent *eventPtr) -{ - TkWindow *winPtr; - Window parentXId, handlerWindow = eventPtr->xany.window; - - if ((eventPtr->xany.type == StructureNotifyMask) - && (eventPtr->xmap.event != eventPtr->xmap.window)) { - handlerWindow = eventPtr->xmap.event; - } - - winPtr = (TkWindow *) Tk_IdToWindow(eventPtr->xany.display, handlerWindow); - - if (winPtr == NULL) { - /* - * There isn't a TkWindow structure for this window. However, if the - * event is a PropertyNotify event then call the selection manager (it - * deals beneath-the-table with certain properties). Also, if the - * window's parent is a Tk window that has the TK_PROP_PROPCHANGE flag - * set, then we must propagate the PropertyNotify event up to the - * parent. - */ - - if (eventPtr->type != PropertyNotify) { - return NULL; - } - TkSelPropProc(eventPtr); - parentXId = ParentXId(eventPtr->xany.display, handlerWindow); - if (parentXId == None) { - return NULL; - } - winPtr = (TkWindow *) Tk_IdToWindow(eventPtr->xany.display, parentXId); - if (winPtr == NULL) { - return NULL; - } - if (!(winPtr->flags & TK_PROP_PROPCHANGE)) { - return NULL; - } - } - return winPtr; -} - -/* - *---------------------------------------------------------------------- - * - * GetEventMaskFromXEvent -- - * - * The event type is looked up in our eventMasks tables, and may be - * changed to a different mask depending on the state of the event and - * window members. - * - * Results: - * The mask for the event. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static unsigned long -GetEventMaskFromXEvent( - XEvent *eventPtr) -{ - unsigned long mask; - - /* - * Get the event mask from the correct table. Note that there are two - * tables here because that means we no longer need this code to rely on - * the exact value of VirtualEvent, which has caused us problems in the - * past when X11 changed the value of LASTEvent. [Bug ???] - */ - - if (eventPtr->xany.type <= MappingNotify) { - mask = realEventMasks[eventPtr->xany.type]; - } else if (eventPtr->xany.type >= VirtualEvent - && eventPtr->xany.type<TK_LASTEVENT) { - mask = virtualEventMasks[eventPtr->xany.type - VirtualEvent]; - } else { - mask = 0; - } - - /* - * Events selected by StructureNotify require special handling. They look - * the same as those selected by SubstructureNotify. The only difference - * is whether the "event" and "window" fields are the same. Compare the - * two fields and convert StructureNotify to SubstructureNotify if - * necessary. - */ - - if (mask == StructureNotifyMask) { - if (eventPtr->xmap.event != eventPtr->xmap.window) { - mask = SubstructureNotifyMask; - } - } - return mask; -} - -/* - *---------------------------------------------------------------------- - * - * RefreshKeyboardMappingIfNeeded -- - * - * If the event is a MappingNotify event, find its display and refresh - * the keyboard mapping information for the display. - * - * Results: - * 0 if the event was not a MappingNotify event - * 1 if the event was a MappingNotify event - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -RefreshKeyboardMappingIfNeeded( - XEvent *eventPtr) -{ - TkDisplay *dispPtr; - - if (eventPtr->type == MappingNotify) { - dispPtr = TkGetDisplay(eventPtr->xmapping.display); - if (dispPtr != NULL) { - XRefreshKeyboardMapping(&eventPtr->xmapping); - dispPtr->bindInfoStale = 1; - } - return 1; - } - return 0; -} - -/* - *---------------------------------------------------------------------- - * - * GetButtonMask -- - * - * Return the proper Button${n}Mask for the button. - * - * Results: - * A button mask. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -GetButtonMask( - unsigned int button) -{ - switch (button) { - case 1: - return Button1Mask; - case 2: - return Button2Mask; - case 3: - return Button3Mask; - case 4: - return Button4Mask; - case 5: - return Button5Mask; - } - return 0; -} - -/* - *---------------------------------------------------------------------- - * - * UpdateButtonEventState -- - * - * Update the button event state in our TkDisplay using the XEvent - * passed. We also may modify the the XEvent passed to fit some aspects - * of our TkDisplay. - * - * Results: - * None. - * - * Side effects: - * The TkDisplay's private button state may be modified. The eventPtr's - * state may be updated to reflect masks stored in our TkDisplay that the - * event doesn't contain. The eventPtr may also be modified to not - * contain a button state for the window in which it was not pressed in. - * - *---------------------------------------------------------------------- - */ - -static void -UpdateButtonEventState( - XEvent *eventPtr) -{ - TkDisplay *dispPtr; - int allButtonsMask = Button1Mask | Button2Mask | Button3Mask - | Button4Mask | Button5Mask; - - switch (eventPtr->type) { - case ButtonPress: - dispPtr = TkGetDisplay(eventPtr->xbutton.display); - dispPtr->mouseButtonWindow = eventPtr->xbutton.window; - eventPtr->xbutton.state |= dispPtr->mouseButtonState; - - dispPtr->mouseButtonState |= GetButtonMask(eventPtr->xbutton.button); - break; - - case ButtonRelease: - dispPtr = TkGetDisplay(eventPtr->xbutton.display); - dispPtr->mouseButtonWindow = None; - dispPtr->mouseButtonState &= ~GetButtonMask(eventPtr->xbutton.button); - eventPtr->xbutton.state |= dispPtr->mouseButtonState; - break; - - case MotionNotify: - dispPtr = TkGetDisplay(eventPtr->xmotion.display); - if (dispPtr->mouseButtonState & allButtonsMask) { - if (eventPtr->xbutton.window != dispPtr->mouseButtonWindow) { - /* - * This motion event should not be interpreted as a button - * press + motion event since this is not the same window the - * button was pressed down in. - */ - - dispPtr->mouseButtonState &= ~allButtonsMask; - dispPtr->mouseButtonWindow = None; - } else { - eventPtr->xmotion.state |= dispPtr->mouseButtonState; - } - } - break; - } -} - -/* - *---------------------------------------------------------------------- - * - * InvokeClientMessageHandlers -- - * - * Iterate the list of handlers and invoke the function pointer for each. - * - * Results: - * None. - * - * Side effects: - * Handlers may be deleted and events may be sent to handlers. - * - *---------------------------------------------------------------------- - */ - -static void -InvokeClientMessageHandlers( - ThreadSpecificData *tsdPtr, - Tk_Window tkwin, - XEvent *eventPtr) -{ - GenericHandler *prevPtr, *tmpPtr, *curPtr = tsdPtr->cmList; - - for (prevPtr = NULL; curPtr != NULL; ) { - if (curPtr->deleteFlag) { - if (!tsdPtr->handlersActive) { - /* - * This handler needs to be deleted and there are no calls - * pending through any handlers, so now is a safe time to - * delete it. - */ - - tmpPtr = curPtr->nextPtr; - if (prevPtr == NULL) { - tsdPtr->cmList = tmpPtr; - } else { - prevPtr->nextPtr = tmpPtr; - } - if (tmpPtr == NULL) { - tsdPtr->lastCmPtr = prevPtr; - } - ckfree(curPtr); - curPtr = tmpPtr; - continue; - } - } else { - int done; - - tsdPtr->handlersActive++; - done = (*(Tk_ClientMessageProc *)curPtr->proc)(tkwin, eventPtr); - tsdPtr->handlersActive--; - if (done) { - break; - } - } - prevPtr = curPtr; - curPtr = curPtr->nextPtr; - } -} - -/* - *---------------------------------------------------------------------- - * - * InvokeGenericHandlers -- - * - * Iterate the list of handlers and invoke the function pointer for each. - * If the handler invoked returns a non-zero value then we are done. - * - * Results: - * 0 when the event wasn't handled by a handler. Non-zero when it was - * processed and handled by a handler. - * - * Side effects: - * Handlers may be deleted and events may be sent to handlers. - * - *---------------------------------------------------------------------- - */ - -static int -InvokeGenericHandlers( - ThreadSpecificData *tsdPtr, - XEvent *eventPtr) -{ - GenericHandler *prevPtr, *tmpPtr, *curPtr = tsdPtr->genericList; - - for (prevPtr = NULL; curPtr != NULL; ) { - if (curPtr->deleteFlag) { - if (!tsdPtr->handlersActive) { - /* - * This handler needs to be deleted and there are no calls - * pending through the handler, so now is a safe time to - * delete it. - */ - - tmpPtr = curPtr->nextPtr; - if (prevPtr == NULL) { - tsdPtr->genericList = tmpPtr; - } else { - prevPtr->nextPtr = tmpPtr; - } - if (tmpPtr == NULL) { - tsdPtr->lastGenericPtr = prevPtr; - } - ckfree(curPtr); - curPtr = tmpPtr; - continue; - } - } else { - int done; - - tsdPtr->handlersActive++; - done = curPtr->proc(curPtr->clientData, eventPtr); - tsdPtr->handlersActive--; - if (done) { - return done; - } - } - prevPtr = curPtr; - curPtr = curPtr->nextPtr; - } - return 0; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_CreateEventHandler -- - * - * Arrange for a given function to be invoked whenever events from a - * given class occur in a given window. - * - * Results: - * None. - * - * Side effects: - * From now on, whenever an event of the type given by mask occurs for - * token and is processed by Tk_HandleEvent, proc will be called. See the - * manual entry for details of the calling sequence and return value for - * proc. - * - *---------------------------------------------------------------------- - */ - -void -Tk_CreateEventHandler( - Tk_Window token, /* Token for window in which to create - * handler. */ - unsigned long mask, /* Events for which proc should be called. */ - Tk_EventProc *proc, /* Function to call for each selected event */ - ClientData clientData) /* Arbitrary data to pass to proc. */ -{ - register TkEventHandler *handlerPtr; - register TkWindow *winPtr = (TkWindow *) token; - - /* - * Skim through the list of existing handlers to (a) compute the overall - * event mask for the window (so we can pass this new value to the X - * system) and (b) see if there's already a handler declared with the same - * callback and clientData (if so, just change the mask). If no existing - * handler matches, then create a new handler. - */ - - if (winPtr->handlerList == NULL) { - /* - * No event handlers defined at all, so must create. - */ - - handlerPtr = ckalloc(sizeof(TkEventHandler)); - winPtr->handlerList = handlerPtr; - } else { - int found = 0; - - for (handlerPtr = winPtr->handlerList; ; - handlerPtr = handlerPtr->nextPtr) { - if ((handlerPtr->proc == proc) - && (handlerPtr->clientData == clientData)) { - handlerPtr->mask = mask; - found = 1; - } - if (handlerPtr->nextPtr == NULL) { - break; - } - } - - /* - * If we found anything, we're done because we do not need to use - * XSelectInput; Tk always selects on all events anyway in order to - * support binding on classes, 'all' and other bind-tags. - */ - - if (found) { - return; - } - - /* - * No event handler matched, so create a new one. - */ - - handlerPtr->nextPtr = ckalloc(sizeof(TkEventHandler)); - handlerPtr = handlerPtr->nextPtr; - } - - /* - * Initialize the new event handler. - */ - - handlerPtr->mask = mask; - handlerPtr->proc = proc; - handlerPtr->clientData = clientData; - handlerPtr->nextPtr = NULL; - - /* - * No need to call XSelectInput: Tk always selects on all events for all - * windows (needed to support bindings on classes and "all"). - */ -} - -/* - *---------------------------------------------------------------------- - * - * Tk_DeleteEventHandler -- - * - * Delete a previously-created handler. - * - * Results: - * None. - * - * Side effects: - * If there existed a handler as described by the parameters, the handler - * is deleted so that proc will not be invoked again. - * - *---------------------------------------------------------------------- - */ - -void -Tk_DeleteEventHandler( - Tk_Window token, /* Same as corresponding arguments passed */ - unsigned long mask, /* previously to Tk_CreateEventHandler. */ - Tk_EventProc *proc, - ClientData clientData) -{ - register TkEventHandler *handlerPtr; - register InProgress *ipPtr; - TkEventHandler *prevPtr; - register TkWindow *winPtr = (TkWindow *) token; - ThreadSpecificData *tsdPtr = - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - - /* - * Find the event handler to be deleted, or return immediately if it - * doesn't exist. - */ - - for (handlerPtr = winPtr->handlerList, prevPtr = NULL; ; - prevPtr = handlerPtr, handlerPtr = handlerPtr->nextPtr) { - if (handlerPtr == NULL) { - return; - } - if ((handlerPtr->mask == mask) && (handlerPtr->proc == proc) - && (handlerPtr->clientData == clientData)) { - break; - } - } - - /* - * If Tk_HandleEvent is about to process this handler, tell it to process - * the next one instead. - */ - - for (ipPtr = tsdPtr->pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) { - if (ipPtr->nextHandler == handlerPtr) { - ipPtr->nextHandler = handlerPtr->nextPtr; - } - } - - /* - * Free resources associated with the handler. - */ - - if (prevPtr == NULL) { - winPtr->handlerList = handlerPtr->nextPtr; - } else { - prevPtr->nextPtr = handlerPtr->nextPtr; - } - ckfree(handlerPtr); - - /* - * No need to call XSelectInput: Tk always selects on all events for all - * windows (needed to support bindings on classes and "all"). - */ -} - -/*---------------------------------------------------------------------- - * - * Tk_CreateGenericHandler -- - * - * Register a function to be called on each X event, regardless of - * display or window. Generic handlers are useful for capturing events - * that aren't associated with windows, or events for windows not managed - * by Tk. - * - * Results: - * None. - * - * Side Effects: - * From now on, whenever an X event is given to Tk_HandleEvent, invoke - * proc, giving it clientData and the event as arguments. - * - *---------------------------------------------------------------------- - */ - -void -Tk_CreateGenericHandler( - Tk_GenericProc *proc, /* Function to call on every event. */ - ClientData clientData) /* One-word value to pass to proc. */ -{ - GenericHandler *handlerPtr; - ThreadSpecificData *tsdPtr = - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - - handlerPtr = ckalloc(sizeof(GenericHandler)); - - handlerPtr->proc = proc; - handlerPtr->clientData = clientData; - handlerPtr->deleteFlag = 0; - handlerPtr->nextPtr = NULL; - if (tsdPtr->genericList == NULL) { - tsdPtr->genericList = handlerPtr; - } else { - tsdPtr->lastGenericPtr->nextPtr = handlerPtr; - } - tsdPtr->lastGenericPtr = handlerPtr; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_DeleteGenericHandler -- - * - * Delete a previously-created generic handler. - * - * Results: - * None. - * - * Side Effects: - * If there existed a handler as described by the parameters, that - * handler is logically deleted so that proc will not be invoked again. - * The physical deletion happens in the event loop in Tk_HandleEvent. - * - *---------------------------------------------------------------------- - */ - -void -Tk_DeleteGenericHandler( - Tk_GenericProc *proc, - ClientData clientData) -{ - GenericHandler * handler; - ThreadSpecificData *tsdPtr = - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - - for (handler=tsdPtr->genericList ; handler ; handler=handler->nextPtr) { - if ((handler->proc == proc) && (handler->clientData == clientData)) { - handler->deleteFlag = 1; - } - } -} - -/*---------------------------------------------------------------------- - * - * Tk_CreateClientMessageHandler -- - * - * Register a function to be called on each ClientMessage event. - * ClientMessage handlers are useful for Drag&Drop extensions. - * - * Results: - * None. - * - * Side Effects: - * From now on, whenever a ClientMessage event is received that isn't a - * WM_PROTOCOL event or SelectionEvent, invoke proc, giving it tkwin and - * the event as arguments. - * - *---------------------------------------------------------------------- - */ - -void -Tk_CreateClientMessageHandler( - Tk_ClientMessageProc *proc) /* Function to call on event. */ -{ - GenericHandler *handlerPtr; - ThreadSpecificData *tsdPtr = - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - - /* - * We use a GenericHandler struct, because it's basically the same, except - * with an extra clientData field we'll never use. - */ - - handlerPtr = ckalloc(sizeof(GenericHandler)); - - handlerPtr->proc = (Tk_GenericProc *) proc; - handlerPtr->clientData = NULL; /* never used */ - handlerPtr->deleteFlag = 0; - handlerPtr->nextPtr = NULL; - if (tsdPtr->cmList == NULL) { - tsdPtr->cmList = handlerPtr; - } else { - tsdPtr->lastCmPtr->nextPtr = handlerPtr; - } - tsdPtr->lastCmPtr = handlerPtr; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_DeleteClientMessageHandler -- - * - * Delete a previously-created ClientMessage handler. - * - * Results: - * None. - * - * Side Effects: - * If there existed a handler as described by the parameters, that - * handler is logically deleted so that proc will not be invoked again. - * The physical deletion happens in the event loop in - * TkClientMessageEventProc. - * - *---------------------------------------------------------------------- - */ - -void -Tk_DeleteClientMessageHandler( - Tk_ClientMessageProc *proc) -{ - GenericHandler * handler; - ThreadSpecificData *tsdPtr = - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - - for (handler=tsdPtr->cmList ; handler!=NULL ; handler=handler->nextPtr) { - if (handler->proc == (Tk_GenericProc *) proc) { - handler->deleteFlag = 1; - } - } -} - -/* - *---------------------------------------------------------------------- - * - * TkEventInit -- - * - * This functions initializes all the event module structures used by the - * current thread. It must be called before any other function in this - * file is called. - * - * Results: - * None. - * - * Side Effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -TkEventInit(void) -{ - ThreadSpecificData *tsdPtr = - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - - tsdPtr->handlersActive = 0; - tsdPtr->pendingPtr = NULL; - tsdPtr->genericList = NULL; - tsdPtr->lastGenericPtr = NULL; - tsdPtr->cmList = NULL; - tsdPtr->lastCmPtr = NULL; - tsdPtr->restrictProc = NULL; - tsdPtr->restrictArg = NULL; -} - -/* - *---------------------------------------------------------------------- - * - * TkXErrorHandler -- - * - * TkXErrorHandler is an error handler, to be installed via - * Tk_CreateErrorHandler, that will set a flag if an X error occurred. - * - * Results: - * Always returns 0, indicating that the X error was handled. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -TkXErrorHandler( - ClientData clientData, /* Pointer to flag we set. */ - XErrorEvent *errEventPtr) /* X error info. */ -{ - int *error = clientData; - - *error = 1; - return 0; -} - -/* - *---------------------------------------------------------------------- - * - * ParentXId -- - * - * Returns the parent of the given window, or "None" if the window - * doesn't exist. - * - * Results: - * Returns an X window ID. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static Window -ParentXId( - Display *display, - Window w) -{ - Tk_ErrorHandler handler; - int gotXError; - Status status; - Window parent; - Window root; - Window *childList; - unsigned int nChildren; - - /* - * Handle errors ourselves. - */ - - gotXError = 0; - handler = Tk_CreateErrorHandler(display, -1, -1, -1, - TkXErrorHandler, &gotXError); - - /* - * Get the parent window. - */ - - status = XQueryTree(display, w, &root, &parent, &childList, &nChildren); - - /* - * Do some cleanup; gotta return "None" if we got an error. - */ - - Tk_DeleteErrorHandler(handler); - XSync(display, False); - if (status != 0 && childList != NULL) { - XFree(childList); - } - if (status == 0) { - parent = None; - } - - return parent; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_HandleEvent -- - * - * Given an event, invoke all the handlers that have been registered for - * the event. - * - * Results: - * None. - * - * Side effects: - * Depends on the handlers. - * - *---------------------------------------------------------------------- - */ - -void -Tk_HandleEvent( - XEvent *eventPtr) /* Event to dispatch. */ -{ - register TkEventHandler *handlerPtr; - TkWindow *winPtr; - unsigned long mask; - InProgress ip; - Tcl_Interp *interp = NULL; - ThreadSpecificData *tsdPtr = - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - - UpdateButtonEventState(eventPtr); - - /* - * If the generic handler processed this event we are done and can return. - */ - - if (InvokeGenericHandlers(tsdPtr, eventPtr)) { - goto releaseEventResources; - } - - if (RefreshKeyboardMappingIfNeeded(eventPtr)) { - /* - * We are done with a MappingNotify event. - */ - - goto releaseEventResources; - } - - mask = GetEventMaskFromXEvent(eventPtr); - winPtr = GetTkWindowFromXEvent(eventPtr); - - if (winPtr == NULL) { - goto releaseEventResources; - } - - /* - * Once a window has started getting deleted, don't process any more - * events for it except for the DestroyNotify event. This check is needed - * because a DestroyNotify handler could re-invoke the event loop, causing - * other pending events to be handled for the window (the window doesn't - * get totally expunged from our tables until after the DestroyNotify - * event has been completely handled). - */ - - if ((winPtr->flags & TK_ALREADY_DEAD) - && (eventPtr->type != DestroyNotify)) { - goto releaseEventResources; - } - - if (winPtr->mainPtr != NULL) { - int result; - - interp = winPtr->mainPtr->interp; - - /* - * 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. - */ - - Tcl_Preserve(interp); - - result = ((InvokeFocusHandlers(&winPtr, mask, eventPtr)) - || (InvokeMouseHandlers(winPtr, mask, eventPtr))); - - if (result) { - goto releaseInterpreter; - } - } - - /* - * Create the input context for the window if it hasn't already been done - * (XFilterEvent needs this context). When the event is a FocusIn event, - * set the input context focus to the receiving window. This code is only - * ever active for X11. - */ - -#ifdef TK_USE_INPUT_METHODS - if ((winPtr->dispPtr->flags & TK_DISPLAY_USE_IM)) { - if (!(winPtr->flags & (TK_CHECKED_IC|TK_ALREADY_DEAD))) { - winPtr->flags |= TK_CHECKED_IC; - if (winPtr->dispPtr->inputMethod != NULL) { - CreateXIC(winPtr); - } - } - if (eventPtr->type == FocusIn && winPtr->inputContext != NULL) { - XSetICFocus(winPtr->inputContext); - } - } -#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 = tsdPtr->pendingPtr; - tsdPtr->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) { - if (eventPtr->xclient.message_type == - Tk_InternAtom((Tk_Window) winPtr, "WM_PROTOCOLS")) { - TkWmProtocolEventProc(winPtr, eventPtr); - } else { - InvokeClientMessageHandlers(tsdPtr, (Tk_Window) winPtr, - eventPtr); - } - } - } else { - for (handlerPtr = winPtr->handlerList; handlerPtr != NULL; ) { - if (handlerPtr->mask & mask) { - 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 functions. - */ - - /* - * ...well, except when we use the tkwm patches, in which case we DO - * handle CreateNotify events, so we gotta pass 'em through. - */ - - if ((ip.winPtr != None) - && ((mask != SubstructureNotifyMask) - || (eventPtr->type == CreateNotify))) { - TkBindEventProc(winPtr, eventPtr); - } - } - tsdPtr->pendingPtr = ip.nextPtr; - - /* - * Release the interpreter for this window so that it can be potentially - * deleted if requested. - */ - - releaseInterpreter: - if (interp != NULL) { - Tcl_Release(interp); - } - - /* - * Release the user_data from the event (if it is a virtual event and the - * field was non-NULL in the first place.) Note that this is done using a - * Tcl_Obj interface, and we set the field back to NULL afterwards out of - * paranoia. Also clean up any cached %A substitutions from key events. - */ - - releaseEventResources: - CleanUpTkEvent(eventPtr); -} - -/* - *---------------------------------------------------------------------- - * - * TkEventDeadWindow -- - * - * This function 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. - * - *---------------------------------------------------------------------- - */ - -void -TkEventDeadWindow( - TkWindow *winPtr) /* Information about the window that is being - * deleted. */ -{ - register TkEventHandler *handlerPtr; - register InProgress *ipPtr; - ThreadSpecificData *tsdPtr = - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - - /* - * 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 = tsdPtr->pendingPtr; ipPtr != NULL; - ipPtr = ipPtr->nextPtr) { - if (ipPtr->nextHandler == handlerPtr) { - ipPtr->nextHandler = NULL; - } - if (ipPtr->winPtr == winPtr) { - ipPtr->winPtr = None; - } - } - ckfree(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. - * - *---------------------------------------------------------------------- - */ - -Time -TkCurrentTime( - TkDisplay *dispPtr) /* Display for which the time is desired. */ -{ - register XEvent *eventPtr; - ThreadSpecificData *tsdPtr = - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - - if (tsdPtr->pendingPtr == NULL) { - return dispPtr->lastEventTime; - } - eventPtr = tsdPtr->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 function 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 function that determines whether they are to be - * processed immediately, deferred, or discarded. - * - * Results: - * The return value is the previous restriction function 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( - Tk_RestrictProc *proc, /* Function 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; - ThreadSpecificData *tsdPtr = - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - - prev = tsdPtr->restrictProc; - *prevArgPtr = tsdPtr->restrictArg; - tsdPtr->restrictProc = proc; - tsdPtr->restrictArg = arg; - return prev; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_CollapseMotionEvents -- - * - * This function controls whether we collapse motion events in a - * particular display or not. - * - * Results: - * The return value is the previous collapse value in effect. - * - * Side effects: - * Filtering of motion events may be changed after calling this. - * - *---------------------------------------------------------------------- - */ - -int -Tk_CollapseMotionEvents( - Display *display, /* Display handling these events. */ - int collapse) /* Boolean value that specifies whether motion - * events should be collapsed. */ -{ - TkDisplay *dispPtr = (TkDisplay *) display; - int prev = (dispPtr->flags & TK_DISPLAY_COLLAPSE_MOTION_EVENTS); - - if (collapse) { - dispPtr->flags |= TK_DISPLAY_COLLAPSE_MOTION_EVENTS; - } else { - dispPtr->flags &= ~TK_DISPLAY_COLLAPSE_MOTION_EVENTS; - } - return prev; -} - -/* - *---------------------------------------------------------------------- - * - * Tk_QueueWindowEvent -- - * - * Given an X-style window event, this function adds it to the Tcl event - * queue at the given position. This function also performs mouse motion - * event collapsing if possible. - * - * Results: - * None. - * - * Side effects: - * Adds stuff to the event queue, which will eventually be processed. - * - *---------------------------------------------------------------------- - */ - -void -Tk_QueueWindowEvent( - XEvent *eventPtr, /* Event to add to queue. This function 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 = TkGetDisplayList(); ; dispPtr = dispPtr->nextPtr) { - if (dispPtr == NULL) { - return; - } - if (dispPtr->display == eventPtr->xany.display) { - break; - } - } - - /* - * Don't filter motion events if the user defaulting to true (1), which - * could be set to false (0) when the user wishes to receive all the - * motion data) - */ - - if (!(dispPtr->flags & TK_DISPLAY_COLLAPSE_MOTION_EVENTS)) { - wevPtr = ckalloc(sizeof(TkWindowEvent)); - wevPtr->header.proc = WindowEventProc; - wevPtr->event = *eventPtr; - Tcl_QueueEvent(&wevPtr->header, position); - return; - } - - 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, dispPtr); - } - } - - wevPtr = 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) { - Tcl_Panic("Tk_QueueWindowEvent found unexpected delayed motion event"); - } - dispPtr->delayedMotionPtr = wevPtr; - Tcl_DoWhenIdle(DelayedMotionProc, 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. - * - *---------------------------------------------------------------------- - */ - -void -TkQueueEventForAllChildren( - TkWindow *winPtr, /* Window to which event is sent. */ - XEvent *eventPtr) /* The event to be sent. */ -{ - TkWindow *childPtr; - - if (!Tk_IsMapped(winPtr)) { - return; - } - - eventPtr->xany.window = winPtr->window; - Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_TAIL); - - childPtr = winPtr->childList; - while (childPtr != NULL) { - if (!Tk_TopWinHierarchy(childPtr)) { - TkQueueEventForAllChildren(childPtr, eventPtr); - } - childPtr = childPtr->nextPtr; - } -} - -/* - *---------------------------------------------------------------------- - * - * WindowEventProc -- - * - * This function is called by Tcl_DoOneEvent when a window event reaches - * the front of the event queue. This function 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 int -WindowEventProc( - 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; - ThreadSpecificData *tsdPtr = - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - - if (!(flags & TCL_WINDOW_EVENTS)) { - return 0; - } - if (tsdPtr->restrictProc != NULL) { - result = tsdPtr->restrictProc(tsdPtr->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. - */ - - CleanUpTkEvent(&wevPtr->event); - return 1; - } - } - } - Tk_HandleEvent(&wevPtr->event); - CleanUpTkEvent(&wevPtr->event); - return 1; -} - -/* - *---------------------------------------------------------------------- - * - * CleanUpTkEvent -- - * - * This function is called to remove and deallocate any information in - * the event which is not directly in the event structure itself. It may - * be called multiple times per event, so it takes care to set the - * cleared pointer fields to NULL afterwards. - * - * Results: - * None. - * - * Side effects: - * Makes the event no longer have any external resources. - * - *---------------------------------------------------------------------- - */ - -static void -CleanUpTkEvent( - XEvent *eventPtr) -{ - switch (eventPtr->type) { - case KeyPress: - case KeyRelease: { - TkKeyEvent *kePtr = (TkKeyEvent *) eventPtr; - - if (kePtr->charValuePtr != NULL) { - ckfree(kePtr->charValuePtr); - kePtr->charValuePtr = NULL; - kePtr->charValueLen = 0; - } - break; - } - - case VirtualEvent: { - XVirtualEvent *vePtr = (XVirtualEvent *) eventPtr; - - if (vePtr->user_data != NULL) { - Tcl_DecrRefCount(vePtr->user_data); - vePtr->user_data = NULL; - } - break; - } - } -} - -/* - *---------------------------------------------------------------------- - * - * DelayedMotionProc -- - * - * This function 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 void -DelayedMotionProc( - ClientData clientData) /* Pointer to display containing a delayed - * motion event to be serviced. */ -{ - TkDisplay *dispPtr = clientData; - - if (dispPtr->delayedMotionPtr == NULL) { - Tcl_Panic("DelayedMotionProc found no delayed mouse motion event"); - } - Tcl_QueueEvent(&dispPtr->delayedMotionPtr->header, TCL_QUEUE_TAIL); - dispPtr->delayedMotionPtr = NULL; -} - -/* - *---------------------------------------------------------------------- - * - * TkCreateExitHandler -- - * - * Same as Tcl_CreateExitHandler, but private to Tk. - * - * Results: - * None. - * - * Side effects. - * Sets a handler with Tcl_CreateExitHandler if this is the first call. - * - *---------------------------------------------------------------------- - */ - -void -TkCreateExitHandler( - Tcl_ExitProc *proc, /* Function to invoke. */ - ClientData clientData) /* Arbitrary value to pass to proc. */ -{ - ExitHandler *exitPtr; - - exitPtr = ckalloc(sizeof(ExitHandler)); - exitPtr->proc = proc; - exitPtr->clientData = clientData; - Tcl_MutexLock(&exitMutex); - - /* - * The call to TclInExit() is disabled here. That's a private Tcl routine, - * and calling it is causing some trouble with portability of building Tk. - * We should avoid private Tcl routines generally. - * - * In this case, the TclInExit() call is being used only to prevent a - * Tcl_CreateExitHandler() call when Tcl finalization is in progress. - * That's a situation that shouldn't happen anyway. Recent changes within - * Tcl_Finalize now cause a Tcl_Panic() to happen if exit handlers get - * added after exit handling is complete. By disabling the guard here, - * that panic will serve to help us find the buggy conditions and correct - * them. - * - * We can restore this guard if we find we must (hopefully getting public - * access to TclInExit() if we discover extensions really do need this), - * but during alpha development, this is a good time to dig in and find - * the root causes of finalization bugs. - */ - - if (firstExitPtr == NULL/* && !TclInExit()*/) { - Tcl_CreateExitHandler(TkFinalize, NULL); - } - exitPtr->nextPtr = firstExitPtr; - firstExitPtr = exitPtr; - Tcl_MutexUnlock(&exitMutex); -} - -/* - *---------------------------------------------------------------------- - * - * TkDeleteExitHandler -- - * - * Same as Tcl_DeleteExitHandler, but private to Tk. - * - * Results: - * None. - * - * Side effects. - * None. - * - *---------------------------------------------------------------------- - */ - -void -TkDeleteExitHandler( - Tcl_ExitProc *proc, /* Function that was previously registered. */ - ClientData clientData) /* Arbitrary value to pass to proc. */ -{ - ExitHandler *exitPtr, *prevPtr; - - Tcl_MutexLock(&exitMutex); - for (prevPtr = NULL, exitPtr = firstExitPtr; exitPtr != NULL; - prevPtr = exitPtr, exitPtr = exitPtr->nextPtr) { - if ((exitPtr->proc == proc) - && (exitPtr->clientData == clientData)) { - if (prevPtr == NULL) { - firstExitPtr = exitPtr->nextPtr; - } else { - prevPtr->nextPtr = exitPtr->nextPtr; - } - ckfree(exitPtr); - break; - } - } - Tcl_MutexUnlock(&exitMutex); - return; -} - -/* - *---------------------------------------------------------------------- - * - * TkCreateThreadExitHandler -- - * - * Same as Tcl_CreateThreadExitHandler, but private to Tk. - * - * Results: - * None. - * - * Side effects: - * Proc will be invoked with clientData as argument when the application - * exits. - * - *---------------------------------------------------------------------- - */ - -void -TkCreateThreadExitHandler( - Tcl_ExitProc *proc, /* Function to invoke. */ - ClientData clientData) /* Arbitrary value to pass to proc. */ -{ - ExitHandler *exitPtr; - ThreadSpecificData *tsdPtr = - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - - exitPtr = ckalloc(sizeof(ExitHandler)); - exitPtr->proc = proc; - exitPtr->clientData = clientData; - - /* - * See comments in TkCreateExitHandler(). - */ - - if (tsdPtr->firstExitPtr == NULL/* && !TclInExit()*/) { - Tcl_CreateThreadExitHandler(TkFinalizeThread, NULL); - } - exitPtr->nextPtr = tsdPtr->firstExitPtr; - tsdPtr->firstExitPtr = exitPtr; -} - -/* - *---------------------------------------------------------------------- - * - * TkDeleteThreadExitHandler -- - * - * Same as Tcl_DeleteThreadExitHandler, but private to Tk. - * - * Results: - * None. - * - * Side effects: - * If there is an exit handler corresponding to proc and clientData then - * it is cancelled; if no such handler exists then nothing happens. - * - *---------------------------------------------------------------------- - */ - -void -TkDeleteThreadExitHandler( - Tcl_ExitProc *proc, /* Function that was previously registered. */ - ClientData clientData) /* Arbitrary value to pass to proc. */ -{ - ExitHandler *exitPtr, *prevPtr; - ThreadSpecificData *tsdPtr = - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - - for (prevPtr = NULL, exitPtr = tsdPtr->firstExitPtr; exitPtr != NULL; - prevPtr = exitPtr, exitPtr = exitPtr->nextPtr) { - if ((exitPtr->proc == proc) - && (exitPtr->clientData == clientData)) { - if (prevPtr == NULL) { - tsdPtr->firstExitPtr = exitPtr->nextPtr; - } else { - prevPtr->nextPtr = exitPtr->nextPtr; - } - ckfree(exitPtr); - return; - } - } -} - -/* - *---------------------------------------------------------------------- - * - * TkFinalize -- - * - * Runs our private exit handlers and removes itself from Tcl. This is - * benificial should we want to protect from dangling pointers should the - * Tk shared library be unloaded prior to Tcl which can happen on windows - * should the process be forcefully exiting from an exception handler. - * - * Results: - * None. - * - * Side effects. - * None. - * - *---------------------------------------------------------------------- - */ - -void -TkFinalize( - ClientData clientData) /* Arbitrary value to pass to proc. */ -{ - ExitHandler *exitPtr; - -#if defined(_WIN32) && !defined(STATIC_BUILD) - if (!tclStubsPtr) { - return; - } -#endif - - Tcl_DeleteExitHandler(TkFinalize, NULL); - - Tcl_MutexLock(&exitMutex); - for (exitPtr = firstExitPtr; exitPtr != NULL; exitPtr = firstExitPtr) { - /* - * Be careful to remove the handler from the list before invoking its - * callback. This protects us against double-freeing if the callback - * should call TkDeleteExitHandler on itself. - */ - - firstExitPtr = exitPtr->nextPtr; - Tcl_MutexUnlock(&exitMutex); - exitPtr->proc(exitPtr->clientData); - ckfree(exitPtr); - Tcl_MutexLock(&exitMutex); - } - firstExitPtr = NULL; - Tcl_MutexUnlock(&exitMutex); -} - -/* - *---------------------------------------------------------------------- - * - * TkFinalizeThread -- - * - * Runs our private thread exit handlers and removes itself from Tcl. - * This is beneficial should we want to protect from dangling pointers - * should the Tk shared library be unloaded prior to Tcl which can happen - * on Windows should the process be forcefully exiting from an exception - * handler. - * - * Results: - * None. - * - * Side effects. - * None. - * - *---------------------------------------------------------------------- - */ - -void -TkFinalizeThread( - ClientData clientData) /* Arbitrary value to pass to proc. */ -{ - ExitHandler *exitPtr; - ThreadSpecificData *tsdPtr = - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - - Tcl_DeleteThreadExitHandler(TkFinalizeThread, NULL); - - if (tsdPtr != NULL) { - tsdPtr->inExit = 1; - - for (exitPtr = tsdPtr->firstExitPtr; exitPtr != NULL; - exitPtr = tsdPtr->firstExitPtr) { - /* - * Be careful to remove the handler from the list before invoking - * its callback. This protects us against double-freeing if the - * callback should call TkDeleteThreadExitHandler on itself. - */ - - tsdPtr->firstExitPtr = exitPtr->nextPtr; - exitPtr->proc(exitPtr->clientData); - ckfree(exitPtr); - } - } -} - -/* - *---------------------------------------------------------------------- - * - * 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. - * - *---------------------------------------------------------------------- - */ - -void -Tk_MainLoop(void) -{ - while (Tk_GetNumMainWindows() > 0) { - Tcl_DoOneEvent(0); - } -} - -/* - * Local Variables: - * mode: c - * c-basic-offset: 4 - * fill-column: 78 - * End: - */ |