X-Git-Url: https://code.delx.au/spectrwm/blobdiff_plain/f82969b59c414218f709b1d95a799fae6fc40f49..df0824f66a64252c87077b0a27df1d9567eb02de:/spectrwm.c diff --git a/spectrwm.c b/spectrwm.c index d67d875..78e9b85 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -69,6 +69,7 @@ #include #include #include +#include #include #include #include @@ -708,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, @@ -752,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}, @@ -824,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, @@ -1032,6 +1036,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); @@ -1061,6 +1066,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); @@ -1506,6 +1512,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) { @@ -1526,8 +1577,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; @@ -3376,18 +3426,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); @@ -3710,7 +3762,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"); @@ -4133,6 +4194,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(); } @@ -6552,6 +6617,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) { @@ -7338,6 +7429,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} }, @@ -8124,6 +8216,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); @@ -9792,11 +9885,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); } @@ -9828,15 +9916,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; @@ -9967,7 +10064,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); @@ -11053,7 +11149,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); @@ -11479,7 +11575,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; @@ -11554,13 +11649,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; } @@ -11572,7 +11662,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); @@ -11605,6 +11697,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. */