|
|
1.1 ! root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.