X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=spectrwm.c;h=75b833f17cc54f01676e40d0b4b75d3e9309722a;hb=36e10e1dfb7db4bd6190be8990df27e08ceecb36;hp=267d0148c463b4afbc99bd1b60e5072e5b9f5423;hpb=42610fddc37e9af64d0ebf3a274b16c96200b46c;p=spectrwm.git diff --git a/spectrwm.c b/spectrwm.c index 267d014..75b833f 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -269,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; @@ -280,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; @@ -832,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; @@ -851,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); @@ -1645,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); } @@ -1851,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 */ @@ -1923,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) @@ -2148,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; @@ -2314,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; @@ -2447,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); @@ -2458,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); @@ -2780,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) @@ -2788,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; } @@ -2873,12 +2888,13 @@ switchws(struct swm_region *r, union arg *args) TAILQ_FOREACH(win, &old_ws->winlist, entry) unmap_window(win); - new_ws->focus_pending = get_region_focus(new_ws->r); + if (focus_mode != SWM_FOCUS_FOLLOW) + new_ws->focus_pending = get_region_focus(new_ws->r); - if (new_ws->focus_pending) { + 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); + focus_win(new_ws->focus_pending); } else { /* make sure bar gets updated if ws is empty */ bar_update(); @@ -2925,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); @@ -2955,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 */ @@ -2980,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(); } @@ -3029,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); @@ -3226,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; } @@ -3251,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); @@ -3270,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); } @@ -3523,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, " @@ -3534,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) @@ -3592,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) { @@ -3650,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; @@ -3697,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; @@ -3842,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 @@ -3885,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; @@ -3896,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 @@ -3963,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(); @@ -3978,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); } @@ -4033,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++; } @@ -4051,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); @@ -4160,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)); @@ -4247,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) @@ -4259,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; @@ -4434,7 +4477,6 @@ wkill(struct swm_region *r, union arg *args) xcb_flush(conn); } - int floating_toggle_win(struct ws_win *win) { @@ -4583,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) */ @@ -4781,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); @@ -4892,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, @@ -6192,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; @@ -6507,7 +6549,6 @@ struct config_option configopt[] = { { "layout", setlayout, 0 }, }; - int conf_load(char *filename, int keymapping) { @@ -6515,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"); @@ -6564,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; @@ -6849,7 +6890,7 @@ 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) { @@ -6916,7 +6957,6 @@ manage_window(xcb_window_t id, uint16_t mapped) update_window(win); } - /* 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 | @@ -7276,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) { @@ -7306,16 +7349,20 @@ destroynotify(xcb_destroy_notify_event_t *e) return; } - /* If we were focused, make sure we focus on something else. */ - if (win == win->ws->focus) - win->ws->focus_pending = get_focus_prev(win); + 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); stack(); - if (win->ws->focus_pending) { - focus_win(win->ws->focus_pending); - win->ws->focus_pending = NULL; + 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); @@ -7450,9 +7497,11 @@ mapnotify(xcb_map_notify_event_t *e) win->mapped = 1; set_win_state(win, XCB_ICCCM_WM_STATE_NORMAL); - if (win->ws->focus_pending == win) { - focus_win(win); - win->ws->focus_pending = NULL; + if (focus_mode != SWM_FOCUS_FOLLOW) { + if (win->ws->focus_pending == win) { + focus_win(win); + win->ws->focus_pending = NULL; + } } xcb_flush(conn); @@ -7498,7 +7547,8 @@ maprequest(xcb_map_request_event_t *e) stack(); /* The new window should get focus. */ - win->ws->focus_pending = 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) @@ -7561,39 +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. */ - win->ws->focus_pending = get_focus_magic(win); - stack(); + if (e->state == XCB_PROPERTY_NEW_VALUE) { + if (focus_mode != SWM_FOCUS_FOLLOW) + win->ws->focus_pending = get_focus_prev(win); - /* Flush EnterNotify for mapnotify, if needed. */ - focus_flush(); - return; - } else if (e->state == XCB_PROPERTY_NEW_VALUE) { 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->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(); + + /* Flush EnterNotify for mapnotify, if needed. */ + focus_flush(); } - } else if (e->atom == a_state && e->state == XCB_PROPERTY_NEW_VALUE) { + } else if (e->atom == a_state) { /* State just changed, make sure it gets focused if mapped. */ - if (win->mapped && win->ws->focus_pending == win) { - win->ws->focus_pending = NULL; - focus_win(win); + 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; + } + } } - } - - switch (e->atom) { - case XCB_ATOM_WM_CLASS: - case XCB_ATOM_WM_NAME: + } else if (e->atom == XCB_ATOM_WM_CLASS || + e->atom == XCB_ATOM_WM_NAME) { bar_update(); - break; - default: - break; } xcb_flush(conn); @@ -7603,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); @@ -7611,17 +7668,29 @@ 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 == win->ws->focus) - win->ws->focus_pending = get_focus_prev(win); + if (win == ws->focus) + if (focus_mode != SWM_FOCUS_FOLLOW) + ws->focus_pending = get_focus_prev(win); + unfocus_win(win); unmanage_window(win); stack(); - if (win->ws->focus_pending) { - focus_win(win->ws->focus_pending); - win->ws->focus_pending = NULL; + 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(); @@ -8421,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); @@ -8455,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;