X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=scrotwm.c;h=a97a184ae883d5e27dd4c55bb684ffabea20fb71;hb=c83c5792fd6a3cf26da08b3a50e655f1134bfd0e;hp=d160c47e5c3bf23d6320bcdedf98e6e4f26c0dbb;hpb=45ef141d5c94019c82cc1ea17b89c081b0037c91;p=spectrwm.git diff --git a/scrotwm.c b/scrotwm.c index d160c47..a97a184 100644 --- a/scrotwm.c +++ b/scrotwm.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -60,12 +61,15 @@ #include #include #include +#include #include +#include #include #include #include #include +#include #include #include @@ -85,7 +89,6 @@ #endif #endif -#define SWM_DEBUG /* #define SWM_DEBUG */ #ifdef SWM_DEBUG #define DPRINTF(x...) do { if (swm_debug) fprintf(stderr, x); } while(0) @@ -96,6 +99,7 @@ #define SWM_D_FOCUS 0x0008 #define SWM_D_MOVE 0x0010 #define SWM_D_STACK 0x0020 +#define SWM_D_MOUSE 0x0040 u_int32_t swm_debug = 0 | SWM_D_MISC @@ -110,9 +114,10 @@ u_int32_t swm_debug = 0 #define DNPRINTF(n,x...) #endif -#define LENGTH(x) (sizeof x / sizeof x[0]) +#define LENGTH(x) (sizeof x / sizeof x[0]) #define MODKEY Mod1Mask -#define CLEANMASK(mask) (mask & ~(numlockmask | LockMask)) +#define CLEANMASK(mask) (mask & ~(numlockmask | LockMask)) +#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) #define X(r) (r)->g.x #define Y(r) (r)->g.y @@ -129,15 +134,20 @@ int ignore_enter = 0; unsigned int numlockmask = 0; Display *display; +int cycle_empty = 0; +int cycle_visible = 0; + /* 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-*-*-*-*-*-*-*-*-*-*", @@ -174,7 +184,7 @@ struct ws_win { TAILQ_ENTRY(ws_win) entry; Window id; struct swm_geometry g; - int focus; + int got_focus; int floating; int transient; struct workspace *ws; /* always valid */ @@ -185,31 +195,28 @@ TAILQ_HEAD(ws_win_list, ws_win); /* layout handlers */ void stack(void); -void vertical_init(struct workspace *); -void vertical_resize(struct workspace *, int); +void vertical_config(struct workspace *, int); void vertical_stack(struct workspace *, struct swm_geometry *); -void horizontal_init(struct workspace *); -void horizontal_resize(struct workspace *, int); +void horizontal_config(struct workspace *, int); void horizontal_stack(struct workspace *, struct swm_geometry *); -void max_init(struct workspace *); void max_stack(struct workspace *, struct swm_geometry *); +void grabbuttons(struct ws_win *, int); + struct layout { - void (*l_init)(struct workspace *); /* init/reset */ void (*l_stack)(struct workspace *, struct swm_geometry *); - void (*l_resize)(struct workspace *, int); + void (*l_config)(struct workspace *, int); } layouts[] = { - /* init stack, resize */ - { vertical_init, vertical_stack, vertical_resize}, - { horizontal_init, horizontal_stack, horizontal_resize}, - { NULL, max_stack, NULL}, - { NULL, NULL, NULL}, + /* stack, configure */ + { vertical_stack, vertical_config}, + { horizontal_stack, horizontal_config}, + { max_stack, NULL}, + { NULL, NULL}, }; #define SWM_H_SLICE (32) #define SWM_V_SLICE (32) - /* define work spaces */ struct workspace { int idx; /* workspace index */ @@ -222,7 +229,9 @@ struct workspace { /* stacker state */ struct { int horizontal_msize; + int horizontal_mwin; int vertical_msize; + int vertical_mwin; } l_state; }; @@ -244,7 +253,6 @@ struct swm_screen { }; struct swm_screen *screens; int num_screens; -Window rootclick = 0; struct ws_win *cur_focus = NULL; @@ -259,6 +267,12 @@ union arg { #define SWM_ARG_ID_SWAPMAIN (5) #define SWM_ARG_ID_MASTERSHRINK (6) #define SWM_ARG_ID_MASTERGROW (7) +#define SWM_ARG_ID_MASTERADD (8) +#define SWM_ARG_ID_MASTERDEL (9) +#define SWM_ARG_ID_STACKRESET (10) +#define SWM_ARG_ID_STACKINIT (11) +#define SWM_ARG_ID_CYCLEWS_UP (12) +#define SWM_ARG_ID_CYCLEWS_DOWN (13) char **argv; }; @@ -287,6 +301,32 @@ name_to_color(char *colorname) return (result); } +int +varmatch(char *var, char *name, int *index) +{ + char *p, buf[5]; + int i; + + i = strncmp(var, name, 255); + if (index == NULL) + return (i); + + *index = -1; + if (i <= 0) + return (i); + p = var + strlen(name); + if (*p++ != '[') + return (i); + bzero(buf, sizeof buf); + i = 0; + while (isdigit(*p) && i < sizeof buf) + buf[i++] = *p++; + if (i == 0 || i >= sizeof buf || *p != ']') + return (1); + *index = strtonum(buf, 0, 99, NULL); + return (0); +} + /* conf file stuff */ #define SWM_CONF_WS "\n= \t" #define SWM_CONF_FILE "scrotwm.conf" @@ -296,7 +336,7 @@ conf_load(char *filename) FILE *config; char *line, *cp, *var, *val; size_t len, lineno = 0; - int i; + int i, sc; DNPRINTF(SWM_D_MISC, "conf_load: filename %s\n", filename); @@ -306,7 +346,7 @@ conf_load(char *filename) if ((config = fopen(filename, "r")) == NULL) return (1); - for (;;) { + for (sc = ScreenCount(display);;) { if ((line = fparseln(config, &len, &lineno, NULL, 0)) == NULL) if (feof(config)) break; @@ -328,18 +368,37 @@ conf_load(char *filename) case 'b': if (!strncmp(var, "bar_enabled", strlen("bar_enabled"))) bar_enabled = atoi(val); - else if (!strncmp(var, "bar_border", - strlen("bar_border"))) - for (i = 0; i < ScreenCount(display); i++) - screens[i].bar_border = name_to_color(val); - else if (!strncmp(var, "bar_color", - strlen("bar_color"))) - for (i = 0; i < ScreenCount(display); i++) - screens[i].bar_color = name_to_color(val); - else if (!strncmp(var, "bar_font_color", - strlen("bar_font_color"))) - for (i = 0; i < ScreenCount(display); i++) - screens[i].bar_font_color = name_to_color(val); + else if (!varmatch(var, "bar_border", &i)) + if (i > 0 && i <= sc) + screens[i - 1].bar_border = + name_to_color(val); + else if (i == -1) + for (i = 0; i < sc; i++) + screens[i].bar_border = + name_to_color(val); + else + goto badidx; + else if (!varmatch(var, "bar_color", &i)) + if (i > 0 && i <= sc) + screens[i - 1].bar_color = + name_to_color(val); + else if (i == -1) + for (i = 0; i < sc; i++) + screens[i].bar_color = + name_to_color(val); + else + goto badidx; + else if (!varmatch(var, "bar_font_color", &i)) + if (i > 0 && i <= sc) + screens[i - 1].bar_font_color = + name_to_color(val); + else if (i == -1) + for (i = 0; i < sc; i++) + screens[i].bar_font_color = + name_to_color(val); + else + goto badidx; + else if (!strncmp(var, "bar_font", strlen("bar_font"))) asprintf(&bar_fonts[0], "%s", val); else @@ -347,13 +406,30 @@ conf_load(char *filename) break; case 'c': - if (!strncmp(var, "color_focus", strlen("color_focus"))) - for (i = 0; i < ScreenCount(display); i++) - screens[i].color_focus = name_to_color(val); - else if (!strncmp(var, "color_unfocus", - strlen("color_unfocus"))) - for (i = 0; i < ScreenCount(display); i++) - screens[i].color_unfocus = name_to_color(val); + if (!varmatch(var, "color_focus", &i)) + if (i > 0 && i <= sc) + screens[i - 1].color_focus = + name_to_color(val); + else if (i == -1) + for (i = 0; i < sc; i++) + screens[i].color_focus = + name_to_color(val); + else + goto badidx; + else if (!varmatch(var, "color_unfocus", &i)) + if (i > 0 && i <= sc) + screens[i - 1].color_unfocus = + name_to_color(val); + else if (i == -1) + for (i = 0; i < sc; i++) + screens[i].color_unfocus = + name_to_color(val); + else + goto badidx; + else if (!strncmp(var, "cycle_empty", strlen("cycle_empty"))) + cycle_visible = atoi(val); + else if (!strncmp(var, "cycle_visible", strlen("cycle_visible"))) + cycle_visible = atoi(val); else goto bad; break; @@ -382,70 +458,81 @@ conf_load(char *filename) return (0); bad: errx(1, "invalid conf file entry: %s=%s", var, val); +badidx: + errx(1, "invalid screen index: %s out of bounds", var); } void -bar_print(struct swm_region *r) +bar_print(struct swm_region *r, char *s) +{ + XClearWindow(display, r->bar_window); + XSetForeground(display, bar_gc, r->s->bar_font_color); + XDrawString(display, r->bar_window, bar_gc, 4, bar_fs->ascent, s, + strlen(s)); +} + +void +bar_update(void) { time_t tmt; struct tm tm; - + struct swm_region *r; + int i, x; + char s[SWM_BAR_MAX]; + char e[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)); + 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); + } + } 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(struct swm_region *r, union arg *args) { - struct swm_region *tmpr; - int i, j; + struct swm_region *tmpr; + int i, j, sc = ScreenCount(display); DNPRINTF(SWM_D_MISC, "bar_toggle\n"); if (bar_enabled) { - for (i = 0; i < ScreenCount(display); i++) + for (i = 0; i < sc; i++) TAILQ_FOREACH(tmpr, &screens[i].rl, entry) XUnmapWindow(display, tmpr->bar_window); } else { - for (i = 0; i < ScreenCount(display); i++) + for (i = 0; i < sc; i++) TAILQ_FOREACH(tmpr, &screens[i].rl, entry) XMapRaised(display, tmpr->bar_window); } bar_enabled = !bar_enabled; XSync(display, False); - for (i = 0; i < ScreenCount(display); i++) + for (i = 0; i < sc; i++) for (j = 0; j < SWM_WS_MAX; j++) screens[i].ws[j].restack = 1; stack(); /* must be after stack */ - for (i = 0; i < ScreenCount(display); i++) + for (i = 0; i < sc; i++) TAILQ_FOREACH(tmpr, &screens[i].rl, entry) - bar_print(tmpr); + bar_update(); } void @@ -463,7 +550,7 @@ bar_setup(struct swm_region *r) 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); @@ -474,7 +561,25 @@ bar_setup(struct swm_region *r) if (signal(SIGALRM, bar_signal) == SIG_ERR) err(1, "could not install bar_signal"); - bar_print(r); + 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].bar_border; + wa.background_pixel = screens[i].bar_color; + XChangeWindowAttributes(display, r->bar_window, + CWBackPixel | CWBorderPixel, &wa); + } + bar_update(); } void @@ -528,6 +633,11 @@ 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"); @@ -547,23 +657,20 @@ root_to_region(Window root) 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); + if (XQueryPointer(display, screens[i].root, + &rr, &cr, &x, &y, &wx, &wy, &mask) == False) { + /* if we can't query the pointer, grab the first region */ + r = TAILQ_FIRST(&screens[i].rl); + } 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)) + break; } + + if (r == NULL) + r = TAILQ_FIRST(&screens[i].rl); } return (r); } @@ -605,36 +712,45 @@ spawn(struct swm_region *r, union arg *args) } void -unfocus_win(struct ws_win *win) +unfocus_all(void) { - DNPRINTF(SWM_D_FOCUS, "unfocus_win: id: %lu\n", win->id); - if (win->ws->r && win->focus) - XSetWindowBorder(display, win->id, - win->ws->r->s->color_unfocus); - win->focus = 0; - if (win->ws->focus == win) - win->ws->focus = NULL; - if (cur_focus == win) - cur_focus = NULL; -} + struct ws_win *win; + int i, j; + + DNPRINTF(SWM_D_FOCUS, "unfocus_all:\n"); + for (i = 0; i < ScreenCount(display); i++) + for (j = 0; j < SWM_WS_MAX; j++) + TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) { + if (win->ws->r == NULL) + continue; + grabbuttons(win, 0); + XSetWindowBorder(display, win->id, + win->ws->r->s->color_unfocus); + win->got_focus = 0; + win->ws->focus = NULL; + cur_focus = NULL; + } +} void focus_win(struct ws_win *win) { - DNPRINTF(SWM_D_FOCUS, "focus_win: id: %lu\n", win->id); + DNPRINTF(SWM_D_FOCUS, "focus_win: id: %lu\n", win ? win->id : 0); - rootclick = 0; + if (win == NULL) + return; + unfocus_all(); win->ws->focus = win; if (win->ws->r != NULL) { - if (cur_focus && cur_focus != win) - unfocus_win(cur_focus); cur_focus = win; - if (!win->focus) + if (!win->got_focus) { XSetWindowBorder(display, win->id, win->ws->r->s->color_focus); - win->focus = 1; + grabbuttons(win, 1); + } + win->got_focus = 1; XSetInputFocus(display, win->id, RevertToPointerRoot, CurrentTime); } @@ -660,10 +776,8 @@ switchws(struct swm_region *r, union arg *args) return; other_r = new_ws->r; - fprintf(stderr, "switchws: other_r %p\n", other_r); if (!other_r) { /* 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); @@ -685,6 +799,46 @@ switchws(struct swm_region *r, union arg *args) if (new_ws->focus) focus_win(new_ws->focus); stack(); + bar_update(); +} + +void +cyclews(struct swm_region *r, union arg *args) +{ + union arg a; + struct swm_screen *s = r->s; + + DNPRINTF(SWM_D_WS, "cyclews 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); + + a.id = r->ws->idx; + + do { + switch (args->id) { + case SWM_ARG_ID_CYCLEWS_UP: + if (a.id < SWM_WS_MAX - 1) + a.id++; + else + a.id = 0; + break; + case SWM_ARG_ID_CYCLEWS_DOWN: + if (a.id > 0) + a.id--; + else + a.id = SWM_WS_MAX - 1; + break; + default: + return; + }; + + if (cycle_empty == 0 && TAILQ_EMPTY(&s->ws[a.id].winlist)) + continue; + if (cycle_visible == 0 && s->ws[a.id].r != NULL) + continue; + + switchws(r, &a); + } while (a.id != r->ws->idx); } void @@ -795,28 +949,18 @@ cycle_layout(struct swm_region *r, union arg *args) } void -resize_master(struct swm_region *r, union arg *args) +stack_config(struct swm_region *r, union arg *args) { struct workspace *ws = r->ws; - DNPRINTF(SWM_D_STACK, "resize_master for workspace %d (id %d\n", + DNPRINTF(SWM_D_STACK, "stack_config for workspace %d (id %d\n", args->id, ws->idx); - if (ws->cur_layout->l_resize != NULL) - ws->cur_layout->l_resize(ws, args->id); -} + if (ws->cur_layout->l_config != NULL) + ws->cur_layout->l_config(ws, args->id); -void -stack_reset(struct swm_region *r, union arg *args) -{ - struct workspace *ws = r->ws; - - DNPRINTF(SWM_D_STACK, "stack_reset: ws %d\n", ws->idx); - - if (ws->cur_layout->l_init != NULL) { - ws->cur_layout->l_init(ws); + if (args->id != SWM_ARG_ID_STACKINIT); stack(); - } } void @@ -873,36 +1017,36 @@ stack_floater(struct ws_win *win, struct swm_region *r) XConfigureWindow(display, win->id, mask, &wc); } -int vertical_msize[SWM_WS_MAX]; void -vertical_init(struct workspace *ws) -{ - DNPRINTF(SWM_D_MISC, "vertical_init: workspace: %d\n", ws->idx); - - ws->l_state.vertical_msize = SWM_V_SLICE / 2; -} - -void -vertical_resize(struct workspace *ws, int id) +vertical_config(struct workspace *ws, int id) { DNPRINTF(SWM_D_STACK, "vertical_resize: workspace: %d\n", ws->idx); switch (id) { + case SWM_ARG_ID_STACKRESET: + case SWM_ARG_ID_STACKINIT: + ws->l_state.vertical_msize = SWM_V_SLICE / 2; + ws->l_state.vertical_mwin = 1; + break; case SWM_ARG_ID_MASTERSHRINK: - ws->l_state.vertical_msize--; - if (ws->l_state.vertical_msize < 1) - ws->l_state.vertical_msize = 1; + if (ws->l_state.vertical_msize > 1) + ws->l_state.vertical_msize--; break; case SWM_ARG_ID_MASTERGROW: - ws->l_state.vertical_msize++; - if (ws->l_state.vertical_msize > SWM_V_SLICE - 1) - ws->l_state.vertical_msize = SWM_V_SLICE - 1; + if (ws->l_state.vertical_msize < SWM_V_SLICE - 1) + ws->l_state.vertical_msize++; + break; + case SWM_ARG_ID_MASTERADD: + ws->l_state.vertical_mwin++; + break; + case SWM_ARG_ID_MASTERDEL: + if (ws->l_state.vertical_mwin > 0) + ws->l_state.vertical_mwin--; break; default: return; } - stack(); } void @@ -910,7 +1054,7 @@ vertical_stack(struct workspace *ws, struct swm_geometry *g) { XWindowChanges wc; struct swm_geometry gg = *g; struct ws_win *win, *winfocus; - int i, hrh, winno, main_width; + int i, j, split, colno, hrh, winno, main_width; unsigned int mask; DNPRINTF(SWM_D_STACK, "vertical_stack: workspace: %d\n", ws->idx); @@ -922,35 +1066,38 @@ vertical_stack(struct workspace *ws, struct swm_geometry *g) { ws->focus = TAILQ_FIRST(&ws->winlist); winfocus = cur_focus ? cur_focus : ws->focus; - if (winno > 1) { + if (ws->l_state.vertical_mwin && + winno > ws->l_state.vertical_mwin) { + split = ws->l_state.vertical_mwin; + colno = split; main_width = (g->w / SWM_V_SLICE) * ws->l_state.vertical_msize; gg.w = main_width; + } else { + colno = winno; + split = 0; } + hrh = g->h / colno; + gg.h = hrh - 2; - if (winno > 2) - hrh = g->h / (winno - 1); - else - hrh = 0; - - i = 0; + i = j = 0; TAILQ_FOREACH(win, &ws->winlist, entry) { - if (i == 1) { + if (split && i == split) { + colno = winno - split; + hrh = (g->h / colno); gg.x += main_width + 2; gg.w = g->w - (main_width + 2); + gg.h = hrh - 2; + j = 0; } - if (i != 0 && hrh != 0) { - /* correct the last window for lost pixels */ - if (win == TAILQ_LAST(&ws->winlist, ws_win_list)) { - gg.h = hrh + (g->h - (i * hrh)); - gg.y += hrh; - } else { - gg.h = hrh - 2; - /* leave first right hand window at y = 0 */ - if (i > 1) - gg.y += gg.h + 2; - } - } + if (j == colno - 1) + gg.h = (hrh + (g->h - (colno * hrh))); + + if (j == 0) + gg.y = g->y; + else + gg.y += hrh; + if (win->transient != 0 || win->floating != 0) stack_floater(win, ws->r); @@ -967,6 +1114,7 @@ vertical_stack(struct workspace *ws, struct swm_geometry *g) { XMapRaised(display, win->id); i++; + j++; } if (winfocus) @@ -975,33 +1123,34 @@ vertical_stack(struct workspace *ws, struct swm_geometry *g) { void -horizontal_init(struct workspace *ws) +horizontal_config(struct workspace *ws, int id) { - DNPRINTF(SWM_D_STACK, "horizontal_init: workspace: %d\n", ws->idx); - - ws->l_state.horizontal_msize = SWM_H_SLICE / 2; -} - -void -horizontal_resize(struct workspace *ws, int id) -{ - DNPRINTF(SWM_D_STACK, "horizontal_resize: workspace: %d\n", ws->idx); + DNPRINTF(SWM_D_STACK, "horizontal_config: workspace: %d\n", ws->idx); switch (id) { + case SWM_ARG_ID_STACKRESET: + case SWM_ARG_ID_STACKINIT: + ws->l_state.horizontal_mwin = 1; + ws->l_state.horizontal_msize = SWM_H_SLICE / 2; + break; case SWM_ARG_ID_MASTERSHRINK: - ws->l_state.horizontal_msize--; - if (ws->l_state.horizontal_msize < 1) - ws->l_state.horizontal_msize = 1; + if (ws->l_state.horizontal_msize > 1) + ws->l_state.horizontal_msize--; break; case SWM_ARG_ID_MASTERGROW: - ws->l_state.horizontal_msize++; - if (ws->l_state.horizontal_msize > SWM_H_SLICE - 1) - ws->l_state.horizontal_msize = SWM_H_SLICE - 1; + if (ws->l_state.horizontal_msize < SWM_H_SLICE - 1) + ws->l_state.horizontal_msize++; + break; + case SWM_ARG_ID_MASTERADD: + ws->l_state.horizontal_mwin++; + break; + case SWM_ARG_ID_MASTERDEL: + if (ws->l_state.horizontal_mwin > 0) + ws->l_state.horizontal_mwin--; break; default: return; } - stack(); } void @@ -1009,7 +1158,7 @@ horizontal_stack(struct workspace *ws, struct swm_geometry *g) { XWindowChanges wc; struct swm_geometry gg = *g; struct ws_win *win, *winfocus; - int i, hrw, winno, main_height; + int i, j, split, rowno, hrw, winno, main_height; unsigned int mask; DNPRINTF(SWM_D_STACK, "horizontal_stack: workspace: %d\n", ws->idx); @@ -1021,35 +1170,37 @@ horizontal_stack(struct workspace *ws, struct swm_geometry *g) { ws->focus = TAILQ_FIRST(&ws->winlist); winfocus = cur_focus ? cur_focus : ws->focus; - if (winno > 1) { - main_height = (g->h / SWM_H_SLICE) * - ws->l_state.horizontal_msize; + if (ws->l_state.horizontal_mwin && + winno > ws->l_state.horizontal_mwin) { + split = ws->l_state.horizontal_mwin; + rowno = split; + main_height = (g->h / SWM_V_SLICE) * + ws->l_state.horizontal_msize; gg.h = main_height; + } else { + rowno = winno; + split = 0; } + hrw = g->w / rowno; + gg.w = hrw - 2; - if (winno > 2) - hrw = g->w / (winno - 1); - else - hrw = 0; - - i = 0; + i = j = 0; TAILQ_FOREACH(win, &ws->winlist, entry) { - if (i == 1) { + if (split && i == split) { + rowno = winno - split; + hrw = (g->w / rowno); gg.y += main_height + 2; gg.h = g->h - (main_height + 2); + gg.w = hrw - 2; + j = 0; } - if (i != 0 && hrw != 0) { - /* correct the last window for lost pixels */ - if (win == TAILQ_LAST(&ws->winlist, ws_win_list)) { - gg.w = hrw + (g->w - (i * hrw)); - gg.x += hrw; - } else { - gg.w = hrw - 2; - /* leave first bottom window at x = 0 */ - if (i > 1) - gg.x += gg.w + 2; - } - } + if (j == rowno - 1) + gg.w = (hrw + (g->w - (rowno * hrw))); + + if (j == 0) + gg.x = g->x; + else + gg.x += hrw; if (win->transient != 0 || win->floating != 0) stack_floater(win, ws->r); @@ -1065,6 +1216,7 @@ horizontal_stack(struct workspace *ws, struct swm_geometry *g) { } XMapRaised(display, win->id); + j++; i++; } @@ -1161,9 +1313,11 @@ struct key { } keys[] = { /* modifier key function argument */ { MODKEY, XK_space, cycle_layout, {0} }, - { MODKEY | ShiftMask, XK_space, stack_reset, {0} }, - { MODKEY, XK_h, resize_master, {.id = SWM_ARG_ID_MASTERSHRINK} }, - { MODKEY, XK_l, resize_master, {.id = SWM_ARG_ID_MASTERGROW} }, + { MODKEY | ShiftMask, XK_space, stack_config, {.id = SWM_ARG_ID_STACKRESET} }, + { MODKEY, XK_h, stack_config, {.id = SWM_ARG_ID_MASTERSHRINK} }, + { MODKEY, XK_l, stack_config, {.id = SWM_ARG_ID_MASTERGROW} }, + { MODKEY, XK_comma, stack_config, {.id = SWM_ARG_ID_MASTERADD} }, + { MODKEY, XK_period, stack_config, {.id = SWM_ARG_ID_MASTERDEL} }, { MODKEY, XK_Return, swapwin, {.id = SWM_ARG_ID_SWAPMAIN} }, { MODKEY, XK_j, focus, {.id = SWM_ARG_ID_FOCUSNEXT} }, { MODKEY, XK_k, focus, {.id = SWM_ARG_ID_FOCUSPREV} }, @@ -1184,6 +1338,8 @@ struct key { { MODKEY, XK_8, switchws, {.id = 7} }, { MODKEY, XK_9, switchws, {.id = 8} }, { MODKEY, XK_0, switchws, {.id = 9} }, + { MODKEY, XK_Right, cyclews, {.id = SWM_ARG_ID_CYCLEWS_UP} }, + { MODKEY, XK_Left, cyclews, {.id = SWM_ARG_ID_CYCLEWS_DOWN} }, { MODKEY | ShiftMask, XK_1, send_to_ws, {.id = 0} }, { MODKEY | ShiftMask, XK_2, send_to_ws, {.id = 1} }, { MODKEY | ShiftMask, XK_3, send_to_ws, {.id = 2} }, @@ -1200,6 +1356,36 @@ struct key { }; void +click(struct swm_region *r, union arg *args) +{ + DNPRINTF(SWM_D_MOUSE, "click: button: %d\n", args->id); + + switch (args->id) { + case Button1: + break; + case Button2: + break; + case Button3: + break; + default: + return; + } +} + +/* mouse */ +enum { client_click, root_click }; +struct button { + unsigned int action; + unsigned int mask; + unsigned int button; + void (*func)(struct swm_region *r, union arg *); + union arg args; +} buttons[] = { + /* action key mouse button func args */ + { client_click, MODKEY, Button1, click, {.id=Button1} }, +}; + +void updatenumlockmask(void) { unsigned int i, j; @@ -1232,9 +1418,9 @@ grabkeys(void) 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, @@ -1242,6 +1428,30 @@ grabkeys(void) } } } + +void +grabbuttons(struct ws_win *win, int focused) +{ + unsigned int i, j; + unsigned int modifiers[] = + { 0, LockMask, numlockmask, numlockmask|LockMask }; + + updatenumlockmask(); + XUngrabButton(display, AnyButton, AnyModifier, win->id); + if(focused) { + for (i = 0; i < LENGTH(buttons); i++) + if (buttons[i].action == client_click) + for (j = 0; j < LENGTH(modifiers); j++) + XGrabButton(display, buttons[i].button, + buttons[i].mask | modifiers[j], + win->id, False, BUTTONMASK, + GrabModeAsync, GrabModeSync, None, + None); + } else + XGrabButton(display, AnyButton, AnyModifier, win->id, False, + BUTTONMASK, GrabModeAsync, GrabModeSync, None, None); +} + void expose(XEvent *e) { @@ -1270,35 +1480,26 @@ void buttonpress(XEvent *e) { XButtonPressedEvent *ev = &e->xbutton; -#ifdef SWM_CLICKTOFOCUS + struct ws_win *win; - struct workspace *ws; - struct swm_region *r; -#endif + int i, action; DNPRINTF(SWM_D_EVENT, "buttonpress: window: %lu\n", ev->window); - if (ev->window == ev->root) { - rootclick = ev->root; - return; - } - if (ev->window == cur_focus->id) + action = root_click; + if ((win = find_window(ev->window)) == NULL) 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 */ - XSetWindowBorder(display, ev->window, 0xff0000); - XSetWindowBorder(display, ws->focus->id, 0x888888); - XSetInputFocus(display, ev->window, RevertToPointerRoot, - CurrentTime); - ws->focus = win; - XSync(display, False); - break; + else { + focus_win(win); + action = client_click; } -#endif + + for (i = 0; i < LENGTH(buttons); i++) + if (action == buttons[i].action && buttons[i].func && + buttons[i].button == ev->button && + CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) + buttons[i].func(root_to_region(ev->root), + &buttons[i].args); } void @@ -1438,11 +1639,12 @@ destroynotify(XEvent *e) { struct ws_win *win; XDestroyWindowEvent *ev = &e->xdestroywindow; + struct workspace *ws; DNPRINTF(SWM_D_EVENT, "destroynotify: window %lu\n", ev->window); if ((win = find_window(ev->window)) != NULL) { - struct workspace *ws = win->ws; + ws = win->ws; /* find a window to focus */ if (ws->focus == win) ws->focus = TAILQ_PREV(win, ws_win_list, entry); @@ -1450,18 +1652,13 @@ destroynotify(XEvent *e) ws->focus = TAILQ_FIRST(&ws->winlist); if (ws->focus == win) ws->focus = NULL; - if (cur_focus == win) { - if (ws->focus == NULL) - unfocus_win(win); /* XXX focus another ws? */ - else - focus_win(ws->focus); - } + if (cur_focus == win) + focus_win(ws->focus); TAILQ_REMOVE(&ws->winlist, win, entry); set_win_state(win, WithdrawnState); free(win); } - stack(); } @@ -1470,47 +1667,23 @@ enternotify(XEvent *e) { XCrossingEvent *ev = &e->xcrossing; struct ws_win *win; - int i, j; DNPRINTF(SWM_D_EVENT, "enternotify: window: %lu\n", ev->window); - if((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && - ev->window != ev->root) - return; if (ignore_enter) { /* eat event(r) to prevent autofocus */ ignore_enter--; return; } - /* 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) { - if (win->id == ev->window) - focus_win(win); - } - } - } + + if ((win = find_window(ev->window)) != NULL) + focus_win(win); } void focusin(XEvent *e) { DNPRINTF(SWM_D_EVENT, "focusin: window: %lu\n", e->xfocus.window); - - /* XXX this probably needs better handling now. - if (ev->window == ev->root) - return; - */ - /* - * kill grab for now so that we can cut and paste , this screws up - * click to focus - */ - /* - DNPRINTF(SWM_D_EVENT, "focusin: window: %lu grabbing\n", ev->window); - XGrabButton(display, Button1, AnyModifier, ev->window, False, - ButtonPress, GrabModeAsync, GrabModeSync, None, None); - */ } void @@ -1569,7 +1742,7 @@ visibilitynotify(XEvent *e) 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 *) = { @@ -1667,16 +1840,16 @@ void setup_screens(void) { #ifdef SWM_XRR_HAS_CRTC - XRRCrtcInfo *crtc_info; - XRRScreenResources *res; + XRRCrtcInfo *ci; + XRRScreenResources *sr; int c; #endif /* SWM_XRR_HAS_CRTC */ Window d1, d2, *wins = NULL; XWindowAttributes wa; struct swm_region *r; - unsigned int num; + unsigned int no; int errorbase, major, minor; - int ncrtc, w = 0; + int ncrtc = 0, w = 0; int i, j, k; struct workspace *ws; @@ -1690,9 +1863,6 @@ setup_screens(void) screens[i].idx = i; TAILQ_INIT(&screens[i].rl); 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"); @@ -1710,10 +1880,10 @@ setup_screens(void) ws->r = NULL; TAILQ_INIT(&ws->winlist); - for (k = 0; layouts[k].l_stack != NULL; k++) { - if (layouts[k].l_init != NULL) - layouts[k].l_init(ws); - } + for (k = 0; layouts[k].l_stack != NULL; k++) + if (layouts[k].l_config != NULL) + layouts[k].l_config(ws, + SWM_ARG_ID_STACKINIT); ws->cur_layout = &layouts[0]; } @@ -1733,41 +1903,37 @@ setup_screens(void) #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->noutput == 0) + ci = XRRGetCrtcInfo(display, sr, sr->crtcs[c]); + if (ci->noutput == 0) continue; - if (crtc_info != NULL && crtc_info->mode == None) - new_region(&screens[i], &screens[i].ws[w], - 0, 0, DisplayWidth(display, i), + 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 */ @@ -1776,27 +1942,31 @@ setup_screens(void) 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; + } } } @@ -1807,6 +1977,8 @@ main(int argc, char *argv[]) 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); @@ -1826,6 +1998,8 @@ main(int argc, char *argv[]) if (pwd == NULL) errx(1, "invalid user %d", getuid()); + setup_screens(); + snprintf(conf, sizeof conf, "%s/.%s", pwd->pw_dir, SWM_CONF_FILE); if (stat(conf, &sb) != -1) { if (S_ISREG(sb.st_mode)) @@ -1839,18 +2013,28 @@ main(int argc, char *argv[]) } if (cfile) conf_load(cfile); + bar_refresh(); - 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);