|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - downloadIndex: ┃ T s ┃
Length: 19042 (0x4a62) Types: TextFile Names: »sxDispatch.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki └─ ⟦526ad3590⟧ »EUUGD11/gnu-31mar87/X.V10.R4.tar.Z« └─⟦2109abc41⟧ └─ ⟦this⟧ »./X.V10R4/Toolkit/Sx/code/sxDispatch.c«
/* * $Source: /u1/Sx.new/code/RCS/sxDispatch.c,v $ * $Header: sxDispatch.c,v 1.1 86/12/03 16:09:48 swick Exp $ */ #ifndef lint static char *rcsid_sxDispatch_c = "$Header: sxDispatch.c,v 1.1 86/12/03 16:09:48 swick Exp $"; #endif lint /* * sxDispatch.c -- * * This file implements the sx dispatcher, which processes * events and calls clients that have expressed an interest * in the events. * * Copyright (C) 1986 Regents of the University of California * Permission to use, copy, modify, and distribute this * software and its documentation for any purpose and without * fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright * notice and this permission notice appear in supporting * documentation. The University of California makes no * representations about the suitability of this software for * any purpose. It is provided "as is" without express or * implied warranty. */ #ifndef lint static char rcsid[] = "$Header: sxDispatch.c,v 1.1 86/12/03 16:09:48 swick Exp $ SPRITE (Berkeley)"; #endif not lint #include <sys/types.h> #include <X/Xlib.h> #include "sprite.h" #include "mem.h" #include "sx.h" /* * Miscellaneous imports: */ extern XAssocTable *XCreateAssocTable(); /* * The following data structure is used to keep track of the handlers * declared by calls to Sx_HandlerCreate. One such structure is allocated * for each call to Sx_HandlerCreate. In order to keep users from having * to see the guts of a handler, it's declared here as a different type * and cast into and out of the user's type as needed. */ typedef struct Handler { Window w; /* Window in which event must occur. */ int mask; /* Mask of events in w that are desired. */ void (*proc)(); /* Procedure to call for each such event. */ ClientData clientData; /* Additional stuff to pass to proc. */ struct Handler *nextPtr; /* Next handler in list of those associated * with this window, or NULL for end of * list. */ } Handler; /* * The data structure below is kept on a window-by-window basis. There * is one for each window that's created by this client or used in a * Sx_HandlerCreate call. These structures record the window structure * so that when windows get deleted, clients requested SX_DESTROYED events * can be notified (must keep track of structure because when parent gets * deleted X will automatically delete children). The structure also * points to a list of handlers that have been declared for the window. * The addresses of WindowStuff structures are kept in the windowAssocs * hash table. */ typedef struct WindowStuff { Window w; /* X's id for window. */ int width, height; /* Must save width and height to help * in translating ExposeRegion events * into ExposeWindow events. */ Handler *firstHandler; /* First in list of handlers * associated with this window. */ struct WindowStuff *parentPtr; /* Points to parent, if this window's * parent is known, or NULL if parent * isn't known (because window wasn't * created by this client). */ struct WindowStuff *childPtr; /* First in list of children of this * window. NULL means no children. */ struct WindowStuff *nextPtr; /* Next in list of siblings with same * parent. NULL means end of list. */ } WindowStuff; /* * To make it easy to locate information associated with a particular * window, an XAssocTable is used to keep track of all the WindowStuff * structures: */ static XAssocTable *windowTable = NULL; /* * There's a potential problem if a handler is deleted while it's * current (i.e. it's procedure is executing), since Sx_HandleEvent * will need to read the handle's "nextPtr" field when the procedure * returns. To handle this problem, the variable below is used to * hold the address of the next handler to be considered by * Sx_HandleEvent. It gets updated if the handler pointed to is * deleted. */ static Handler *nextHandler; /* * X doesn't do mouse-grabbing quite right (it's grabbing by a CLIENT, * not a window), so we do it right here. The variable below keeps track * of the window that has grabbed input. */ static Window grabbingWindow; /* * The variable below serves no purpose except to force the * locally-modified versions of several X library routines to * be included from the Sx library (even if they don't appear * to be needed). */ static Window (*dummy)() = XCreateWindow; /* * Forward references to things defined later in this file: */ extern WindowStuff * GetStuff(); \f /* *---------------------------------------------------------------------- * * Sx_HandlerCreate -- * * This procedure sets up a handler for a particular class * of events on a particular window. * * Results: * The return value is a handler, which can be passed to * Sx_HandlerDelete to delete the handler (the handler should * be deleted before deleting w). * * Side effects: * From now on, whenever an event of one of the types given * by mask occurs for w and is processed by Sx_HandleEvent, * proc will be called as shown below: * * void * proc(clientData, eventPtr) * ClientData clientData; * XEvent *eventPtr; * { * } * * In the call to proc, clientData is the same value passed to * Sx_HandlerCreate and eventPtr refers to X'es description of * the event. multiple handlers have been specified for a * given event, then they are invoked in the order they were set * up. * * Another side effect of this procedure is that a call is made * to XSelectInput to change the set of events selected for this * window. * *---------------------------------------------------------------------- */ Sx_EventHandler Sx_HandlerCreate(w, mask, proc, clientData) Window w; /* Window for which event was generated. */ int mask; /* Events for which proc should be called. * May be any of the X event types, or * SX_DESTROYED. SX_DESTROYED events * are generated whenever the window is * destroyed. These events only work for * windows created by this client. */ void (*proc)(); /* Procedure to call for each selected event */ ClientData clientData; /* Arbitrary data to pass to proc. */ { WindowStuff *wsPtr; Handler *handlerPtr; register Handler *h2Ptr; int windowMask; wsPtr = GetStuff(w); if ((mask & SX_DESTROYED) && (wsPtr->parentPtr == NULL)) { Sx_Panic("Sx_HandlerCreate: can't select SX_DESTROYED for \ windows not created by this client"); } /* * Add a new handler to the end of the list of handlers for the * window. While skimming through the list, compute the overall * event mask for the window, so we can pass this new value to * the X system. */ handlerPtr = (Handler *) Mem_Alloc(sizeof(Handler)); handlerPtr->w = w; handlerPtr->mask = mask; handlerPtr->proc = proc; handlerPtr->clientData = clientData; handlerPtr->nextPtr = NULL; windowMask = mask; if (wsPtr->firstHandler == NULL) { wsPtr->firstHandler = handlerPtr; } else { for (h2Ptr = wsPtr->firstHandler; ; h2Ptr = h2Ptr->nextPtr) { windowMask |= h2Ptr->mask; if (h2Ptr->nextPtr == NULL) { h2Ptr->nextPtr = handlerPtr; break; } } } /* * Make sure that X knows about all the events of interest in this * window. */ XSelectInput(w, windowMask); return (Sx_EventHandler) handlerPtr; } \f /* *---------------------------------------------------------------------- * * Sx_HandlerDelete -- * * Remove a handler. * * Results: * None. * * Side effects: * After this call, the handler will never be invoked again (unless * it is recreated with a call to Sx_HandlerCreate). * *---------------------------------------------------------------------- */ void Sx_HandlerDelete(handlerToken) Sx_EventHandler handlerToken; /* Token for handler to delete; must * have been returned by previous call * to Sx_HandlerCreate. */ { register Handler *handlerPtr = (Handler *) handlerToken; WindowStuff *wsPtr; register Handler *prevPtr; int mask; /* * Remove the handler from the chain associated with its * window, and compute the new mask of events desired from * the window. */ wsPtr = (WindowStuff *) XLookUpAssoc(windowTable, handlerPtr->w); if (wsPtr == NULL) { return; } mask = 0; if (wsPtr->firstHandler == handlerPtr) { wsPtr->firstHandler = handlerPtr->nextPtr; } else for (prevPtr = wsPtr->firstHandler; prevPtr != NULL; prevPtr = prevPtr->nextPtr) { if (prevPtr->nextPtr == handlerPtr) { prevPtr->nextPtr = handlerPtr->nextPtr; } mask |= prevPtr->mask; } /* * If Sx_HandleEvent is about to process this handler, tell it to * process the next one instead. */ if (nextHandler == handlerPtr) { nextHandler = handlerPtr->nextPtr; } /* * Free the handler and tell X about the events we're now interested in. */ XSelectInput(handlerPtr->w, mask); Mem_Free((char *) handlerPtr); } \f /* *---------------------------------------------------------------------- * * Sx_HandleEvent -- * * This procedure processes an event, calling all the handlers * that have been declared for that event. * * Results: * None. * * Side effects: * The only side effects are those taken by the handlers. * *---------------------------------------------------------------------- */ void Sx_HandleEvent(eventPtr) XEvent *eventPtr; /* Event to be parceled off to handler(s). */ { register Handler *handlerPtr; register WindowStuff *wsPtr; register XExposeWindowEvent *eventReg; XKeyOrButtonEvent grabbedEvent; register int type; /* * First, see if window grabbing is in effect. If so, translate the * event to the grabbed window's coordinates. Ignore EnterWindow and * LeaveWindow events when grabbing is in effect. */ if ((grabbingWindow != 0) && (grabbingWindow != eventPtr->window)) { if (eventPtr->type & (EnterWindow|LeaveWindow)) { return; } else if (eventPtr->type & (ButtonPressed|ButtonReleased|MouseMoved)) { int x, y; grabbedEvent = *((XKeyOrButtonEvent *) eventPtr); (void) XInterpretLocator(grabbingWindow, &x, &y, &grabbedEvent.subwindow, grabbedEvent.location); grabbedEvent.window = grabbingWindow; grabbedEvent.x = x; grabbedEvent.y = y; eventPtr = (XEvent *) &grabbedEvent; } } /* * Locate information for the event's window. */ if (windowTable == NULL) { return; } eventReg = (XExposeWindowEvent *) eventPtr; type = eventReg->type; wsPtr = (WindowStuff *) XLookUpAssoc(windowTable, eventReg->window); if (wsPtr == NULL) { return; } /* * Keep our information about the window's size up-to-date (needed * for ExposeRegion event translation, below). */ if (eventReg->type == ExposeWindow) { wsPtr->width = eventReg->width; wsPtr->height = eventReg->height; } /* * MouseMoved events have to be translated to LeftDownMotion, * MiddleDownMotion, and RightDownMotion events. */ if (type == MouseMoved) { if (eventReg->detail & LeftMask) { type |= LeftDownMotion; } if (eventReg->detail & MiddleMask) { type |= MiddleDownMotion; } if (eventReg->detail & RightMask) { type |= RightDownMotion; } } /* * There's a potential interaction here with Sx_HandlerDelete. * Read the documentation for nextHandler. */ for (handlerPtr = wsPtr->firstHandler; handlerPtr != NULL; handlerPtr = nextHandler) { nextHandler = handlerPtr->nextPtr; if ((handlerPtr->mask & type) != 0) { (*(handlerPtr->proc))(handlerPtr->clientData, eventReg); } else if ((type == ExposeRegion) && (handlerPtr->mask & ExposeWindow)) { XExposeEvent newEvent; /* * If the client requested ExposeWindow events but we * get ExposeRegion events (because some other client * requested them), we've got to translate. */ newEvent.type = ExposeWindow; newEvent.window = eventReg->window; newEvent.detail = eventReg->detail; newEvent.width = wsPtr->width; newEvent.height = wsPtr->height; newEvent.subwindow = eventReg->subwindow; newEvent.x = newEvent.y = 0; (*(handlerPtr->proc))(handlerPtr->clientData, &newEvent); } } } \f /* *---------------------------------------------------------------------- * * Sx_GrabMouse -- * * Arrange for all future mouse-related events to be passed to * a particular window, even if the mouse is over some other * window. Note: clients should not ever call XGrabMouse * directly if they use this routine. * * Results: * None. * * Side effects: * Until Sx_UngrabMouse is called, all mouse-related events * arriving for any window other than w will be redirected * to w. If some other window had already grabbed the mouse, * it is automatically un-grabbed. Only events indicated by * mask will be considered; all others will be ignored until * Sx_UngrabMouse is called. * *---------------------------------------------------------------------- */ void Sx_GrabMouse(w, cursor, mask) Window w; /* Window to which to direct mouse events. */ Cursor cursor; /* New cursor to use while mouse is grabbed. */ int mask; /* Mask of events to be accepted during grab period. */ { if (grabbingWindow != 0) { Sx_UngrabMouse(); } grabbingWindow = w; (void) XGrabMouse(w, cursor, mask); } \f /* *---------------------------------------------------------------------- * * Sx_UngrabMouse -- * * Undoes the effects of a previous call to Sx_GrabMouse, allowing * mouse-related events to be directed to windows in the normal * fashion. * * Results: * None. * * Side effects: * Mouse grabbing is turned off. * *---------------------------------------------------------------------- */ void Sx_UngrabMouse() { grabbingWindow = 0; XUngrabMouse(); } \f /* *---------------------------------------------------------------------- * * SxWindowCreated -- * * This procedure is called by the X library routines just after * a new window is created. This call records structural * information about that window for use in handling SX_DESTROYED * events. * * Results: * None. * * Side effects: * Information about the new window is added to windowTable. * *---------------------------------------------------------------------- */ void SxWindowCreated(parent, child) Window parent; /* Parent of new window. */ Window child; /* Child of new window. */ { WindowStuff *parentPtr, *childPtr; parentPtr = GetStuff(parent); childPtr = GetStuff(child); childPtr->parentPtr = parentPtr; childPtr->nextPtr = parentPtr->childPtr; parentPtr->childPtr = childPtr; } \f /* *---------------------------------------------------------------------- * * SxWindowDestroyed -- * * Called by the X library routines after a window is destroyed. * It cleans up structures maintained here, plus calls all the * clients that have selected SX_DESTROYED events. It also * assumes the destruction of all descendants of this window, and * handles them in the same way. * * Results: * None. * * Side effects: * The WindowStuff information for this window (and all its * descendants) gets deleted, and SX_DESTROYED event handlers * get called. * *---------------------------------------------------------------------- */ void SxWindowDestroyed(w) Window w; /* What was destroyed. */ { register WindowStuff *wsPtr; WindowStuff *siblingPtr; Handler *handler; XEvent event; /* * Get the entry for this window out of the hash table, and remove * it also from the list of children of its parent. */ wsPtr = (WindowStuff *) XLookUpAssoc(windowTable, w); if (wsPtr == NULL) { return; } XDeleteAssoc(windowTable, w); if (wsPtr->parentPtr != NULL) { if (wsPtr->parentPtr->childPtr == wsPtr) { wsPtr->parentPtr->childPtr = wsPtr->nextPtr; } else { for (siblingPtr = wsPtr->parentPtr->childPtr; siblingPtr != NULL; siblingPtr = siblingPtr->nextPtr) { if (siblingPtr->nextPtr == wsPtr) { siblingPtr->nextPtr = wsPtr->nextPtr; break; } } } } /* * Call all handlers that want to know about deletions, and also * delete the handlers along the way. */ event.type = SX_DESTROYED; event.window = w; event.pad_l1 = event.pad_l2 = 0; event.subwindow = 0; event.pad_l4 = 0; while (wsPtr->firstHandler != NULL) { handler = wsPtr->firstHandler; if (handler->mask & SX_DESTROYED) { (*handler->proc)(handler->clientData, &event); } wsPtr->firstHandler = handler->nextPtr; Mem_Free((Address) handler); } /* * Recursively delete all of the children of this window. */ while (wsPtr->childPtr != NULL) { SxWindowDestroyed(wsPtr->childPtr->w); } Mem_Free((Address) wsPtr); } \f /* *---------------------------------------------------------------------- * * SxSubwindowsDestroyed -- * * Called as part of the XDestroySubwindows call. It calls * SxWindowDestroyed for each deleted subwindow. * * Results: * None. * * Side effects: * See SxWindowDestroyed. * *---------------------------------------------------------------------- */ void SxSubwindowsDestroyed(w) Window w; /* Window whose subwindows are all dead now. */ { register WindowStuff * wsPtr; wsPtr = (WindowStuff *) XLookUpAssoc(windowTable, w); if (wsPtr == NULL) { return; } while (wsPtr->childPtr != NULL) { SxWindowDestroyed(wsPtr->childPtr->w); } } \f /* *---------------------------------------------------------------------- * * GetStuff -- * * This procedure is called to create the dispatching association * table if necessary, and also to create an entry in it for a * particular window. * * Results: * The return value is a pointer to the WindowStuff associated * with w, which will be newly initialized if there wasn't * previously an entry for w. * * Side effects: * A new entry may be added to windowTable. * *---------------------------------------------------------------------- */ static WindowStuff * GetStuff(w) Window w; { register WindowStuff *wsPtr; if (windowTable == NULL) { windowTable = XCreateAssocTable(32); dummy = dummy; /* Just to keep lint from complaining. */ } wsPtr = (WindowStuff *) XLookUpAssoc(windowTable, w); if (wsPtr == NULL) { wsPtr = (WindowStuff *) Mem_Alloc(sizeof(WindowStuff)); wsPtr->w = w; wsPtr->width = wsPtr->height = 0; wsPtr->firstHandler = NULL; wsPtr->parentPtr = NULL; wsPtr->childPtr = NULL; wsPtr->nextPtr = NULL; XMakeAssoc(windowTable, w, (caddr_t) wsPtr); } return wsPtr; }