#include <stdio.h>
#include <stdlib.h>
#include <err.h>
+#include <errno.h>
#include <locale.h>
#include <unistd.h>
#include <time.h>
#include <pwd.h>
#include <sys/types.h>
+#include <sys/time.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/queue.h>
#include <sys/param.h>
+#include <sys/select.h>
#include <X11/cursorfont.h>
#include <X11/keysym.h>
/* dialog windows */
double dialog_ratio = .6;
/* status bar */
+#define SWM_BAR_MAX (128)
+sig_atomic_t bar_alarm = 0;
int bar_enabled = 1;
+int bar_verbose = 1;
int bar_height = 0;
GC bar_gc;
XGCValues bar_gcv;
XFontStruct *bar_fs;
-char bar_text[128];
char *bar_fonts[] = {
"-*-terminus-*-*-*-*-*-*-*-*-*-*-*-*",
"-*-times-medium-r-*-*-*-*-*-*-*-*-*-*",
/* layout handlers */
void stack(void);
void vertical_init(struct workspace *);
-void vertical_resize(int);
+void vertical_resize(struct workspace *, int);
void vertical_stack(struct workspace *, struct swm_geometry *);
void horizontal_init(struct workspace *);
-void horizontal_resize(int);
+void horizontal_resize(struct workspace *, int);
void horizontal_stack(struct workspace *, struct swm_geometry *);
void max_init(struct workspace *);
void max_stack(struct workspace *, struct swm_geometry *);
struct layout {
void (*l_init)(struct workspace *); /* init/reset */
void (*l_stack)(struct workspace *, struct swm_geometry *);
- void (*l_resize)(int);
+ void (*l_resize)(struct workspace *, int);
} layouts[] = {
/* init stack, resize */
{ vertical_init, vertical_stack, vertical_resize},
unsigned long bar_font_color;
unsigned long color_focus; /* XXX should this be per ws? */
unsigned long color_unfocus;
+ char bar_text[SWM_BAR_MAX];
};
struct swm_screen *screens;
int num_screens;
+Window rootclick = 0;
struct ws_win *cur_focus = NULL;
}
void
-bar_print(struct swm_region *r)
+bar_print(struct swm_region *r, char *s, int erase)
+{
+ if (erase) {
+ XSetForeground(display, bar_gc, r->s->bar_color);
+ XDrawString(display, r->bar_window, bar_gc, 4, bar_fs->ascent,
+ r->s->bar_text, strlen(r->s->bar_text));
+ }
+
+ strlcpy(r->s->bar_text, s, sizeof r->s->bar_text);
+ XSetForeground(display, bar_gc, r->s->bar_font_color);
+ XDrawString(display, r->bar_window, bar_gc, 4, bar_fs->ascent,
+ r->s->bar_text, strlen(r->s->bar_text));
+}
+
+void
+bar_update(void)
{
time_t tmt;
struct tm tm;
-
+ struct swm_region *r;
+ int i;
+ char s[SWM_BAR_MAX];
+
if (bar_enabled == 0)
return;
- /* clear old text */
- XSetForeground(display, bar_gc, r->s->bar_color);
- XDrawString(display, r->bar_window,
- bar_gc, 4, bar_fs->ascent, bar_text, strlen(bar_text));
-
/* draw new text */
time(&tmt);
localtime_r(&tmt, &tm);
- strftime(bar_text, sizeof bar_text, "%a %b %d %R %Z %Y", &tm);
- XSetForeground(display, bar_gc, r->s->bar_font_color);
- XDrawString(display, r->bar_window, bar_gc, 4,
- bar_fs->ascent, bar_text, strlen(bar_text));
- XSync(display, False);
+ strftime(s, sizeof s, "%a %b %d %R %Z %Y", &tm);
+ for (i = 0; i < ScreenCount(display); i++)
+ TAILQ_FOREACH(r, &screens[i].rl, entry)
+ bar_print(r, s, 1);
+ XSync(display, False);
alarm(60);
}
void
bar_signal(int sig)
{
- /* XXX yeah yeah byte me */
- if (cur_focus)
- bar_print(cur_focus->ws->r);
+ bar_alarm = 1;
}
void
-bar_toggle(union arg *args)
+bar_toggle(struct swm_region *r, union arg *args)
{
- struct swm_region *r;
- int i, j;
+ struct swm_region *tmpr;
+ int i, j;
DNPRINTF(SWM_D_MISC, "bar_toggle\n");
if (bar_enabled) {
for (i = 0; i < ScreenCount(display); i++)
- TAILQ_FOREACH(r, &screens[i].rl, entry)
- XUnmapWindow(display, r->bar_window);
+ TAILQ_FOREACH(tmpr, &screens[i].rl, entry)
+ XUnmapWindow(display, tmpr->bar_window);
} else {
for (i = 0; i < ScreenCount(display); i++)
- TAILQ_FOREACH(r, &screens[i].rl, entry)
- XMapRaised(display, r->bar_window);
+ TAILQ_FOREACH(tmpr, &screens[i].rl, entry)
+ XMapRaised(display, tmpr->bar_window);
}
bar_enabled = !bar_enabled;
XSync(display, False);
stack();
/* must be after stack */
for (i = 0; i < ScreenCount(display); i++)
- TAILQ_FOREACH(r, &screens[i].rl, entry)
- bar_print(r);
+ TAILQ_FOREACH(tmpr, &screens[i].rl, entry)
+ bar_update();
}
void
bar_height = bar_fs->ascent + bar_fs->descent + 3;
r->bar_window = XCreateSimpleWindow(display,
- r->s->root, X(r), Y(r), WIDTH(r), bar_height - 2,
+ r->s->root, X(r), Y(r), WIDTH(r) - 2, bar_height - 2,
1, r->s->bar_border, r->s->bar_color);
bar_gc = XCreateGC(display, r->bar_window, 0, &bar_gcv);
XSetFont(display, bar_gc, bar_fs->fid);
if (signal(SIGALRM, bar_signal) == SIG_ERR)
err(1, "could not install bar_signal");
- bar_print(r);
+ bar_update();
}
void
}
void
-quit(union arg *args)
+quit(struct swm_region *r, union arg *args)
{
DNPRINTF(SWM_D_MISC, "quit\n");
running = 0;
}
void
-restart(union arg *args)
+restart(struct swm_region *r, union arg *args)
{
DNPRINTF(SWM_D_MISC, "restart: %s\n", start_argv[0]);
+ /* disable alarm because the following code may not be interrupted */
+ alarm(0);
+ if (signal(SIGALRM, SIG_IGN) == SIG_ERR)
+ errx(1, "can't disable alarm");
+
XCloseDisplay(display);
execvp(start_argv[0], start_argv);
fprintf(stderr, "execvp failed\n");
perror(" failed");
- quit(NULL);
+ quit(NULL, NULL);
}
struct swm_region *
-cur_region(void)
+root_to_region(Window root)
{
- if (cur_focus && cur_focus->ws->r) {
- return (cur_focus->ws->r);
- } else {
- /* XXX get region from pointer */
- int i;
- struct swm_region *r;
- for (i = 0; i < ScreenCount(display); i++)
- if ((r = TAILQ_FIRST(&screens[i].rl)) != NULL)
- return (r);
- }
-errx(1, "cur_region: no regions!?!?!\n");
-}
+ struct swm_region *r;
+ Window rr, cr;
+ int i, x, y, wx, wy;
+ unsigned int mask;
-struct workspace *
-cur_ws(void)
-{
- return (cur_region()->ws);
+ for (i = 0; i < ScreenCount(display); i++)
+ if (screens[i].root == root)
+ break;
+
+ if (rootclick != root && /* if root was just clicked in, use cursor */
+ cur_focus && cur_focus->ws->r && cur_focus->s == &screens[i])
+ r = cur_focus->ws->r;
+ else {
+ if (XQueryPointer(display, screens[i].root,
+ &rr, &cr, &x, &y, &wx, &wy, &mask) == False) {
+ r = TAILQ_FIRST(&screens[i].rl);
+ } else {
+ TAILQ_FOREACH(r, &screens[i].rl, entry) {
+ if (x > X(r) && x < X(r) + WIDTH(r) &&
+ y > Y(r) && y < Y(r) + HEIGHT(r))
+ break;
+ }
+
+ if (r == NULL)
+ r = TAILQ_FIRST(&screens[i].rl);
+ }
+ }
+ return (r);
}
struct ws_win *
find_window(Window id)
{
- struct ws_win *win;
- int i, j;
+ struct ws_win *win;
+ int i, j;
for (i = 0; i < ScreenCount(display); i++)
for (j = 0; j < SWM_WS_MAX; j++)
}
void
-spawn(union arg *args)
+spawn(struct swm_region *r, union arg *args)
{
DNPRINTF(SWM_D_MISC, "spawn: %s\n", args->argv[0]);
/*
{
DNPRINTF(SWM_D_FOCUS, "focus_win: id: %lu\n", win->id);
+ rootclick = 0;
+
win->ws->focus = win;
if (win->ws->r != NULL) {
if (cur_focus && cur_focus != win)
}
void
-switchws(union arg *args)
+switchws(struct swm_region *r, union arg *args)
{
int wsid = args->id;
struct swm_region *this_r, *other_r;
struct ws_win *win;
struct workspace *new_ws, *old_ws;
- DNPRINTF(SWM_D_WS, "switchws: %d\n", wsid + 1);
-
- this_r = cur_region();
+ this_r = r;
old_ws = this_r->ws;
new_ws = &this_r->s->ws[wsid];
+ DNPRINTF(SWM_D_WS, "switchws screen %d region %dx%d+%d+%d: "
+ "%d -> %d\n", r->s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r),
+ old_ws->idx, wsid);
+
if (new_ws == old_ws)
return;
other_r = new_ws->r;
if (!other_r) {
- /* if the other region is hidden, switch windows */
-
+ /* if the other workspace is hidden, switch windows */
/* map new window first to prevent ugly blinking */
TAILQ_FOREACH(win, &new_ws->winlist, entry)
XMapRaised(display, win->id);
XUnmapWindow(display, win->id);
old_ws->r = NULL;
+ old_ws->restack = 1;
} else {
other_r->ws = old_ws;
old_ws->r = other_r;
}
-
this_r->ws = new_ws;
new_ws->r = this_r;
ignore_enter = 1;
/* set focus */
- if (new_ws->restack) {
- stack();
- bar_print(this_r);
- } else {
- if (new_ws->focus)
- focus_win(new_ws->focus);
- XSync(display, False);
- }
+ if (new_ws->focus)
+ focus_win(new_ws->focus);
+ stack();
}
void
-swapwin(union arg *args)
+swapwin(struct swm_region *r, union arg *args)
{
struct ws_win *target;
struct ws_win_list *wl;
- DNPRINTF(SWM_D_MOVE, "swapwin: id %d\n", args->id);
+ DNPRINTF(SWM_D_WS, "swapwin id %d "
+ "in screen %d region %dx%d+%d+%d ws %d\n", args->id,
+ r->s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r), r->ws->idx);
if (cur_focus == NULL)
return;
}
void
-focus(union arg *args)
+focus(struct swm_region *r, union arg *args)
{
struct ws_win *winfocus, *winlostfocus;
struct ws_win_list *wl;
}
void
-cycle_layout(union arg *args)
+cycle_layout(struct swm_region *r, union arg *args)
{
- struct workspace *ws;
-
- ws = cur_ws();
+ struct workspace *ws = r->ws;
DNPRINTF(SWM_D_EVENT, "cycle_layout: workspace: %d\n", ws->idx);
}
void
-resize_master(union arg *args)
+resize_master(struct swm_region *r, union arg *args)
{
- struct workspace *ws = cur_ws();
+ struct workspace *ws = r->ws;
DNPRINTF(SWM_D_STACK, "resize_master for workspace %d (id %d\n",
args->id, ws->idx);
if (ws->cur_layout->l_resize != NULL)
- ws->cur_layout->l_resize(args->id);
+ ws->cur_layout->l_resize(ws, args->id);
}
void
-stack_reset(union arg *args)
+stack_reset(struct swm_region *r, union arg *args)
{
- struct workspace *ws = cur_ws();
+ struct workspace *ws = r->ws;
DNPRINTF(SWM_D_STACK, "stack_reset: ws %d\n", ws->idx);
void
stack(void) {
- struct swm_geometry g;
- struct swm_region *r;
- int i, j;
+ struct swm_geometry g;
+ struct swm_region *r;
+ int i, j;
DNPRINTF(SWM_D_STACK, "stack\n");
}
void
-vertical_resize(int id)
+vertical_resize(struct workspace *ws, int id)
{
- struct workspace *ws = cur_ws();
-
DNPRINTF(SWM_D_STACK, "vertical_resize: workspace: %d\n", ws->idx);
switch (id) {
}
void
-horizontal_resize(int id)
+horizontal_resize(struct workspace *ws, int id)
{
- struct workspace *ws = cur_ws();
DNPRINTF(SWM_D_STACK, "horizontal_resize: workspace: %d\n", ws->idx);
switch (id) {
}
void
-send_to_ws(union arg *args)
+send_to_ws(struct swm_region *r, union arg *args)
{
int wsid = args->id;
struct ws_win *win = cur_focus;
struct key {
unsigned int mod;
KeySym keysym;
- void (*func)(union arg *);
+ void (*func)(struct swm_region *r, union arg *);
union arg args;
} keys[] = {
/* modifier key function argument */
if (TAILQ_EMPTY(&screens[k].rl))
continue;
XUngrabKey(display, AnyKey, AnyModifier, screens[k].root);
- for(i = 0; i < LENGTH(keys); i++) {
- if((code = XKeysymToKeycode(display, keys[i].keysym)))
- for(j = 0; j < LENGTH(modifiers); j++)
+ for (i = 0; i < LENGTH(keys); i++) {
+ if ((code = XKeysymToKeycode(display, keys[i].keysym)))
+ for (j = 0; j < LENGTH(modifiers); j++)
XGrabKey(display, code,
keys[i].mod | modifiers[j],
screens[k].root, True,
if (keysym == keys[i].keysym
&& CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
&& keys[i].func)
- keys[i].func(&(keys[i].args));
+ keys[i].func(root_to_region(ev->root),
+ &(keys[i].args));
}
void
XButtonPressedEvent *ev = &e->xbutton;
#ifdef SWM_CLICKTOFOCUS
struct ws_win *win;
- struct workspace *ws = cur_ws();
+ struct workspace *ws;
+ struct swm_region *r;
#endif
DNPRINTF(SWM_D_EVENT, "buttonpress: window: %lu\n", ev->window);
- if (ev->window == ev->root)
+ if (ev->window == ev->root) {
+ rootclick = ev->root;
return;
+ }
if (ev->window == cur_focus->id)
return;
#ifdef SWM_CLICKTOFOCUS
+ r = root_to_region(ev->root);
+ ws = r->ws;
TAILQ_FOREACH(win, &ws->winlist, entry)
if (win->id == ev->window) {
/* focus in the clicked window */
DNPRINTF(SWM_D_MISC, "manage_window: win %u transient %u\n",
(unsigned)win->id, win->transient);
}
- XGetWindowAttributes(display, win->id, &win->wa);
+ XGetWindowAttributes(display, id, &win->wa);
win->g.w = win->wa.width;
win->g.h = win->wa.height;
win->g.x = win->wa.x;
set_win_state(win, WithdrawnState);
free(win);
}
-
stack();
}
DNPRINTF(SWM_D_EVENT, "enternotify: window: %lu\n", ev->window);
- if((ev->mode != NotifyNormal || ev->detail == NotifyInferior) &&
+ if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) &&
ev->window != ev->root)
return;
if (ignore_enter) {
ignore_enter--;
return;
}
- /* XXX update cur_ws here?... brute force for now */
+ /* brute force for now */
for (i = 0; i < ScreenCount(display); i++) {
for (j = 0; j < SWM_WS_MAX; j++) {
TAILQ_FOREACH(win, &screens[i].ws[j].winlist , entry) {
{
XMapRequestEvent *ev = &e->xmaprequest;
XWindowAttributes wa;
- struct workspace *ws = cur_ws();
+ struct swm_region *r;
DNPRINTF(SWM_D_EVENT, "maprequest: window: %lu\n",
e->xmaprequest.window);
return;
if (wa.override_redirect)
return;
- manage_window(e->xmaprequest.window, ws); /* RRR */
+ r = root_to_region(wa.root);
+ manage_window(e->xmaprequest.window, r->ws);
stack();
}
void
visibilitynotify(XEvent *e)
{
- int i;
- struct swm_region *r;
- DNPRINTF(SWM_D_EVENT, "visibilitynotify: window: %lu\n", e->xvisibility.window);
+ int i;
+ struct swm_region *r;
+
+ DNPRINTF(SWM_D_EVENT, "visibilitynotify: window: %lu\n",
+ e->xvisibility.window);
if (e->xvisibility.state == VisibilityUnobscured)
for (i = 0; i < ScreenCount(display); i++)
TAILQ_FOREACH(r, &screens[i].rl, entry)
if (e->xvisibility.window == r->bar_window)
- bar_print(r);
+ bar_update();
}
void (*handler[LASTEvent])(XEvent *) = {
new_region(struct swm_screen *s, struct workspace *ws,
int x, int y, int w, int h)
{
- struct swm_region *r;
+ struct swm_region *r;
DNPRINTF(SWM_D_MISC, "new region on screen %d: %dx%d (%d, %d)\n",
s->idx, x, y, w, h);
void
setup_screens(void)
{
- int i;
-
+#ifdef SWM_XRR_HAS_CRTC
+ XRRCrtcInfo *ci;
+ XRRScreenResources *sr;
+ int c;
+#endif /* SWM_XRR_HAS_CRTC */
+ Window d1, d2, *wins = NULL;
+ XWindowAttributes wa;
+ struct swm_region *r;
+ unsigned int no;
+ int errorbase, major, minor;
+ int ncrtc = 0, w = 0;
+ int i, j, k;
+ struct workspace *ws;
if ((screens = calloc(ScreenCount(display),
sizeof(struct swm_screen))) == NULL)
/* map physical screens */
for (i = 0; i < ScreenCount(display); i++) {
-#ifdef SWM_XRR_HAS_CRTC
- XRRCrtcInfo *crtc_info;
- XRRScreenResources *res;
- int c;
-#endif /* SWM_XRR_HAS_CRTC */
- Window d1, d2, *wins = NULL;
- XWindowAttributes wa;
- struct swm_region *r;
- int errorbase, major, minor;
- int j, ncrtc, w = 0;
- unsigned int num;
-
+ DNPRINTF(SWM_D_WS, "setup_screens: init screen %d\n", i);
screens[i].idx = i;
TAILQ_INIT(&screens[i].rl);
- screens[i].root = ScreenOfDisplay(display, i)->root;
screens[i].root = RootWindow(display, i);
+ XGetWindowAttributes(display, screens[i].root, &wa);
+ XSelectInput(display, screens[i].root,
+ ButtonPressMask | wa.your_event_mask);
/* set default colors */
screens[i].color_focus = name_to_color("red");
/* init all workspaces */
for (j = 0; j < SWM_WS_MAX; j++) {
- int k;
- struct workspace *ws = &screens[i].ws[j];
-
+ ws = &screens[i].ws[j];
ws->idx = j;
ws->restack = 1;
ws->focus = NULL;
ws->r = NULL;
TAILQ_INIT(&ws->winlist);
- for (k = 0; layouts[k].l_stack != NULL; k++) {
+ for (k = 0; layouts[k].l_stack != NULL; k++)
if (layouts[k].l_init != NULL)
layouts[k].l_init(ws);
- }
ws->cur_layout = &layouts[0];
}
#endif
/* grab existing windows (before we build the bars)*/
- if (!XQueryTree(display, screens[i].root,
- &d1, &d2, &wins, &num)) {
- if (wins) /* not sure if this is necessary */
- XFree(wins);
+ if (!XQueryTree(display, screens[i].root, &d1, &d2, &wins, &no))
continue;
- }
-
#ifdef SWM_XRR_HAS_CRTC
- res = XRRGetScreenResources (display, screens[i].root);
- if (res == NULL) {
- ncrtc = 0;
+ sr = XRRGetScreenResources(display, screens[i].root);
+ if (sr == NULL)
new_region(&screens[i], &screens[i].ws[w],
0, 0, DisplayWidth(display, i),
DisplayHeight(display, i));
- } else
- ncrtc = res->ncrtc;
+ else
+ ncrtc = sr->ncrtc;
for (c = 0; c < ncrtc; c++) {
- crtc_info = XRRGetCrtcInfo(display, res, res->crtcs[c]);
- if (crtc_info != NULL && crtc_info->mode == None)
- new_region(&screens[i], &screens[i].ws[w],
- 0, 0, DisplayWidth(display, i),
+ ci = XRRGetCrtcInfo(display, sr, sr->crtcs[c]);
+ if (ci->noutput == 0)
+ continue;
+
+ if (ci != NULL && ci->mode == None)
+ new_region(&screens[i], &screens[i].ws[w], 0, 0,
+ DisplayWidth(display, i),
DisplayHeight(display, i));
else
new_region(&screens[i], &screens[i].ws[w],
- crtc_info->x, crtc_info->y,
- crtc_info->width, crtc_info->height);
+ ci->x, ci->y, ci->width, ci->height);
w++;
}
+ XRRFreeCrtcInfo(ci);
+ XRRFreeScreenResources(sr);
#else
- new_region(&screens[i], &screens[i].ws[w],
- 0, 0, DisplayWidth(display, i),
+ new_region(&screens[i], &screens[i].ws[w], 0, 0,
+ DisplayWidth(display, i),
DisplayHeight(display, i));
#endif /* SWM_XRR_HAS_CRTC */
if ((r = TAILQ_FIRST(&screens[i].rl)) == NULL)
errx(1, "no regions on screen %d", i);
- for (i = 0; i < num; i++) {
+ for (i = 0; i < no; i++) {
XGetWindowAttributes(display, wins[i], &wa);
if (!XGetWindowAttributes(display, wins[i], &wa) ||
wa.override_redirect ||
XGetTransientForHint(display, wins[i], &d1))
continue;
+
if (wa.map_state == IsViewable ||
getstate(wins[i]) == NormalState)
manage_window(wins[i], r->ws);
}
/* transient windows */
- for (i = 0; i < num; i++) {
+ for (i = 0; i < no; i++) {
if (!XGetWindowAttributes(display, wins[i], &wa))
continue;
+
if (XGetTransientForHint(display, wins[i], &d1) &&
(wa.map_state == IsViewable || getstate(wins[i]) ==
NormalState))
manage_window(wins[i], r->ws);
}
- if (wins)
+ if (wins) {
XFree(wins);
+ wins = NULL;
+ }
}
}
char conf[PATH_MAX], *cfile = NULL;
struct stat sb;
XEvent e;
+ int xfd;
+ fd_set rd;
start_argv = argv;
fprintf(stderr, "Welcome to scrotwm V%s\n", SWM_VERSION);
setup_screens();
- //ws[0].focus = TAILQ_FIRST(&ws[0].winlist);
+ /* ws[0].focus = TAILQ_FIRST(&ws[0].winlist); */
grabkeys();
stack();
+ xfd = ConnectionNumber(display);
while (running) {
- XNextEvent(display, &e);
- if (handler[e.type])
- handler[e.type](&e);
+ FD_SET(xfd, &rd);
+ if (select(xfd + 1, &rd, NULL, NULL, NULL) == -1)
+ if (errno != EINTR)
+ errx(1, "select failed");
+ if (bar_alarm) {
+ bar_alarm = 0;
+ bar_update();
+ }
+ while(XPending(display)) {
+ XNextEvent(display, &e);
+ if (handler[e.type])
+ handler[e.type](&e);
+ }
}
XCloseDisplay(display);