X-Git-Url: https://code.delx.au/spectrwm/blobdiff_plain/22faec83542aea52c2b6552ea1625e9ae1179c91..52e240df35f04eefeef7596afc12893130d22725:/spectrwm.c diff --git a/spectrwm.c b/spectrwm.c index 5840b0d..dde9b70 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -23,38 +23,6 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* - * Much code and ideas taken from dwm under the following license: - * MIT/X Consortium License - * - * 2006-2008 Anselm R Garbe - * 2006-2007 Sander van Dijk - * 2006-2007 Jukka Salmi - * 2007 Premysl Hruby - * 2007 Szabolcs Nagy - * 2007 Christof Musik - * 2007-2008 Enno Gottox Boland - * 2007-2008 Peter Hartlich - * 2008 Martin Hurton - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ /* kernel includes */ #include @@ -101,6 +69,7 @@ #include #include #include +#include #include #include #include @@ -249,7 +218,6 @@ uint32_t swm_debug = 0 #define MOUSEMASK (BUTTONMASK|XCB_EVENT_MASK_POINTER_MOTION) #define SWM_PROPLEN (16) #define SWM_FUNCNAME_LEN (32) -#define SWM_KEYS_LEN (255) #define SWM_QUIRK_LEN (64) #define X(r) ((r)->g.x) #define Y(r) ((r)->g.y) @@ -297,17 +265,12 @@ uint32_t swm_debug = 0 #define SWM_FOCUS_FOLLOW (1) #define SWM_FOCUS_MANUAL (2) -#define SWM_CK_NONE (0) #define SWM_CK_ALL (0xf) #define SWM_CK_FOCUS (0x1) #define SWM_CK_POINTER (0x2) #define SWM_CK_FALLBACK (0x4) #define SWM_CK_REGION (0x8) -#define SWM_G_ALL (0xf) -#define SWM_G_SIZE (0x1) -#define SWM_G_POS (0x2) - #define SWM_CONF_DEFAULT (0) #define SWM_CONF_KEYMAPPING (1) @@ -572,6 +535,7 @@ struct workspace { struct ws_win *focus; /* may be NULL */ struct ws_win *focus_prev; /* may be NULL */ struct ws_win *focus_pending; /* may be NULL */ + struct ws_win *focus_raise; /* may be NULL */ struct swm_region *r; /* may be NULL */ struct swm_region *old_r; /* may be NULL */ struct ws_win_list winlist; /* list of windows in ws */ @@ -664,8 +628,6 @@ union arg { #define SWM_ARG_ID_CYCLEWS_MOVE_DOWN (47) #define SWM_ARG_ID_STACKINC (50) #define SWM_ARG_ID_STACKDEC (51) -#define SWM_ARG_ID_SS_ALL (60) -#define SWM_ARG_ID_SS_WINDOW (61) #define SWM_ARG_ID_DONTCENTER (70) #define SWM_ARG_ID_CENTER (71) #define SWM_ARG_ID_KILLWINDOW (80) @@ -678,8 +640,6 @@ union arg { #define SWM_ARG_ID_MOVEDOWN (101) #define SWM_ARG_ID_MOVELEFT (102) #define SWM_ARG_ID_MOVERIGHT (103) -#define SWM_ARG_ID_RAISE (105) -#define SWM_ARG_ID_LOWER (106) #define SWM_ARG_ID_BAR_TOGGLE (110) #define SWM_ARG_ID_BAR_TOGGLE_WS (111) #define SWM_ARG_ID_CYCLERG_MOVE_UP (112) @@ -749,6 +709,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, @@ -793,6 +754,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}, @@ -865,6 +827,7 @@ enum actionid { FN_FOCUS_NEXT, FN_FOCUS_PREV, FN_FOCUS_URGENT, + FN_FULLSCREEN_TOGGLE, FN_MAXIMIZE_TOGGLE, FN_HEIGHT_GROW, FN_HEIGHT_SHRINK, @@ -887,6 +850,8 @@ enum actionid { FN_MVRG_7, FN_MVRG_8, FN_MVRG_9, + KF_MVRG_NEXT, + KF_MVRG_PREV, FN_MVWS_1, FN_MVWS_2, FN_MVWS_3, @@ -911,6 +876,7 @@ enum actionid { FN_MVWS_22, FN_NAME_WORKSPACE, FN_QUIT, + FN_RAISE, FN_RAISE_TOGGLE, FN_RESIZE, FN_RESIZE_CENTERED, @@ -1022,7 +988,6 @@ 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_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 *); @@ -1070,6 +1035,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); @@ -1099,6 +1065,7 @@ void focusout(xcb_focus_out_event_t *); void focusrg(struct binding *, struct swm_region *, union arg *); void fontset_init(void); void free_window(struct ws_win *); +void fullscreen_toggle(struct binding *, struct swm_region *, union arg *); xcb_atom_t get_atom_from_string(const char *); #ifdef SWM_DEBUG char *get_atom_name(xcb_atom_t); @@ -1174,6 +1141,7 @@ void quirk_remove(struct quirk *); void quirk_replace(struct quirk *, const char *, const char *, const char *, uint32_t, int); void quit(struct binding *, struct swm_region *, union arg *); +void raise_focus(struct binding *, struct swm_region *, union arg *); void raise_toggle(struct binding *, struct swm_region *, union arg *); void raise_window(struct ws_win *); void region_containment(struct ws_win *, struct swm_region *, int); @@ -1196,6 +1164,7 @@ void search_win(struct binding *, struct swm_region *, union arg *); void search_win_cleanup(void); void search_workspace(struct binding *, struct swm_region *, union arg *); void send_to_rg(struct binding *, struct swm_region *, union arg *); +void send_to_rg_relative(struct binding *, struct swm_region *, union arg *); void send_to_ws(struct binding *, struct swm_region *, union arg *); void set_region(struct swm_region *); int setautorun(const char *, const char *, int); @@ -1542,6 +1511,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) { @@ -1562,8 +1576,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; @@ -1575,6 +1588,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 @@ -2452,7 +2484,7 @@ bar_urgent(char *s, size_t sz) strlcat(s, "- ", sz); } } - if(urgent_collapse && s[0]) + if (urgent_collapse && s[0]) s[strlen(s) - 1] = 0; } @@ -3412,18 +3444,20 @@ update_win_stacking(struct ws_win *win) sibling = TAILQ_NEXT(win, stack_entry); if (sibling != NULL && (FLOATING(win) == FLOATING(sibling) || - (win->ws->always_raise && win->ws->focus == win))) + (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[1] = XCB_STACK_MODE_ABOVE; + } else if (FLOATING(win) || (win->ws->always_raise && + win->ws->focus == win)) { val[0] = r->bar->id; - else - val[0] = r->id; + val[1] = XCB_STACK_MODE_ABOVE; + } else { + val[0] = r->bar->id; + val[1] = XCB_STACK_MODE_BELOW; + } DNPRINTF(SWM_D_EVENT, "update_win_stacking: win %#x (%#x), " - "sibling %#x\n", win->frame, win->id, val[0]); - - val[1] = XCB_STACK_MODE_ABOVE; + "sibling %#x mode %#x\n", win->frame, win->id, val[0], val[1]); xcb_configure_window(conn, win->frame, XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE, val); @@ -3746,7 +3780,16 @@ spawn(int ws_idx, union arg *args, bool close_fd) close(xcb_get_file_descriptor(conn)); - setenv("LD_PRELOAD", SWM_LIB, 1); + 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"); @@ -3812,6 +3855,8 @@ kill_refs(struct ws_win *win) ws->focus_prev = NULL; if (win == ws->focus_pending) ws->focus_pending = NULL; + if (win == ws->focus_raise) + ws->focus_raise = NULL; if (TRANS(win)) TAILQ_FOREACH(w, &ws->winlist, entry) @@ -3897,6 +3942,9 @@ unfocus_win(struct ws_win *win) if (win->ws->focus == win) { win->ws->focus = NULL; win->ws->focus_prev = win; + if (win->ws->focus_raise == win && !FLOATING(win)) { + update_win_stacking(win); + } } if (validate_win(win->ws->focus)) { @@ -4164,6 +4212,10 @@ set_region(struct swm_region *r) r->s->r_focus = r; + /* Update the focus window frame on the now unfocused region. */ + if (rf && rf->ws->focus) + draw_frame(rf->ws->focus); + ewmh_update_current_desktop(); } @@ -4208,8 +4260,6 @@ switchws(struct binding *bp, struct swm_region *r, union arg *args) int wsid = args->id; bool unmap_old = false; - (void)bp; - if (!(r && r->s)) return; @@ -4229,7 +4279,8 @@ switchws(struct binding *bp, struct swm_region *r, union arg *args) return; other_r = new_ws->r; - if (other_r && workspace_clamp) { + if (other_r && workspace_clamp && + bp->action != FN_RG_MOVE_NEXT && bp->action != FN_RG_MOVE_PREV) { DNPRINTF(SWM_D_WS, "switchws: ws clamped.\n"); if (warp_focus) { @@ -5668,6 +5719,30 @@ send_to_ws(struct binding *bp, struct swm_region *r, union arg *args) focus_flush(); } +/* Transfer focused window to region-relative workspace and focus. */ +void +send_to_rg_relative(struct binding *bp, struct swm_region *r, union arg *args) +{ + union arg args_abs; + struct swm_region *r_other; + + if (args->id == 1) { + r_other = TAILQ_NEXT(r, entry); + if (r_other == NULL) + r_other = TAILQ_FIRST(&r->s->rl); + } else { + r_other = TAILQ_PREV(r, swm_region_list, entry); + if (r_other == NULL) + r_other = TAILQ_LAST(&r->s->rl, swm_region_list); + } + + /* Map relative to absolute */ + args_abs = *args; + args_abs.id = r_other->ws->idx; + + send_to_ws(bp, r, &args_abs); +} + void win_to_ws(struct ws_win *win, int wsid, bool unfocus) { @@ -5775,6 +5850,31 @@ pressbutton(struct binding *bp, struct swm_region *r, union arg *args) XCB_CURRENT_TIME, XCB_WINDOW_NONE, 0, 0, 0); } +void +raise_focus(struct binding *bp, struct swm_region *r, union arg *args) +{ + struct ws_win *win; + uint32_t val; + + /* Suppress warning. */ + (void)bp; + (void)args; + + if (r == NULL || r->ws == NULL || r->ws->focus == NULL) + return; + + win = r->ws->focus; + r->ws->focus_raise = win; + raise_window(win); + + /* Temporarily override stacking order also in the stack */ + if (!FLOATING(win)) { + val = XCB_STACK_MODE_ABOVE; + xcb_configure_window(conn, win->frame, + XCB_CONFIG_WINDOW_STACK_MODE, &val); + } +} + void raise_toggle(struct binding *bp, struct swm_region *r, union arg *args) { @@ -6157,7 +6257,7 @@ ewmh_update_desktop_names(void) ++len; } - if((name_list = calloc(len, sizeof(char))) == NULL) + if ((name_list = calloc(len, sizeof(char))) == NULL) err(1, "update_desktop_names: calloc: failed to " "allocate memory."); @@ -6535,6 +6635,32 @@ floating_toggle(struct binding *bp, struct swm_region *r, union arg *args) DNPRINTF(SWM_D_MISC, "floating_toggle: done\n"); } +void +fullscreen_toggle(struct binding *bp, struct swm_region *r, union arg *args) +{ + struct ws_win *w = r->ws->focus; + + /* suppress unused warning since var is needed */ + (void)bp; + (void)args; + + if (w == NULL) + return; + + DNPRINTF(SWM_D_MISC, "fullscreen_toggle: win %#x\n", w->id); + + ewmh_apply_flags(w, w->ewmh_flags ^ EWMH_F_FULLSCREEN); + ewmh_update_wm_state(w); + + stack(r); + + if (w == w->ws->focus) + focus_win(w); + + center_pointer(r); + focus_flush(); + DNPRINTF(SWM_D_MISC, "fullscreen_toggle: done\n"); +} void region_containment(struct ws_win *win, struct swm_region *r, int opts) { @@ -7321,6 +7447,7 @@ struct action { { "focus_next", focus, 0, {.id = SWM_ARG_ID_FOCUSNEXT} }, { "focus_prev", focus, 0, {.id = SWM_ARG_ID_FOCUSPREV} }, { "focus_urgent", focus, 0, {.id = SWM_ARG_ID_FOCUSURGENT} }, + { "fullscreen_toggle", fullscreen_toggle, 0, {0} }, { "maximize_toggle", maximize_toggle,0, {0} }, { "height_grow", resize, 0, {.id = SWM_ARG_ID_HEIGHTGROW} }, { "height_shrink", resize, 0, {.id = SWM_ARG_ID_HEIGHTSHRINK} }, @@ -7343,6 +7470,8 @@ struct action { { "mvrg_7", send_to_rg, 0, {.id = 6} }, { "mvrg_8", send_to_rg, 0, {.id = 7} }, { "mvrg_9", send_to_rg, 0, {.id = 8} }, + { "mvrg_next", send_to_rg_relative, 0, {.id = 1} }, + { "mvrg_prev", send_to_rg_relative, 0, {.id = -1} }, { "mvws_1", send_to_ws, 0, {.id = 0} }, { "mvws_2", send_to_ws, 0, {.id = 1} }, { "mvws_3", send_to_ws, 0, {.id = 2} }, @@ -7367,6 +7496,7 @@ struct action { { "mvws_22", send_to_ws, 0, {.id = 21} }, { "name_workspace", name_workspace, 0, {0} }, { "quit", quit, 0, {0} }, + { "raise", raise_focus, 0, {0} }, { "raise_toggle", raise_toggle, 0, {0} }, { "resize", resize, FN_F_NOREPLAY, {.id = SWM_ARG_ID_DONTCENTER} }, { "resize_centered", resize, FN_F_NOREPLAY, {.id = SWM_ARG_ID_CENTER} }, @@ -8104,6 +8234,7 @@ setup_keybindings(void) BINDKEY(MODKEY, XK_k, FN_FOCUS_PREV); BINDKEY(MODSHIFT, XK_Tab, FN_FOCUS_PREV); BINDKEY(MODKEY, XK_u, FN_FOCUS_URGENT); + BINDKEY(MODSHIFT, XK_e, FN_FULLSCREEN_TOGGLE); BINDKEY(MODKEY, XK_e, FN_MAXIMIZE_TOGGLE); BINDKEY(MODSHIFT, XK_equal, FN_HEIGHT_GROW); BINDKEY(MODSHIFT, XK_minus, FN_HEIGHT_SHRINK); @@ -8149,6 +8280,7 @@ setup_keybindings(void) BINDKEY(MODSHIFT, XK_F12, FN_MVWS_22); BINDKEY(MODSHIFT, XK_slash, FN_NAME_WORKSPACE); BINDKEY(MODSHIFT, XK_q, FN_QUIT); + BINDKEY(MODKEY, XK_r, FN_RAISE); BINDKEY(MODSHIFT, XK_r, FN_RAISE_TOGGLE); BINDKEY(MODKEY, XK_q, FN_RESTART); BINDKEY(MODKEY, XK_KP_End, FN_RG_1); @@ -9771,11 +9903,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); } @@ -9807,15 +9934,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); + + /* 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; + } - win->id = id; + 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"); - /* Figureout which region the window belongs to. */ - r = root_to_region(gr->root, SWM_CK_ALL); + win->id = id; + } /* Ignore window border if there is one. */ WIDTH(win) = gr->width; @@ -9946,7 +10082,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); @@ -10357,7 +10492,7 @@ get_stack_mode_name(uint8_t mode) { char *name; - switch(mode) { + switch (mode) { case XCB_STACK_MODE_ABOVE: name = "Above"; break; @@ -11032,7 +11167,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); @@ -11458,7 +11593,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; @@ -11533,13 +11667,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; } @@ -11551,7 +11680,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); @@ -11584,6 +11715,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. */ @@ -11757,6 +11898,7 @@ setup_screens(void) ws->focus = NULL; ws->focus_prev = NULL; ws->focus_pending = NULL; + ws->focus_raise = NULL; ws->r = NULL; ws->old_r = NULL; ws->state = SWM_WS_STATE_HIDDEN;