X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=spectrwm.c;h=629f69969ed9d1d6a76bc70499e3eee723d36599;hb=7e463aa1bd6f8a52e1c55d6ae6c3c439a702ea64;hp=38883f6ad4be528822be8342072f10c0b888a04d;hpb=a8461cfbb9c22d8b09cf9ed39871a8e95f1c19f5;p=spectrwm.git diff --git a/spectrwm.c b/spectrwm.c index 38883f6..629f699 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -243,7 +243,8 @@ u_int32_t swm_debug = 0 #define SH_INC_W(w) (w)->sh.width_inc #define SH_INC_H(w) (w)->sh.height_inc #define SWM_MAX_FONT_STEPS (3) -#define WINID(w) ((w) ? (w)->id : 0) +#define WINID(w) ((w) ? (w)->id : XCB_WINDOW_NONE) +#define WS_FOCUSED(ws) ((ws)->r && (ws)->r->s->r_focus == (ws)->r) #define YESNO(x) ((x) ? "yes" : "no") /* Constrain Window flags */ @@ -279,10 +280,7 @@ xcb_atom_t a_state; xcb_atom_t a_prot; xcb_atom_t a_delete; xcb_atom_t a_takefocus; -xcb_atom_t a_wmname; -xcb_atom_t a_netwmname; xcb_atom_t a_utf8_string; -xcb_atom_t a_string; xcb_atom_t a_swm_iconic; xcb_atom_t a_swm_ws; volatile sig_atomic_t running = 1; @@ -947,6 +945,7 @@ struct ws_win *get_pointer_win(xcb_window_t); struct ws_win *get_region_focus(struct swm_region *); int get_region_index(struct swm_region *); xcb_screen_t *get_screen(int); +xcb_window_t get_sibling(struct ws_win *, int); int get_screen_count(void); #ifdef SWM_DEBUG char *get_stack_mode_name(uint8_t); @@ -1050,6 +1049,7 @@ void spawn(int, union arg *, int); void spawn_custom(struct swm_region *, union arg *, const char *); int spawn_expand(struct swm_region *, union arg *, const char *, char ***); void spawn_insert(const char *, const char *, int); +struct spawn_prog *spawn_find(const char *); void spawn_remove(struct spawn_prog *); void spawn_replace(struct spawn_prog *, const char *, const char *, int); void spawn_select(struct swm_region *, union arg *, const char *, int *); @@ -2829,8 +2829,8 @@ map_window(struct ws_win *win, xcb_window_t sibling) if (win == NULL) return; - DNPRINTF(SWM_D_EVENT, "map_window: win 0x%x, mapped: %s, sibling: %x\n", - win->id, YESNO(win->mapped), sibling); + DNPRINTF(SWM_D_EVENT, "map_window: win 0x%x, mapped: %s, " + "sibling: 0x%x\n", win->id, YESNO(win->mapped), sibling); xcb_configure_window(conn, win->id, mode, val); @@ -3180,6 +3180,42 @@ validate_ws(struct workspace *testws) return (1); } +xcb_window_t +get_sibling(struct ws_win *win, int mode) +{ + struct ws_win *w = win; + + switch (mode) { + case SWM_STACK_TOP: + TAILQ_FOREACH_REVERSE(w, &w->ws->winlist, ws_win_list, entry) + if (w != win && !w->floating && !w->iconic) + break; + break; + case SWM_STACK_ABOVE: + do { + w = TAILQ_NEXT(w, entry); + } while (w != NULL && (w == win || w->floating || w->iconic)); + break; + case SWM_STACK_BELOW: + do { + w = TAILQ_PREV(w, ws_win_list, entry); + } while (w != NULL && (w == win || w->floating || w->iconic)); + break; + case SWM_STACK_BOTTOM: + TAILQ_FOREACH(w, &w->ws->winlist, entry) + if (w != win && !w->floating && !w->iconic) + break; + break; + default: + w = NULL; + } + + if (w == NULL) + return (win->ws->r->id); + else + return (w->id); +} + void unfocus_win(struct ws_win *win) { @@ -3211,6 +3247,8 @@ unfocus_win(struct ws_win *win) } if (win->ws->focus == win) { + if (tile_gap < 0 && !win->floating) + map_window(win, get_sibling(win, SWM_STACK_BELOW)); win->ws->focus = NULL; win->ws->focus_prev = win; } @@ -3328,6 +3366,14 @@ focus_win(struct ws_win *win) TAILQ_FOREACH(w, &ws->winlist, entry) if (w->transient == win->id && !w->iconic) map_window(w, XCB_WINDOW_NONE); + } else if (tile_gap < 0 && !win->floating) { + /* + * Windows overlap in the layout. + * Raise focused win above all tiled wins. + */ + if (tile_gap < 0 && !win->floating) + map_window(win, + get_sibling(win, SWM_STACK_TOP)); } set_region(ws->r); @@ -3449,10 +3495,11 @@ focus_region(struct swm_region *r) void switchws(struct swm_region *r, union arg *args) { - int wsid = args->id, unmap_old = 0; struct swm_region *this_r, *other_r; struct ws_win *win; struct workspace *new_ws, *old_ws; + xcb_window_t none = XCB_WINDOW_NONE; + int wsid = args->id, unmap_old = 0; if (!(r && r->s)) return; @@ -3472,7 +3519,14 @@ switchws(struct swm_region *r, union arg *args) if (new_ws == old_ws) return; - unfocus_win(old_ws->focus); + if ((win = old_ws->focus) != NULL) { + xcb_change_window_attributes(conn, win->id, XCB_CW_BORDER_PIXEL, + &win->ws->r->s->c[SWM_S_COLOR_UNFOCUS].pixel); + + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->s->root, + ewmh[_NET_ACTIVE_WINDOW].atom, XCB_ATOM_WINDOW, 32, 1, + &none); + } other_r = new_ws->r; if (other_r == NULL) { @@ -3491,8 +3545,11 @@ switchws(struct swm_region *r, union arg *args) /* Set focus_pending before stacking, if needed. */ if (focus_mode != SWM_FOCUS_FOLLOW && (!new_ws->focus_pending || - validate_win(new_ws->focus_pending))) + validate_win(new_ws->focus_pending))) { new_ws->focus_pending = get_region_focus(new_ws->r); + new_ws->focus = new_ws->focus_prev; + new_ws->focus_prev = NULL; + } stack(); @@ -4198,8 +4255,7 @@ void stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) { struct swm_geometry win_g, r_g = *g; - struct ws_win *win, *fs_win = NULL, *wtmp; - xcb_window_t sibling; + struct ws_win *win, *fs_win = NULL; int i, j, s, stacks; int w_inc = 1, h_inc, w_base = 1, h_base; int hrh, extra = 0, h_slice, last_h = 0; @@ -4376,19 +4432,17 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) update_window(win); } - wtmp = TAILQ_PREV(win, ws_win_list, entry); - if (wtmp) - sibling = wtmp->id; - else - sibling = ws->r->bar->id; - - map_window(win, sibling); + map_window(win, get_sibling(win, SWM_STACK_BELOW)); last_h = win_g.h; i++; j++; } + /* Map/raise focused tiled window to top if windows could overlap. */ + if (tile_gap < 0 && ws->focus != NULL && !ws->focus->floating) + map_window(ws->focus, get_sibling(ws->focus, SWM_STACK_TOP)); + notiles: /* now, stack all the floaters and transients */ TAILQ_FOREACH(win, &ws->winlist, entry) { @@ -4815,7 +4869,7 @@ get_win_name(xcb_window_t win) xcb_get_property_reply_t *r; /* First try _NET_WM_NAME for UTF-8. */ - c = xcb_get_property(conn, 0, win, a_netwmname, + c = xcb_get_property(conn, 0, win, ewmh[_NET_WM_NAME].atom, XCB_GET_PROPERTY_TYPE_ANY, 0, UINT_MAX); r = xcb_get_property_reply(conn, c, NULL); @@ -5264,16 +5318,12 @@ wkill(struct swm_region *r, union arg *args) int floating_toggle_win(struct ws_win *win) { - struct swm_region *r; - if (win == NULL) return (0); if (!win->ws->r) return (0); - r = win->ws->r; - /* reject floating toggles in max stack mode */ if (win->ws->cur_layout == &layouts[SWM_MAX_STACK]) return (0); @@ -5663,14 +5713,12 @@ move(struct ws_win *win, union arg *args) { xcb_timestamp_t timestamp = 0; int move_stp = 0, moving; - struct swm_region *r = NULL; xcb_query_pointer_reply_t *qpr = NULL; xcb_generic_event_t *evt; xcb_motion_notify_event_t *mne; if (win == NULL) return; - r = win->ws->r; if (win->ewmh_flags & EWMH_F_FULLSCREEN) return; @@ -5996,7 +6044,7 @@ spawn_expand(struct swm_region *r, union arg *args, const char *spawn_name, char ***ret_args) { struct spawn_prog *prog = NULL; - int i; + int i, c; char *ap, **real_args; /* suppress unused warning since var is needed */ @@ -6019,62 +6067,68 @@ spawn_expand(struct swm_region *r, union arg *args, const char *spawn_name, err(1, "spawn_custom: calloc real_args"); /* expand spawn_args into real_args */ - for (i = 0; i < prog->argc; i++) { + for (i = c = 0; i < prog->argc; i++) { ap = prog->argv[i]; DNPRINTF(SWM_D_SPAWN, "spawn_custom: raw arg: %s\n", ap); if (!strcasecmp(ap, "$bar_border")) { - if ((real_args[i] = + if ((real_args[c] = strdup(r->s->c[SWM_S_COLOR_BAR_BORDER].name)) == NULL) err(1, "spawn_custom border color"); } else if (!strcasecmp(ap, "$bar_color")) { - if ((real_args[i] = + if ((real_args[c] = strdup(r->s->c[SWM_S_COLOR_BAR].name)) == NULL) err(1, "spawn_custom bar color"); } else if (!strcasecmp(ap, "$bar_font")) { - if ((real_args[i] = strdup(bar_fonts)) + if ((real_args[c] = strdup(bar_fonts)) == NULL) err(1, "spawn_custom bar fonts"); } else if (!strcasecmp(ap, "$bar_font_color")) { - if ((real_args[i] = + if ((real_args[c] = strdup(r->s->c[SWM_S_COLOR_BAR_FONT].name)) == NULL) err(1, "spawn_custom color font"); } else if (!strcasecmp(ap, "$color_focus")) { - if ((real_args[i] = + if ((real_args[c] = strdup(r->s->c[SWM_S_COLOR_FOCUS].name)) == NULL) err(1, "spawn_custom color focus"); } else if (!strcasecmp(ap, "$color_unfocus")) { - if ((real_args[i] = + if ((real_args[c] = strdup(r->s->c[SWM_S_COLOR_UNFOCUS].name)) == NULL) err(1, "spawn_custom color unfocus"); } else if (!strcasecmp(ap, "$region_index")) { - if (asprintf(&real_args[i], "%d", + if (asprintf(&real_args[c], "%d", get_region_index(r) + 1) < 1) err(1, "spawn_custom region index"); } else if (!strcasecmp(ap, "$workspace_index")) { - if (asprintf(&real_args[i], "%d", r->ws->idx + 1) < 1) + if (asprintf(&real_args[c], "%d", r->ws->idx + 1) < 1) + err(1, "spawn_custom workspace index"); + } else if (!strcasecmp(ap, "$dmenu_bottom")) { + if (!bar_at_bottom) + continue; + if ((real_args[c] = strdup("-b")) == NULL) err(1, "spawn_custom workspace index"); } else { /* no match --> copy as is */ - if ((real_args[i] = strdup(ap)) == NULL) + if ((real_args[c] = strdup(ap)) == NULL) err(1, "spawn_custom strdup(ap)"); } DNPRINTF(SWM_D_SPAWN, "spawn_custom: cooked arg: %s\n", - real_args[i]); + real_args[c]); + ++c; } #ifdef SWM_DEBUG DNPRINTF(SWM_D_SPAWN, "spawn_custom: result: "); - for (i = 0; i < prog->argc; i++) - DNPRINTF(SWM_D_SPAWN, "\"%s\" ", real_args[i]); - DNPRINTF(SWM_D_SPAWN, "\n"); + for (i = 0; i < c; ++i) + DPRINTF("\"%s\" ", real_args[i]); + DPRINTF("\n"); #endif *ret_args = real_args; - return (prog->argc); + return (c); } void @@ -6191,6 +6245,18 @@ spawn_remove(struct spawn_prog *sp) DNPRINTF(SWM_D_SPAWN, "spawn_remove: leave\n"); } +struct spawn_prog* +spawn_find(const char *name) +{ + struct spawn_prog *sp; + + TAILQ_FOREACH(sp, &spawns, entry) + if (!strcasecmp(sp->name, name)) + return sp; + + return NULL; +} + void setspawn(const char *name, const char *args, int flags) { @@ -6202,11 +6268,8 @@ setspawn(const char *name, const char *args, int flags) return; /* Remove any old spawn under the same name. */ - TAILQ_FOREACH(sp, &spawns, entry) - if (!strcmp(sp->name, name)) { - spawn_remove(sp); - break; - } + if ((sp = spawn_find(name)) != NULL) + spawn_remove(sp); if (*args != '\0') spawn_insert(name, args, flags); @@ -6246,11 +6309,7 @@ validate_spawns(void) continue; /* find program */ - TAILQ_FOREACH(sp, &spawns, entry) { - if (!strcasecmp(kp->spawn_name, sp->name)) - break; - } - + sp = spawn_find(kp->spawn_name); if (sp == NULL || sp->flags & SWM_SPAWN_OPTIONAL) continue; @@ -6278,6 +6337,7 @@ setup_spawn(void) setconfspawn("spawn_term", "xterm", 0); setconfspawn("menu", "dmenu_run" + " $dmenu_bottom" " -fn $bar_font" " -nb $bar_color" " -nf $bar_font_color" @@ -6285,6 +6345,7 @@ setup_spawn(void) " -sf $bar_color", 0); setconfspawn("search", "dmenu" + " $dmenu_bottom" " -i" " -fn $bar_font" " -nb $bar_color" @@ -6293,6 +6354,7 @@ setup_spawn(void) " -sf $bar_color", 0); setconfspawn("name_workspace", "dmenu" + " $dmenu_bottom" " -p Workspace" " -fn $bar_font" " -nb $bar_color" @@ -6487,17 +6549,15 @@ setconfbinding(char *selector, char *value, int flags) } } /* search by custom spawn name */ - TAILQ_FOREACH(sp, &spawns, entry) { - if (strcasecmp(selector, sp->name) == 0) { - DNPRINTF(SWM_D_KEY, "setconfbinding: %s: match " - "spawn\n", selector); - if (parsekeys(value, mod_key, &mod, &ks) == 0) { - setkeybinding(mod, ks, KF_SPAWN_CUSTOM, - sp->name); - return (0); - } else - return (1); - } + if ((sp = spawn_find(selector)) != NULL) { + DNPRINTF(SWM_D_KEY, "setconfbinding: %s: match " + "spawn\n", selector); + if (parsekeys(value, mod_key, &mod, &ks) == 0) { + setkeybinding(mod, ks, KF_SPAWN_CUSTOM, + sp->name); + return (0); + } else + return (1); } DNPRINTF(SWM_D_KEY, "setconfbinding: no match\n"); return (1); @@ -7157,8 +7217,6 @@ setconfvalue(char *selector, char *value, int flags) break; case SWM_S_TILE_GAP: tile_gap = atoi(value); - if (tile_gap < 0) - tile_gap = 0; break; case SWM_S_TITLE_CLASS_ENABLED: title_class_enabled = atoi(value); @@ -8360,11 +8418,11 @@ destroynotify(xcb_destroy_notify_event_t *e) unmanage_window(win); stack(); - if (focus_mode != SWM_FOCUS_FOLLOW) { + if (focus_mode != SWM_FOCUS_FOLLOW && WS_FOCUSED(win->ws)) { if (win->ws->focus_pending) { focus_win(win->ws->focus_pending); win->ws->focus_pending = NULL; - } else if (win == win->ws->focus && win->ws->r) { + } else if (win == win->ws->focus) { xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT, win->ws->r->id, XCB_CURRENT_TIME); } @@ -8513,7 +8571,7 @@ mapnotify(xcb_map_notify_event_t *e) win->mapped = 1; set_win_state(win, XCB_ICCCM_WM_STATE_NORMAL); - if (focus_mode != SWM_FOCUS_FOLLOW) { + if (focus_mode != SWM_FOCUS_FOLLOW && WS_FOCUSED(win->ws)) { if (win->ws->focus_pending == win) { focus_win(win); win->ws->focus_pending = NULL; @@ -8695,7 +8753,8 @@ propertynotify(xcb_property_notify_event_t *e) if (ws->r) { stack(); - if (focus_mode != SWM_FOCUS_FOLLOW) { + if (focus_mode != SWM_FOCUS_FOLLOW && + WS_FOCUSED(ws)) { if (ws->focus_pending) { focus_win(ws->focus_pending); ws->focus_pending = NULL; @@ -8722,7 +8781,7 @@ propertynotify(xcb_property_notify_event_t *e) } else if (e->atom == a_state) { /* State just changed, make sure it gets focused if mapped. */ if (e->state == XCB_PROPERTY_NEW_VALUE) { - if (focus_mode != SWM_FOCUS_FOLLOW) { + if (focus_mode != SWM_FOCUS_FOLLOW && WS_FOCUSED(ws)) { if (win->mapped && ws->focus_pending == win) { focus_win(ws->focus_pending); @@ -8778,15 +8837,16 @@ unmapnotify(xcb_unmap_notify_event_t *e) if (ws->r) stack(); - if (focus_mode == SWM_FOCUS_FOLLOW) { - if (ws->r) + if (WS_FOCUSED(ws)) { + if (focus_mode == SWM_FOCUS_FOLLOW) { focus_win(get_pointer_win(ws->r->s->root)); - } else if (ws->focus_pending) { - focus_win(ws->focus_pending); - ws->focus_pending = NULL; - } else if (ws->focus == NULL && ws->r) { - xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT, - ws->r->id, XCB_CURRENT_TIME); + } else if (ws->focus_pending) { + focus_win(ws->focus_pending); + ws->focus_pending = NULL; + } else if (ws->focus == NULL) { + xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT, + ws->r->id, XCB_CURRENT_TIME); + } } } @@ -8833,7 +8893,10 @@ clientmessage(xcb_client_message_event_t *e) if (e->type == ewmh[_NET_ACTIVE_WINDOW].atom) { DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_ACTIVE_WINDOW\n"); - focus_win(win); + if (WS_FOCUSED(win->ws)) + focus_win(win); + else + win->ws->focus_pending = win; } if (e->type == ewmh[_NET_CLOSE_WINDOW].atom) { DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_CLOSE_WINDOW\n"); @@ -9383,10 +9446,7 @@ setup_globals(void) a_prot = get_atom_from_string("WM_PROTOCOLS"); a_delete = get_atom_from_string("WM_DELETE_WINDOW"); a_takefocus = get_atom_from_string("WM_TAKE_FOCUS"); - a_wmname = get_atom_from_string("WM_NAME"); - a_netwmname = get_atom_from_string("_NET_WM_NAME"); a_utf8_string = get_atom_from_string("UTF8_STRING"); - a_string = get_atom_from_string("STRING"); a_swm_iconic = get_atom_from_string("_SWM_ICONIC"); a_swm_ws = get_atom_from_string("_SWM_WS"); } @@ -9415,7 +9475,8 @@ workaround(void) xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win, netwmcheck, XCB_ATOM_WINDOW, 32, 1, &win); xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win, - a_netwmname, a_utf8_string, 8, strlen("LG3D"), "LG3D"); + ewmh[_NET_WM_NAME].atom, a_utf8_string, 8, strlen("LG3D"), + "LG3D"); } }