|
|
1.1 root 1: #ifndef lint
2: static char *rcsid_uwm_c = "$Header: uwm.c,v 10.7 86/11/19 19:03:58 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 = "@(#)uwm.c 3.8 1/24/86";
40: #endif
41:
42: #include <sys/time.h>
43: #include "uwm.h"
44:
45: #ifdef PROFIL
46: #include <signal.h>
47: /*
48: * Dummy handler for profiling.
49: */
50: ptrap()
51: {
52: exit(0);
53: }
54: #endif
55:
56: #include <fcntl.h>
57:
58: static short gray_bits[16] = {
59: 0xaaaa, 0x5555, 0xaaaa, 0x5555,
60: 0xaaaa, 0x5555, 0xaaaa, 0x5555,
61: 0xaaaa, 0x5555, 0xaaaa, 0x5555,
62: 0xaaaa, 0x5555, 0xaaaa, 0x5555
63: };
64:
65: Bool ChkMline();
66: char *sfilename;
67: extern FILE *yyin;
68:
69: /*
70: * Main program.
71: */
72: main(argc, argv, environ)
73: int argc;
74: char **argv;
75: char **environ;
76: {
77: short hi; /* Button event high detail. */
78: short lo; /* Button event low detail. */
79: int x, y; /* Mouse X and Y coordinates. */
80: int cur_x, cur_y; /* Current mouse X and Y coordinates. */
81: int str_width; /* Width in pixels of output string. */
82: int pop_width, pop_height; /* Pop up window width and height. */
83: int context; /* Root, window, or icon context. */
84: Bool func_stat; /* If true, function swallowed a ButtonUp. */
85: Bool delta_done; /* If true, then delta functions are done. */
86: register Binding *bptr; /* Pointer to Bindings list. */
87: char *root_name; /* Root window name. */
88: char *display = NULL; /* Display name pointer. */
89: char message[128]; /* Error message buffer. */
90: char *rc_file; /* Pointer to $HOME/.uwmrc. */
91: Bitmap gray_bitmap; /* Gray bitmap used for gray pixmap. */
92: Display *dpy; /* Display info pointer. */
93: Window event_win; /* Event window. */
94: Window sub_win; /* Subwindow for XUpdateMouse calls. */
95: WindowInfo root_info; /* Root window info. */
96: WindowInfo event_info; /* Event window info. */
97: XButtonEvent button_event; /* Button input event. */
98: char *malloc();
99:
100:
101: #ifdef PROFIL
102: signal(SIGTERM, ptrap);
103: #endif
104:
105: /*
106: * Set up internal defaults.
107: */
108: strcpy(IFontName, DEF_FONT);
109: strcpy(PFontName, DEF_FONT);
110: strcpy(MFontName, DEF_FONT);
111: CursorFunc = DEF_FUNC;
112: Delta = DEF_DELTA;
113: IBorderWidth = DEF_ICON_BORDER_WIDTH;
114: HIconPad = DEF_ICON_PADDING;
115: VIconPad = DEF_ICON_PADDING;
116: PBorderWidth = DEF_POP_BORDER_WIDTH;
117: PPadding = DEF_POP_PADDING;
118: MBorderWidth = DEF_MENU_BORDER_WIDTH;
119: HMenuPad = DEF_MENU_PADDING;
120: VMenuPad = DEF_MENU_PADDING;
121: Volume = DEF_VOLUME;
122:
123: /*
124: * Set XErrorFunction to be non-terminating.
125: */
126: XErrorHandler(XError);
127:
128: /*
129: * Parse the command line arguments.
130: */
131: Argv = argv;
132: Environ = environ;
133: argc--, argv++;
134: while (argc) {
135: if (!(strcmp(*argv, "-f"))) {
136: argc--, argv++;
137: if ((argc == 0) || (Startup_File[0] != '\0'))
138: Usage();
139: strncpy(Startup_File, *argv, NAME_LEN);
140: }
141: else display = *argv;
142: argc--, argv++;
143: }
144:
145: /*
146: * Initialize the default bindings.
147: */
148: InitBindings();
149:
150: /*
151: * Read in and parse $HOME/.uwmrc, if it exists.
152: */
153: sfilename = rc_file = malloc(NAME_LEN);
154: sprintf(rc_file, "%s/.uwmrc", getenv("HOME"));
155: if ((yyin = fopen(rc_file, "r")) != NULL) {
156: Lineno = 1;
157: yyparse();
158: fclose(yyin);
159: if (Startup_File_Error)
160: Error("Bad .uwmrc file...aborting");
161: }
162:
163: /*
164: * Read in and parse the startup file from the command line, if
165: * specified.
166: */
167: if (Startup_File[0] != '\0') {
168: sfilename = Startup_File;
169: if ((yyin = fopen(Startup_File, "r")) == NULL) {
170: sprintf(message, "Cannot open startup file '%s'", Startup_File);
171: Error(message);
172: }
173: Lineno = 1;
174: yyparse();
175: fclose(yyin);
176: if (Startup_File_Error)
177: Error("Bad startup file...aborting");
178: }
179:
180: /*
181: * Verify the menu bindings.
182: */
183: VerifyMenuBindings();
184: if (Startup_File_Error)
185: Error("Bad startup file...aborting");
186:
187: /*
188: * Open the display.
189: */
190: if ((dpy = XOpenDisplay(display)) == NULL) {
191: fprintf(stderr, "%s: Can't open display '%s'\n",
192: Argv[0], XDisplayName(display));
193: exit(1);
194: }
195:
196: /*
197: * Force child processes to disinherit the TCP file descriptor.
198: * This helps shell commands forked and exec'ed from menus
199: * to work properly.
200: */
201: if ((status = fcntl(dpyno(), F_SETFD, 1)) == -1) {
202: perror("uwm: child cannot disinherit TCP fd");
203: Error("TCP file descriptor problems");
204: }
205:
206: /*
207: * If the root window has not been named, name it.
208: */
209: status = XFetchName(RootWindow, &root_name);
210: if (status == FAILURE) Error("Can't fetch Root Window name string");
211: if (root_name == NULL) XStoreName(RootWindow, " X Root Window ");
212: if (root_name) free(root_name);
213:
214: /*
215: * Gather information about the root window.
216: */
217: status = XQueryWindow(RootWindow, &root_info);
218: if (status == FAILURE)
219: Error("Can't acquire root window information from X server");
220:
221: ScreenHeight = root_info.height; /* True height of entire screen */
222: ScreenWidth = root_info.width; /* True width of entire screen */
223:
224: /*
225: * Create and store the icon background pixmap.
226: */
227: gray_bitmap = XStoreBitmap(16, 16, gray_bits);
228: GrayPixmap = XMakePixmap(gray_bitmap, BlackPixel, WhitePixel);
229:
230: /*
231: * Set up icon window, icon cursor and pop-up window color parameters.
232: */
233: if (Reverse) {
234: IconCursorFunc = GXcopyInverted;
235: IBorder = WhitePixmap;
236: IBackground = GrayPixmap;
237: ITextForground = WhitePixel;
238: ITextBackground = BlackPixel;
239: PBorder = BlackPixmap;
240: PBackground = WhitePixmap;
241: PTextForground = BlackPixel;
242: PTextBackground = WhitePixel;
243: MBorder = WhitePixmap;
244: MBackground = BlackPixmap;
245: MTextForground = WhitePixel;
246: MTextBackground = BlackPixel;
247: }
248: else {
249: IconCursorFunc = GXcopy;
250: IBorder = BlackPixmap;
251: IBackground = GrayPixmap;
252: ITextForground = BlackPixel;
253: ITextBackground = WhitePixel;
254: PBorder = WhitePixmap;
255: PBackground = BlackPixmap;
256: PTextForground = WhitePixel;
257: PTextBackground = BlackPixel;
258: MBorder = BlackPixmap;
259: MBackground = WhitePixmap;
260: MTextForground = BlackPixel;
261: MTextBackground = WhitePixel;
262: }
263:
264: /*
265: * Store all the cursors.
266: */
267: StoreCursors();
268:
269: /*
270: * grab the mouse buttons according to the map structure
271: */
272: Grab_Buttons();
273:
274: /*
275: * Load the selected fonts.
276: */
277: IFont = XGetFont(IFontName);
278: if (IFont == FAILURE) {
279: sprintf(message, "Unable to get font '%s'.", IFontName);
280: Error(message);
281: }
282: PFont = XGetFont(PFontName);
283: if (PFont == FAILURE) {
284: sprintf(message, "Unable to get font '%s'.", PFontName);
285: Error(message);
286: }
287: MFont = XGetFont(MFontName);
288: if (MFont == FAILURE) {
289: sprintf(message, "Unable to get font '%s'.", MFontName);
290: Error(message);
291: }
292:
293: /*
294: * Retrieve the information structure for the specifed fonts and
295: * set the global font information pointers.
296: */
297: status = XQueryFont(IFont, &IFontInfo);
298: if (status == FAILURE) {
299: sprintf(message, "Unable to query X server for info on font '%s'.",
300: IFontName);
301: Error(message);
302: }
303: status = XQueryFont(PFont, &PFontInfo);
304: if (status == FAILURE) {
305: sprintf(message, "Unable to query X server for info on font '%s'.",
306: PFontName);
307: Error(message);
308: }
309: status = XQueryFont(MFont, &MFontInfo);
310: if (status == FAILURE) {
311: sprintf(message, "Unable to query X server for info on font '%s'.",
312: MFontName);
313: Error(message);
314: }
315:
316: /*
317: * Calculate size of the resize pop-up window.
318: */
319: str_width = XQueryWidth(PText, PFont);
320: pop_width = str_width + (PPadding << 1);
321: PWidth = pop_width + (PBorderWidth << 1);
322: pop_height = PFontInfo.height + (PPadding << 1);
323: PHeight = pop_height + (PBorderWidth << 1);
324:
325: /*
326: * Create the pop-up window. Create it at (0, 0) for now. We will
327: * move it where we want later.
328: */
329: Pop = XCreateWindow(RootWindow,
330: 0, 0,
331: pop_width, pop_height,
332: PBorderWidth,
333: PBorder, PBackground);
334: if (Pop == FAILURE) Error("Can't create pop-up dimension display window.");
335:
336: /*
337: * Create the menus for later use.
338: */
339: CreateMenus();
340:
341: /*
342: * Tell the user we're alive and well.
343: */
344: XFeep(Volume);
345:
346: /*
347: * Main command loop.
348: */
349: while (TRUE) {
350:
351: delta_done = func_stat = FALSE;
352:
353: /*
354: * Get the next mouse button event. Spin our wheels until
355: * a ButtonPressed event is returned.
356: * Note that mouse events within an icon window are handled
357: * in the "GetButton" function or by the icon's owner if
358: * it is not uwm.
359: */
360: while (TRUE) {
361: if (!GetButton(&button_event)) continue;
362: if (button_event.type == ButtonPressed) break;
363: }
364:
365: /*
366: * Okay, determine the event window and mouse coordinates.
367: */
368: status = XInterpretLocator(RootWindow,
369: &x, &y,
370: &event_win,
371: button_event.location);
372:
373: if (status == FAILURE) continue;
374:
375: /*
376: * Determine the event window and context.
377: */
378: if (event_win == 0) {
379: event_win = RootWindow;
380: context = ROOT;
381: } else {
382: status = XQueryWindow(event_win, &event_info);
383: if (status == FAILURE) continue;
384: if (event_info.type & IsIcon)
385: context = ICON;
386: else context = WINDOW;
387: }
388:
389: /*
390: * Get the button event detail.
391: */
392: lo = (button_event.detail & ValueMask);
393: hi = KeyMask(button_event.detail);
394:
395: /*
396: * Determine which function was selected and invoke it.
397: */
398: for(bptr = Blist; bptr; bptr = bptr->next) {
399:
400: if ((bptr->button != lo) ||
401: (KeyMask(bptr->mask) != hi))
402: continue;
403:
404: if (bptr->context != context)
405: continue;
406:
407: if (!(bptr->mask & ButtonDown))
408: continue;
409:
410: /*
411: * Found a match! Invoke the function.
412: */
413: if ((*bptr->func)(event_win,
414: (int)bptr->mask & ~ButtonMods,
415: bptr->button,
416: x, y,
417: bptr->menu)) {
418: func_stat = TRUE;
419: break;
420: }
421: }
422:
423: /*
424: * If the function ate the ButtonUp event, then restart the loop.
425: */
426: if (func_stat) continue;
427:
428: while(TRUE) {
429: /*
430: * Wait for the next button event.
431: */
432: if (XPending() && GetButton(&button_event)) {
433:
434: /*
435: * If it's not a release of the same button that was pressed,
436: * don't do the function bound to 'ButtonUp'.
437: */
438: if (button_event.type != ButtonReleased)
439: break;
440: if (lo != (button_event.detail & ValueMask))
441: break;
442: if (hi != KeyMask(button_event.detail))
443: break;
444:
445: /*
446: * Okay, determine the event window and mouse coordinates.
447: */
448: status = XInterpretLocator(RootWindow,
449: &x, &y,
450: &event_win,
451: button_event.location);
452:
453: if (status == FAILURE) break;
454:
455: if (event_win == 0) {
456: event_win = RootWindow;
457: context = ROOT;
458: } else {
459: status = XQueryWindow(event_win, &event_info);
460: if (status == FAILURE) break;
461: if (event_info.type & IsIcon)
462: context = ICON;
463: else context = WINDOW;
464: }
465:
466: /*
467: * Determine which function was selected and invoke it.
468: */
469: for(bptr = Blist; bptr; bptr = bptr->next) {
470:
471: if ((bptr->button != lo) ||
472: (KeyMask(bptr->mask) != hi))
473: continue;
474:
475: if (bptr->context != context)
476: continue;
477:
478: if (!(bptr->mask & ButtonUp))
479: continue;
480:
481: /*
482: * Found a match! Invoke the function.
483: */
484: (*bptr->func)(event_win,
485: (int)bptr->mask & ~ButtonMods,
486: bptr->button,
487: x, y,
488: bptr->menu);
489: }
490: break;
491: }
492:
493: XUpdateMouse(RootWindow, &cur_x, &cur_y, &sub_win);
494: if (!delta_done &&
495: ((abs(cur_x - x) > Delta) || (abs(cur_y - y) > Delta))) {
496: /*
497: * Delta functions are done once (and only once.)
498: */
499: delta_done = TRUE;
500:
501: /*
502: * Determine the new event window's coordinates.
503: */
504: status = XInterpretLocator(RootWindow,
505: &x, &y,
506: &event_win,
507: button_event.location);
508: if (status == FAILURE) break;
509:
510: /*
511: * Determine the event window and context.
512: */
513: if (event_win == 0) {
514: event_win = RootWindow;
515: context = ROOT;
516: } else {
517: status = XQueryWindow(event_win, &event_info);
518: if (status == FAILURE) break;
519: if (event_info.type & IsIcon)
520: context = ICON;
521: else context = WINDOW;
522: }
523:
524: /*
525: * Determine which function was selected and invoke it.
526: */
527: for(bptr = Blist; bptr; bptr = bptr->next) {
528:
529: if ((bptr->button != lo) ||
530: (KeyMask(bptr->mask) != hi))
531: continue;
532:
533: if (bptr->context != context)
534: continue;
535:
536: if (!(bptr->mask & DeltaMotion))
537: continue;
538:
539: /*
540: * Found a match! Invoke the function.
541: */
542: if ((*bptr->func)(event_win,
543: (int)bptr->mask & ~ButtonMods,
544: bptr->button,
545: x, y,
546: bptr->menu)) {
547: func_stat = TRUE;
548: break;
549: }
550: }
551: /*
552: * If the function ate the ButtonUp event,
553: * then restart the loop.
554: */
555: if (func_stat) break;
556: }
557: }
558: }
559: }
560:
561: /*
562: * Initialize the default bindings. First, write the character array
563: * out to a temp file, then point the parser to it and read it in.
564: * Afterwards, we unlink the temp file.
565: */
566: InitBindings()
567: {
568: char *mktemp();
569: char *tempfile = TEMPFILE; /* Temporary filename. */
570: register FILE *fp; /* Temporary file pointer. */
571: register char **ptr; /* Default bindings string array pointer. */
572:
573: /*
574: * Create and write the temp file.
575: */
576: sfilename = mktemp(tempfile);
577: if ((fp = fopen(tempfile, "w")) == NULL) {
578: perror("uwm: cannot create temp file");
579: exit(1);
580: }
581: for (ptr = DefaultBindings; *ptr; ptr++) {
582: fputs(*ptr, fp);
583: fputc('\n', fp);
584: }
585: fclose(fp);
586:
587: /*
588: * Read in the bindings from the temp file and parse them.
589: */
590: if ((yyin = fopen(tempfile, "r")) == NULL) {
591: perror("uwm: cannot open temp file");
592: exit(1);
593: }
594: Lineno = 1;
595: yyparse();
596: fclose(yyin);
597: unlink(tempfile);
598: if (Startup_File_Error)
599: Error("Bad default bindings...aborting");
600:
601: /*
602: * Parse the system startup file, if one exists.
603: */
604: if ((yyin = fopen(SYSFILE, "r")) != NULL) {
605: sfilename = SYSFILE;
606: Lineno = 1;
607: yyparse();
608: fclose(yyin);
609: if (Startup_File_Error)
610: Error("Bad system startup file...aborting");
611: }
612: }
613:
614: /*
615: * Verify menu bindings by checking that a menu that is mapped actually
616: * exists. Stash a pointer in the binding to the relevant menu info data
617: * structure.
618: * Check nested menu consistency.
619: */
620: VerifyMenuBindings()
621: {
622: Binding *bptr;
623: MenuLink *mptr;
624:
625: for(bptr = Blist; bptr; bptr = bptr->next) {
626: if (bptr->func == Menu) {
627: for(mptr = Menus; mptr; mptr = mptr->next) {
628: if(!(strcmp(bptr->menuname, mptr->menu->name))) {
629: bptr->menu = mptr->menu;
630: break;
631: }
632: }
633: if (mptr == NULL) {
634: fprintf(stderr,
635: "uwm: non-existent menu reference: \"%s\"\n",
636: bptr->menuname);
637: Startup_File_Error = TRUE;
638: }
639: }
640: }
641: CheckMenus();
642: }
643:
644: /*
645: * Check nested menu consistency by verifying that every menu line that
646: * calls another menu references a menu that actually exists.
647: */
648: CheckMenus()
649: {
650: MenuLink *ptr;
651: Bool errflag = FALSE;
652:
653: for(ptr = Menus; ptr; ptr = ptr->next) {
654: if (ChkMline(ptr->menu))
655: errflag = TRUE;
656: }
657: if (errflag)
658: Error("Nested menu inconsistency");
659: }
660:
661: Bool ChkMline(menu)
662: MenuInfo *menu;
663: {
664: MenuLine *ptr;
665: MenuLink *lptr;
666: Bool errflag = FALSE;
667:
668: for(ptr = menu->line; ptr; ptr = ptr->next) {
669: if (ptr->type == IsMenuFunction) {
670: for(lptr = Menus; lptr; lptr = lptr->next) {
671: if(!(strcmp(ptr->text, lptr->menu->name))) {
672: ptr->menu = lptr->menu;
673: break;
674: }
675: }
676: if (lptr == NULL) {
677: fprintf(stderr,
678: "uwm: non-existent menu reference: \"%s\"\n",
679: ptr->text);
680: errflag = TRUE;
681: }
682: }
683: }
684: return(errflag);
685: }
686:
687: /*
688: * Grab the mouse buttons according to the bindings list.
689: */
690: Grab_Buttons()
691: {
692: Binding *bptr;
693:
694: for(bptr = Blist; bptr; bptr = bptr->next)
695: Grab(bptr->mask);
696: }
697:
698: /*
699: * Grab a mouse button according to the given mask.
700: */
701: Grab(mask)
702: short mask;
703: {
704: short m = LeftMask | MiddleMask | RightMask;
705:
706: switch (mask & m) {
707: case LeftMask:
708: status = XGrabButton(RootWindow, LeftButtonCursor,
709: mask & ~ButtonMods,
710: EVENTMASK);
711: if (status == FAILURE)
712: Error("Can't grab left mouse button.");
713: break;
714:
715: case MiddleMask:
716: status = XGrabButton(RootWindow, MiddleButtonCursor,
717: mask & ~ButtonMods,
718: EVENTMASK);
719: if (status == FAILURE)
720: Error("Can't grab middle mouse button.");
721: break;
722:
723: case RightMask:
724: status = XGrabButton(RootWindow, RightButtonCursor,
725: mask & ~ButtonMods,
726: EVENTMASK);
727: if (status == FAILURE)
728: Error("Can't grab right mouse button.");
729: break;
730: }
731: }
732:
733: /*
734: * error routine for .uwmrc parser
735: */
736: yyerror(s)
737: char*s;
738: {
739: fprintf(stderr, "uwm: %s: %d: %s\n", sfilename, Lineno, s);
740: Startup_File_Error = TRUE;
741: }
742:
743: /*
744: * Print usage message and quit.
745: */
746: Usage()
747: {
748: fputs("Usage: uwm [-f <file>] [<host>:<display>]\n", stderr);
749: exit(1);
750: }
751:
752: /*
753: * error handler for X I/O errors
754: */
755: XIOError(dsp)
756: Display *dsp;
757: {
758: perror("uwm");
759: exit(3);
760: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.