X-Git-Url: https://code.delx.au/spectrwm/blobdiff_plain/0fb39f91df94ac144f7364259225214d773e1b7f..refs/heads/hacking:/spectrwm.c diff --git a/spectrwm.c b/spectrwm.c index f68e08b..a835d00 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -69,6 +69,7 @@ #include #include #include +#include #include #include #include @@ -247,7 +248,8 @@ uint32_t swm_debug = 0 #define MAXIMIZED(w) (MAXIMIZED_VERT(w) || MAXIMIZED_HORZ(w)) #define MANUAL(w) ((w)->ewmh_flags & SWM_F_MANUAL) #define TRANS(w) ((w)->transient != XCB_WINDOW_NONE) -#define FLOATING(w) (ABOVE(w) || TRANS(w) || FULLSCREEN(w) || \ +#define FLOATING(w) (ABOVE(w) || TRANS(w)) +#define FLOATINGFULLMAX(w) (ABOVE(w) || TRANS(w) || FULLSCREEN(w) || \ MAXIMIZED(w)) /* Constrain Window flags */ @@ -395,6 +397,7 @@ int region_padding = 0; int tile_gap = 0; bool java_workaround = true; bool verbose_layout = false; +bool track_pid_ws = true; #ifdef SWM_DEBUG bool debug_enabled; time_t time_started; @@ -497,6 +500,7 @@ void vertical_stack(struct workspace *, struct swm_geometry *); void horizontal_config(struct workspace *, int); void horizontal_stack(struct workspace *, struct swm_geometry *); void max_stack(struct workspace *, struct swm_geometry *); +void max_config(struct workspace *, int); void plain_stacker(struct workspace *); void fancy_stacker(struct workspace *); @@ -511,7 +515,7 @@ struct layout { /* stack, configure */ { vertical_stack, vertical_config, 0, plain_stacker }, { horizontal_stack, horizontal_config, 0, plain_stacker }, - { max_stack, NULL, + { max_stack, max_config, SWM_L_MAPONFOCUS | SWM_L_FOCUSPREV, plain_stacker }, { NULL, NULL, 0, NULL }, }; @@ -598,6 +602,16 @@ struct swm_screen { }; struct swm_screen *screens; +struct layout_config { + bool configured; + int layout; + int master_grow; + int master_add; + int stack_inc; + int always_raise; + bool apply_flip; +} initial_layouts[SWM_WS_MAX]; + /* args to functions */ union arg { int id; @@ -614,7 +628,6 @@ union arg { #define SWM_ARG_ID_MASTERADD (22) #define SWM_ARG_ID_MASTERDEL (23) #define SWM_ARG_ID_FLIPLAYOUT (24) -#define SWM_ARG_ID_STACKRESET (30) #define SWM_ARG_ID_STACKINIT (31) #define SWM_ARG_ID_STACKBALANCE (32) #define SWM_ARG_ID_CYCLEWS_UP (40) @@ -708,6 +721,7 @@ enum { _NET_WM_STATE_SKIP_PAGER, _NET_WM_STATE_SKIP_TASKBAR, _NET_WM_WINDOW_TYPE, + _NET_WM_WINDOW_TYPE_DESKTOP, _NET_WM_WINDOW_TYPE_DIALOG, _NET_WM_WINDOW_TYPE_DOCK, _NET_WM_WINDOW_TYPE_NORMAL, @@ -752,6 +766,7 @@ struct ewmh_hint { {"_NET_WM_STATE_SKIP_PAGER", XCB_ATOM_NONE}, {"_NET_WM_STATE_SKIP_TASKBAR", XCB_ATOM_NONE}, {"_NET_WM_WINDOW_TYPE", XCB_ATOM_NONE}, + {"_NET_WM_WINDOW_TYPE_DESKTOP", XCB_ATOM_NONE}, {"_NET_WM_WINDOW_TYPE_DIALOG", XCB_ATOM_NONE}, {"_NET_WM_WINDOW_TYPE_DOCK", XCB_ATOM_NONE}, {"_NET_WM_WINDOW_TYPE_NORMAL", XCB_ATOM_NONE}, @@ -899,7 +914,7 @@ enum actionid { FN_STACK_BALANCE, FN_STACK_INC, FN_STACK_DEC, - FN_STACK_RESET, + FN_STACK_INIT, FN_SWAP_MAIN, FN_SWAP_NEXT, FN_SWAP_PREV, @@ -985,11 +1000,12 @@ void bar_toggle(struct binding *, struct swm_region *, union arg *); void bar_urgent(char *, size_t); void bar_window_class(char *, size_t, struct swm_region *); void bar_window_class_instance(char *, size_t, struct swm_region *); -void bar_window_float(char *, size_t, struct swm_region *); +void bar_window_index_count(char *, size_t, struct swm_region *); void bar_window_instance(char *, size_t, struct swm_region *); void bar_window_name(char *, size_t, struct swm_region *); void bar_window_state(char *, size_t, struct swm_region *); void bar_workspace_name(char *, size_t, struct swm_region *); +void bar_workspace_state(char *, size_t, struct swm_region *); int binding_cmp(struct binding *, struct binding *); void binding_insert(uint16_t, enum binding_type, uint32_t, enum actionid, uint32_t, const char *); @@ -1033,6 +1049,7 @@ void ewmh_apply_flags(struct ws_win *, uint32_t); void ewmh_autoquirk(struct ws_win *); void ewmh_get_desktop_names(void); void ewmh_get_wm_state(struct ws_win *); +int ewmh_handle_special_types(xcb_window_t, struct swm_region *); void ewmh_update_actions(struct ws_win *); void ewmh_update_client_list(void); void ewmh_update_current_desktop(void); @@ -1097,6 +1114,7 @@ void grab_windows(void); void grabbuttons(void); void grabkeys(void); void iconify(struct binding *, struct swm_region *, union arg *); +void initlayout(struct workspace *); bool isxlfd(char *); bool keybindreleased(struct binding *, xcb_key_release_event_t *); void keypress(xcb_key_press_event_t *); @@ -1508,6 +1526,51 @@ teardown_ewmh(void) } } +int +ewmh_handle_special_types(xcb_window_t id, struct swm_region *region) +{ + xcb_get_property_reply_t *r; + xcb_get_property_cookie_t c; + xcb_atom_t *type; + int i, n; + uint16_t configure_mask = 0; + uint32_t wa[2]; + + c = xcb_get_property(conn, 0, id, + ewmh[_NET_WM_WINDOW_TYPE].atom, XCB_ATOM_ATOM, 0, UINT32_MAX); + r = xcb_get_property_reply(conn, c, NULL); + if (r == NULL) + return 0; + + type = xcb_get_property_value(r); + n = xcb_get_property_value_length(r) / sizeof(xcb_atom_t); + + for (i = 0; i < n; i++) { + if (type[i] == ewmh[_NET_WM_WINDOW_TYPE_DESKTOP].atom) { + configure_mask = XCB_CONFIG_WINDOW_STACK_MODE | + XCB_CONFIG_WINDOW_SIBLING; + wa[0] = region->id; + wa[1] = XCB_STACK_MODE_ABOVE; + break; + } + + if (type[i] == ewmh[_NET_WM_WINDOW_TYPE_DOCK].atom) { + configure_mask = XCB_CONFIG_WINDOW_STACK_MODE; + wa[0] = XCB_STACK_MODE_ABOVE; + break; + } + } + free(r); + + if (configure_mask != 0) { + xcb_map_window(conn, id); + xcb_configure_window (conn, id, configure_mask, wa); + return 1; + } + + return 0; +} + void ewmh_autoquirk(struct ws_win *win) { @@ -1528,8 +1591,7 @@ ewmh_autoquirk(struct ws_win *win) for (i = 0; i < n; i++) { if (type[i] == ewmh[_NET_WM_WINDOW_TYPE_NORMAL].atom) break; - if (type[i] == ewmh[_NET_WM_WINDOW_TYPE_DOCK].atom || - type[i] == ewmh[_NET_WM_WINDOW_TYPE_TOOLBAR].atom || + if (type[i] == ewmh[_NET_WM_WINDOW_TYPE_TOOLBAR].atom || type[i] == ewmh[_NET_WM_WINDOW_TYPE_UTILITY].atom) { win->quirks = SWM_Q_FLOAT | SWM_Q_ANYWHERE; break; @@ -1541,6 +1603,25 @@ ewmh_autoquirk(struct ws_win *win) } } free(r); + + + c = xcb_get_property(conn, 0, win->id, + ewmh[_NET_WM_STATE].atom, XCB_ATOM_ATOM, 0, UINT32_MAX); + r = xcb_get_property_reply(conn, c, NULL); + if (r == NULL) + return; + + type = xcb_get_property_value(r); + n = xcb_get_property_value_length(r) / sizeof(xcb_atom_t); + + for (i = 0; i < n; i++) { + if (type[i] == ewmh[_NET_WM_STATE_SKIP_PAGER].atom || + type[i] == ewmh[_NET_WM_STATE_SKIP_TASKBAR].atom) { + win->quirks = SWM_Q_FLOAT | SWM_Q_ANYWHERE; + break; + } + } + free(r); } void @@ -1659,19 +1740,14 @@ ewmh_apply_flags(struct ws_win *win, uint32_t pending) } if (changed & EWMH_F_ABOVE) { - if (ws->cur_layout != &layouts[SWM_MAX_STACK]) { - if (ABOVE(win)) - load_float_geom(win); - else if (!MAXIMIZED(win)) - store_float_geom(win); + if (ABOVE(win)) + load_float_geom(win); + else if (!MAXIMIZED(win)) + store_float_geom(win); - win->ewmh_flags &= ~EWMH_F_MAXIMIZED; - changed &= ~EWMH_F_MAXIMIZED; - raise_window(win); - } else { - /* Revert. */ - win->ewmh_flags ^= EWMH_F_ABOVE & pending; - } + win->ewmh_flags &= ~EWMH_F_MAXIMIZED; + changed &= ~EWMH_F_MAXIMIZED; + raise_window(win); } if (changed & EWMH_F_MAXIMIZED) { @@ -2352,6 +2428,30 @@ bar_window_class_instance(char *s, size_t sz, struct swm_region *r) bar_window_instance(s, sz, r); } +void +bar_window_index_count(char *s, size_t sz, struct swm_region *r) +{ + struct ws_win *w; + int count, index; + + if (r == NULL || r->ws == NULL || r->ws->focus == NULL) { + strlcat(s, "0/0", sz); + return; + } + + count = 0; + index = 0; + + TAILQ_FOREACH(w, &r->ws->winlist, entry) { + ++count; + if (w->id == r->ws->focus->id) { + index = count; + } + } + + snprintf(s, sz, "%d/%d", index, count); +} + void bar_window_state(char *s, size_t sz, struct swm_region *r) { @@ -2431,6 +2531,44 @@ bar_workspace_name(char *s, size_t sz, struct swm_region *r) strlcat(s, r->ws->name, sz); } +void +bar_workspace_state(char *s, size_t sz, struct swm_region *r) +{ + struct ws_win *win; + int i, j, num_screens; + bool used_workspaces[SWM_WS_MAX]; + char tmp[8]; + int first = 1; + char *fmt; + + if (r == NULL || r->ws == NULL) + return; + + for (i = 0; i < SWM_WS_MAX; ++i) + used_workspaces[i] = false; + + num_screens = get_screen_count(); + for (i = 0; i < num_screens; i++) + for (j = 0; j < workspace_limit; j++) + TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) + ++used_workspaces[win->ws->idx]; + + for (i = 0; i < SWM_WS_MAX; ++i) { + fmt = NULL; + if (i == r->ws->idx) { + fmt = " [%d]"; + } else if (used_workspaces[i]) { + fmt = " %d"; + } + if (fmt) { + fmt = fmt + first; + first = 0; + snprintf(tmp, sizeof tmp, fmt, i + 1); + strlcat(s, tmp, sz); + } + } +} + /* build the default bar format according to the defined enabled options */ void bar_fmt(const char *fmtexp, char *fmtnew, struct swm_region *r, size_t sz) @@ -2553,6 +2691,9 @@ bar_replace_seq(char *fmt, char *fmtrep, struct swm_region *r, size_t *offrep, case 'I': snprintf(tmp, sizeof tmp, "%d", r->ws->idx + 1); break; + case 'i': + bar_workspace_state(tmp, sizeof tmp, r); + break; case 'M': count = 0; TAILQ_FOREACH(w, &r->ws->winlist, entry) @@ -2564,6 +2705,9 @@ bar_replace_seq(char *fmt, char *fmtrep, struct swm_region *r, size_t *offrep, case 'N': snprintf(tmp, sizeof tmp, "%d", r->s->idx + 1); break; + case 'p': + bar_window_index_count(tmp, sizeof tmp, r); + break; case 'P': bar_window_class_instance(tmp, sizeof tmp, r); break; @@ -3209,13 +3353,13 @@ config_win(struct ws_win *win, xcb_configure_request_event_t *ev) } int -count_win(struct workspace *ws, bool count_transient) +count_win(struct workspace *ws, bool count_floating) { struct ws_win *win; int count = 0; TAILQ_FOREACH(win, &ws->winlist, entry) { - if (!count_transient && FLOATING(win)) + if (!count_floating && FLOATING(win)) continue; if (ICONIC(win)) continue; @@ -3360,11 +3504,11 @@ raise_window(struct ws_win *win) void update_win_stacking(struct ws_win *win) { - struct ws_win *sibling; #ifdef SWM_DEBUG struct ws_win *w; #endif struct swm_region *r; + uint16_t configure_mask; uint32_t val[2]; if (win == NULL || (r = win->ws->r) == NULL) @@ -3376,23 +3520,25 @@ update_win_stacking(struct ws_win *win) return; } - sibling = TAILQ_NEXT(win, stack_entry); - if (sibling != NULL && (FLOATING(win) == FLOATING(sibling) || - (win->ws->always_raise && win->ws->focus == win))) - val[0] = sibling->frame; - else if (FLOATING(win) || (win->ws->always_raise && - win->ws->focus == win)) - val[0] = r->bar->id; - else - val[0] = r->id; + if (FLOATINGFULLMAX(win) || (win->ws->always_raise && + win->ws->focus == win)) { + configure_mask = XCB_CONFIG_WINDOW_STACK_MODE; + val[0] = XCB_STACK_MODE_ABOVE; + val[1] = 0; - DNPRINTF(SWM_D_EVENT, "update_win_stacking: win %#x (%#x), " - "sibling %#x\n", win->frame, win->id, val[0]); + DNPRINTF(SWM_D_EVENT, "update_win_stacking: to very top " + "win %#x (%#x), ", win->frame, win->id); + } else { + configure_mask = XCB_CONFIG_WINDOW_STACK_MODE | + XCB_CONFIG_WINDOW_SIBLING; + val[0] = r->bar->id; + val[1] = XCB_STACK_MODE_BELOW; - val[1] = XCB_STACK_MODE_ABOVE; + DNPRINTF(SWM_D_EVENT, "update_win_stacking: to tile top " + "win %#x (%#x), ", win->frame, win->id); + } - xcb_configure_window(conn, win->frame, XCB_CONFIG_WINDOW_SIBLING | - XCB_CONFIG_WINDOW_STACK_MODE, val); + xcb_configure_window(conn, win->frame, configure_mask, val); #ifdef SWM_DEBUG TAILQ_FOREACH(w, &win->ws->winlist, entry) @@ -3712,32 +3858,34 @@ spawn(int ws_idx, union arg *args, bool close_fd) close(xcb_get_file_descriptor(conn)); - if ((ret = getenv("LD_PRELOAD"))) { - if (asprintf(&ret, "%s:%s", SWM_LIB, ret) == -1) { - warn("spawn: asprintf LD_PRELOAD"); + if (track_pid_ws) { + if ((ret = getenv("LD_PRELOAD"))) { + if (asprintf(&ret, "%s:%s", SWM_LIB, ret) == -1) { + warn("spawn: asprintf LD_PRELOAD"); + _exit(1); + } + setenv("LD_PRELOAD", ret, 1); + free(ret); + } else { + setenv("LD_PRELOAD", SWM_LIB, 1); + } + + if (asprintf(&ret, "%d", ws_idx) == -1) { + warn("spawn: asprintf SWM_WS"); _exit(1); } - setenv("LD_PRELOAD", ret, 1); + setenv("_SWM_WS", ret, 1); free(ret); - } else { - setenv("LD_PRELOAD", SWM_LIB, 1); - } + ret = NULL; - if (asprintf(&ret, "%d", ws_idx) == -1) { - warn("spawn: asprintf SWM_WS"); - _exit(1); - } - setenv("_SWM_WS", ret, 1); - free(ret); - ret = NULL; - - if (asprintf(&ret, "%d", getpid()) == -1) { - warn("spawn: asprintf _SWM_PID"); - _exit(1); + if (asprintf(&ret, "%d", getpid()) == -1) { + warn("spawn: asprintf _SWM_PID"); + _exit(1); + } + setenv("_SWM_PID", ret, 1); + free(ret); + ret = NULL; } - setenv("_SWM_PID", ret, 1); - free(ret); - ret = NULL; if (setsid() == -1) { warn("spawn: setsid"); @@ -4513,9 +4661,6 @@ swapwin(struct binding *bp, struct swm_region *r, union arg *args) goto out; } - if (r->ws->cur_layout == &layouts[SWM_MAX_STACK]) - return; - clear_maximized(r->ws); source = cur_focus; @@ -4890,14 +5035,15 @@ stack_config(struct binding *bp, struct swm_region *r, union arg *args) DNPRINTF(SWM_D_STACK, "stack_config: id: %d workspace: %d\n", args->id, ws->idx); - if (clear_maximized(ws) > 0) - stack(r); - - if (ws->cur_layout->l_config != NULL) + if (args->id == SWM_ARG_ID_STACKINIT) { + initlayout(ws); + } else { ws->cur_layout->l_config(ws, args->id); + } + + clear_maximized(ws); + stack(r); - if (args->id != SWM_ARG_ID_STACKINIT) - stack(r); bar_draw(r->bar); center_pointer(r); @@ -5209,7 +5355,7 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, bool flip) if (ICONIC(win)) continue; - if (FLOATING(win)) { + if (FLOATINGFULLMAX(win)) { update_floater(win); continue; } @@ -5343,7 +5489,6 @@ vertical_config(struct workspace *ws, int id) id, 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; @@ -5396,7 +5541,6 @@ horizontal_config(struct workspace *ws, int id) 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; @@ -5449,15 +5593,13 @@ max_stack(struct workspace *ws, struct swm_geometry *g) { struct swm_geometry gg = *g; struct ws_win *w, *win = NULL, *parent = NULL, *tmpw; - int winno; DNPRINTF(SWM_D_STACK, "max_stack: workspace: %d\n", ws->idx); if (ws == NULL) return; - winno = count_win(ws, false); - if (winno == 0 && count_win(ws, true) == 0) + if (count_win(ws, true) == 0) return; /* Figure out which top level window should be visible. */ @@ -5480,17 +5622,13 @@ max_stack(struct workspace *ws, struct swm_geometry *g) if (ICONIC(w)) continue; - if (TRANS(w)) { + if (TRANS(w) || ABOVE(w)) { update_floater(w); continue; } /* Set maximized flag for all maxed windows. */ if (!MAXIMIZED(w)) { - /* Preserve floating geometry. */ - if (ABOVE(w)) - store_float_geom(w); - ewmh_apply_flags(w, w->ewmh_flags | EWMH_F_MAXIMIZED); ewmh_update_wm_state(w); } @@ -5537,6 +5675,16 @@ max_stack(struct workspace *ws, struct swm_geometry *g) map_window(w); } +void +max_config(struct workspace *ws, int id) +{ + /* suppress unused warning since vars are needed */ + (void)ws; + (void)id; + + DNPRINTF(SWM_D_STACK, "max_config: workspace: %d (noop)\n", ws->idx); +} + void send_to_rg(struct binding *bp, struct swm_region *r, union arg *args) { @@ -6879,8 +7027,8 @@ resize_win(struct ws_win *win, struct binding *bp, int opt) if (FULLSCREEN(win)) return; - /* In max_stack mode, should only resize transients. */ - if (win->ws->cur_layout == &layouts[SWM_MAX_STACK] && !TRANS(win)) + /* In max_stack mode, should only resize transients/floating. */ + if (win->ws->cur_layout == &layouts[SWM_MAX_STACK] && !TRANS(win) && !ABOVE(win)) return; DNPRINTF(SWM_D_EVENT, "resize: win %#x, floating: %s, " @@ -7168,10 +7316,6 @@ move_win(struct ws_win *win, struct binding *bp, int opt) DNPRINTF(SWM_D_EVENT, "move: win %#x, floating: %s, transient: " "%#x\n", win->id, YESNO(ABOVE(win)), win->transient); - /* in max_stack mode should only move transients */ - if (win->ws->cur_layout == &layouts[SWM_MAX_STACK] && !TRANS(win)) - return; - if (!(ABOVE(win) || TRANS(win)) || MAXIMIZED(win)) { store_float_geom(win); restack = true; @@ -7454,7 +7598,7 @@ struct action { { "stack_balance", stack_config, 0, {.id = SWM_ARG_ID_STACKBALANCE} }, { "stack_inc", stack_config, 0, {.id = SWM_ARG_ID_STACKINC} }, { "stack_dec", stack_config, 0, {.id = SWM_ARG_ID_STACKDEC} }, - { "stack_reset", stack_config, 0, {.id = SWM_ARG_ID_STACKRESET} }, + { "stack_reset", stack_config, 0, {.id = SWM_ARG_ID_STACKINIT} }, { "swap_main", swapwin, 0, {.id = SWM_ARG_ID_SWAPMAIN} }, { "swap_next", swapwin, 0, {.id = SWM_ARG_ID_SWAPNEXT} }, { "swap_prev", swapwin, 0, {.id = SWM_ARG_ID_SWAPPREV} }, @@ -8236,7 +8380,7 @@ setup_keybindings(void) BINDKEYSPAWN(MODSHIFT, XK_Return, "term"); BINDKEY(MODSHIFT, XK_comma, FN_STACK_INC); BINDKEY(MODSHIFT, XK_period, FN_STACK_DEC); - BINDKEY(MODSHIFT, XK_space, FN_STACK_RESET); + BINDKEY(MODSHIFT, XK_space, FN_STACK_INIT); BINDKEY(MODKEY, XK_Return, FN_SWAP_MAIN); BINDKEY(MODSHIFT, XK_j, FN_SWAP_NEXT); BINDKEY(MODSHIFT, XK_k, FN_SWAP_PREV); @@ -8861,6 +9005,7 @@ enum { SWM_S_STACK_ENABLED, SWM_S_TERM_WIDTH, SWM_S_TILE_GAP, + SWM_S_TRACK_PID_WS, SWM_S_URGENT_COLLAPSE, SWM_S_URGENT_ENABLED, SWM_S_VERBOSE_LAYOUT, @@ -9069,6 +9214,9 @@ setconfvalue(const char *selector, const char *value, int flags) case SWM_S_TILE_GAP: tile_gap = atoi(value); break; + case SWM_S_TRACK_PID_WS: + track_pid_ws = atoi(value); + break; case SWM_S_URGENT_COLLAPSE: urgent_collapse = (atoi(value) != 0); break; @@ -9294,7 +9442,7 @@ int setlayout(const char *selector, const char *value, int flags) { struct workspace *ws; - int ws_id, i, x, mg, ma, si, ar; + int ws_id, i, mg, ma, si, ar; int st = SWM_V_STACK, num_screens; char s[1024]; bool f = false; @@ -9303,9 +9451,6 @@ setlayout(const char *selector, const char *value, int flags) (void)selector; (void)flags; - if (getenv("SWM_STARTED")) - return (0); - bzero(s, sizeof s); if (sscanf(value, "ws[%d]:%d:%d:%d:%d:%1023c", &ws_id, &mg, &ma, &si, &ar, s) != 6) @@ -9328,46 +9473,69 @@ setlayout(const char *selector, const char *value, int flags) f = true; } else if (strcasecmp(s, "fullscreen") == 0) st = SWM_MAX_STACK; - else + else { errx(1, "invalid layout entry, should be 'ws[]:" "::::" "'"); + return 0; + } + + initial_layouts[ws_id].configured = true; + initial_layouts[ws_id].layout = st; + initial_layouts[ws_id].master_grow = mg; + initial_layouts[ws_id].master_add = ma; + initial_layouts[ws_id].stack_inc = si; + initial_layouts[ws_id].always_raise = ar; + initial_layouts[ws_id].apply_flip = f; num_screens = get_screen_count(); - for (i = 0; i < num_screens; i++) { - ws = (struct workspace *)&screens[i].ws; - ws[ws_id].cur_layout = &layouts[st]; + for (i = 0; i < num_screens; ++i) { + ws = &screens[i].ws[ws_id]; + initlayout(ws); + } - ws[ws_id].always_raise = (ar != 0); - if (st == SWM_MAX_STACK) - continue; + return 0; +} - /* master grow */ - for (x = 0; x < abs(mg); x++) { - ws[ws_id].cur_layout->l_config(&ws[ws_id], - mg >= 0 ? SWM_ARG_ID_MASTERGROW : - SWM_ARG_ID_MASTERSHRINK); - } - /* master add */ - for (x = 0; x < abs(ma); x++) { - ws[ws_id].cur_layout->l_config(&ws[ws_id], - ma >= 0 ? SWM_ARG_ID_MASTERADD : - SWM_ARG_ID_MASTERDEL); - } - /* stack inc */ - for (x = 0; x < abs(si); x++) { - ws[ws_id].cur_layout->l_config(&ws[ws_id], - si >= 0 ? SWM_ARG_ID_STACKINC : - SWM_ARG_ID_STACKDEC); - } - /* Apply flip */ - if (f) { - ws[ws_id].cur_layout->l_config(&ws[ws_id], - SWM_ARG_ID_FLIPLAYOUT); - } - } +void +initlayout(struct workspace *ws) +{ + int i, ws_id; - return (0); + ws_id = ws->idx; + + if (!initial_layouts[ws_id].configured) + return; + + ws->cur_layout = &layouts[initial_layouts[ws_id].layout]; + + ws->cur_layout->l_config(ws, SWM_ARG_ID_STACKINIT); + + ws->always_raise = (initial_layouts[ws_id].always_raise != 0); + + /* master grow */ + for (i = 0; i < abs(initial_layouts[ws_id].master_grow); i++) { + ws->cur_layout->l_config(ws, + initial_layouts[ws_id].master_grow >= 0 ? SWM_ARG_ID_MASTERGROW : + SWM_ARG_ID_MASTERSHRINK); + } + /* master add */ + for (i = 0; i < abs(initial_layouts[ws_id].master_add); i++) { + ws->cur_layout->l_config(ws, + initial_layouts[ws_id].master_add >= 0 ? SWM_ARG_ID_MASTERADD : + SWM_ARG_ID_MASTERDEL); + } + /* stack inc */ + for (i = 0; i < abs(initial_layouts[ws_id].stack_inc); i++) { + ws->cur_layout->l_config(ws, + initial_layouts[ws_id].stack_inc >= 0 ? SWM_ARG_ID_STACKINC : + SWM_ARG_ID_STACKDEC); + } + /* Apply flip */ + if (initial_layouts[ws_id].apply_flip) { + ws->cur_layout->l_config(ws, + SWM_ARG_ID_FLIPLAYOUT); + } } /* config options */ @@ -9427,6 +9595,7 @@ struct config_option configopt[] = { { "tile_gap", setconfvalue, SWM_S_TILE_GAP }, { "title_class_enabled", setconfvalue, SWM_S_WINDOW_CLASS_ENABLED }, /* For backwards compat. */ { "title_name_enabled", setconfvalue, SWM_S_WINDOW_INSTANCE_ENABLED }, /* For backwards compat. */ + { "track_pid_ws", setconfvalue, SWM_S_TRACK_PID_WS }, { "urgent_collapse", setconfvalue, SWM_S_URGENT_COLLAPSE }, { "urgent_enabled", setconfvalue, SWM_S_URGENT_ENABLED }, { "verbose_layout", setconfvalue, SWM_S_VERBOSE_LAYOUT }, @@ -9569,6 +9738,10 @@ conf_load(const char *filename, int keymapping) configopt[optidx].optname); continue; } + /* trim trailing spaces */ + ce = optval + strlen(optval) - 1; + while (ce > optval && isspace(*ce)) --ce; + *(ce + 1) = '\0'; /* call function to deal with it all */ if (configopt[optidx].func(optsub, optval, configopt[optidx].funcflags) != 0) { @@ -9835,11 +10008,6 @@ manage_window(xcb_window_t id, int spawn_pos, bool mapping) DNPRINTF(SWM_D_MISC, "manage_window: win %#x found on " "unmanaged list.\n", id); TAILQ_REMOVE(&win->ws->unmanagedlist, win, entry); - - if (TRANS(win)) - set_child_transient(win, &trans); - - goto remanage; } else { DNPRINTF(SWM_D_MISC, "manage_window: win %#x is new.\n", id); } @@ -9871,15 +10039,24 @@ manage_window(xcb_window_t id, int spawn_pos, bool mapping) goto out; } - /* Create and initialize ws_win object. */ - if ((win = calloc(1, sizeof(struct ws_win))) == NULL) - err(1, "manage_window: calloc: failed to allocate memory for " - "new window"); + /* Figure out which region the window belongs to. */ + r = root_to_region(gr->root, SWM_CK_ALL); - win->id = id; + /* Handle special windows with special _NET_WM_WINDOW_TYPE */ + if (ewmh_handle_special_types(id, r)) { + DNPRINTF(SWM_D_EVENT, "manage_window: " + "unmanaged ewmh window type\n"); + goto out; + } - /* Figureout which region the window belongs to. */ - r = root_to_region(gr->root, SWM_CK_ALL); + if (!win) { + /* Create and initialize ws_win object. */ + if ((win = calloc(1, sizeof(struct ws_win))) == NULL) + err(1, "manage_window: calloc: failed to allocate " + "memory for new window"); + + win->id = id; + } /* Ignore window border if there is one. */ WIDTH(win) = gr->width; @@ -10010,7 +10187,6 @@ manage_window(xcb_window_t id, int spawn_pos, bool mapping) update_window(win); } -remanage: /* Figure out where to insert the window in the workspace list. */ if (trans && (ww = find_window(trans))) TAILQ_INSERT_AFTER(&win->ws->winlist, ww, win, entry); @@ -11096,7 +11272,7 @@ reparentnotify(xcb_reparent_notify_event_t *e) if (win->state == SWM_WIN_STATE_REPARENTING) { win->state = SWM_WIN_STATE_REPARENTED; - if (win->ws->r) + if (win->ws->r && !ICONIC(win)) map_window(win); else unmap_window(win); @@ -11522,7 +11698,6 @@ scan_randr(int idx) int ncrtc = 0; #endif /* SWM_XRR_HAS_CRTC */ struct swm_region *r; - struct ws_win *win; int num_screens; xcb_randr_get_screen_resources_current_cookie_t src; xcb_randr_get_screen_resources_current_reply_t *srr; @@ -11597,13 +11772,8 @@ scan_randr(int idx) screen->height_in_pixels); out: - /* Cleanup unused previously visible workspaces. */ + /* The screen shouldn't focus on unused regions. */ TAILQ_FOREACH(r, &screens[idx].orl, entry) { - TAILQ_FOREACH(win, &r->ws->winlist, entry) - unmap_window(win); - r->ws->state = SWM_WS_STATE_HIDDEN; - - /* The screen shouldn't focus on an unused region. */ if (screens[idx].r_focus == r) screens[idx].r_focus = NULL; } @@ -11615,7 +11785,9 @@ void screenchange(xcb_randr_screen_change_notify_event_t *e) { struct swm_region *r; - int i, num_screens; + struct workspace *ws; + struct ws_win *win; + int i, j, num_screens; DNPRINTF(SWM_D_EVENT, "screenchange: root: %#x\n", e->root); @@ -11648,6 +11820,16 @@ screenchange(xcb_randr_screen_change_notify_event_t *e) focus_region(r); } + /* Cleanup unused previously visible workspaces. */ + for (j = 0; j < workspace_limit; j++) { + ws = &screens[i].ws[j]; + if (ws->r == NULL && ws->state != SWM_WS_STATE_HIDDEN) { + TAILQ_FOREACH(win, &ws->winlist, entry) + unmap_window(win); + ws->state = SWM_WS_STATE_HIDDEN; + } + } + focus_flush(); /* Update workspace state and bar on all regions. */ @@ -11830,9 +12012,7 @@ setup_screens(void) TAILQ_INIT(&ws->unmanagedlist); for (k = 0; layouts[k].l_stack != NULL; k++) - if (layouts[k].l_config != NULL) - layouts[k].l_config(ws, - SWM_ARG_ID_STACKINIT); + layouts[k].l_config(ws, SWM_ARG_ID_STACKINIT); ws->cur_layout = &layouts[0]; ws->cur_layout->l_string(ws); }