|
|
1.1 root 1: /*
2: * Copyright 1985, Cognition Inc.
3: * This software is not supported by Cognition Inc. and is
4: * provided "as is". To keep the X revolution growing, please forward
5: * enhancements and bug fixes to anyone who is interested.
6: */
7:
8: /*
9: * XShell - a quick "shell" to allow you to cons up programs on the fly. The
10: * program looks at Button and Key Pressed events and looks up Xshell.name in
11: * $HOME/.Xdefaults where name is:
12: *
13: * LeftButton, MiddleButton, RightButton - on button events.
14: * ascii (e.g. [aB^9]) - on key pressed events.
15: * PF# and various special names - on special keys.
16: *
17: * The idea is that the user can define any set of key/button bindings which
18: * can be invoked by simply pressing in the XShell window. This can be very
19: * useful for times when you have filled all of your windows with things that
20: * you don't want to (or can't) suspend.
21: *
22: * I find it useful to have a large and small terminal window, a dc, and
23: * sometimes an editor that I can pop up on demand. This program was written
24: * because I was tired of getting into situations where I didn't have a window
25: * handy and I needed to run some little calculator or editor. Since I use
26: * a small, terse window manager I didn't just stick a bag on the side of it,
27: * but wrote a separate program instead.
28: *
29: * Apologies to anyone who has the scallop shell as a trademark.
30: *
31: * Author: Jim Fulton, Cognition Inc.
32: */
33: #ifndef lint
34: static char *rcsid_xshell_c = "$Header: xshell.c,v 10.7 86/11/19 19:55:45 jg Rel $";
35: #endif
36:
37: #include <stdio.h>
38: #include <X/Xlib.h>
39: #include <X/Xkeyboard.h>
40: #include <signal.h>
41: #include <ctype.h>
42: #include <strings.h>
43: #include <sys/file.h>
44: #include <sys/ioctl.h>
45: #include <sys/wait.h>
46: #include <sys/time.h>
47: #include <sys/resource.h>
48: #include <sys/types.h>
49: #include "scallopshell.h"
50: #include "largescallopshell.h"
51:
52: extern KeyMapEntry StdMap[];
53:
54: extern char *malloc();
55:
56: #define strneq(a,b) (strncmp ((a), (b), strlen(a)) == 0)
57: #define streq(a,b) (strcmp ((a), (b)) == 0)
58: #define isopt(optname) (strneq(*argv, optname)) /* does partial matching */
59: #define hasarg ((argv[1] != (char *) NULL) && (argv[1][0] != '-'))
60: #define NO 0
61: #define YES 1
62: #define DEFAULT_FONT "helv12b"
63: #define micro2centi (10000) /* microsecond to 1/100 second */
64:
65: char *ProgramName;
66:
67: Window ShellWindow;
68: Display *dpy;
69: int fg = BlackPixel; /* print bits in black */
70: int bg = WhitePixel; /* print background in white */
71: int bd = BlackPixel; /* print border in black */
72: int bw = 0; /* no border */
73: int volume = 1;
74: WindowInfo RootWindowInfo;
75: Bitmap IconBitmap;
76: Pixmap IconPixmap;
77: XEvent inputevent;
78: int width, height;
79: unsigned long code;
80: int nflash = 3;
81: struct timeval delaytime = {0, 5*micro2centi};
82: int quiet = NO;
83: short *icon_bits;
84: int icon_width, icon_height;
85:
86: char **actionvector[256]; /* command table */
87: char actionfound[256]; /* see flags below */
88: #define ACTION_NEW ((char) 0)
89: #define ACTION_FOUND ((char) 1)
90: #define ACTION_NOT_FOUND ((char) 2)
91:
92: char *yes[] = {"y", "yes", "YES", "on", "ON", "On",
93: "t", "true", "TRUE", "True", (char *) NULL};
94:
95: char *small[] = {"s", "S", "small", "SMALL", "Small", "sm", "SM", "Sm",
96: (char *) NULL};
97:
98: int IsMemberOf (list, string)
99: register char *list[];
100: register char *string;
101: {
102: for (; *list; list++) {
103: if (streq (string, *list)) return (YES);
104: }
105: return (NO);
106: }
107:
108: reapchild ()
109: {
110: union wait status;
111:
112: while (wait3 (&status, WNOHANG, (struct rusage *) 0) > 0) ;
113: return;
114: }
115:
116: static void Error (msg, arg)
117: char *msg, *arg;
118: {
119: fprintf (stderr, "%s: error with %s", msg);
120: if (arg != (char *) NULL && *arg != '\0')
121: fprintf (stderr, ": %s\n", arg);
122: else
123: fprintf (stderr, "\n");
124: exit (1);
125: }
126:
127: static void Usage (msg)
128: char *msg;
129: {
130: fprintf (stderr, "%s: error with \"%s\". Usage is\n",
131: ProgramName, msg);
132: fprintf (stderr, "\n\t\t%s [-flags] [=WxH+X+Y] [host:displaynum]\n\n",
133: ProgramName);
134: fprintf (stderr, "where -flags are:\n");
135: fprintf (stderr, "\t-fg color Foreground color.\n");
136: fprintf (stderr, "\t-bg color Background color.\n");
137: fprintf (stderr, "\t-bd color Border color.\n");
138: fprintf (stderr, "\t-bw[idth]n Border width in pixels.\n");
139: fprintf (stderr, "\t-v[olume] n Bell volume.\n");
140: fprintf (stderr, "\t-fl[ash] n Number of times to flash icon.\n");
141: fprintf (stderr, "\t-d[elay] n 1/10ths of a second flashes.\n");
142: fprintf (stderr, "\t-r[everse] Reverse video.\n");
143: fprintf (stderr, "\t-q[uiet] Don\'t feep on errors.\n");
144: fprintf (stderr, "\t-s[mall] Use a small icon instead of a big one.\n");
145: fprintf (stderr, "\n");
146: exit (1);
147: }
148:
149: quit ()
150: {
151: XUnmapWindow (ShellWindow);
152: XCloseDisplay (dpy);
153: exit (0);
154: }
155:
156: main (argc, argv)
157: int argc;
158: char *argv[];
159: {
160: register int i;
161: register char *cp;
162: char *fgname, *bgname, *bdname;
163: int reverse;
164: char *displayname;
165: Color colorstruct;
166: int c;
167: char cbuf[2];
168: int xoff, yoff, xsign, ysign;
169:
170: (void) signal (SIGINT, quit);
171: (void) signal (SIGHUP, quit);
172: (void) signal (SIGCHLD, reapchild);
173:
174: setlinebuf (stderr);
175:
176: /* set program name for errors */
177: ProgramName = argv[0];
178: cp = rindex (ProgramName, '/');
179: if (cp) ProgramName = ++cp; /* strip off directory name */
180:
181: /* Initialize variables */
182: fgname = bgname = bdname = (char *) NULL;
183: reverse = NO;
184: displayname = (char *) NULL;
185: bzero (actionfound, sizeof (actionfound));
186: icon_bits = largescallopshell_bits;
187: width = -1;
188: height = -1;
189: icon_width = largescallopshell_width;
190: icon_height = largescallopshell_height;
191:
192: /* read in defaults from .Xdefaults */
193:
194: fgname = XGetDefault (ProgramName, "Foreground");
195:
196: bgname = XGetDefault (ProgramName, "Background");
197:
198: bdname = XGetDefault (ProgramName, "Border");
199:
200: cp = XGetDefault (ProgramName, "BorderWidth");
201: if (cp) bw = atoi (cp);
202:
203: cp = XGetDefault (ProgramName, "Volume");
204: if (cp) volume = atoi (cp);
205:
206: cp = XGetDefault (ProgramName, "Flash");
207: if (cp) nflash = atoi (cp);
208:
209: cp = XGetDefault (ProgramName, "Delay");
210: if (cp) delaytime.tv_usec = atoi (cp) * micro2centi;
211:
212: if ((cp = XGetDefault (ProgramName, "ReverseVideo")) != NULL)
213: if (IsMemberOf (yes, cp)) reverse = YES;
214:
215: if ((cp = XGetDefault (ProgramName, "Quiet")) != NULL)
216: if (IsMemberOf (yes, cp)) quiet = YES;
217:
218: if ((cp = XGetDefault (ProgramName, "IconSize")) != NULL) {
219: if (IsMemberOf(small, cp)) {
220: icon_bits = scallopshell_bits;
221: icon_width = scallopshell_width;
222: icon_height = scallopshell_height;
223: }
224: }
225:
226: cp = XGetDefault (ProgramName, "WindowGeometry");
227: if (cp) {
228: if (!XParse_Window_Geometry (cp, &width, &height,
229: &xsign, &xoff, &ysign, &yoff)) Usage ("default =WxH+XOFF+YOFF");
230: }
231:
232: /* read command arguments */
233: argv++; /* advance past command name */
234: for (; *argv; argv++) { /* iterate over arguments */
235: if (**argv == '-') {
236: if (isopt ("-fg")) {
237: if (hasarg) {
238: fgname = *++argv;
239: } else Usage ("-fg foreground");
240: } else
241: if (isopt ("-bg")) {
242: if (hasarg) {
243: bgname = *++argv;
244: } else Usage ("-bg background");
245: } else
246: if (isopt ("-bd")) {
247: if (hasarg) {
248: bdname = *++argv;
249: } else Usage ("-bd border color");
250: } else
251: if (isopt ("-bwidth")) {
252: if (hasarg) {
253: bw = atoi (*++argv);
254: } else Usage ("-bwidth borderwidth");
255: } else
256: if (isopt ("-volume")) {
257: if (hasarg) {
258: volume = atoi (*++argv);
259: } else Usage ("-volume volume");
260: } else
261: if (isopt ("-flash")) {
262: if (hasarg) {
263: nflash = atoi (*++argv);
264: } else Usage ("-flash n");
265: } else
266: if (isopt ("-delay")) {
267: if (hasarg) {
268: delaytime.tv_usec = atoi (*++argv) * micro2centi;
269: } else Usage ("-delay n");
270: } else
271: if (isopt ("-reverse")) {
272: reverse = YES;
273: } else
274: if (isopt ("-quiet")) {
275: quiet = YES;
276: } else
277: if (isopt ("-small")) {
278: icon_bits = scallopshell_bits;
279: icon_width = scallopshell_width;
280: icon_height = scallopshell_height;
281: } else
282: Usage ("-unknown flag"); /* end if command line options */
283: } else if (**argv == '=') {
284: if (!XParse_Window_Geometry (*argv, &width, &height,
285: &xsign, &xoff, &ysign, &yoff)) Usage ("=WxH+XOFF+YOFF");
286: } else
287: displayname = *argv;
288: } /*end for*/
289:
290:
291: if (width == -1) width = icon_width;
292: if (height == -1) height = icon_height;
293:
294: /* okay, now set things up */
295: dpy = XOpenDisplay (displayname);
296: if (!dpy) {
297: fprintf(stderr, "%s: Can't open display '%s'\n",
298: ProgramName, XDisplayName(displayname));
299: exit(1);
300: }
301:
302: if (!XQueryWindow (RootWindow, &RootWindowInfo))
303: Error ("query root", "");
304:
305: if (xsign < 0) xoff = RootWindowInfo.width - xoff - width - 2*bw;
306: if (ysign < 0) yoff = RootWindowInfo.height - yoff - height - 2*bw;
307:
308: /* set the colors for the various parts */
309:
310: #define setcolor(colorname,colornum) \
311: if (colorname && DisplayCells() > 2 && \
312: XParseColor(colorname, &colorstruct) && \
313: XGetHardwareColor(&colorstruct)) { \
314: colornum = colorstruct.pixel; \
315: reverse = NO; \
316: }
317:
318: setcolor (fgname, fg);
319: setcolor (bgname, bg);
320: setcolor (bdname, bd);
321:
322: #undef setcolor
323:
324: if (reverse) {
325: i = fg;
326: fg = bg;
327: bg = i;
328: }
329: /* now, make up the icon pixmap */
330:
331: IconBitmap = XStoreBitmap (icon_width, icon_height, icon_bits);
332: if (!IconBitmap) Error ("storing icon bitmap", "");
333:
334: IconPixmap = XMakePixmap (IconBitmap, fg, bg);
335: if (!IconPixmap) Error ("storing icon pixmap", "");
336:
337:
338: /* make the window */
339:
340: ShellWindow = XCreateWindow (RootWindow, xoff, yoff, width, height,
341: bw, XMakeTile(bd), XMakeTile(bg));
342: if (!ShellWindow) Error ("creating shell window", "");
343:
344: /* and store away the program name in the window */
345:
346: XStoreName (ShellWindow, ProgramName);
347:
348: /* select the window events */
349:
350: XSelectInput (ShellWindow, KeyPressed | ButtonPressed | ExposeWindow);
351:
352: /* and map it, this should generate an Expose event */
353: XMapWindow (ShellWindow);
354:
355: while (1) { /* loop forever */
356: XNextEvent (&inputevent);
357: code = ((XKeyOrButtonEvent *) &inputevent)->detail;
358: switch ((int) inputevent.type) {
359: case ExposeWindow: /* repaint the icon */
360: if (inputevent.window == ShellWindow)
361: XPixmapPut (ShellWindow, 0, 0, 0, 0,
362: icon_width, icon_height,
363: IconPixmap, GXcopy, AllPlanes);
364: break;
365:
366: case KeyPressed:
367: c = StdMap [code & ValueMask] [KeyState(code)];
368: switch (c) {
369: case -1:
370: feep ();
371: break;
372: case SHFT:
373: perform ("SHIFT");
374: break;
375: case CNTL:
376: perform ("CONTROL");
377: break;
378: case LOCK:
379: perform ("LOCK");
380: break;
381: case SYMBOL:
382: perform ("SYMBOL");
383: break;
384: case KEYPAD:
385: switch (code & ValueMask) {
386: case KC_KEYPAD_0:
387: perform ("KEYPAD0");
388: break;
389: case KC_KEYPAD_PERIOD:
390: perform ("KEYPAD.");
391: break;
392: case KC_ENTER:
393: perform ("ENTER");
394: break;
395: case KC_KEYPAD_1:
396: perform ("KEYPAD1");
397: break;
398: case KC_KEYPAD_2:
399: perform ("KEYPAD2");
400: break;
401: case KC_KEYPAD_3:
402: perform ("KEYPAD3");
403: break;
404: case KC_KEYPAD_4:
405: perform ("KEYPAD4");
406: break;
407: case KC_KEYPAD_5:
408: perform ("KEYPAD5");
409: break;
410: case KC_KEYPAD_6:
411: perform ("KEYPAD6");
412: break;
413: case KC_KEYPAD_COMMA:
414: perform ("KEYPAD,");
415: break;
416: case KC_KEYPAD_7:
417: perform ("KEYPAD7");
418: break;
419: case KC_KEYPAD_8:
420: perform ("KEYPAD8");
421: break;
422: case KC_KEYPAD_9:
423: perform ("KEYPAD9");
424: break;
425: case KC_KEYPAD_MINUS:
426: perform ("KEYPAD-");
427: break;
428: default:
429: feep ();
430: break;
431: } /*end switch*/
432: break;
433: case CURSOR:
434: switch (code & ValueMask) {
435: case KC_CURSOR_LEFT:
436: perform ("LEFTARROW");
437: break;
438: case KC_CURSOR_RIGHT:
439: perform ("RIGHTARROW");
440: break;
441: case KC_CURSOR_DOWN:
442: perform ("DOWNARROW");
443: break;
444: case KC_CURSOR_UP:
445: perform ("UPARROW");
446: break;
447: default:
448: feep ();
449: break;
450: }
451: break;
452: case PFX:
453: switch (code & ValueMask) {
454: case KC_PF1:
455: perform ("PF1");
456: case KC_PF2:
457: perform ("PF2");
458: case KC_PF3:
459: perform ("PF3");
460: case KC_PF4:
461: perform ("PF4");
462: default:
463: feep ();
464: break;
465: }
466: break;
467: case FUNC1:
468: perform ("FUNC1");
469: break;
470: case FUNC2:
471: perform ("FUNC2");
472: break;
473: case FUNC3:
474: perform ("FUNC3");
475: break;
476: case FUNC4:
477: perform ("FUNC4");
478: break;
479: case FUNC5:
480: perform ("FUNC5");
481: break;
482: case FUNC6:
483: perform ("FUNC6");
484: break;
485: case FUNC7:
486: perform ("FUNC7");
487: break;
488: case FUNC8:
489: perform ("FUNC8");
490: break;
491: case FUNC9:
492: perform ("FUNC9");
493: break;
494: case FUNC10:
495: perform ("FUNC10");
496: break;
497: case FUNC11:
498: perform ("FUNC11");
499: break;
500: case FUNC12:
501: perform ("FUNC12");
502: break;
503: case FUNC13:
504: perform ("FUNC13");
505: break;
506: case FUNC14:
507: perform ("FUNC14");
508: break;
509: case FUNC15:
510: perform ("FUNC15");
511: break;
512: case FUNC16:
513: perform ("FUNC16");
514: break;
515: case FUNC17:
516: perform ("FUNC17");
517: break;
518: case FUNC18:
519: perform ("FUNC18");
520: break;
521: case FUNC19:
522: perform ("FUNC19");
523: break;
524: case FUNC20:
525: perform ("FUNC20");
526: break;
527: case E1:
528: perform ("E1");
529: break;
530: case E2:
531: perform ("E2");
532: break;
533: case E3:
534: perform ("E3");
535: break;
536: case E4:
537: perform ("E4");
538: break;
539: case E5:
540: perform ("E5");
541: break;
542: case E6:
543: perform ("E6");
544: break;
545: default: /* must be ascii */
546: cbuf[0] = (char) c;
547: cbuf[1] = '\0';
548: perform (cbuf);
549: break;
550: } /*end switch on keycode*/
551: break;
552:
553: case ButtonPressed:
554: switch (code & ValueMask) {
555: case LeftButton:
556: perform ("LEFTBUTTON");
557: break;
558: case MiddleButton:
559: perform ("MIDDLEBUTTON");
560: break;
561: case RightButton:
562: perform ("RIGHTBUTTON");
563: break;
564: default:
565: feep ();
566: break;
567: }
568: break;
569:
570: default:
571: feep ();
572: break;
573: } /*end switch on event type*/
574: } /*end while forever getting input events*/
575: } /*end main*/
576:
577: /****************************************************************************
578: * perform - This routine looks in its table to see if it already has a key
579: * code, else it does an XGetDefault of the keyname.
580: */
581:
582: static perform (keyname)
583: char *keyname;
584: {
585: char buf[32];
586: register char *cp;
587:
588: if (actionfound [code] == ACTION_NEW) {
589: (void) strcpy (buf, "action.");
590: (void) strcat (buf, keyname);
591: cp = XGetDefault (ProgramName, buf);
592: if (!cp)
593: actionfound [code] = ACTION_NOT_FOUND;
594: else { /* else we have to parse the string */
595: parseaction (cp);
596: } /*end if we have an action*/
597: } /*end if we needed to look up an action*/
598:
599: if (actionfound [code] == ACTION_FOUND) {
600: if (vfork() == 0) /* in child, start program */
601: execvp (actionvector [code] [0], actionvector [code]);
602: else /* in parent, flash icon */
603: flash ();
604: } else {
605: if (!quiet) feep ();
606: }
607:
608: return;
609: }
610:
611:
612: static parseaction (actionstring)
613: char *actionstring;
614: {
615: register char *cp;
616: register int wc = 0; /* word count */
617: register int inword;
618: register char **actionlist;
619: register int i;
620:
621: inword = 0;
622: for (cp = actionstring; *cp; cp++) { /* iterate over string */
623: if (isspace(*cp)) {
624: if (inword) inword = 0; /* no longer in a word */
625: } else {
626: if (!inword) { /* weren't in word */
627: inword = 1; /* but now we are */
628: wc++; /* so increment counter */
629: }
630: }
631: }
632: /* wc now contains the number of separate words */
633: actionlist = (char **) malloc ((unsigned)sizeof (char *) * (wc + 1));
634: if (!actionlist)
635: Error ("allocating memory for command list", actionstring);
636:
637: i = 0;
638: inword = 0;
639: for (cp = actionstring; *cp; cp++) {
640: if (isspace(*cp)) {
641: if (inword) { /* were in a word */
642: inword = 0; /* but now we're not */
643: }
644: *cp = '\0'; /* and null out space */
645: } else {
646: if (!inword) { /* weren't in a word */
647: inword = 1; /* but now we are */
648: actionlist [i++] = cp; /* store pointer to start of word */
649: }
650: }
651: }
652: actionlist [wc] = (char *) NULL; /* execv wants this */
653:
654: actionfound [code] = ACTION_FOUND;
655: actionvector [code] = actionlist; /* store the action */
656: return;
657: }
658:
659:
660: /****************************************************************************
661: * feep - is designed to alert the user that something went wrong. It could
662: * put up a dialog box if it were smart....
663: */
664:
665: static feep ()
666: {
667: XFeep (volume);
668: XFlush ();
669: return;
670: }
671:
672:
673: /****************************************************************************
674: * flash - this just flashes the shell box a couple of times
675: */
676:
677: flash ()
678: {
679: register int i, j;
680:
681: for (i = 0; i < nflash; i++) {
682: for (j = 0; j < 2; j++) {
683: XPixFill (ShellWindow, 0, 0, width, height, BlackPixel,
684: (Bitmap) 0, GXinvert, AllPlanes);
685: XFlush ();
686: (void) select (0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &delaytime);
687: }
688: }
689: return;
690: }
691:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.