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