|
|
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.6 86/02/01 16:19:36 tony 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: Error ("opening display", "");
298:
299: if (!XQueryWindow (RootWindow, &RootWindowInfo))
300: Error ("query root", "");
301:
302: if (xsign < 0) xoff = RootWindowInfo.width - xoff - width - 2*bw;
303: if (ysign < 0) yoff = RootWindowInfo.height - yoff - height - 2*bw;
304:
305: /* set the colors for the various parts */
306:
307: #define setcolor(colorname,colornum) \
308: if (colorname && DisplayCells() > 2 && \
309: XParseColor(colorname, &colorstruct) && \
310: XGetHardwareColor(&colorstruct)) { \
311: colornum = colorstruct.pixel; \
312: reverse = NO; \
313: }
314:
315: setcolor (fgname, fg);
316: setcolor (bgname, bg);
317: setcolor (bdname, bd);
318:
319: #undef setcolor
320:
321: if (reverse) {
322: i = fg;
323: fg = bg;
324: bg = i;
325: }
326: /* now, make up the icon pixmap */
327:
328: IconBitmap = XStoreBitmap (icon_width, icon_height, icon_bits);
329: if (!IconBitmap) Error ("storing icon bitmap", "");
330:
331: IconPixmap = XMakePixmap (IconBitmap, fg, bg);
332: if (!IconPixmap) Error ("storing icon pixmap", "");
333:
334:
335: /* make the window */
336:
337: ShellWindow = XCreateWindow (RootWindow, xoff, yoff, width, height,
338: bw, XMakeTile(bd), XMakeTile(bg));
339: if (!ShellWindow) Error ("creating shell window", "");
340:
341: /* and store away the program name in the window */
342:
343: XStoreName (ShellWindow, ProgramName);
344:
345: /* select the window events */
346:
347: XSelectInput (ShellWindow, KeyPressed | ButtonPressed | ExposeWindow);
348:
349: /* and map it, this should generate an Expose event */
350: XMapWindow (ShellWindow);
351:
352: while (1) { /* loop forever */
353: XNextEvent (&inputevent);
354: code = ((XKeyOrButtonEvent *) &inputevent)->detail;
355: switch ((int) inputevent.type) {
356: case ExposeWindow: /* repaint the icon */
357: if (inputevent.window == ShellWindow)
358: XPixmapPut (ShellWindow, 0, 0, 0, 0,
359: icon_width, icon_height,
360: IconPixmap, GXcopy, AllPlanes);
361: break;
362:
363: case KeyPressed:
364: c = StdMap [code & ValueMask] [KeyState(code)];
365: switch (c) {
366: case -1:
367: feep ();
368: break;
369: case SHFT:
370: perform ("SHIFT");
371: break;
372: case CNTL:
373: perform ("CONTROL");
374: break;
375: case LOCK:
376: perform ("LOCK");
377: break;
378: case SYMBOL:
379: perform ("SYMBOL");
380: break;
381: case KEYPAD:
382: switch (code & ValueMask) {
383: case KC_KEYPAD_0:
384: perform ("KEYPAD0");
385: break;
386: case KC_KEYPAD_PERIOD:
387: perform ("KEYPAD.");
388: break;
389: case KC_ENTER:
390: perform ("ENTER");
391: break;
392: case KC_KEYPAD_1:
393: perform ("KEYPAD1");
394: break;
395: case KC_KEYPAD_2:
396: perform ("KEYPAD2");
397: break;
398: case KC_KEYPAD_3:
399: perform ("KEYPAD3");
400: break;
401: case KC_KEYPAD_4:
402: perform ("KEYPAD4");
403: break;
404: case KC_KEYPAD_5:
405: perform ("KEYPAD5");
406: break;
407: case KC_KEYPAD_6:
408: perform ("KEYPAD6");
409: break;
410: case KC_KEYPAD_COMMA:
411: perform ("KEYPAD,");
412: break;
413: case KC_KEYPAD_7:
414: perform ("KEYPAD7");
415: break;
416: case KC_KEYPAD_8:
417: perform ("KEYPAD8");
418: break;
419: case KC_KEYPAD_9:
420: perform ("KEYPAD9");
421: break;
422: case KC_KEYPAD_MINUS:
423: perform ("KEYPAD-");
424: break;
425: default:
426: feep ();
427: break;
428: } /*end switch*/
429: break;
430: case CURSOR:
431: switch (code & ValueMask) {
432: case KC_CURSOR_LEFT:
433: perform ("LEFTARROW");
434: break;
435: case KC_CURSOR_RIGHT:
436: perform ("RIGHTARROW");
437: break;
438: case KC_CURSOR_DOWN:
439: perform ("DOWNARROW");
440: break;
441: case KC_CURSOR_UP:
442: perform ("UPARROW");
443: break;
444: default:
445: feep ();
446: break;
447: }
448: break;
449: case PFX:
450: switch (code & ValueMask) {
451: case KC_PF1:
452: perform ("PF1");
453: case KC_PF2:
454: perform ("PF2");
455: case KC_PF3:
456: perform ("PF3");
457: case KC_PF4:
458: perform ("PF4");
459: default:
460: feep ();
461: break;
462: }
463: break;
464: case FUNC1:
465: perform ("FUNC1");
466: break;
467: case FUNC2:
468: perform ("FUNC2");
469: break;
470: case FUNC3:
471: perform ("FUNC3");
472: break;
473: case FUNC4:
474: perform ("FUNC4");
475: break;
476: case FUNC5:
477: perform ("FUNC5");
478: break;
479: case FUNC6:
480: perform ("FUNC6");
481: break;
482: case FUNC7:
483: perform ("FUNC7");
484: break;
485: case FUNC8:
486: perform ("FUNC8");
487: break;
488: case FUNC9:
489: perform ("FUNC9");
490: break;
491: case FUNC10:
492: perform ("FUNC10");
493: break;
494: case FUNC11:
495: perform ("FUNC11");
496: break;
497: case FUNC12:
498: perform ("FUNC12");
499: break;
500: case FUNC13:
501: perform ("FUNC13");
502: break;
503: case FUNC14:
504: perform ("FUNC14");
505: break;
506: case FUNC15:
507: perform ("FUNC15");
508: break;
509: case FUNC16:
510: perform ("FUNC16");
511: break;
512: case FUNC17:
513: perform ("FUNC17");
514: break;
515: case FUNC18:
516: perform ("FUNC18");
517: break;
518: case FUNC19:
519: perform ("FUNC19");
520: break;
521: case FUNC20:
522: perform ("FUNC20");
523: break;
524: case E1:
525: perform ("E1");
526: break;
527: case E2:
528: perform ("E2");
529: break;
530: case E3:
531: perform ("E3");
532: break;
533: case E4:
534: perform ("E4");
535: break;
536: case E5:
537: perform ("E5");
538: break;
539: case E6:
540: perform ("E6");
541: break;
542: default: /* must be ascii */
543: cbuf[0] = (char) c;
544: cbuf[1] = '\0';
545: perform (cbuf);
546: break;
547: } /*end switch on keycode*/
548: break;
549:
550: case ButtonPressed:
551: switch (code & ValueMask) {
552: case LeftButton:
553: perform ("LEFTBUTTON");
554: break;
555: case MiddleButton:
556: perform ("MIDDLEBUTTON");
557: break;
558: case RightButton:
559: perform ("RIGHTBUTTON");
560: break;
561: default:
562: feep ();
563: break;
564: }
565: break;
566:
567: default:
568: feep ();
569: break;
570: } /*end switch on event type*/
571: } /*end while forever getting input events*/
572: } /*end main*/
573:
574: /****************************************************************************
575: * perform - This routine looks in its table to see if it already has a key
576: * code, else it does an XGetDefault of the keyname.
577: */
578:
579: static perform (keyname)
580: char *keyname;
581: {
582: char buf[32];
583: register char *cp;
584:
585: if (actionfound [code] == ACTION_NEW) {
586: (void) strcpy (buf, "action.");
587: (void) strcat (buf, keyname);
588: cp = XGetDefault (ProgramName, buf);
589: if (!cp)
590: actionfound [code] = ACTION_NOT_FOUND;
591: else { /* else we have to parse the string */
592: parseaction (cp);
593: } /*end if we have an action*/
594: } /*end if we needed to look up an action*/
595:
596: if (actionfound [code] == ACTION_FOUND) {
597: if (vfork() == 0) /* in child, start program */
598: execvp (actionvector [code] [0], actionvector [code]);
599: else /* in parent, flash icon */
600: flash ();
601: } else {
602: if (!quiet) feep ();
603: }
604:
605: return;
606: }
607:
608:
609: static parseaction (actionstring)
610: char *actionstring;
611: {
612: register char *cp;
613: register int wc = 0; /* word count */
614: register int inword;
615: register char **actionlist;
616: register int i;
617:
618: inword = 0;
619: for (cp = actionstring; *cp; cp++) { /* iterate over string */
620: if (isspace(*cp)) {
621: if (inword) inword = 0; /* no longer in a word */
622: } else {
623: if (!inword) { /* weren't in word */
624: inword = 1; /* but now we are */
625: wc++; /* so increment counter */
626: }
627: }
628: }
629: /* wc now contains the number of separate words */
630: actionlist = (char **) malloc ((unsigned)sizeof (char *) * (wc + 1));
631: if (!actionlist)
632: Error ("allocating memory for command list", actionstring);
633:
634: i = 0;
635: inword = 0;
636: for (cp = actionstring; *cp; cp++) {
637: if (isspace(*cp)) {
638: if (inword) { /* were in a word */
639: inword = 0; /* but now we're not */
640: }
641: *cp = '\0'; /* and null out space */
642: } else {
643: if (!inword) { /* weren't in a word */
644: inword = 1; /* but now we are */
645: actionlist [i++] = cp; /* store pointer to start of word */
646: }
647: }
648: }
649: actionlist [wc] = (char *) NULL; /* execv wants this */
650:
651: actionfound [code] = ACTION_FOUND;
652: actionvector [code] = actionlist; /* store the action */
653: return;
654: }
655:
656:
657: /****************************************************************************
658: * feep - is designed to alert the user that something went wrong. It could
659: * put up a dialog box if it were smart....
660: */
661:
662: static feep ()
663: {
664: XFeep (volume);
665: XFlush ();
666: return;
667: }
668:
669:
670: /****************************************************************************
671: * flash - this just flashes the shell box a couple of times
672: */
673:
674: flash ()
675: {
676: register int i, j;
677:
678: for (i = 0; i < nflash; i++) {
679: for (j = 0; j < 2; j++) {
680: XPixFill (ShellWindow, 0, 0, width, height, BlackPixel,
681: (Bitmap) 0, GXinvert, AllPlanes);
682: XFlush ();
683: (void) select (0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &delaytime);
684: }
685: }
686: return;
687: }
688:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.