X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=spectrwm.c;h=648b0c54dc0e47fb0008a1f6d5da128c770340dc;hb=5d83029a3a9b69ab0f1287aa6c0499b681d891d9;hp=e8ffe1105e4edf8373af6a112c1bc997717118ac;hpb=24f75da3573f28d53bbb67563012beb860435dbe;p=spectrwm.git diff --git a/spectrwm.c b/spectrwm.c index e8ffe11..648b0c5 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -245,8 +245,8 @@ u_int32_t swm_debug = 0 #define YESNO(x) ((x) ? "yes" : "no") #define SWM_FOCUS_DEFAULT (0) -#define SWM_FOCUS_SYNERGY (1) -#define SWM_FOCUS_FOLLOW (2) +#define SWM_FOCUS_FOLLOW (1) +#define SWM_FOCUS_MANUAL (2) #define SWM_CONF_DEFAULT (0) #define SWM_CONF_KEYMAPPING (1) @@ -279,6 +279,7 @@ 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; @@ -411,13 +412,14 @@ struct ws_win { TAILQ_ENTRY(ws_win) entry; xcb_window_t id; xcb_window_t transient; - struct ws_win *child_trans; /* transient child window */ + struct ws_win *focus_child; /* focus on child transient */ struct swm_geometry g; /* current geometry */ struct swm_geometry g_float; /* region coordinates */ int g_floatvalid; /* g_float geometry validity */ int floatmaxed; /* whether maxed by max_stack */ int floating; int manual; + int32_t mapped; int32_t iconic; int bordered; unsigned int ewmh_flags; @@ -544,7 +546,6 @@ union arg { #define SWM_ARG_ID_FOCUSNEXT (0) #define SWM_ARG_ID_FOCUSPREV (1) #define SWM_ARG_ID_FOCUSMAIN (2) -#define SWM_ARG_ID_FOCUSCUR (4) #define SWM_ARG_ID_SWAPNEXT (10) #define SWM_ARG_ID_SWAPPREV (11) #define SWM_ARG_ID_SWAPMAIN (12) @@ -605,6 +606,7 @@ enum { _NET_ACTIVE_WINDOW, _NET_CLOSE_WINDOW, _NET_MOVERESIZE_WINDOW, + _NET_WM_ACTION_ABOVE, _NET_WM_ACTION_CLOSE, _NET_WM_ACTION_FULLSCREEN, _NET_WM_ACTION_MOVE, @@ -638,6 +640,7 @@ struct ewmh_hint { {"_NET_ACTIVE_WINDOW", XCB_ATOM_NONE}, {"_NET_CLOSE_WINDOW", XCB_ATOM_NONE}, {"_NET_MOVERESIZE_WINDOW", XCB_ATOM_NONE}, + {"_NET_WM_ACTION_ABOVE", XCB_ATOM_NONE}, {"_NET_WM_ACTION_CLOSE", XCB_ATOM_NONE}, {"_NET_WM_ACTION_FULLSCREEN", XCB_ATOM_NONE}, {"_NET_WM_ACTION_MOVE", XCB_ATOM_NONE}, @@ -671,8 +674,8 @@ void configurenotify(xcb_configure_notify_event_t *); void configurerequest(xcb_configure_request_event_t *); void constrain_window(struct ws_win *, struct swm_region *, int); void destroynotify(xcb_destroy_notify_event_t *); -void do_sync(void); void enternotify(xcb_enter_notify_event_t *); +void event_drain(uint8_t); void event_error(xcb_generic_error_t *); void event_handle(xcb_generic_event_t *); char *expand_tilde(char *); @@ -680,7 +683,10 @@ void expose(xcb_expose_event_t *); struct ws_win *find_window(xcb_window_t); int floating_toggle_win(struct ws_win *); void focus(struct swm_region *, union arg *); -void focus_magic(struct ws_win *); +void focus_flush(void); +struct ws_win *get_focus_magic(struct ws_win *); +struct ws_win *get_focus_prev(struct ws_win *); +void focus_win(struct ws_win *); #ifdef SWM_DEBUG void focusin(xcb_focus_in_event_t *); #endif @@ -690,15 +696,18 @@ char *get_atom_name(xcb_atom_t); char *get_notify_detail_label(uint8_t); char *get_notify_mode_label(uint8_t); #endif +struct ws_win *get_region_focus(struct swm_region *); xcb_screen_t *get_screen(int); char *get_win_name(xcb_window_t); uint32_t getstate(xcb_window_t); -void grabbuttons(struct ws_win *, int); +void grabbuttons(struct ws_win *); void keypress(xcb_key_press_event_t *); #ifdef SWM_DEBUG void leavenotify(xcb_leave_notify_event_t *); #endif -void map_window_raised(xcb_window_t); +void load_float_geom(struct ws_win *, struct swm_region *); +struct ws_win *manage_window(xcb_window_t, uint16_t); +void map_window(struct ws_win *); void mapnotify(xcb_map_notify_event_t *); void mappingnotify(xcb_mapping_notify_event_t *); void maprequest(xcb_map_request_event_t *); @@ -711,6 +720,7 @@ void shutdown_cleanup(void); void store_float_geom(struct ws_win *, struct swm_region *); void unmanage_window(struct ws_win *); void unmapnotify(xcb_unmap_notify_event_t *); +void unfocus_win(struct ws_win *); void update_window(struct ws_win *); /*void visibilitynotify(xcb_visibility_notify_event_t *);*/ @@ -792,28 +802,12 @@ get_screen(int screen) } void -do_sync(void) +focus_flush(void) { - xcb_get_input_focus_cookie_t c; - xcb_get_input_focus_reply_t *r; - - /* mimic XSync() */ - c = xcb_get_input_focus(conn); - xcb_flush(conn); - r = xcb_get_input_focus_reply(conn, c, NULL); - if (r) - free(r); -} - -void -map_window_raised(xcb_window_t win) -{ - uint32_t val = XCB_STACK_MODE_ABOVE; - - xcb_configure_window(conn, win, - XCB_CONFIG_WINDOW_STACK_MODE, &val); - - xcb_map_window(conn, win); + if (focus_mode == SWM_FOCUS_DEFAULT) + event_drain(XCB_ENTER_NOTIFY); + else + xcb_flush(conn); } xcb_atom_t @@ -850,7 +844,7 @@ update_iconic(struct ws_win *win, int newv) } int32_t -get_iconic(struct ws_win *win) +get_swm_iconic(struct ws_win *win) { int32_t v = 0; xcb_get_property_reply_t *pr = NULL; @@ -989,12 +983,7 @@ ewmh_set_win_fullscreen(struct ws_win *win, int fs) win->g = win->ws->r->g; win->bordered = 0; } else { - if (win->g_floatvalid) { - /* refloat at last floating relative position */ - win->g = win->g_float; - X(win) += X(win->ws->r); - Y(win) += Y(win->ws->r); - } + load_float_geom(win, win->ws->r); } return (1); @@ -1014,6 +1003,7 @@ ewmh_update_actions(struct ws_win *win) if (win->floating) { actions[n++] = ewmh[_NET_WM_ACTION_MOVE].atom; actions[n++] = ewmh[_NET_WM_ACTION_RESIZE].atom; + actions[n++] = ewmh[_NET_WM_ACTION_ABOVE].atom; } xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->id, @@ -1039,16 +1029,15 @@ ewmh_update_win_state(struct ws_win *win, xcb_atom_t state, long action) if (state == ewmh[_NET_WM_STATE_FULLSCREEN].atom) mask = EWMH_F_FULLSCREEN; - if (state == ewmh[_NET_WM_STATE_ABOVE].atom) + else if (state == ewmh[_NET_WM_STATE_ABOVE].atom) mask = EWMH_F_ABOVE; - if (state == ewmh[_SWM_WM_STATE_MANUAL].atom) + else if (state == ewmh[_SWM_WM_STATE_MANUAL].atom) mask = SWM_F_MANUAL; - if (state == ewmh[_NET_WM_STATE_SKIP_PAGER].atom) + else if (state == ewmh[_NET_WM_STATE_SKIP_PAGER].atom) mask = EWMH_F_SKIP_PAGER; - if (state == ewmh[_NET_WM_STATE_SKIP_TASKBAR].atom) + else if (state == ewmh[_NET_WM_STATE_SKIP_TASKBAR].atom) mask = EWMH_F_SKIP_TASKBAR; - orig_flags = win->ewmh_flags; switch (action) { @@ -1065,18 +1054,17 @@ ewmh_update_win_state(struct ws_win *win, xcb_atom_t state, long action) changed = (win->ewmh_flags & mask) ^ (orig_flags & mask) ? 1 : 0; - if (state == ewmh[_NET_WM_STATE_ABOVE].atom) - if (changed) - if (!floating_toggle_win(win)) + if (state == ewmh[_NET_WM_STATE_ABOVE].atom) { + if (changed && !floating_toggle_win(win)) win->ewmh_flags = orig_flags; /* revert */ - if (state == ewmh[_SWM_WM_STATE_MANUAL].atom) + } else if (state == ewmh[_SWM_WM_STATE_MANUAL].atom) { if (changed) win->manual = (win->ewmh_flags & SWM_F_MANUAL) != 0; - if (state == ewmh[_NET_WM_STATE_FULLSCREEN].atom) - if (changed) - if (!ewmh_set_win_fullscreen(win, + } else if (state == ewmh[_NET_WM_STATE_FULLSCREEN].atom) { + if (changed && !ewmh_set_win_fullscreen(win, win->ewmh_flags & EWMH_F_FULLSCREEN)) win->ewmh_flags = orig_flags; /* revert */ + } xcb_delete_property(conn, win->id, ewmh[_NET_WM_STATE].atom); @@ -1084,19 +1072,19 @@ ewmh_update_win_state(struct ws_win *win, xcb_atom_t state, long action) xcb_change_property(conn, XCB_PROP_MODE_APPEND, win->id, ewmh[_NET_WM_STATE].atom, XCB_ATOM_ATOM, 32, 1, &ewmh[_NET_WM_STATE_FULLSCREEN].atom); - if (win->ewmh_flags & EWMH_F_SKIP_PAGER) + else if (win->ewmh_flags & EWMH_F_SKIP_PAGER) xcb_change_property(conn, XCB_PROP_MODE_APPEND, win->id, ewmh[_NET_WM_STATE].atom, XCB_ATOM_ATOM, 32, 1, &ewmh[_NET_WM_STATE_SKIP_PAGER].atom); - if (win->ewmh_flags & EWMH_F_SKIP_TASKBAR) + else if (win->ewmh_flags & EWMH_F_SKIP_TASKBAR) xcb_change_property(conn, XCB_PROP_MODE_APPEND, win->id, ewmh[_NET_WM_STATE].atom, XCB_ATOM_ATOM, 32, 1, &ewmh[_NET_WM_STATE_SKIP_TASKBAR].atom); - if (win->ewmh_flags & EWMH_F_ABOVE) + else if (win->ewmh_flags & EWMH_F_ABOVE) xcb_change_property(conn, XCB_PROP_MODE_APPEND, win->id, ewmh[_NET_WM_STATE].atom, XCB_ATOM_ATOM, 32, 1, &ewmh[_NET_WM_STATE_ABOVE].atom); - if (win->ewmh_flags & SWM_F_MANUAL) + else if (win->ewmh_flags & SWM_F_MANUAL) xcb_change_property(conn, XCB_PROP_MODE_APPEND, win->id, ewmh[_NET_WM_STATE].atom, XCB_ATOM_ATOM, 32, 1, &ewmh[_SWM_WM_STATE_MANUAL].atom); @@ -1440,8 +1428,7 @@ bar_print_legacy(struct swm_region *r, const char *s) /* clear back buffer */ gcv[0] = r->s->c[SWM_S_COLOR_BAR].pixel; xcb_change_gc(conn, r->s->bar_gc, XCB_GC_FOREGROUND, gcv); - xcb_poly_fill_rectangle(conn, r->bar->buffer, r->s->bar_gc, - sizeof(rect), &rect); + xcb_poly_fill_rectangle(conn, r->bar->buffer, r->s->bar_gc, 1, &rect); /* draw back buffer */ gcvd.graphics_exposures = 0; @@ -1494,8 +1481,7 @@ bar_print(struct swm_region *r, const char *s) /* clear back buffer */ gcv[0] = r->s->c[SWM_S_COLOR_BAR].pixel; xcb_change_gc(conn, r->s->bar_gc, XCB_GC_FOREGROUND, gcv); - xcb_poly_fill_rectangle(conn, r->bar->buffer, r->s->bar_gc, - sizeof(rect), &rect); + xcb_poly_fill_rectangle(conn, r->bar->buffer, r->s->bar_gc, 1, &rect); /* draw back buffer */ draw = XftDrawCreate(display, r->bar->buffer, @@ -1914,16 +1900,17 @@ bar_toggle(struct swm_region *r, union arg *args) for (i = 0; i < num_screens; i++) TAILQ_FOREACH(tmpr, &screens[i].rl, entry) if (tmpr->bar) - map_window_raised(tmpr->bar->id); + xcb_map_window(conn, tmpr->bar->id); } bar_enabled = !bar_enabled; stack(); + /* must be after stack */ bar_update(); - xcb_flush(conn); + focus_flush(); } void @@ -2132,7 +2119,7 @@ bar_setup(struct swm_region *r) XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE); if (bar_enabled) - map_window_raised(r->bar->id); + xcb_map_window(conn, r->bar->id); DNPRINTF(SWM_D_BAR, "bar_setup: window: 0x%x, (x,y) w x h: (%d,%d) " "%d x %d\n", WINID(r->bar), X(r->bar), Y(r->bar), WIDTH(r->bar), @@ -2208,12 +2195,22 @@ version(struct swm_region *r, union arg *args) } void -client_msg(struct ws_win *win, xcb_atom_t a) +client_msg(struct ws_win *win, xcb_atom_t a, xcb_timestamp_t t) { xcb_client_message_event_t ev; +#ifdef SWM_DEBUG + char *name; +#endif if (win == NULL) return; +#ifdef SWM_DEBUG + name = get_atom_name(a); + DNPRINTF(SWM_D_EVENT, "client_msg: window: 0x%x, atom: %s(%u), " + "time: %#x\n", + win->id, name, a, t); + free(name); +#endif bzero(&ev, sizeof ev); ev.response_type = XCB_CLIENT_MESSAGE; @@ -2221,7 +2218,7 @@ client_msg(struct ws_win *win, xcb_atom_t a) ev.type = a_prot; ev.format = 32; ev.data.data32[0] = a; - ev.data.data32[1] = XCB_CURRENT_TIME; + ev.data.data32[1] = t; xcb_send_event(conn, 0, win->id, XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); @@ -2340,22 +2337,42 @@ quit(struct swm_region *r, union arg *args) } void -unmap_window(struct ws_win *win) +map_window(struct ws_win *win) { - DNPRINTF(SWM_D_EVENT, "unmap_window: window: 0x%x\n", win->id); + uint32_t val = XCB_STACK_MODE_ABOVE; if (win == NULL) return; - /* don't unmap again */ - if (getstate(win->id) == XCB_ICCCM_WM_STATE_ICONIC) + DNPRINTF(SWM_D_EVENT, "map_window: win 0x%x, mapped: %s\n", win->id, + YESNO(win->mapped)); + + xcb_configure_window(conn, win->id, + XCB_CONFIG_WINDOW_STACK_MODE, &val); + + if (win->mapped) return; - set_win_state(win, XCB_ICCCM_WM_STATE_ICONIC); + xcb_map_window(conn, win->id); + set_win_state(win, XCB_ICCCM_WM_STATE_NORMAL); + win->mapped = 1; +} + +void +unmap_window(struct ws_win *win) +{ + if (win == NULL) + return; + + DNPRINTF(SWM_D_EVENT, "unmap_window: win 0x%x, mapped: %s\n", win->id, + YESNO(win->mapped)); + + if (!win->mapped) + return; xcb_unmap_window(conn, win->id); - xcb_change_window_attributes(conn, win->id, - XCB_CW_BORDER_PIXEL, &win->s->c[SWM_S_COLOR_UNFOCUS].pixel); + set_win_state(win, XCB_ICCCM_WM_STATE_ICONIC); + win->mapped = 0; } void @@ -2640,16 +2657,23 @@ unfocus_win(struct ws_win *win) if (win == NULL) return; - if (win->ws == NULL) + if (win->ws == NULL) { + DNPRINTF(SWM_D_FOCUS, "unfocus_win: NULL ws.\n"); return; + } - if (validate_ws(win->ws)) - return; /* XXX this gets hit with thunderbird, needs fixing */ + if (validate_ws(win->ws)) { + DNPRINTF(SWM_D_FOCUS, "unfocus_win: invalid ws.\n"); + return; + } - if (win->ws->r == NULL) + if (win->ws->r == NULL) { + DNPRINTF(SWM_D_FOCUS, "unfocus_win: NULL region.\n"); return; + } if (validate_win(win)) { + DNPRINTF(SWM_D_FOCUS, "unfocus_win: invalid win.\n"); kill_refs(win); return; } @@ -2668,93 +2692,118 @@ unfocus_win(struct ws_win *win) win->ws->focus_prev = NULL; } - grabbuttons(win, 0); 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); -} -void -unfocus_all(void) -{ - struct ws_win *win; - int i, j, num_screens; - - DNPRINTF(SWM_D_FOCUS, "unfocus_all\n"); - - num_screens = xcb_setup_roots_length(xcb_get_setup(conn)); - for (i = 0; i < num_screens; i++) - for (j = 0; j < workspace_limit; j++) - TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) - unfocus_win(win); + DNPRINTF(SWM_D_FOCUS, "unfocus_win: done.\n"); } void focus_win(struct ws_win *win) { - struct ws_win *cfw = NULL; + struct ws_win *cfw = NULL; xcb_get_input_focus_reply_t *r; - xcb_window_t cur_focus = XCB_WINDOW_NONE; DNPRINTF(SWM_D_FOCUS, "focus_win: window: 0x%x\n", WINID(win)); if (win == NULL) - return; + goto out; + if (win->ws == NULL) - return; + goto out; if (validate_ws(win->ws)) - return; /* XXX this gets hit with thunderbird, needs fixing */ - - if (validate_win(win)) { - kill_refs(win); - return; - } + goto out; if (validate_win(win)) { kill_refs(win); - return; + goto out; } r = xcb_get_input_focus_reply(conn, xcb_get_input_focus(conn), NULL); if (r) { - cur_focus = r->focus; + cfw = find_window(r->focus); + if (cfw != win) + unfocus_win(cfw); free(r); } - if ((cfw = find_window(cur_focus)) != NULL) - unfocus_win(cfw); - else { -#if 0 - /* use larger hammer since the window was killed somehow */ - TAILQ_FOREACH(cfw, &win->ws->winlist, entry) - if (cfw->ws && cfw->ws->r && cfw->ws->r->s) - xcb_change_window_attributes(conn, cfw->id, - XCB_CW_BORDER_PIXEL, - &cfw->ws->r->s->c[SWM_S_COLOR_UNFOCUS].pixel); -#endif - } - win->ws->focus = win; + if (win->ws->focus != win) { + if (win->ws->focus && win->ws->focus != cfw) + unfocus_win(win->ws->focus); + win->ws->focus = win; + } - if (win->ws->r != NULL) { - if (win->java == 0) + if (cfw != win && win->ws->r != NULL) { + /* Set input focus if no input hint, or indicated by hint. */ + if (!(win->hints.flags & XCB_ICCCM_WM_HINT_INPUT) || + (win->hints.flags & XCB_ICCCM_WM_HINT_INPUT && + win->hints.input)) xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT, - win->id, XCB_CURRENT_TIME); - grabbuttons(win, 1); - xcb_change_window_attributes(conn, win->id, - XCB_CW_BORDER_PIXEL, + win->id, last_event_time); + + /* Tell app it can adjust focus to a specific window. */ + if (win->take_focus) { + /* java is special; always tell parent */ + if (win->transient && win->java) + client_msg(find_window(win->transient), + a_takefocus, last_event_time); + else + client_msg(win, a_takefocus, last_event_time); + } + + xcb_change_window_attributes(conn, win->id, XCB_CW_BORDER_PIXEL, &win->ws->r->s->c[SWM_S_COLOR_FOCUS].pixel); + if (win->ws->cur_layout->flags & SWM_L_MAPONFOCUS || win->ws->always_raise) - map_window_raised(win->id); + map_window(win); xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->s->root, ewmh[_NET_ACTIVE_WINDOW].atom, XCB_ATOM_WINDOW, 32, 1, &win->id); } +out: bar_update(); + + DNPRINTF(SWM_D_FOCUS, "focus_win: done.\n"); +} + +/* If a child window should have focus instead, return it. */ +struct ws_win * +get_focus_magic(struct ws_win *win) +{ + struct ws_win *parent = NULL; + + DNPRINTF(SWM_D_FOCUS, "get_focus_magic: window: 0x%x\n", WINID(win)); + if (win == NULL) + return 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; + 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; + else + win->focus_child = NULL; + } + + return win; } void @@ -2762,7 +2811,8 @@ event_drain(uint8_t rt) { xcb_generic_event_t *evt; - xcb_flush(conn); + /* ensure all pending requests have been processed before filtering. */ + xcb_aux_sync(conn); while ((evt = xcb_poll_for_event(conn))) { if (XCB_EVENT_RESPONSE_TYPE(evt) != rt) event_handle(evt); @@ -2778,7 +2828,6 @@ switchws(struct swm_region *r, union arg *args) struct swm_region *this_r, *other_r; struct ws_win *win; struct workspace *new_ws, *old_ws; - union arg a; if (!(r && r->s)) return; @@ -2813,24 +2862,29 @@ switchws(struct swm_region *r, union arg *args) this_r->ws = new_ws; new_ws->r = this_r; - /* this is needed so that we can click on a window after a restart */ - unfocus_all(); + unfocus_win(old_ws->focus); stack(); - a.id = SWM_ARG_ID_FOCUSCUR; - focus(new_ws->r, &a); /* unmap old windows */ if (unmap_old) TAILQ_FOREACH(win, &old_ws->winlist, entry) unmap_window(win); - if (focus_mode == SWM_FOCUS_DEFAULT) - event_drain(XCB_ENTER_NOTIFY); - else - xcb_flush(conn); + 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); + + /* make sure bar gets updated if ws is empty */ + if (!new_ws->focus) + bar_update(); - DNPRINTF(SWM_D_WS, "switchws: done\n"); + focus_flush(); + + DNPRINTF(SWM_D_WS, "switchws: done.\n"); } void @@ -2899,7 +2953,6 @@ void cyclescr(struct swm_region *r, union arg *args) { struct swm_region *rr = NULL; - union arg a; int i, x, y, num_screens; num_screens = xcb_setup_roots_length(xcb_get_setup(conn)); @@ -2931,8 +2984,7 @@ cyclescr(struct swm_region *r, union arg *args) xcb_warp_pointer(conn, XCB_WINDOW_NONE, rr->s[i].root, 0, 0, 0, 0, x, y); - a.id = SWM_ARG_ID_FOCUSCUR; - focus(rr, &a); + rr->ws->focus = get_region_focus(rr); if (rr->ws->focus) { /* move to focus window */ @@ -2941,6 +2993,8 @@ cyclescr(struct swm_region *r, union arg *args) xcb_warp_pointer(conn, XCB_WINDOW_NONE, rr->s[i].root, 0, 0, 0, 0, x, y); } + + focus_flush(); } void @@ -3038,11 +3092,11 @@ swapwin(struct swm_region *r, union arg *args) stack(); - xcb_flush(conn); + focus_flush(); } -void -focus_prev(struct ws_win *win) +struct ws_win * +get_focus_prev(struct ws_win *win) { struct ws_win *winfocus = NULL; struct ws_win *cur_focus = NULL; @@ -3050,13 +3104,13 @@ focus_prev(struct ws_win *win) struct workspace *ws = NULL; if (!(win && win->ws)) - return; + return NULL; ws = win->ws; wl = &ws->winlist; cur_focus = ws->focus; - DNPRINTF(SWM_D_FOCUS, "focus_prev: window: 0x%x, cur_focus: 0x%x\n", + DNPRINTF(SWM_D_FOCUS, "get_focus_prev: window: 0x%x, cur_focus: 0x%x\n", WINID(win), WINID(cur_focus)); /* pickle, just focus on whatever */ @@ -3085,7 +3139,7 @@ focus_prev(struct ws_win *win) goto done; } - DNPRINTF(SWM_D_FOCUS, "focus_prev: focus_close: %d\n", focus_close); + DNPRINTF(SWM_D_FOCUS, "get_focus_prev: focus_close: %d\n", focus_close); if (winfocus == NULL || winfocus == win) { switch (focus_close) { @@ -3124,14 +3178,34 @@ done: } kill_refs(win); - focus_magic(winfocus); + + return get_focus_magic(winfocus); +} + +struct ws_win * +get_region_focus(struct swm_region *r) +{ + struct ws_win *winfocus = NULL; + + if (!(r && r->ws)) + return NULL; + + if (r->ws->focus && !r->ws->focus->iconic) + winfocus = r->ws->focus; + else if (r->ws->focus_prev && !r->ws->focus_prev->iconic) + winfocus = r->ws->focus_prev; + else + TAILQ_FOREACH(winfocus, &r->ws->winlist, entry) + if (!winfocus->iconic) + break; + + return get_focus_magic(winfocus); } void focus(struct swm_region *r, union arg *args) { - struct ws_win *winfocus = NULL, *head; - struct ws_win *cur_focus = NULL; + struct ws_win *head, *cur_focus = NULL, *winfocus = NULL; struct ws_win_list *wl = NULL; struct workspace *ws = NULL; int all_iconics; @@ -3141,21 +3215,6 @@ focus(struct swm_region *r, union arg *args) DNPRINTF(SWM_D_FOCUS, "focus: id: %d\n", args->id); - /* treat FOCUS_CUR special */ - if (args->id == SWM_ARG_ID_FOCUSCUR) { - if (r->ws->focus && r->ws->focus->iconic == 0) - winfocus = r->ws->focus; - else if (r->ws->focus_prev && r->ws->focus_prev->iconic == 0) - winfocus = r->ws->focus_prev; - else - TAILQ_FOREACH(winfocus, &r->ws->winlist, entry) - if (winfocus->iconic == 0) - break; - - focus_magic(winfocus); - return; - } - if ((cur_focus = r->ws->focus) == NULL) return; ws = r->ws; @@ -3226,7 +3285,7 @@ focus(struct swm_region *r, union arg *args) return; } - focus_magic(winfocus); + focus_win(get_focus_magic(winfocus)); xcb_flush(conn); } @@ -3235,7 +3294,6 @@ void cycle_layout(struct swm_region *r, union arg *args) { struct workspace *ws = r->ws; - union arg a; /* suppress unused warning since var is needed */ (void)args; @@ -3249,11 +3307,9 @@ cycle_layout(struct swm_region *r, union arg *args) stack(); bar_update(); - if (focus_mode == SWM_FOCUS_DEFAULT) - event_drain(XCB_ENTER_NOTIFY); + focus_win(get_region_focus(r)); - a.id = SWM_ARG_ID_FOCUSCUR; - focus(r, &a); + focus_flush(); } void @@ -3270,6 +3326,8 @@ stack_config(struct swm_region *r, union arg *args) if (args->id != SWM_ARG_ID_STACKINIT) stack(); bar_update(); + + focus_flush(); } void @@ -3310,15 +3368,15 @@ stack(void) { if (font_adjusted) font_adjusted--; - if (focus_mode == SWM_FOCUS_DEFAULT) - event_drain(XCB_ENTER_NOTIFY); - DNPRINTF(SWM_D_STACK, "stack: end\n"); } void store_float_geom(struct ws_win *win, struct swm_region *r) { + if (win == NULL || r == NULL) + return; + /* retain window geom and region geom */ win->g_float = win->g; win->g_float.x -= X(r); @@ -3331,6 +3389,25 @@ store_float_geom(struct ws_win *win, struct swm_region *r) } void +load_float_geom(struct ws_win *win, struct swm_region *r) +{ + if (win == NULL || r == NULL) + return; + + if (win->g_floatvalid) { + win->g = win->g_float; + X(win) += X(r); + Y(win) += Y(r); + DNPRINTF(SWM_D_MISC, "load_float_geom: window: 0x%x, g: (%d,%d)" + "%d x %d\n", win->id, X(win), Y(win), WIDTH(win), + HEIGHT(win)); + } else { + DNPRINTF(SWM_D_MISC, "load_float_geom: window: 0x%x, g_float " + "is not set.\n", win->id); + } +} + +void stack_floater(struct ws_win *win, struct swm_region *r) { if (win == NULL) @@ -3342,12 +3419,10 @@ stack_floater(struct ws_win *win, struct swm_region *r) * to allow windows to change their size (e.g. mplayer fs) only retrieve * geom on ws switches or return from max mode */ - if (win->g_floatvalid && (win->floatmaxed || (r != r->ws->old_r && - !(win->ewmh_flags & EWMH_F_FULLSCREEN)))) { - /* refloat at last floating relative position */ - win->g = win->g_float; - X(win) += X(r); - Y(win) += Y(r); + if (win->floatmaxed || (r != r->ws->old_r && + !(win->ewmh_flags & EWMH_F_FULLSCREEN))) { + /* update geometry for the new region */ + load_float_geom(win, r); } win->floatmaxed = 0; @@ -3359,7 +3434,7 @@ stack_floater(struct ws_win *win, struct swm_region *r) if (!win->g_floatvalid) store_float_geom(win, win->ws->r); - win->g = win->ws->r->g; + win->g = r->g; } /* @@ -3385,13 +3460,16 @@ stack_floater(struct ws_win *win, struct swm_region *r) HEIGHT(win) = (double)HEIGHT(r) * dialog_ratio; } - if (!win->manual) { + if (!win->manual && !(win->ewmh_flags & EWMH_F_FULLSCREEN) && + !(win->quirks & SWM_Q_ANYWHERE)) { /* - * floaters and transients are auto-centred unless moved - * or resized + * floaters and transients are auto-centred unless moved, + * resized or ANYWHERE quirk is set. */ X(win) = X(r) + (WIDTH(r) - WIDTH(win)) / 2 - BORDER(win); Y(win) = Y(r) + (HEIGHT(r) - HEIGHT(win)) / 2 - BORDER(win); + + store_float_geom(win, r); } /* keep window within region bounds */ @@ -3445,7 +3523,6 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) int split, colno, winno, mwin, msize, mscale; int remain, missing, v_slice, reconfigure; int bordered = 1; - xcb_get_window_attributes_reply_t *war; DNPRINTF(SWM_D_STACK, "stack_master: workspace: %d, rot: %s, " "flip: %s\n", ws->idx, YESNO(rot), YESNO(flip)); @@ -3608,14 +3685,7 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) update_window(win); } - war = xcb_get_window_attributes_reply(conn, - xcb_get_window_attributes(conn, win->id), - NULL); - if (war) { - if (war->map_state == XCB_MAP_STATE_UNMAPPED) - map_window_raised(win->id); - free(war); - } + map_window(win); last_h = win_g.h; i++; @@ -3635,12 +3705,12 @@ notiles: } stack_floater(win, ws->r); - map_window_raised(win->id); + map_window(win); } if (fs_win) { stack_floater(fs_win, ws->r); - map_window_raised(fs_win->id); + map_window(fs_win); } } @@ -3802,9 +3872,9 @@ max_stack(struct workspace *ws, struct swm_geometry *g) /* put the last transient on top */ if (wintrans) { if (parent) - map_window_raised(parent->id); + map_window(parent); stack_floater(wintrans, ws->r); - focus_magic(wintrans); + ws->focus = get_focus_magic(wintrans); } } @@ -3864,7 +3934,7 @@ send_to_ws(struct swm_region *r, union arg *args) stack(); bar_update(); - xcb_flush(conn); + focus_flush(); } void @@ -3894,26 +3964,19 @@ raise_toggle(struct swm_region *r, union arg *args) if (r->ws->always_raise == 0) stack(); - xcb_flush(conn); + focus_flush(); } void iconify(struct swm_region *r, union arg *args) { - union arg a; - /* suppress unused warning since var is needed */ (void)args; if (r->ws->focus == NULL) return; - unmap_window(r->ws->focus); - update_iconic(r->ws->focus, 1); - stack(); - r->ws->focus = NULL; - a.id = SWM_ARG_ID_FOCUSCUR; - focus(r, &a); + update_iconic(r->ws->focus, 1); xcb_flush(conn); } @@ -3997,8 +4060,6 @@ uniconify(struct swm_region *r, union arg *args) } fclose(lfile); - - xcb_flush(conn); } void @@ -4133,7 +4194,7 @@ search_win(struct swm_region *r, union arg *args) XCB_COPY_FROM_PARENT, XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL, wa); - map_window_raised(w); + xcb_map_window(conn, w); sw->indicator = w; TAILQ_INSERT_TAIL(&search_wl, sw, entry); @@ -4197,6 +4258,7 @@ search_resp_uniconify(char *resp, unsigned long len) if (strncmp(s, resp, len) == 0) { /* XXX this should be a callback to generalize */ update_iconic(win, 0); + xcb_flush(conn); free(s); break; } @@ -4349,6 +4411,8 @@ done: search_resp_action = SWM_SEARCH_NONE; close(select_resp_pipe[0]); free(resp); + + xcb_flush(conn); } void @@ -4363,7 +4427,7 @@ wkill(struct swm_region *r, union arg *args) xcb_kill_client(conn, r->ws->focus->id); else if (r->ws->focus->can_delete) - client_msg(r->ws->focus, a_delete); + client_msg(r->ws->focus, a_delete, 0); xcb_flush(conn); } @@ -4393,13 +4457,7 @@ floating_toggle_win(struct ws_win *win) } win->floating = 0; } else { - if (win->g_floatvalid) { - /* refloat at last floating relative position */ - X(win) = win->g_float.x + X(r); - Y(win) = win->g_float.y + Y(r); - WIDTH(win) = win->g_float.w; - HEIGHT(win) = win->g_float.h; - } + load_float_geom(win, r); win->floating = 1; } @@ -4412,7 +4470,6 @@ void floating_toggle(struct swm_region *r, union arg *args) { struct ws_win *win = r->ws->focus; - union arg a; /* suppress unused warning since var is needed */ (void)args; @@ -4420,18 +4477,18 @@ floating_toggle(struct swm_region *r, union arg *args) if (win == NULL) return; + if (win->ewmh_flags & EWMH_F_FULLSCREEN) + return; + ewmh_update_win_state(win, ewmh[_NET_WM_STATE_ABOVE].atom, _NET_WM_STATE_TOGGLE); stack(); - if (win == win->ws->focus) { - a.id = SWM_ARG_ID_FOCUSCUR; - focus(win->ws->r, &a); - } + if (win == win->ws->focus) + focus_win(win); - xcb_flush(conn); - event_drain(XCB_ENTER_NOTIFY); + focus_flush(); } void @@ -4537,6 +4594,8 @@ resize(struct ws_win *win, union arg *args) stack(); + focus_flush(); + switch (args->id) { case SWM_ARG_ID_WIDTHSHRINK: WIDTH(win) -= SWM_RESIZE_STEPS; @@ -4655,8 +4714,8 @@ resize(struct ws_win *win, union arg *args) /* not free, don't sync more than 120 times / second */ if ((mne->time - timestamp) > (1000 / 120) ) { timestamp = mne->time; - do_sync(); update_window(win); + xcb_flush(conn); } break; default: @@ -4666,8 +4725,8 @@ resize(struct ws_win *win, union arg *args) free(evt); } if (timestamp) { - do_sync(); update_window(win); + xcb_flush(conn); } store_float_geom(win,r); @@ -4675,7 +4734,7 @@ resize(struct ws_win *win, union arg *args) xcb_free_cursor(conn, cursor); xcb_close_font(conn, cursor_font); free(xpr); - DNPRINTF(SWM_D_EVENT, "resize: done\n"); + DNPRINTF(SWM_D_EVENT, "resize: done.\n"); } void @@ -4730,6 +4789,8 @@ move(struct ws_win *win, union arg *args) stack(); + focus_flush(); + move_step = 0; switch (args->id) { case SWM_ARG_ID_MOVELEFT: @@ -4797,8 +4858,8 @@ move(struct ws_win *win, union arg *args) /* not free, don't sync more than 120 times / second */ if ((mne->time - timestamp) > (1000 / 120) ) { timestamp = mne->time; - do_sync(); update_window(win); + xcb_flush(conn); } break; default: @@ -4808,15 +4869,15 @@ move(struct ws_win *win, union arg *args) free(evt); } if (timestamp) { - do_sync(); update_window(win); + xcb_flush(conn); } store_float_geom(win, r); free(qpr); xcb_free_cursor(conn, cursor); xcb_close_font(conn, cursor_font); xcb_ungrab_pointer(conn, XCB_CURRENT_TIME); - DNPRINTF(SWM_D_EVENT, "move: done\n"); + DNPRINTF(SWM_D_EVENT, "move: done.\n"); } void @@ -5069,9 +5130,9 @@ struct button { } buttons[] = { #define MODKEY_SHIFT MODKEY | XCB_MOD_MASK_SHIFT /* action key mouse button func args */ - { client_click, MODKEY, Button3, resize, {.id = SWM_ARG_ID_DONTCENTER} }, - { client_click, MODKEY_SHIFT, Button3, resize, {.id = SWM_ARG_ID_CENTER} }, - { client_click, MODKEY, Button1, move, {0} }, + { client_click, MODKEY, XCB_BUTTON_INDEX_3, resize, {.id = SWM_ARG_ID_DONTCENTER} }, + { client_click, MODKEY_SHIFT, XCB_BUTTON_INDEX_3, resize, {.id = SWM_ARG_ID_CENTER} }, + { client_click, MODKEY, XCB_BUTTON_INDEX_1, move, {0} }, #undef MODKEY_SHIFT }; @@ -5350,7 +5411,7 @@ setconfspawn(char *selector, char *value, int flags) setspawn(selector, args); free(args); - DNPRINTF(SWM_D_SPAWN, "setconfspawn: done\n"); + DNPRINTF(SWM_D_SPAWN, "setconfspawn: done.\n"); return (0); } @@ -5776,40 +5837,37 @@ grabkeys(void) XCB_MOD_MASK_ANY); RB_FOREACH(kp, key_tree, &keys) { if ((code = xcb_key_symbols_get_keycode(syms, - kp->keysym))) + kp->keysym))) { for (j = 0; j < LENGTH(modifiers); j++) xcb_grab_key(conn, 1, screens[k].root, kp->mod | modifiers[j], - *code, XCB_GRAB_MODE_ASYNC, + *code, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); free(code); + } } } } void -grabbuttons(struct ws_win *win, int focused) +grabbuttons(struct ws_win *win) { int i; - xcb_ungrab_button(conn, XCB_BUTTON_INDEX_ANY, win->id, - XCB_BUTTON_MASK_ANY); - if (focused) { - for (i = 0; i < LENGTH(buttons); i++) - if (buttons[i].action == client_click) - xcb_grab_button(conn, 0, win->id, - BUTTONMASK, - XCB_GRAB_MODE_ASYNC, - XCB_GRAB_MODE_SYNC, - XCB_WINDOW_NONE, - XCB_CURSOR_NONE, - buttons[i].button, - buttons[i].mask); - } else - xcb_grab_button(conn, 0, win->id, BUTTONMASK, - XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_SYNC, XCB_WINDOW_NONE, - XCB_CURSOR_NONE, XCB_BUTTON_INDEX_ANY, XCB_BUTTON_MASK_ANY); + DNPRINTF(SWM_D_MOUSE, "grabbuttons: win 0x%x\n", win->id); + + for (i = 0; i < LENGTH(buttons); i++) + if (buttons[i].action == client_click) + xcb_grab_button(conn, 0, win->id, BUTTONMASK, + XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, + XCB_WINDOW_NONE, XCB_CURSOR_NONE, + buttons[i].button, buttons[i].mask); + + /* click to focus */ + xcb_grab_button(conn, 0, win->id, BUTTONMASK, XCB_GRAB_MODE_SYNC, + XCB_GRAB_MODE_ASYNC, XCB_WINDOW_NONE, XCB_CURSOR_NONE, + XCB_BUTTON_INDEX_1, XCB_BUTTON_MASK_ANY); } const char *quirkname[] = { @@ -6134,8 +6192,8 @@ setconfvalue(char *selector, char *value, int flags) focus_mode = SWM_FOCUS_DEFAULT; else if (!strcmp(value, "follow_cursor")) focus_mode = SWM_FOCUS_FOLLOW; - else if (!strcmp(value, "synergy")) - focus_mode = SWM_FOCUS_SYNERGY; + else if (!strcmp(value, "manual")) + focus_mode = SWM_FOCUS_MANUAL; else errx(1, "focus_mode"); break; @@ -6389,6 +6447,8 @@ setlayout(char *selector, char *value, int flags) } } + focus_flush(); + return (0); } @@ -6568,7 +6628,7 @@ set_child_transient(struct ws_win *win, xcb_window_t *trans) parent = find_window(win->transient); if (parent) - parent->child_trans = win; + parent->focus_child = win; else { DNPRINTF(SWM_D_MISC, "set_child_transient: parent doesn't exist" " for 0x%x trans 0x%x\n", win->id, win->transient); @@ -6587,7 +6647,7 @@ set_child_transient(struct ws_win *win, xcb_window_t *trans) if (win->hints.window_group != wmh.window_group) continue; - w->child_trans = win; + w->focus_child = win; win->transient = w->id; *trans = w->id; DNPRINTF(SWM_D_MISC, "set_child_transient: adjusting " @@ -6686,88 +6746,88 @@ get_ws_idx(xcb_window_t id) } struct ws_win * -manage_window(xcb_window_t id) +manage_window(xcb_window_t id, uint16_t mapped) { xcb_window_t trans = XCB_WINDOW_NONE; - struct workspace *ws; struct ws_win *win, *ww; - int ws_idx, border_me = 0; - char ws_idx_str[SWM_PROPLEN], *prop = NULL; + 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) - return (win); /* already being managed */ + if ((win = find_window(id)) != NULL) { + DNPRINTF(SWM_D_MISC, "manage_window: win 0x%x already " + "managed; skipping.)\n", id); + return (win); /* Already managed. */ + } - /* see if we are on the unmanaged list */ + /* See if window is on the unmanaged list. */ if ((win = find_unmanaged_window(id)) != NULL) { - DNPRINTF(SWM_D_MISC, "manage_window: previously unmanaged " - "window: 0x%x\n", win->id); + DNPRINTF(SWM_D_MISC, "manage_window: win 0x%x found on " + "unmanaged list.\n", id); TAILQ_REMOVE(&win->ws->unmanagedlist, win, entry); + if (win->transient) set_child_transient(win, &trans); - if (trans && (ww = find_window(trans))) - TAILQ_INSERT_AFTER(&win->ws->winlist, ww, win, entry); - else if ((ww = win->ws->focus) && - spawn_position == SWM_STACK_ABOVE) - TAILQ_INSERT_AFTER(&win->ws->winlist, win->ws->focus, - win, entry); - else if (ww && spawn_position == SWM_STACK_BELOW) - TAILQ_INSERT_BEFORE(win->ws->focus, win, entry); - else switch (spawn_position) { - default: - case SWM_STACK_TOP: - case SWM_STACK_ABOVE: - TAILQ_INSERT_TAIL(&win->ws->winlist, win, entry); - break; - case SWM_STACK_BOTTOM: - case SWM_STACK_BELOW: - TAILQ_INSERT_HEAD(&win->ws->winlist, win, entry); - } - - ewmh_update_actions(win); - return (win); + goto out; + } else { + DNPRINTF(SWM_D_MISC, "manage_window: win 0x%x is new.\n", id); } + /* 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; - win->bordered = 0; - - /* see if we need to override the workspace */ - p = find_pid(window_get_pid(id)); - - /* Get all the window data in one shot */ - ws_idx = get_ws_idx(id); + /* Get window geometry. */ win->wa = xcb_get_geometry_reply(conn, - xcb_get_geometry(conn, id), + xcb_get_geometry(conn, win->id), NULL); + + /* Figure out which region the window belongs to. */ + r = root_to_region(win->wa->root); + + /* 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 - 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; + win->s = r->s; /* this never changes */ + + store_float_geom(win, r); + + /* Get WM_SIZE_HINTS. */ xcb_icccm_get_wm_normal_hints_reply(conn, - xcb_icccm_get_wm_normal_hints(conn, id), + xcb_icccm_get_wm_normal_hints(conn, win->id), &win->sh, NULL); + + /* Get WM_HINTS. */ xcb_icccm_get_wm_hints_reply(conn, - xcb_icccm_get_wm_hints(conn, id), + xcb_icccm_get_wm_hints(conn, win->id), &win->hints, NULL); + + /* Get WM_TRANSIENT_FOR; see if window is a transient. */ xcb_icccm_get_wm_transient_for_reply(conn, - xcb_icccm_get_wm_transient_for(conn, id), + xcb_icccm_get_wm_transient_for(conn, win->id), &trans, NULL); if (trans) { win->transient = trans; - set_child_transient(win, &trans); - DNPRINTF(SWM_D_MISC, "manage_window: window: 0x%x, " - "transient: 0x%x\n", win->id, win->transient); + set_child_transient(win, &win->transient); } - /* get supported protocols */ + /* Get supported protocols. */ if (xcb_icccm_get_wm_protocols_reply(conn, - xcb_icccm_get_wm_protocols(conn, id, a_prot), + xcb_icccm_get_wm_protocols(conn, win->id, a_prot), &wpr, NULL)) { for (i = 0; i < wpr.atoms_len; i++) { if (wpr.atoms[i] == a_takefocus) @@ -6778,77 +6838,27 @@ manage_window(xcb_window_t id) xcb_icccm_get_wm_protocols_reply_wipe(&wpr); } - win->iconic = get_iconic(win); + win->iconic = get_swm_iconic(win); - /* - * Figure out where to put the window. If it was previously assigned to - * a workspace (either by spawn() or manually moving), and isn't - * transient, * put it in the same workspace - */ - r = root_to_region(win->wa->root); - if (p) { - ws = &r->s->ws[p->ws]; + /* Figure out which workspace the window belongs to. */ + if ((p = find_pid(window_get_pid(win->id))) != NULL) { + win->ws = &r->s->ws[p->ws]; TAILQ_REMOVE(&pidlist, p, entry); free(p); p = NULL; - } else if (ws_idx != -1 && win->transient == 0) { - ws = &r->s->ws[ws_idx]; + } else if ((ws_idx = get_ws_idx(win->id)) != -1 && + win->transient == 0) { + /* _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; } else { - ws = r->ws; - /* this should launch transients in the same ws as parent */ - if (id && trans) - if ((ww = find_window(trans)) != NULL) - if (ws->r) { - ws = ww->ws; - if (ww->ws->r) - r = ww->ws->r; - else - warnx("manage_window: fix this " - "bug mcbride"); - border_me = 1; - } - } - - /* set up the window layout */ - win->id = id; - win->ws = ws; - win->s = r->s; /* this never changes */ - if (trans && (ww = find_window(trans))) - TAILQ_INSERT_AFTER(&ws->winlist, ww, win, entry); - else if (win->ws->focus && spawn_position == SWM_STACK_ABOVE) - TAILQ_INSERT_AFTER(&win->ws->winlist, win->ws->focus, win, - entry); - else if (win->ws->focus && spawn_position == SWM_STACK_BELOW) - TAILQ_INSERT_BEFORE(win->ws->focus, win, entry); - else switch (spawn_position) { - default: - case SWM_STACK_TOP: - case SWM_STACK_ABOVE: - TAILQ_INSERT_TAIL(&win->ws->winlist, win, entry); - break; - case SWM_STACK_BOTTOM: - case SWM_STACK_BELOW: - TAILQ_INSERT_HEAD(&win->ws->winlist, win, entry); + win->ws = r->ws; } - /* 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; - win->g_floatvalid = 0; - win->floatmaxed = 0; - win->ewmh_flags = 0; - - DNPRINTF(SWM_D_MISC, "manage_window: window: 0x%x, (x,y) w x h: " - "(%d,%d) %d x %d, ws: %d\n", win->id, X(win), Y(win), WIDTH(win), - HEIGHT(win), ws->idx); - - constrain_window(win, r, 0); - - /* Set window properties so we can remember this after reincarnation */ - if (prop == NULL && snprintf(ws_idx_str, SWM_PROPLEN, "%d", ws->idx) < + /* Set the _SWM_WS atom so we can remember this after reincarnation. */ + if (snprintf(ws_idx_str, SWM_PROPLEN, "%d", win->ws->idx) < SWM_PROPLEN) { DNPRINTF(SWM_D_PROP, "manage_window: set _SWM_WS: %s\n", ws_idx_str); @@ -6856,11 +6866,11 @@ manage_window(xcb_window_t id) a_swm_ws, XCB_ATOM_STRING, 8, strlen(ws_idx_str), ws_idx_str); } - if (prop) - free(prop); + /* Handle EWMH */ ewmh_autoquirk(win); + /* Determine initial quirks. */ if (xcb_icccm_get_wm_class_reply(conn, xcb_icccm_get_wm_class(conn, win->id), &win->ch, NULL)) { @@ -6869,34 +6879,26 @@ manage_window(xcb_window_t id) /* java is retarded so treat it special */ if (strstr(win->ch.instance_name, "sun-awt")) { + DNPRINTF(SWM_D_CLASS, "manage_window: java window " + "detected.\n"); win->java = 1; - border_me = 1; } TAILQ_FOREACH(qp, &quirks, entry) { if (!strcmp(win->ch.class_name, qp->class) && !strcmp(win->ch.instance_name, qp->name)) { - DNPRINTF(SWM_D_CLASS, "manage_window: found: " - "class: %s, name: %s\n", win->ch.class_name, - win->ch.instance_name); - if (qp->quirk & SWM_Q_FLOAT) { + DNPRINTF(SWM_D_CLASS, "manage_window: on quirks" + "list; mask: 0x%lx\n", qp->quirk); + 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) { - win->manual = 1; /* don't center the quirky windows */ - if (bar_enabled && Y(win) < bar_height) - Y(win) = bar_height; - if (WIDTH(win) + X(win) > WIDTH(r)) - X(win) = WIDTH(r) - WIDTH(win) - 2; - border_me = 1; - } + /* Alter window position if quirky */ + if (win->quirks & SWM_Q_ANYWHERE) + win->manual = 1; /* Reset font sizes (the bruteforce way; no default keybinding). */ if (win->quirks & SWM_Q_XTERM_FONTADJ) { @@ -6906,29 +6908,55 @@ manage_window(xcb_window_t id) fake_keypress(win, XK_KP_Add, XCB_MOD_MASK_SHIFT); } - ewmh_get_win_state(win); - ewmh_update_actions(win); - ewmh_update_win_state(win, None, _NET_WM_STATE_REMOVE); - - /* border me */ - 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) { + constrain_window(win, win->ws->r, 0); update_window(win); } - 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, 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. */ + if (trans && (ww = find_window(trans))) + TAILQ_INSERT_AFTER(&win->ws->winlist, ww, win, entry); + else if (win->ws->focus && spawn_position == SWM_STACK_ABOVE) + TAILQ_INSERT_AFTER(&win->ws->winlist, win->ws->focus, win, + entry); + else if (win->ws->focus && spawn_position == SWM_STACK_BELOW) + TAILQ_INSERT_BEFORE(win->ws->focus, win, entry); + else switch (spawn_position) { + default: + case SWM_STACK_TOP: + case SWM_STACK_ABOVE: + TAILQ_INSERT_TAIL(&win->ws->winlist, win, entry); + break; + case SWM_STACK_BOTTOM: + case SWM_STACK_BELOW: + TAILQ_INSERT_HEAD(&win->ws->winlist, win, entry); + } + + /* Get initial _NET_WM_STATE */ + ewmh_get_win_state(win); + /* Set initial _NET_WM_ALLOWED_ACTIONS */ + ewmh_update_actions(win); + + grabbuttons(win); - /* floaters need to be mapped if they are in the current workspace */ - if ((win->floating || win->transient) && (ws->idx == r->ws->idx)) - map_window_raised(win->id); + DNPRINTF(SWM_D_MISC, "manage_window: done. window: 0x%x, (x,y) w x h: " + "(%d,%d) %d x %d, ws: %d, iconic: %s, transient: 0x%x\n", win->id, + X(win), Y(win), WIDTH(win), HEIGHT(win), win->ws->idx, + YESNO(win->iconic), win->transient); return (win); } @@ -6954,14 +6982,13 @@ free_window(struct ws_win *win) memset(win, 0xff, sizeof *win); /* XXX kill later */ free(win); - DNPRINTF(SWM_D_MISC, "free_window: done\n"); + DNPRINTF(SWM_D_MISC, "free_window: done.\n"); } void unmanage_window(struct ws_win *win) { struct ws_win *parent; - xcb_screen_t *screen; if (win == NULL) return; @@ -6971,60 +6998,16 @@ unmanage_window(struct ws_win *win) if (win->transient) { parent = find_window(win->transient); if (parent) - parent->child_trans = NULL; + parent->focus_child = NULL; } - /* focus on root just in case */ - screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data; - xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, - screen->root, XCB_CURRENT_TIME); - - focus_prev(win); + focus_win(get_focus_prev(win)); TAILQ_REMOVE(&win->ws->winlist, win, entry); TAILQ_INSERT_TAIL(&win->ws->unmanagedlist, win, entry); } void -focus_magic(struct ws_win *win) -{ - DNPRINTF(SWM_D_FOCUS, "focus_magic: window: 0x%x\n", WINID(win)); - - if (win == NULL) { - /* if there are no windows clear the status-bar */ - bar_update(); - return; - } - - if (win->child_trans) { - /* win = parent & has a transient so focus on that */ - if (win->java) { - focus_win(win->child_trans); - if (win->child_trans->take_focus) - client_msg(win, a_takefocus); - } else { - /* make sure transient hasn't disappeared */ - if (validate_win(win->child_trans) == 0) { - focus_win(win->child_trans); - if (win->child_trans->take_focus) - client_msg(win->child_trans, - a_takefocus); - } else { - win->child_trans = NULL; - focus_win(win); - if (win->take_focus) - client_msg(win, a_takefocus); - } - } - } else { - /* regular focus */ - focus_win(win); - if (win->take_focus) - client_msg(win, a_takefocus); - } -} - -void expose(xcb_expose_event_t *e) { int i, num_screens; @@ -7049,6 +7032,14 @@ focusin(xcb_focus_in_event_t *e) "detail: %s(%u)\n", e->event, get_notify_mode_label(e->mode), e->mode, get_notify_detail_label(e->detail), e->detail); } + +void +focusout(xcb_focus_out_event_t *e) +{ + DNPRINTF(SWM_D_EVENT, "focusout: window: 0x%x, mode: %s(%u), " + "detail: %s(%u)\n", e->event, get_notify_mode_label(e->mode), + e->mode, get_notify_detail_label(e->detail), e->detail); +} #endif void @@ -7064,6 +7055,8 @@ keypress(xcb_key_press_event_t *e) if ((kp = key_lookup(CLEANMASK(e->state), keysym)) == NULL) return; + last_event_time = e->time; + if (kp->funcid == KF_SPAWN_CUSTOM) spawn_custom(root_to_region(e->root), &(keyfuncs[kp->funcid].args), kp->spawn_name); @@ -7077,7 +7070,7 @@ buttonpress(xcb_button_press_event_t *e) { struct ws_win *win; int i; - unsigned int action; + int handled = 0; DNPRINTF(SWM_D_EVENT, "buttonpress: window 0x%x, detail: %u\n", e->event, e->detail); @@ -7085,14 +7078,24 @@ buttonpress(xcb_button_press_event_t *e) if ((win = find_window(e->event)) == NULL) return; - focus_magic(win); - action = client_click; + last_event_time = e->time; + + focus_win(get_focus_magic(win)); for (i = 0; i < LENGTH(buttons); i++) - if (action == buttons[i].action && buttons[i].func && + if (client_click == buttons[i].action && buttons[i].func && buttons[i].button == e->detail && - CLEANMASK(buttons[i].mask) == CLEANMASK(e->state)) + CLEANMASK(buttons[i].mask) == CLEANMASK(e->state)) { buttons[i].func(win, &buttons[i].args); + handled = 1; + } + + if (!handled) { + DNPRINTF(SWM_D_EVENT, "buttonpress: passing to window.\n"); + xcb_allow_events(conn, XCB_ALLOW_REPLAY_POINTER, e->time); + } else { + DNPRINTF(SWM_D_EVENT, "buttonpress: handled.\n"); + } xcb_flush(conn); } @@ -7120,10 +7123,41 @@ print_win_geom(xcb_window_t w) } #endif +#ifdef SWM_DEBUG +char * +get_stack_mode_name(uint8_t mode) +{ + char *name; + + switch(mode) { + case XCB_STACK_MODE_ABOVE: + name = "Above"; + break; + case XCB_STACK_MODE_BELOW: + name = "Below"; + break; + case XCB_STACK_MODE_TOP_IF: + name = "TopIf"; + break; + case XCB_STACK_MODE_BOTTOM_IF: + name = "BottomIf"; + break; + case XCB_STACK_MODE_OPPOSITE: + name = "Opposite"; + break; + default: + name = "Unknown"; + } + + return name; +} +#endif + void configurerequest(xcb_configure_request_event_t *e) { struct ws_win *win; + struct swm_region *r = NULL; int new = 0, i = 0; uint16_t mask = 0; uint32_t wc[7] = {0}; @@ -7131,82 +7165,110 @@ configurerequest(xcb_configure_request_event_t *e) if ((win = find_window(e->window)) == NULL) if ((win = find_unmanaged_window(e->window)) == NULL) new = 1; + #ifdef SWM_DEBUG - print_win_geom(e->window); + if (swm_debug & SWM_D_EVENT) { + print_win_geom(e->window); + + DNPRINTF(SWM_D_EVENT, "configurerequest: window: 0x%x, " + "parent: 0x%x, new: %s, value_mask: %u { ", e->window, + e->parent, YESNO(new), e->value_mask); + if (e->value_mask & XCB_CONFIG_WINDOW_X) + DPRINTF("X: %d ", e->x); + if (e->value_mask & XCB_CONFIG_WINDOW_Y) + DPRINTF("Y: %d ", e->y); + if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) + DPRINTF("W: %u ", e->width); + if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) + DPRINTF("H: %u ", e->height); + if (e->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH) + DPRINTF("Border: %u ", e->border_width); + if (e->value_mask & XCB_CONFIG_WINDOW_SIBLING) + DPRINTF("Sibling: 0x%x ", e->sibling); + if (e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE) + DPRINTF("StackMode: %s(%u) ", + get_stack_mode_name(e->stack_mode), e->stack_mode); + DPRINTF("}\n"); + } #endif + if (new) { - DNPRINTF(SWM_D_EVENT, "configurerequest: new window: 0x%x, " - "value_mask: 0x%x", e->window, e->value_mask); if (e->value_mask & XCB_CONFIG_WINDOW_X) { mask |= XCB_CONFIG_WINDOW_X; wc[i++] = e->x; - DPRINTF(", X: %d", e->x); } if (e->value_mask & XCB_CONFIG_WINDOW_Y) { mask |= XCB_CONFIG_WINDOW_Y; wc[i++] = e->y; - DPRINTF(", Y: %d", e->y); } if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) { mask |= XCB_CONFIG_WINDOW_WIDTH; wc[i++] = e->width; - DPRINTF(", W: %u", e->width); } if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) { mask |= XCB_CONFIG_WINDOW_HEIGHT; wc[i++] = e->height; - DPRINTF(", H: %u", e->height); } if (e->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH) { mask |= XCB_CONFIG_WINDOW_BORDER_WIDTH; wc[i++] = e->border_width; - DPRINTF(", Border: %u", e->border_width); } if (e->value_mask & XCB_CONFIG_WINDOW_SIBLING) { mask |= XCB_CONFIG_WINDOW_SIBLING; wc[i++] = e->sibling; - DPRINTF(", Sibling: 0x%x", e->sibling); } if (e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE) { mask |= XCB_CONFIG_WINDOW_STACK_MODE; wc[i++] = e->stack_mode; - DPRINTF(", StackMode: %u", e->stack_mode); } if (mask != 0) xcb_configure_window(conn, e->window, mask, wc); - - DPRINTF(", Sent: %s\n", YESNO((mask != 0))); } else if ((!win->manual || win->quirks & SWM_Q_ANYWHERE) && !(win->ewmh_flags & EWMH_F_FULLSCREEN)) { - win->g_float.x = e->x; - win->g_float.y = e->y; - if (win->ws->r) { - win->g_float.x -= X(win->ws->r); - win->g_float.y -= Y(win->ws->r); - } else if (win->ws->old_r) { - win->g_float.x -= X(win->ws->old_r); - win->g_float.y -= Y(win->ws->old_r); + if (win->ws->r) + r = win->ws->r; + else if (win->ws->old_r) + r = win->ws->old_r; + + /* windows are centered unless ANYWHERE quirk is set. */ + if (win->quirks & SWM_Q_ANYWHERE) { + if (e->value_mask & XCB_CONFIG_WINDOW_X) { + win->g_float.x = e->x; + if (r) + win->g_float.x -= X(r); + } + + if (e->value_mask & XCB_CONFIG_WINDOW_Y) { + win->g_float.y = e->y; + if (r) + win->g_float.y -= Y(r); + } } - win->g_float.w = e->width; - win->g_float.h = e->height; + if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) + win->g_float.w = e->width; + + if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) + win->g_float.h = e->height; + win->g_floatvalid = 1; - if (win->floating) { - win->g.x = e->x; - win->g.y = e->y; - win->g.w = e->width; - win->g.h = e->height; - update_window(win); + if (win->floating && r) { + WIDTH(win) = win->g_float.w; + HEIGHT(win) = win->g_float.h; + + stack_floater(win, win->ws->r); + + focus_flush(); } else { config_win(win, e); + xcb_flush(conn); } } else { config_win(win, e); + xcb_flush(conn); } - - xcb_flush(conn); } void @@ -7223,8 +7285,10 @@ configurenotify(xcb_configure_notify_event_t *e) xcb_icccm_get_wm_normal_hints(conn, win->id), &win->sh, NULL); adjust_font(win); - if (font_adjusted) + if (font_adjusted) { stack(); + xcb_flush(conn); + } } } @@ -7246,8 +7310,11 @@ destroynotify(xcb_destroy_notify_event_t *e) win->floating = 0; unmanage_window(win); - stack(); free_window(win); + + stack(); + + focus_flush(); } #ifdef SWM_DEBUG @@ -7318,33 +7385,30 @@ void enternotify(xcb_enter_notify_event_t *e) { struct ws_win *win; - DNPRINTF(SWM_D_FOCUS, "enternotify: window: 0x%x, mode: %s(%d), " - "detail: %s(%d), root: 0x%x, subwindow: 0x%x, same_screen_focus: " - "%s, state: %d\n", e->event, get_notify_mode_label(e->mode), - e->mode, get_notify_detail_label(e->detail), e->detail, e->root, - e->child, YESNO(e->same_screen_focus), e->state); - - if (e->mode != XCB_NOTIFY_MODE_NORMAL) { - DNPRINTF(SWM_D_EVENT, "skip enternotify: generated by " - "cursor grab.\n"); - return; - } - switch (focus_mode) { - case SWM_FOCUS_DEFAULT: - break; - case SWM_FOCUS_FOLLOW: - break; - case SWM_FOCUS_SYNERGY: - break; + DNPRINTF(SWM_D_FOCUS, "enternotify: time: %u, win (x,y): 0x%x " + "(%d,%d), mode: %s(%d), detail: %s(%d), root (x,y): 0x%x (%d,%d), " + "child: 0x%x, same_screen_focus: %s, state: %d\n", + e->time, e->event, e->event_x, e->event_y, + get_notify_mode_label(e->mode), e->mode, + get_notify_detail_label(e->detail), e->detail, + e->root, e->root_x, e->root_y, e->child, + YESNO(e->same_screen_focus), e->state); + + if (focus_mode == SWM_FOCUS_MANUAL && + e->mode == XCB_NOTIFY_MODE_NORMAL) { + DNPRINTF(SWM_D_EVENT, "enternotify: manual focus; ignoring.\n"); + return; } if ((win = find_window(e->event)) == NULL) { - DNPRINTF(SWM_D_EVENT, "skip enternotify: window is NULL\n"); + DNPRINTF(SWM_D_EVENT, "enternotify: window is NULL; ignoring\n"); return; } - focus_magic(win); + last_event_time = e->time; + + focus_win(get_focus_magic(win)); xcb_flush(conn); } @@ -7353,11 +7417,14 @@ enternotify(xcb_enter_notify_event_t *e) void leavenotify(xcb_leave_notify_event_t *e) { - DNPRINTF(SWM_D_FOCUS, "leavenotify: window: 0x%x, mode: %s(%d), " - "detail: %s(%d), root: 0x%x, subwindow: 0x%x, same_screen_focus: " - "%s, state: %d\n", e->event, get_notify_mode_label(e->mode), - e->mode, get_notify_detail_label(e->detail), e->detail, e->root, - e->child, YESNO(e->same_screen_focus), e->state); + DNPRINTF(SWM_D_FOCUS, "leavenotify: time: %u, win (x,y): 0x%x " + "(%d,%d), mode: %s(%d), detail: %s(%d), root (x,y): 0x%x (%d,%d), " + "child: 0x%x, same_screen_focus: %s, state: %d\n", + e->time, e->event, e->event_x, e->event_y, + get_notify_mode_label(e->mode), e->mode, + get_notify_detail_label(e->detail), e->detail, + e->root, e->root_x, e->root_y, e->child, + YESNO(e->same_screen_focus), e->state); } #endif @@ -7371,16 +7438,17 @@ mapnotify(xcb_map_notify_event_t *e) DNPRINTF(SWM_D_EVENT, "mapnotify: window: 0x%x\n", e->window); - win = manage_window(e->window); - if (win) - set_win_state(win, XCB_ICCCM_WM_STATE_NORMAL); + if ((win = find_window(e->window)) == NULL) + win = manage_window(e->window, 1); - /* - * focus_win can only set input focus on a mapped window. - * make sure the window really has focus since it is just being mapped. - */ + 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); + + xcb_flush(conn); } void @@ -7396,34 +7464,41 @@ void maprequest(xcb_map_request_event_t *e) { struct ws_win *win; - struct swm_region *r; xcb_get_window_attributes_reply_t *war; - DNPRINTF(SWM_D_EVENT, "maprequest: window: 0x%x\n", + DNPRINTF(SWM_D_EVENT, "maprequest: win 0x%x\n", e->window); war = xcb_get_window_attributes_reply(conn, xcb_get_window_attributes(conn, e->window), NULL); - if (!war) - return; - if (war->override_redirect) { - free(war); - return; + if (war == NULL) { + DNPRINTF(SWM_D_EVENT, "maprequest: window lost.\n"); + goto out; } - free(war); - win = manage_window(e->window); - if (win == NULL) { - return; /* can't happen */ + if (war->override_redirect) { + DNPRINTF(SWM_D_EVENT, "maprequest: override_redirect; " + "skipping.\n"); + goto out; } - stack(); + win = manage_window(e->window, + (war->map_state == XCB_MAP_STATE_VIEWABLE)); - /* make new win focused */ - r = root_to_region(win->wa->root); - if (win->ws == r->ws) - focus_magic(win); + /* All windows need to be mapped if they are in the current workspace.*/ + if (win->ws->r) + stack(); + + /* The new window should get focus. */ + win->ws->focus = get_focus_magic(win); + + /* Ignore EnterNotify to handle the mapnotify without interference. */ + if (focus_mode == SWM_FOCUS_DEFAULT) + event_drain(XCB_ENTER_NOTIFY); +out: + free(war); + DNPRINTF(SWM_D_EVENT, "maprequest: done.\n"); } #ifdef SWM_DEBUG @@ -7431,6 +7506,11 @@ char * get_atom_name(xcb_atom_t atom) { char *name = NULL; +#if 0 + /* + * This should be disabled during most debugging since + * xcb_get_* causes an xcb_flush. + */ size_t len; xcb_get_atom_name_reply_t *r; @@ -7448,7 +7528,9 @@ get_atom_name(xcb_atom_t atom) } free(r); } - +#else + (void)atom; +#endif return (name); } #endif @@ -7461,21 +7543,43 @@ propertynotify(xcb_property_notify_event_t *e) char *name; name = get_atom_name(e->atom); - DNPRINTF(SWM_D_EVENT, "propertynotify: window: 0x%x, atom: %s(%u)\n", - e->window, name, e->atom); + DNPRINTF(SWM_D_EVENT, "propertynotify: window: 0x%x, atom: %s(%u), " + "time: %#x\n", e->window, name, e->atom, e->time); free(name); #endif - win = find_window(e->window); if (win == NULL) return; - if (e->state == XCB_PROPERTY_DELETE && e->atom == a_swm_iconic) { - update_iconic(win, 0); - map_window_raised(win->id); - stack(); - focus_win(win); - return; + 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; + + unfocus_win(win); + unmap_window(win); + + if (win->ws->r) { + focus_win(get_focus_prev(win)); + stack(); + 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); } switch (e->atom) { @@ -7486,6 +7590,8 @@ propertynotify(xcb_property_notify_event_t *e) default: break; } + + xcb_flush(conn); } void @@ -7503,10 +7609,7 @@ unmapnotify(xcb_unmap_notify_event_t *e) if (getstate(e->window) == XCB_ICCCM_WM_STATE_NORMAL) { unmanage_window(win); stack(); - - /* resend unmap because we ated it */ - xcb_unmap_window(conn, e->window); - xcb_flush(conn); + focus_flush(); } } @@ -7551,7 +7654,7 @@ clientmessage(xcb_client_message_event_t *e) if (e->type == ewmh[_NET_CLOSE_WINDOW].atom) { DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_CLOSE_WINDOW\n"); if (win->can_delete) - client_msg(win, a_delete); + client_msg(win, a_delete, 0); else xcb_kill_client(conn, win->id); } @@ -7838,7 +7941,7 @@ grab_windows(void) xcb_window_t *wins = NULL; int no; int i, j, num_screens; - uint16_t state, manage; + uint16_t state, manage, mapped; xcb_query_tree_cookie_t qtc; xcb_query_tree_reply_t *qtr; @@ -7876,8 +7979,9 @@ grab_windows(void) state = getstate(wins[j]); manage = state == XCB_ICCCM_WM_STATE_ICONIC; - if (r->map_state == XCB_MAP_STATE_VIEWABLE || manage) - manage_window(wins[j]); + mapped = r->map_state != XCB_MAP_STATE_UNMAPPED; + if (mapped || manage) + manage_window(wins[j], mapped); free(r); } /* transient windows */ @@ -7894,14 +7998,15 @@ grab_windows(void) state = getstate(wins[j]); manage = state == XCB_ICCCM_WM_STATE_ICONIC; + mapped = r->map_state != XCB_MAP_STATE_UNMAPPED; pc = xcb_icccm_get_wm_transient_for(conn, wins[j]); if (xcb_icccm_get_wm_transient_for_reply(conn, pc, &wins[j], NULL) && manage) - manage_window(wins[j]); + manage_window(wins[j], mapped); } free(qtr); } - DNPRINTF(SWM_D_INIT, "grab_windows: done\n"); + DNPRINTF(SWM_D_INIT, "grab_windows: done.\n"); } void @@ -8033,7 +8138,6 @@ workaround(void) int i, num_screens; xcb_atom_t netwmcheck; xcb_window_t root, win; - uint32_t wa[2]; /* work around sun jdk bugs, code from wmname */ netwmcheck = get_atom_from_string("_NET_SUPPORTING_WM_CHECK"); @@ -8043,11 +8147,9 @@ workaround(void) root = screens[i].root; win = xcb_generate_id(conn); - wa[0] = screens[i].c[SWM_S_COLOR_UNFOCUS].pixel; - wa[1] = screens[i].c[SWM_S_COLOR_UNFOCUS].pixel; - xcb_create_window(conn, XCB_COPY_FROM_PARENT, win, 0, 0, 0, 1, - 1, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, - XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL, wa); + xcb_create_window(conn, XCB_COPY_FROM_PARENT, win, root, + 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, + XCB_COPY_FROM_PARENT, 0, NULL); xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, netwmcheck, XCB_ATOM_WINDOW, 32, 1, &win); @@ -8111,9 +8213,9 @@ event_handle(xcb_generic_event_t *evt) { uint8_t type = XCB_EVENT_RESPONSE_TYPE(evt); - DNPRINTF(SWM_D_EVENT, "XCB Event: %s(%d)\n", + DNPRINTF(SWM_D_EVENT, "XCB Event: %s(%d), seq %u\n", xcb_event_get_label(XCB_EVENT_RESPONSE_TYPE(evt)), - XCB_EVENT_RESPONSE_TYPE(evt)); + XCB_EVENT_RESPONSE_TYPE(evt), evt->sequence); switch (type) { #define EVENT(type, callback) case type: callback((void *)evt); return @@ -8132,8 +8234,8 @@ event_handle(xcb_generic_event_t *evt) EVENT(XCB_EXPOSE, expose); #ifdef SWM_DEBUG EVENT(XCB_FOCUS_IN, focusin); + EVENT(XCB_FOCUS_OUT, focusout); #endif - /*EVENT(XCB_FOCUS_OUT, );*/ /*EVENT(XCB_GRAPHICS_EXPOSURE, );*/ /*EVENT(XCB_GRAVITY_NOTIFY, );*/ EVENT(XCB_KEY_PRESS, keypress); @@ -8166,7 +8268,6 @@ main(int argc, char *argv[]) { struct swm_region *r, *rr; struct ws_win *winfocus = NULL; - union arg a; char conf[PATH_MAX], *cfile = NULL; struct stat sb; int xfd, i, num_screens; @@ -8295,8 +8396,6 @@ noconfig: bar_setup(r); } - //unfocus_all(); - grabkeys(); stack(); @@ -8325,8 +8424,8 @@ noconfig: rr->s[0].root, 0, 0, 0, 0, X(rr), Y(rr) + (bar_enabled ? bar_height : 0)); - a.id = SWM_ARG_ID_FOCUSCUR; - focus(rr, &a); + focus_win(get_region_focus(rr)); + focus_flush(); winfocus = NULL; continue; }