X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=spectrwm.c;h=06b73c0b9a1ef2b9f6e5a3a6d35c215a62b6a09c;hb=4c59fde083056c15e80b6b9e9ceb89e09598293d;hp=b33b88df499db3906abe6d3a34d31158bd7d1632;hpb=6f1236b9179b93ec6df7fcd04a6b934d8abb081c;p=spectrwm.git diff --git a/spectrwm.c b/spectrwm.c index b33b88d..06b73c0 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -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; @@ -418,6 +419,7 @@ struct ws_win { 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) @@ -683,7 +684,8 @@ struct ws_win *find_window(xcb_window_t); int floating_toggle_win(struct ws_win *); void focus(struct swm_region *, union arg *); void focus_flush(void); -struct ws_win *focus_magic(struct ws_win *); +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 *); @@ -694,6 +696,7 @@ 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); @@ -703,7 +706,8 @@ void keypress(xcb_key_press_event_t *); void leavenotify(xcb_leave_notify_event_t *); #endif void load_float_geom(struct ws_win *, struct swm_region *); -void map_window_raised(xcb_window_t); +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 *); @@ -716,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 *);*/ @@ -805,17 +810,6 @@ focus_flush(void) xcb_flush(conn); } -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); -} - xcb_atom_t get_atom_from_string(const char *str) { @@ -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; @@ -1906,7 +1900,7 @@ 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; @@ -2125,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), @@ -2201,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; @@ -2214,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); @@ -2333,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 @@ -2633,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; } @@ -2663,104 +2694,92 @@ unfocus_win(struct ws_win *win) 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; DNPRINTF(SWM_D_FOCUS, "focus_win: window: 0x%x\n", WINID(win)); - if (win == NULL) { - /* Clear the status-bar. */ - bar_update(); - return; - } + if (win == NULL) + goto out; if (win->ws == NULL) - return; + goto out; if (validate_ws(win->ws)) - 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) { cfw = find_window(r->focus); + if (cfw != win) + unfocus_win(cfw); free(r); } if (win->ws->focus != win) { - unfocus_win(win->ws->focus); + if (win->ws->focus && win->ws->focus != cfw) + unfocus_win(win->ws->focus); win->ws->focus = win; } - /* Tell app it can set focus. */ - if (win->take_focus) { - /* java is special; always tell parent */ - if (win->transient && win->java) - client_msg(find_window(win->transient), a_takefocus); - else - client_msg(win, a_takefocus); - } - - if (cfw != win) { - if (cfw) - unfocus_win(cfw); - - if (win->ws->r != NULL) { - if (win->java == 0) - xcb_set_input_focus(conn, - XCB_INPUT_FOCUS_PARENT, win->id, - XCB_CURRENT_TIME); + 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, 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); + 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); + if (win->ws->cur_layout->flags & SWM_L_MAPONFOCUS || + win->ws->always_raise) + 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); - } + 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 * -focus_magic(struct ws_win *win) +get_focus_magic(struct ws_win *win) { struct ws_win *parent = NULL; - DNPRINTF(SWM_D_FOCUS, "focus_magic: window: 0x%x\n", WINID(win)); + DNPRINTF(SWM_D_FOCUS, "get_focus_magic: window: 0x%x\n", WINID(win)); if (win == NULL) return win; @@ -2809,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; @@ -2844,21 +2862,22 @@ 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(); - stack(); - a.id = SWM_ARG_ID_FOCUSCUR; - focus(new_ws->r, &a); + + 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(); + focus_flush(); - DNPRINTF(SWM_D_WS, "switchws: done\n"); + DNPRINTF(SWM_D_WS, "switchws: done.\n"); } void @@ -2927,7 +2946,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)); @@ -2959,8 +2977,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 */ @@ -2969,6 +2986,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 @@ -3069,8 +3088,8 @@ swapwin(struct swm_region *r, union arg *args) 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; @@ -3078,13 +3097,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 */ @@ -3113,7 +3132,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) { @@ -3152,14 +3171,34 @@ done: } kill_refs(win); - focus_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; @@ -3169,21 +3208,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_win(focus_magic(winfocus)); - return; - } - if ((cur_focus = r->ws->focus) == NULL) return; ws = r->ws; @@ -3254,7 +3278,7 @@ focus(struct swm_region *r, union arg *args) return; } - focus_win(focus_magic(winfocus)); + focus_win(get_focus_magic(winfocus)); xcb_flush(conn); } @@ -3263,7 +3287,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; @@ -3277,8 +3300,7 @@ cycle_layout(struct swm_region *r, union arg *args) stack(); bar_update(); - a.id = SWM_ARG_ID_FOCUSCUR; - focus(r, &a); + focus_win(get_region_focus(r)); focus_flush(); } @@ -3297,6 +3319,8 @@ stack_config(struct swm_region *r, union arg *args) if (args->id != SWM_ARG_ID_STACKINIT) stack(); bar_update(); + + focus_flush(); } void @@ -3492,7 +3516,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)); @@ -3655,14 +3678,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++; @@ -3682,12 +3698,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); } } @@ -3849,9 +3865,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_win(focus_magic(wintrans)); + ws->focus = get_focus_magic(wintrans); } } @@ -3947,22 +3963,15 @@ raise_toggle(struct swm_region *r, union arg *args) 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); - focus_flush(); + xcb_flush(conn); } char * @@ -4044,8 +4053,6 @@ uniconify(struct swm_region *r, union arg *args) } fclose(lfile); - - xcb_flush(conn); } void @@ -4180,7 +4187,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); @@ -4244,6 +4251,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; } @@ -4396,6 +4404,8 @@ done: search_resp_action = SWM_SEARCH_NONE; close(select_resp_pipe[0]); free(resp); + + xcb_flush(conn); } void @@ -4410,7 +4420,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); } @@ -4453,7 +4463,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; @@ -4469,10 +4478,8 @@ floating_toggle(struct swm_region *r, union arg *args) 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); focus_flush(); } @@ -4720,7 +4727,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 @@ -4863,7 +4870,7 @@ move(struct ws_win *win, union arg *args) 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 @@ -5116,9 +5123,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 }; @@ -5397,7 +5404,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); } @@ -5823,7 +5830,7 @@ 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, @@ -5831,6 +5838,7 @@ grabkeys(void) *code, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); free(code); + } } } } @@ -5838,26 +5846,21 @@ grabkeys(void) void grabbuttons(struct ws_win *win) { -#if 0 int i; -#endif DNPRINTF(SWM_D_MOUSE, "grabbuttons: win 0x%x\n", win->id); -#if 0 - xcb_ungrab_button(conn, XCB_BUTTON_INDEX_ANY, win->id, - XCB_BUTTON_MASK_ANY); - 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); -#endif + + /* 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_ANY, XCB_BUTTON_MASK_ANY); + XCB_BUTTON_INDEX_1, XCB_BUTTON_MASK_ANY); } const char *quirkname[] = { @@ -6736,7 +6739,7 @@ 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 ws_win *win, *ww; @@ -6789,6 +6792,7 @@ manage_window(xcb_window_t id) X(win) = win->wa->x + win->wa->border_width; Y(win) = win->wa->y + win->wa->border_width; win->bordered = 0; + win->mapped = mapped; win->floatmaxed = 0; win->ewmh_flags = 0; win->s = r->s; /* this never changes */ @@ -6827,7 +6831,7 @@ 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 which workspace the window belongs to. */ if ((p = find_pid(window_get_pid(win->id))) != NULL) { @@ -6982,14 +6986,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; @@ -7002,12 +7005,7 @@ unmanage_window(struct ws_win *win) 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); @@ -7038,6 +7036,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 @@ -7053,6 +7059,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); @@ -7074,7 +7082,9 @@ buttonpress(xcb_button_press_event_t *e) if ((win = find_window(e->event)) == NULL) return; - focus_win(focus_magic(win)); + last_event_time = e->time; + + focus_win(get_focus_magic(win)); for (i = 0; i < LENGTH(buttons); i++) if (client_click == buttons[i].action && buttons[i].func && @@ -7085,8 +7095,10 @@ buttonpress(xcb_button_press_event_t *e) } if (!handled) { - DNPRINTF(SWM_D_EVENT, "buttonpress: passing to window\n"); + 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); @@ -7378,11 +7390,14 @@ 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); + 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) { @@ -7395,7 +7410,9 @@ enternotify(xcb_enter_notify_event_t *e) return; } - focus_win(focus_magic(win)); + last_event_time = e->time; + + focus_win(get_focus_magic(win)); xcb_flush(conn); } @@ -7404,11 +7421,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 @@ -7423,13 +7443,16 @@ mapnotify(xcb_map_notify_event_t *e) DNPRINTF(SWM_D_EVENT, "mapnotify: window: 0x%x\n", e->window); if ((win = find_window(e->window)) == NULL) - win = manage_window(e->window); + win = manage_window(e->window, 1); + 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 @@ -7464,14 +7487,15 @@ maprequest(xcb_map_request_event_t *e) goto out; } - win = manage_window(e->window); + win = manage_window(e->window, + (war->map_state == XCB_MAP_STATE_VIEWABLE)); /* 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 = focus_magic(win); + win->ws->focus = get_focus_magic(win); /* Ignore EnterNotify to handle the mapnotify without interference. */ if (focus_mode == SWM_FOCUS_DEFAULT) @@ -7523,22 +7547,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 - xcb_flush(conn); - 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) { @@ -7549,6 +7594,8 @@ propertynotify(xcb_property_notify_event_t *e) default: break; } + + xcb_flush(conn); } void @@ -7566,10 +7613,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(); } } @@ -7614,7 +7658,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); } @@ -7901,7 +7945,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; @@ -7939,8 +7983,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 */ @@ -7957,14 +8002,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 @@ -8171,9 +8217,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 @@ -8192,8 +8238,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); @@ -8226,7 +8272,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; @@ -8355,8 +8400,6 @@ noconfig: bar_setup(r); } - //unfocus_all(); - grabkeys(); stack(); @@ -8385,8 +8428,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; }