|
|
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.