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

Configure Feed

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

at master 287 lines 6.8 kB view raw
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 27struct program { 28 char *name; 29 action_t *action; 30 struct program *next; 31}; 32 33Window launcher_win; 34XftDraw *launcher_xftdraw; 35struct program *program_head = NULL, *program_tail = NULL; 36int launcher_width = 0, launcher_height = 0, launcher_highlighted = 0, 37 launcher_item_height = 0, launcher_item_padding = 0; 38 39void launcher_reload(void); 40void launcher_redraw(void); 41 42void 43launcher_setup(void) 44{ 45 XTextProperty name; 46 char *title = "Programs"; 47 XSizeHints *hints; 48 49 launcher_reload(); 50 51 launcher_win = XCreateWindow(dpy, root, 0, 0, launcher_width, 52 launcher_height, 0, DefaultDepth(dpy, screen), CopyFromParent, 53 DefaultVisual(dpy, screen), 0, NULL); 54 if (!launcher_win) 55 err(1, "XCreateWindow"); 56 57 hints = XAllocSizeHints(); 58 if (!hints) 59 err(1, "XAllocSizeHints"); 60 61 hints->flags = PMinSize | PMaxSize; 62 hints->min_width = launcher_width; 63 hints->min_height = launcher_height; 64 hints->max_width = launcher_width; 65 hints->max_height = launcher_height; 66 67 XSetWMNormalHints(dpy, launcher_win, hints); 68 69 XFree(hints); 70 71 if (!XStringListToTextProperty(&title, 1, &name)) 72 err(1, "XStringListToTextProperty"); 73 XSetWMName(dpy, launcher_win, &name); 74 75 XSetWindowBackground(dpy, launcher_win, launcher_bg.pixel); 76 77 set_atoms(launcher_win, net_wm_state, XA_ATOM, &net_wm_state_above, 1); 78 set_atoms(launcher_win, net_wm_wintype, XA_ATOM, &net_wm_type_utility, 79 1); 80 81 launcher_xftdraw = XftDrawCreate(dpy, launcher_win, 82 DefaultVisual(dpy, screen), DefaultColormap(dpy, screen)); 83} 84 85void 86launcher_reload(void) 87{ 88 FILE *ini; 89 struct program *program = NULL; 90 XGlyphInfo extents; 91 action_t *action; 92 char *key, *val; 93 int tw; 94 95 launcher_programs_free(); 96 97 launcher_width = 0; 98 launcher_height = 0; 99 launcher_item_padding = opt_pad * 2; 100 launcher_item_height = font->ascent + (launcher_item_padding * 2); 101 102 ini = open_ini(opt_config_file); 103 104 if (!find_ini_section(ini, "launcher")) 105 goto done; 106 107 while (get_ini_kv(ini, &key, &val)) { 108 action = parse_action(key, val); 109 if (action == NULL) 110 continue; 111 112 program = malloc(sizeof(struct program)); 113 if (!program) 114 err(1, "malloc"); 115 116 program->next = NULL; 117 118 if (program_tail) { 119 program_tail->next = program; 120 program_tail = program; 121 } else { 122 program_head = program; 123 program_tail = program; 124 } 125 126 XftTextExtentsUtf8(dpy, font, (FcChar8 *)key, strlen(key), 127 &extents); 128 tw = extents.xOff + (launcher_item_padding * 2); 129 if (tw > launcher_width) 130 launcher_width = tw; 131 launcher_height += launcher_item_height; 132 133 program->name = strdup(key); 134 program->action = action; 135 136 free(key); 137 free(val); 138 } 139 140done: 141 fclose(ini); 142} 143 144void 145launcher_show(XButtonEvent *e) 146{ 147 client_t *c; 148 XEvent ev; 149 struct program *program; 150 int x, y, mx, my, prev_highlighted; 151 152 if (e) { 153 x = e->x_root; 154 y = e->y_root; 155 } else 156 get_pointer(&x, &y); 157 158 XMoveResizeWindow(dpy, launcher_win, x, y, launcher_width, 159 launcher_height); 160 161 c = new_client(launcher_win); 162 c->placed = 1; 163 c->desk = cur_desk; 164 map_client(c); 165 map_if_desk(c); 166 167 x = c->geom.x; 168 y = c->geom.y; 169 170 launcher_highlighted = prev_highlighted = -1; 171 launcher_redraw(); 172 173 /* 174 * If we launched from a mouse button down event, grab the pointer to 175 * watch for it to be released, otherwise we launched from the keyboard 176 * and we'll dismiss on click 177 */ 178 if (XGrabPointer(dpy, root, False, MouseMask, GrabModeAsync, 179 GrabModeAsync, root, None, CurrentTime) != GrabSuccess) { 180 warnx("failed grabbing pointer"); 181 goto close_launcher; 182 } 183 184 for (;;) { 185 XMaskEvent(dpy, PointerMotionMask | ButtonPressMask | 186 ButtonReleaseMask, &ev); 187 188 switch (ev.type) { 189 case MotionNotify: { 190 XMotionEvent *xmv = (XMotionEvent *)&ev; 191 mx = xmv->x - x; 192 my = xmv->y - y; 193 194 if (mx < 0 || mx > launcher_width || 195 my < 0 || my > launcher_height) 196 launcher_highlighted = -1; 197 else 198 launcher_highlighted = (my / 199 launcher_item_height); 200 201 if (launcher_highlighted != prev_highlighted) 202 launcher_redraw(); 203 204 prev_highlighted = launcher_highlighted; 205 break; 206 } 207 case ButtonPress: 208 break; 209 case ButtonRelease: 210 goto close_launcher; 211 break; 212 } 213 } 214 215close_launcher: 216 XUngrabPointer(dpy, CurrentTime); 217 XUnmapWindow(dpy, launcher_win); 218 del_client(c, DEL_WITHDRAW); 219 220 if (launcher_highlighted < 0) 221 return; 222 223 for (x = 0, program = program_head; program; 224 program = program->next, x++) { 225 if (x != launcher_highlighted) 226 continue; 227 228 take_action(program->action); 229 break; 230 } 231} 232 233void 234launcher_programs_free(void) 235{ 236 struct program *program; 237 238 for (program = program_head; program;) { 239 struct program *t = program; 240 241 if (program->name) 242 free(program->name); 243 if (program->action) { 244 if (program->action->sarg) 245 free(program->action->sarg); 246 free(program->action); 247 } 248 program = program->next; 249 free(t); 250 } 251 252 program_head = program_tail = NULL; 253} 254 255void 256launcher_redraw(void) 257{ 258 struct program *program; 259 XftColor *color; 260 int i; 261 262 XClearWindow(dpy, launcher_win); 263 264 for (i = 0, program = program_head; program; 265 program = program->next, i++) { 266 if (launcher_highlighted == i) { 267 XSetForeground(dpy, DefaultGC(dpy, screen), 268 launcher_fg.pixel); 269 XFillRectangle(dpy, launcher_win, 270 DefaultGC(dpy, screen), 271 0, launcher_item_height * i, 272 launcher_width, launcher_item_height); 273 color = &xft_launcher_highlighted; 274 } else { 275 XSetForeground(dpy, DefaultGC(dpy, screen), 276 launcher_fg.pixel); 277 color = &xft_launcher; 278 } 279 280 281 XftDrawStringUtf8(launcher_xftdraw, color, font, 282 launcher_item_padding, 283 (launcher_item_height * (i + 1)) - launcher_item_padding, 284 (unsigned char *)program->name, 285 strlen(program->name)); 286 } 287}