summaryrefslogtreecommitdiffstats
path: root/tk8.6/generic/tkEvent.c
diff options
context:
space:
mode:
Diffstat (limited to 'tk8.6/generic/tkEvent.c')
-rw-r--r--tk8.6/generic/tkEvent.c2158
1 files changed, 0 insertions, 2158 deletions
diff --git a/tk8.6/generic/tkEvent.c b/tk8.6/generic/tkEvent.c
deleted file mode 100644
index d058e7c..0000000
--- a/tk8.6/generic/tkEvent.c
+++ /dev/null
@@ -1,2158 +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;
- }
- winPtr->ximGeneration = dispPtr->ximGeneration;
-
- /*
- * 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 the XIC has been invalidated, it must be recreated.
- */
- if (winPtr->dispPtr->ximGeneration != winPtr->ximGeneration) {
- winPtr->flags &= ~TK_CHECKED_IC;
- winPtr->inputContext = NULL;
- }
-
- 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->dispPtr->inputMethod != NULL) &&
- (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:
- */