progman.exe^H^H^H^H
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

launcher: Replace external aemenu with our own launcher

This lets us drop the dependency on Gtk and avoids having to shell
out to an external program.

Admittedly the new launcher window has a very Xt feel to it, but
maybe we can spruce it up with some button bevels or something
later.

+338 -407
+2 -5
.gitignore
··· 1 - aewm 2 - aedesk 3 - aemenu 4 - aepanel 5 - aesession 1 + progman 2 + progman_ini.h 6 3 *.o
+16 -28
Makefile
··· 24 24 PREFIX?= /usr/local 25 25 X11BASE?= /usr/X11R6 26 26 27 - PKGLIBS= x11 xft xext xpm gtk+-2.0 27 + PKGLIBS= x11 xft xext xpm 28 28 29 29 CC?= cc 30 30 CFLAGS+= -O2 -Wall -Wunused \ ··· 33 33 `pkg-config --cflags ${PKGLIBS}` 34 34 LDFLAGS+= `pkg-config --libs ${PKGLIBS}` 35 35 36 - # uncomment to enable debugging 36 + # use gdk-pixbuf to rescale icons; optional 37 + PKGLIBS+= gdk-pixbuf-xlib-2.0 38 + CFLAGS+= -DUSE_GDK_PIXBUF 39 + 40 + # enable debugging; optional 37 41 #CFLAGS+= -g -DDEBUG=1 38 42 39 - # uncomment for HiDPI displays 43 + # use 2x icons, borders, fonts for HiDPI displays; optional 40 44 CFLAGS+= -DHIDPI=1 41 45 42 - # uncomment to use gdk-pixbuf to rescale icons 43 - PKGLIBS+= gdk-pixbuf-xlib-2.0 44 - CFLAGS+= -DUSE_GDK_PIXBUF 45 - 46 46 BINDIR= $(PREFIX)/bin 47 47 48 - PROGMAN_SRC= atom.c \ 48 + SRC= atom.c \ 49 49 client.c \ 50 50 common.c \ 51 51 events.c \ 52 52 keyboard.c \ 53 + launcher.c \ 53 54 manage.c \ 54 - menu.c \ 55 55 parser.c \ 56 56 progman.c 57 57 58 - AEMENU_SRC= aemenu.c \ 59 - atom.c \ 60 - common.c \ 61 - menu.c \ 62 - parser.c 58 + OBJ= ${SRC:.c=.o} 63 59 64 - PROGMAN_OBJ= ${PROGMAN_SRC:.c=.o} 65 - AEMENU_OBJ= ${AEMENU_SRC:.c=.o} 66 - 67 - OBJ= $(PROGMAN_OBJ) \ 68 - $(AEMENU_OBJ) 69 - 70 - BIN= progman aemenu 60 + BIN= progman 71 61 72 62 all: $(BIN) 73 63 74 - $(PROGMAN_OBJ): progman.h progman_ini.h 64 + $(OBJ): progman.h Makefile 65 + parser.o: progman.h progman_ini.h 75 66 76 - progman_ini.h: progman.ini 67 + progman_ini.h: progman.ini 77 68 xxd -i progman.ini > $@ 78 69 79 - progman: $(PROGMAN_OBJ) 80 - $(CC) -o $@ $(PROGMAN_OBJ) $(LDFLAGS) 81 - 82 - aemenu: $(AEMENU_OBJ) progman.h 83 - $(CC) -o $@ $(AEMENU_OBJ) $(LDFLAGS) 70 + progman: $(OBJ) 71 + $(CC) -o $@ $(OBJ) $(LDFLAGS) 84 72 85 73 install: all 86 74 mkdir -p $(BINDIR) $(MANDIR)
+2 -2
README.md
··· 28 28 - [Theme support](https://github.com/jcs/progman/tree/master/themes) 29 29 - Optional HiDPI support by defining `-DHIDPI` in `Makefile`, to double-size 30 30 images, icons, and borders 31 - - Right-clicking on the desktop launches the `launcher` defined in 32 - `progman.ini`, which is `aemenu` by default (left over from aewm) 31 + - Right-clicking on the desktop shows a launcher menu containing programs 32 + listed in `progman.ini`
-139
aemenu.c
··· 1 - /* 2 - * Copyright 1998-2007 Decklin Foster <decklin@red-bean.com>. 3 - * 4 - * Permission is hereby granted, free of charge, to any person obtaining a copy 5 - * of this software and associated documentation files (the "Software"), to 6 - * deal in the Software without restriction, including without limitation the 7 - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 - * sell copies of the Software, and to permit persons to whom the Software is 9 - * furnished to do so, subject to the following conditions: 10 - * 11 - * The above copyright notice and this permission notice shall be included in 12 - * all copies or substantial portions of the Software. 13 - * 14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 - * AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 18 - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 19 - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 - */ 21 - 22 - #include <locale.h> 23 - #include <stdlib.h> 24 - #include <string.h> 25 - #include <stdio.h> 26 - #include <X11/Xatom.h> 27 - #include <gtk/gtk.h> 28 - #include <gdk/gdkx.h> 29 - #include "common.h" 30 - #include "atom.h" 31 - #include "menu.h" 32 - 33 - void *make_launchitem_cb(void *, char *, char *); 34 - void make_clientitem(GtkWidget *, Window); 35 - void fork_exec_cb(GtkWidget *, char *); 36 - void raise_win_cb(GtkWidget *, Window); 37 - 38 - int 39 - main(int argc, char **argv) 40 - { 41 - GtkWidget *main_menu; 42 - int i, mode = LAUNCH; 43 - char *opt_config = NULL; 44 - unsigned long read, left; 45 - Window w; 46 - 47 - setlocale(LC_ALL, ""); 48 - gtk_init(&argc, &argv); 49 - 50 - for (i = 1; i < argc; i++) { 51 - if (ARG("config", "rc", 1)) { 52 - opt_config = argv[++i]; 53 - } else if (ARG("launch", "l", 0)) { 54 - mode = LAUNCH; 55 - } else if (ARG("switch", "s", 0)) { 56 - mode = SWITCH; 57 - } else { 58 - fprintf(stderr, 59 - "usage: aemenu [--switch|-s] " 60 - "[--config|-rc <file>]\n"); 61 - exit(2); 62 - } 63 - } 64 - 65 - main_menu = gtk_menu_new(); 66 - 67 - if (mode == LAUNCH) { 68 - make_launch_menu(opt_config, main_menu, make_launchitem_cb); 69 - } else { /* mode == SWITCH */ 70 - dpy = GDK_DISPLAY(); 71 - root = GDK_ROOT_WINDOW(); 72 - setup_switch_atoms(); 73 - for (i = 0, left = 1; left; i += read) { 74 - read = get_atoms(root, net_client_list, XA_WINDOW, i, 75 - &w, 1, &left); 76 - if (!read) 77 - break; 78 - 79 - make_clientitem(main_menu, w); 80 - } 81 - } 82 - 83 - gtk_signal_connect_object(GTK_OBJECT(main_menu), "deactivate", 84 - GTK_SIGNAL_FUNC(gtk_main_quit), NULL); 85 - gtk_menu_popup(GTK_MENU(main_menu), NULL, NULL, NULL, NULL, 0, 0); 86 - 87 - gtk_main(); 88 - return 0; 89 - } 90 - 91 - void * 92 - make_launchitem_cb(void *menu, char *label, char *cmd) 93 - { 94 - GtkWidget *item, *sub_menu = NULL; 95 - 96 - item = gtk_menu_item_new_with_label(strdup(label)); 97 - gtk_menu_append(GTK_MENU(menu), item); 98 - 99 - if (cmd) { 100 - gtk_signal_connect(GTK_OBJECT(item), "activate", 101 - GTK_SIGNAL_FUNC(fork_exec_cb), strdup(cmd)); 102 - } else { 103 - sub_menu = gtk_menu_new(); 104 - gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), sub_menu); 105 - } 106 - 107 - gtk_widget_show(item); 108 - return sub_menu; 109 - } 110 - 111 - void 112 - make_clientitem(GtkWidget *menu, Window w) 113 - { 114 - GtkWidget *item; 115 - char buf[BUF_SIZE]; 116 - 117 - if (is_on_cur_desk(w) && !is_skip(w)) { 118 - snprint_wm_name(buf, sizeof buf, w); 119 - item = gtk_menu_item_new_with_label(buf); 120 - gtk_menu_append(GTK_MENU(menu), item); 121 - gtk_signal_connect(GTK_OBJECT(item), "activate", 122 - GTK_SIGNAL_FUNC(raise_win_cb), (gpointer) w); 123 - gtk_widget_show(item); 124 - } 125 - } 126 - 127 - void 128 - fork_exec_cb(GtkWidget * widget, char *data) 129 - { 130 - fork_exec(data); 131 - gtk_main_quit(); 132 - } 133 - 134 - void 135 - raise_win_cb(GtkWidget * widget, Window w) 136 - { 137 - raise_win(w); 138 - gtk_main_quit(); 139 - }
+6 -9
events.c
··· 45 45 static void handle_expose_event(XExposeEvent *); 46 46 static void handle_shape_change(XShapeEvent *); 47 47 48 - static int root_button_pressed = 0; 49 - 50 48 static XEvent ev; 51 49 52 50 void ··· 148 146 (fc->state & STATE_ICONIFIED)) { 149 147 c = fc; 150 148 e->window = c->icon; 149 + } else if (e->button == Button3) { 150 + launcher_show(e); 151 151 } 152 + 153 + return; 152 154 } 153 155 154 - if (e->window == root) { 155 - root_button_pressed = e->button; 156 - } else if (c && (c->state & STATE_DOCK)) { 156 + if (c && (c->state & STATE_DOCK)) { 157 157 /* pass button event through */ 158 158 XAllowEvents(dpy, ReplayPointer, CurrentTime); 159 159 } else if (c) { ··· 191 191 } 192 192 } 193 193 194 - if (e->window == root && root_button_pressed == Button3) { 195 - fork_exec(opt_launcher); 196 - root_button_pressed = 0; 197 - } else if (c) { 194 + if (c) { 198 195 if (find_client(e->window, MATCH_FRAME)) 199 196 user_action(c, e->window, e->x, e->y, e->button, 0); 200 197
+265
launcher.c
··· 1 + /* 2 + * Copyright (c) 2021 joshua stein <jcs@jcs.org> 3 + * 4 + * Permission is hereby granted, free of charge, to any person obtaining a copy 5 + * of this software and associated documentation files (the "Software"), to 6 + * deal in the Software without restriction, including without limitation the 7 + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 + * sell copies of the Software, and to permit persons to whom the Software is 9 + * furnished to do so, subject to the following conditions: 10 + * 11 + * The above copyright notice and this permission notice shall be included in 12 + * all copies or substantial portions of the Software. 13 + * 14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 + * AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 18 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 19 + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 + */ 21 + 22 + #include <stdlib.h> 23 + #include <err.h> 24 + #include "parser.h" 25 + #include "progman.h" 26 + 27 + struct program { 28 + char *name; 29 + char *path; 30 + struct program *next; 31 + }; 32 + 33 + Window launcher_win; 34 + XftDraw *launcher_xftdraw; 35 + struct program *program_head = NULL, *program_tail = NULL; 36 + int launcher_width = 0, launcher_height = 0, launcher_highlighted = 0, 37 + launcher_item_height = 0, launcher_item_padding = 0; 38 + 39 + void launcher_reload(void); 40 + void launcher_redraw(void); 41 + 42 + void 43 + launcher_setup(void) 44 + { 45 + XTextProperty name; 46 + char *title = "Programs"; 47 + 48 + launcher_reload(); 49 + 50 + launcher_win = XCreateWindow(dpy, root, 0, 0, launcher_width, 51 + launcher_height, 0, DefaultDepth(dpy, screen), CopyFromParent, 52 + DefaultVisual(dpy, screen), 0, NULL); 53 + if (!launcher_win) 54 + err(1, "XCreateWindow"); 55 + 56 + if (!XStringListToTextProperty(&title, 1, &name)) 57 + err(1, "XStringListToTextProperty"); 58 + XSetWMName(dpy, launcher_win, &name); 59 + 60 + XSetWindowBackground(dpy, launcher_win, launcher_bg.pixel); 61 + 62 + set_atoms(launcher_win, net_wm_state, XA_ATOM, &net_wm_state_above, 1); 63 + set_atoms(launcher_win, net_wm_wintype, XA_ATOM, &net_wm_type_utility, 64 + 1); 65 + 66 + launcher_xftdraw = XftDrawCreate(dpy, launcher_win, 67 + DefaultVisual(dpy, screen), DefaultColormap(dpy, screen)); 68 + } 69 + 70 + void 71 + launcher_reload(void) 72 + { 73 + FILE *ini; 74 + struct program *program = NULL; 75 + XSizeHints *hints; 76 + XGlyphInfo extents; 77 + char *key, *val; 78 + int tw; 79 + 80 + launcher_programs_free(); 81 + 82 + launcher_width = 0; 83 + launcher_height = 0; 84 + launcher_item_padding = opt_pad * 2; 85 + launcher_item_height = font->ascent + (launcher_item_padding * 2); 86 + 87 + ini = open_ini(opt_config_file); 88 + 89 + if (!find_ini_section(ini, "launcher")) 90 + goto done; 91 + 92 + while (get_ini_kv(ini, &key, &val)) { 93 + program = malloc(sizeof(struct program)); 94 + if (!program) 95 + err(1, "malloc"); 96 + 97 + program->next = NULL; 98 + 99 + if (program_tail) { 100 + program_tail->next = program; 101 + program_tail = program; 102 + } else { 103 + program_head = program; 104 + program_tail = program; 105 + } 106 + 107 + XftTextExtentsUtf8(dpy, font, (FcChar8 *)key, strlen(key), 108 + &extents); 109 + tw = extents.xOff + (launcher_item_padding * 2); 110 + if (tw > launcher_width) 111 + launcher_width = tw; 112 + launcher_height += launcher_item_height; 113 + 114 + program->name = strdup(key); 115 + program->path = strdup(val); 116 + 117 + printf("%s -> %s\n", key, val); 118 + 119 + free(key); 120 + free(val); 121 + } 122 + 123 + done: 124 + fclose(ini); 125 + 126 + hints = XAllocSizeHints(); 127 + if (!hints) 128 + err(1, "XAllocSizeHints"); 129 + 130 + hints->flags = PMinSize | PMaxSize; 131 + hints->min_width = launcher_width; 132 + hints->min_height = launcher_height; 133 + hints->max_width = launcher_width; 134 + hints->max_height = launcher_height; 135 + 136 + XSetWMNormalHints(dpy, launcher_win, hints); 137 + 138 + XFree(hints); 139 + } 140 + 141 + void 142 + launcher_show(XButtonEvent *e) 143 + { 144 + client_t *c; 145 + XEvent ev; 146 + struct program *program; 147 + int x, y, mx, my, prev_highlighted; 148 + 149 + /* TODO: reload ini if it's changed since we last looked at it */ 150 + 151 + x = e->x_root; 152 + y = e->y_root; 153 + XMoveResizeWindow(dpy, launcher_win, x, y, launcher_width, 154 + launcher_height); 155 + 156 + c = new_client(launcher_win); 157 + c->placed = 1; 158 + map_client(c); 159 + map_if_desk(c); 160 + 161 + launcher_highlighted = prev_highlighted = 0; 162 + launcher_redraw(); 163 + 164 + if (XGrabPointer(dpy, root, False, MouseMask, GrabModeAsync, 165 + GrabModeAsync, root, None, CurrentTime) != GrabSuccess) { 166 + warnx("failed grabbing pointer"); 167 + goto close_launcher; 168 + } 169 + 170 + for (;;) { 171 + XMaskEvent(dpy, PointerMotionMask | ButtonReleaseMask, &ev); 172 + 173 + switch (ev.type) { 174 + case MotionNotify: { 175 + XMotionEvent *xmv = (XMotionEvent *)&ev; 176 + mx = xmv->x - x; 177 + my = xmv->y - y; 178 + 179 + if (mx < 0 || mx > launcher_width || 180 + my < 0 || my > launcher_height) 181 + launcher_highlighted = -1; 182 + else 183 + launcher_highlighted = (my / 184 + launcher_item_height); 185 + 186 + if (launcher_highlighted != prev_highlighted) 187 + launcher_redraw(); 188 + 189 + prev_highlighted = launcher_highlighted; 190 + break; 191 + } 192 + case ButtonRelease: 193 + goto close_launcher; 194 + break; 195 + } 196 + } 197 + 198 + close_launcher: 199 + XUngrabPointer(dpy, CurrentTime); 200 + XUnmapWindow(dpy, launcher_win); 201 + del_client(c, DEL_WITHDRAW); 202 + 203 + if (launcher_highlighted >= 0) { 204 + for (x = 0, program = program_head; program; 205 + program = program->next, x++) { 206 + if (x == launcher_highlighted) { 207 + fork_exec(program->path); 208 + break; 209 + } 210 + } 211 + } 212 + } 213 + 214 + void 215 + launcher_programs_free(void) 216 + { 217 + struct program *program; 218 + 219 + for (program = program_head; program;) { 220 + struct program *t = program; 221 + 222 + if (program->name) 223 + free(program->name); 224 + if (program->path) 225 + free(program->path); 226 + program = program->next; 227 + free(t); 228 + } 229 + 230 + program_head = program_tail = NULL; 231 + } 232 + 233 + void 234 + launcher_redraw(void) 235 + { 236 + struct program *program; 237 + XftColor *color; 238 + int i; 239 + 240 + XClearWindow(dpy, launcher_win); 241 + 242 + for (i = 0, program = program_head; program; 243 + program = program->next, i++) { 244 + if (launcher_highlighted == i) { 245 + XSetForeground(dpy, DefaultGC(dpy, screen), 246 + launcher_fg.pixel); 247 + XFillRectangle(dpy, launcher_win, 248 + DefaultGC(dpy, screen), 249 + 0, launcher_item_height * i, 250 + launcher_width, launcher_item_height); 251 + color = &xft_launcher_highlighted; 252 + } else { 253 + XSetForeground(dpy, DefaultGC(dpy, screen), 254 + launcher_fg.pixel); 255 + color = &xft_launcher; 256 + } 257 + 258 + 259 + XftDrawStringUtf8(launcher_xftdraw, color, font, 260 + launcher_item_padding, 261 + (launcher_item_height * (i + 1)) - launcher_item_padding, 262 + (unsigned char *)program->name, 263 + strlen(program->name)); 264 + } 265 + }
-163
menu.c
··· 1 - /* 2 - * Copyright 1998-2007 Decklin Foster <decklin@red-bean.com>. 3 - * 4 - * Permission is hereby granted, free of charge, to any person obtaining a copy 5 - * of this software and associated documentation files (the "Software"), to 6 - * deal in the Software without restriction, including without limitation the 7 - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 - * sell copies of the Software, and to permit persons to whom the Software is 9 - * furnished to do so, subject to the following conditions: 10 - * 11 - * The above copyright notice and this permission notice shall be included in 12 - * all copies or substantial portions of the Software. 13 - * 14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 - * AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 18 - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 19 - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 - */ 21 - 22 - #include <err.h> 23 - #include <stdlib.h> 24 - #include <stdio.h> 25 - #include <string.h> 26 - #include <ctype.h> 27 - #include <unistd.h> 28 - #include <sys/types.h> 29 - #include <X11/Xlib.h> 30 - #include <X11/Xatom.h> 31 - #include <X11/Xutil.h> 32 - #include "common.h" 33 - #include "parser.h" 34 - #include "atom.h" 35 - #include "menu.h" 36 - 37 - void 38 - setup_switch_atoms(void) 39 - { 40 - utf8_string = XInternAtom(dpy, "UTF8_STRING", False); 41 - wm_state = XInternAtom(dpy, "WM_STATE", False); 42 - net_client_list = XInternAtom(dpy, "_NET_CLIENT_LIST", False); 43 - net_cur_desk = XInternAtom(dpy, "_NET_CURRENT_DESKTOP", False); 44 - net_wm_name = XInternAtom(dpy, "_NET_WM_NAME", False); 45 - net_wm_desk = XInternAtom(dpy, "_NET_WM_DESKTOP", False); 46 - net_wm_icon_name = XInternAtom(dpy, "_NET_WM_ICON_NAME", False); 47 - net_wm_state = XInternAtom(dpy, "_NET_WM_STATE", False); 48 - net_wm_state_skipt = XInternAtom(dpy, "_NET_WM_STATE_SKIP_TASKBAR", 49 - False); 50 - net_wm_state_skipp = XInternAtom(dpy, "_NET_WM_STATE_SKIP_PAGER", 51 - False); 52 - net_wm_wintype = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); 53 - net_wm_type_dock = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False); 54 - net_wm_type_desk = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", 55 - False); 56 - net_active_window = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); 57 - } 58 - 59 - void 60 - snprint_wm_name(char *buf, size_t len, Window w) 61 - { 62 - char *n; 63 - 64 - if (get_wm_state(w) == NormalState) { 65 - if ((n = get_wm_name(w))) { 66 - if (snprintf(buf, len, "%s", n) > len) 67 - strcpy(buf + len - 4, "..."); 68 - XFree(n); 69 - } else 70 - snprintf(buf, len, "%#lx", w); 71 - } else { 72 - if ((n = get_wm_icon_name(w))) { 73 - if (snprintf(buf, len, "[%s]", n) > len) 74 - strcpy(buf + len - 5, "...]"); 75 - XFree(n); 76 - } else 77 - snprintf(buf, len, "[%#lx]", w); 78 - } 79 - } 80 - 81 - /* 82 - * The WM receives the ClientMessage here and sets the property in response, so 83 - * we only do this after the PropertyNotify. 84 - */ 85 - int 86 - is_on_cur_desk(Window w) 87 - { 88 - unsigned long w_desk, cur_desk; 89 - 90 - if (get_atoms(root, net_cur_desk, XA_CARDINAL, 0, &cur_desk, 1, NULL) && 91 - (get_atoms(w, net_wm_desk, XA_CARDINAL, 0, &w_desk, 1, NULL))) 92 - return IS_ON_DESK(w_desk, cur_desk); 93 - 94 - return 1; 95 - } 96 - 97 - int 98 - is_skip(Window w) 99 - { 100 - Atom win_type, state; 101 - int i; 102 - unsigned long r; 103 - 104 - if (get_atoms(w, net_wm_wintype, XA_ATOM, 0, &win_type, 1, NULL) && 105 - (win_type == net_wm_type_dock || win_type == net_wm_type_desk)) 106 - return 1; 107 - 108 - for (i = 0, r = 1; r; i += r) 109 - if ((r = get_atoms(w, net_wm_state, XA_ATOM, i, &state, 1, 110 - NULL)) && (state == net_wm_state_skipt || 111 - state == net_wm_state_skipp)) 112 - return 1; 113 - 114 - return 0; 115 - } 116 - 117 - /* 118 - * This XSync call is required, as we don't have any sort of integration with 119 - * the real X event loop. 120 - */ 121 - void 122 - raise_win(Window w) 123 - { 124 - XMapRaised(dpy, w); 125 - XSync(dpy, False); 126 - send_xmessage(root, w, net_active_window, 0, SubstructureNotifyMask); 127 - } 128 - 129 - static int 130 - do_launch_menu(FILE *ini, void *menu, make_item_func make_item_cb) 131 - { 132 - char *key, *val; 133 - 134 - if (!find_ini_section(ini, "launcher")) 135 - return 1; 136 - 137 - while (get_ini_kv(ini, &key, &val)) { 138 - make_item_cb(menu, key, val); 139 - free(key); 140 - free(val); 141 - } 142 - 143 - return 0; 144 - } 145 - 146 - void 147 - make_launch_menu(char *inifile, void *menu, make_item_func make_item_cb) 148 - { 149 - FILE *ini; 150 - 151 - ini = open_ini(inifile); 152 - if (!ini) 153 - goto fallback; 154 - 155 - if (do_launch_menu(ini, menu, make_item_cb) != 0) 156 - goto fallback; 157 - 158 - fclose(ini); 159 - return; 160 - 161 - fallback: 162 - make_item_cb(menu, "xterm", "xterm"); 163 - }
-39
menu.h
··· 1 - /* 2 - * Copyright 1998-2007 Decklin Foster <decklin@red-bean.com>. 3 - * 4 - * Permission is hereby granted, free of charge, to any person obtaining a copy 5 - * of this software and associated documentation files (the "Software"), to 6 - * deal in the Software without restriction, including without limitation the 7 - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 - * sell copies of the Software, and to permit persons to whom the Software is 9 - * furnished to do so, subject to the following conditions: 10 - * 11 - * The above copyright notice and this permission notice shall be included in 12 - * all copies or substantial portions of the Software. 13 - * 14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 - * AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 18 - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 19 - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 - */ 21 - 22 - #ifndef PROGMAN_MENU_H 23 - #define PROGMAN_MENU_H 24 - 25 - enum { 26 - LAUNCH, 27 - SWITCH, 28 - }; 29 - 30 - typedef void *(*make_item_func) (void *, char *, char *); 31 - 32 - extern void setup_switch_atoms(void); 33 - extern void snprint_wm_name(char *, size_t, Window); 34 - extern int is_on_cur_desk(Window); 35 - extern int is_skip(Window); 36 - extern void raise_win(Window); 37 - extern void make_launch_menu(char *, void *, make_item_func); 38 - 39 - #endif /* PROGMAN_MENU_H */
+26 -14
progman.c
··· 77 77 XftFont *iconfont; 78 78 XftColor xft_fg; 79 79 XftColor xft_fg_unfocused; 80 + XftColor xft_launcher; 81 + XftColor xft_launcher_highlighted; 80 82 81 83 Colormap def_cmap; 82 84 XColor fg; ··· 88 90 XColor bevel_light; 89 91 XColor border_fg; 90 92 XColor border_bg; 93 + XColor launcher_fg; 94 + XColor launcher_bg; 91 95 GC pixmap_gc; 92 96 GC invert_gc; 93 97 Pixmap close_pm; ··· 131 135 char *opt_button_bg = DEF_BUTTON_BG; 132 136 char *opt_bevel_dark = DEF_BEVEL_DARK; 133 137 char *opt_bevel_light = DEF_BEVEL_LIGHT; 134 - char *opt_border_bg = DEF_BORDER_BG; 135 138 char *opt_border_fg = DEF_BORDER_FG; 139 + char *opt_border_bg = DEF_BORDER_BG; 140 + char *opt_launcher_fg = DEF_LAUNCHER_FG; 141 + char *opt_launcher_bg = DEF_LAUNCHER_BG; 136 142 char *opt_root_bg = DEF_ROOTBG; 137 143 int opt_bw = DEF_BW; 138 144 int opt_pad = DEF_PAD; 139 145 int opt_bevel = DEF_BEVEL; 140 146 int opt_edge_resist = DEF_EDGE_RES; 141 - char *opt_launcher = DEF_LAUNCHER; 142 147 143 148 static void cleanup(void); 144 149 static void read_config(void); ··· 187 192 sigaction(SIGCHLD, &act, NULL); 188 193 189 194 setup_display(); 195 + launcher_setup(); 190 196 event_loop(); 191 197 cleanup(); 192 198 ··· 221 227 opt_border_fg = strdup(val); 222 228 else if (strcmp(key, "border_bgcolor") == 0) 223 229 opt_border_bg = strdup(val); 230 + else if (strcmp(key, "launcher_fgcolor") == 0) 231 + opt_launcher_fg = strdup(val); 232 + else if (strcmp(key, "launcher_bgcolor") == 0) 233 + opt_launcher_bg = strdup(val); 224 234 else if (strcmp(key, "border_width") == 0) 225 235 opt_bw = atoi(val); 226 236 else if (strcmp(key, "title_padding") == 0) ··· 229 239 opt_edge_resist = atoi(val); 230 240 else if (strcmp(key, "root_bgcolor") == 0) 231 241 opt_root_bg = strdup(val); 232 - else if (strcmp(key, "launcher") == 0) 233 - opt_launcher = strdup(val); 234 242 else 235 243 warnx("unknown key \"%s\" and value \"%s\" in " 236 244 "ini", key, val); ··· 294 302 alloc_color(opt_bevel_light, &bevel_light, "bevel_lightcolor"); 295 303 alloc_color(opt_border_fg, &border_fg, "border_fgcolor"); 296 304 alloc_color(opt_border_bg, &border_bg, "border_bgcolor"); 305 + alloc_color(opt_launcher_fg, &launcher_fg, "launcher_fgcolor"); 306 + alloc_color(opt_launcher_bg, &launcher_bg, "launcher_bgcolor"); 297 307 298 308 XSetLineAttributes(dpy, DefaultGC(dpy, screen), 1, LineSolid, CapButt, 299 309 JoinBevel); 300 310 XSetFillStyle(dpy, DefaultGC(dpy, screen), FillSolid); 301 311 302 - xft_fg.color.red = fg.red; 303 - xft_fg.color.green = fg.green; 304 - xft_fg.color.blue = fg.blue; 305 - xft_fg.color.alpha = 0xffff; 306 - xft_fg.pixel = fg.pixel; 312 + #define create_xft_color(_xft, _pixel) \ 313 + (_xft).color.red = (_pixel).red; \ 314 + (_xft).color.green = (_pixel).green; \ 315 + (_xft).color.blue = (_pixel).blue; \ 316 + (_xft).color.alpha = 0xffff; \ 317 + (_xft).pixel = (_pixel).pixel; 307 318 308 - xft_fg_unfocused.color.red = unfocused_fg.red; 309 - xft_fg_unfocused.color.green = unfocused_fg.green; 310 - xft_fg_unfocused.color.blue = unfocused_fg.blue; 311 - xft_fg_unfocused.color.alpha = 0xffff; 312 - xft_fg_unfocused.pixel = unfocused_fg.pixel; 319 + create_xft_color(xft_fg, fg); 320 + create_xft_color(xft_fg_unfocused, unfocused_fg); 321 + create_xft_color(xft_launcher, launcher_fg); 322 + create_xft_color(xft_launcher_highlighted, launcher_bg); 313 323 314 324 font = XftFontOpenName(dpy, screen, opt_font); 315 325 if (!font) ··· 492 502 493 503 XDeleteProperty(dpy, root, net_supported); 494 504 XDeleteProperty(dpy, root, net_client_list); 505 + 506 + launcher_programs_free(); 495 507 496 508 XCloseDisplay(dpy); 497 509 exit(0);
+15 -4
progman.h
··· 43 43 #define DEF_BEVEL_LIGHT "white" 44 44 45 45 /* Borders */ 46 + #define DEF_BORDER_FG "black" 46 47 #define DEF_BORDER_BG "#c0c7c8" 47 - #define DEF_BORDER_FG "black" 48 + 49 + /* Launcher */ 50 + #define DEF_LAUNCHER_FG "black" 51 + #define DEF_LAUNCHER_BG "#c0c7c8" 48 52 49 53 /* Default root color is unchanged */ 50 54 #define DEF_ROOTBG NULL ··· 68 72 #endif 69 73 70 74 #define DEF_NDESKS 5 71 - 72 - #define DEF_LAUNCHER "aemenu --launch" 73 75 74 76 #define DOUBLE_CLICK_MSEC 250 75 77 ··· 258 260 extern XftFont *iconfont; 259 261 extern XftColor xft_fg; 260 262 extern XftColor xft_fg_unfocused; 263 + extern XftColor xft_launcher; 264 + extern XftColor xft_launcher_highlighted; 261 265 extern Colormap cmap; 262 266 extern XColor fg; 263 267 extern XColor bg; ··· 268 272 extern XColor bevel_light; 269 273 extern XColor border_fg; 270 274 extern XColor border_bg; 275 + extern XColor launcher_fg; 276 + extern XColor launcher_bg; 271 277 extern GC pixmap_gc; 272 278 extern GC invert_gc; 273 279 extern Pixmap close_pm; ··· 315 321 extern int opt_bw; 316 322 extern int opt_pad; 317 323 extern int opt_edge_resist; 318 - extern char *opt_launcher; 319 324 extern void sig_handler(int signum); 320 325 extern int exitmsg[2]; 321 326 ··· 394 399 /* keyboard.c */ 395 400 extern void bind_keys(void); 396 401 extern void handle_key_event(XKeyEvent *); 402 + 403 + /* launcher.c */ 404 + extern Window launcher_win; 405 + extern void launcher_setup(void); 406 + extern void launcher_show(XButtonEvent *); 407 + extern void launcher_programs_free(void); 397 408 398 409 #endif /* PROGMAN_H */
+6 -4
progman.ini
··· 18 18 unfocused_bgcolor = white 19 19 20 20 # Borders 21 - border_bgcolor = #c0c7c8 22 21 border_fgcolor = black 22 + border_bgcolor = #c0c7c8 23 23 border_width = 6 24 24 button_bgcolor = #c0c7c8 25 25 title_padding = 6 26 26 27 + # Launcher 28 + launcher_fgcolor = black 29 + launcher_bgcolor = #c0c7c8 30 + 27 31 # When not specified, the root color is not changed 28 32 #root_bgcolor = #c0c7c8 29 33 30 34 # When moving windows, how hard to resist going off-screen 31 35 edgeresist = 80 32 - 33 - # What to launch when right-clicking the root 34 - launcher = aemenu 35 36 36 37 # Custom key bindings can be specified as "Modifier+Key = action". 37 38 [keyboard] ··· 50 51 Alt+0 = desk 9 51 52 Win+T = exec xterm 52 53 54 + # When right-clicking on the root, this list of programs will be shown 53 55 [launcher] 54 56 Xterm = xterm 55 57 Firefox = firefox