9menu-1.9/9menu.1000644 001750 001750 00000011662 12545113032 014725 0ustar00epsilonepsilon000000 000000 .TH 9MENU 1 "June 25 2015" .SH NAME 9menu \- create a menu to run commands .SH SYNOPSIS .B 9menu [ .BI \-bg " background-color" ] [ .BI \-display " displayname" ] [ .BI \-file " name" ] [ .BI \-fg " foreground-color" ] [ .BI \-font " fname" ] [ .BI \-geometry " geom" ] [ .B \-iconic ] [ .BI \-label " name" ] [ .B \-path ] [ .B \-popdown ] [ .B \-popup ] [ .BI \-shell " prog" ] [ .B \-teleport ] [ .B \-version ] [ .B \-warp ] .IR menuitem [: command ] \&... .SH DESCRIPTION .I 9menu is a simple program that accepts a list of menu item and command pairs on the command line. It creates a window that consists of nothing but a menu. When a particular item is selected, the corresponding command is executed. .PP Either .B Button1 or .B Button3 may be used to select an item. Alternatively, the UP-ARROW and DOWN-ARROW cursor keys may be used to highlight different items, with ENTER used to select the highlighted item. .PP Menu items and commands are separated by a colon. The colon and command are optional. If they are missing, then the menu item is assumed to be a command that can be executed directly. .PP A menu item consisting of the word .B exit causes .I 9menu to exit when it is selected. Otherwise, to stop .I 9menu , delete it using the window manager. The .B exit menu item can be anywhere in the list, although by convention it is last. If a command is supplied along with the .B exit item, that command is executed before .I 9menu exits. .PP If a menu item's command starts with the word .BR exec , .I 9menu ceases operating after launching it. .PP .I 9menu accepts the following command line options, listed alphabetically: .TP .BI \-bg " background-color" Set the background color to .IR background-color . By default, the background color is white. .TP .BI \-display " displayname" Use the X display .IR displayname , instead of the default display. .TP .BI \-file " filename" Read items to display from .IR filename , in addition to any other command line arguments. This is intended for use with .B #! in scripts. A .I filename of .B - causes .I 9menu to read items from standard input. .TP .BI \-fg " foreground-color" Set the foreground color to .IR foreground-color . By default, the foreground color is black. .TP .BI \-font " fname" Use the font .IR fname , instead of one of the default fonts built into .IR 9wm . .TP .BI \-geometry " geom" Use .I geom (a geometry in standard X format) as the geometry of the menu. This is most useful for specifying the initial location of the menu. Note that .I 9menu overrides the size part of the geometry specification. The window is always just large enough to hold the menu. .TP .B \-iconic Start up in the iconified state. .TP .BI \-label " name" Change both the window and icon labels of the window to .IR name . The default label is the last component of the path used to run .IR 9menu , typically, .BR 9menu . .TP .B \-path Append the current directory to the command search path. .TP .B \-popdown Once an item is selected, the menu window automatically iconifies itself. .TP .B \-popup Act like a pop-up menu. Once a menu item is selected, .I 9menu exits. This option overrides .BR \-popdown . .TP .BI \-shell " prog" Use .I prog as the shell to run commands, instead of .BR /bin/sh . A popular alternative shell is .IR rc (1). If the shell cannot be executed, .I 9menu then .I silently falls back to using .BR /bin/sh . .TP .B \-teleport Move the menu to where the mouse is when the menu is uniconified. This option is particularly useful when combined with .BR \-popdown . .TP .B \-version This option prints the version of .I 9menu on the standard output, and then exits with an exit value of zero. .TP .B \-warp Warp the mouse to the menu when the menu is uniconified. After the selection is made, restore the mouse to where it was. This option is particularly useful when combined with .BR \-popdown . .SH EXAMPLES .ft B .nf 9menu \-label Remotes xterm 'acme:rsh acme xterm' 'herman:rsh herman 9term' & .sp 9menu \-label 'X progs' ghostview xdvi xeyes xneko exit & .ft .fi .SH SEE ALSO .IR sam (1), .IR 9term (1), .IR 9wm (1), .IR rc (1). .PP .IR "The Plan 9 Programmer's Manual" . .SH VERSION This man page documents .I 9menu version 1.9. .PP Source code is available from .BR ftp://ftp.freefriends.org/arnold/Source/9menu.shar.gz . .PP The code with full history is also available via Git from .BR http://github.com/arnoldrobbins/9menu . .SH BUGS This program has grown to have too many options. .SH AUTHORS The initial idea for this program was by Arnold Robbins, after having worked with John Mackin's GWM Blit emulation. Matty Farrow wrote a version using libXg, from which some ideas were borrowed. This code was written by David Hogan and Arnold Robbins. Rich Salz motivated the .B \-shell option. Christopher Platt motivated the .B \-teleport option. John O'Donnell supplied the basic code for the .B \-fg and .B \-bg options. Peter Seebach provided the base code for the .B \-file and .B \-path options. Matthias Bauer made it work with the keyboard. 9menu-1.9/Imakefile000644 001750 001750 00000000331 12545113032 015406 0ustar00epsilonepsilon000000 000000 INCLUDES = -I$(TOP) DEPLIBS = $(DEPXLIBONLY) LOCAL_LIBRARIES = $(XLIBONLY) DEFINES = -DSHAPE #-DDEBUG -DDEBUG_EV SRCS = 9menu.c OBJS = 9menu.o ComplexProgramTarget(9menu) 9menu-1.9/Makefile.noimake000644 001750 001750 00000000265 12545113032 016665 0ustar00epsilonepsilon000000 000000 # Makefile for 9menu. # # Edit to taste # # Arnold Robbins # arnold@skeeve.atl.ga.us CC = gcc CFLAGS = -g -O LIBS = -lX11 9menu: 9menu.c $(CC) $(CFLAGS) 9menu.c $(LIBS) -o 9menu 9menu-1.9/000755 001750 001750 00000000000 12545115157 013612 5ustar00epsilonepsilon000000 000000 9menu-1.9/README000644 001750 001750 00000002615 12545113032 014464 0ustar00epsilonepsilon000000 000000 Thu Mar 19 23:51:38 IST 2015 This is 9menu, a simple program that allows you to create X menus from the shell, where each menu item will run a command. 9menu is intended for use with 9wm, but can be used with any other window manager. The idea of a command line menu generator is from xmenu, but xmenu was exclusively a pop-up menu, not what I wanted. The files are: README --- this file 9menu.1 --- man page for 9menu 9menu.c --- source code Imakefile --- a contributed Imakefile, from Bengt Kleberg Makefile.noimake --- a simple makefile. Licence ======= 9menu is free software, and is Copyright (c) 1994 by David Hogan and Arnold Robbins. Permission is granted to all sentient beings to use this software, to make copies of it, and to distribute those copies, provided that: (1) the copyright and licence notices are left intact (2) the recipients are aware that it is free software (3) any unapproved changes in functionality are either (i) only distributed as patches or (ii) distributed as a new program which is not called 9menu and whose documentation gives credit where it is due (4) the authors are not held responsible for any defects or shortcomings in the software, or damages caused by it. There is no warranty for this software. Have a nice day. -- Arnold Robbins arnold@skeeve.com 9menu-1.9/9menu.c000644 001750 001750 00000047222 12545113032 015010 0ustar00epsilonepsilon000000 000000 /* * 9menu.c * * This program puts up a window that is just a menu, and executes * commands that correspond to the items selected. * * Initial idea: Arnold Robbins * Version using libXg: Matty Farrow (some ideas borrowed) * This code by: David Hogan and Arnold Robbins * * Copyright (c), Arnold Robbins and David Hogan * * Arnold Robbins * arnold@skeeve.com * October, 1994 * * Code added to cause pop-up (unIconify) to move menu to mouse. * Christopher Platt * platt@coos.dartmouth.edu * May, 1995 * * Said code moved to -teleport option, and -warp option added. * Arnold Robbins * June, 1995 * * Code added to allow -fg and -bg colors. * John M. O'Donnell * odonnell@stpaul.lampf.lanl.gov * April, 1997 * * Code added for -file and -path options. * Peter Seebach * seebs@plethora.net * October, 2001 * * Code added to allow up and down arrow keys to go up * and down menu and RETURN to select an item. * Matthias Bauer * bauerm@immd1.informatik.uni-erlangen.de * June, 2003 * * spawn() changed to do exec directly if -popup, based on * suggestion from * Andrew Stribblehill * a.d.stribblehill@durham.ac.uk * June, 2004 * * Allow "-" to mean read info from stdin. * suggestion from * Peter Bailey, by way of * Andrew Stribblehill * a.d.stribblehill@durham.ac.uk * August, 2005 * * Fix compile warnings (getcwd and getting a key sym). * Arnold Robbins * January, 2015. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include char version[] = "@(#) 9menu version 1.9"; Display *dpy; /* lovely X stuff */ int screen; Window root; Window menuwin; GC gc; unsigned long black; unsigned long white; char *fgcname = NULL; char *bgcname = NULL; Colormap defcmap; XColor color; XFontStruct *font; Atom wm_protocols; Atom wm_delete_window; int g_argc; /* for XSetWMProperties to use */ char **g_argv; int f_argc; /* for labels read from files */ char **f_argv; char *geometry = ""; int savex, savey; Window savewindow; char *fontlist[] = { /* default font list if no -font */ "pelm.latin1.9", "lucm.latin1.9", "blit", "9x15bold", "9x15", "lucidasanstypewriter-12", "fixed", NULL }; /* the 9menu icon, for garish window managers */ #define nine_menu_width 40 #define nine_menu_height 40 static unsigned char nine_menu_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x04, 0x00, 0x80, 0xe0, 0x01, 0x04, 0x00, 0x80, 0xe0, 0x00, 0xfc, 0xff, 0xff, 0xe0, 0x01, 0xfc, 0xff, 0xff, 0x20, 0x03, 0x04, 0x00, 0x80, 0x00, 0x06, 0x04, 0x00, 0x80, 0x00, 0x0c, 0xfc, 0xff, 0xff, 0x00, 0x08, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; /* Modify this to your liking */ #define CONFIG_MENU_UP_KEY XK_Up #define CONFIG_MENU_DOWN_KEY XK_Down #define CONFIG_MENU_SELECT_KEY XK_Return char *progname; /* my name */ char *displayname; /* X display */ char *fontname; /* font */ char *labelname; /* window and icon name */ char *filename; /* file to read options or labels from */ int popup; /* true if we're a popup window */ int popdown; /* autohide after running a command */ int iconic; /* start iconified */ int teleport; /* teleport the menu */ int warp; /* warp the mouse */ char **labels; /* list of labels and commands */ char **commands; int numitems; char *shell = "/bin/sh"; /* default shell */ extern void usage(), run_menu(), spawn(), ask_wm_for_delete(); extern void reap(), set_wm_hints(); extern void redraw(), teleportmenu(), warpmouse(), restoremouse(); extern void memory(); extern int args(); /* memory --- print the out of memory message and die */ void memory(char *s) { fprintf(stderr, "%s: couldn't allocate memory for %s\n", progname, s); exit(1); } /* args --- go through the argument list, set options */ int args(int argc, char **argv) { int i; if (argc == 0 || argv == NULL || argv[0] == '\0') return -1; for (i = 0; i < argc && argv[i] != NULL; i++) { if (strcmp(argv[i], "-display") == 0) { displayname = argv[i+1]; i++; } else if (strcmp(argv[i], "-file") == 0) { filename = argv[i+1]; i++; } else if (strcmp(argv[i], "-font") == 0) { fontname = argv[i+1]; i++; } else if (strcmp(argv[i], "-geometry") == 0) { geometry = argv[i+1]; i++; } else if (strcmp(argv[i], "-label") == 0) { labelname = argv[i+1]; i++; } else if (strcmp(argv[i], "-shell") == 0) { shell = argv[i+1]; i++; } else if (strcmp(argv[i], "-popup") == 0) popup++; else if (strcmp(argv[i], "-popdown") == 0) popdown++; else if (strcmp(argv[i], "-fg") == 0) fgcname = argv[++i]; else if (strcmp(argv[i], "-bg") == 0) bgcname = argv[++i]; else if (strcmp(argv[i], "-iconic") == 0) iconic++; else if (strcmp(argv[i], "-path") == 0) { char pathbuf[MAXPATHLEN]; char *s, *t; s = getenv("PATH"); if (s != NULL) { /* append current dir to PATH */ char *cp = getcwd(pathbuf, MAXPATHLEN); t = malloc(strlen(s) + strlen(pathbuf) + 7); sprintf(t, "PATH=%s:%s", pathbuf, s); putenv(t); } } else if (strcmp(argv[i], "-teleport") == 0) teleport++; else if (strcmp(argv[i], "-warp") == 0) warp++; else if (strcmp(argv[i], "-version") == 0) { printf("%s\n", version); exit(0); } else if (argv[i][0] == '-') usage(); else break; } return i; } /* main --- crack arguments, set up X stuff, run the main menu loop */ int main(int argc, char **argv) { int i, j; char *cp; XGCValues gv; unsigned long mask; int nlabels = 0; g_argc = argc; g_argv = argv; /* set default label name */ if ((cp = strrchr(argv[0], '/')) == NULL) labelname = argv[0]; else labelname = ++cp; ++argv; --argc; /* and program name for diagnostics */ progname = labelname; i = args(argc, argv); numitems = argc - i; if (numitems <= 0 && filename == NULL) usage(); if (filename) { /* Read options and labels from file */ char fbuf[1024]; FILE *fp; if (strcmp(filename, "-") == 0) { fp = stdin; } else { fp = fopen(filename, "r"); } if (fp == NULL) { fprintf(stderr, "%s: couldn't open '%s'\n", progname, filename); exit(1); } while (fgets(fbuf, sizeof fbuf, fp)) { char *s = fbuf; strtok(s, "\n"); if (s[0] == '-') { char *temp[3]; temp[0] = s; temp[1] = strchr(s, ' '); if (temp[1]) { *(temp[1]++) = '\0'; s = malloc(strlen(temp[1]) + 1); if (s == NULL) memory("temporary argument"); strcpy(s, temp[1]); temp[1] = s; } temp[2] = 0; args(temp[1] ? 2 : 1, temp); continue; } if (s[0] == '#') continue; /* allow - in menu items to be escaped */ if (s[0] == '\\') ++s; /* allocate space */ if (f_argc < nlabels + 1) { int k; char **temp = malloc(sizeof(char *) * (f_argc + 5)); if (temp == 0) memory("temporary item"); for (k = 0; k < nlabels; k++) temp[k] = f_argv[k]; free(f_argv); f_argv = temp; f_argc += 5; } f_argv[nlabels] = malloc(strlen(s) + 1); if (f_argv[nlabels] == NULL) memory("temporary text"); strcpy(f_argv[nlabels], s); ++nlabels; } } labels = (char **) malloc((numitems + nlabels) * sizeof(char *)); commands = (char **) malloc((numitems + nlabels) * sizeof(char *)); if (commands == NULL || labels == NULL) memory("command and label arrays"); for (j = 0; j < numitems; j++) { labels[j] = argv[i + j]; if ((cp = strchr(labels[j], ':')) != NULL) { *cp++ = '\0'; commands[j] = cp; } else commands[j] = labels[j]; } /* * Now we no longer need i (our offset into argv) so we recycle it, * while keeping the old value of j! */ for (i = 0; i < nlabels; i++) { labels[j] = f_argv[i]; if ((cp = strchr(labels[j], ':')) != NULL) { *cp++ = '\0'; commands[j] = cp; } else commands[j] = labels[j]; ++j; } /* And now we merge the totals */ numitems += nlabels; dpy = XOpenDisplay(displayname); if (dpy == NULL) { fprintf(stderr, "%s: cannot open display", progname); if (displayname != NULL) fprintf(stderr, " %s", displayname); fprintf(stderr, "\n"); exit(1); } screen = DefaultScreen(dpy); root = RootWindow(dpy, screen); /* * This used to be * black = BlackPixel(dpy, screen); * white = WhitePixel(dpy, screen); */ defcmap = DefaultColormap(dpy, screen); if (fgcname == NULL || XParseColor(dpy, defcmap, fgcname, &color) == 0 || XAllocColor(dpy, defcmap, &color) == 0) black = BlackPixel(dpy, screen); else black = color.pixel; if (bgcname == NULL || XParseColor(dpy, defcmap, bgcname, &color) == 0 || XAllocColor(dpy, defcmap, &color) == 0) white = WhitePixel(dpy, screen); else white = color.pixel; /* try user's font first */ if (fontname != NULL) { font = XLoadQueryFont(dpy, fontname); if (font == NULL) fprintf(stderr, "%s: warning: can't load font %s\n", progname, fontname); } /* if no user font, try one of our default fonts */ if (font == NULL) { for (i = 0; fontlist[i] != NULL; i++) { font = XLoadQueryFont(dpy, fontlist[i]); if (font != NULL) break; } } if (font == NULL) { fprintf(stderr, "%s: fatal: cannot load a font\n", progname); exit(1); } gv.foreground = black^white; gv.background = white; gv.font = font->fid; gv.function = GXxor; gv.line_width = 0; mask = GCForeground | GCBackground | GCFunction | GCFont | GCLineWidth; gc = XCreateGC(dpy, root, mask, &gv); signal(SIGCHLD, reap); run_menu(); XCloseDisplay(dpy); exit(0); } /* spawn --- run a command */ void spawn(char *com) { int pid; static char *sh_base = NULL; if (sh_base == NULL) { sh_base = strrchr(shell, '/'); if (sh_base != NULL) sh_base++; else sh_base = shell; } /* * Since -popup means run command and exit, just * fall straight into exec code. Thus only fork * if not popup. */ if (! popup) { if (strncmp(com, "exec ", 5) != 0) { pid = fork(); if (pid < 0) { fprintf(stderr, "%s: can't fork\n", progname); return; } else if (pid > 0) return; } else { com += 5; } } close(ConnectionNumber(dpy)); execl(shell, sh_base, "-c", com, NULL); execl("/bin/sh", "sh", "-c", com, NULL); _exit(1); } /* reap --- collect dead children */ void reap(int s) { (void) wait((int *) NULL); signal(s, reap); } /* usage --- print a usage message and die */ void usage() { fprintf(stderr, "usage: %s [-display displayname] [-font fname] ", progname); fprintf(stderr, "[-file filename] [-path]"); fprintf(stderr, "[-geometry geom] [-shell shell] [-label name] "); fprintf(stderr, "[-popup] [-popdown] [-iconic] [-teleport] "); fprintf(stderr, "[-warp] [-version] menitem:command ...\n"); exit(0); } /* run_menu --- put up the window, execute selected commands */ void run_menu() { XEvent ev; XClientMessageEvent *cmsg; KeySym key; int i, cur, old, wide, high, ico, dx, dy; dx = 0; for (i = 0; i < numitems; i++) { wide = XTextWidth(font, labels[i], strlen(labels[i])) + 4; if (wide > dx) dx = wide; } wide = dx; old = cur = -1; high = font->ascent + font->descent + 1; dy = numitems * high; set_wm_hints(wide, dy); ask_wm_for_delete(); #define MenuMask (ButtonPressMask|ButtonReleaseMask\ |LeaveWindowMask|PointerMotionMask|ButtonMotionMask\ |ExposureMask|StructureNotifyMask|KeyPressMask) XSelectInput(dpy, menuwin, MenuMask); XMapWindow(dpy, menuwin); ico = 1; /* warp to first item */ i = 0; /* save menu Item position */ for (;;) { XNextEvent(dpy, &ev); switch (ev.type) { default: fprintf(stderr, "%s: unknown ev.type %d\n", progname, ev.type); break; case ButtonRelease: /* allow button 1 or button 3 */ if (ev.xbutton.button == Button2) break; i = ev.xbutton.y/high; if (ev.xbutton.x < 0 || ev.xbutton.x > wide) break; else if (i < 0 || i >= numitems) break; if (warp) restoremouse(); if (strcmp(labels[i], "exit") == 0) { if (commands[i] != labels[i]) { spawn(commands[i]); } return; } spawn(commands[i]); if (popup) return; if (cur >= 0 && cur < numitems) XFillRectangle(dpy, menuwin, gc, 0, cur*high, wide, high); if (popdown) XIconifyWindow(dpy, menuwin, screen); cur = -1; break; case ButtonPress: case MotionNotify: old = cur; cur = ev.xbutton.y/high; if (ev.xbutton.x < 0 || ev.xbutton.x > wide) cur = -1; else if (cur < 0 || cur >= numitems) cur = -1; if (cur == old) break; if (old >= 0 && old < numitems) XFillRectangle(dpy, menuwin, gc, 0, old*high, wide, high); if (cur >= 0 && cur < numitems) XFillRectangle(dpy, menuwin, gc, 0, cur*high, wide, high); break; case KeyPress: /* http://stackoverflow.com/questions/9838385/replace-of-xkeycodetokeysym */ key = XkbKeycodeToKeysym(dpy, ev.xkey.keycode, 0, ev.xkey.state & ShiftMask ? 1 : 0); if (key != CONFIG_MENU_UP_KEY && key != CONFIG_MENU_DOWN_KEY && key != CONFIG_MENU_SELECT_KEY) break; if (key == CONFIG_MENU_UP_KEY) { old = cur; cur--; } else if (key == CONFIG_MENU_DOWN_KEY) { old = cur; cur++; } while (cur < 0) cur += numitems; cur %= numitems; if (key == CONFIG_MENU_UP_KEY || key == CONFIG_MENU_DOWN_KEY) { if (cur == old) break; if (old >= 0 && old < numitems && cur != -1) XFillRectangle(dpy, menuwin, gc, 0, old*high, wide, high); if (cur >= 0 && cur < numitems && cur != -1) XFillRectangle(dpy, menuwin, gc, 0, cur*high, wide, high); break; } if (warp) restoremouse(); if (key == CONFIG_MENU_SELECT_KEY) { if (strcmp(labels[cur], "exit") == 0) { if (commands[cur] != labels[cur]) { spawn(commands[cur]); } return; } spawn(commands[cur]); } if (popup) return; if (popdown) XIconifyWindow(dpy, menuwin, screen); break; case LeaveNotify: cur = old = -1; XClearWindow(dpy, menuwin); redraw(cur, high, wide); break; case ReparentNotify: case ConfigureNotify: /* * ignore these, they come from XMoveWindow * and are enabled by Struct.. */ break; case UnmapNotify: ico = 1; XClearWindow(dpy, menuwin); break; case MapNotify: if (ico) { if (teleport) teleportmenu(i, wide, high); else if (warp) warpmouse(i, wide, high); } XClearWindow(dpy, menuwin); redraw(cur = i, high, wide); ico = 0; break; case Expose: XClearWindow(dpy, menuwin); redraw(cur, high, wide); break; case ClientMessage: cmsg = &ev.xclient; if (cmsg->message_type == wm_protocols && cmsg->data.l[0] == wm_delete_window) return; case MappingNotify: /* why do we get this? */ break; } } } /* set_wm_hints --- set all the window manager hints */ void set_wm_hints(int wide, int high) { Pixmap iconpixmap; XWMHints *wmhints; XSizeHints *sizehints; XClassHint *classhints; XTextProperty wname, iname; if ((sizehints = XAllocSizeHints()) == NULL) memory("size hints"); if ((wmhints = XAllocWMHints()) == NULL) memory("window manager hints"); if ((classhints = XAllocClassHint()) == NULL) memory("class hints"); /* fill in hints in order to parse geometry spec */ sizehints->width = sizehints->min_width = sizehints->max_width = wide; sizehints->height = sizehints->min_height = sizehints->max_height = high; sizehints->flags = USSize|PSize|PMinSize|PMaxSize; if (XWMGeometry(dpy, screen, geometry, "", 1, sizehints, &sizehints->x, &sizehints->y, &sizehints->width, &sizehints->height, &sizehints->win_gravity) & (XValue|YValue)) sizehints->flags |= USPosition; /* override -geometry for size of window */ sizehints->width = sizehints->min_width = sizehints->max_width = wide; sizehints->height = sizehints->min_height = sizehints->max_height = high; if (XStringListToTextProperty(& labelname, 1, & wname) == 0) memory("window name structure"); if (XStringListToTextProperty(& labelname, 1, & iname) == 0) memory("icon name structure"); menuwin = XCreateSimpleWindow(dpy, root, sizehints->x, sizehints->y, sizehints->width, sizehints->height, 1, black, white); iconpixmap = XCreateBitmapFromData(dpy, menuwin, nine_menu_bits, nine_menu_width, nine_menu_height); wmhints->icon_pixmap = iconpixmap; wmhints->input = False; /* no keyboard input */ if (iconic) wmhints->initial_state = IconicState; else wmhints->initial_state = NormalState; wmhints->flags = IconPixmapHint | StateHint | InputHint; classhints->res_name = progname; classhints->res_class = "9menu"; #ifdef SET_PROPERTIES_MANUALLY /* * For some reason, XSetWMProperties (see below) is failing * John O'Donnell replaces it with the following commands * (this leaves out XSetWMClientMachine, * and also environment variable checking from ClassHint) */ XSetWMName(dpy, menuwin, &wname); XSetWMIconName(dpy, menuwin, &iname); XSetCommand(dpy, menuwin, g_argv, g_argc); XSetWMHints(dpy, menuwin, wmhints); XSetClassHint(dpy, menuwin, classhints); XSetWMNormalHints(dpy, menuwin, sizehints); #else XSetWMProperties(dpy, menuwin, & wname, & iname, g_argv, g_argc, sizehints, wmhints, classhints); #endif } /* ask_wm_for_delete --- jump through hoops to ask WM to delete us */ void ask_wm_for_delete() { int status; wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False); wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", False); status = XSetWMProtocols(dpy, menuwin, & wm_delete_window, 1); if (status != True) fprintf(stderr, "%s: could not ask for clean delete\n", progname); } /* redraw --- actually redraw the menu */ void redraw(int cur, int high, int wide) { int tx, ty, i; for (i = 0; i < numitems; i++) { tx = (wide - XTextWidth(font, labels[i], strlen(labels[i]))) / 2; ty = i*high + font->ascent + 1; XDrawString(dpy, menuwin, gc, tx, ty, labels[i], strlen(labels[i])); } if (cur >= 0 && cur < numitems) XFillRectangle(dpy, menuwin, gc, 0, cur*high, wide, high); } /* teleportmenu --- move the menu to the right place */ void teleportmenu(int cur, int wide, int high) { int x, y, dummy; Window wdummy; if (XQueryPointer(dpy, menuwin, &wdummy, &wdummy, &x, &y, &dummy, &dummy, &dummy)) XMoveWindow(dpy, menuwin, x-wide/2, y-cur*high-high/2); } /* warpmouse --- bring the mouse to the menu */ void warpmouse(int cur, int wide, int high) { int dummy; Window wdummy; int offset; /* move tip of pointer into middle of menu item */ offset = (font->ascent + font->descent + 1) / 2; offset += 6; /* fudge factor */ if (XQueryPointer(dpy, menuwin, &wdummy, &wdummy, &savex, &savey, &dummy, &dummy, &dummy)) XWarpPointer(dpy, None, menuwin, 0, 0, 0, 0, wide/2, cur*high-high/2+offset); } /* restoremouse --- put the mouse back where it was */ void restoremouse() { XWarpPointer(dpy, menuwin, root, 0, 0, 0, 0, savex, savey); }