Annotation of 43BSDTahoe/new/X/xterm/menu.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  *     $Source: /u1/X/xterm/RCS/menu.c,v $
                      3:  *     $Header: menu.c,v 10.101 86/12/01 17:52:43 swick Rel $
                      4:  */
                      5: 
                      6: #ifdef MODEMENU
                      7: #include "X/Xlib.h"
                      8: #include "menu.h"
                      9: 
                     10: #ifndef lint
                     11: static char sccs_id[] = "@(#)menu.c\tX10/6.6B\t12/26/86";
                     12: #endif lint
                     13: 
                     14: #define        FALSE                   0
                     15: #define        TRUE                    1
                     16: #define        InvertPlane             1
                     17: #define        SetStateFlags(item)     item->itemFlags = (item->itemFlags &\
                     18:                                 ~(itemStateMask | itemChanged)) |\
                     19:                                 ((item->itemFlags & itemSetMask) >>\
                     20:                                 itemSetMaskShift)
                     21: 
                     22: 
                     23: static short Check_MarkBits[] = {
                     24:    0x0100, 0x0180, 0x00c0, 0x0060,
                     25:    0x0031, 0x001b, 0x000e, 0x0004
                     26: };
                     27: static short Check_GrayBits[] = {
                     28:    0x0100, 0x0080, 0x0040, 0x0020,
                     29:    0x0011, 0x000a, 0x0004, 0x0000
                     30: };
                     31: static short Default_CursorBits[] = {
                     32:    0x0000, 0x0002, 0x0006, 0x000e,
                     33:    0x001e, 0x003e, 0x007e, 0x00fe,
                     34:    0x01fe, 0x003e, 0x0036, 0x0062,
                     35:    0x0060, 0x00c0, 0x00c0, 0x0000
                     36: };
                     37: static short Default_GrayBits[] = {
                     38:    0xaaaa, 0x5555, 0xaaaa, 0x5555,
                     39:    0xaaaa, 0x5555, 0xaaaa, 0x5555,
                     40:    0xaaaa, 0x5555, 0xaaaa, 0x5555,
                     41:    0xaaaa, 0x5555, 0xaaaa, 0x5555,
                     42: };
                     43: static short Default_MaskBits[] = {
                     44:    0x0003, 0x0007, 0x000f, 0x001f,
                     45:    0x003f, 0x007f, 0x00ff, 0x01ff,
                     46:    0x03ff, 0x07ff, 0x007f, 0x00f7,
                     47:    0x00f3, 0x01e1, 0x01e0, 0x01c0
                     48: };
                     49: static char def_menu_font[] = "vtsingle";
                     50: 
                     51: Pixmap Gray_Tile;
                     52: Menu Menu_Default;
                     53: Cursor Menu_DefaultCursor;
                     54: char *Menu_DefaultFont;
                     55: FontInfo *Menu_DefaultFontInfo;
                     56: 
                     57: /*
                     58:  * AddMenuItem() adds a menu item to an existing menu, at the end of the
                     59:  * list, which are number sequentially from zero.  The menuitem index is
                     60:  * return, or -1 if failed.
                     61:  */
                     62: 
                     63: AddMenuItem(menu, text)
                     64: register Menu *menu;
                     65: register char *text;
                     66: {
                     67:        register MenuItem *menuitem, **next;
                     68:        register int i;
                     69:        extern char *malloc();
                     70: 
                     71:        if(!menu || !text || (menuitem = (MenuItem *)malloc(sizeof(MenuItem)))
                     72:         == (MenuItem *)0)
                     73:                return(-1);
                     74:        bzero((char *)menuitem, sizeof(MenuItem));
                     75:        menuitem->itemText = text;
                     76:        menuitem->itemTextLength = strlen(text);
                     77:        for(i = 0, next = &menu->menuItems ; *next ; i++)
                     78:                next = &(*next)->nextItem;
                     79:        *next = menuitem;
                     80:        menu->menuFlags |= menuChanged;
                     81:        return(i);
                     82: }
                     83: 
                     84: /*
                     85:  * DisposeItem() releases the memory allocated for the given indexed
                     86:  * menuitem.  Nonzero is returned if an item was actual disposed of.
                     87:  */
                     88: DisposeItem(menu, i)
                     89: register Menu *menu;
                     90: register int i;
                     91: {
                     92:        register MenuItem **next, **last, *menuitem;
                     93: 
                     94:        if(!menu || i < 0)
                     95:                return(0);
                     96:        next = &menu->menuItems;
                     97:        do {
                     98:                if(!*next)
                     99:                        return(0);
                    100:                last = next;
                    101:                next = &(*next)->nextItem;
                    102:        } while(i-- > 0);
                    103:        menuitem = *last;
                    104:        *last = *next;
                    105:        free(menuitem);
                    106:        return(1);
                    107: }
                    108: 
                    109: /*
                    110:  * DisposeMenu() releases the memory allocated for the given menu.
                    111:  */
                    112: DisposeMenu(menu)
                    113: register Menu *menu;
                    114: {
                    115:        static Unmap_Menu();
                    116: 
                    117:        if(!menu)
                    118:                return;
                    119:        if(menu->menuFlags & menuMapped)
                    120:                Unmap_Menu(menu);
                    121:        while(DisposeItem(menu, 0));
                    122:        if(menu->menuWindow)
                    123:                XDestroyWindow(menu->menuWindow);
                    124:        if(menu->menuSaved)
                    125:                XFreePixmap(menu->menuSaved);
                    126:        free(menu);
                    127: }
                    128: 
                    129: InitMenu(name)
                    130: register char *name;
                    131: {
                    132:        register char *cp;
                    133:        register Bitmap bit;
                    134: 
                    135:        /*
                    136:         * If the gray tile hasn't been set up, do it now.
                    137:         */
                    138:        if(!Gray_Tile) {
                    139:                if(!(bit = XStoreBitmap(grayWidth, grayHeight,
                    140:                 Default_GrayBits)))
                    141:                        return;
                    142:                Gray_Tile = XMakePixmap(bit, WhitePixel, BlackPixel);
                    143:                XFreeBitmap(bit);
                    144:        }
                    145:        Menu_Default.menuFlags = menuChanged;
                    146:        if((cp = XGetDefault(name, "MenuFreeze")) && strcmp(cp, "on") == 0)
                    147:                Menu_Default.menuFlags |= menuFreeze;
                    148:        if((cp = XGetDefault(name, "MenuSave")) && strcmp(cp, "on") == 0)
                    149:                Menu_Default.menuFlags |= menuSaveMenu;
                    150:        Menu_Default.menuInitialItem = -1;
                    151:        Menu_Default.menuBorderWidth = (cp = XGetDefault(name, "MenuBorder")) ?
                    152:         atoi(cp) : 2;
                    153:        Menu_Default.menuItemPad = (cp = XGetDefault(name, "MenuPad")) ?
                    154:         atoi(cp) : 3;
                    155:        Menu_DefaultFont = (cp = XGetDefault(name, "MenuFont")) ? cp :
                    156:         def_menu_font;
                    157: };
                    158: 
                    159: /*
                    160:  * ItemFlags returns the state of item "n" of the menu.
                    161:  */
                    162: ItemFlags(menu, n)
                    163: register Menu *menu;
                    164: register int n;
                    165: {
                    166:        register MenuItem *item;
                    167: 
                    168:        if(!menu || !menu->menuItems || n < 0)
                    169:                return(-1);
                    170:        for(item = menu->menuItems ; n > 0 ; n--)
                    171:                if(!(item = item->nextItem))
                    172:                        return(0);
                    173:        return((item->itemFlags & itemSetMask) >> itemSetMaskShift);
                    174: }
                    175: 
                    176: /*
                    177:  * ItemText changes the text of item "n" of the menu.
                    178:  */
                    179: ItemText(menu, n, text)
                    180: register Menu *menu;
                    181: register int n;
                    182: char *text;
                    183: {
                    184:        register MenuItem *item;
                    185: 
                    186:        if(!menu || !menu->menuItems || n < 0 || !text)
                    187:                return(0);
                    188:        for(item = menu->menuItems ; n > 0 ; n--)
                    189:                if(!(item = item->nextItem))
                    190:                        return(0);
                    191:        item->itemText = text;
                    192:        menu->menuFlags |= menuChanged;
                    193:        return(1);
                    194: }
                    195: 
                    196: /*
                    197:  * NewMenu() returns a pointer to an initialized new Menu structure, or NULL
                    198:  * if failed.
                    199:  *
                    200:  * The Menu structure _menuDefault contains the default menu settings.
                    201:  */
                    202: Menu *NewMenu(name, reverse)
                    203: char *name;
                    204: int reverse;
                    205: {
                    206:        register Menu *menu;
                    207:        register int fg, bg;
                    208:        extern char *malloc();
                    209: 
                    210:        /*
                    211:         * If the GrayTile hasn't been defined, InitMenu() was never
                    212:         * run, so exit.
                    213:         */
                    214:        if(!Gray_Tile)
                    215:                return((Menu *)0);
                    216:        /*
                    217:         * Allocate the memory for the menu structure.
                    218:         */
                    219:        if((menu = (Menu *)malloc(sizeof(Menu))) == (Menu *)0)
                    220:                return((Menu *)0);
                    221:        /*
                    222:         * Initialize to default values.
                    223:         */
                    224:        *menu = Menu_Default;
                    225:        /*
                    226:         * If the menu font hasn't yet been gotten, go get it.
                    227:         */
                    228:        if(!menu->menuFontInfo) {
                    229:                if(!Menu_DefaultFontInfo && !(Menu_DefaultFontInfo =
                    230:                 XOpenFont(Menu_DefaultFont)))
                    231:                        return((Menu *)0);
                    232:                menu->menuFontInfo = Menu_DefaultFontInfo;
                    233:        }
                    234:        /*
                    235:         * If the menu cursor hasn't been given, make a default one.
                    236:         */
                    237:        if(!menu->menuCursor) {
                    238:                if(!Menu_DefaultCursor) {
                    239:                        if(reverse) {
                    240:                                fg = WhitePixel;
                    241:                                bg = BlackPixel;
                    242:                        } else {
                    243:                                fg = BlackPixel;
                    244:                                bg = WhitePixel;
                    245:                        }
                    246:                        if(!(Menu_DefaultCursor =
                    247:                         XCreateCursor(defaultCursorWidth, defaultCursorHeight,
                    248:                          Default_CursorBits, Default_MaskBits, defaultCursorX,
                    249:                          defaultCursorY, fg, bg, GXcopy)))
                    250:                                return((Menu *)0);
                    251:                }
                    252:                menu->menuCursor = Menu_DefaultCursor;
                    253:        }
                    254:        /*
                    255:         * Initialze the default background and border pixmaps and foreground
                    256:         * and background colors (black and white).
                    257:         */
                    258:        if(reverse) {
                    259:                menu->menuBgTile = BlackPixmap;
                    260:                menu->menuFgColor = WhitePixel;
                    261:                menu->menuBgColor = BlackPixel;
                    262:        } else {
                    263:                menu->menuBgTile = WhitePixmap;
                    264:                menu->menuFgColor = BlackPixel;
                    265:                menu->menuBgColor = WhitePixel;
                    266:        }
                    267:        /*
                    268:         * Set the menu title.  If name is NULL or is an empty string, no
                    269:         * title will be displayed.
                    270:         */
                    271:        if(name && *name) {
                    272:                menu->menuTitleLength = strlen(menu->menuTitle = name);
                    273:                menu->menuTitleWidth = XStringWidth(name, menu->menuFontInfo,
                    274:                 0, 0);
                    275:                menu->menuItemTop = menu->menuFontInfo->height + 2 *
                    276:                 menu->menuItemPad + 1;
                    277:        } else
                    278:                menu->menuTitleLength = menu->menuTitleWidth =
                    279:                 menu->menuItemTop = 0;
                    280:        return(menu);
                    281: }
                    282: 
                    283: /*
                    284:  * SetItemCheck sets the check state of item "n" of the menu to "state".
                    285:  */
                    286: SetItemCheck(menu, n, state)
                    287: register Menu *menu;
                    288: register int n;
                    289: int state;
                    290: {
                    291:        register MenuItem *item;
                    292: 
                    293:        if(!menu || !menu->menuItems || n < 0)
                    294:                return(0);
                    295:        for(item = menu->menuItems ; n > 0 ; n--)
                    296:                if(!(item = item->nextItem))
                    297:                        return(0);
                    298:        if(state)
                    299:                item->itemFlags |= itemSetChecked;
                    300:        else
                    301:                item->itemFlags &= ~itemSetChecked;
                    302:        if(((item->itemFlags & itemSetMask) >> itemSetMaskShift) !=
                    303:         (item->itemFlags & itemStateMask)) {
                    304:                item->itemFlags |= itemChanged;
                    305:                menu->menuFlags |= menuItemChanged;
                    306:        } else
                    307:                item->itemFlags &= ~itemChanged;
                    308:        return(1);
                    309: }
                    310: 
                    311: /*
                    312:  * SetItemDisable sets the disable state of item "n" of the menu to "state".
                    313:  */
                    314: SetItemDisable(menu, n, state)
                    315: register Menu *menu;
                    316: register int n;
                    317: int state;
                    318: {
                    319:        register MenuItem *item;
                    320: 
                    321:        if(!menu || !menu->menuItems || n < 0)
                    322:                return(0);
                    323:        for(item = menu->menuItems ; n > 0 ; n--)
                    324:                if(!(item = item->nextItem))
                    325:                        return(0);
                    326:        if(state)
                    327:                item->itemFlags |= itemSetDisabled;
                    328:        else
                    329:                item->itemFlags &= ~itemSetDisabled;
                    330:        if(((item->itemFlags & itemSetMask) >> itemSetMaskShift) !=
                    331:         (item->itemFlags & itemStateMask)) {
                    332:                item->itemFlags |= itemChanged;
                    333:                menu->menuFlags |= menuItemChanged;
                    334:        } else
                    335:                item->itemFlags &= ~itemChanged;
                    336:        return(1);
                    337: }
                    338: 
                    339: /*
                    340:  * TrackMenu does most of the work of displaying the menu and tracking the
                    341:  * mouse.
                    342:  */
                    343: TrackMenu(menu, event)
                    344: register Menu *menu;
                    345: register XButtonPressedEvent *event;
                    346: {
                    347:        register MenuItem *item;
                    348:        register int i, button;
                    349:        register MenuItem *hilited_item = (MenuItem *)0;
                    350:        register int drawn;
                    351:        XButtonReleasedEvent ev;
                    352:        register int changed;
                    353:        int y, n, hilited_y, hilited_n, in_window;
                    354:        static MenuItem *Mouse_InItem(), *Y_InItem();
                    355:        static Unmap_Menu();
                    356: 
                    357:        /*
                    358:         * Check that things are reasonable.
                    359:         */
                    360:        if(!menu || !event || !menu->menuItems || event->type != ButtonPressed)
                    361:                return(-1);
                    362:        /*
                    363:         * Set the changed flag and clear the menu changed flags.
                    364:         */
                    365:        changed = menu->menuFlags & (menuChanged | menuItemChanged);
                    366:        /*
                    367:         * If the entire menu has changed, throw away any saved pixmap and
                    368:         * then call RecalcMenu().
                    369:         */
                    370:        if(changed & menuChanged) {
                    371:                if(menu->menuSaved)
                    372:                        XFreePixmap(menu->menuSaved);
                    373:                menu->menuSaved = (Pixmap)0;
                    374:                if(!Recalc_Menu(menu))
                    375:                        return(-1);
                    376:                changed &= ~menuItemChanged;
                    377:        }
                    378:        /*
                    379:         * Now if the window was never created, go ahead and make it.  Otherwise
                    380:         * if the menu has changed, resize the window.
                    381:         */
                    382:        if(!menu->menuWindow) {
                    383:                if((menu->menuWindow = XCreateWindow(RootWindow, 0, 0,
                    384:                 menu->menuWidth, menu->menuHeight, menu->menuBorderWidth,
                    385:                 Gray_Tile, menu->menuBgTile)) == (Window)0)
                    386:                        return(-1);
                    387:                XDefineCursor(menu->menuWindow, menu->menuCursor);
                    388:                XSelectInput(menu->menuWindow, ExposeWindow | EnterWindow |
                    389:                 LeaveWindow | MouseMoved | ButtonReleased);
                    390:        } else if(changed & menuChanged)
                    391:                XChangeWindow(menu->menuWindow, menu->menuWidth,
                    392:                 menu->menuHeight);
                    393:        /*
                    394:         * Figure out where the menu is supposed to go, from the initial button
                    395:         * press, and move the window there.  Then map the menu.
                    396:         */
                    397:        if(!Move_Menu(menu, event) || !Map_Menu(menu))
                    398:                return(-1);
                    399:        /*
                    400:         * Try to grab the mouse, over a period of 10 seconds.
                    401:         */
                    402:        for(i = 10 ; ; ) {
                    403:                if(XGrabMouse(menu->menuWindow, menu->menuCursor,
                    404:                 ButtonReleased | EnterWindow | LeaveWindow | MouseMoved))
                    405:                        break;
                    406:                if(--i <= 0) {
                    407:                        Unmap_Menu(menu);
                    408:                        return(-1);
                    409:                }
                    410:                sleep(1);
                    411:        }
                    412:        /*
                    413:         * Save away the button that was pressed and use it to match a
                    414:         * corresponding ButtonReleased event.
                    415:         */
                    416:        button = event->detail & 03;
                    417:        /*
                    418:         * Now process events for the menu window.
                    419:         */
                    420:        drawn = 0;
                    421:        for( ; ; ) {
                    422:                XNextEvent(&ev);
                    423:                if(ev.type != ButtonReleased && ev.window != menu->menuWindow) {
                    424:                        if(menu->menuEventHandler)
                    425:                                (*menu->menuEventHandler)(&ev);
                    426:                        continue;
                    427:                }
                    428:                switch(ev.type) {
                    429:                 case ExposeWindow:
                    430:                        /*
                    431:                         * If we have a saved pixmap, display it.  Otherwise
                    432:                         * redraw the menu and save it away.
                    433:                         */
                    434:                        if(menu->menuSaved) {
                    435:                                XPixmapPut(menu->menuWindow, 0, 0, 0, 0,
                    436:                                 menu->menuWidth, menu->menuHeight,
                    437:                                 menu->menuSaved, GXcopy, AllPlanes);
                    438:                                /*
                    439:                                 * If the menuItemChanged flag is still set,
                    440:                                 * then we need to redraw certain menu items.
                    441:                                 * ("i" is the vertical position of the top
                    442:                                 * of the current item.)
                    443:                                 */
                    444:                                if(changed & menuItemChanged) {
                    445:                                        i = menu->menuItemTop;
                    446:                                        for(item = menu->menuItems ; item ;
                    447:                                         item = item->nextItem) {
                    448:                                                if(item->itemFlags &
                    449:                                                 itemChanged)
                    450:                                                        Modify_Item(menu, item,
                    451:                                                         i);
                    452:                                                i += item->itemHeight;
                    453:                                        }
                    454:                                }
                    455:                        } else
                    456:                                Draw_Menu(menu);
                    457:                        /*
                    458:                         * If the menu has changed in any way and we want to
                    459:                         * save the menu, throw away any existing save menu
                    460:                         * image and make a new one.
                    461:                         */
                    462:                        XFlush();
                    463:                        if(changed && (menu->menuFlags & menuSaveMenu)) {
                    464:                                if(menu->menuSaved)
                    465:                                        XFreePixmap(menu->menuSaved);
                    466:                                menu->menuSaved = XPixmapSave(menu->menuWindow,
                    467:                                 0, 0, menu->menuWidth, menu->menuHeight);
                    468:                        }
                    469:                        /*
                    470:                         * See which item the cursor may currently be in.  If
                    471:                         * it is in a non-disabled item, hilite it.
                    472:                         */
                    473:                        if(hilited_item = Mouse_InItem(menu, &hilited_y,
                    474:                         &hilited_n, &in_window))
                    475:                                XPixFill(menu->menuWindow, 0, hilited_y,
                    476:                                 menu->menuWidth, hilited_item->itemHeight,
                    477:                                 BlackPixmap, (Bitmap)0, GXinvert, InvertPlane);
                    478:                        drawn++;
                    479:                        break;
                    480:                 case EnterWindow:
                    481:                        in_window = TRUE;
                    482:                        /* drop through */
                    483:                 case MouseMoved:
                    484:                        if(!drawn || !in_window)
                    485:                                break;
                    486:                        /*
                    487:                         * See which item the cursor may currently be in.  If
                    488:                         * the item has changed, unhilite the old one and
                    489:                         * then hilited the new one.
                    490:                         */
                    491:                        y = ((XEnterWindowEvent *)&ev)->y;
                    492:                        if((item = Y_InItem(menu, &y, &n)) != hilited_item) {
                    493:                                if(hilited_item)
                    494:                                        XPixFill(menu->menuWindow, 0,
                    495:                                         hilited_y, menu->menuWidth,
                    496:                                         hilited_item->itemHeight, BlackPixmap,
                    497:                                         (Bitmap)0, GXinvert, InvertPlane);
                    498:                                if(hilited_item = item) {
                    499:                                        XPixFill(menu->menuWindow, 0,
                    500:                                         hilited_y = y, menu->menuWidth,
                    501:                                         item->itemHeight, BlackPixmap,
                    502:                                         (Bitmap)0, GXinvert, InvertPlane);
                    503:                                        hilited_n = n;
                    504:                                }
                    505:                        }
                    506:                        break;
                    507:                 case LeaveWindow:
                    508:                        if(!drawn)
                    509:                                break;
                    510:                        /*
                    511:                         * Unhilite any window that is currently hilited.
                    512:                         */
                    513:                        if(hilited_item) {
                    514:                                XPixFill(menu->menuWindow, 0, hilited_y,
                    515:                                 menu->menuWidth, hilited_item->itemHeight,
                    516:                                 BlackPixmap, (Bitmap)0, GXinvert, InvertPlane);
                    517:                                hilited_item = (MenuItem *)0;
                    518:                        }
                    519:                        in_window = FALSE;
                    520:                        break;
                    521:                 case ButtonReleased:
                    522:                        /*
                    523:                         * If the correct button was released, ungrab the mouse
                    524:                         * and return the index number of any selected menu
                    525:                         * item.
                    526:                         */
                    527:                        if((ev.detail & 0x3) == button) {
                    528:                                if(in_window) {
                    529:                                        y = ((XButtonReleasedEvent *)&ev)->y;
                    530:                                        if((item = Y_InItem(menu, &y, &n)) !=
                    531:                                         hilited_item) {
                    532:                                            if(hilited_item)
                    533:                                                XPixFill(menu->menuWindow, 0,
                    534:                                                 hilited_y, menu->menuWidth,
                    535:                                                 hilited_item->itemHeight,
                    536:                                                 BlackPixmap, (Bitmap)0,
                    537:                                                 GXinvert, InvertPlane);
                    538:                                            if(hilited_item = item) {
                    539:                                                XPixFill(menu->menuWindow, 0,
                    540:                                                 hilited_y = y, menu->menuWidth,
                    541:                                                 hilited_item->itemHeight,
                    542:                                                 BlackPixmap, (Bitmap)0,
                    543:                                                 GXinvert, InvertPlane);
                    544:                                                hilited_n = n;
                    545:                                            }
                    546:                                        }
                    547:                                }
                    548:                                XUngrabMouse();
                    549:                                menu->menuFlags &= ~(menuChanged |
                    550:                                 menuItemChanged);
                    551:                                Unmap_Menu(menu);
                    552:                                XFlush();
                    553:                                if(hilited_item)
                    554:                                        return(menu->menuInitialItem =
                    555:                                         hilited_n);
                    556:                                return(-1);
                    557:                        }
                    558:                        break;
                    559:                }
                    560:        }
                    561: }
                    562: 
                    563: /*
                    564:  * Recalculate all of the various menu and item variables.
                    565:  */
                    566: static Recalc_Menu(menu)
                    567: register Menu *menu;
                    568: {
                    569:        register MenuItem *item;
                    570:        register int max, i, height, fontheight;
                    571: 
                    572:        /*
                    573:         * We must have already gotten the menu font.
                    574:         */
                    575:        if(!menu->menuFontInfo)
                    576:                return(0);
                    577:        /*
                    578:         * Initialize the various max width variables.
                    579:         */
                    580:        fontheight = menu->menuFontInfo->height;
                    581:        height = menu->menuItemTop;
                    582:        menu->menuMaxTextWidth = menu->menuTitleWidth;
                    583:        /*
                    584:         * The item height is the maximum of the font height and the
                    585:         * checkbox height.
                    586:         */
                    587:        max = fontheight;
                    588:        if(checkMarkHeight > max)
                    589:                max = checkMarkHeight;
                    590:        /*
                    591:         * Go through the menu item list.
                    592:         */
                    593:        for(item = menu->menuItems ; item ; item = item->nextItem) {
                    594:                /*
                    595:                 * If the item text is a single dash, we assume this is
                    596:                 * a line separator and treat it special.
                    597:                 */
                    598:                if(strcmp(item->itemText, "-") == 0)
                    599:                        height += (item->itemHeight = lineSeparatorHeight);
                    600:                else {
                    601:                        height += (item->itemHeight = max);
                    602:                        /*
                    603:                         * Check the text width with the max value stored in
                    604:                         * menu.
                    605:                         */
                    606:                        if((item->itemTextWidth = XStringWidth(item->itemText,
                    607:                         menu->menuFontInfo, 0, 0)) > menu->menuMaxTextWidth)
                    608:                                menu->menuMaxTextWidth = item->itemTextWidth;
                    609:                }
                    610:                /*
                    611:                 * If the itemChanged flag is set, set the state bits.
                    612:                 */
                    613:                if(item->itemFlags & itemChanged) {
                    614:                        item->itemFlags = (item->itemFlags & ~itemStateMask) |
                    615:                         ((item->itemFlags & itemSetMask) >> itemSetMaskShift);
                    616:                        item->itemFlags &= ~itemChanged;
                    617:                }
                    618:        }
                    619:        /*
                    620:         * Set the menu height and then set the menu width.
                    621:         */
                    622:        menu->menuHeight = height;
                    623:        menu->menuWidth = 3 * menu->menuItemPad + menu->menuMaxTextWidth +
                    624:         checkMarkWidth;
                    625:        return(1);
                    626: }
                    627: 
                    628: /*
                    629:  * Figure out where to popup the menu, relative to the where the button was
                    630:  * pressed.
                    631:  */
                    632: static Move_Menu(menu, ev)
                    633: register Menu *menu;
                    634: XButtonPressedEvent *ev;
                    635: {
                    636:        register MenuItem *item;
                    637:        register int n, x, y;
                    638:        int ev_x, ev_y;
                    639:        int total_width;
                    640:        Window subw;
                    641:        extern int dropmenu;    /* XXX */
                    642: 
                    643:        /*
                    644:         * Get the coordinates of the mouse when the button was pressed.
                    645:         */
                    646:        XInterpretLocator(RootWindow, &ev_x, &ev_y, &subw, ev->location);
                    647:        /*
                    648:         * Try to popup the menu so that the cursor is centered within the
                    649:         * width of the menu, but compensate if that would run it outside
                    650:         * the display area.
                    651:         */
                    652:        total_width = menu->menuWidth + 2 * menu->menuBorderWidth;
                    653:        if((x = ev_x - total_width / 2) < 0)
                    654:                x = 0;
                    655:        else if(x + total_width > DisplayWidth())
                    656:                x = DisplayWidth() - total_width;
                    657:        if (dropmenu)
                    658:                y = 0;
                    659:        else if(menu->menuInitialItem >= 0) {
                    660:                /*
                    661:                 * If we have an inital item, try to popup the menu centered
                    662:                 * vertically within this item.
                    663:                 *
                    664:                 * Look through the item list. "y" is the vertical position
                    665:                 * of the top of the current item and "n" is the item number.
                    666:                 */
                    667:                y = menu->menuItemTop + menu->menuBorderWidth;
                    668:                for(n = 0, item = menu->menuItems ; ; n++) {
                    669:                        /*
                    670:                         * On finding the intial item, center within this item.
                    671:                         */
                    672:                        if(n == menu->menuInitialItem) {
                    673:                                y += item->itemHeight / 2;
                    674:                                break;
                    675:                        }
                    676:                        y += item->itemHeight;
                    677:                        /*
                    678:                         * If we run out of items, turn off the initial item
                    679:                         * and treat this as if no initial item.
                    680:                         */
                    681:                        if(!(item = item->nextItem)) {
                    682:                                menu->menuInitialItem = -1;
                    683:                                goto noInitial;
                    684:                        }
                    685:                }
                    686:        /*
                    687:         * If no initial item, try to popup the menu centered in the item
                    688:         * nearest the center of the menu.
                    689:         */
                    690:        } else {
                    691: noInitial:
                    692:                /*
                    693:                 * Look through the item list. "y" is the vertical position
                    694:                 * of the top of the current item and "n" is the vertical
                    695:                 * position of the center of the menu.
                    696:                 */
                    697:                y = menu->menuItemTop + menu->menuBorderWidth;
                    698:                for(n = menu->menuHeight / 2, item = menu->menuItems ; item ;
                    699:                 item = item->nextItem)
                    700:                        /*
                    701:                         * If the center of the menu is in this item, we
                    702:                         * center within this item.
                    703:                         */
                    704:                        if((y += item->itemHeight) > n) {
                    705:                                y -= item->itemHeight / 2;
                    706:                                break;
                    707:                        }
                    708:        }
                    709:        /*
                    710:         * If the menu extends above outside of the display, warp
                    711:         * the mouse vertically so the menu will all show up.
                    712:         */
                    713:        if((y = ev_y - y) < 0) {
                    714:                XWarpMouse(RootWindow, ev_x, ev_y - y);
                    715:                y = 0;
                    716:        } else if((n = y + menu->menuHeight + 2 * menu->menuBorderWidth
                    717:                       - DisplayHeight()) > 0) {
                    718:                XWarpMouse(RootWindow, ev_x, ev_y - n);
                    719:                y -= n;
                    720:        }
                    721:        XMoveWindow(menu->menuWindow, x, y);
                    722:        /*
                    723:         * If we are in freeze mode, save what will be the coordinates of
                    724:         * the save image.
                    725:         */
                    726:        if(menu->menuFlags & menuFreeze) {
                    727:                menu->menuSavedImageX = x;
                    728:                menu->menuSavedImageY = y;
                    729:        }
                    730:        return(1);
                    731: }
                    732: 
                    733: /*
                    734:  * Map the menu window.
                    735:  */
                    736: static Map_Menu(menu)
                    737: register Menu *menu;
                    738: {
                    739:        register int i;
                    740: 
                    741:        /*
                    742:         * If we are in freeze mode, save the pixmap underneath where the menu
                    743:         * will be (including the border).
                    744:         */
                    745:        if(menu->menuFlags & menuFreeze) {
                    746:                XGrabServer();
                    747:                i = 2 * menu->menuBorderWidth;
                    748:                if((menu->menuSavedImage = XPixmapSave(RootWindow,
                    749:                 menu->menuSavedImageX, menu->menuSavedImageY, menu->menuWidth
                    750:                 + i, menu->menuHeight + i)) == (Pixmap)0)
                    751:                        return(0);
                    752:        }
                    753:        /*
                    754:         * Actually map the window.
                    755:         */
                    756:        XMapWindow(menu->menuWindow);
                    757:        menu->menuFlags |= menuMapped;
                    758:        return(1);
                    759: }
                    760: 
                    761: /*
                    762:  * Draw the entire menu in the blank window.
                    763:  */
                    764: static Draw_Menu(menu)
                    765: register Menu *menu;
                    766: {
                    767:        register MenuItem *item;
                    768:        register int top = menu->menuItemTop;
                    769:        register int x = menu->menuItemPad;
                    770:        register int y, dim;
                    771: 
                    772:        /*
                    773:         * If we have a menu title, draw it first, centered and hilited.
                    774:         */
                    775:        if(menu->menuTitleLength) {
                    776:                XPixSet(menu->menuWindow, 0, 0, menu->menuWidth,
                    777:                 top - 1, menu->menuFgColor);
                    778:                XText(menu->menuWindow, (menu->menuWidth -
                    779:                 menu->menuTitleWidth) / 2, menu->menuItemPad, menu->menuTitle,
                    780:                 menu->menuTitleLength, menu->menuFontInfo->id,
                    781:                 menu->menuBgColor, menu->menuFgColor);
                    782:        }
                    783:        /*
                    784:         * For each item in the list, first draw any check mark and then
                    785:         * draw the rest of it.
                    786:         */
                    787:        for(item = menu->menuItems ; item ; item = item->nextItem) {
                    788:                SetStateFlags(item);
                    789:                dim = (item->itemFlags & itemDisabled);
                    790:                /*
                    791:                 * Draw the check mark, possibly dimmed, wherever is necessary.
                    792:                 */
                    793:                if(item->itemFlags & itemChecked) {
                    794:                        XBitmapBitsPut(menu->menuWindow, x, y = top +
                    795:                         (item->itemHeight - checkMarkHeight) / 2,
                    796:                         checkMarkWidth, checkMarkHeight, dim ? Check_GrayBits :
                    797:                         Check_MarkBits, menu->menuFgColor, menu->menuBgColor,
                    798:                         (Bitmap)0, GXcopy, AllPlanes);
                    799:                }
                    800:                /*
                    801:                 * Draw the item, possibly dimmed.
                    802:                 */
                    803:                Draw_Item(menu, item, top, dim);
                    804:                top += item->itemHeight;
                    805:        }
                    806: }
                    807: 
                    808: /*
                    809:  * Modify the item at vertical position y.  This routine is table driven and
                    810:  * the state and set bits are each 2 bits long, contiguous, the least
                    811:  * significant bits in the flag word and with the state bits in bits 0 & 1.
                    812:  */
                    813: 
                    814: #define        drawCheck       0x10
                    815: #define        removeCheck     0x08
                    816: #define        dimCheck        0x04
                    817: #define        drawItem        0x02
                    818: #define        dimItem         0x01
                    819: 
                    820: static char Modify_Table[] = {
                    821:        0x00, 0x02, 0x08, 0x0a, 0x01, 0x00, 0x09, 0x08,
                    822:        0x10, 0x12, 0x00, 0x12, 0x15, 0x14, 0x05, 0x00
                    823: };
                    824:        
                    825: static Modify_Item(menu, item, top)
                    826: register Menu *menu;
                    827: register MenuItem *item;
                    828: int top;
                    829: {
                    830:        register int x = menu->menuItemPad;
                    831:        register int y;
                    832:        register int center = top + item->itemHeight / 2;
                    833:        register int func = Modify_Table[item->itemFlags &
                    834:         (itemStateMask | itemSetMask)];
                    835: 
                    836:        /*
                    837:         * If we really won't be making a change, return.
                    838:         */
                    839:        if(func == 0)
                    840:                return;
                    841:        /*
                    842:         * Draw the check mark if needed, possibly dimmed.
                    843:         */
                    844:        y = center - (checkMarkHeight / 2);
                    845:        if(func & (drawCheck | dimCheck))
                    846:                XBitmapBitsPut(menu->menuWindow, x, y, checkMarkWidth,
                    847:                 checkMarkHeight, (func & dimCheck) ? Check_GrayBits :
                    848:                 Check_MarkBits, menu->menuFgColor, menu->menuBgColor,
                    849:                 (Bitmap)0, GXcopy, AllPlanes);
                    850:        /*
                    851:         * Remove the check mark if needed.
                    852:         */
                    853:        if(func & removeCheck)
                    854:                XTileSet(menu->menuWindow, x, y, checkMarkWidth,
                    855:                 checkMarkHeight, menu->menuBgTile);
                    856:        /*
                    857:         * Call Draw_Item if we need to draw or dim the item.
                    858:         */
                    859:        if((x = func & dimItem) || (func & drawItem))
                    860:                Draw_Item(menu, item, top, x);
                    861:        /*
                    862:         * Update state flags.
                    863:         */
                    864:        SetStateFlags(item);
                    865: }
                    866: 
                    867: /*
                    868:  * Draw the item (less check mark) at vertical position y.
                    869:  * Dim the item if "dim" is set.
                    870:  */
                    871: static Draw_Item(menu, item, y, dim)
                    872: register Menu *menu;
                    873: register MenuItem *item;
                    874: register int y;
                    875: int  dim;
                    876: {
                    877:        register int x = 2 * menu->menuItemPad + checkMarkWidth;
                    878:        register int center = y + item->itemHeight / 2;
                    879: 
                    880:        /*
                    881:         * If the item text is a single dash, draw a separating line.
                    882:         */
                    883:        if(strcmp(item->itemText, "-") == 0) {
                    884:                XLine(menu->menuWindow, 0, center, menu->menuWidth, center,
                    885:                 1, 1, menu->menuFgColor, GXcopy, AllPlanes);
                    886:                return;
                    887:        }
                    888:        /*
                    889:         * Draw and/or dim the text, centered vertically.
                    890:         */
                    891:        y = center - (menu->menuFontInfo->height / 2);
                    892:        if(dim) {
                    893:                XTileSet(menu->menuWindow, x, y, item->itemTextWidth,
                    894:                 menu->menuFontInfo->height, Gray_Tile);
                    895:                XTextPad(menu->menuWindow, x, y, item->itemText,
                    896:                 item->itemTextLength, menu->menuFontInfo->id, 0, 0,
                    897:                 menu->menuFgColor, menu->menuBgColor, menu->menuFgColor ?
                    898:                 GXand : GXor, AllPlanes);
                    899:        } else
                    900:                XText(menu->menuWindow, x, y, item->itemText,
                    901:                 item->itemTextLength, menu->menuFontInfo->id,
                    902:                 menu->menuFgColor, menu->menuBgColor);
                    903: }
                    904: 
                    905: /*
                    906:  * Determine which enabled menu item the mouse is currently in.  Return the
                    907:  * top position of this item and its item number.  Set inwindow to whether
                    908:  * we are or not.
                    909:  */
                    910: static MenuItem *Mouse_InItem(menu, top, n, inwindow)
                    911: register Menu *menu;
                    912: int *top, *n, *inwindow;
                    913: {
                    914:        int x, y;
                    915:        Window subw;
                    916:        static MenuItem *Y_InItem();
                    917: 
                    918:        /*
                    919:         * Find out where the mouse is.  If its not in the menu window,
                    920:         * return NULL.
                    921:         */
                    922:        XQueryMouse(RootWindow, &x, &y, &subw);
                    923:        if(subw != menu->menuWindow) {
                    924:                *inwindow = FALSE;
                    925:                return((MenuItem *)0);
                    926:        }
                    927:        *inwindow = TRUE;
                    928:        /*
                    929:         * Now get the coordinates relative to the menu window.
                    930:         */
                    931:        XInterpretLocator(menu->menuWindow, &x, &y, &subw, (x << 16) | y);
                    932:        /*
                    933:         * Call Y_InItem().
                    934:         */
                    935:        *top = y;
                    936:        return(Y_InItem(menu, top, n));
                    937: }
                    938: 
                    939: /*
                    940:  * Return which enabled item the locator is in.  Also return the
                    941:  * top position of this item and its item number.  Initial y passed
                    942:  * in top.
                    943:  */
                    944: static MenuItem *Y_InItem(menu, top, n)
                    945: register Menu *menu;
                    946: int *top, *n;
                    947: {
                    948:        register MenuItem *item;
                    949:        register int t, i;
                    950:        register int y = *top;
                    951:        Window subw;
                    952: 
                    953:        /*
                    954:         * Go through the item list.  "t" is the vertical position of the
                    955:         * current item and "i" is its item number.
                    956:         */
                    957:        t = menu->menuItemTop;
                    958:        /*
                    959:         * If the mouse is before the first item, return.
                    960:         */
                    961:        if(y < t)
                    962:                return((MenuItem *)0);
                    963:        for(i = 0, item = menu->menuItems ; item ; i++, item = item->nextItem) {
                    964:                /*
                    965:                 * If the y coordinate is within this menu item, then return.
                    966:                 * But don't return disable items.
                    967:                 */
                    968:                if(t + item->itemHeight > y) {
                    969:                        if(item->itemFlags & itemDisabled)
                    970:                                return((MenuItem *)0);
                    971:                        *top = t;
                    972:                        *n = i;
                    973:                        return(item);
                    974:                }
                    975:                t += item->itemHeight;
                    976:        }
                    977:        /*
                    978:         * Should never get here.
                    979:         */
                    980:        return((MenuItem *)0);
                    981: }
                    982: 
                    983: /*
                    984:  * Unmap_Menu() unmaps a menu, if it is currently mapped.
                    985:  */
                    986: static Unmap_Menu(menu)
                    987: register Menu *menu;
                    988: {
                    989:        register int i;
                    990: 
                    991:        if(!menu || !(menu->menuFlags & menuMapped))
                    992:                return;
                    993:        if(menu->menuFlags & menuFreeze) {
                    994:                XUnmapTransparent(menu->menuWindow);
                    995:                i = 2 * menu->menuBorderWidth;
                    996:                XPixmapPut(RootWindow, 0, 0, menu->menuSavedImageX,
                    997:                 menu->menuSavedImageY, menu->menuWidth + i,
                    998:                 menu->menuHeight + i, menu->menuSavedImage,
                    999:                 GXcopy, AllPlanes);
                   1000:                XFreePixmap(menu->menuSavedImage);
                   1001:                XUngrabServer();
                   1002:        } else
                   1003:                XUnmapWindow(menu->menuWindow);
                   1004:        menu->menuFlags &= ~menuMapped;
                   1005: }
                   1006: #endif MODEMENU

unix.superglobalmegacorp.com

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