#include <stdlib.h>
#include <err.h>
#include <errno.h>
+#include <fcntl.h>
#include <locale.h>
#include <unistd.h>
#include <time.h>
#define SWM_D_MOVE 0x0010
#define SWM_D_STACK 0x0020
#define SWM_D_MOUSE 0x0040
+#define SWM_D_PROP 0x0080
+
u_int32_t swm_debug = 0
| SWM_D_MISC
| SWM_D_FOCUS
| SWM_D_MOVE
| SWM_D_STACK
+ | SWM_D_PROP
;
#else
#define DPRINTF(x...)
#define WIDTH(r) (r)->g.w
#define HEIGHT(r) (r)->g.h
+#ifndef SWM_LIB
+#define SWM_LIB "/usr/X11R6/lib/swmhack.so"
+#endif
+
+#define SWM_PROPLEN (16)
+
char **start_argv;
Atom astate;
int (*xerrorxlib)(Display *, XErrorEvent *);
double dialog_ratio = .6;
/* status bar */
#define SWM_BAR_MAX (128)
+char *bar_argv[] = { NULL, NULL };
+int bar_pipe[2];
+char bar_ext[SWM_BAR_MAX];
sig_atomic_t bar_alarm = 0;
+int bar_delay = 30;
int bar_enabled = 1;
+int bar_extra = 1;
+int bar_extra_running = 0;
int bar_verbose = 1;
int bar_height = 0;
+pid_t bar_pid;
GC bar_gc;
XGCValues bar_gcv;
int bar_fidx = 0;
NULL
};
-
-
/* terminal + args */
-char *spawn_term[] = { "xterm", NULL };
-char *spawn_menu[] = { "dmenu_run", "-fn", NULL,
- "-nb", NULL, "-nf", NULL, "-sb", NULL, "-sf", NULL, NULL };
+char *spawn_term[] = { "xterm", NULL };
+char *spawn_menu[] = { "dmenu_run", "-fn", NULL,
+ "-nb", NULL, "-nf", NULL, "-sb", NULL, "-sf", NULL, NULL };
#define SWM_MENU_FN (2)
#define SWM_MENU_NB (4)
};
TAILQ_HEAD(swm_region_list, swm_region);
-
struct ws_win {
TAILQ_ENTRY(ws_win) entry;
Window id;
} l_state;
};
-
enum { SWM_S_COLOR_BAR, SWM_S_COLOR_BAR_BORDER, SWM_S_COLOR_BAR_FONT,
SWM_S_COLOR_FOCUS, SWM_S_COLOR_UNFOCUS, SWM_S_COLOR_MAX };
if (!strncmp(var, "bar_enabled", strlen("bar_enabled")))
bar_enabled = atoi(val);
else if (!varmatch(var, "bar_border", &i))
- setscreencolor(var, i, SWM_S_COLOR_BAR_BORDER);
+ setscreencolor(val, i, SWM_S_COLOR_BAR_BORDER);
else if (!varmatch(var, "bar_color", &i))
- setscreencolor(var, i, SWM_S_COLOR_BAR);
+ setscreencolor(val, i, SWM_S_COLOR_BAR);
else if (!varmatch(var, "bar_font_color", &i))
- setscreencolor(var, i, SWM_S_COLOR_BAR_FONT);
+ setscreencolor(val, i, SWM_S_COLOR_BAR_FONT);
else if (!strncmp(var, "bar_font", strlen("bar_font")))
asprintf(&bar_fonts[0], "%s", val);
+ else if (!strncmp(var, "bar_action", strlen("bar_action")))
+ asprintf(&bar_argv[0], "%s", val);
+ else if (!strncmp(var, "bar_delay", strlen("bar_delay")))
+ bar_delay = atoi(val);
else
goto bad;
break;
case 'c':
if (!varmatch(var, "color_focus", &i))
- setscreencolor(var, i, SWM_S_COLOR_FOCUS);
+ setscreencolor(val, i, SWM_S_COLOR_FOCUS);
else if (!varmatch(var, "color_unfocus", &i))
- setscreencolor(var, i, SWM_S_COLOR_UNFOCUS);
+ setscreencolor(val, i, SWM_S_COLOR_UNFOCUS);
else if (!strncmp(var, "cycle_empty", strlen("cycle_empty")))
cycle_visible = atoi(val);
else if (!strncmp(var, "cycle_visible", strlen("cycle_visible")))
}
void
+socket_setnonblock(int fd)
+{
+ int flags;
+
+ if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
+ err(1, "fcntl F_GETFL");
+ flags |= O_NONBLOCK;
+ if ((flags = fcntl(fd, F_SETFL, flags)) == -1)
+ err(1, "fcntl F_SETFL");
+}
+
+void
bar_print(struct swm_region *r, char *s)
{
XClearWindow(display, r->bar_window);
}
void
+bar_extra_stop(void)
+{
+ if (bar_pipe[0]) {
+ close(bar_pipe[0]);
+ bzero(bar_pipe, sizeof bar_pipe);
+ }
+ if (bar_pid) {
+ kill(bar_pid, SIGTERM);
+ bar_pid = 0;
+ }
+ strlcpy(bar_ext, "", sizeof bar_ext);
+ bar_extra = 0;
+}
+
+void
bar_update(void)
{
time_t tmt;
struct tm tm;
struct swm_region *r;
int i, x;
+ size_t len;
char s[SWM_BAR_MAX];
- char e[SWM_BAR_MAX];
-
+ char loc[SWM_BAR_MAX];
+ char *b;
+
if (bar_enabled == 0)
return;
+ if (bar_extra && bar_extra_running) {
+ /* ignore short reads; it'll correct itself */
+ while ((b = fgetln(stdin, &len)) != NULL)
+ if (b && b[len - 1] == '\n') {
+ b[len - 1] = '\0';
+ strlcpy(bar_ext, b, sizeof bar_ext);
+ }
+ if (b == NULL && errno != EAGAIN) {
+ fprintf(stderr, "bar_extra failed: errno: %d %s\n",
+ errno, strerror(errno));
+ bar_extra_stop();
+ }
+ } else
+ strlcpy(bar_ext, "", sizeof bar_ext);
+
time(&tmt);
localtime_r(&tmt, &tm);
strftime(s, sizeof s, "%a %b %d %R %Z %Y", &tm);
for (i = 0; i < ScreenCount(display); i++) {
x = 1;
TAILQ_FOREACH(r, &screens[i].rl, entry) {
- snprintf(e, sizeof e, "%s %d:%d",
- s, x++, r->ws->idx + 1);
- bar_print(r, e);
+ snprintf(loc, sizeof loc, "%s %d:%d %s",
+ s, x++, r->ws->idx + 1, bar_ext);
+ bar_print(r, loc);
}
}
XSync(display, False);
- alarm(60);
+ alarm(bar_delay);
}
void
}
void
+bar_refresh(void)
+{
+ XSetWindowAttributes wa;
+ struct swm_region *r;
+ int i;
+
+ /* do this here because the conf file is in memory */
+ if (bar_extra && bar_extra_running == 0 && bar_argv[0]) {
+ /* launch external status app */
+ bar_extra_running = 1;
+ if (pipe(bar_pipe) == -1)
+ err(1, "pipe error");
+ socket_setnonblock(bar_pipe[0]);
+ socket_setnonblock(bar_pipe[1]); /* XXX hmmm, really? */
+ if (dup2(bar_pipe[0], 0) == -1)
+ errx(1, "dup2");
+ if (dup2(bar_pipe[1], 1) == -1)
+ errx(1, "dup2");
+ if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
+ err(1, "could not disable SIGPIPE");
+ switch (bar_pid = fork()) {
+ case -1:
+ err(1, "cannot fork");
+ break;
+ case 0: /* child */
+ close(bar_pipe[0]);
+ execvp(bar_argv[0], bar_argv);
+ err(1, "%s external app failed", bar_argv[0]);
+ break;
+ default: /* parent */
+ close(bar_pipe[1]);
+ break;
+ }
+ }
+
+ bzero(&wa, sizeof wa);
+ for (i = 0; i < ScreenCount(display); i++)
+ TAILQ_FOREACH(r, &screens[i].rl, entry) {
+ wa.border_pixel =
+ screens[i].c[SWM_S_COLOR_BAR_BORDER].color;
+ wa.background_pixel =
+ screens[i].c[SWM_S_COLOR_BAR].color;
+ XChangeWindowAttributes(display, r->bar_window,
+ CWBackPixel | CWBorderPixel, &wa);
+ }
+ bar_update();
+}
+
+void
bar_setup(struct swm_region *r)
{
int i;
if (signal(SIGALRM, bar_signal) == SIG_ERR)
err(1, "could not install bar_signal");
- bar_update();
-}
-
-void
-bar_refresh(void)
-{
- XSetWindowAttributes wa;
- struct swm_region *r;
- int i;
-
- bzero(&wa, sizeof wa);
- for (i = 0; i < ScreenCount(display); i++)
- TAILQ_FOREACH(r, &screens[i].rl, entry) {
- wa.border_pixel =
- screens[i].c[SWM_S_COLOR_BAR_BORDER].color;
- wa.background_pixel =
- screens[i].c[SWM_S_COLOR_BAR].color;
- XChangeWindowAttributes(display, r->bar_window,
- CWBackPixel | CWBorderPixel, &wa);
- }
- bar_update();
+ bar_refresh();
}
void
if (signal(SIGALRM, SIG_IGN) == SIG_ERR)
errx(1, "can't disable alarm");
+ bar_extra_stop();
+ bar_extra = 1;
XCloseDisplay(display);
execvp(start_argv[0], start_argv);
fprintf(stderr, "execvp failed\n");
} else {
/* otherwise, choose a region based on pointer location */
TAILQ_FOREACH(r, &screens[i].rl, entry) {
- if (x > X(r) && x < X(r) + WIDTH(r) &&
- y > Y(r) && y < Y(r) + HEIGHT(r))
+ if (x >= X(r) && x <= X(r) + WIDTH(r) &&
+ y >= Y(r) && y <= Y(r) + HEIGHT(r))
break;
}
*/
if (fork() == 0) {
if (fork() == 0) {
+ char *ret;
if (display)
close(ConnectionNumber(display));
+ setenv("LD_PRELOAD", SWM_LIB, 1);
+ if (asprintf(&ret, "%d", r->ws->idx))
+ setenv("_SWM_WS", ret, 1);
+ if (asprintf(&ret, "%d", getpid()))
+ setenv("_SWM_PID", ret, 1);
setsid();
execvp(args->argv[0], args->argv);
fprintf(stderr, "execvp failed\n");
wait(0);
}
-
void
spawnmenu(struct swm_region *r, union arg *args)
{
XConfigureWindow(display, win->id, mask, &wc);
}
-
void
vertical_config(struct workspace *ws, int id)
{
win->g.h = wc.height = gg.h;
mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
XConfigureWindow(display, win->id, mask, &wc);
+ /*
+ fprintf(stderr, "vertical_stack: win %d x %d y %d w %d h %d bw %d\n", win->id, win->g.x, win->g.y, win->g.w , win->g.h, wc.border_width);
+ */
}
XMapRaised(display, win->id);
focus_win(winfocus); /* has to be done outside of the loop */
}
-
void
horizontal_config(struct workspace *ws, int id)
{
int wsid = args->id;
struct ws_win *win = cur_focus;
struct workspace *ws, *nws;
+ Atom ws_idx_atom = 0;
+ unsigned char ws_idx_str[SWM_PROPLEN];
DNPRINTF(SWM_D_MOVE, "send_to_ws: win: %lu\n", win->id);
TAILQ_INSERT_TAIL(&nws->winlist, win, entry);
win->ws = nws;
+ /* Try to update the window's workspace property */
+ ws_idx_atom = XInternAtom(display, "_SWM_WS", False);
+ if (ws_idx_atom &&
+ snprintf(ws_idx_str, SWM_PROPLEN, "%d", nws->idx) < SWM_PROPLEN) {
+ DNPRINTF(SWM_D_PROP, "setting property _SWM_WS to %s\n",
+ ws_idx_str);
+ XChangeProperty(display, win->id, ws_idx_atom, XA_STRING, 8,
+ PropModeReplace, ws_idx_str, SWM_PROPLEN);
+ }
+
if (count_win(nws, 1) == 1)
nws->focus = win;
ws->restack = 1;
stack();
}
+void
+wkill(struct swm_region *r, union arg *args)
+{
+ DNPRINTF(SWM_D_MISC, "wkill\n");
+ if(r->ws->focus != NULL)
+ XKillClient(display, r->ws->focus->id);
+}
+
/* key definitions */
struct key {
unsigned int mod;
{ MODKEY, XK_b, bar_toggle, {0} },
{ MODKEY, XK_Tab, focus, {.id = SWM_ARG_ID_FOCUSNEXT} },
{ MODKEY | ShiftMask, XK_Tab, focus, {.id = SWM_ARG_ID_FOCUSPREV} },
+ { MODKEY | ShiftMask, XK_x, wkill, {0} },
};
void
}
struct ws_win *
-manage_window(Window id, struct workspace *ws)
+manage_window(Window id)
{
Window trans;
+ struct workspace *ws;
struct ws_win *win;
XClassHint ch;
+ int format;
+ unsigned long nitems, bytes;
+ Atom ws_idx_atom = 0, type;
+ unsigned char ws_idx_str[SWM_PROPLEN], *prop = NULL;
+ struct swm_region *r;
- TAILQ_FOREACH(win, &ws->winlist, entry) {
- if (win->id == id)
+ if ((win = find_window(id)) != NULL)
return (win); /* already being managed */
- }
if ((win = calloc(1, sizeof(struct ws_win))) == NULL)
errx(1, "calloc: failed to allocate memory for new window");
+ ws_idx_atom = XInternAtom(display, "_SWM_WS", False);
+ if (ws_idx_atom)
+ XGetWindowProperty(display, id, ws_idx_atom, 0, SWM_PROPLEN,
+ False, XA_STRING, &type, &format, &nitems, &bytes, &prop);
+
+ XGetWindowAttributes(display, id, &win->wa);
+ r = root_to_region(win->wa.root);
+ /* If the window was managed before, put it in the same workspace */
+ if (prop) {
+ int ws_idx;
+ const char *errstr;
+
+ DNPRINTF(SWM_D_PROP, "got property _SWM_WS=%s\n", prop);
+ ws_idx = strtonum(prop, 0, 9, &errstr);
+ if (errstr)
+ DNPRINTF(SWM_D_EVENT, "window idx is %s: %s",
+ errstr, prop);
+ ws = &r->s->ws[ws_idx];
+ } else
+ ws = r->ws;
+
win->id = id;
win->ws = ws;
- win->s = ws->r->s; /* this never changes */
+ win->s = r->s; /* this never changes */
TAILQ_INSERT_TAIL(&ws->winlist, win, entry);
/* make new win focused */
DNPRINTF(SWM_D_MISC, "manage_window: win %u transient %u\n",
(unsigned)win->id, win->transient);
}
- XGetWindowAttributes(display, id, &win->wa);
win->g.w = win->wa.width;
win->g.h = win->wa.height;
win->g.x = win->wa.x;
win->g.y = win->wa.y;
+ if (ws_idx_atom && prop == NULL &&
+ snprintf(ws_idx_str, SWM_PROPLEN, "%d", ws->idx) < SWM_PROPLEN) {
+ DNPRINTF(SWM_D_PROP, "setting property _SWM_WS to %s\n",
+ ws_idx_str);
+ XChangeProperty(display, win->id, ws_idx_atom, XA_STRING, 8,
+ PropModeReplace, ws_idx_str, SWM_PROPLEN);
+ }
+ XFree(prop);
+
+ /*
+ fprintf(stderr, "manage window: %d x %d y %d w %d h %d\n", win->id, win->g.x, win->g.y, win->g.w, win->g.h);
+ */
+
/* XXX make this a table */
bzero(&ch, sizeof ch);
if (XGetClassHint(display, win->id, &ch)) {
{
XConfigureRequestEvent *ev = &e->xconfigurerequest;
struct ws_win *win;
- int new = 1;
+ int new = 0;
XWindowChanges wc;
if ((win = find_window(ev->window)) == NULL)
if (new) {
DNPRINTF(SWM_D_EVENT, "configurerequest: new window: %lu\n",
ev->window);
+ /*
+ fprintf(stderr, "configurerequest: new window: %lu x %d y %d w %d h %d bw %d s %d sm %d\n",
+ ev->window, ev->x, ev->y, ev->width, ev->height, ev->border_width, ev->above, ev->detail);
+ */
bzero(&wc, sizeof wc);
wc.x = ev->x;
wc.y = ev->y;
wc.stack_mode = ev->detail;
XConfigureWindow(display, ev->window, ev->value_mask, &wc);
} else {
+ /*
+ fprintf(stderr, "configurerequest: change window: %lu\n",
+ ev->window);
+ */
DNPRINTF(SWM_D_EVENT, "configurerequest: change window: %lu\n",
ev->window);
if (win->floating) {
{
XMapRequestEvent *ev = &e->xmaprequest;
XWindowAttributes wa;
- struct swm_region *r;
DNPRINTF(SWM_D_EVENT, "maprequest: window: %lu\n",
e->xmaprequest.window);
return;
if (wa.override_redirect)
return;
- r = root_to_region(wa.root);
- manage_window(e->xmaprequest.window, r->ws);
+ manage_window(e->xmaprequest.window);
stack();
}
int ncrtc = 0, w = 0;
int i, j, k;
struct workspace *ws;
+ int ws_idx_atom;
+
if ((screens = calloc(ScreenCount(display),
sizeof(struct swm_screen))) == NULL)
errx(1, "calloc: screens");
+ ws_idx_atom = XInternAtom(display, "_SWM_WS", False);
+
+
/* map physical screens */
for (i = 0; i < ScreenCount(display); i++) {
DNPRINTF(SWM_D_WS, "setup_screens: init screen %d\n", i);
else
ncrtc = sr->ncrtc;
- for (c = 0; c < ncrtc; c++) {
+ for (c = 0, ci = NULL; c < ncrtc; c++) {
ci = XRRGetCrtcInfo(display, sr, sr->crtcs[c]);
if (ci->noutput == 0)
continue;
ci->x, ci->y, ci->width, ci->height);
w++;
}
- XRRFreeCrtcInfo(ci);
+ if (ci)
+ XRRFreeCrtcInfo(ci);
XRRFreeScreenResources(sr);
#else
new_region(&screens[i], &screens[i].ws[w], 0, 0,
if (wa.map_state == IsViewable ||
getstate(wins[i]) == NormalState)
- manage_window(wins[i], r->ws);
+ manage_window(wins[i]);
}
/* transient windows */
for (i = 0; i < no; i++) {
if (XGetTransientForHint(display, wins[i], &d1) &&
(wa.map_state == IsViewable || getstate(wins[i]) ==
NormalState))
- manage_window(wins[i], r->ws);
+ manage_window(wins[i]);
}
if (wins) {
XFree(wins);