Annotation of researchv9/X11/src/X.V11R1/clients/xterm/menu.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  *     $Source: /u1/X11/clients/xterm/RCS/menu.c,v $
                      3:  *     $Header: menu.c,v 1.28 87/09/11 22:31:28 rws Exp $
                      4:  */
                      5: 
                      6: #include <X11/copyright.h>
                      7: 
                      8: /*
                      9:  * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
                     10:  *
                     11:  *                         All Rights Reserved
                     12:  *
                     13:  * Permission to use, copy, modify, and distribute this software and its
                     14:  * documentation for any purpose and without fee is hereby granted,
                     15:  * provided that the above copyright notice appear in all copies and that
                     16:  * both that copyright notice and this permission notice appear in
                     17:  * supporting documentation, and that the name of Digital Equipment
                     18:  * Corporation not be used in advertising or publicity pertaining to
                     19:  * distribution of the software without specific, written prior permission.
                     20:  *
                     21:  *
                     22:  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
                     23:  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
                     24:  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
                     25:  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
                     26:  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
                     27:  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
                     28:  * SOFTWARE.
                     29:  */
                     30: 
                     31: #include <stdio.h>
                     32: #ifdef MODEMENU
                     33: #include <X11/Xlib.h>
                     34: #include <X11/Intrinsic.h>
                     35: #include <X11/Xutil.h>
                     36: #include <X11/Xatom.h>
                     37: #include <X11/cursorfont.h>
                     38: #include <X11/Xtlib.h>
                     39: #include "menu.h"
                     40: #include <setjmp.h>
                     41: #include "ptyx.h"
                     42: #include "data.h"
                     43: 
                     44: #ifndef lint
                     45: static char rcs_id[] = "$Header: menu.c,v 1.28 87/09/11 22:31:28 rws Exp $";
                     46: #endif lint
                     47: 
                     48: #define DEFMENUBORDER  2
                     49: #define DEFMENUPAD     3
                     50: 
                     51: #define  XtNxterm                "xterm"
                     52: #define  XtCApp                  "App"
                     53: 
                     54: #define XOR(a,b)       ((a&(~b)) | ((~a)&b))
                     55: 
                     56: #define        SetStateFlags(item)     item->itemFlags = (item->itemFlags &\
                     57:                                 ~(itemStateMask | itemChanged)) |\
                     58:                                 ((item->itemFlags & itemSetMask) >>\
                     59:                                 itemSetMaskShift)
                     60: 
                     61: 
                     62: static char Check_MarkBits[] = {
                     63:    0x00, 0x01, 0x80, 0x01, 0xc0, 0x00, 0x60, 0x00,
                     64:    0x31, 0x00, 0x1b, 0x00, 0x0e, 0x00, 0x04, 0x00
                     65: };
                     66: static char Default_CursorBits[] = {
                     67:    0x00, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0e, 0x00,
                     68:    0x1e, 0x00, 0x3e, 0x00, 0x7e, 0x00, 0xfe, 0x00,
                     69:    0xfe, 0x01, 0x3e, 0x00, 0x36, 0x00, 0x62, 0x00,
                     70:    0x60, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0x00, 0x00
                     71: };
                     72: static char Default_MaskBits[] = {
                     73:    0x03, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x1f, 0x00,
                     74:    0x3f, 0x00, 0x7f, 0x00, 0xff, 0x00, 0xff, 0x01,
                     75:    0xff, 0x03, 0xff, 0x07, 0x7f, 0x00, 0xf7, 0x00,
                     76:    0xf3, 0x00, 0xe1, 0x01, 0xe0, 0x01, 0xc0, 0x01
                     77: };
                     78: 
                     79: static GC MenuGC, MenuInverseGC, MenuInvertGC, MenuGrayGC;
                     80: static int gotGCs = FALSE;
                     81: 
                     82: Pixmap Gray_Tile, Check_Tile;
                     83: Menu Menu_Default;
                     84: Cursor Menu_DefaultCursor;
                     85: char *Menu_DefaultFont;
                     86: 
                     87: extern XrmNameList nameList;
                     88: extern XrmClassList classList;
                     89: extern EventDoNothing();
                     90: 
                     91: static int default_menuBorder = DEFMENUBORDER;
                     92: static int default_menuPad = DEFMENUPAD;
                     93: static char *defaultNULL = NULL;
                     94: 
                     95: static Resource resourceList[] = {
                     96:   {"menuBorder", "MenuBorder", XrmRInt, sizeof(int),
                     97:      (caddr_t) &Menu_Default.menuBorderWidth, (caddr_t) &default_menuBorder},
                     98:   {"menuFont", XtCFont, XrmRString, sizeof(char *),
                     99:      (caddr_t) &Menu_DefaultFont, (caddr_t) &defaultNULL},
                    100:   {"menuPad", "MenuPad", XrmRInt, sizeof(int),
                    101:      (caddr_t) &Menu_Default.menuItemPad, (caddr_t) &default_menuPad}
                    102: };
                    103: 
                    104: /*
                    105:  * AddMenuItem() adds a menu item to an existing menu, at the end of the
                    106:  * list, which are number sequentially from zero.  The menuitem index is
                    107:  * return, or -1 if failed.
                    108:  */
                    109: 
                    110: AddMenuItem(menu, text)
                    111: register Menu *menu;
                    112: register char *text;
                    113: {
                    114:        register MenuItem *menuitem, **next;
                    115:        register int i;
                    116:        extern char *malloc();
                    117: 
                    118:        if(!menu || !text || (menuitem = (MenuItem *)malloc(sizeof(MenuItem)))
                    119:         == (MenuItem *)0)
                    120:                return(-1);
                    121:        bzero((char *)menuitem, sizeof(MenuItem));
                    122:        menuitem->itemText = text;
                    123:        menuitem->itemTextLength = strlen(text);
                    124:        for(i = 0, next = &menu->menuItems ; *next ; i++)
                    125:                next = &(*next)->nextItem;
                    126:        *next = menuitem;
                    127:        menu->menuFlags |= menuChanged;
                    128:        return(i);
                    129: }
                    130: 
                    131: /*
                    132:  * DisposeItem() releases the memory allocated for the given indexed
                    133:  * menuitem.  Nonzero is returned if an item was actual disposed of.
                    134:  */
                    135: DisposeItem(menu, i)
                    136: register Menu *menu;
                    137: register int i;
                    138: {
                    139:        register MenuItem **next, **last, *menuitem;
                    140: 
                    141:        if(!menu || i < 0)
                    142:                return(0);
                    143:        next = &menu->menuItems;
                    144:        do {
                    145:                if(!*next)
                    146:                        return(0);
                    147:                last = next;
                    148:                next = &(*next)->nextItem;
                    149:        } while(i-- > 0);
                    150:        menuitem = *last;
                    151:        *last = *next;
                    152:        free(menuitem);
                    153:        return(1);
                    154: }
                    155: 
                    156: /*
                    157:  * DisposeMenu() releases the memory allocated for the given menu.
                    158:  */
                    159: DisposeMenu(menu)
                    160: register Menu *menu;
                    161: {
                    162:        register TScreen *screen = &term.screen;
                    163:        static Unmap_Menu();
                    164: 
                    165:        if(!menu)
                    166:                return;
                    167:        if(menu->menuFlags & menuMapped)
                    168:                Unmap_Menu(menu);
                    169:        while(DisposeItem(menu, 0));
                    170:        if(menu->menuWindow)
                    171:                XDestroyWindow(screen->display, menu->menuWindow);
                    172:        if(menu->menuSaved)
                    173:                XFreePixmap(screen->display, menu->menuSaved);
                    174:        free(menu);
                    175: }
                    176: 
                    177: InitMenu(name)
                    178: register char *name;
                    179: {
                    180:        register TScreen *screen = &term.screen;
                    181:        register char *cp;
                    182:        extern Pixmap make_gray();
                    183:        Display *dpy = screen->display;
                    184: 
                    185:        /*
                    186:         * If the gray tile hasn't been set up, do it now.
                    187:         */
                    188:        if(!Gray_Tile) 
                    189:                Gray_Tile = make_gray(WhitePixel(dpy, DefaultScreen(dpy)), 
                    190:                BlackPixel(dpy, DefaultScreen(dpy)), 1);
                    191:        if (!Check_Tile) {
                    192:                Check_Tile = Make_tile(checkMarkWidth, checkMarkHeight,
                    193:                  Check_MarkBits, BlackPixel(dpy, DefaultScreen(dpy)),
                    194:                  WhitePixel(dpy, DefaultScreen(dpy)),
                    195:                  DefaultDepth(dpy, DefaultScreen(dpy)));
                    196:         }
                    197:        Menu_Default.menuFlags = menuChanged;
                    198: /*     if((cp = XGetDefault(dpy, name, "MenuFreeze")) && XStrCmp(cp, "on") == 0)
                    199:                Menu_Default.menuFlags |= menuFreeze;
                    200:        if((cp = XGetDefault(dpy, name, "MenuSave")) && XStrCmp(cp, "on") == 0)
                    201:                Menu_Default.menuFlags |= menuSaveMenu;
                    202: */
                    203:        Menu_Default.menuInitialItem = -1;
                    204:        XtGetResources( dpy, resourceList, XtNumber(resourceList),
                    205:                        (ArgList) NULL, 0, DefaultRootWindow(dpy),
                    206:                        XtNxterm, XtCApp, &nameList, &classList );
                    207: 
                    208:        /* would be nice if (Xrm)CvtStringToFontStruct didn't complain
                    209:         * when the font didn't exist! */
                    210:        if (Menu_DefaultFont != NULL) {
                    211:            Menu_Default.menuFontInfo = XLoadQueryFont(dpy, Menu_DefaultFont);
                    212:            if (!Menu_Default.menuFontInfo)
                    213:                Menu_DefaultFont = NULL;
                    214:        }
                    215: 
                    216:        /* actually, we need to know whether the fid is valid anyway */
                    217:        if (Menu_DefaultFont == NULL) {
                    218:            Menu_Default.menuFontInfo = screen->fnt_norm;
                    219:            MenugcFontMask = VTgcFontMask;
                    220:        }
                    221: };
                    222: 
                    223: /*
                    224:  * ItemFlags returns the state of item "n" of the menu.
                    225:  */
                    226: ItemFlags(menu, n)
                    227: register Menu *menu;
                    228: register int n;
                    229: {
                    230:        register MenuItem *item;
                    231: 
                    232:        if(!menu || !menu->menuItems || n < 0)
                    233:                return(-1);
                    234:        for(item = menu->menuItems ; n > 0 ; n--)
                    235:                if(!(item = item->nextItem))
                    236:                        return(0);
                    237:        return((item->itemFlags & itemSetMask) >> itemSetMaskShift);
                    238: }
                    239: 
                    240: /*
                    241:  * ItemText changes the text of item "n" of the menu.
                    242:  */
                    243: ItemText(menu, n, text)
                    244: register Menu *menu;
                    245: register int n;
                    246: char *text;
                    247: {
                    248:        register MenuItem *item;
                    249: 
                    250:        if(!menu || !menu->menuItems || n < 0 || !text)
                    251:                return(0);
                    252:        for(item = menu->menuItems ; n > 0 ; n--)
                    253:                if(!(item = item->nextItem))
                    254:                        return(0);
                    255:        item->itemText = text;
                    256:        menu->menuFlags |= menuChanged;
                    257:        return(1);
                    258: }
                    259: 
                    260: /*
                    261:  * NewMenu() returns a pointer to an initialized new Menu structure, or NULL
                    262:  * if failed.
                    263:  *
                    264:  * The Menu structure _menuDefault contains the default menu settings.
                    265:  */
                    266: Menu *NewMenu(name, reverse)
                    267: char *name;
                    268: int reverse;
                    269: {
                    270:        register Menu *menu;
                    271:        register int fg, bg;
                    272:        register TScreen *screen = &term.screen;
                    273:        XGCValues xgc;
                    274:        extern char *malloc();
                    275:        extern XFontStruct *XLoadQueryFont();
                    276:        register Display *dpy = screen->display;
                    277: 
                    278:        /*
                    279:         * If the GrayTile hasn't been defined, InitMenu() was never
                    280:         * run, so exit.
                    281:         */
                    282:        if(!Gray_Tile)
                    283:                return((Menu *)0);
                    284:        /*
                    285:         * Allocate the memory for the menu structure.
                    286:         */
                    287:        if((menu = (Menu *)malloc(sizeof(Menu))) == (Menu *)0)
                    288:                return((Menu *)0);
                    289:        /*
                    290:         * Initialize to default values.
                    291:         */
                    292:        *menu = Menu_Default;
                    293:        /*
                    294:         * If the menu cursor hasn't been given, make a default one.
                    295:         */
                    296:        if(!menu->menuCursor) {
                    297:                if(!Menu_DefaultCursor) {
                    298:                        if(reverse) {
                    299:                                fg = WhitePixel(dpy, 
                    300:                                        DefaultScreen(dpy));
                    301:                                bg = BlackPixel(dpy, 
                    302:                                        DefaultScreen(dpy));
                    303:                        } else {
                    304:                                fg = BlackPixel(dpy, 
                    305:                                        DefaultScreen(dpy));
                    306:                                bg = WhitePixel(dpy, 
                    307:                                        DefaultScreen(dpy));
                    308:                        }
                    309:                        if(!(Menu_DefaultCursor =
                    310:                           XCreateFontCursor(dpy, XC_left_ptr)))
                    311:                                return((Menu *)0);
                    312:                }
                    313:                menu->menuCursor = Menu_DefaultCursor;
                    314:        }
                    315:        /*
                    316:         * Initialze the default background and border pixmaps and foreground
                    317:         * and background colors (black and white).
                    318:         */
                    319:        if(reverse) {
                    320:                menu->menuFgColor = WhitePixel(dpy, 
                    321:                        DefaultScreen(dpy));
                    322:                menu->menuBgColor = BlackPixel(dpy, 
                    323:                        DefaultScreen(dpy));
                    324:        } else {
                    325:                menu->menuFgColor = BlackPixel(dpy, 
                    326:                        DefaultScreen(dpy));
                    327:                menu->menuBgColor = WhitePixel(dpy, 
                    328:                        DefaultScreen(dpy));
                    329:        }
                    330:        if(!gotGCs) {
                    331:                xgc.foreground = menu->menuFgColor;
                    332:                xgc.function = GXinvert;
                    333:                xgc.plane_mask = XOR(menu->menuFgColor, menu->menuBgColor);
                    334:                MenuInvertGC = XCreateGC(dpy, DefaultRootWindow(dpy),
                    335:                  GCForeground+GCFunction+GCPlaneMask, &xgc);
                    336:                xgc.foreground = menu->menuFgColor;
                    337:                xgc.background = menu->menuBgColor;
                    338:                xgc.font = menu->menuFontInfo->fid;
                    339:                xgc.function = GXcopy;
                    340:                xgc.fill_style = FillSolid;
                    341:                MenuGC = XCreateGC(dpy, DefaultRootWindow(dpy),
                    342:                 MenugcFontMask+GCForeground+GCBackground+GCFunction+GCFillStyle,
                    343:                 &xgc);
                    344:                xgc.foreground = menu->menuBgColor;
                    345:                xgc.background = menu->menuFgColor;
                    346:                xgc.font = menu->menuFontInfo->fid;
                    347:                xgc.function = GXcopy;
                    348:                xgc.fill_style = FillSolid;
                    349:                MenuInverseGC = XCreateGC(dpy, DefaultRootWindow(dpy),
                    350:                 MenugcFontMask+GCForeground+GCBackground+GCFunction+GCFillStyle,
                    351:                 &xgc);
                    352:                xgc.foreground = menu->menuFgColor;
                    353:                xgc.background = menu->menuBgColor;
                    354:                xgc.function = menu->menuFgColor ? GXor : GXand;
                    355: /*             xgc.function = GXcopy;*/
                    356:                xgc.stipple = Gray_Tile;
                    357:                xgc.fill_style = FillStippled;
                    358:                MenuGrayGC = XCreateGC(dpy, DefaultRootWindow(dpy),
                    359:                 GCStipple+GCFillStyle+MenugcFontMask
                    360:                                       +GCForeground+GCBackground+GCFunction, 
                    361:                 &xgc);
                    362:                gotGCs = TRUE;
                    363:        }
                    364:        /*
                    365:         * Set the menu title.  If name is NULL or is an empty string, no
                    366:         * title will be displayed.
                    367:         */
                    368:        if(name && *name) {
                    369:                menu->menuTitleLength = strlen(menu->menuTitle = name);
                    370:                menu->menuTitleWidth = XTextWidth(menu->menuFontInfo, name, 
                    371:                 menu->menuTitleLength);
                    372:                menu->menuItemTop = menu->menuFontInfo->ascent + 
                    373:                 menu->menuFontInfo->descent + 2 * menu->menuItemPad + 1;
                    374:        } else
                    375:                menu->menuTitleLength = menu->menuTitleWidth =
                    376:                 menu->menuItemTop = 0;
                    377:        return(menu);
                    378: }
                    379: 
                    380: /*
                    381:  * SetItemCheck sets the check state of item "n" of the menu to "state".
                    382:  */
                    383: SetItemCheck(menu, n, state)
                    384: register Menu *menu;
                    385: register int n;
                    386: int state;
                    387: {
                    388:        register MenuItem *item;
                    389: 
                    390:        if(!menu || !menu->menuItems || n < 0)
                    391:                return(0);
                    392:        for(item = menu->menuItems ; n > 0 ; n--)
                    393:                if(!(item = item->nextItem))
                    394:                        return(0);
                    395:        if(state)
                    396:                item->itemFlags |= itemSetChecked;
                    397:        else
                    398:                item->itemFlags &= ~itemSetChecked;
                    399:        if(((item->itemFlags & itemSetMask) >> itemSetMaskShift) !=
                    400:         (item->itemFlags & itemStateMask)) {
                    401:                item->itemFlags |= itemChanged;
                    402:                menu->menuFlags |= menuItemChanged;
                    403:        } else
                    404:                item->itemFlags &= ~itemChanged;
                    405:        return(1);
                    406: }
                    407: 
                    408: /*
                    409:  * SetItemDisable sets the disable state of item "n" of the menu to "state".
                    410:  */
                    411: SetItemDisable(menu, n, state)
                    412: register Menu *menu;
                    413: register int n;
                    414: int state;
                    415: {
                    416:        register MenuItem *item;
                    417: 
                    418:        if(!menu || !menu->menuItems || n < 0)
                    419:                return(0);
                    420:        for(item = menu->menuItems ; n > 0 ; n--)
                    421:                if(!(item = item->nextItem))
                    422:                        return(0);
                    423:        if(state)
                    424:                item->itemFlags |= itemSetDisabled;
                    425:        else
                    426:                item->itemFlags &= ~itemSetDisabled;
                    427:        if(((item->itemFlags & itemSetMask) >> itemSetMaskShift) !=
                    428:         (item->itemFlags & itemStateMask)) {
                    429:                item->itemFlags |= itemChanged;
                    430:                menu->menuFlags |= menuItemChanged;
                    431:        } else
                    432:                item->itemFlags &= ~itemChanged;
                    433:        return(1);
                    434: }
                    435: 
                    436: static Menu *menu;
                    437: static MenuItem *item;
                    438: static int i;
                    439: static MenuItem *hilited_item;
                    440: static int drawn;
                    441: static int changed;
                    442: int y, n, hilited_y, hilited_n, in_window;
                    443: static MenuItem *Mouse_InItem(), *Y_InItem();
                    444: static Unmap_Menu();
                    445: 
                    446: XtEventReturnCode MenuExposeWindow(event, eventdata)
                    447: register XEvent *event;
                    448: caddr_t eventdata;
                    449: {
                    450:        register TScreen *screen = &term.screen;
                    451:        /*
                    452:         * If we have a saved pixmap, display it.  Otherwise
                    453:         * redraw the menu and save it away.
                    454:         */
                    455:        if (event->type == NoExpose) return;
                    456:        if(menu->menuSaved) {
                    457:                XCopyArea(screen->display, menu->menuSaved, menu->menuWindow, 
                    458:                 MenuGC, 0, 0,
                    459:                 menu->menuWidth, menu->menuHeight, 0, 0);
                    460:                /*
                    461:                 * If the menuItemChanged flag is still set,
                    462:                 * then we need to redraw certain menu items.
                    463:                 * ("i" is the vertical position of the top
                    464:                 * of the current item.)
                    465:                 */
                    466:                if(changed & menuItemChanged) {
                    467:                        i = menu->menuItemTop;
                    468:                        for(item = menu->menuItems ; item ;
                    469:                         item = item->nextItem) {
                    470:                                if(item->itemFlags & itemChanged)
                    471:                                        Modify_Item(menu, item, i);
                    472:                                i += item->itemHeight;
                    473:                        }
                    474:                }
                    475:        } else
                    476:                Draw_Menu(menu);
                    477:        /*
                    478:         * If the menu has changed in any way and we want to
                    479:         * save the menu, throw away any existing save menu
                    480:         * image and make a new one.
                    481:         */
                    482:        XFlush(screen->display);
                    483:        if(changed && (menu->menuFlags & menuSaveMenu)) {
                    484:                if(menu->menuSaved)
                    485:                        XFreePixmap(screen->display, menu->menuSaved);
                    486: /*             menu->menuSaved = XPixmapSave(screen->display, 
                    487:                 menu->menuWindow, 0, 0, menu->menuWidth, menu->menuHeight);
                    488: */
                    489:        }
                    490:        /*
                    491:         * See which item the cursor may currently be in.  If
                    492:         * it is in a non-disabled item, hilite it.
                    493:         */
                    494:        if(hilited_item = Mouse_InItem(menu, &hilited_y, &hilited_n))
                    495:                XFillRectangle(screen->display, menu->menuWindow, 
                    496:                 MenuInvertGC, 0, hilited_y,
                    497:                 menu->menuWidth, hilited_item->itemHeight);
                    498:        drawn++;
                    499:        return (XteventHandled);
                    500: }
                    501: 
                    502: XtEventReturnCode MenuMouseMoved(event, eventdata)
                    503: XButtonEvent *event;
                    504: caddr_t eventdata;
                    505: {
                    506:        register TScreen *screen = &term.screen;
                    507:        if(!drawn || !in_window)
                    508:                return;
                    509:        /*
                    510:         * See which item the cursor may currently be in.  If
                    511:         * the item has changed, unhilite the old one and
                    512:         * then hilited the new one.
                    513:         */
                    514:        y = event->y;
                    515:        if((item = Y_InItem(menu, &y, &n)) != hilited_item) {
                    516:                if(hilited_item)
                    517:                        XFillRectangle(screen->display, menu->menuWindow, 
                    518:                         MenuInvertGC, 0, hilited_y,
                    519:                         menu->menuWidth, hilited_item->itemHeight);
                    520:                if(hilited_item = item) {
                    521:                        XFillRectangle(screen->display, menu->menuWindow, 
                    522:                         MenuInvertGC, 0,
                    523:                         hilited_y = y, menu->menuWidth, item->itemHeight);
                    524:                        hilited_n = n;
                    525:                }
                    526:        }
                    527:        return (XteventHandled);
                    528: }
                    529: 
                    530: XtEventReturnCode MenuEnterWindow(event, eventdata)
                    531: XEvent *event;
                    532: caddr_t eventdata;
                    533: {
                    534:        in_window = TRUE;
                    535:        return (MenuMouseMoved(event, eventdata));
                    536: }
                    537: 
                    538: XtEventReturnCode MenuLeaveWindow(event, eventdata)
                    539: XEvent *event;
                    540: caddr_t eventdata;
                    541: {
                    542:        register TScreen *screen = &term.screen;
                    543:        if(!drawn)
                    544:                return (XteventHandled);
                    545:        /*
                    546:         * Unhilite any window that is currently hilited.
                    547:         */
                    548:        if(hilited_item) {
                    549:                XFillRectangle(screen->display, menu->menuWindow, 
                    550:                 MenuInvertGC, 0, hilited_y,
                    551:                 menu->menuWidth, hilited_item->itemHeight);
                    552:                hilited_item = (MenuItem *)0;
                    553:        }
                    554:        in_window = FALSE;
                    555:        return (XteventHandled);
                    556: }
                    557: 
                    558: XtEventReturnCode MenuButtonReleased(event, eventdata)
                    559: XButtonEvent *event;
                    560: caddr_t eventdata;
                    561: {
                    562:        register TScreen *screen = &term.screen;
                    563:        extern FinishModeMenu();
                    564: 
                    565:        /*
                    566:         * return the index number of any selected menu
                    567:         * item.
                    568:         */
                    569: 
                    570:        if (! AllButtonsUp(event->state, event->button))
                    571:                return(XteventHandled);
                    572: 
                    573:        XUngrabPointer(screen->display, CurrentTime);
                    574:        
                    575:        if(in_window) {
                    576:                y = event->y;
                    577:                if((item = Y_InItem(menu, &y, &n)) != hilited_item) {
                    578:                    if(hilited_item)
                    579:                        XFillRectangle(screen->display, menu->menuWindow, 
                    580:                         MenuInvertGC, 0,
                    581:                         hilited_y, menu->menuWidth,
                    582:                         hilited_item->itemHeight);
                    583:                    if(hilited_item = item) {
                    584:                        XFillRectangle(screen->display, menu->menuWindow, 
                    585:                         MenuInvertGC, 0,
                    586:                         hilited_y = y, menu->menuWidth,
                    587:                         hilited_item->itemHeight);
                    588:                        hilited_n = n;
                    589:                    }
                    590:                }
                    591:        }
                    592:        XFlush(screen->display);
                    593:        menu->menuFlags &= ~(menuChanged | menuItemChanged);
                    594:        Unmap_Menu(menu);
                    595:        drawn = 0;
                    596:        if(hilited_item)
                    597:                FinishModeMenu(menu->menuInitialItem = hilited_n);
                    598:        else
                    599:                FinishModeMenu(-1);
                    600:        return (XteventHandled);
                    601: }
                    602: 
                    603: /*
                    604:  * TrackMenu does most of the work of displaying the menu and tracking the
                    605:  * mouse.
                    606:  */
                    607: TrackMenu(lmenu, event)
                    608: register Menu *lmenu;
                    609: register XButtonPressedEvent *event;
                    610: {
                    611:        register TScreen *screen = &term.screen;
                    612:        XButtonReleasedEvent ev;
                    613:        XSetWindowAttributes attr;
                    614: 
                    615:        menu = lmenu;
                    616:        hilited_item = (MenuItem *)0;
                    617:        /*
                    618:         * Check that things are reasonable.
                    619:         */
                    620:        if(!menu || !event || !menu->menuItems || event->type != ButtonPress)
                    621:                return(-1);
                    622:        /*
                    623:         * Set the changed flag and clear the menu changed flags.
                    624:         */
                    625:        changed = menu->menuFlags & (menuChanged | menuItemChanged);
                    626:        /*
                    627:         * If the entire menu has changed, throw away any saved pixmap and
                    628:         * then call RecalcMenu().
                    629:         */
                    630:        if(changed & menuChanged) {
                    631:                if(menu->menuSaved)
                    632:                        XFreePixmap(screen->display, menu->menuSaved);
                    633:                menu->menuSaved = (Pixmap)0;
                    634:                if(!Recalc_Menu(menu))
                    635:                        return(-1);
                    636:                changed &= ~menuItemChanged;
                    637:        }
                    638:        /*
                    639:         * Now if the window was never created, go ahead and make it.  Otherwise
                    640:         * if the menu has changed, resize the window.
                    641:         */
                    642:        if(!menu->menuWindow) {
                    643:                attr.override_redirect = TRUE;
                    644:                attr.border_pixmap = make_gray(
                    645:                  WhitePixel(screen->display, DefaultScreen(screen->display)), 
                    646:                  BlackPixel(screen->display, DefaultScreen(screen->display)), 
                    647:                  DefaultDepth(screen->display, DefaultScreen(screen->display)));
                    648:                attr.background_pixel = menu->menuBgColor;
                    649:                attr.cursor = menu->menuCursor;
                    650:                if((menu->menuWindow = XCreateWindow(screen->display, 
                    651:                 DefaultRootWindow(screen->display), 0, 0,
                    652:                 menu->menuWidth, menu->menuHeight, menu->menuBorderWidth,
                    653:                 0, CopyFromParent, CopyFromParent, 
                    654:                 CWBorderPixmap+CWBackPixel+CWOverrideRedirect+CWCursor, 
                    655:                 &attr)) == (Window)0)
                    656:                        return(-1);
                    657: 
                    658: 
                    659:                XtSetEventHandler(screen->display, menu->menuWindow,
                    660:                 (XtEventHandler) MenuExposeWindow, ExposureMask, 
                    661:                 (caddr_t)NULL);
                    662:                XtSetEventHandler(screen->display, menu->menuWindow,
                    663:                 (XtEventHandler) MenuEnterWindow, EnterWindowMask, 
                    664:                 (caddr_t)NULL);
                    665:                XtSetEventHandler(screen->display, menu->menuWindow,
                    666:                 (XtEventHandler) MenuLeaveWindow, LeaveWindowMask, 
                    667:                 (caddr_t)NULL);
                    668:                XtSetEventHandler(screen->display, menu->menuWindow,
                    669:                 (XtEventHandler) MenuMouseMoved, PointerMotionMask, 
                    670:                 (caddr_t)NULL);
                    671:                XtSetEventHandler(screen->display, menu->menuWindow,
                    672:                 (XtEventHandler) MenuButtonReleased, ButtonReleaseMask,
                    673:                 (caddr_t)NULL);
                    674:                XtSetEventHandler(screen->display, menu->menuWindow,
                    675:                 (XtEventHandler) EventDoNothing, ButtonPressMask, 
                    676:                 (caddr_t)NULL);
                    677:        } else if(changed & menuChanged)
                    678:                XResizeWindow(screen->display, menu->menuWindow, 
                    679:                 menu->menuWidth, menu->menuHeight);
                    680:        /*
                    681:         * Figure out where the menu is supposed to go, from the initial button
                    682:         * press, and move the window there.  Then map the menu.
                    683:         */
                    684:        if(!Move_Menu(menu, event) || !Map_Menu(menu))
                    685:                return(-1);
                    686: 
                    687:        menuWindow = menu->menuWindow;
                    688:        in_window = TRUE;
                    689:        XGrabPointer(screen->display, menu->menuWindow, FALSE,
                    690:         ExposureMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask
                    691:         | ButtonReleaseMask | ButtonPressMask,
                    692:         GrabModeAsync, GrabModeAsync, None, menu->menuCursor, CurrentTime
                    693:         );
                    694: }
                    695: 
                    696: /*
                    697:  * Recalculate all of the various menu and item variables.
                    698:  */
                    699: static Recalc_Menu(menu)
                    700: register Menu *menu;
                    701: {
                    702:        register MenuItem *item;
                    703:        register int max, i, height, fontheight;
                    704: 
                    705:        /*
                    706:         * We must have already gotten the menu font.
                    707:         */
                    708:        if(!menu->menuFontInfo)
                    709:                return(0);
                    710:        /*
                    711:         * Initialize the various max width variables.
                    712:         */
                    713:        fontheight = menu->menuFontInfo->ascent + menu->menuFontInfo->descent;
                    714:        height = menu->menuItemTop;
                    715:        menu->menuMaxTextWidth = menu->menuTitleWidth;
                    716:        /*
                    717:         * The item height is the maximum of the font height and the
                    718:         * checkbox height.
                    719:         */
                    720:        max = fontheight;
                    721:        if(checkMarkHeight > max)
                    722:                max = checkMarkHeight;
                    723:        /*
                    724:         * Go through the menu item list.
                    725:         */
                    726:        for(item = menu->menuItems ; item ; item = item->nextItem) {
                    727:                /*
                    728:                 * If the item text is a single dash, we assume this is
                    729:                 * a line separator and treat it special.
                    730:                 */
                    731:                if(XStrCmp(item->itemText, "-") == 0)
                    732:                        height += (item->itemHeight = lineSeparatorHeight);
                    733:                else {
                    734:                        height += (item->itemHeight = max);
                    735:                        /*
                    736:                         * Check the text width with the max value stored in
                    737:                         * menu.
                    738:                         */
                    739:                        if((item->itemTextWidth = XTextWidth(
                    740:                          menu->menuFontInfo, item->itemText,
                    741:                          strlen(item->itemText))) > menu->menuMaxTextWidth)
                    742:                                menu->menuMaxTextWidth = item->itemTextWidth;
                    743:                }
                    744:                /*
                    745:                 * If the itemChanged flag is set, set the state bits.
                    746:                 */
                    747:                if(item->itemFlags & itemChanged) {
                    748:                        item->itemFlags = (item->itemFlags & ~itemStateMask) |
                    749:                         ((item->itemFlags & itemSetMask) >> itemSetMaskShift);
                    750:                        item->itemFlags &= ~itemChanged;
                    751:                }
                    752:        }
                    753:        /*
                    754:         * Set the menu height and then set the menu width.
                    755:         */
                    756:        menu->menuHeight = height;
                    757:        menu->menuWidth = 3 * menu->menuItemPad + menu->menuMaxTextWidth +
                    758:         checkMarkWidth;
                    759:        return(1);
                    760: }
                    761: 
                    762: /*
                    763:  * Figure out where to popup the menu, relative to the where the button was
                    764:  * pressed.
                    765:  */
                    766: static Move_Menu(menu, ev)
                    767: register Menu *menu;
                    768: XButtonPressedEvent *ev;
                    769: {
                    770:        register MenuItem *item;
                    771:        register int n, x, y;
                    772:        register TScreen *screen = &term.screen;
                    773:        int total_width;
                    774:        Window subw;
                    775:        /*
                    776:         * Try to popup the menu so that the cursor is centered within the
                    777:         * width of the menu, but compensate if that would run it outside
                    778:         * the display area.
                    779:         */
                    780:        total_width = menu->menuWidth + 2 * menu->menuBorderWidth;
                    781:        if((x = ev->x_root - total_width / 2) < 0)
                    782:                x = 0;
                    783:        else if(x + total_width > DisplayWidth(screen->display,
                    784:                                               DefaultScreen(screen->display)))
                    785:                x = DisplayWidth(screen->display,
                    786:                                 DefaultScreen(screen->display)) - total_width;
                    787:        /*
                    788:         * If the menu extends above outside of the display, warp
                    789:         * the mouse vertically so the menu will all show up.
                    790:         */
                    791:        if((y = ev->y_root) < 0) {
                    792: /* don't bother warping pointer 
                    793:                XWarpPointer(screen->display, None, 
                    794:                  DefaultRootWindow(screen->display), 0, 0, 0, 0, ev->x_root, 
                    795:                    0);
                    796: */
                    797:                y = 0;
                    798:        } else if((n = y + menu->menuHeight + 2 * menu->menuBorderWidth - 
                    799:          DisplayHeight(screen->display, DefaultScreen(screen->display))) > 0) {
                    800: /* don't bother warping pointer 
                    801:                XWarpPointer(screen->display, None,
                    802:                 DefaultRootWindow(screen->display), 0, 0, 0, 0, ev->x_root, 
                    803:                  ev->y_root - n);
                    804: */
                    805:                y -= n;
                    806:        }
                    807:        XMoveWindow(screen->display, menu->menuWindow, x, y);
                    808:        /*
                    809:         * If we are in freeze mode, save what will be the coordinates of
                    810:         * the save image.
                    811:         */
                    812:        if(menu->menuFlags & menuFreeze) {
                    813:                menu->menuSavedImageX = x;
                    814:                menu->menuSavedImageY = y;
                    815:        }
                    816:        return(1);
                    817: }
                    818: 
                    819: /*
                    820:  * Map the menu window.
                    821:  */
                    822: static Map_Menu(menu)
                    823: register Menu *menu;
                    824: {
                    825:        register int i;
                    826:        register TScreen *screen = &term.screen;
                    827: 
                    828:        /*
                    829:         * If we are in freeze mode, save the pixmap underneath where the menu
                    830:         * will be (including the border).
                    831:         */
                    832:        if(menu->menuFlags & menuFreeze) {
                    833:                XGrabServer(screen->display);
                    834:                i = 2 * menu->menuBorderWidth;
                    835: /*             if((menu->menuSavedImage = XPixmapSave(screen->display,
                    836:                 DefaultRootWindow(screen->display),
                    837:                 menu->menuSavedImageX, menu->menuSavedImageY, menu->menuWidth
                    838:                 + i, menu->menuHeight + i)) == (Pixmap)0)
                    839: */
                    840:                        return(0);
                    841:        }
                    842:        /*
                    843:         * Actually map the window.
                    844:         */
                    845:        XMapRaised(screen->display, menu->menuWindow);
                    846:        menu->menuFlags |= menuMapped;
                    847:        return(1);
                    848: }
                    849: 
                    850: /*
                    851:  * Draw the entire menu in the blank window.
                    852:  */
                    853: static Draw_Menu(menu)
                    854: register Menu *menu;
                    855: {
                    856:        register MenuItem *item;
                    857:        register int top = menu->menuItemTop;
                    858:        register int x = menu->menuItemPad;
                    859:        register int y, dim;
                    860:        register TScreen *screen = &term.screen;
                    861: 
                    862:        /*
                    863:         * If we have a menu title, draw it first, centered and hilited.
                    864:         */
                    865:        if(menu->menuTitleLength) {
                    866:                XFillRectangle(screen->display, menu->menuWindow, 
                    867:                 MenuGC, 0, 0, menu->menuWidth, top - 1);
                    868:                XDrawImageString(screen->display, menu->menuWindow, 
                    869:                 MenuInverseGC, (menu->menuWidth -
                    870:                 menu->menuTitleWidth) / 2, 
                    871:                 menu->menuItemPad+menu->menuFontInfo->ascent, 
                    872:                 menu->menuTitle, menu->menuTitleLength);
                    873:        }
                    874:        /*
                    875:         * For each item in the list, first draw any check mark and then
                    876:         * draw the rest of it.
                    877:         */
                    878:        for(item = menu->menuItems ; item ; item = item->nextItem) {
                    879:                SetStateFlags(item);
                    880:                dim = (item->itemFlags & itemDisabled);
                    881:                /*
                    882:                 * Draw the check mark, possibly dimmed, wherever is necessary.
                    883:                 */
                    884:                if(item->itemFlags & itemChecked) {
                    885:                        XCopyArea(screen->display, 
                    886:                         Check_Tile, menu->menuWindow, 
                    887:                         dim ? MenuGrayGC : MenuGC,
                    888:                         0, 0, checkMarkWidth, checkMarkHeight, x, 
                    889:                         y = top + (item->itemHeight - checkMarkHeight) / 2);
                    890:                }
                    891:                /*
                    892:                 * Draw the item, possibly dimmed.
                    893:                 */
                    894:                Draw_Item(menu, item, top, dim);
                    895:                top += item->itemHeight;
                    896:        }
                    897: }
                    898: 
                    899: /*
                    900:  * Modify the item at vertical position y.  This routine is table driven and
                    901:  * the state and set bits are each 2 bits long, contiguous, the least
                    902:  * significant bits in the flag word and with the state bits in bits 0 & 1.
                    903:  */
                    904: 
                    905: #define        drawCheck       0x10
                    906: #define        removeCheck     0x08
                    907: #define        dimCheck        0x04
                    908: #define        drawItem        0x02
                    909: #define        dimItem         0x01
                    910: 
                    911: static char Modify_Table[] = {
                    912:        0x00, 0x02, 0x08, 0x0a, 0x01, 0x00, 0x09, 0x08,
                    913:        0x10, 0x12, 0x00, 0x12, 0x15, 0x14, 0x05, 0x00
                    914: };
                    915:        
                    916: static Modify_Item(menu, item, top)
                    917: register Menu *menu;
                    918: register MenuItem *item;
                    919: int top;
                    920: {
                    921:        register int x = menu->menuItemPad;
                    922:        register int y;
                    923:        register int center = top + item->itemHeight / 2;
                    924:        register int func = Modify_Table[item->itemFlags &
                    925:         (itemStateMask | itemSetMask)];
                    926:        register TScreen *screen = &term.screen;
                    927: 
                    928:        /*
                    929:         * If we really won't be making a change, return.
                    930:         */
                    931:        if(func == 0)
                    932:                return;
                    933:        /*
                    934:         * Draw the check mark if needed, possibly dimmed.
                    935:         */
                    936:        y = center - (checkMarkHeight / 2);
                    937:        if(func & (drawCheck | dimCheck))
                    938:                XCopyArea(screen->display, 
                    939:                 Check_Tile, menu->menuWindow, 
                    940:                 (func & dimCheck) ? MenuGrayGC : MenuGC,
                    941:                 0, 0, checkMarkWidth, checkMarkHeight, x, 
                    942:                  y = top + (item->itemHeight - checkMarkHeight) / 2);
                    943:        /*
                    944:         * Remove the check mark if needed.
                    945:         */
                    946:        if(func & removeCheck)
                    947:                XClearArea(screen->display, menu->menuWindow, 
                    948:                 x, y, checkMarkWidth, checkMarkHeight);
                    949:        /*
                    950:         * Call Draw_Item if we need to draw or dim the item.
                    951:         */
                    952:        if((x = func & dimItem) || (func & drawItem))
                    953:                Draw_Item(menu, item, top, x);
                    954:        /*
                    955:         * Update state flags.
                    956:         */
                    957:        SetStateFlags(item);
                    958: }
                    959: 
                    960: /*
                    961:  * Draw the item (less check mark) at vertical position y.
                    962:  * Dim the item if "dim" is set.
                    963:  */
                    964: static Draw_Item(menu, item, y, dim)
                    965: register Menu *menu;
                    966: register MenuItem *item;
                    967: register int y;
                    968: int  dim;
                    969: {
                    970:        register int x = 2 * menu->menuItemPad + checkMarkWidth;
                    971:        register int center = y + item->itemHeight / 2;
                    972:        register TScreen *screen = &term.screen;
                    973: 
                    974:        /*
                    975:         * If the item text is a single dash, draw a separating line.
                    976:         */
                    977:        if(XStrCmp(item->itemText, "-") == 0) {
                    978:                XDrawLine(screen->display, menu->menuWindow,  MenuGC,
                    979:                 0, center, menu->menuWidth, center);
                    980:                return;
                    981:        }
                    982:        /*
                    983:         * Draw and/or dim the text, centered vertically.
                    984:         */
                    985:        y = center - 
                    986:         ((menu->menuFontInfo->ascent + menu->menuFontInfo->descent)/ 2);
                    987:        if(dim) {
                    988:                XDrawString(screen->display, menu->menuWindow, MenuGrayGC,
                    989:                 x, y+menu->menuFontInfo->ascent, 
                    990:                 item->itemText, item->itemTextLength);
                    991:        } else
                    992:                XDrawImageString(screen->display, menu->menuWindow, 
                    993:                 MenuGC, x, y+menu->menuFontInfo->ascent, 
                    994:                 item->itemText, item->itemTextLength);
                    995: }
                    996: 
                    997: /*
                    998:  * Determine which enabled menu item the mouse is currently in.  Return the
                    999:  * top position of this item and its item number.  Set inwindow to whether
                   1000:  * we are or not.
                   1001:  */
                   1002: static MenuItem *Mouse_InItem(menu, top, n)
                   1003: register Menu *menu;
                   1004: int *top, *n;
                   1005: {
                   1006:        int x, y, rootx, rooty, mask;
                   1007:        Window subw, root;
                   1008:        static MenuItem *Y_InItem();
                   1009:        register TScreen *screen = &term.screen;
                   1010: 
                   1011:        /*
                   1012:         * Find out where the mouse is.  If its not in the menu window,
                   1013:         * return NULL.
                   1014:         */
                   1015:        XQueryPointer(screen->display, menu->menuWindow, 
                   1016:        &root, &subw, &rootx, &rooty, &x, &y, &mask);
                   1017:        if((x <0) || (y < 0) || 
                   1018:           (x > menu->menuWidth) || (y > menu->menuHeight)) {
                   1019:                return((MenuItem *)0);
                   1020:        }
                   1021:        /*
                   1022:         * Call Y_InItem().
                   1023:         */
                   1024:        *top = y;
                   1025:        return(Y_InItem(menu, top, n));
                   1026: }
                   1027: 
                   1028: /*
                   1029:  * Return which enabled item the locator is in.  Also return the
                   1030:  * top position of this item and its item number.  Initial y passed
                   1031:  * in top.
                   1032:  */
                   1033: static MenuItem *Y_InItem(menu, top, n)
                   1034: register Menu *menu;
                   1035: int *top, *n;
                   1036: {
                   1037:        register MenuItem *item;
                   1038:        register int t, i;
                   1039:        register int y = *top;
                   1040:        Window subw;
                   1041: 
                   1042:        /*
                   1043:         * Go through the item list.  "t" is the vertical position of the
                   1044:         * current item and "i" is its item number.
                   1045:         */
                   1046:        t = menu->menuItemTop;
                   1047:        /*
                   1048:         * If the mouse is before the first item, return.
                   1049:         */
                   1050:        if(y < t)
                   1051:                return((MenuItem *)0);
                   1052:        for(i = 0, item = menu->menuItems ; item ; i++, item = item->nextItem) {
                   1053:                /*
                   1054:                 * If the y coordinate is within this menu item, then return.
                   1055:                 * But don't return disable items.
                   1056:                 */
                   1057:                if(t + item->itemHeight > y) {
                   1058:                        if(item->itemFlags & itemDisabled)
                   1059:                                return((MenuItem *)0);
                   1060:                        *top = t;
                   1061:                        *n = i;
                   1062:                        return(item);
                   1063:                }
                   1064:                t += item->itemHeight;
                   1065:        }
                   1066:        /*
                   1067:         * Should never get here.
                   1068:         */
                   1069:        return((MenuItem *)0);
                   1070: }
                   1071: 
                   1072: /*
                   1073:  * Unmap_Menu() unmaps a menu, if it is currently mapped.
                   1074:  */
                   1075: static Unmap_Menu(menu)
                   1076: register Menu *menu;
                   1077: {
                   1078:        register int i;
                   1079:        register TScreen *screen = &term.screen;
                   1080: 
                   1081:        if(!menu || !(menu->menuFlags & menuMapped))
                   1082:                return;
                   1083:        if(menu->menuFlags & menuFreeze) {
                   1084:                XUnmapWindow(screen->display, menu->menuWindow);
                   1085:                i = 2 * menu->menuBorderWidth;
                   1086:                XCopyArea(screen->display, 
                   1087:                 menu->menuSavedImage, DefaultRootWindow(screen->display), 
                   1088:                 MenuGC, 0, 0, menu->menuWidth + i,
                   1089:                 menu->menuHeight + i, menu->menuSavedImageX, 
                   1090:                 menu->menuSavedImageY);
                   1091:                XFreePixmap(screen->display, menu->menuSavedImage);
                   1092:                XUngrabServer(screen->display);
                   1093:        } else
                   1094:                XUnmapWindow(screen->display, menu->menuWindow);
                   1095:        menu->menuFlags &= ~menuMapped;
                   1096: }
                   1097: #endif MODEMENU

unix.superglobalmegacorp.com

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