diff options
Diffstat (limited to 'monsterwm.c')
| -rw-r--r-- | monsterwm.c | 180 |
1 files changed, 108 insertions, 72 deletions
diff --git a/monsterwm.c b/monsterwm.c index f832223..fdb68eb 100644 --- a/monsterwm.c +++ b/monsterwm.c @@ -1,5 +1,5 @@ /* see license for copyright and license */ - +#define _XOPEN_SOURCE #include <stdlib.h> #include <stdio.h> #include <err.h> @@ -8,6 +8,8 @@ #include <string.h> #include <signal.h> #include <sys/wait.h> +#include <time.h> +#include <sys/time.h> #include <X11/Xutil.h> #include <X11/XKBlib.h> #include <X11/Xproto.h> @@ -74,7 +76,7 @@ typedef struct { typedef struct { const char *class; const int desktop; - const Bool follow, floating; + const Bool follow, floating, ignore; } AppRule; /* exposed function prototypes sorted alphabetically */ @@ -85,15 +87,11 @@ static void killclient(); static void last_desktop(); static void move_down(); static void move_up(); -static void moveresize(const Arg *arg); static void mousemotion(const Arg *arg); static void next_win(); static void prev_win(); static void quit(const Arg *arg); static void resize_master(const Arg *arg); -static void resize_stack(const Arg *arg); -static void rotate(const Arg *arg); -static void rotate_filled(const Arg *arg); static void spawn(const Arg *arg); static void swap_master(); static void switch_mode(const Arg *arg); @@ -147,7 +145,7 @@ static void cleanup(void); static void clientmessage(XEvent *e); static void configurerequest(XEvent *e); static void deletewindow(Window w); -static void desktopinfo(void); +static void write_status(void); static void destroynotify(XEvent *e); static void enternotify(XEvent *e); static void focus(Client *c, Desktop *d); @@ -280,7 +278,7 @@ void change_desktop(const Arg *arg) { if (d->curr) XUnmapWindow(dis, d->curr->win); XChangeWindowAttributes(dis, root, CWEventMask, &(XSetWindowAttributes){.event_mask = ROOTMASK}); if (n->head) { tile(n); focus(n->curr, n); } - desktopinfo(); + write_status(); } /** @@ -319,7 +317,7 @@ void client_to_desktop(const Arg *arg) { /* link client to new desktop and make it the current */ focus(l ? (l->next = c):n->head ? (n->head->next = c):(n->head = c), n); - if (FOLLOW_WINDOW) change_desktop(arg); else desktopinfo(); + if (FOLLOW_WINDOW) change_desktop(arg); else write_status(); } /** @@ -404,30 +402,52 @@ void deletewindow(Window w) { } /** - * output info about the desktops on standard output stream - * - * the information is formatted as a space separated line - * where each token contains information about a desktop. - * each token is a formatted as ':' separated string of values. - * the values are: - * - the desktop number/id - * - the desktop's client count - * - the desktop's tiling layout mode/id - * - whether the desktop is the current focused (1) or not (0) - * - whether any client in that desktop has received an urgent hint - * - * once the info is collected, immediately flush the stream + * output status bar */ -void desktopinfo(void) { +void write_status(void) { Desktop *d = NULL; Client *c = NULL; Bool urgent = False; + time_t now; + struct tm *ptm; + char buff[32]; + // Desktops + printf("%%{l}"); for (int w = 0, i = 0; i < DESKTOPS; i++, w = 0, urgent = False) { for (d = &desktops[i], c = d->head; c; urgent |= c->isurgn, ++w, c = c->next); - printf("%d:%d:%d:%d:%d%c", i, w, d->mode, i == currdeskidx, urgent, (i < DESKTOPS - 1) ? ' ':'|'); + if (w>0) { + printf("[%c%d%c] ", urgent ? '!' : ' ', i, i == currdeskidx ? '*' : ' '); + } } - printf("%s\n", desktops[currdeskidx].curr ? desktops[currdeskidx].curr->title : ""); + + // Currently focused window + printf("%%{c}%s\n", desktops[currdeskidx].curr ? desktops[currdeskidx].curr->title : ""); + + // Times + printf("%%{r}"); + now = time(NULL); + + putenv("TZ=PST8PDT"); + ptm = localtime(&now); + strftime(buff, sizeof(buff), "%Z %H:%M", ptm); + printf("%s | ", buff); + + putenv("TZ=America/Chicago"); + ptm = localtime(&now); + strftime(buff, sizeof(buff), "%Z %H:%M", ptm); + printf("%s | ", buff); + + putenv("TZ=UTC"); + ptm = localtime(&now); + strftime(buff, sizeof(buff), "%Z %H:%M", ptm); + printf("%s | ", buff); + + putenv("TZ=Europe/Amsterdam"); + ptm = localtime(&now); + strftime(buff, sizeof(buff), "%Z %H:%M:%S %D", ptm); + printf("%s", buff); + fflush(stdout); } @@ -556,7 +576,7 @@ void focus(Client *c, Desktop *d) { PropModeReplace, (unsigned char *)&d->curr->win, 1); XSync(dis, False); - desktopinfo(); + write_status(); } /** @@ -709,12 +729,21 @@ void maprequest(XEvent *e) { Bool follow = False, floating = False; int newdsk = currdeskidx; - if (XGetClassHint(dis, w, &ch)) for (unsigned int i = 0; i < LENGTH(rules); i++) - if (strstr(ch.res_class, rules[i].class) || strstr(ch.res_name, rules[i].class)) { - if (rules[i].desktop >= 0 && rules[i].desktop < DESKTOPS) newdsk = rules[i].desktop; - follow = rules[i].follow, floating = rules[i].floating; - break; + if (XGetClassHint(dis, w, &ch)) { + for (unsigned int i = 0; i < LENGTH(rules); i++) { + if (strstr(ch.res_class, rules[i].class) || strstr(ch.res_name, rules[i].class)) { + if (rules[i].desktop >= 0 && rules[i].desktop < DESKTOPS) newdsk = rules[i].desktop; + follow = rules[i].follow; + floating = rules[i].floating; + if (rules[i].ignore) { + if (ch.res_class) XFree(ch.res_class); + if (ch.res_name) XFree(ch.res_name); + return; + } + break; + } } + } if (ch.res_class) XFree(ch.res_class); if (ch.res_name) XFree(ch.res_name); @@ -740,7 +769,7 @@ void maprequest(XEvent *e) { else if (follow) change_desktop(&(Arg){.i = newdsk}); focus(c, d); - if (!follow) desktopinfo(); + if (!follow) write_status(); } /** @@ -775,17 +804,39 @@ void mousemotion(const Arg *arg) { if (!d->curr->isfloat && !d->curr->istrans) { d->curr->isfloat = True; tile(d); focus(d->curr, d); } + /* init rectangle properties */ + XGCValues gv = { .function = GXinvert, .subwindow_mode = IncludeInferiors, .line_width = BORDER_WIDTH }; + GC gc = XCreateGC(dis, root, GCFunction|GCSubwindowMode|GCLineWidth, &gv); + + /* draw rectangle */ + if (arg->i == MOVE) XDrawRectangle(dis, root, gc, xw = wa.x, yh = wa.y, wa.width, wa.height); + else XDrawRectangle(dis, root, gc, wa.x, wa.y, xw = wa.width, yh = wa.height); + do { XMaskEvent(dis, BUTTONMASK|PointerMotionMask|SubstructureRedirectMask, &ev); if (ev.type == MotionNotify) { + /* clear rectangle from prev position */ + if (arg->i == MOVE) XDrawRectangle(dis, root, gc, xw, yh, wa.width, wa.height); + else if (arg->i == RESIZE) XDrawRectangle(dis, root, gc, wa.x, wa.y, xw, yh); + xw = (arg->i == MOVE ? wa.x:wa.width) + ev.xmotion.x - rx; yh = (arg->i == MOVE ? wa.y:wa.height) + ev.xmotion.y - ry; - if (arg->i == RESIZE) XResizeWindow(dis, d->curr->win, - xw > MINWSZ ? xw:wa.width, yh > MINWSZ ? yh:wa.height); - else if (arg->i == MOVE) XMoveWindow(dis, d->curr->win, xw, yh); + + /* draw rectangle in new position */ + if (arg->i == MOVE) XDrawRectangle(dis, root, gc, xw, yh, wa.width, wa.height); + else if (arg->i == RESIZE) XDrawRectangle(dis, root, gc, wa.x, wa.y, xw, yh); } else if (ev.type == ConfigureRequest || ev.type == MapRequest) events[ev.type](&ev); } while (ev.type != ButtonRelease); + /* clear rectangle from last position */ + if (arg->i == MOVE) XDrawRectangle(dis, root, gc, xw, yh, wa.width, wa.height); + else if (arg->i == RESIZE) XDrawRectangle(dis, root, gc, wa.x, wa.y, xw, yh); + + /* actually move/resize the window to the new position/size */ + if (arg->i == RESIZE) XResizeWindow(dis, d->curr->win, + xw > MINWSZ ? xw:wa.width, yh > MINWSZ ? yh:wa.height); + else if (arg->i == MOVE) XMoveWindow(dis, d->curr->win, xw, yh); + XUngrabPointer(dis, CurrentTime); } @@ -877,17 +928,6 @@ void move_up(void) { if (!d->curr->isfloat && !d->curr->istrans) tile(d); } -/** - * move and resize a window with the keyboard - */ -void moveresize(const Arg *arg) { - Desktop *d = &desktops[currdeskidx]; - XWindowAttributes wa; - if (!d->curr || !XGetWindowAttributes(dis, d->curr->win, &wa)) return; - if (!d->curr->isfloat && !d->curr->istrans) { d->curr->isfloat = True; tile(d); focus(d->curr, d); } - XMoveResizeWindow(dis, d->curr->win, wa.x + ((int *)arg->v)[0], wa.y + ((int *)arg->v)[1], - wa.width + ((int *)arg->v)[2], wa.height + ((int *)arg->v)[3]); -} /** * cyclic focus the next window @@ -936,7 +976,7 @@ void propertynotify(XEvent *e) { c->title[sizeof(c->title) - 1] = '\0'; if (name.value) XFree(name.value); } - desktopinfo(); + write_status(); } /** @@ -962,7 +1002,7 @@ void removeclient(Client *c, Desktop *d) { if (c == d->curr || (d->head && !d->head->next)) focus(d->prev, d); if (!(c->isfloat || c->istrans) || (d->head && !d->head->next)) tile(d); free(c); - desktopinfo(); + write_status(); } /** @@ -978,36 +1018,33 @@ void resize_master(const Arg *arg) { } /** - * resize the first stack window + * main event loop + * on receival of an event call the appropriate handler */ -void resize_stack(const Arg *arg) { - desktops[currdeskidx].sasz += arg->i; - tile(&desktops[currdeskidx]); -} -/** - * jump and focus the next or previous desktop - */ -void rotate(const Arg *arg) { - change_desktop(&(Arg){.i = (DESKTOPS + currdeskidx + arg->i) % DESKTOPS}); + +// check if FD has been updated within last second +static int wait_fd(int fd) { + struct timeval tv = { .tv_sec = 1, .tv_usec = 0}; + fd_set in_fds; FD_ZERO(&in_fds); FD_SET(fd, &in_fds); + return select(fd+1, &in_fds, 0, 0, &tv); } -/** - * jump and focus the next non-empty desktop - */ -void rotate_filled(const Arg *arg) { - int n = arg->i; - while (n < DESKTOPS && !desktops[(DESKTOPS + currdeskidx + n) % DESKTOPS].head) (n += arg->i); - change_desktop(&(Arg){.i = (DESKTOPS + currdeskidx + n) % DESKTOPS}); +// Like XNextEvent, except that it waits at most a second +int XNextEventTimeout(XEvent *event) { + if (XPending(dis) || wait_fd(ConnectionNumber(dis))) { + XNextEvent(dis, event); + return 0; + } + return 1; } -/** - * main event loop - * on receival of an event call the appropriate handler - */ void run(void) { XEvent ev; - while(running && !XNextEvent(dis, &ev)) if (events[ev.type]) events[ev.type](&ev); + while(running) { + if (!XNextEventTimeout(&ev) && events[ev.type]) events[ev.type](&ev); + write_status(); + } } /** @@ -1188,7 +1225,7 @@ void switch_mode(const Arg *arg) { if (d->mode != arg->i) d->mode = arg->i; else if (d->mode != FLOAT) for (Client *c = d->head; c; c = c->next) c->isfloat = False; if (d->head) { tile(d); focus(d->curr, d); } - desktopinfo(); + write_status(); } /** @@ -1257,7 +1294,6 @@ int main(int argc, char *argv[]) { else if (argc != 1) errx(EXIT_FAILURE, "usage: man monsterwm"); if (!(dis = XOpenDisplay(NULL))) errx(EXIT_FAILURE, "cannot open display"); setup(); - desktopinfo(); /* zero out every desktop on (re)start */ run(); cleanup(); XCloseDisplay(dis); |
