X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=spectrwm.c;h=eff0c5d301e83b4302ca7b102563cc9fe0b7d4c6;hb=f9609966f0d40cccd8e67ce5d871f1eab55b676a;hp=75b833f17cc54f01676e40d0b4b75d3e9309722a;hpb=36e10e1dfb7db4bd6190be8990df27e08ceecb36;p=spectrwm.git diff --git a/spectrwm.c b/spectrwm.c index 75b833f..eff0c5d 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -249,6 +249,12 @@ u_int32_t swm_debug = 0 #define SWM_FOCUS_FOLLOW (1) #define SWM_FOCUS_MANUAL (2) +#define SWM_CK_NONE 0 +#define SWM_CK_ALL 0x7 +#define SWM_CK_FOCUS 0x1 +#define SWM_CK_POINTER 0x2 +#define SWM_CK_FALLBACK 0x4 + #define SWM_CONF_DEFAULT (0) #define SWM_CONF_KEYMAPPING (1) @@ -697,6 +703,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_pointer_win(xcb_window_t); struct ws_win *get_region_focus(struct swm_region *); xcb_screen_t *get_screen(int); char *get_win_name(xcb_window_t); @@ -2443,8 +2450,30 @@ restart(struct swm_region *r, union arg *args) quit(NULL, NULL); } +struct ws_win * +get_pointer_win(xcb_window_t root) +{ + struct ws_win *win = NULL; + xcb_query_pointer_reply_t *r; + + DNPRINTF(SWM_D_EVENT, "get_pointer_win: root: 0x%x.\n", root); + + r = xcb_query_pointer_reply(conn, xcb_query_pointer(conn, root), NULL); + if (r) { + win = find_window(r->child); + if (win) { + DNPRINTF(SWM_D_EVENT, "get_pointer_win: 0x%x.\n", + win->id); + } else { + DNPRINTF(SWM_D_EVENT, "get_pointer_win: none.\n"); + } + } + + return win; +} + struct swm_region * -root_to_region(xcb_window_t root) +root_to_region(xcb_window_t root, int check) { struct ws_win *cfw; struct swm_region *r = NULL; @@ -2459,34 +2488,39 @@ root_to_region(xcb_window_t root) if (screens[i].root == root) break; - /* 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 (check & SWM_CK_FOCUS) { + /* 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; - free(gifr); + free(gifr); + } } - if (r == NULL) { + if (r == NULL && check & SWM_CK_POINTER) { /* 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); + 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)) + 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) + if (r == NULL && check & SWM_CK_FALLBACK) r = TAILQ_FIRST(&screens[i].rl); return (r); @@ -2888,18 +2922,26 @@ switchws(struct swm_region *r, union arg *args) TAILQ_FOREACH(win, &old_ws->winlist, entry) unmap_window(win); - if (focus_mode != SWM_FOCUS_FOLLOW) + if (focus_mode != SWM_FOCUS_FOLLOW) { new_ws->focus_pending = get_region_focus(new_ws->r); - if (new_ws->focus_pending && focus_mode != SWM_FOCUS_FOLLOW) { /* if workspaces were swapped, then don't wait to set focus */ - if (old_ws->r) - focus_win(new_ws->focus_pending); - } else { - /* make sure bar gets updated if ws is empty */ - bar_update(); + if (old_ws->r) { + if (new_ws->focus_pending) { + focus_win(new_ws->focus_pending); + } else { + /* Empty region, focus on root. */ + xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT, + new_ws->r->s[new_ws->r->s->idx].root, + XCB_CURRENT_TIME); + } + } } + /* Clear bar if new ws is empty. */ + if (new_ws->focus_pending == NULL) + bar_update(); + focus_flush(); DNPRINTF(SWM_D_WS, "switchws: done.\n"); @@ -2970,6 +3012,7 @@ priorws(struct swm_region *r, union arg *args) void cyclescr(struct swm_region *r, union arg *args) { + struct ws_win *nfw; struct swm_region *rr = NULL; int i, num_screens; @@ -2996,7 +3039,18 @@ cyclescr(struct swm_region *r, union arg *args) if (rr == NULL) return; - focus_win(get_region_focus(rr)); + nfw = get_region_focus(rr); + if (nfw) { + focus_win(nfw); + } else { + /* New region is empty; unfocus old region and warp pointer. */ + unfocus_win(r->ws->focus); + xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT, + rr->s[i].root, XCB_CURRENT_TIME); + + /* Clear bar since empty. */ + bar_update(); + } focus_flush(); } @@ -4474,7 +4528,7 @@ wkill(struct swm_region *r, union arg *args) if (r->ws->focus->can_delete) client_msg(r->ws->focus, a_delete, 0); - xcb_flush(conn); + focus_flush(); } int @@ -5906,11 +5960,6 @@ grabbuttons(struct ws_win *win) 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[] = { @@ -6676,7 +6725,7 @@ set_child_transient(struct ws_win *win, xcb_window_t *trans) DNPRINTF(SWM_D_MISC, "set_child_transient: parent doesn't exist" " for 0x%x trans 0x%x\n", win->id, win->transient); - r = root_to_region(win->wa->root); + r = root_to_region(win->wa->root, SWM_CK_ALL); ws = r->ws; /* parent doen't exist in our window list */ TAILQ_FOREACH(w, &ws->winlist, entry) { @@ -6834,7 +6883,7 @@ manage_window(xcb_window_t id, uint16_t mapped) NULL); /* Figure out which region the window belongs to. */ - r = root_to_region(win->wa->root); + r = root_to_region(win->wa->root, SWM_CK_ALL); /* Ignore window border if there is one. */ WIDTH(win) = win->wa->width; @@ -7098,10 +7147,10 @@ keypress(xcb_key_press_event_t *e) last_event_time = e->time; if (kp->funcid == KF_SPAWN_CUSTOM) - spawn_custom(root_to_region(e->root), + spawn_custom(root_to_region(e->root, SWM_CK_ALL), &(keyfuncs[kp->funcid].args), kp->spawn_name); else if (keyfuncs[kp->funcid].func) - keyfuncs[kp->funcid].func(root_to_region(e->root), + keyfuncs[kp->funcid].func(root_to_region(e->root, SWM_CK_ALL), &(keyfuncs[kp->funcid].args)); } @@ -7109,13 +7158,46 @@ void buttonpress(xcb_button_press_event_t *e) { struct ws_win *win; + struct swm_region *r, *old_r; int i; int handled = 0; - DNPRINTF(SWM_D_EVENT, "buttonpress: window 0x%x, detail: %u\n", - e->event, e->detail); + DNPRINTF(SWM_D_EVENT, "buttonpress: win (x,y): 0x%x (%d,%d), " + "detail: %u, time: %u, root (x,y): 0x%x (%d,%d), child: 0x%x, " + "state: %u, same_screen: %s\n", e->event, e->event_x, e->event_y, + e->detail, e->time, e->root, e->root_x, e->root_y, e->child, + e->state, YESNO(e->same_screen)); + + if (e->event == e->root) { + if (e->child != 0) { + win = find_window(e->child); + /* Pass ButtonPress to window if it isn't managed. */ + if (win == NULL) + goto out; + } else { + /* Focus on empty region */ + /* If no windows on region if its empty. */ + r = root_to_region(e->root, SWM_CK_POINTER); + if (TAILQ_EMPTY(&r->ws->winlist)) { + old_r = root_to_region(e->root, SWM_CK_FOCUS); + if (old_r && old_r != r) + unfocus_win(old_r->ws->focus); + + xcb_set_input_focus(conn, + XCB_INPUT_FOCUS_PARENT, e->root, e->time); + + /* Clear bar since empty. */ + bar_update(); + + handled = 1; + goto out; + } + } + } else { + win = find_window(e->event); + } - if ((win = find_window(e->event)) == NULL) + if (win == NULL) return; last_event_time = e->time; @@ -7130,11 +7212,15 @@ buttonpress(xcb_button_press_event_t *e) handled = 1; } +out: if (!handled) { DNPRINTF(SWM_D_EVENT, "buttonpress: passing to window.\n"); + /* Replay event to event window */ xcb_allow_events(conn, XCB_ALLOW_REPLAY_POINTER, e->time); } else { DNPRINTF(SWM_D_EVENT, "buttonpress: handled.\n"); + /* Unfreeze grab events. */ + xcb_allow_events(conn, XCB_ALLOW_SYNC_POINTER, e->time); } xcb_flush(conn); @@ -7262,8 +7348,10 @@ configurerequest(xcb_configure_request_event_t *e) wc[i++] = e->stack_mode; } - if (mask != 0) + if (mask != 0) { xcb_configure_window(conn, e->window, mask, wc); + xcb_flush(conn); + } } else if ((!win->manual || win->quirks & SWM_Q_ANYWHERE) && !(win->ewmh_flags & EWMH_F_FULLSCREEN)) { if (win->ws->r) @@ -7438,6 +7526,7 @@ void enternotify(xcb_enter_notify_event_t *e) { struct ws_win *win; + struct swm_region *old_r, *r; 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), " @@ -7454,13 +7543,32 @@ enternotify(xcb_enter_notify_event_t *e) return; } + last_event_time = e->time; + if ((win = find_window(e->event)) == NULL) { - DNPRINTF(SWM_D_EVENT, "enternotify: window is NULL; ignoring\n"); + if (e->event == e->root) { + /* If no windows on pointer region, then focus root. */ + r = root_to_region(e->root, SWM_CK_POINTER); + if (TAILQ_EMPTY(&r->ws->winlist)) { + old_r = root_to_region(e->root, SWM_CK_FOCUS); + if (old_r && old_r != r) + unfocus_win(old_r->ws->focus); + + xcb_set_input_focus(conn, + XCB_INPUT_FOCUS_PARENT, e->root, e->time); + + /* Clear bar since empty. */ + bar_update(); + + focus_flush(); + } + } else { + DNPRINTF(SWM_D_EVENT, "enternotify: window is NULL; " + "ignoring\n"); + } return; } - last_event_time = e->time; - focus_win(get_focus_magic(win)); xcb_flush(conn); @@ -7668,10 +7776,10 @@ unmapnotify(xcb_unmap_notify_event_t *e) if (win == NULL) return; + win->mapped = 0; 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. */ @@ -7694,6 +7802,9 @@ unmapnotify(xcb_unmap_notify_event_t *e) } focus_flush(); + } else if (focus_mode == SWM_FOCUS_FOLLOW) { + if (ws->r) + focus_win(get_pointer_win(ws->r->s->root)); } } @@ -7813,7 +7924,8 @@ int enable_wm(void) { int num_screens, i; - const uint32_t val = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT; + const uint32_t val = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | + XCB_EVENT_MASK_ENTER_WINDOW; xcb_screen_t *sc; xcb_void_cookie_t wac; xcb_generic_error_t *error; @@ -7833,6 +7945,11 @@ enable_wm(void) free(error); return 1; } + + /* click to focus on empty region */ + xcb_grab_button(conn, 1, sc->root, BUTTONMASK, + XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, XCB_WINDOW_NONE, + XCB_CURSOR_NONE, XCB_BUTTON_INDEX_1, XCB_BUTTON_MASK_ANY); } return 0; @@ -8504,11 +8621,6 @@ noconfig: winfocus = NULL; continue; } - /* move pointer to first screen if multi screen */ - if (num_screens > 1 || outputs > 1) - xcb_warp_pointer(conn, XCB_WINDOW_NONE, - rr->s[0].root, 0, 0, 0, 0, X(rr), - Y(rr) + (bar_enabled ? bar_height : 0)); focus_win(get_region_focus(rr)); focus_flush();