X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=scrotwm.c;h=51f73cf00ec237da33e155704e11d304dc214744;hb=541344a40ab0857de33f1c8bab5889ff3a8bc801;hp=29d22e9bab1267b2d637474d98f3a3ac567af261;hpb=2a214e3e6cab1e778ec552e6f45330c9ccbe2664;p=spectrwm.git diff --git a/scrotwm.c b/scrotwm.c index 29d22e9..51f73cf 100644 --- a/scrotwm.c +++ b/scrotwm.c @@ -48,7 +48,7 @@ * DEALINGS IN THE SOFTWARE. */ -#define SWM_VERSION "0.5" +#define SWM_VERSION "0.6" #include #include @@ -175,7 +175,7 @@ char *bar_fonts[] = { /* terminal + args */ char *spawn_term[] = { "xterm", NULL }; -char *spawn_screenshot[] = { "scrot", NULL, NULL }; /* XXX get from conf */ +char *spawn_screenshot[] = { "screenshot.sh", NULL, NULL }; char *spawn_menu[] = { "dmenu_run", "-fn", NULL, "-nb", NULL, "-nf", NULL, "-sb", NULL, "-sf", NULL, NULL }; @@ -216,6 +216,7 @@ struct ws_win { struct workspace *ws; /* always valid */ struct swm_screen *s; /* always valid, never changes */ XWindowAttributes wa; + XSizeHints sh; }; TAILQ_HEAD(ws_win_list, ws_win); @@ -301,6 +302,8 @@ union arg { #define SWM_ARG_ID_STACKINIT (11) #define SWM_ARG_ID_CYCLEWS_UP (12) #define SWM_ARG_ID_CYCLEWS_DOWN (13) +#define SWM_ARG_ID_CYCLESC_UP (14) +#define SWM_ARG_ID_CYCLESC_DOWN (15) #define SWM_ARG_ID_SS_ALL (0) #define SWM_ARG_ID_SS_WINDOW (1) char **argv; @@ -456,10 +459,13 @@ conf_load(char *filename) case 's': if (!strncmp(var, "spawn_term", strlen("spawn_term"))) - asprintf(&spawn_term[0], "%s", val); /* XXX args? */ + asprintf(&spawn_term[0], "%s", val); if (!strncmp(var, "screenshot_enabled", strlen("screenshot_enabled"))) ss_enabled = atoi(val); + if (!strncmp(var, "screenshot_app", + strlen("screenshot_app"))) + asprintf(&spawn_screenshot[0], "%s", val); break; default: goto bad; @@ -719,6 +725,18 @@ quit(struct swm_region *r, union arg *args) } void +unmap_all(void) +{ + struct ws_win *win; + int i, j; + + for (i = 0; i < ScreenCount(display); i++) + for (j = 0; j < SWM_WS_MAX; j++) + TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) + XUnmapWindow(display, win->id); +} + +void restart(struct swm_region *r, union arg *args) { DNPRINTF(SWM_D_MISC, "restart: %s\n", start_argv[0]); @@ -730,6 +748,7 @@ restart(struct swm_region *r, union arg *args) bar_extra_stop(); bar_extra = 1; + unmap_all(); XCloseDisplay(display); execvp(start_argv[0], start_argv); fprintf(stderr, "execvp failed\n"); @@ -784,6 +803,8 @@ find_window(Window id) void spawn(struct swm_region *r, union arg *args) { + char *ret; + DNPRINTF(SWM_D_MISC, "spawn: %s\n", args->argv[0]); /* * The double-fork construct avoids zombie processes and keeps the code @@ -791,14 +812,17 @@ spawn(struct swm_region *r, union arg *args) */ 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)) + if (asprintf(&ret, "%d", r->ws->idx)) { setenv("_SWM_WS", ret, 1); - if (asprintf(&ret, "%d", getpid())) + free(ret); + } + if (asprintf(&ret, "%d", getpid())) { setenv("_SWM_PID", ret, 1); + free(ret); + } setsid(); execvp(args->argv[0], args->argv); fprintf(stderr, "execvp failed\n"); @@ -896,7 +920,6 @@ switchws(struct swm_region *r, union arg *args) TAILQ_FOREACH(win, &old_ws->winlist, entry) XUnmapWindow(display, win->id); - old_ws->r = NULL; old_ws->restack = 1; } else { @@ -925,7 +948,6 @@ cyclews(struct swm_region *r, union arg *args) 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: @@ -954,6 +976,33 @@ cyclews(struct swm_region *r, union arg *args) } void +cyclescr(struct swm_region *r, union arg *args) +{ + struct swm_region *rr; + int i; + + i = r->s->idx; + switch (args->id) { + case SWM_ARG_ID_CYCLESC_UP: + rr = TAILQ_NEXT(r, entry); + if (rr == NULL) + rr = TAILQ_FIRST(&screens[i].rl); + break; + case SWM_ARG_ID_CYCLESC_DOWN: + rr = TAILQ_PREV(r, swm_region_list, entry); + if (rr == NULL) + rr = TAILQ_LAST(&screens[i].rl, swm_region_list); + break; + default: + return; + }; + unfocus_all(); + XSetInputFocus(display, PointerRoot, RevertToPointerRoot, CurrentTime); + XWarpPointer(display, None, rr->s[i].root, 0, 0, 0, 0, rr->g.x, + rr->g.y + bar_enabled ? bar_height : 0); +} + +void swapwin(struct swm_region *r, union arg *args) { struct ws_win *target; @@ -1038,9 +1087,10 @@ focus(struct swm_region *r, union arg *args) return; } - if (winfocus == winlostfocus) + if (winfocus == winlostfocus || winfocus == NULL) return; + XMapRaised(display, winfocus->id); focus_win(winfocus); XSync(display, False); } @@ -1056,7 +1106,6 @@ cycle_layout(struct swm_region *r, union arg *args) if (ws->cur_layout->l_stack == NULL) ws->cur_layout = &layouts[0]; ignore_enter = 1; - stack(); } @@ -1129,46 +1178,25 @@ stack_floater(struct ws_win *win, struct swm_region *r) XConfigureWindow(display, win->id, mask, &wc); } +#define SWAPXY(g) do { \ + int tmp; \ + tmp = (g)->y; (g)->y = (g)->x; (g)->x = tmp; \ + tmp = (g)->h; (g)->h = (g)->w; (g)->w = tmp; \ +} while (0) void -vertical_config(struct workspace *ws, int id) +stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) { - 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: - if (ws->l_state.vertical_msize > 1) - ws->l_state.vertical_msize--; - break; - case SWM_ARG_ID_MASTERGROW: - 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; - } -} - -void -vertical_stack(struct workspace *ws, struct swm_geometry *g) { XWindowChanges wc; - struct swm_geometry gg = *g; + struct swm_geometry win_g, r_g = *g; struct ws_win *win, *winfocus; - int i, j, split, colno, hrh, winno, main_width; + int i, j, w_inc, h_inc, w_base, h_base; + int hrh, extra, h_slice, last_h = 0; + int split, colno, winno, mwin, msize, mscale; + int remain, missing, v_slice;; unsigned int mask; - DNPRINTF(SWM_D_STACK, "vertical_stack: workspace: %d\n", ws->idx); + DNPRINTF(SWM_D_STACK, "stack_master: workspace: %d\n rot=%s flip=%s", + ws->idx, rot ? "yes" : "no", flip ? "yes" : "no"); if ((winno = count_win(ws, 0)) == 0) return; @@ -1177,48 +1205,112 @@ vertical_stack(struct workspace *ws, struct swm_geometry *g) { ws->focus = TAILQ_FIRST(&ws->winlist); winfocus = cur_focus ? cur_focus : ws->focus; - if (ws->l_state.vertical_mwin && - winno > ws->l_state.vertical_mwin) { - split = ws->l_state.vertical_mwin; + win = TAILQ_FIRST(&ws->winlist); + if (rot) { + w_inc = win->sh.width_inc; + w_base = win->sh.base_width; + mwin = ws->l_state.horizontal_mwin; + mscale = ws->l_state.horizontal_msize; + SWAPXY(&r_g); + } else { + w_inc = win->sh.height_inc; + w_base = win->sh.base_height; + mwin = ws->l_state.vertical_mwin; + mscale = ws->l_state.vertical_msize; + } + win_g = r_g; + + h_slice = r_g.h / SWM_H_SLICE; + if (mwin && winno > mwin) { + v_slice = r_g.w / SWM_V_SLICE; + + split = mwin; colno = split; - main_width = (g->w / SWM_V_SLICE) * - ws->l_state.vertical_msize; - gg.w = main_width; + msize = v_slice * mscale; + + if (w_inc > 1 && w_inc < v_slice) { + /* adjust for window's requested size increment */ + remain = (win_g.w - w_base) % w_inc; + missing = w_inc - remain; + + if (missing <= extra || j == 0) { + extra -= missing; + win_g.w += missing; + } else { + win_g.w -= remain; + extra += remain; + } + } + + win_g.w = msize; + if (flip) + win_g.x += r_g.w - msize; } else { colno = winno; split = 0; } - hrh = g->h / colno; - gg.h = hrh - 2; + hrh = r_g.h / colno; + extra = r_g.h - (colno * hrh); + win_g.h = hrh - 2; i = j = 0; TAILQ_FOREACH(win, &ws->winlist, entry) { 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; + hrh = (r_g.h / colno); + extra = r_g.h - (colno * hrh); + if (flip) + win_g.x = r_g.x; + else + win_g.x += msize + 2; + win_g.w = r_g.w - (msize + 2); j = 0; } - if (j == colno - 1) - gg.h = (hrh + (g->h - (colno * hrh))); + win_g.h = hrh - 2; + if (rot) { + h_inc = win->sh.width_inc; + h_base = win->sh.base_width; + } else { + h_inc = win->sh.height_inc; + h_base = win->sh.base_height; + } + if (j == colno - 1) { + win_g.h = hrh + extra; + } else if (h_inc > 1 && h_inc < h_slice) { + /* adjust for window's requested size increment */ + remain = (win_g.h - h_base) % h_inc; + missing = h_inc - remain; + + if (missing <= extra || j == 0) { + extra -= missing; + win_g.h += missing; + } else { + win_g.h -= remain; + extra += remain; + } + } if (j == 0) - gg.y = g->y; + win_g.y = r_g.y; else - gg.y += hrh; - + win_g.y += last_h + 2; if (win->transient != 0 || win->floating != 0) stack_floater(win, ws->r); else { bzero(&wc, sizeof wc); wc.border_width = 1; - win->g.x = wc.x = gg.x; - win->g.y = wc.y = gg.y; - win->g.w = wc.width = gg.w; - win->g.h = wc.height = gg.h; + if (rot) { + win->g.x = wc.x = win_g.y; + win->g.y = wc.y = win_g.x; + win->g.w = wc.width = win_g.h; + win->g.h = wc.height = win_g.w; + } else { + win->g.x = wc.x = win_g.x; + win->g.y = wc.y = win_g.y; + win->g.w = wc.width = win_g.w; + win->g.h = wc.height = win_g.h; + } mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth; XConfigureWindow(display, win->id, mask, &wc); /* @@ -1227,6 +1319,7 @@ vertical_stack(struct workspace *ws, struct swm_geometry *g) { } XMapRaised(display, win->id); + last_h = win_g.h; i++; j++; } @@ -1236,6 +1329,45 @@ vertical_stack(struct workspace *ws, struct swm_geometry *g) { } void +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: + if (ws->l_state.vertical_msize > 1) + ws->l_state.vertical_msize--; + break; + case SWM_ARG_ID_MASTERGROW: + 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; + } +} + +void +vertical_stack(struct workspace *ws, struct swm_geometry *g) +{ + DNPRINTF(SWM_D_STACK, "vertical_stack: workspace: %d\n", ws->idx); + + stack_master(ws, g, 0, 0); +} + +void horizontal_config(struct workspace *ws, int id) { DNPRINTF(SWM_D_STACK, "horizontal_config: workspace: %d\n", ws->idx); @@ -1267,74 +1399,11 @@ horizontal_config(struct workspace *ws, int id) } void -horizontal_stack(struct workspace *ws, struct swm_geometry *g) { - XWindowChanges wc; - struct swm_geometry gg = *g; - struct ws_win *win, *winfocus; - int i, j, split, rowno, hrw, winno, main_height; - unsigned int mask; - - DNPRINTF(SWM_D_STACK, "horizontal_stack: workspace: %d\n", ws->idx); - - if ((winno = count_win(ws, 0)) == 0) - return; - - if (ws->focus == NULL) - ws->focus = TAILQ_FIRST(&ws->winlist); - winfocus = cur_focus ? cur_focus : ws->focus; - - 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; - - i = j = 0; - TAILQ_FOREACH(win, &ws->winlist, entry) { - 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 (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); - else { - bzero(&wc, sizeof wc); - wc.border_width = 1; - win->g.x = wc.x = gg.x; - win->g.y = wc.y = gg.y; - win->g.w = wc.width = gg.w; - win->g.h = wc.height = gg.h; - mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth; - XConfigureWindow(display, win->id, mask, &wc); - } - - XMapRaised(display, win->id); - j++; - i++; - } +horizontal_stack(struct workspace *ws, struct swm_geometry *g) +{ + DNPRINTF(SWM_D_STACK, "vertical_stack: workspace: %d\n", ws->idx); - if (winfocus) - focus_win(winfocus); /* this has to be done outside of the loop */ + stack_master(ws, g, 1, 0); } /* fullscreen view */ @@ -1449,10 +1518,10 @@ screenshot(struct swm_region *r, union arg *args) switch (args->id) { case SWM_ARG_ID_SS_ALL: - spawn_screenshot[1] = "-m"; + spawn_screenshot[1] = "full"; break; case SWM_ARG_ID_SS_WINDOW: - spawn_screenshot[1] = "-s"; /* XXX doesn't work with scrot */ + spawn_screenshot[1] = "window"; break; default: return; @@ -1497,6 +1566,8 @@ struct key { { 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_Right, cyclescr, {.id = SWM_ARG_ID_CYCLESC_UP} }, + { MODKEY | ShiftMask, XK_Left, cyclescr, {.id = SWM_ARG_ID_CYCLESC_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} }, @@ -1685,6 +1756,9 @@ manage_window(Window id) Atom ws_idx_atom = 0, type; unsigned char ws_idx_str[SWM_PROPLEN], *prop = NULL; struct swm_region *r; + long mask; + int ws_idx; + const char *errstr; if ((win = find_window(id)) != NULL) return (win); /* already being managed */ @@ -1701,9 +1775,6 @@ manage_window(Window id) 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) @@ -1732,6 +1803,8 @@ manage_window(Window id) win->g.x = win->wa.x; win->g.y = win->wa.y; + XGetWMNormalHints(display, win->id, &win->sh, &mask); + 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", @@ -1855,16 +1928,16 @@ destroynotify(XEvent *e) ws->focus = TAILQ_PREV(win, ws_win_list, entry); if (ws->focus == NULL) ws->focus = TAILQ_FIRST(&ws->winlist); - if (ws->focus == win) + if (ws->focus == NULL || ws->focus == win) { ws->focus = NULL; - if (cur_focus == win) + unfocus_all(); + } else focus_win(ws->focus); - TAILQ_REMOVE(&ws->winlist, win, entry); set_win_state(win, WithdrawnState); free(win); + stack(); } - stack(); } void