aboutsummaryrefslogtreecommitdiff
path: root/monsterwm.c
diff options
context:
space:
mode:
authortslil clingman <tslil@posteo.de>2022-10-09 17:12:37 +0200
committertslil clingman <tslil@posteo.de>2022-10-09 17:43:58 +0200
commitc565c09250f3b1cec255bc1f36a0b373a92467cd (patch)
tree4515907178f762eaaf3e91dc512cc969541ba974 /monsterwm.c
parentbe7782eb232d3703831ae86ade3699aace3661d0 (diff)
write status for lemonbar periodically, remove unused functions, add ignore to AppRule, use titles, rectangle
Diffstat (limited to 'monsterwm.c')
-rw-r--r--monsterwm.c180
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);