X-Git-Url: https://code.delx.au/spectrwm/blobdiff_plain/7a7a5aa57185b7307be2a1f33e3f6c789c86153b..HEAD:/spectrwm.c diff --git a/spectrwm.c b/spectrwm.c index 75df373..285bac9 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -69,6 +69,7 @@ #include #include #include +#include #include #include #include @@ -534,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 */ @@ -823,6 +825,7 @@ enum actionid { FN_FOCUS_NEXT, FN_FOCUS_PREV, FN_FOCUS_URGENT, + FN_FULLSCREEN_TOGGLE, FN_MAXIMIZE_TOGGLE, FN_HEIGHT_GROW, FN_HEIGHT_SHRINK, @@ -845,6 +848,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, @@ -869,6 +874,7 @@ enum actionid { FN_MVWS_22, FN_NAME_WORKSPACE, FN_QUIT, + FN_RAISE, FN_RAISE_TOGGLE, FN_RESIZE, FN_RESIZE_CENTERED, @@ -1057,6 +1063,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); @@ -1132,6 +1139,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); @@ -1154,6 +1162,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); @@ -2410,7 +2419,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; } @@ -3704,7 +3713,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"); @@ -3770,6 +3788,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) @@ -3855,6 +3875,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)) { @@ -4122,6 +4145,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(); } @@ -4166,8 +4193,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; @@ -4187,7 +4212,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) { @@ -5626,6 +5652,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) { @@ -5733,6 +5783,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) { @@ -6115,7 +6190,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."); @@ -6493,6 +6568,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) { @@ -7279,6 +7380,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} }, @@ -7301,6 +7403,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} }, @@ -7325,6 +7429,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} }, @@ -8062,6 +8167,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); @@ -8107,6 +8213,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); @@ -10315,7 +10422,7 @@ get_stack_mode_name(uint8_t mode) { char *name; - switch(mode) { + switch (mode) { case XCB_STACK_MODE_ABOVE: name = "Above"; break; @@ -10990,7 +11097,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); @@ -11416,7 +11523,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; @@ -11491,13 +11597,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; } @@ -11509,7 +11610,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); @@ -11542,6 +11645,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. */ @@ -11715,6 +11828,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;