Annotation of micropolis/src/tk/tkshare.c, revision 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.