Annotation of 43BSDTahoe/new/X/XMenu/XMenuActivate.c, revision 1.1.1.1

1.1       root        1: /* $Header: XMenuActivate.c,v 10.19 86/07/11 16:50:09 tony Rel $ */
                      2: /* Copyright    Massachusetts Institute of Technology    1985  */
                      3: 
                      4: /*
                      5:  * XMenu:      MIT Project Athena, X Window system menu package
                      6:  *
                      7:  *     XMenuActivate - Maps a given menu to the display and activates
                      8:  *                     the menu for user selection.  The user is allowed to
                      9:  *                     specify which pane and selection will be current,
                     10:  *                     the X and Y location of the menu (relative to the
                     11:  *                     parent window) and the mouse button event mask that
                     12:  *                     will be used to identify a selection request.
                     13:  *
                     14:  *                     A menu selection is shown to be current by placing
                     15:  *                     a highlight box around the selection as the mouse
                     16:  *                     cursor enters its active region.  Inactive selections
                     17:  *                     will not be highlited.  As the mouse cursor moved
                     18:  *                     from one menu pane to another menu pane the pane being
                     19:  *                     entered is raised and made current and the pane being
                     20:  *                     left is lowered.
                     21:  *
                     22:  *                     Anytime XMenuActivate returns, the p_num and
                     23:  *                     s_num are left at their last known values (i.e.,
                     24:  *                     the last known current pane and selection indices).
                     25:  *                     The following are the defined return states:
                     26:  *
                     27:  *                     1)      If at any time an error occurs the data
                     28:  *                             pointer is left untouched and XM_FAILURE
                     29:  *                             is returned.  
                     30:  *
                     31:  *                     2)      When a selection request is recieved (i.e.,
                     32:  *                             when the specified mouse event occurs) the
                     33:  *                             data pointer will be set to the data
                     34:  *                             associated with the particular selection
                     35:  *                             current at the time of the selection request
                     36:  *                             and XM_SUCCESS is returned.
                     37:  *
                     38:  *                     3)      If no selection was current at the time a
                     39:  *                             selection request is made the data pointer
                     40:  *                             will be left untouched and XM_NO_SELECT will
                     41:  *                             be returned.
                     42:  *
                     43:  *                     4)      If the selection that was current at the time 
                     44:  *                             a selection request is made is not an active
                     45:  *                             selection the data pointer will be left
                     46:  *                             untouched and XM_IA_SELECT will be returned.
                     47:  *
                     48:  *                     Since X processes events in an asynchronous manner
                     49:  *                     it is likely that XMenuActivate will encounter
                     50:  *                     a "foreign event" while it is executing.  Foreign
                     51:  *                     events are handled in one of three ways:
                     52:  *
                     53:  *                     1)      The event is discarded.  This is the default
                     54:  *                             mode and requires no action on the part of the
                     55:  *                             application.
                     56:  *
                     57:  *                     2)      The application has identified an asynchronous
                     58:  *                             event handler that will be called and the
                     59:  *                             foreign event handed off to it.  Note:
                     60:  *                             AEQ mode disables this mode temporarily.
                     61:  *
                     62:  *                     3)      The application has enabled asynchronous event
                     63:  *                             queueing mode.  In this mode all foreign events
                     64:  *                             will be queued up untill XMenuActivate
                     65:  *                             terminates; at which time they will be
                     66:  *                             returned to the X event queue.  As long as
                     67:  *                             AEQ mode is enabled any asynchronous event
                     68:  *                             handler as temporarily disabled.
                     69:  *
                     70:  *                     Any events encountered while taking down the menu
                     71:  *                     (i.e., exposure events from occluded windows) will
                     72:  *                     automatically be returned to the X event queue after
                     73:  *                     XMenuActivate has cleaned the queue of any of its own
                     74:  *                     events that are no longer needed.
                     75:  *
                     76:  *     Author:         Tony Della Fera, DEC
                     77:  *                     March 12, 1986
                     78:  *
                     79:  */
                     80: 
                     81: #include "XMenuInternal.h"
                     82: 
                     83: int
                     84: XMenuActivate(menu, p_num, s_num, x_pos, y_pos, event_mask, data)
                     85:     register XMenu *menu;              /* Menu to activate. */
                     86:     int *p_num;                                /* Pane number selected. */
                     87:     int *s_num;                                /* Selection number selected. */
                     88:     int x_pos;                         /* X coordinate of menu position. */
                     89:     int y_pos;                         /* Y coordinate of menu position. */
                     90:     int event_mask;                    /* Mouse button event mask. */
                     91:     char **data;                       /* Pointer to return data value. */
                     92: {
                     93:     register int i;                    /* Loop counter. */
                     94:     int status;                                /* X routine call status. */
                     95:     int orig_x;                                /* Upper left menu origin X coord. */
                     96:     int orig_y;                                /* Upper left menu origin Y coord. */
                     97:     int save_x;                                /* Upper left X of save region. */
                     98:     int save_y;                                /* Upper left Y of save region. */
                     99:     int save_w;                                /* Width of pixmap save region. */
                    100:     int save_h;                                /* Height of pixmap save region. */
                    101:     int save_w_offscr;                 /* Pixmap save width off screen. */
                    102:     int save_h_offscr;                 /* Pixmap save height off screen. */
                    103:     int x, y;                          /* Dummy X and Y arguments. */
                    104:     int ret_val;                       /* Return value. */
                    105: 
                    106:     register XMPane *p_ptr;            /* Current XMPane. */
                    107:     register XMPane *event_xmp;                /* Event XMPane pointer. */
                    108:     register XMPane *cur_p;            /* Current pane. */
                    109:     register XMSelect *cur_s;          /* Current selection. */
                    110:     XMWindow *event_xmw;               /* Event XMWindow pointer. */
                    111:     XEvent event;                      /* X input event. */
                    112:     XCrossingEvent *xc_event;          /* X window crossing event. */
                    113:     Window xc_window;                  /* X window crossing event window. */
                    114: 
                    115:     Pixmap save_pixmap;                        /* Pixmap to save bits under menu. */
                    116: 
                    117:     Bool saved = TRUE;                 /* Pixmap save succeeded. */
                    118:     Bool selection = FALSE;            /* Selection has been made. */
                    119:     Bool forward = TRUE;               /* Moving forward in the pane list. */
                    120:     Bool p_lock = TRUE;                        /* Pane entrance lock. */
                    121:     Bool s_lock = TRUE;                        /* Selection entrance lock. */
                    122: 
                    123:     /*
                    124:      * Define and allocate a foreign event queue to hold events
                    125:      * that don't belong to XMenu.  These events are later restored
                    126:      * to the X event queue.
                    127:      */
                    128:     typedef struct _xmeventque {
                    129:        XEvent event;
                    130:        struct _xmeventque *next;
                    131:     } XMEventQue;
                    132: 
                    133:     XMEventQue *feq = NULL;                    /* Foreign event queue. */
                    134:     XMEventQue *feq_tmp;               /* Foreign event queue temporary. */
                    135: 
                    136:     /*
                    137:      * Are the position arguments are positive?
                    138:      */
                    139:     if ((x_pos <= 0) || (y_pos <= 0)) {
                    140:        _XMErrorCode = XME_ARG_BOUNDS;
                    141:        return(XM_FAILURE);
                    142:     }
                    143: 
                    144:     /*
                    145:      * If there are no panes in the menu then return failure
                    146:      * beacuse the menu is not initialized.
                    147:      */
                    148:     if (menu->p_count == 0) {
                    149:        _XMErrorCode = XME_NOT_INIT;
                    150:        return(XM_FAILURE);
                    151:     }
                    152: 
                    153:     /*
                    154:      * Find the desired current pane.
                    155:      */
                    156:     cur_p = _XMGetPanePtr(menu, *p_num);
                    157:     if (cur_p == NULL) return(XM_FAILURE);
                    158: 
                    159:     /*
                    160:      * Find the desired current selection.
                    161:      * If the current selection index is out of range a null current selection
                    162:      * will be assumed and the cursor will be placed in the current pane
                    163:      * header.
                    164:      */
                    165:     cur_s = _XMGetSelectionPtr(cur_p, *s_num);
                    166: 
                    167:     /*
                    168:      * Check to see that the menu's dependencies have been
                    169:      * recomputed and are up to date.  If not, do it now.
                    170:      */
                    171:     if (menu->recompute) XMenuRecompute(menu);
                    172: 
                    173:     /*
                    174:      * If the current pane is active then activate it.
                    175:      */
                    176:     if (cur_p->active) {
                    177:        cur_p->activated = 1;
                    178:        XChangeBackground(cur_p->window, menu->bkgnd_pixmap);
                    179:     }
                    180: 
                    181:     /*
                    182:      * Compute the new menu origin such that the cursor hot point lies
                    183:      * in the center of the desired current pane and selection.
                    184:      */
                    185:     _XMTransToOrigin(menu, cur_p, cur_s, x_pos, y_pos, &orig_x, &orig_y);
                    186: 
                    187:     /*
                    188:      * Then move all the panes into position relative to the newly
                    189:      * computed origin.
                    190:      */
                    191:     for (
                    192:        p_ptr = menu->p_list->next;
                    193:        p_ptr != menu->p_list;
                    194:        p_ptr = p_ptr->next
                    195:     ){
                    196:        XMoveWindow(
                    197:            p_ptr->window,
                    198:            orig_x + p_ptr->window_x,
                    199:            orig_y + p_ptr->window_y
                    200:        );
                    201:     }
                    202: 
                    203:     /*<
                    204:      * If server freeze mode is selected...
                    205:      */
                    206:     if (menu->freeze) {
                    207:        /*
                    208:         * Compute pixmap save region.
                    209:         */
                    210:        save_x = max(orig_x, 0);
                    211:        save_y = max(orig_y, 0);
                    212:        save_w_offscr = (orig_x + menu->width) - DisplayWidth();
                    213:        save_h_offscr = (orig_y + menu->height) - DisplayHeight();
                    214:        if (save_w_offscr < 0) save_w = menu->width;
                    215:        else save_w = menu->width - save_w_offscr;
                    216:        if (save_h_offscr < 0) save_h = menu->height;
                    217:        else save_h = menu->height - save_h_offscr;
                    218: 
                    219:        /*
                    220:         * Grab the X server.
                    221:         */
                    222:        XGrabServer();
                    223: 
                    224:        /* 
                    225:         * Save the bits under where the menu will be.
                    226:         */
                    227:        save_pixmap = XPixmapSave(
                    228:            menu->parent,
                    229:            save_x, save_y,
                    230:            save_w, save_h
                    231:        );
                    232:        if (save_pixmap == _X_FAILURE) saved = FALSE;
                    233:     }
                    234:     else {
                    235:        saved = FALSE;
                    236:     }
                    237: 
                    238:     /*
                    239:      * Synchronize the X buffers and the event queue.
                    240:      * From here on, all events in the queue that don't belong to
                    241:      * XMenu are send back to the application via an application
                    242:      * provided event handler or discarded if the application has
                    243:      * not provided an event handler.
                    244:      */
                    245:     XSync(0);
                    246:     
                    247:     /*
                    248:      * Grab the mouse for menu input.
                    249:      */
                    250:     status = XGrabMouse(menu->parent, menu->mouse_cursor, event_mask);
                    251:     if (status == _X_FAILURE) {
                    252:        _XMErrorCode = XME_GRAB_MOUSE;
                    253:        return(XM_FAILURE);
                    254:     }
                    255: 
                    256:     /*
                    257:      * Map the menu panes.
                    258:      */
                    259:     for (
                    260:        p_ptr = menu->p_list->prev;
                    261:        p_ptr != menu->p_list;
                    262:        p_ptr = p_ptr->prev
                    263:     ){
                    264:        if (p_ptr == cur_p) break;
                    265:        XMapWindow(p_ptr->window);
                    266:     }
                    267:     for (
                    268:        p_ptr = menu->p_list->next;
                    269:        p_ptr != menu->p_list;
                    270:        p_ptr = p_ptr->next
                    271:     ){
                    272:        if (p_ptr == cur_p) break;
                    273:        XMapWindow(p_ptr->window);
                    274:     }
                    275:     XMapWindow(cur_p->window);
                    276:     
                    277:     /*
                    278:      * Clear the current selection.
                    279:      */
                    280:     cur_s = NULL;
                    281: 
                    282:     /*
                    283:      * Begin event processing loop.
                    284:      */
                    285:     while (1) {
                    286:        /*
                    287:         * Fetch the next event.
                    288:         */
                    289:        XNextEvent(&event);
                    290:        /*
                    291:         * Dispatch on the event type.
                    292:         */
                    293:        switch (event.type) {
                    294:            case ExposeWindow:
                    295:                event_xmp = (XMPane *)XLookUpAssoc(
                    296:                    menu->assoc_tab, event.window
                    297:                );
                    298:                if (event_xmp == NULL) {
                    299:                    /*
                    300:                     * If AEQ mode is enabled then queue the event.
                    301:                     */
                    302:                    if (menu->aeq) {
                    303:                        feq_tmp = (XMEventQue *)malloc(sizeof(XMEventQue));
                    304:                        if (feq_tmp == NULL) {
                    305:                            _XMErrorCode = XME_CALLOC;
                    306:                            return(XM_FAILURE);
                    307:                        }
                    308:                        feq_tmp->event = event;
                    309:                        feq_tmp->next = feq;
                    310:                        feq = feq_tmp;
                    311:                    }
                    312:                    else if (_XMEventHandler) (*_XMEventHandler)(&event);
                    313:                    break;
                    314:                }
                    315:                if (event_xmp == cur_p) {
                    316:                    _XMRefreshPane(menu, cur_p);
                    317:                }
                    318:                else _XMRefreshPaneText(menu, event_xmp);
                    319:                break;
                    320:            case EnterWindow:
                    321:                event_xmw = (XMWindow *)XLookUpAssoc(
                    322:                    menu->assoc_tab,
                    323:                    event.window
                    324:                );
                    325:                if (event_xmw == NULL) break;
                    326:                if (event_xmw->type == SELECTION) {
                    327:                    /*
                    328:                     * We have entered a selection.
                    329:                     */
                    330:                    cur_s = (XMSelect *)event_xmw;
                    331:                    /*
                    332:                     * If the pane we are in is active and the
                    333:                     * selection entered is active then activate
                    334:                     * the selection.
                    335:                     */
                    336:                    if (cur_p->active && cur_s->active) {
                    337:                        cur_s->activated = 1;
                    338:                        _XMRefreshSelection(menu, cur_s);
                    339:                    }
                    340:                }
                    341:                else {
                    342:                    /*
                    343:                     * We have entered a pane.
                    344:                     */
                    345:                    xc_event = (XCrossingEvent *)&event;
                    346:                    status = XInterpretLocator(
                    347:                        menu->parent,
                    348:                        &x, &y,
                    349:                        &xc_window,
                    350:                        xc_event->location
                    351:                    );
                    352:                    if (status == _X_FAILURE) {
                    353:                        _XMErrorCode = XME_INTERP_LOC;
                    354:                        return(XM_FAILURE);
                    355:                    }
                    356:                    event_xmp = (XMPane *)XLookUpAssoc(
                    357:                        menu->assoc_tab,
                    358:                        xc_window
                    359:                    );
                    360:                    if (event_xmp->window == cur_p->window) break;
                    361:                    if (event_xmp->serial > cur_p->serial) forward = TRUE;
                    362:                    else forward = FALSE;
                    363:                    p_ptr = cur_p;
                    364:                    while(1) {
                    365:                        if (forward) p_ptr = p_ptr->next;
                    366:                        else p_ptr = p_ptr->prev;
                    367:                        /*
                    368:                         * If the new pane is an active pane then
                    369:                         * activate it.
                    370:                         */
                    371:                        if (p_ptr->active) {
                    372:                            p_ptr->activated = 1;
                    373:                            XChangeBackground(
                    374:                                p_ptr->window,
                    375:                                menu->bkgnd_pixmap
                    376:                            );
                    377:                            XClear(p_ptr->window);
                    378:                        }
                    379:                        /*
                    380:                         * Raise the new pane.
                    381:                         */
                    382:                        XRaiseWindow(p_ptr->window);
                    383:                        /*
                    384:                         * If the previous current pane was activated
                    385:                         * deactivate it.
                    386:                         */
                    387:                        if (cur_p->activated) {
                    388:                            cur_p->activated = 0;
                    389:                            XChangeBackground(
                    390:                                cur_p->window,
                    391:                                menu->inact_pixmap
                    392:                            );
                    393:                            _XMRefreshPaneText(menu, cur_p);
                    394:                        }
                    395:                        /*
                    396:                         * Make the new pane the current pane.
                    397:                         */
                    398:                        cur_p = p_ptr;
                    399:                        /* 
                    400:                         * If we have cycled through to the event
                    401:                         * pane we are done.
                    402:                         */
                    403:                        if (p_ptr->window == event_xmp->window) break;
                    404:                    }
                    405:                }
                    406:                break;
                    407:            case LeaveWindow:
                    408:                event_xmw = (XMWindow *)XLookUpAssoc(
                    409:                    menu->assoc_tab,
                    410:                    event.window
                    411:                );
                    412:                if (event_xmw == NULL) break;
                    413:                /*
                    414:                 * If the current selection was activated then
                    415:                 * deactivate it.
                    416:                 */
                    417:                if (cur_s->activated) {
                    418:                    cur_s->activated = 0;
                    419:                    _XMRefreshSelection(menu, cur_s);
                    420:                }
                    421:                cur_s = NULL;
                    422:                break;
                    423:            case ButtonPressed:
                    424:            case ButtonReleased:
                    425:                *p_num = cur_p->serial;
                    426:                /*
                    427:                 * Check to see if there is a current selecion.
                    428:                 */
                    429:                if (cur_s != NULL) {
                    430:                    /*
                    431:                     * Set the selection number to the current selection.
                    432:                     */
                    433:                    *s_num = cur_s->serial;
                    434:                    /*
                    435:                     * If the current selection was activated then
                    436:                     * we have a valid selection otherwise we have
                    437:                     * an inactive selection.
                    438:                     */
                    439:                    if (cur_s->activated) {
                    440:                        *data = cur_s->data;
                    441:                        ret_val = XM_SUCCESS;
                    442:                    }
                    443:                    else {
                    444:                        ret_val = XM_IA_SELECT;
                    445:                    }
                    446:                }
                    447:                else {
                    448:                    /*
                    449:                     * No selection was current.
                    450:                     */
                    451:                    ret_val = XM_NO_SELECT;
                    452:                }
                    453:                selection = TRUE;
                    454:                break;
                    455:            default:
                    456:                /*
                    457:                 * If AEQ mode is enabled then queue the event.
                    458:                 */
                    459:                if (menu->aeq) {
                    460:                    feq_tmp = (XMEventQue *)malloc(sizeof(XMEventQue));
                    461:                    if (feq_tmp == NULL) {
                    462:                        _XMErrorCode = XME_CALLOC;
                    463:                        return(XM_FAILURE);
                    464:                    }
                    465:                    feq_tmp->event = event;
                    466:                    feq_tmp->next = feq;
                    467:                    feq = feq_tmp;
                    468:                }
                    469:                else if (_XMEventHandler) (*_XMEventHandler)(&event);
                    470:        }
                    471:        /*
                    472:         * If a selection has been made, break out of the event loop.
                    473:         */
                    474:        if (selection == TRUE) break;
                    475:     }
                    476: 
                    477:     /*
                    478:      * Unmap the menu.
                    479:      */
                    480:     if (saved) {
                    481:        for (
                    482:            p_ptr = menu->p_list->next;
                    483:            p_ptr != menu->p_list;
                    484:            p_ptr = p_ptr->next
                    485:        ) {
                    486:            XUnmapTransparent(p_ptr->window);
                    487:        }
                    488:     }
                    489:     else {
                    490:        for (
                    491:            p_ptr = menu->p_list->next;
                    492:            p_ptr != menu->p_list;
                    493:            p_ptr = p_ptr->next
                    494:        ) {
                    495:            XUnmapWindow(p_ptr->window);
                    496:        }
                    497:     }
                    498: 
                    499:     /*
                    500:      * Ungrab the mouse.
                    501:      */
                    502:     XUngrabMouse();
                    503: 
                    504:     /* 
                    505:      * Restore bits under where the menu was if we managed
                    506:      * to save them and free the pixmap.
                    507:      */
                    508:     if (saved) {
                    509:        XPixmapPut(
                    510:            menu->parent,
                    511:            0, 0,
                    512:            save_x, save_y,
                    513:            save_w, save_h,
                    514:            save_pixmap,
                    515:            GXcopy, AllPlanes
                    516:        );
                    517:        XFreePixmap(save_pixmap);
                    518:     }
                    519: 
                    520:     /*
                    521:      * Ungrab the X server.
                    522:      */
                    523:     if (menu->freeze) XUngrabServer();
                    524: 
                    525:     /*
                    526:      * If there is a current selection deactivate it.
                    527:      */
                    528:     if (cur_s != NULL) cur_s->activated = 0;
                    529: 
                    530:     /*
                    531:      * Deactivate the current pane.
                    532:      */
                    533:     cur_p->activated = 0;
                    534:     XChangeBackground(cur_p->window, menu->inact_pixmap);
                    535: 
                    536:     /*
                    537:      * Synchronize the X buffers and the X event queue.
                    538:      */
                    539:     XSync(0);
                    540:     
                    541:     /*
                    542:      * Dispatch any events remaining on the queue.
                    543:      */
                    544:     while (QLength()) {
                    545:        /*
                    546:         * Fetch the next event.
                    547:         */
                    548:        XNextEvent(&event);
                    549: 
                    550:        /*
                    551:         * Discard any events left on the queue that belong to XMenu.
                    552:         * All others are held and then returned to the event queue.
                    553:         */
                    554:        switch (event.type) {
                    555:            case ExposeWindow:
                    556:            case EnterWindow:
                    557:            case LeaveWindow:
                    558:            case ButtonPressed:
                    559:            case ButtonReleased:
                    560:                /*
                    561:                 * Does this event belong to one of XMenu's windows?
                    562:                 * If so, discard it and process the next event.
                    563:                 * If not fall through and treat it as a foreign event.
                    564:                 */
                    565:                event_xmp = (XMPane *)XLookUpAssoc(
                    566:                    menu->assoc_tab,
                    567:                    event.window
                    568:                );
                    569:                if (event_xmp != NULL) continue;
                    570:            default:
                    571:                /*
                    572:                 * This is a foreign event.
                    573:                 * Queue it for later return to the X event queue.
                    574:                 */
                    575:                feq_tmp = (XMEventQue *)malloc(sizeof(XMEventQue));
                    576:                if (feq_tmp == NULL) {
                    577:                    _XMErrorCode = XME_CALLOC;
                    578:                    return(XM_FAILURE);
                    579:                }
                    580:                feq_tmp->event = event;
                    581:                feq_tmp->next = feq;
                    582:                feq = feq_tmp;
                    583:        }
                    584:     }
                    585: 
                    586:     /*
                    587:      * Return any foreign events that were queued to the X event queue.
                    588:      */
                    589:     while (feq != NULL) {
                    590:        feq_tmp = feq;
                    591:        XPutBackEvent(&feq_tmp->event);
                    592:        feq = feq_tmp->next;
                    593:        free((char *)feq_tmp);
                    594:     }
                    595: 
                    596:     /*
                    597:      * Return successfully.
                    598:      */
                    599:     _XMErrorCode = XME_NO_ERROR;
                    600:     return(ret_val);
                    601: }

unix.superglobalmegacorp.com

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