X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=spectrwm.c;h=75b833f17cc54f01676e40d0b4b75d3e9309722a;hb=36e10e1dfb7db4bd6190be8990df27e08ceecb36;hp=71c7d9c46edd3cc2330828e450c1d007318bfb8a;hpb=2c636ec10aa163bac3b5465fb6fe99746aea4b1f;p=spectrwm.git diff --git a/spectrwm.c b/spectrwm.c index 71c7d9c..75b833f 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -128,6 +128,7 @@ static const char *buildstr = SPECTRWM_VERSION; #define XCB_ICCCM_SIZE_HINT_P_MIN_SIZE XCB_SIZE_HINT_P_MIN_SIZE #define XCB_ICCCM_SIZE_HINT_P_MAX_SIZE XCB_SIZE_HINT_P_MAX_SIZE #define XCB_ICCCM_SIZE_HINT_P_RESIZE_INC XCB_SIZE_HINT_P_RESIZE_INC +#define XCB_ICCCM_WM_HINT_INPUT XCB_WM_HINT_INPUT #define XCB_ICCCM_WM_HINT_X_URGENCY XCB_WM_HINT_X_URGENCY #define XCB_ICCCM_WM_STATE_ICONIC XCB_WM_STATE_ICONIC #define XCB_ICCCM_WM_STATE_WITHDRAWN XCB_WM_STATE_WITHDRAWN @@ -268,8 +269,8 @@ xcb_atom_t a_swm_iconic; xcb_atom_t a_swm_ws; volatile sig_atomic_t running = 1; volatile sig_atomic_t restart_wm = 0; +xcb_timestamp_t last_event_time = 0; int outputs = 0; -/*int last_focus_event = FocusOut;*/ int other_wm; int ss_enabled = 0; int xrandr_support; @@ -279,7 +280,6 @@ unsigned int numlockmask = 0; Display *display; xcb_connection_t *conn; xcb_key_symbols_t *syms; -xcb_timestamp_t last_event_time; int cycle_empty = 0; int cycle_visible = 0; @@ -490,6 +490,7 @@ struct workspace { struct layout *cur_layout; /* current layout handlers */ struct ws_win *focus; /* may be NULL */ struct ws_win *focus_prev; /* may be NULL */ + struct ws_win *focus_pending; /* 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 */ @@ -830,7 +831,7 @@ get_atom_from_string(const char *str) } void -update_iconic(struct ws_win *win, int newv) +set_swm_iconic(struct ws_win *win, int newv) { int32_t v = newv; @@ -849,7 +850,6 @@ get_swm_iconic(struct ws_win *win) int32_t v = 0; xcb_get_property_reply_t *pr = NULL; - pr = xcb_get_property_reply(conn, xcb_get_property(conn, 0, win->id, a_swm_iconic, XCB_ATOM_INTEGER, 0, 1), NULL); @@ -1643,7 +1643,7 @@ bar_fmt(const char *fmtexp, char *fmtnew, struct swm_region *r, size_t sz) if (title_class_enabled) { strlcat(fmtnew, "+C", sz); - if (title_name_enabled == 0) + if (!title_name_enabled) strlcat(fmtnew, "+4<", sz); } @@ -1849,7 +1849,7 @@ bar_update(void) size_t len; char *b; - if (bar_enabled == 0) + if (!bar_enabled) return; if (bar_extra && bar_extra_running) { /* ignore short reads; it'll correct itself */ @@ -1921,7 +1921,7 @@ bar_refresh(void) int i, num_screens; /* do this here because the conf file is in memory */ - if (bar_extra && bar_extra_running == 0 && bar_argv[0]) { + if (bar_extra && !bar_extra_running && bar_argv[0]) { /* launch external status app */ bar_extra_running = 1; if (pipe(bar_pipe) == -1) @@ -2146,7 +2146,8 @@ set_win_state(struct ws_win *win, uint16_t state) { uint16_t data[2] = { state, XCB_ATOM_NONE }; - DNPRINTF(SWM_D_EVENT, "set_win_state: window: 0x%x\n", win->id); + DNPRINTF(SWM_D_EVENT, "set_win_state: window: 0x%x, state: %u\n", + win->id, state); if (win == NULL) return; @@ -2312,9 +2313,9 @@ count_win(struct workspace *ws, int count_transient) int count = 0; TAILQ_FOREACH(win, &ws->winlist, entry) { - if (count_transient == 0 && win->floating) + if (!count_transient && win->floating) continue; - if (count_transient == 0 && win->transient) + if (!count_transient && win->transient) continue; if (win->iconic) continue; @@ -2445,9 +2446,11 @@ restart(struct swm_region *r, union arg *args) struct swm_region * root_to_region(xcb_window_t root) { + struct ws_win *cfw; struct swm_region *r = NULL; int i, num_screens; xcb_query_pointer_reply_t *qpr; + xcb_get_input_focus_reply_t *gifr; DNPRINTF(SWM_D_MISC, "root_to_region: window: 0x%x\n", root); @@ -2456,20 +2459,33 @@ root_to_region(xcb_window_t root) if (screens[i].root == root) break; - qpr = xcb_query_pointer_reply(conn, xcb_query_pointer(conn, - screens[i].root), NULL); + /* Try to find an actively focused window */ + gifr = xcb_get_input_focus_reply(conn, xcb_get_input_focus(conn), NULL); + if (gifr) { + cfw = find_window(gifr->focus); + if (cfw && cfw->ws->r) + r = cfw->ws->r; - if (qpr) { - DNPRINTF(SWM_D_MISC, "root_to_region: pointer: (%d,%d)\n", - qpr->root_x, qpr->root_y); - /* choose a region based on pointer location */ - TAILQ_FOREACH(r, &screens[i].rl, entry) - if (X(r) <= qpr->root_x && qpr->root_x < MAX_X(r) && - Y(r) <= qpr->root_y && qpr->root_y < MAX_Y(r)) - break; - free(qpr); + free(gifr); + } + + if (r == NULL) { + /* No region with an active focus; try to use pointer. */ + qpr = xcb_query_pointer_reply(conn, xcb_query_pointer(conn, + screens[i].root), NULL); + + if (qpr) { + DNPRINTF(SWM_D_MISC, "root_to_region: pointer: (%d,%d)\n", + qpr->root_x, qpr->root_y); + TAILQ_FOREACH(r, &screens[i].rl, entry) + if (X(r) <= qpr->root_x && qpr->root_x < MAX_X(r) && + Y(r) <= qpr->root_y && qpr->root_y < MAX_Y(r)) + break; + free(qpr); + } } + /* Last resort. */ if (r == NULL) r = TAILQ_FIRST(&screens[i].rl); @@ -2778,6 +2794,7 @@ struct ws_win * get_focus_magic(struct ws_win *win) { struct ws_win *parent = NULL; + struct ws_win *child = NULL; DNPRINTF(SWM_D_FOCUS, "get_focus_magic: window: 0x%x\n", WINID(win)); if (win == NULL) @@ -2786,19 +2803,19 @@ get_focus_magic(struct ws_win *win) if (win->transient) { parent = find_window(win->transient); - /* If parent prefers focus elsewhere, then do so. */ - if (parent && parent->focus_child) { - if (validate_win(parent->focus_child) == 0) - win = parent->focus_child; + /* If parent prefers focus elsewhere, then try to do so. */ + if (parent && (child = parent->focus_child)) { + if (validate_win(child) == 0 && child->mapped) + win = child; else parent->focus_child = NULL; } } - /* If this window prefers focus elsewhere, then do so. */ - if (win->focus_child) { - if (validate_win(win->focus_child) == 0) - win = win->focus_child; + /* If this window prefers focus elsewhere, then try to do so. */ + if ((child = win->focus_child)) { + if (validate_win(child) == 0 && child->mapped) + win = child; else win->focus_child = NULL; } @@ -2847,6 +2864,8 @@ switchws(struct swm_region *r, union arg *args) if (new_ws == old_ws) return; + unfocus_win(old_ws->focus); + other_r = new_ws->r; if (other_r == NULL) { /* the other workspace is hidden, hide this one */ @@ -2862,8 +2881,6 @@ switchws(struct swm_region *r, union arg *args) this_r->ws = new_ws; new_ws->r = this_r; - unmap_window(old_ws->focus); - stack(); /* unmap old windows */ @@ -2871,20 +2888,17 @@ switchws(struct swm_region *r, union arg *args) TAILQ_FOREACH(win, &old_ws->winlist, entry) unmap_window(win); - new_ws->focus = get_region_focus(new_ws->r); - - /* unmap old windows */ - if (unmap_old) - TAILQ_FOREACH(win, &old_ws->winlist, entry) - unmap_window(win); + if (focus_mode != SWM_FOCUS_FOLLOW) + new_ws->focus_pending = get_region_focus(new_ws->r); - /* make sure bar gets updated if ws is empty */ - if (!new_ws->focus) - bar_update(); - - /* make sure bar gets updated if ws is empty */ - if (!new_ws->focus) + if (new_ws->focus_pending && focus_mode != SWM_FOCUS_FOLLOW) { + /* if workspaces were swapped, then don't wait to set focus */ + if (old_ws->r) + focus_win(new_ws->focus_pending); + } else { + /* make sure bar gets updated if ws is empty */ bar_update(); + } focus_flush(); @@ -2927,9 +2941,9 @@ cyclews(struct swm_region *r, union arg *args) }; if (!cycle_all && - (cycle_empty == 0 && TAILQ_EMPTY(&s->ws[a.id].winlist))) + (!cycle_empty && TAILQ_EMPTY(&s->ws[a.id].winlist))) continue; - if (cycle_visible == 0 && s->ws[a.id].r != NULL) + if (!cycle_visible && s->ws[a.id].r != NULL) continue; switchws(r, &a); @@ -2957,7 +2971,7 @@ void cyclescr(struct swm_region *r, union arg *args) { struct swm_region *rr = NULL; - int i, x, y, num_screens; + int i, num_screens; num_screens = xcb_setup_roots_length(xcb_get_setup(conn)); /* do nothing if we don't have more than one screen */ @@ -2982,21 +2996,7 @@ cyclescr(struct swm_region *r, union arg *args) if (rr == NULL) return; - /* move mouse to region */ - x = X(rr) + 1; - y = Y(rr) + 1 + (bar_enabled ? bar_height : 0); - xcb_warp_pointer(conn, XCB_WINDOW_NONE, rr->s[i].root, 0, 0, 0, 0, - x, y); - - rr->ws->focus = get_region_focus(rr); - - if (rr->ws->focus) { - /* move to focus window */ - x = X(rr->ws->focus) + 1; - y = Y(rr->ws->focus) + 1; - xcb_warp_pointer(conn, XCB_WINDOW_NONE, rr->s[i].root, 0, 0, 0, - 0, x, y); - } + focus_win(get_region_focus(rr)); focus_flush(); } @@ -3031,7 +3031,6 @@ swapwin(struct swm_region *r, union arg *args) struct ws_win *cur_focus; struct ws_win_list *wl; - DNPRINTF(SWM_D_WS, "swapwin: id: %d, screen[%d]:%dx%d+%d+%d, ws: %d\n", args->id, r->s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r), r->ws->idx); @@ -3228,7 +3227,7 @@ focus(struct swm_region *r, union arg *args) /* make sure there is at least one uniconified window */ all_iconics = 1; TAILQ_FOREACH(winfocus, wl, entry) - if (winfocus->iconic == 0) { + if (!winfocus->iconic) { all_iconics = 0; break; } @@ -3253,7 +3252,7 @@ focus(struct swm_region *r, union arg *args) while (winfocus != cur_focus) { if (winfocus == NULL) winfocus = TAILQ_LAST(wl, ws_win_list); - if (winfocus->iconic == 0) + if (!winfocus->iconic) break; winfocus = TAILQ_PREV(winfocus, ws_win_list, entry); @@ -3272,7 +3271,7 @@ focus(struct swm_region *r, union arg *args) while (winfocus != cur_focus) { if (winfocus == NULL) winfocus = TAILQ_FIRST(wl); - if (winfocus->iconic == 0) + if (!winfocus->iconic) break; winfocus = TAILQ_NEXT(winfocus, entry); } @@ -3525,7 +3524,7 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) int w_inc = 1, h_inc, w_base = 1, h_base; int hrh, extra = 0, h_slice, last_h = 0; int split, colno, winno, mwin, msize, mscale; - int remain, missing, v_slice, reconfigure; + int remain, missing, v_slice, reconfigure = 0; int bordered = 1; DNPRINTF(SWM_D_STACK, "stack_master: workspace: %d, rot: %s, " @@ -3536,8 +3535,7 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) return; TAILQ_FOREACH(win, &ws->winlist, entry) - if (win->transient == 0 && win->floating == 0 - && win->iconic == 0) + if (!win->transient && !win->floating && !win->iconic) break; if (win == NULL) @@ -3594,9 +3592,9 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) /* stack all the tiled windows */ i = j = 0, s = stacks; TAILQ_FOREACH(win, &ws->winlist, entry) { - if (win->transient != 0 || win->floating != 0) + if (win->transient || win->floating) continue; - if (win->iconic != 0) + if (win->iconic) continue; if (win->ewmh_flags & EWMH_F_FULLSCREEN) { @@ -3652,7 +3650,7 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) else win_g.y += last_h + 2 * border_width; - if (disable_border && bar_enabled == 0 && winno == 1){ + if (disable_border && !bar_enabled && winno == 1){ bordered = 0; win_g.w += 2 * border_width; win_g.h += 2 * border_width; @@ -3699,9 +3697,9 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) notiles: /* now, stack all the floaters and transients */ TAILQ_FOREACH(win, &ws->winlist, entry) { - if (win->transient == 0 && win->floating == 0) + if (!win->transient && !win->floating) continue; - if (win->iconic == 1) + if (win->iconic) continue; if (win->ewmh_flags & EWMH_F_FULLSCREEN) { fs_win = win; @@ -3844,7 +3842,7 @@ max_stack(struct workspace *ws, struct swm_geometry *g) continue; } - if (win->floating && win->floatmaxed == 0 ) { + if (win->floating && !win->floatmaxed ) { /* * retain geometry for retrieval on exit from * max_stack mode @@ -3887,9 +3885,8 @@ send_to_ws(struct swm_region *r, union arg *args) { int wsid = args->id; struct ws_win *win = NULL, *parent; - struct workspace *ws, *nws; + struct workspace *ws, *nws, *pws; char ws_idx_str[SWM_PROPLEN]; - union arg a; if (wsid >= workspace_limit) return; @@ -3898,47 +3895,91 @@ send_to_ws(struct swm_region *r, union arg *args) win = r->ws->focus; else return; - if (win == NULL) - return; + if (win->ws->idx == wsid) return; - DNPRINTF(SWM_D_MOVE, "send_to_ws: window: 0x%x\n", win->id); + DNPRINTF(SWM_D_MOVE, "send_to_ws: win 0x%x, ws %d -> %d\n", win->id, + win->ws->idx, wsid); ws = win->ws; nws = &win->s->ws[wsid]; - a.id = SWM_ARG_ID_FOCUSPREV; - focus(r, &a); - if (win->transient) { - parent = find_window(win->transient); - if (parent) { - unmap_window(parent); - TAILQ_REMOVE(&ws->winlist, parent, entry); - TAILQ_INSERT_TAIL(&nws->winlist, parent, entry); - parent->ws = nws; + /* Update the window's workspace property: _SWM_WS */ + if (snprintf(ws_idx_str, SWM_PROPLEN, "%d", nws->idx) < SWM_PROPLEN) { + if (focus_mode != SWM_FOCUS_FOLLOW) + ws->focus_pending = get_focus_prev(win); + + /* Move the parent if this is a transient window. */ + if (win->transient) { + parent = find_window(win->transient); + if (parent) { + pws = parent->ws; + /* Set new focus in parent's ws if needed. */ + if (pws->focus == parent) { + if (focus_mode != SWM_FOCUS_FOLLOW) + pws->focus_pending = + get_focus_prev(parent); + + unfocus_win(parent); + + if (focus_mode != SWM_FOCUS_FOLLOW) + pws->focus = pws->focus_pending; + + if (focus_mode != SWM_FOCUS_FOLLOW) + pws->focus_pending = NULL; + } + + /* Don't unmap parent if new ws is visible */ + if (nws->r == NULL) + unmap_window(parent); + + /* Transfer */ + TAILQ_REMOVE(&ws->winlist, parent, entry); + TAILQ_INSERT_TAIL(&nws->winlist, parent, entry); + parent->ws = nws; + + DNPRINTF(SWM_D_PROP, "send_to_ws: set " + "property: _SWM_WS: %s\n", ws_idx_str); + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, + parent->id, a_swm_ws, XCB_ATOM_STRING, 8, + strlen(ws_idx_str), ws_idx_str); + } } - } - unmap_window(win); - TAILQ_REMOVE(&ws->winlist, win, entry); - TAILQ_INSERT_TAIL(&nws->winlist, win, entry); - if (TAILQ_EMPTY(&ws->winlist)) - r->ws->focus = NULL; - win->ws = nws; - /* Try to update the window's workspace property */ - if (snprintf(ws_idx_str, SWM_PROPLEN, "%d", nws->idx) < SWM_PROPLEN) { + unfocus_win(win); + + /* Don't unmap if new ws is visible */ + if (nws->r == NULL) + unmap_window(win); + + /* Transfer */ + TAILQ_REMOVE(&ws->winlist, win, entry); + TAILQ_INSERT_TAIL(&nws->winlist, win, entry); + win->ws = nws; + + /* Set focus on new ws. */ + unfocus_win(nws->focus); + nws->focus = win; + DNPRINTF(SWM_D_PROP, "send_to_ws: set property: _SWM_WS: %s\n", ws_idx_str); xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->id, a_swm_ws, XCB_ATOM_STRING, 8, strlen(ws_idx_str), ws_idx_str); - } - stack(); - bar_update(); + /* Restack and set new focus. */ + stack(); - focus_flush(); + if (focus_mode != SWM_FOCUS_FOLLOW) { + focus_win(ws->focus_pending); + ws->focus_pending = NULL; + } + + focus_flush(); + } + + DNPRINTF(SWM_D_MOVE, "send_to_ws: done.\n"); } void @@ -3965,7 +4006,7 @@ raise_toggle(struct swm_region *r, union arg *args) r->ws->always_raise = !r->ws->always_raise; /* bring floaters back to top */ - if (r->ws->always_raise == 0) + if (!r->ws->always_raise) stack(); focus_flush(); @@ -3980,7 +4021,7 @@ iconify(struct swm_region *r, union arg *args) if (r->ws->focus == NULL) return; - update_iconic(r->ws->focus, 1); + set_swm_iconic(r->ws->focus, 1); xcb_flush(conn); } @@ -4035,7 +4076,7 @@ uniconify(struct swm_region *r, union arg *args) TAILQ_FOREACH(win, &r->ws->winlist, entry) { if (win->ws == NULL) continue; /* should never happen */ - if (win->iconic == 0) + if (!win->iconic) continue; count++; } @@ -4053,7 +4094,7 @@ uniconify(struct swm_region *r, union arg *args) TAILQ_FOREACH(win, &r->ws->winlist, entry) { if (win->ws == NULL) continue; /* should never happen */ - if (win->iconic == 0) + if (!win->iconic) continue; name = get_win_name(win->id); @@ -4162,7 +4203,7 @@ search_win(struct swm_region *r, union arg *args) i = 1; TAILQ_FOREACH(win, &r->ws->winlist, entry) { - if (win->iconic == 1) + if (win->iconic) continue; sw = calloc(1, sizeof(struct search_window)); @@ -4249,7 +4290,7 @@ search_resp_uniconify(char *resp, unsigned long len) DNPRINTF(SWM_D_MISC, "search_resp_uniconify: resp: %s\n", resp); TAILQ_FOREACH(win, &search_r->ws->winlist, entry) { - if (win->iconic == 0) + if (!win->iconic) continue; name = get_win_name(win->id); if (name == NULL) @@ -4261,7 +4302,7 @@ search_resp_uniconify(char *resp, unsigned long len) free(name); if (strncmp(s, resp, len) == 0) { /* XXX this should be a callback to generalize */ - update_iconic(win, 0); + set_swm_iconic(win, 0); xcb_flush(conn); free(s); break; @@ -4436,7 +4477,6 @@ wkill(struct swm_region *r, union arg *args) xcb_flush(conn); } - int floating_toggle_win(struct ws_win *win) { @@ -4585,7 +4625,7 @@ resize(struct ws_win *win, union arg *args) "transient: 0x%x\n", win->id, YESNO(win->floating), win->transient); - if (!(win->transient != 0 || win->floating != 0)) + if (!win->transient && !win->floating) return; /* reject resizes in max mode for floaters (transient ok) */ @@ -4783,7 +4823,7 @@ move(struct ws_win *win, union arg *args) return; win->manual = 1; - if (win->floating == 0 && !win->transient) { + if (!win->floating && !win->transient) { store_float_geom(win, r); ewmh_update_win_state(win, ewmh[_NET_WM_STATE_ABOVE].atom, _NET_WM_STATE_ADD); @@ -4894,13 +4934,12 @@ move_step(struct swm_region *r, union arg *args) else return; - if (!(win->transient != 0 || win->floating != 0)) + if (!win->transient && !win->floating) return; move(win, args); } - /* user/key callable function IDs */ enum keyfuncid { KF_BAR_TOGGLE, @@ -6194,7 +6233,8 @@ setconfvalue(char *selector, char *value, int flags) case SWM_S_FOCUS_MODE: if (!strcmp(value, "default")) focus_mode = SWM_FOCUS_DEFAULT; - else if (!strcmp(value, "follow_cursor")) + else if (!strcmp(value, "follow") || + !strcmp(value, "follow_cursor")) focus_mode = SWM_FOCUS_FOLLOW; else if (!strcmp(value, "manual")) focus_mode = SWM_FOCUS_MANUAL; @@ -6509,7 +6549,6 @@ struct config_option configopt[] = { { "layout", setlayout, 0 }, }; - int conf_load(char *filename, int keymapping) { @@ -6517,7 +6556,7 @@ conf_load(char *filename, int keymapping) char *line, *cp, *optsub, *optval; size_t linelen, lineno = 0; int wordlen, i, optidx; - struct config_option *opt; + struct config_option *opt = NULL; DNPRINTF(SWM_D_CONF, "conf_load: begin\n"); @@ -6566,7 +6605,7 @@ conf_load(char *filename, int keymapping) filename, lineno, wordlen, cp); goto out; } - if (keymapping && strcmp(opt->optname, "bind")) { + if (keymapping && opt && strcmp(opt->optname, "bind")) { warnx("%s: line %zd: invalid option %.*s", filename, lineno, wordlen, cp); goto out; @@ -6754,12 +6793,12 @@ manage_window(xcb_window_t id, uint16_t mapped) { xcb_window_t trans = XCB_WINDOW_NONE; struct ws_win *win, *ww; - int ws_idx, border_me = 0; + int ws_idx; char ws_idx_str[SWM_PROPLEN]; struct swm_region *r; struct pid_e *p; struct quirk *qp; - uint32_t event_mask, i; + uint32_t i, wa[2]; xcb_icccm_get_wm_protocols_reply_t wpr; if ((win = find_window(id)) != NULL) { @@ -6800,9 +6839,9 @@ manage_window(xcb_window_t id, uint16_t mapped) /* Ignore window border if there is one. */ WIDTH(win) = win->wa->width; HEIGHT(win) = win->wa->height; - X(win) = win->wa->x + win->wa->border_width; - Y(win) = win->wa->y + win->wa->border_width; - win->bordered = 0; + X(win) = win->wa->x + win->wa->border_width - border_width; + Y(win) = win->wa->y + win->wa->border_width - border_width; + win->bordered = 1; win->mapped = mapped; win->floatmaxed = 0; win->ewmh_flags = 0; @@ -6851,13 +6890,12 @@ manage_window(xcb_window_t id, uint16_t mapped) free(p); p = NULL; } else if ((ws_idx = get_ws_idx(win->id)) != -1 && - win->transient == 0) { + !win->transient) { /* _SWM_WS is set; use that. */ win->ws = &r->s->ws[ws_idx]; } else if (trans && (ww = find_window(trans)) != NULL) { /* Launch transients in the same ws as parent. */ win->ws = ww->ws; - border_me = 1; } else { win->ws = r->ws; } @@ -6887,7 +6925,6 @@ manage_window(xcb_window_t id, uint16_t mapped) DNPRINTF(SWM_D_CLASS, "manage_window: java window " "detected.\n"); win->java = 1; - border_me = 1; } TAILQ_FOREACH(qp, &quirks, entry) { @@ -6895,20 +6932,16 @@ manage_window(xcb_window_t id, uint16_t mapped) !strcmp(win->ch.instance_name, qp->name)) { DNPRINTF(SWM_D_CLASS, "manage_window: on quirks" "list; mask: 0x%lx\n", qp->quirk); - if (qp->quirk & SWM_Q_FLOAT) { + if (qp->quirk & SWM_Q_FLOAT) win->floating = 1; - border_me = 1; - } win->quirks = qp->quirk; } } } /* Alter window position if quirky */ - if (win->quirks & SWM_Q_ANYWHERE) { + if (win->quirks & SWM_Q_ANYWHERE) win->manual = 1; - border_me = 1; - } /* Reset font sizes (the bruteforce way; no default keybinding). */ if (win->quirks & SWM_Q_XTERM_FONTADJ) { @@ -6918,28 +6951,22 @@ manage_window(xcb_window_t id, uint16_t mapped) fake_keypress(win, XK_KP_Add, XCB_MOD_MASK_SHIFT); } - if (border_me) { - win->bordered = 1; - X(win) -= border_width; - Y(win) -= border_width; - } - /* Make sure window is positioned inside its region, if its active. */ - if (win->ws->r) + if (win->ws->r) { constrain_window(win, win->ws->r, 0); - - if (win->ws->r || border_me) update_window(win); + } - /* Select which X events to monitor. */ - event_mask = XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_FOCUS_CHANGE | - XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_STRUCTURE_NOTIFY; + /* Select which X events to monitor and set border pixel color. */ + wa[0] = win->s->c[SWM_S_COLOR_UNFOCUS].pixel; + wa[1] = XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_PROPERTY_CHANGE | + XCB_EVENT_MASK_STRUCTURE_NOTIFY; #ifdef SWM_DEBUG - event_mask |= XCB_EVENT_MASK_LEAVE_WINDOW; + wa[1] |= XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_FOCUS_CHANGE; #endif - xcb_change_window_attributes(conn, win->id, XCB_CW_EVENT_MASK, - &event_mask); + xcb_change_window_attributes(conn, win->id, XCB_CW_BORDER_PIXEL | + XCB_CW_EVENT_MASK, wa); out: /* Figure out where to stack the window in the workspace. */ @@ -7016,8 +7043,6 @@ unmanage_window(struct ws_win *win) parent->focus_child = NULL; } - focus_win(get_focus_prev(win)); - TAILQ_REMOVE(&win->ws->winlist, win, entry); TAILQ_INSERT_TAIL(&win->ws->unmanagedlist, win, entry); } @@ -7291,8 +7316,11 @@ configurenotify(xcb_configure_notify_event_t *e) { struct ws_win *win; - DNPRINTF(SWM_D_EVENT, "configurenotify: window: 0x%x\n", - e->window); + DNPRINTF(SWM_D_EVENT, "configurenotify: win 0x%x, event win: 0x%x, " + "(x,y) WxH: (%d,%d) %ux%u, border: %u, above_sibling: 0x%x, " + "override_redirect: %s\n", e->window, e->event, e->x, e->y, + e->width, e->height, e->border_width, e->above_sibling, + YESNO(e->override_redirect)); win = find_window(e->window); if (win) { @@ -7321,14 +7349,24 @@ destroynotify(xcb_destroy_notify_event_t *e) return; } - /* make sure we focus on something */ - win->floating = 0; + if (focus_mode != SWM_FOCUS_FOLLOW) { + /* If we were focused, make sure we focus on something else. */ + if (win == win->ws->focus) + win->ws->focus_pending = get_focus_prev(win); + } unmanage_window(win); - free_window(win); - stack(); + if (focus_mode != SWM_FOCUS_FOLLOW) { + if (win->ws->focus_pending) { + focus_win(win->ws->focus_pending); + win->ws->focus_pending = NULL; + } + } + + free_window(win); + focus_flush(); } @@ -7459,9 +7497,12 @@ mapnotify(xcb_map_notify_event_t *e) win->mapped = 1; set_win_state(win, XCB_ICCCM_WM_STATE_NORMAL); - /* Focus on window if it is selected. */ - if (win->ws->focus == win) - focus_win(win); + if (focus_mode != SWM_FOCUS_FOLLOW) { + if (win->ws->focus_pending == win) { + focus_win(win); + win->ws->focus_pending = NULL; + } + } xcb_flush(conn); } @@ -7506,7 +7547,8 @@ maprequest(xcb_map_request_event_t *e) stack(); /* The new window should get focus. */ - win->ws->focus = get_focus_magic(win); + if (focus_mode != SWM_FOCUS_FOLLOW) + win->ws->focus_pending = get_focus_magic(win); /* Ignore EnterNotify to handle the mapnotify without interference. */ if (focus_mode == SWM_FOCUS_DEFAULT) @@ -7554,7 +7596,6 @@ void propertynotify(xcb_property_notify_event_t *e) { struct ws_win *win; - union arg a; #ifdef SWM_DEBUG char *name; @@ -7570,41 +7611,45 @@ propertynotify(xcb_property_notify_event_t *e) last_event_time = e->time; if (e->atom == a_swm_iconic) { - if (e->state == XCB_PROPERTY_DELETE) { - /* The window is no longer iconic, restack ws. */ - stack(); - - /* The window should get focus. */ - win->ws->focus = get_focus_magic(win); - - /* Flush EnterNotify for mapnotify, if needed. */ - focus_flush(); - return; - } else if (e->state == XCB_PROPERTY_NEW_VALUE) { - win->ws->focus = NULL; + if (e->state == XCB_PROPERTY_NEW_VALUE) { + if (focus_mode != SWM_FOCUS_FOLLOW) + win->ws->focus_pending = get_focus_prev(win); unfocus_win(win); unmap_window(win); if (win->ws->r) { - focus_win(get_focus_prev(win)); stack(); + if (focus_mode != SWM_FOCUS_FOLLOW) { + focus_win(win->ws->focus_pending); + win->ws->focus_pending = NULL; + } focus_flush(); } - } - } else if (e->atom == a_state && e->state == XCB_PROPERTY_NEW_VALUE) { - /* Focus on window if it is selected. */ - if (win->ws->focus == win) - focus_win(win); - } + } else if (e->state == XCB_PROPERTY_DELETE) { + /* The window is no longer iconic, restack ws. */ + if (focus_mode != SWM_FOCUS_FOLLOW) + win->ws->focus_pending = get_focus_magic(win); + + stack(); - switch (e->atom) { - case XCB_ATOM_WM_CLASS: - case XCB_ATOM_WM_NAME: + /* Flush EnterNotify for mapnotify, if needed. */ + focus_flush(); + } + } 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 (win->mapped && + win->ws->focus_pending == win) { + focus_win(win->ws->focus_pending); + win->ws->focus_pending = NULL; + } + } + } + } else if (e->atom == XCB_ATOM_WM_CLASS || + e->atom == XCB_ATOM_WM_NAME) { bar_update(); - break; - default: - break; } xcb_flush(conn); @@ -7614,6 +7659,7 @@ void unmapnotify(xcb_unmap_notify_event_t *e) { struct ws_win *win; + struct workspace *ws; DNPRINTF(SWM_D_EVENT, "unmapnotify: window: 0x%x\n", e->window); @@ -7622,9 +7668,31 @@ unmapnotify(xcb_unmap_notify_event_t *e) if (win == NULL) return; + ws = win->ws; + if (getstate(e->window) == XCB_ICCCM_WM_STATE_NORMAL) { + win->mapped = 0; + set_win_state(win, XCB_ICCCM_WM_STATE_ICONIC); + + /* If we were focused, make sure we focus on something else. */ + if (win == ws->focus) + if (focus_mode != SWM_FOCUS_FOLLOW) + ws->focus_pending = get_focus_prev(win); + + unfocus_win(win); unmanage_window(win); stack(); + + DNPRINTF(SWM_D_EVENT, "unmapnotify: focus_pending: 0x%x\n", + ws->focus_pending->id); + + if (focus_mode != SWM_FOCUS_FOLLOW) { + if (ws->focus_pending) { + focus_win(ws->focus_pending); + ws->focus_pending = NULL; + } + } + focus_flush(); } } @@ -8101,6 +8169,8 @@ setup_screens(void) ws->idx = j; ws->name = NULL; ws->focus = NULL; + ws->focus_prev = NULL; + ws->focus_pending = NULL; ws->r = NULL; ws->old_r = NULL; TAILQ_INIT(&ws->winlist); @@ -8420,7 +8490,7 @@ noconfig: while (running) { while ((evt = xcb_poll_for_event(conn))) { - if (running == 0) + if (!running) goto done; event_handle(evt); free(evt); @@ -8454,11 +8524,11 @@ noconfig: if (errno != EINTR) { DNPRINTF(SWM_D_MISC, "select failed"); } - if (restart_wm == 1) + if (restart_wm) restart(NULL, NULL); - if (search_resp == 1) + if (search_resp) search_do_resp(); - if (running == 0) + if (!running) goto done; if (bar_alarm) { bar_alarm = 0;