Annotation of micropolis/src/tk/tkshare.c, revision 1.1.1.1

1.1       root        1: /* 
                      2:  * tkShare.c --
                      3:  *
                      4:  *     This module implements a simple mechanism for sharing
                      5:  *     mouse- and button-related events among collections of
                      6:  *     windows.  It is used primarily for menus.  For example,
                      7:  *     if one menu is posted and mouse moves over the menu button
                      8:  *     for a different menu, then the menubutton needs to see the
                      9:  *     event so that it can post itself and unpost the first menu.
                     10:  *
                     11:  * Copyright 1990-1992 Regents of the University of California
                     12:  * Permission to use, copy, modify, and distribute this
                     13:  * software and its documentation for any purpose and without
                     14:  * fee is hereby granted, provided that the above copyright
                     15:  * notice appear in all copies.  The University of California
                     16:  * makes no representations about the suitability of this
                     17:  * software for any purpose.  It is provided "as is" without
                     18:  * express or implied warranty.
                     19:  */
                     20: 
                     21: #ifndef lint
                     22: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkShare.c,v 1.10 92/05/31 16:20:12 ouster Exp $ SPRITE (Berkeley)";
                     23: #endif /* not lint */
                     24: 
                     25: #include "tkconfig.h"
                     26: #include "tk.h"
                     27: 
                     28: /*
                     29:  * the global variable below is used to tell TkPointerEvent
                     30:  * not to do any processing on an event that we're forwarding from one
                     31:  * window to another.  This is really ugly.  Eventually this file and
                     32:  * tkGrab.c need to get merged together to produce something cleaner.
                     33:  */
                     34: 
                     35: XEvent *tkShareEventPtr = NULL;
                     36: 
                     37: /*
                     38:  * Sharing is implemented in terms of groups of windows, where events
                     39:  * are shared among all the windows in a group.  One of the following
                     40:  * structures exists for each group.
                     41:  */
                     42: 
                     43: typedef struct Group {
                     44:     Tk_Uid groupId;                    /* Identifies group uniquely among all
                     45:                                         * share groups. */
                     46:     Tk_Window *windows;                        /* Pointer to array of windows in
                     47:                                         * this group.  Malloc'ed. */
                     48:     int numWindows;                    /* Number of windows currently in
                     49:                                         * this group. */
                     50:     Tk_Window lastWindow;              /* Last window found that contained
                     51:                                         * an event.  Needed in order to
                     52:                                         * notify window when mouse moves out
                     53:                                         * of it.  NULL means nobody to
                     54:                                         * notify. */
                     55:     XEvent *activeEvent;               /* If non-NULL, means that a recursive
                     56:                                         * call to Tk_HandleEvent is in
                     57:                                         * progress for this share group, and
                     58:                                         * identifies event.  NULL means no
                     59:                                         * recursive call in progress.  Used
                     60:                                         * to avoid infinite recursion. */
                     61:     struct Group *nextPtr;             /* Next in list of all share groups. */
                     62: } Group;
                     63: 
                     64: static Group *groupList = NULL;                /* First in list of all share groups
                     65:                                         * currently defined. */
                     66: 
                     67: /*
                     68:  * Forward declarations for procedures defined later in this file:
                     69:  */
                     70: 
                     71: static void            DeleteGroup _ANSI_ARGS_((Group *groupPtr));
                     72: static void            ShareEventProc _ANSI_ARGS_((ClientData clientData,
                     73:                            XEvent *eventPtr));
                     74: 
                     75: /*
                     76:  *----------------------------------------------------------------------
                     77:  *
                     78:  * Tk_ShareEvents --
                     79:  *
                     80:  *     Add tkwin to a group of windows sharing events.
                     81:  *
                     82:  * Results:
                     83:  *     None.
                     84:  *
                     85:  * Side effects:
                     86:  *     In the future, if a button- or mouse-related event occurs for
                     87:  *     any window in the same group as tkwin, but the mouse is actually
                     88:  *     in tkwin (the event went to a different window because of a
                     89:  *     grab) then a synthetic event will be generated with tkwin as
                     90:  *     window and adjusted coordinates.
                     91:  *
                     92:  *----------------------------------------------------------------------
                     93:  */
                     94: 
                     95: void
                     96: Tk_ShareEvents(tkwin, groupId)
                     97:     Tk_Window tkwin;                   /* Token for window. */
                     98:     Tk_Uid groupId;                    /* Identifier for group among which
                     99:                                         * events are to be shared. */
                    100: {
                    101:     register Group *groupPtr;
                    102: 
                    103:     /*
                    104:      * See if this group exists.  If so, add the window to the group.
                    105:      */
                    106: 
                    107:     for (groupPtr = groupList; groupPtr != NULL;
                    108:            groupPtr = groupPtr->nextPtr) {
                    109:        Tk_Window *new;
                    110: 
                    111:        if (groupPtr->groupId != groupId) {
                    112:            continue;
                    113:        }
                    114:        new = (Tk_Window *) ckalloc((unsigned)
                    115:                (groupPtr->numWindows+1) * sizeof(Tk_Window *));
                    116:        memcpy((VOID *) (new+1), (VOID *) groupPtr->windows, 
                    117:                (groupPtr->numWindows * sizeof(Tk_Window *)));
                    118:        ckfree((char *) groupPtr->windows);
                    119:        groupPtr->windows = new;
                    120:        groupPtr->windows[0] = tkwin;
                    121:        groupPtr->numWindows++;
                    122:        break;
                    123:     }
                    124: 
                    125:     if (groupPtr == NULL) {
                    126:        /*
                    127:         * Group doesn't exist.  Make a new one.
                    128:         */
                    129:     
                    130:        groupPtr = (Group *) ckalloc(sizeof(Group));
                    131:        groupPtr->groupId = groupId;
                    132:        groupPtr->windows = (Tk_Window *) ckalloc(sizeof (Tk_Window *));
                    133:        groupPtr->windows[0] = tkwin;
                    134:        groupPtr->numWindows = 1;
                    135:        groupPtr->lastWindow = NULL;
                    136:        groupPtr->activeEvent = NULL;
                    137:        groupPtr->nextPtr = groupList;
                    138:        groupList = groupPtr;
                    139:     }
                    140: 
                    141:     /*
                    142:      * Create an event handler so we find out about relevant events
                    143:      * that are directed to tkwin.
                    144:      */
                    145: 
                    146:     Tk_CreateEventHandler(tkwin,
                    147:            ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
                    148:            ShareEventProc, (ClientData) groupPtr);
                    149: }
                    150: 
                    151: /*
                    152:  *----------------------------------------------------------------------
                    153:  *
                    154:  * Tk_UnshareEvents --
                    155:  *
                    156:  *     Remove tkwin from a group of windows sharing events.
                    157:  *
                    158:  * Results:
                    159:  *     None.
                    160:  *
                    161:  * Side effects:
                    162:  *     Tkwin will no longer participate in event-sharing for the
                    163:  *     given group, either as source of events or as destination.
                    164:  *
                    165:  *----------------------------------------------------------------------
                    166:  */
                    167: 
                    168: void
                    169: Tk_UnshareEvents(tkwin, groupId)
                    170:     Tk_Window tkwin;                   /* Token for window. */
                    171:     Tk_Uid groupId;                    /* Identifier for group. */
                    172: {
                    173:     register Group *groupPtr;
                    174:     int i;
                    175: 
                    176:     for (groupPtr = groupList; groupPtr != NULL;
                    177:            groupPtr = groupPtr->nextPtr) {
                    178:        if (groupPtr->groupId != groupId) {
                    179:            continue;
                    180:        }
                    181:        if (groupPtr->lastWindow == tkwin) {
                    182:            groupPtr->lastWindow = NULL;
                    183:        }
                    184:        for (i = 0; i < groupPtr->numWindows; i++) {
                    185:            if (groupPtr->windows[i] != tkwin) {
                    186:                continue;
                    187:            }
                    188:            if ((i+1) < groupPtr->numWindows) {
                    189:                memcpy((VOID *) (groupPtr->windows + i),
                    190:                        (VOID *) (groupPtr->windows + i + 1),
                    191:                        (groupPtr->numWindows - (i+1))*sizeof(Tk_Window *));
                    192:            }
                    193:            groupPtr->numWindows--;
                    194:            Tk_DeleteEventHandler(tkwin,
                    195:                    ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
                    196:                    ShareEventProc, (ClientData) groupPtr);
                    197:            if (groupPtr->numWindows == 0) {
                    198:                DeleteGroup(groupPtr);
                    199:            }
                    200:            return;
                    201:        }
                    202:     }
                    203: }
                    204: 
                    205: /*
                    206:  *----------------------------------------------------------------------
                    207:  *
                    208:  * DeleteGroup --
                    209:  *
                    210:  *     This procedure is called when a group has no more members.
                    211:  *     It deletes the group from the list of existing groups.
                    212:  *
                    213:  * Results:
                    214:  *     None.
                    215:  *
                    216:  * Side effects:
                    217:  *     Memory gets freed.
                    218:  *
                    219:  *----------------------------------------------------------------------
                    220:  */
                    221: 
                    222: static void
                    223: DeleteGroup(groupPtr)
                    224:     Group *groupPtr;                   /* Group to delete. */
                    225: {
                    226:     if (groupList == groupPtr) {
                    227:        groupList = groupPtr->nextPtr;
                    228:     } else {
                    229:        register Group *prevPtr;
                    230: 
                    231:        for (prevPtr = groupList; ; prevPtr = prevPtr->nextPtr) {
                    232:            if (prevPtr == NULL) {
                    233:                panic("DeleteGroup couldn't find group on shareList");
                    234:            }
                    235:            if (prevPtr->nextPtr == groupPtr) {
                    236:                prevPtr->nextPtr = groupPtr->nextPtr;
                    237:                break;
                    238:            }
                    239:        }
                    240:     }
                    241:     ckfree((char *) groupPtr->windows);
                    242:     ckfree((char *) groupPtr);
                    243: }
                    244: 
                    245: /*
                    246:  *----------------------------------------------------------------------
                    247:  *
                    248:  * ShareEventProc --
                    249:  *
                    250:  *     This procedure is invoked by the Tk dispatcher when an event
                    251:  *     occurs for which we need to implement sharing.
                    252:  *
                    253:  * Results:
                    254:  *     None.
                    255:  *
                    256:  * Side effects:
                    257:  *     If the mouse is actually in a window other than the one for
                    258:  *     which the event occurred, generate a new event translated to
                    259:  *     that window.
                    260:  *
                    261:  *----------------------------------------------------------------------
                    262:  */
                    263: 
                    264: static void
                    265: ShareEventProc(clientData, eventPtr)
                    266:     ClientData clientData;             /* Information about share group. */
                    267:     register XEvent *eventPtr;         /* Event that just occurred. */
                    268: {
                    269:     register Group *groupPtr = (Group *) clientData;
                    270:     register Tk_Window tkwin;
                    271:     Window window;
                    272:     XEvent newEvent, *savedActive, *savedShareEventPtr;
                    273:     int i, x, y;
                    274:     Tk_Uid savedId;
                    275:     register Group *grpPtr;
                    276: 
                    277:     /*
                    278:      * If this event was a synthetic one that we generated, then
                    279:      * don't bother to process it again.
                    280:      */
                    281: 
                    282:     if (groupPtr->activeEvent == eventPtr) {
                    283:        return;
                    284:     }
                    285:     savedActive = groupPtr->activeEvent;
                    286:     groupPtr->activeEvent = &newEvent;
                    287:     savedId = groupPtr->groupId;
                    288: 
                    289:     savedShareEventPtr = tkShareEventPtr;
                    290:     tkShareEventPtr = &newEvent;
                    291: 
                    292:     /*
                    293:      * Scan through all of the windows for this group to find the
                    294:      * first one (if any) that contains the event.
                    295:      */
                    296: 
                    297:     tkwin = NULL;              /* Not needed, but stops compiler warning. */
                    298:     for (i = 0; i < groupPtr->numWindows; i++) {
                    299:        Tk_Window tkwin2;
                    300: 
                    301:        tkwin = groupPtr->windows[i];
                    302:        Tk_GetRootCoords(tkwin, &x, &y);
                    303:        x = eventPtr->xmotion.x_root - x - Tk_Changes(tkwin)->border_width;
                    304:        y = eventPtr->xmotion.y_root - y - Tk_Changes(tkwin)->border_width;
                    305:        if ((x < 0) || (y < 0) || (x >= Tk_Width(tkwin))
                    306:                || (y >= Tk_Height(tkwin))) {
                    307:            continue;
                    308:        }
                    309:        for (tkwin2 = tkwin; ; tkwin2 = Tk_Parent(tkwin2)) {
                    310:            if (tkwin2 == NULL) {
                    311:                goto foundWindow;
                    312:            }
                    313:            if (!Tk_IsMapped(tkwin2)) {
                    314:                break;
                    315:            }
                    316:            if (((Tk_FakeWin *) (tkwin2))->flags & TK_TOP_LEVEL) {
                    317:                goto foundWindow;
                    318:            }
                    319:        }
                    320:     }
                    321: 
                    322:     foundWindow:
                    323:     window = None;     /* Not really needed but stops compiler warning. */
                    324:     if (i >= groupPtr->numWindows) {
                    325:        tkwin = NULL;
                    326:     } else {
                    327:        window = Tk_WindowId(tkwin);
                    328:     }
                    329: 
                    330:     /*
                    331:      * SPECIAL NOTE:  it is possible that any or all of the information
                    332:      * in groupPtr could be modified as part of the processing of the
                    333:      * events that we generate and hand to Tk_HandleEvent below.  For this
                    334:      * to work smoothly, it is imperative that we extract any information
                    335:      * we need from groupPtr (and from tkwin's, since they could be
                    336:      * deleted) before the first call to Tk_HandleEvent below.  The code
                    337:      * below may potentially pass an X window identifier to Tk_HandleEvent
                    338:      * after the window has been deleted, but as long as identifiers
                    339:      * aren't recycled Tk_HandleEvent will simply discard the event if
                    340:      * this occurs.
                    341:      */
                    342: 
                    343:     /*
                    344:      * If the pointer is in a different window now than the last time
                    345:      * we were invoked, send a LeaveNotify event to the old window and
                    346:      * an EnterNotify event to the new window.
                    347:      */
                    348: 
                    349:     newEvent = *eventPtr;
                    350:     newEvent.xany.send_event = True;
                    351:     if (tkwin != groupPtr->lastWindow) {
                    352:        newEvent = *eventPtr;
                    353:        newEvent.xany.send_event = True;
                    354:        newEvent.xcrossing.mode = TK_NOTIFY_SHARE;
                    355:        newEvent.xcrossing.detail = NotifyAncestor;
                    356:        newEvent.xcrossing.same_screen = True;
                    357:        newEvent.xcrossing.state = eventPtr->xmotion.state;
                    358:        if (groupPtr->lastWindow != NULL) {
                    359:            newEvent.xcrossing.type = LeaveNotify;
                    360:            newEvent.xcrossing.window = Tk_WindowId(groupPtr->lastWindow);
                    361:            Tk_GetRootCoords(groupPtr->lastWindow, &newEvent.xcrossing.x,
                    362:                    &newEvent.xcrossing.y);
                    363:            newEvent.xcrossing.x = eventPtr->xmotion.x_root
                    364:                    - newEvent.xcrossing.x
                    365:                    - Tk_Changes(groupPtr->lastWindow)->border_width;
                    366:            newEvent.xcrossing.y = eventPtr->xmotion.y_root
                    367:                    - newEvent.xcrossing.y
                    368:                    - Tk_Changes(groupPtr->lastWindow)->border_width;
                    369:            Tk_HandleEvent(&newEvent);
                    370:        }
                    371:        if (tkwin != NULL) {
                    372:            newEvent.xcrossing.type = EnterNotify;
                    373:            newEvent.xcrossing.window = window;
                    374:            newEvent.xcrossing.x = x;
                    375:            newEvent.xcrossing.y = y;
                    376:            Tk_HandleEvent(&newEvent);
                    377:        }
                    378:        groupPtr->lastWindow = tkwin;
                    379:     }
                    380: 
                    381:     /*
                    382:      * If the pointer is in the window to which the event was sent,
                    383:      * then we needn't do any forwarding at all.  Ditto if the pointer
                    384:      * isn't in any window at all.
                    385:      */
                    386: 
                    387:     if ((tkwin != NULL) && (Tk_WindowId(tkwin) != eventPtr->xmotion.window)) {
                    388:        newEvent = *eventPtr;
                    389:        newEvent.xmotion.send_event = True;
                    390:        newEvent.xmotion.window = window;
                    391:        newEvent.xmotion.x = x;
                    392:        newEvent.xmotion.y = y;
                    393:        Tk_HandleEvent(&newEvent);
                    394:     }
                    395: 
                    396:     /*
                    397:      * Only restore the activeEvent if the group still exists.
                    398:      * (It could be deleted as a side effect of processing the event.)
                    399:      */
                    400: 
                    401:     for (grpPtr = groupList; grpPtr != NULL; grpPtr = grpPtr->nextPtr) {
                    402:        if (grpPtr->groupId == savedId) {
                    403:            groupPtr->activeEvent = savedActive;
                    404:            break;
                    405:        }
                    406:     }
                    407: 
                    408:     tkShareEventPtr = savedShareEventPtr;
                    409: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.