implemented tagging a client
c47da143
5 file(s) · +156 −85
| 11 | 11 | ||
| 12 | 12 | #include "dwm.h" |
|
| 13 | 13 | ||
| 14 | - | static void (*arrange)(void *) = floating; |
|
| 14 | + | static void (*arrange)(Arg *) = floating; |
|
| 15 | + | ||
| 16 | + | static Client * |
|
| 17 | + | next(Client *c) |
|
| 18 | + | { |
|
| 19 | + | for(c = c->next; c && !c->tags[tsel]; c = c->next); |
|
| 20 | + | return c; |
|
| 21 | + | } |
|
| 22 | + | ||
| 23 | + | static Client * |
|
| 24 | + | prev(Client *c) |
|
| 25 | + | { |
|
| 26 | + | for(c = c->prev; c && !c->tags[tsel]; c = c->prev); |
|
| 27 | + | return c; |
|
| 28 | + | } |
|
| 15 | 29 | ||
| 16 | 30 | void |
|
| 17 | - | max(void *aux) |
|
| 31 | + | max(Arg *arg) |
|
| 18 | 32 | { |
|
| 19 | - | if(!stack) |
|
| 33 | + | if(!csel) |
|
| 20 | 34 | return; |
|
| 21 | - | stack->x = sx; |
|
| 22 | - | stack->y = sy; |
|
| 23 | - | stack->w = sw - 2 * stack->border; |
|
| 24 | - | stack->h = sh - 2 * stack->border; |
|
| 25 | - | craise(stack); |
|
| 26 | - | resize(stack); |
|
| 35 | + | csel->x = sx; |
|
| 36 | + | csel->y = sy; |
|
| 37 | + | csel->w = sw - 2 * csel->border; |
|
| 38 | + | csel->h = sh - 2 * csel->border; |
|
| 39 | + | craise(csel); |
|
| 40 | + | resize(csel); |
|
| 27 | 41 | discard_events(EnterWindowMask); |
|
| 28 | 42 | } |
|
| 29 | 43 | ||
| 30 | 44 | void |
|
| 31 | - | floating(void *aux) |
|
| 45 | + | tag(Arg *arg) |
|
| 46 | + | { |
|
| 47 | + | if(!csel) |
|
| 48 | + | return; |
|
| 49 | + | ||
| 50 | + | if(arg->i == tsel) |
|
| 51 | + | return; |
|
| 52 | + | ||
| 53 | + | if(csel->tags[arg->i]) |
|
| 54 | + | csel->tags[arg->i] = NULL; /* toggle tag */ |
|
| 55 | + | else |
|
| 56 | + | csel->tags[arg->i] = tags[arg->i]; |
|
| 57 | + | arrange(NULL); |
|
| 58 | + | } |
|
| 59 | + | ||
| 60 | + | void |
|
| 61 | + | floating(Arg *arg) |
|
| 32 | 62 | { |
|
| 33 | 63 | Client *c; |
|
| 34 | 64 | ||
| 35 | 65 | arrange = floating; |
|
| 36 | - | for(c = stack; c; c = c->snext) |
|
| 66 | + | if(!csel) |
|
| 67 | + | return; |
|
| 68 | + | for(c = csel; c; c = next(c)) |
|
| 37 | 69 | resize(c); |
|
| 38 | 70 | discard_events(EnterWindowMask); |
|
| 39 | 71 | } |
|
| 40 | 72 | ||
| 41 | 73 | void |
|
| 42 | - | tiling(void *aux) |
|
| 74 | + | tiling(Arg *arg) |
|
| 43 | 75 | { |
|
| 44 | 76 | Client *c; |
|
| 45 | 77 | int n, cols, rows, gw, gh, i, j; |
|
| 46 | 78 | float rt, fd; |
|
| 47 | 79 | ||
| 48 | 80 | arrange = tiling; |
|
| 49 | - | if(!clients) |
|
| 81 | + | if(!csel) |
|
| 50 | 82 | return; |
|
| 51 | - | for(n = 0, c = clients; c; c = c->next, n++); |
|
| 83 | + | for(n = 0, c = csel; c; c = next(c), n++); |
|
| 52 | 84 | rt = sqrt(n); |
|
| 53 | 85 | if(modff(rt, &fd) < 0.5) |
|
| 54 | 86 | rows = floor(rt); |
|
| 62 | 94 | gw = (sw - 2) / cols; |
|
| 63 | 95 | gh = (sh - 2) / rows; |
|
| 64 | 96 | ||
| 65 | - | for(i = j = 0, c = clients; c; c = c->next) { |
|
| 97 | + | for(i = j = 0, c = csel; c; c = next(c)) { |
|
| 66 | 98 | c->x = i * gw; |
|
| 67 | 99 | c->y = j * gh; |
|
| 68 | 100 | c->w = gw; |
|
| 77 | 109 | } |
|
| 78 | 110 | ||
| 79 | 111 | void |
|
| 80 | - | sel(void *aux) |
|
| 112 | + | prevc(Arg *arg) |
|
| 81 | 113 | { |
|
| 82 | - | const char *arg = aux; |
|
| 83 | - | Client *c = NULL; |
|
| 114 | + | Client *c; |
|
| 84 | 115 | ||
| 85 | - | if(!arg || !stack) |
|
| 116 | + | if(!csel) |
|
| 86 | 117 | return; |
|
| 87 | - | if(!strncmp(arg, "next", 5)) |
|
| 88 | - | c = stack->snext ? stack->snext : stack; |
|
| 89 | - | else if(!strncmp(arg, "prev", 5)) |
|
| 90 | - | for(c = stack; c && c->snext; c = c->snext); |
|
| 91 | - | if(!c) |
|
| 92 | - | c = stack; |
|
| 93 | - | craise(c); |
|
| 94 | - | XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w / 2, c->h / 2); |
|
| 95 | - | focus(c); |
|
| 118 | + | ||
| 119 | + | if(!(c = prev(csel))) |
|
| 120 | + | c = prev(cend); |
|
| 121 | + | if(c) { |
|
| 122 | + | craise(c); |
|
| 123 | + | XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w / 2, c->h / 2); |
|
| 124 | + | focus(c); |
|
| 125 | + | } |
|
| 96 | 126 | } |
|
| 97 | 127 | ||
| 98 | 128 | void |
|
| 99 | - | ckill(void *aux) |
|
| 129 | + | nextc(Arg *arg) |
|
| 130 | + | { |
|
| 131 | + | Client *c; |
|
| 132 | + | ||
| 133 | + | if(!csel) |
|
| 134 | + | return; |
|
| 135 | + | ||
| 136 | + | if(!(c = next(csel))) |
|
| 137 | + | c = next(cstart); |
|
| 138 | + | ||
| 139 | + | if(c) { |
|
| 140 | + | craise(c); |
|
| 141 | + | XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w / 2, c->h / 2); |
|
| 142 | + | focus(c); |
|
| 143 | + | } |
|
| 144 | + | } |
|
| 145 | + | ||
| 146 | + | void |
|
| 147 | + | ckill(Arg *arg) |
|
| 100 | 148 | { |
|
| 101 | - | Client *c = stack; |
|
| 149 | + | Client *c = csel; |
|
| 102 | 150 | ||
| 103 | 151 | if(!c) |
|
| 104 | 152 | return; |
|
| 208 | 256 | void |
|
| 209 | 257 | focus(Client *c) |
|
| 210 | 258 | { |
|
| 211 | - | Client **l, *old; |
|
| 212 | - | ||
| 213 | - | old = stack; |
|
| 214 | - | for(l = &stack; *l && *l != c; l = &(*l)->snext); |
|
| 215 | - | if(*l) |
|
| 216 | - | *l = c->snext; |
|
| 217 | - | c->snext = stack; |
|
| 218 | - | stack = c; |
|
| 219 | - | if(old && old != c) { |
|
| 220 | - | XSetWindowBorder(dpy, old->win, dc.bg); |
|
| 221 | - | XMapWindow(dpy, old->title); |
|
| 222 | - | draw_client(old); |
|
| 259 | + | if(csel && csel != c) { |
|
| 260 | + | XSetWindowBorder(dpy, csel->win, dc.bg); |
|
| 261 | + | XMapWindow(dpy, csel->title); |
|
| 262 | + | draw_client(csel); |
|
| 223 | 263 | } |
|
| 264 | + | csel = c; |
|
| 224 | 265 | XUnmapWindow(dpy, c->title); |
|
| 225 | 266 | XSetWindowBorder(dpy, c->win, dc.fg); |
|
| 226 | 267 | draw_client(c); |
|
| 232 | 273 | void |
|
| 233 | 274 | manage(Window w, XWindowAttributes *wa) |
|
| 234 | 275 | { |
|
| 235 | - | Client *c, **l; |
|
| 276 | + | Client *c; |
|
| 236 | 277 | XSetWindowAttributes twa; |
|
| 237 | 278 | ||
| 238 | 279 | c = emallocz(sizeof(Client)); |
|
| 258 | 299 | CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa); |
|
| 259 | 300 | ||
| 260 | 301 | update_name(c); |
|
| 261 | - | for(l=&clients; *l; l=&(*l)->next); |
|
| 262 | - | c->next = *l; /* *l == nil */ |
|
| 263 | - | *l = c; |
|
| 302 | + | ||
| 303 | + | if(!cstart) |
|
| 304 | + | cstart = cend = c; |
|
| 305 | + | else { |
|
| 306 | + | cend->next = c; |
|
| 307 | + | c->prev = cend; |
|
| 308 | + | cend = c; |
|
| 309 | + | } |
|
| 310 | + | ||
| 264 | 311 | XSetWindowBorderWidth(dpy, c->win, 1); |
|
| 265 | 312 | XMapRaised(dpy, c->win); |
|
| 266 | 313 | XMapRaised(dpy, c->title); |
|
| 373 | 420 | void |
|
| 374 | 421 | unmanage(Client *c) |
|
| 375 | 422 | { |
|
| 376 | - | Client **l; |
|
| 377 | - | ||
| 378 | 423 | XGrabServer(dpy); |
|
| 379 | 424 | XSetErrorHandler(dummy_error_handler); |
|
| 380 | 425 | ||
| 381 | 426 | XUngrabButton(dpy, AnyButton, AnyModifier, c->win); |
|
| 382 | 427 | XDestroyWindow(dpy, c->title); |
|
| 383 | 428 | ||
| 384 | - | for(l=&clients; *l && *l != c; l=&(*l)->next); |
|
| 385 | - | *l = c->next; |
|
| 386 | - | for(l=&stack; *l && *l != c; l=&(*l)->snext); |
|
| 387 | - | *l = c->snext; |
|
| 429 | + | if(c->prev) { |
|
| 430 | + | c->prev->next = c->next; |
|
| 431 | + | if(csel == c) |
|
| 432 | + | csel = c->prev; |
|
| 433 | + | } |
|
| 434 | + | if(c->next) { |
|
| 435 | + | c->next->prev = c->prev; |
|
| 436 | + | if(csel == c) |
|
| 437 | + | csel = c->next; |
|
| 438 | + | } |
|
| 439 | + | if(cstart == c) |
|
| 440 | + | cstart = c->next; |
|
| 441 | + | if(cend == c) |
|
| 442 | + | cend = c->prev; |
|
| 443 | + | ||
| 388 | 444 | free(c); |
|
| 389 | 445 | ||
| 390 | 446 | XFlush(dpy); |
|
| 391 | 447 | XSetErrorHandler(error_handler); |
|
| 392 | 448 | XUngrabServer(dpy); |
|
| 393 | 449 | arrange(NULL); |
|
| 394 | - | if(stack) |
|
| 395 | - | focus(stack); |
|
| 450 | + | if(csel) |
|
| 451 | + | focus(csel); |
|
| 396 | 452 | } |
|
| 397 | 453 | ||
| 398 | 454 | Client * |
|
| 399 | 455 | gettitle(Window w) |
|
| 400 | 456 | { |
|
| 401 | 457 | Client *c; |
|
| 402 | - | for(c = clients; c; c = c->next) |
|
| 458 | + | for(c = cstart; c; c = c->next) |
|
| 403 | 459 | if(c->title == w) |
|
| 404 | 460 | return c; |
|
| 405 | 461 | return NULL; |
|
| 409 | 465 | getclient(Window w) |
|
| 410 | 466 | { |
|
| 411 | 467 | Client *c; |
|
| 412 | - | for(c = clients; c; c = c->next) |
|
| 468 | + | for(c = cstart; c; c = c->next) |
|
| 413 | 469 | if(c->win == w) |
|
| 414 | 470 | return c; |
|
| 415 | 471 | return NULL; |
|
| 419 | 475 | draw_client(Client *c) |
|
| 420 | 476 | { |
|
| 421 | 477 | int i; |
|
| 422 | - | if(c == stack) |
|
| 478 | + | if(c == csel) |
|
| 423 | 479 | return; |
|
| 424 | 480 | ||
| 425 | 481 | dc.x = dc.y = 0; |
|
| 20 | 20 | const char *xlock[] = { "xlock", NULL }; |
|
| 21 | 21 | ||
| 22 | 22 | static Key key[] = { |
|
| 23 | - | { Mod1Mask, XK_Return, (void (*)(void *))spawn, term }, |
|
| 24 | - | { Mod1Mask, XK_w, (void (*)(void *))spawn, browse }, |
|
| 25 | - | { Mod1Mask, XK_l, (void (*)(void *))spawn, xlock }, |
|
| 26 | - | { Mod1Mask, XK_k, sel, "prev" }, |
|
| 27 | - | { Mod1Mask, XK_j, sel, "next" }, |
|
| 28 | - | { Mod1Mask, XK_t, tiling, NULL }, |
|
| 29 | - | { Mod1Mask, XK_f, floating, NULL }, |
|
| 30 | - | { Mod1Mask, XK_m, max, NULL }, |
|
| 31 | - | { Mod1Mask | ShiftMask, XK_c, ckill, NULL }, |
|
| 32 | - | { Mod1Mask | ShiftMask, XK_q, quit, NULL }, |
|
| 23 | + | { Mod1Mask, XK_Return, spawn, { .argv = term } }, |
|
| 24 | + | { Mod1Mask, XK_w, spawn, { .argv = browse } }, |
|
| 25 | + | { Mod1Mask, XK_l, spawn, { .argv = xlock } }, |
|
| 26 | + | { Mod1Mask, XK_k, prevc, { 0 } }, |
|
| 27 | + | { Mod1Mask, XK_j, nextc, { 0 } }, |
|
| 28 | + | { Mod1Mask, XK_t, tiling, { 0 } }, |
|
| 29 | + | { Mod1Mask, XK_f, floating, { 0 } }, |
|
| 30 | + | { Mod1Mask, XK_m, max, { 0 } }, |
|
| 31 | + | { Mod1Mask, XK_0, tag, { .i = Tscratch } }, |
|
| 32 | + | { Mod1Mask, XK_1, tag, { .i = Tdev } }, |
|
| 33 | + | { Mod1Mask, XK_2, tag, { .i = Tirc } }, |
|
| 34 | + | { Mod1Mask, XK_3, tag, { .i = Twww } }, |
|
| 35 | + | { Mod1Mask, XK_4, tag, { .i = Twork } }, |
|
| 36 | + | { Mod1Mask | ShiftMask, XK_c, ckill, { 0 } }, |
|
| 37 | + | { Mod1Mask | ShiftMask, XK_q, quit, { 0 } }, |
|
| 33 | 38 | }; |
|
| 34 | 39 | ||
| 35 | 40 | /********** CUSTOMIZE **********/ |
|
| 60 | 65 | for(i = 0; i < len; i++) |
|
| 61 | 66 | if((keysym == key[i].keysym) && (key[i].mod == ev->state)) { |
|
| 62 | 67 | if(key[i].func) |
|
| 63 | - | key[i].func(key[i].aux); |
|
| 68 | + | key[i].func(&key[i].arg); |
|
| 64 | 69 | return; |
|
| 65 | 70 | } |
|
| 66 | 71 | } |
|
| 22 | 22 | typedef struct Client Client; |
|
| 23 | 23 | typedef struct Fnt Fnt; |
|
| 24 | 24 | typedef struct Key Key; |
|
| 25 | + | typedef union Arg Arg; |
|
| 26 | + | ||
| 27 | + | union Arg { |
|
| 28 | + | const char **argv; |
|
| 29 | + | int i; |
|
| 30 | + | }; |
|
| 25 | 31 | ||
| 26 | 32 | /* atoms */ |
|
| 27 | 33 | enum { WMProtocols, WMDelete, WMLast }; |
|
| 62 | 68 | Window trans; |
|
| 63 | 69 | Window title; |
|
| 64 | 70 | Client *next; |
|
| 65 | - | Client *snext; |
|
| 71 | + | Client *prev; |
|
| 66 | 72 | }; |
|
| 67 | 73 | ||
| 68 | 74 | struct Key { |
|
| 69 | 75 | unsigned long mod; |
|
| 70 | 76 | KeySym keysym; |
|
| 71 | - | void (*func)(void *aux); |
|
| 72 | - | void *aux; |
|
| 77 | + | void (*func)(Arg *arg); |
|
| 78 | + | Arg arg; |
|
| 73 | 79 | }; |
|
| 74 | 80 | ||
| 75 | 81 | extern Display *dpy; |
|
| 83 | 89 | extern char stext[1024], *tags[TLast]; |
|
| 84 | 90 | ||
| 85 | 91 | extern DC dc; |
|
| 86 | - | extern Client *clients, *stack; |
|
| 92 | + | extern Client *cstart, *cend, *csel; |
|
| 87 | 93 | ||
| 88 | 94 | /* client.c */ |
|
| 89 | 95 | extern void manage(Window w, XWindowAttributes *wa); |
|
| 97 | 103 | extern Client *gettitle(Window w); |
|
| 98 | 104 | extern void craise(Client *c); |
|
| 99 | 105 | extern void lower(Client *c); |
|
| 100 | - | extern void ckill(void *aux); |
|
| 101 | - | extern void sel(void *aux); |
|
| 102 | - | extern void max(void *aux); |
|
| 103 | - | extern void floating(void *aux); |
|
| 104 | - | extern void tiling(void *aux); |
|
| 106 | + | extern void ckill(Arg *arg); |
|
| 107 | + | extern void nextc(Arg *arg); |
|
| 108 | + | extern void prevc(Arg *arg); |
|
| 109 | + | extern void max(Arg *arg); |
|
| 110 | + | extern void floating(Arg *arg); |
|
| 111 | + | extern void tiling(Arg *arg); |
|
| 112 | + | void tag(Arg *arg); |
|
| 105 | 113 | extern void gravitate(Client *c, Bool invert); |
|
| 106 | 114 | ||
| 107 | 115 | /* draw.c */ |
|
| 125 | 133 | extern int error_handler(Display *dsply, XErrorEvent *e); |
|
| 126 | 134 | extern void send_message(Window w, Atom a, long value); |
|
| 127 | 135 | extern int win_proto(Window w); |
|
| 128 | - | extern void quit(void *aux); |
|
| 136 | + | extern void quit(Arg *arg); |
|
| 129 | 137 | ||
| 130 | 138 | /* util.c */ |
|
| 131 | 139 | extern void error(const char *errstr, ...); |
|
| 133 | 141 | extern void *emalloc(unsigned int size); |
|
| 134 | 142 | extern void *erealloc(void *ptr, unsigned int size); |
|
| 135 | 143 | extern char *estrdup(const char *str); |
|
| 136 | - | extern void spawn(char *argv[]); |
|
| 144 | + | extern void spawn(Arg *arg); |
|
| 137 | 145 | extern void swap(void **p1, void **p2); |
|
| 38 | 38 | int screen, sx, sy, sw, sh, th; |
|
| 39 | 39 | ||
| 40 | 40 | DC dc = {0}; |
|
| 41 | - | Client *clients = NULL; |
|
| 42 | - | Client *stack = NULL; |
|
| 41 | + | Client *cstart = NULL; |
|
| 42 | + | Client *cend = NULL; |
|
| 43 | + | Client *csel = NULL; |
|
| 43 | 44 | ||
| 44 | 45 | static Bool other_wm_running; |
|
| 45 | 46 | static const char version[] = |
|
| 168 | 169 | static void |
|
| 169 | 170 | cleanup() |
|
| 170 | 171 | { |
|
| 171 | - | while(clients) |
|
| 172 | - | unmanage(clients); |
|
| 172 | + | while(csel) |
|
| 173 | + | unmanage(csel); |
|
| 173 | 174 | XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); |
|
| 174 | 175 | } |
|
| 175 | 176 | ||
| 176 | 177 | void |
|
| 177 | - | quit(void *aux) |
|
| 178 | + | quit(Arg *arg) |
|
| 178 | 179 | { |
|
| 179 | 180 | running = False; |
|
| 180 | 181 | } |
|
| 75 | 75 | } |
|
| 76 | 76 | ||
| 77 | 77 | void |
|
| 78 | - | spawn(char *argv[]) |
|
| 78 | + | spawn(Arg *arg) |
|
| 79 | 79 | { |
|
| 80 | + | char **argv = (char **)arg->argv; |
|
| 80 | 81 | if(!argv || !argv[0]) |
|
| 81 | 82 | return; |
|
| 82 | 83 | if(fork() == 0) { |