X-Git-Url: https://code.delx.au/spectrwm/blobdiff_plain/638428ac079bad32d3e9150f90450bc71397135c..46020d87811d1d3ec05035cd44db5fcd7c2bcd2b:/spectrwm.c diff --git a/spectrwm.c b/spectrwm.c index 478a6f2..b01ed60 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -77,6 +77,7 @@ #include #include #include +#include #include #include #include @@ -402,6 +403,7 @@ bool stack_enabled = true; bool clock_enabled = true; bool iconic_enabled = false; bool urgent_enabled = false; +bool urgent_collapse = false; char *clock_format = NULL; bool window_class_enabled = false; bool window_instance_enabled = false; @@ -1040,6 +1042,7 @@ char *get_source_type_label(uint32_t); char *get_stack_mode_name(uint8_t); #endif int32_t get_swm_ws(xcb_window_t); +bool get_urgent(struct ws_win *); char *get_win_name(xcb_window_t); uint8_t get_win_state(xcb_window_t); void get_wm_protocols(struct ws_win *); @@ -1062,6 +1065,7 @@ void kill_refs(struct ws_win *); void leavenotify(xcb_leave_notify_event_t *); #endif void load_float_geom(struct ws_win *); +void lower_window(struct ws_win *); struct ws_win *manage_window(xcb_window_t, int, bool); void map_window(struct ws_win *); void mapnotify(xcb_map_notify_event_t *); @@ -2167,6 +2171,22 @@ bar_window_name(char *s, size_t sz, struct swm_region *r) free(title); } +bool +get_urgent(struct ws_win *win) +{ + xcb_icccm_wm_hints_t hints; + xcb_get_property_cookie_t c; + bool urgent = false; + + if (win) { + c = xcb_icccm_get_wm_hints(conn, win->id); + if (xcb_icccm_get_wm_hints_reply(conn, c, &hints, NULL)) + urgent = xcb_icccm_wm_hints_get_urgency(&hints); + } + + return urgent; +} + void bar_urgent(char *s, size_t sz) { @@ -2174,8 +2194,6 @@ bar_urgent(char *s, size_t sz) int i, j, num_screens; bool urgent[SWM_WS_MAX]; char b[8]; - xcb_get_property_cookie_t c; - xcb_icccm_wm_hints_t hints; for (i = 0; i < workspace_limit; i++) urgent[i] = false; @@ -2183,21 +2201,17 @@ bar_urgent(char *s, size_t sz) num_screens = get_screen_count(); for (i = 0; i < num_screens; i++) for (j = 0; j < workspace_limit; j++) - TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) { - c = xcb_icccm_get_wm_hints(conn, win->id); - if (xcb_icccm_get_wm_hints_reply(conn, c, - &hints, NULL) == 0) - continue; - if (hints.flags & XCB_ICCCM_WM_HINT_X_URGENCY) + TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) + if (get_urgent(win)) urgent[j] = true; - } for (i = 0; i < workspace_limit; i++) { - if (urgent[i]) + if (urgent[i]) { snprintf(b, sizeof b, "%d ", i + 1); - else - snprintf(b, sizeof b, "- "); - strlcat(s, b, sz); + strlcat(s, b, sz); + } else if (!urgent_collapse) { + strlcat(s, "- ", sz); + } } } @@ -3004,14 +3018,74 @@ quit(struct swm_region *r, union arg *args) running = 0; } +void +lower_window(struct ws_win *win) +{ + struct ws_win *target = NULL; + struct workspace *ws; + + if (win == NULL) + return; + + ws = win->ws; + + DNPRINTF(SWM_D_EVENT, "lower_window: win %#x\n", win->id); + + TAILQ_FOREACH(target, &ws->stack, stack_entry) { + if (target == win || ICONIC(target)) + continue; + if (ws->cur_layout == &layouts[SWM_MAX_STACK]) + break; + if (TRANS(win)) { + if (win->transient == target->transient) + continue; + if (win->transient == target->id) + break; + } + if (FULLSCREEN(target)) + continue; + if (FULLSCREEN(win)) + break; + if (MAXIMIZED(target)) + continue; + if (MAXIMIZED(win)) + break; + if (ABOVE(target) || TRANS(target)) + continue; + if (ABOVE(win) || TRANS(win)) + break; + } + + /* Change stack position. */ + TAILQ_REMOVE(&ws->stack, win, stack_entry); + if (target) + TAILQ_INSERT_BEFORE(target, win, stack_entry); + else + TAILQ_INSERT_TAIL(&ws->stack, win, stack_entry); + + update_win_stacking(win); + +#ifdef SWM_DEBUG + if (swm_debug & SWM_D_STACK) { + DPRINTF("=== stacking order (top down) === \n"); + TAILQ_FOREACH(target, &ws->stack, stack_entry) { + DPRINTF("win %#x, fs: %s, maximized: %s, above: %s, " + "iconic: %s\n", target->id, YESNO(FULLSCREEN(target)), + YESNO(MAXIMIZED(target)), YESNO(ABOVE(target)), + YESNO(ICONIC(target))); + } + } +#endif + DNPRINTF(SWM_D_EVENT, "lower_window: done\n"); +} + void raise_window(struct ws_win *win) { struct ws_win *target = NULL; - struct swm_region *r; struct workspace *ws; - if (win == NULL || (r = win->ws->r) == NULL) + if (win == NULL) return; ws = win->ws; @@ -3033,23 +3107,25 @@ raise_window(struct ws_win *win) break; if (MAXIMIZED(target)) continue; - if (ABOVE(win) || TRANS(win)) + if (ABOVE(win) || TRANS(win) || + (win->ws->focus == win && ws->always_raise)) break; if (!ABOVE(target) && !TRANS(target)) break; } - if (target != NULL) { - /* Change stack position. */ - TAILQ_REMOVE(&ws->stack, win, stack_entry); + TAILQ_REMOVE(&ws->stack, win, stack_entry); + if (target) TAILQ_INSERT_BEFORE(target, win, stack_entry); - update_win_stacking(win); - } + else + TAILQ_INSERT_TAIL(&ws->stack, win, stack_entry); + + update_win_stacking(win); #ifdef SWM_DEBUG if (swm_debug & SWM_D_STACK) { DPRINTF("=== stacking order (top down) === \n"); - TAILQ_FOREACH(target, &r->ws->stack, stack_entry) { + TAILQ_FOREACH(target, &ws->stack, stack_entry) { DPRINTF("win %#x, fs: %s, maximized: %s, above: %s, " "iconic: %s\n", target->id, YESNO(FULLSCREEN(target)), YESNO(MAXIMIZED(target)), YESNO(ABOVE(target)), @@ -3071,10 +3147,14 @@ update_win_stacking(struct ws_win *win) return; sibling = TAILQ_NEXT(win, stack_entry); - if (sibling != NULL && FLOATING(win) == FLOATING(sibling)) + if (sibling != NULL && (FLOATING(win) == FLOATING(sibling) || + (win->ws->always_raise && win->ws->focus == win))) val[0] = sibling->id; + else if (FLOATING(win) || (win->ws->always_raise && + win->ws->focus == win)) + val[0] = r->bar->id; else - val[0] = FLOATING(win) ? r->bar->id : r->id; + val[0] = r->id; DNPRINTF(SWM_D_EVENT, "update_win_stacking: %#x, sibling %#x\n", win->id, val[0]); @@ -3218,6 +3298,9 @@ center_pointer(struct swm_region *r) return; win = r->ws->focus; + + DNPRINTF(SWM_D_EVENT, "center_pointer: win %#x.\n", WINID(win)); + if (win && win->mapped) xcb_warp_pointer(conn, XCB_NONE, win->id, 0, 0, 0, 0, WIDTH(win) / 2, HEIGHT(win) / 2); @@ -3504,6 +3587,10 @@ unfocus_win(struct ws_win *win) update_window_color(win); + /* Raise window to "top unfocused position." */ + if (win->ws->always_raise) + raise_window(win); + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->s->root, ewmh[_NET_ACTIVE_WINDOW].atom, XCB_ATOM_WINDOW, 32, 1, &none); @@ -4111,6 +4198,7 @@ swapwin(struct swm_region *r, union arg *args) ewmh_update_client_list(); stack(); + center_pointer(r); focus_flush(); out: DNPRINTF(SWM_D_MOVE, "swapwin: done\n"); @@ -4264,7 +4352,6 @@ focus(struct swm_region *r, union arg *args) struct workspace *ws = NULL; union arg a; int i; - xcb_icccm_wm_hints_t hints; if (!(r && r->ws)) goto out; @@ -4337,27 +4424,26 @@ focus(struct swm_region *r, union arg *args) head = TAILQ_FIRST(&r->s->ws[(ws->idx + i) % workspace_limit].winlist); - while (head != NULL && - (head = TAILQ_NEXT(head, entry)) != NULL) { + while (head) { if (head == cur_focus) { - winfocus = cur_focus; - break; - } - if (xcb_icccm_get_wm_hints_reply(conn, - xcb_icccm_get_wm_hints(conn, head->id), - &hints, NULL) != 0 && - xcb_icccm_wm_hints_get_urgency(&hints)) { + if (i > 0) { + winfocus = cur_focus; + break; + } + } else if (get_urgent(head)) { winfocus = head; break; } + + head = TAILQ_NEXT(head, entry); } - if (winfocus != NULL) + if (winfocus) break; } /* Switch ws if new focus is on a different ws. */ - if (winfocus != NULL && winfocus->ws != ws) { + if (winfocus && winfocus->ws != ws) { a.id = winfocus->ws->idx; switchws(r, &a); } @@ -4398,6 +4484,7 @@ cycle_layout(struct swm_region *r, union arg *args) focus_win(get_region_focus(r)); + center_pointer(r); focus_flush(); } @@ -4419,6 +4506,7 @@ stack_config(struct swm_region *r, union arg *args) stack(); bar_draw(); + center_pointer(r); focus_flush(); } @@ -4782,7 +4870,7 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, bool flip) win_g.y += last_h + 2 * border_width + tile_gap; if (disable_border && !(bar_enabled && ws->bar_enabled) && - winno == 1){ + winno == 1) { bordered = false; win_g.w += 2 * border_width; win_g.h += 2 * border_width; @@ -4995,12 +5083,13 @@ max_stack(struct workspace *ws, struct swm_geometry *g) if (X(w) != gg.x || Y(w) != gg.y || WIDTH(w) != gg.w || HEIGHT(w) != gg.h) { w->g = gg; - if (bar_enabled && ws->bar_enabled){ - w->bordered = true; - } else { + + if (disable_border && !(bar_enabled && ws->bar_enabled)) { w->bordered = false; WIDTH(w) += 2 * border_width; HEIGHT(w) += 2 * border_width; + } else { + w->bordered = true; } update_window(w); @@ -5243,7 +5332,7 @@ pressbutton(struct swm_region *r, union arg *args) void raise_toggle(struct swm_region *r, union arg *args) { - /* suppress unused warning since var is needed */ + /* Suppress warning. */ (void)args; if (r == NULL || r->ws == NULL) @@ -5254,9 +5343,8 @@ raise_toggle(struct swm_region *r, union arg *args) r->ws->always_raise = !r->ws->always_raise; - /* bring floaters back to top */ - if (!r->ws->always_raise) - stack(); + /* Update focused win stacking order based on new always_raise value. */ + raise_window(r->ws->focus); focus_flush(); } @@ -5265,7 +5353,8 @@ void iconify(struct swm_region *r, union arg *args) { struct ws_win *w; - /* suppress unused warning since var is needed */ + + /* Suppress warning. */ (void)args; if ((w = r->ws->focus) == NULL) @@ -5946,6 +6035,7 @@ maximize_toggle(struct swm_region *r, union arg *args) if (w == w->ws->focus) focus_win(w); + center_pointer(r); focus_flush(); DNPRINTF(SWM_D_MISC, "maximize_toggle: done\n"); } @@ -6326,6 +6416,7 @@ resize_step(struct swm_region *r, union arg *args) return; resize(win, args); + center_pointer(r); focus_flush(); } @@ -6525,6 +6616,7 @@ move_step(struct swm_region *r, union arg *args) return; move(win, args); + center_pointer(r); focus_flush(); } @@ -7136,6 +7228,8 @@ parsekeys(const char *keystr, unsigned int currmod, unsigned int *mod, KeySym *k *mod |= XCB_MOD_MASK_3; else if (strncmp(name, "Mod4", SWM_MODNAME_SIZE) == 0) *mod |= XCB_MOD_MASK_4; + else if (strncmp(name, "Mod5", SWM_MODNAME_SIZE) == 0) + *mod |= XCB_MOD_MASK_5; else if (strncasecmp(name, "SHIFT", SWM_MODNAME_SIZE) == 0) *mod |= XCB_MOD_MASK_SHIFT; else if (strncasecmp(name, "CONTROL", SWM_MODNAME_SIZE) == 0) @@ -7906,6 +8000,7 @@ enum { SWM_S_STACK_ENABLED, SWM_S_TERM_WIDTH, SWM_S_TILE_GAP, + SWM_S_URGENT_COLLAPSE, SWM_S_URGENT_ENABLED, SWM_S_VERBOSE_LAYOUT, SWM_S_WARP_POINTER, @@ -8108,6 +8203,9 @@ setconfvalue(const char *selector, const char *value, int flags) case SWM_S_TILE_GAP: tile_gap = atoi(value); break; + case SWM_S_URGENT_COLLAPSE: + urgent_collapse = (atoi(value) != 0); + break; case SWM_S_URGENT_ENABLED: urgent_enabled = (atoi(value) != 0); break; @@ -8188,6 +8286,8 @@ setconfmodkey(const char *selector, const char *value, int flags) update_modkey(XCB_MOD_MASK_3); else if (strncasecmp(value, "Mod4", strlen("Mod4")) == 0) update_modkey(XCB_MOD_MASK_4); + else if (strncasecmp(value, "Mod5", strlen("Mod5")) == 0) + update_modkey(XCB_MOD_MASK_5); else return (1); return (0); @@ -8454,6 +8554,7 @@ struct config_option configopt[] = { { "tile_gap", setconfvalue, SWM_S_TILE_GAP }, { "title_class_enabled", setconfvalue, SWM_S_WINDOW_CLASS_ENABLED }, /* For backwards compat. */ { "title_name_enabled", setconfvalue, SWM_S_WINDOW_INSTANCE_ENABLED }, /* For backwards compat. */ + { "urgent_collapse", setconfvalue, SWM_S_URGENT_COLLAPSE }, { "urgent_enabled", setconfvalue, SWM_S_URGENT_ENABLED }, { "verbose_layout", setconfvalue, SWM_S_VERBOSE_LAYOUT }, { "warp_pointer", setconfvalue, SWM_S_WARP_POINTER }, @@ -8947,7 +9048,7 @@ manage_window(xcb_window_t id, int spawn_pos, bool mapped) } out: - /* Figure out where to stack the window in the workspace. */ + /* Figure out where to insert the window in the workspace list. */ if (trans && (ww = find_window(trans))) TAILQ_INSERT_AFTER(&win->ws->winlist, ww, win, entry); else if (win->ws->focus && spawn_pos == SWM_STACK_ABOVE) @@ -8968,7 +9069,8 @@ out: ewmh_update_client_list(); - TAILQ_INSERT_TAIL(&win->ws->stack, win, stack_entry); + TAILQ_INSERT_HEAD(&win->ws->stack, win, stack_entry); + lower_window(win); /* Get/apply initial _NET_WM_STATE */ ewmh_get_wm_state(win); @@ -9517,6 +9619,12 @@ enternotify(xcb_enter_notify_event_t *e) return; } + if (focus_mode != SWM_FOCUS_FOLLOW && + e->mode == XCB_NOTIFY_MODE_UNGRAB) { + DNPRINTF(SWM_D_EVENT, "enternotify: ungrab; ignoring.\n"); + return; + } + last_event_time = e->time; if ((win = find_window(e->event)) == NULL) { @@ -10687,10 +10795,8 @@ main(int argc, char *argv[]) int xfd, i, num_screens; struct sigaction sact; xcb_generic_event_t *evt; - struct timeval tv; - fd_set rd; - int rd_max; int num_readable; + struct pollfd pfd[2]; bool stdin_ready = false, startup = true; /* suppress unused warning since var is needed */ @@ -10827,7 +10933,11 @@ noconfig: TAILQ_FOREACH(r, &screens[i].rl, entry) r->ws->state = SWM_WS_STATE_MAPPED; - rd_max = xfd > STDIN_FILENO ? xfd : STDIN_FILENO; + memset(&pfd, 0, sizeof(pfd)); + pfd[0].fd = xfd; + pfd[0].events = POLLIN; + pfd[1].fd = STDIN_FILENO; + pfd[1].events = POLLIN; while (running) { while ((evt = xcb_poll_for_event(conn))) { @@ -10851,18 +10961,10 @@ noconfig: } } - FD_ZERO(&rd); - - if (bar_extra) - FD_SET(STDIN_FILENO, &rd); - - FD_SET(xfd, &rd); - tv.tv_sec = 1; - tv.tv_usec = 0; - num_readable = select(rd_max + 1, &rd, NULL, NULL, &tv); - if (num_readable == -1 && errno != EINTR) { - DNPRINTF(SWM_D_MISC, "select failed"); - } else if (num_readable > 0 && FD_ISSET(STDIN_FILENO, &rd)) { + num_readable = poll(pfd, bar_extra ? 2 : 1, 1000); + if (num_readable == -1) { + DNPRINTF(SWM_D_MISC, "poll failed: %s", strerror(errno)); + } else if (num_readable > 0 && bar_extra && pfd[1].revents & POLLIN) { stdin_ready = true; }