1: #ifndef lint
   2: static char *rcsid_Menu_c = "$Header: Menu.c,v 10.3 86/02/01 16:23:11 tony Rel $";
   3: #endif	lint
   4: 
   5: /************************************************************************
   6:  *									*
   7:  *			Copyright (c) 1986 by				*
   8:  *		Digital Equipment Corporation, Maynard, MA		*
   9:  *		         All Rights Reserved.				*
  10:  *									*
  11:  *	Permission to use, copy, modify, and distribute this software	*
  12:  *	and its documentation is hereby granted only to licensees of 	*
  13:  *	The Regents of the University of California pursuant to their	*
  14:  *	license agreement for the Berkeley Software Distribution 	*
  15:  *	provided that the following appears on all copies.		*
  16:  *									*
  17:  *            "LICENSED FROM DIGITAL EQUIPMENT CORPORATION		*
  18:  *                      COPYRIGHT (C) 1986				*
  19:  *                 DIGITAL EQUIPMENT CORPORATION			*
  20:  *                         MAYNARD, MA					*
  21:  *                     ALL RIGHTS RESERVED.				*
  22:  *									*
  23:  *      THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT	*
  24:  *	NOTICE AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL	*
  25:  *	EQUIPMENT CORPORATION.  DIGITAL MAKES NO REPRESENTATIONS	*
  26:  *	ABOUT SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. IT IS	*
  27:  *	SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.		*
  28:  *									*
  29:  * 	IF THE UNIVERSITY OF CALIFORNIA OR ITS LICENSEES MODIFY 	*
  30:  *	THE SOFTWARE IN A MANNER CREATING DERIVATIVE COPYRIGHT 		*
  31:  *	RIGHTS APPROPRIATE COPYRIGHT LEGENDS MAY BE PLACED ON THE	*
  32:  *	DERIVATIVE WORK IN ADDITION TO THAT SET FORTH ABOVE."		*
  33:  *									*
  34:  ************************************************************************/
  35: 
  36: 
  37: /*
  38:  * MODIFICATION HISTORY
  39:  *
  40:  * 000 -- M. Gancarz, DEC Ultrix Engineering Group
  41:  */
  42: 
  43: #ifndef lint
  44: static char *sccsid = "@(#)Menu.c	3.8	1/24/86";
  45: #endif
  46: 
  47: #include "uwm.h"
  48: 
  49: #define DisplayLine(w, pane, width, height, str, fg, bg) \
  50:          XPixSet(w, 0, pane, width, height, bg); \
  51:          XTextMask(w, HMenuPad, pane + VMenuPad, str, strlen(str), MFont, fg);
  52: 
  53: #define NVERTS  5           /* Number of vertices for hi-liter. */
  54: 
  55: static Vertex vlist[NVERTS];        /* Vertex list for hi-liter. */
  56: 
  57: Bool Menu(window, mask, button, x, y, menu)
  58: Window window;              /* Event window. */
  59: int mask;               /* Button/key mask. */
  60: short button;               /* Button event detail. */
  61: int x, y;               /* Event mouse position. */
  62: MenuInfo *menu;
  63: {
  64:     XButtonEvent button_event;      /* Button event packet. */
  65:     Bool func_stat;         /* Function status return. */
  66:     int cur_x, cur_y;           /* Current mouse position. */
  67:     Window sub_window;          /* Current subwindow. */
  68:     int cur_item = 0;           /* Current menu item. */
  69:     int hi_lite = 0;            /* Current highlighted item. */
  70:     int i;              /* Iteration counter. */
  71:     short hlfg, hlbg;           /* Hi-liter pixels. */
  72:     MenuLine *ml;           /* Menu lines pointer. */
  73:     char *hlname;           /* Pointer to hi-liter name. */
  74:     char *strbuf;           /* String buffer for IsTextNL. */
  75:     char *malloc();
  76: 
  77:     /*
  78:      * Change the cursor.
  79:      */
  80:     status = XGrabButton(RootWindow, MenuCursor, mask, EVENTMASK);
  81:     if (status == FAILURE)
  82:         Error("Menu -> Unable to grab button and change cursor.");
  83: 
  84:     /*
  85:      * Map the menu.
  86:      */
  87:     MapMenu(menu, x, y);
  88: 
  89:     /*
  90:      * Main loop.
  91:      */
  92:     while (TRUE) {
  93: 
  94:         /*
  95:          * If no button event, check the current mouse position.
  96:          */
  97:         status = XUpdateMouse(menu->w, &cur_x, &cur_y, &sub_window);
  98:         if (status == FAILURE) continue;
  99: 
 100:         /*
 101:          * If the mouse has moved out of the menu sideways, abort
 102:          * the menu operation. Reset the cursor and unmap the menu.
 103:          */
 104:         if (cur_x < 0 || cur_x > menu->width) {
 105:             UnmapMenu(menu, mask);
 106:             return(FALSE);
 107:         }
 108: 
 109:         /*
 110:          * If the mouse has moved below or above the menu, but is still
 111:          * within the same vertical plane, then simply adjust the values
 112:          * so the user doesn't fall off the edge.
 113:          */
 114:         if (cur_y >= menu->height) cur_y = menu->height - 1;
 115:         else if (cur_y < 0) cur_y = 0;
 116: 
 117:         /*
 118:          * If the mouse has moved to another item in the menu,
 119:          * highlight the new item.
 120:          */
 121:         cur_item = cur_y / menu->iheight;
 122:         if (cur_item != hi_lite) {
 123: 
 124:             /*
 125:              * Remove highlighting on old item.
 126:              */
 127:             if (hi_lite) {
 128:                 DisplayLine(menu->w, hi_lite * menu->iheight,
 129:                             menu->width, menu->iheight, hlname,
 130:                             hlfg, hlbg);
 131:             }
 132: 
 133:             /*
 134:              * Highlight new item.
 135:              */
 136:             if (cur_item) {
 137:                 for(i = 1, ml = menu->line; ml; i++, ml = ml->next) {
 138:                     if (i == cur_item) break;
 139:                 }
 140:                 DisplayLine(menu->w, cur_item * menu->iheight,
 141:                             menu->width, menu->iheight, ml->name,
 142:                             menu->hlfg.pixel, menu->hlbg.pixel);
 143:                 vlist[0].y = cur_item * menu->iheight + 1;
 144:                 XDraw(menu->w, vlist, NVERTS, 1, 1,
 145:                       menu->hlfg.pixel, GXcopy, AllPlanes);
 146:             }
 147:             hi_lite = cur_item;
 148:             hlfg = ml->fg.pixel;
 149:             hlbg = ml->bg.pixel;
 150:             hlname = ml->name;
 151:         }
 152: 
 153:         /*
 154:          * Check to see if we have a change in the mouse buttons.
 155:          * This means the user has selected an item or aborted the
 156:          * operation.
 157:          */
 158:         if (XPending() && GetButton(&button_event)) {
 159: 
 160:             /*
 161:              * Was button released?
 162:              */
 163:             if ((button_event.type == ButtonReleased) &&
 164:                 ((button_event.detail & ValueMask) == button)) {
 165:                 break;
 166:             } else {
 167: 
 168:                 /*
 169:                  * Some other button event occurred, so abort the menu
 170:                  * operation.
 171:                  */
 172:                 UnmapMenu(menu, mask);
 173:                 return(TRUE);
 174:             }
 175:         }
 176:     }
 177: 
 178:     /*
 179:      * If no item was selected, simply close the menu and return.
 180:      */
 181:     if (!cur_item) {
 182:         UnmapMenu(menu, mask);
 183:         return(TRUE);
 184:     }
 185: 
 186:     /*
 187:      * Get a pointer to the menu line selected.
 188:      */
 189:     --cur_item;
 190:     for(i = 0, ml = menu->line; ml; i++, ml = ml->next) {
 191:         if (i == cur_item) break;
 192:     }
 193: 
 194:     /*
 195:      * Perform the selected menu line action.
 196:      */
 197:     switch (ml->type) {
 198: 
 199:         case IsShellCommand:
 200:             UnmapMenu(menu, mask);
 201:             system(ml->text);
 202:             break;
 203: 
 204:         case IsText:
 205:             UnmapMenu(menu, mask);
 206:             XStoreBytes(ml->text, strlen(ml->text));
 207:             break;
 208: 
 209:         case IsTextNL:
 210:             UnmapMenu(menu, mask);
 211:             strbuf = (char *)malloc(strlen(ml->text) + 2);
 212:             strcpy(strbuf, ml->text);
 213:             strcat(strbuf, "\n");
 214:             XStoreBytes(strbuf, strlen(strbuf));
 215:             free(strbuf);
 216:             break;
 217: 
 218:         case IsUwmFunction:
 219:             GetContext(&sub_window, &cur_x, &cur_y);
 220:             UnmapMenu(menu, mask);
 221:             if (sub_window != menu->w)
 222:                 (*ml->func) (sub_window, mask, button, cur_x, cur_y);
 223:             break;
 224: 
 225:         case IsImmFunction:
 226:             UnmapMenu(menu, mask);
 227:             (*ml->func) (sub_window, mask, button, cur_x, cur_y);
 228:             break;
 229: 
 230:         case IsMenuFunction:
 231:             while (TRUE) {
 232:                 if (!GetButton(&button_event)) continue;
 233:                 if (button_event.type != ButtonPressed) continue;
 234:                 if ((KeyMask(button_event.detail) != KeyMask(mask)) ||
 235:                     ((button_event.detail & ButtonMods) != button)) {
 236:                     UnmapMenu(menu, mask);
 237:                     return(TRUE);
 238:                 }
 239:                 break;
 240:             }
 241:             UnmapMenu(menu, mask);
 242:             func_stat = Menu(menu->w, mask, button, x, y, ml->menu);
 243:             return(func_stat);
 244:             break;
 245: 
 246:         default:
 247:             Error("Menu -> Internal type error.");
 248:     }
 249:     return(TRUE);
 250: }
 251: 
 252: /*
 253:  * Create the menu windows for later use.
 254:  */
 255: CreateMenus()
 256: {
 257:     MenuLink *ptr;
 258: 
 259:     /*
 260:      * If MaxColors isn't set, then jam it to an impossibly high
 261:      * number.
 262:      */
 263:     if (MaxColors == 0)
 264:         MaxColors = 25000;
 265: 
 266:     for(ptr = Menus; ptr; ptr = ptr->next)
 267:         InitMenu(ptr->menu);
 268: }
 269: 
 270: /*
 271:  * Initialize a menu.
 272:  */
 273: InitMenu(menu)
 274: MenuInfo *menu;
 275: {
 276:     MenuLine *ml;       /* Menu lines pointer. */
 277:     int width;          /* Width of an item name. */
 278:     int maxwidth;       /* Maximum width of item names. */
 279:     int len;            /* Length of an item name. */
 280:     int count = 1;      /* Number of items + 1 for name. */
 281: 
 282:     /*
 283:      * Determine the name of the longest menu item.
 284:      */
 285:     maxwidth = XQueryWidth(menu->name, MFont);
 286:     if (maxwidth == 0)
 287:         Error("InitMenu -> Couldn't get length of menu name");
 288: 
 289:     for(ml = menu->line; ml; ml = ml->next) {
 290:         if ((len = strlen(ml->name)) == 0)
 291:             break;
 292:         width = XQueryWidth(ml->name, MFont);
 293:         if (width == 0) Error("InitMenu -> Couldn't get length of menu item name");
 294:         if (width > maxwidth) maxwidth = width;
 295:         count++;
 296:     }
 297: 
 298:     /*
 299:      * Get the color cells for the menu items.
 300:      */
 301:     GetMenuColors(menu);
 302: 
 303:     /*
 304:      * Stash the menu parameters in the menu info structure.
 305:      */
 306:     menu->iheight = MFontInfo.height + (VMenuPad << 1);
 307:     menu->height = menu->iheight * count;
 308:     menu->width = maxwidth + (HMenuPad << 1);
 309:     menu->image = NULL;
 310: 
 311:     /*
 312:      * Create the menu window.
 313:      */
 314:     menu->w = XCreateWindow(RootWindow,
 315:                             0, 0,
 316:                             menu->width,
 317:                             menu->height,
 318:                             MBorderWidth,
 319:                             MBorder, MBackground);
 320:     if (menu->w == NULL) Error("InitMenu -> Couldn't create menu window");
 321: 
 322:     /*
 323:      * Store the window name.
 324:      */
 325:     XStoreName(menu->w, menu->name);
 326: 
 327:     /*
 328:      * Define a cursor for the window.
 329:      */
 330:     XDefineCursor(menu->w, MenuCursor);
 331: }
 332: 
 333: /*
 334:  * Map a menu.
 335:  */
 336: MapMenu(menu, x, y)
 337: MenuInfo *menu;
 338: int x, y;
 339: {
 340:     int item;
 341:     Window w;
 342:     MenuLine *ml;
 343: 
 344:     w = menu->w;
 345: 
 346:     /*
 347:      * Move the menu into place, normalizing the coordinates, if necessary;
 348:      * then map it.
 349:      */
 350:     x -= (menu->width >> 1);
 351:     if (x < 0) x = 0;
 352:     else if (x + menu->width >= ScreenWidth)
 353:         x = ScreenWidth - menu->width - (MBorderWidth << 1);
 354:     if (y < 0) y = 0;
 355:     else if (y + menu->height >= ScreenHeight)
 356:         y = ScreenHeight - menu->height - (MBorderWidth << 1);
 357:     XMoveWindow(w, x, y);
 358: 
 359:     /*
 360:      * Map the window and draw the text items.
 361:      */
 362:     XMapWindow(w);
 363:     DisplayLine(w, 0, menu->width, menu->iheight, menu->name,
 364:                 menu->bg.pixel, menu->fg.pixel);
 365: 
 366:     SetUpVlist(menu);
 367:     vlist[0].x = 1;
 368:     vlist[0].y = 1;
 369:     XDraw(menu->w, vlist, NVERTS, 1, 1, menu->bg.pixel, GXcopy, AllPlanes);
 370:     item = menu->iheight;
 371:     for(ml = menu->line; ml; ml = ml->next) {
 372:         DisplayLine(w, item, menu->width, menu->iheight, ml->name,
 373:                     ml->fg.pixel, ml->bg.pixel);
 374:         item += menu->iheight;
 375:     }
 376: 
 377:     /*
 378:      * Position the mouse cursor in the menu header (or in the first item
 379:      * if "autoselect" is set).
 380:      */
 381:     if (Autoselect)
 382:         XWarpMouse(w, (menu->width >> 2) * 3, (menu->iheight >> 1) * 3);
 383:     else XWarpMouse(w, (menu->width >> 2) * 3, menu->iheight >> 1);
 384: 
 385:     XFlush();
 386: }
 387: 
 388: /*
 389:  * Unmap a menu, restoring the contents of the screen underneath
 390:  * if necessary. (Restore portion is a future.)
 391:  */
 392: UnmapMenu(menu, mask)
 393: MenuInfo *menu;
 394: int mask;
 395: {
 396:     /*
 397:      * Restore the main cursor.
 398:      */
 399:     Grab((short)mask);
 400: 
 401:     /*
 402:      * Unmap and flush.
 403:      */
 404:     XUnmapWindow(menu->w);
 405:     XFlush();
 406: }
 407: 
 408: /*
 409:  * Get the context for invoking a window manager function.
 410:  */
 411: GetContext(w, x, y)
 412: Window *w;
 413: int *x, *y;
 414: {
 415:     XButtonEvent button_event;  /* Button input event. */
 416: 
 417:     while (TRUE) {
 418: 
 419:         /*
 420:          * Get the next mouse button event.  Spin our wheels until
 421:          * a button event is returned (ie. GetButton == TRUE).
 422:          * Note that mouse events within an icon window are handled
 423:          * in the "GetButton" function or by the icon's owner if
 424:          * it is not uwm.
 425:          */
 426:         if (!GetButton(&button_event)) continue;
 427: 
 428:         /*
 429:          * If the button event received is not a ButtonPressed event
 430:          * then continue until we find one.
 431:          */
 432:         if (button_event.type != ButtonPressed) continue;
 433: 
 434:         /*
 435:          * Okay, determine the event window and mouse coordinates.
 436:          */
 437:         status = XInterpretLocator(RootWindow,
 438:                                     x, y,
 439:                                     w,
 440:                                     button_event.location);
 441: 
 442:         if (status == FAILURE) continue;
 443: 
 444:         if (*w == 0)
 445:             *w = RootWindow;
 446: 
 447:         return;
 448:     }
 449: }
 450: 
 451: /*
 452:  * Get the color cells for a menu.  This function is slightly brain-damaged
 453:  * in that once MaxColors <= 1, then it refuses to even try to allocate any
 454:  * more colors, even though the colors may have already been allocated.  It
 455:  * probably ought to be done right someday.
 456:  */
 457: GetMenuColors(menu)
 458: MenuInfo *menu;
 459: {
 460:     register MenuLine *ml;      /* Menu lines pointer. */
 461: 
 462:     /*
 463:      * If we have more than 2 colors available, then attempt to get
 464:      * the color map entries requested by the user.
 465:      * Otherwise, default to standard black and white.
 466:      */
 467:     if (DisplayCells() > 2) {
 468: 
 469:         /*
 470:          * Get the menu header colors first.
 471:          */
 472:         if (!(menu->foreground && menu->background && MaxColors > 1 &&
 473:               XParseColor(menu->foreground, &menu->fg) &&
 474:               XGetHardwareColor(&menu->fg) &&
 475:               XParseColor(menu->background, &menu->bg) &&
 476:               XGetHardwareColor(&menu->bg))) {
 477:             menu->fg.pixel = MTextForground;
 478:             menu->bg.pixel = MTextBackground;
 479:         } else {
 480:             AdjustMaxColors(menu->fg.pixel);
 481:             AdjustMaxColors(menu->bg.pixel);
 482:         }
 483: 
 484:         /*
 485:          * Get the menu highlight colors.
 486:          */
 487:         if (!(menu->fghighlight && menu->bghighlight && MaxColors > 1 &&
 488:               XParseColor(menu->fghighlight, &menu->hlfg) &&
 489:               XGetHardwareColor(&menu->hlfg) &&
 490:               XParseColor(menu->bghighlight, &menu->hlbg) &&
 491:               XGetHardwareColor(&menu->hlbg))) {
 492:             menu->hlfg.pixel = MTextBackground;
 493:             menu->hlbg.pixel = MTextForground;
 494:         } else {
 495:             AdjustMaxColors(menu->hlfg.pixel);
 496:             AdjustMaxColors(menu->hlbg.pixel);
 497:         }
 498: 
 499:         /*
 500:          * Get the menu item colors.
 501:          */
 502:         for(ml = menu->line; ml; ml = ml->next) {
 503:             if (!(ml->foreground && ml->background && MaxColors > 1 &&
 504:                   XParseColor(ml->foreground, &ml->fg) &&
 505:                   XGetHardwareColor(&ml->fg) &&
 506:                   XParseColor(ml->background, &ml->bg) &&
 507:                   XGetHardwareColor(&ml->bg))) {
 508:                 ml->fg.pixel = MTextForground;
 509:                 ml->bg.pixel = MTextBackground;
 510:             } else {
 511:                 AdjustMaxColors(ml->fg.pixel);
 512:                 AdjustMaxColors(ml->bg.pixel);
 513:             }
 514:         }
 515: 
 516:     } else {
 517: 
 518:         /*
 519:          * Only 2 colors available, so default to standard black and white.
 520:          */
 521:         menu->fg.pixel = MTextForground;
 522:         menu->bg.pixel = MTextBackground;
 523:         menu->hlfg.pixel = MTextBackground;
 524:         menu->hlbg.pixel = MTextForground;
 525:         for(ml = menu->line; ml; ml = ml->next) {
 526:             ml->fg.pixel = MTextForground;
 527:             ml->bg.pixel = MTextBackground;
 528:         }
 529:     }
 530: }
 531: 
 532: /*
 533:  * Decrement "MaxColors" if this pixel value has never been used in a
 534:  * menu before.
 535:  */
 536: AdjustMaxColors(pixel)
 537: int pixel;
 538: {
 539:     register MenuLink *mptr;
 540:     register MenuLine *lptr;
 541:     int count = 0;
 542: 
 543:     for(mptr = Menus; mptr; mptr = mptr->next) {
 544:         if (mptr->menu->fg.pixel == pixel) ++count;
 545:         if (mptr->menu->bg.pixel == pixel) ++count;
 546:         if (mptr->menu->hlfg.pixel == pixel) ++count;
 547:         if (mptr->menu->hlbg.pixel == pixel) ++count;
 548:         for(lptr = mptr->menu->line; lptr; lptr = lptr->next) {
 549:             if (lptr->fg.pixel == pixel) ++count;
 550:             if (lptr->bg.pixel == pixel) ++count;
 551:         }
 552:         if (count > 1) return;
 553:     }
 554:     --MaxColors;
 555: }
 556: 
 557: /*
 558:  * Set up the vertex list for the hi-liter.
 559:  */
 560: SetUpVlist(menu)
 561: MenuInfo *menu;
 562: {
 563:     vlist[1].x = menu->width - 3;
 564:     vlist[1].y = 0;
 565:     vlist[2].x = 0;
 566:     vlist[2].y = menu->iheight - 3;
 567:     vlist[3].x = (short)(0 - menu->width + 3);
 568:     vlist[3].y = 0;
 569:     vlist[4].x = 0;
 570:     vlist[4].y = (short)(0 - menu->iheight + 3);
 571:     vlist[1].flags = vlist[2].flags = vlist[3].flags =
 572:     vlist[4].flags = VertexRelative;
 573: }

Defined functions

AdjustMaxColors defined in line 536; used 6 times
CreateMenus defined in line 255; used 2 times
GetContext defined in line 411; used 1 times
GetMenuColors defined in line 457; used 1 times
InitMenu defined in line 273; used 1 times
MapMenu defined in line 336; used 1 times
  • in line 87
Menu defined in line 57; used 2 times
SetUpVlist defined in line 560; used 1 times
UnmapMenu defined in line 392; used 10 times

Defined variables

rcsid_Menu_c defined in line 2; never used
sccsid defined in line 44; never used
vlist defined in line 55; used 17 times

Defined macros

DisplayLine defined in line 49; used 4 times
NVERTS defined in line 53; used 3 times
Last modified: 1986-02-01
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1709
Valid CSS Valid XHTML 1.0 Strict