X-Git-Url: https://code.delx.au/spectrwm/blobdiff_plain/54ebbac26078d68fd2dc7033504afca91040fbfd..d5362eb9f74aafae8330ae3806f450fdd6ffe17b:/spectrwm.c diff --git a/spectrwm.c b/spectrwm.c index b60cbc7..2cc0d24 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -1,14 +1,15 @@ /* - * Copyright (c) 2009-2012 Marco Peereboom + * Copyright (c) 2009-2015 Marco Peereboom * Copyright (c) 2009-2011 Ryan McBride * Copyright (c) 2009 Darrin Chandler * Copyright (c) 2009 Pierre-Yves Ritschard * Copyright (c) 2010 Tuukka Kataja * Copyright (c) 2011 Jason L. Wright - * Copyright (c) 2011-2014 Reginald Kennedy + * Copyright (c) 2011-2015 Reginald Kennedy * Copyright (c) 2011-2012 Lawrence Teo * Copyright (c) 2011-2012 Tiago Cunha - * Copyright (c) 2012-2013 David Hill + * Copyright (c) 2012-2015 David Hill + * Copyright (c) 2014-2015 Yuri D'Elia * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -77,6 +78,7 @@ #include #include #include +#include #include #include #include @@ -331,6 +333,9 @@ bool cycle_visible = false; int term_width = 0; int font_adjusted = 0; unsigned int mod_key = MODKEY; +bool warp_focus = false; +bool warp_pointer = false; +bool workspace_clamp = false; /* dmenu search */ struct swm_region *search_r; @@ -400,7 +405,9 @@ char *bar_format = NULL; bool stack_enabled = true; bool clock_enabled = true; bool iconic_enabled = false; +bool maximize_hide_bar = false; bool urgent_enabled = false; +bool urgent_collapse = false; char *clock_format = NULL; bool window_class_enabled = false; bool window_instance_enabled = false; @@ -478,7 +485,7 @@ struct ws_win { bool can_delete; bool take_focus; bool java; - unsigned long quirks; + uint32_t quirks; struct workspace *ws; /* always valid */ struct swm_screen *s; /* always valid, never changes */ xcb_size_hints_t sh; @@ -622,6 +629,7 @@ union arg { #define SWM_ARG_ID_FLIPLAYOUT (24) #define SWM_ARG_ID_STACKRESET (30) #define SWM_ARG_ID_STACKINIT (31) +#define SWM_ARG_ID_STACKBALANCE (32) #define SWM_ARG_ID_CYCLEWS_UP (40) #define SWM_ARG_ID_CYCLEWS_DOWN (41) #define SWM_ARG_ID_CYCLERG_UP (42) @@ -650,6 +658,8 @@ union arg { #define SWM_ARG_ID_LOWER (106) #define SWM_ARG_ID_BAR_TOGGLE (110) #define SWM_ARG_ID_BAR_TOGGLE_WS (111) +#define SWM_ARG_ID_CYCLERG_MOVE_UP (112) +#define SWM_ARG_ID_CYCLERG_MOVE_DOWN (113) char **argv; }; @@ -662,18 +672,21 @@ struct quirk { regex_t regex_class; regex_t regex_instance; regex_t regex_name; - unsigned long quirk; + uint32_t quirk; + int ws; /* Initial workspace. */ #define SWM_Q_FLOAT (1<<0) /* float this window */ #define SWM_Q_TRANSSZ (1<<1) /* transiend window size too small */ #define SWM_Q_ANYWHERE (1<<2) /* don't position this window */ #define SWM_Q_XTERM_FONTADJ (1<<3) /* adjust xterm fonts when resizing */ -#define SWM_Q_FULLSCREEN (1<<4) /* remove border */ +#define SWM_Q_FULLSCREEN (1<<4) /* remove border when fullscreen */ #define SWM_Q_FOCUSPREV (1<<5) /* focus on caller */ #define SWM_Q_NOFOCUSONMAP (1<<6) /* Don't focus on window when mapped. */ #define SWM_Q_FOCUSONMAP_SINGLE (1<<7) /* Only focus if single win of type. */ #define SWM_Q_OBEYAPPFOCUSREQ (1<<8) /* Focus when applications ask. */ #define SWM_Q_IGNOREPID (1<<9) /* Ignore PID when determining ws. */ #define SWM_Q_IGNORESPAWNWS (1<<10) /* Ignore _SWM_WS when managing win. */ +#define SWM_Q_NOFOCUSCYCLE (1<<11) /* Remove from normal focus cycle. */ +#define SWM_Q_MINIMALBORDER (1<<12) /* Remove border when floating/unfocused */ }; TAILQ_HEAD(quirk_list, quirk); struct quirk_list quirks = TAILQ_HEAD_INITIALIZER(quirks); @@ -877,6 +890,8 @@ enum keyfuncid { KF_RG_7, KF_RG_8, KF_RG_9, + KF_RG_MOVE_NEXT, + KF_RG_MOVE_PREV, KF_RG_NEXT, KF_RG_PREV, KF_SCREEN_NEXT, @@ -884,6 +899,7 @@ enum keyfuncid { KF_SEARCH_WIN, KF_SEARCH_WORKSPACE, KF_SPAWN_CUSTOM, + KF_STACK_BALANCE, KF_STACK_INC, KF_STACK_DEC, KF_STACK_RESET, @@ -964,9 +980,12 @@ void bar_window_name(char *, size_t, struct swm_region *); void bar_window_state(char *, size_t, struct swm_region *); void bar_workspace_name(char *, size_t, struct swm_region *); void buttonpress(xcb_button_press_event_t *); +void center_pointer(struct swm_region *); void check_conn(void); void clear_keys(void); int clear_maximized(struct workspace *); +void clear_quirks(void); +void clear_spawns(void); void clientmessage(xcb_client_message_event_t *); void client_msg(struct ws_win *, xcb_atom_t, xcb_timestamp_t); int conf_load(const char *, int); @@ -1037,6 +1056,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 *); @@ -1059,6 +1079,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 *); @@ -1072,7 +1093,7 @@ uint32_t name_to_pixel(int, const char *); void name_workspace(struct swm_region *, union arg *); void new_region(struct swm_screen *, int, int, int, int); int parsekeys(const char *, unsigned int, unsigned int *, KeySym *); -int parsequirks(const char *, unsigned long *); +int parsequirks(const char *, uint32_t *, int *); int parse_rgb(const char *, uint16_t *, uint16_t *, uint16_t *); void pressbutton(struct swm_region *, union arg *); void priorws(struct swm_region *, union arg *); @@ -1081,10 +1102,10 @@ void print_win_geom(xcb_window_t); #endif void propertynotify(xcb_property_notify_event_t *); void quirk_free(struct quirk *); -void quirk_insert(const char *, const char *, const char *,unsigned long); +void quirk_insert(const char *, const char *, const char *, uint32_t, int); void quirk_remove(struct quirk *); void quirk_replace(struct quirk *, const char *, const char *, const char *, - unsigned long); + uint32_t, int); void quit(struct swm_region *, union arg *); void raise_toggle(struct swm_region *, union arg *); void raise_window(struct ws_win *); @@ -1119,7 +1140,7 @@ int setconfvalue(const char *, const char *, int); void setkeybinding(unsigned int, KeySym, enum keyfuncid, const char *); int setkeymapping(const char *, const char *, int); int setlayout(const char *, const char *, int); -void setquirk(const char *, const char *, const char *,unsigned long); +void setquirk(const char *, const char *, const char *, uint32_t, int); void setscreencolor(const char *, int, int); void setspawn(const char *, const char *, int); void setup_ewmh(void); @@ -2164,6 +2185,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) { @@ -2171,8 +2208,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; @@ -2180,22 +2215,20 @@ 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); + } } + if(urgent_collapse && s[0]) + s[strlen(s) - 1] = 0; } void @@ -3001,14 +3034,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; @@ -3030,23 +3123,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)), @@ -3068,10 +3163,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]); @@ -3206,6 +3305,26 @@ get_pointer_win(xcb_window_t root) return win; } +void +center_pointer(struct swm_region *r) +{ + struct ws_win *win; + + if (!warp_pointer || r == NULL) + 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); + else + xcb_warp_pointer(conn, XCB_NONE, r->id, 0, 0, 0, 0, + WIDTH(r) / 2, HEIGHT(r) / 2); +} + struct swm_region * root_to_region(xcb_window_t root, int check) { @@ -3484,6 +3603,19 @@ unfocus_win(struct ws_win *win) update_window_color(win); + /* Raise window to "top unfocused position." */ + if (win->ws->always_raise) + raise_window(win); + + /* Update border width */ + if (win->bordered && (win->quirks & SWM_Q_MINIMALBORDER) && + FLOATING(win)) { + win->bordered = 0; + X(win) += border_width; + Y(win) += border_width; + update_window(win); + } + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->s->root, ewmh[_NET_ACTIVE_WINDOW].atom, XCB_ATOM_WINDOW, 32, 1, &none); @@ -3523,6 +3655,16 @@ focus_win(struct ws_win *win) &cfw->s->c[(MAXIMIZED(cfw) ? SWM_S_COLOR_UNFOCUS_MAXIMIZED : SWM_S_COLOR_UNFOCUS)].pixel); + + /* Update border width */ + if (cfw->bordered && + (cfw->quirks & SWM_Q_MINIMALBORDER) && + FLOATING(cfw)) { + cfw->bordered = 0; + X(cfw) += border_width; + Y(cfw) += border_width; + update_window(cfw); + } } else { unfocus_win(cfw); } @@ -3611,10 +3753,20 @@ focus_win(struct ws_win *win) &win->id); } - if (cfw != win) + if (cfw != win) { /* Update window border even if workspace is hidden. */ update_window_color(win); + /* Update border width */ + if (!win->bordered && WS_FOCUSED(win->ws) && + (win->quirks & SWM_Q_MINIMALBORDER) && FLOATING(win)) { + win->bordered = 1; + X(win) -= border_width; + Y(win) -= border_width; + update_window(win); + } + } + out: bar_draw(); @@ -3765,6 +3917,20 @@ switchws(struct swm_region *r, union arg *args) if (new_ws == old_ws) return; + other_r = new_ws->r; + if (other_r && workspace_clamp) { + DNPRINTF(SWM_D_WS, "switchws: ws clamped.\n"); + + if (warp_focus) { + DNPRINTF(SWM_D_WS, "switchws: warping focus to region " + "with ws %d.\n", wsid); + focus_region(other_r); + center_pointer(other_r); + focus_flush(); + } + return; + } + if ((win = old_ws->focus) != NULL) { update_window_color(win); @@ -3773,17 +3939,17 @@ switchws(struct swm_region *r, union arg *args) &none); } - other_r = new_ws->r; - if (other_r == NULL) { - /* the other workspace is hidden, hide this one */ - old_ws->r = NULL; - unmap_old = true; - } else { + if (other_r) { /* the other ws is visible in another region, exchange them */ other_r->ws_prior = new_ws; other_r->ws = old_ws; old_ws->r = other_r; + } else { + /* the other workspace is hidden, hide this one */ + old_ws->r = NULL; + unmap_old = true; } + this_r->ws_prior = old_ws; this_r->ws = new_ws; new_ws->r = this_r; @@ -3823,6 +3989,7 @@ switchws(struct swm_region *r, union arg *args) ewmh_update_current_desktop(); + center_pointer(r); focus_flush(); new_ws->state = SWM_WS_STATE_MAPPED; @@ -3919,6 +4086,7 @@ focusrg(struct swm_region *r, union arg *args) return; focus_region(rr); + center_pointer(rr); focus_flush(); DNPRINTF(SWM_D_FOCUS, "focusrg: done\n"); } @@ -3926,6 +4094,7 @@ focusrg(struct swm_region *r, union arg *args) void cyclerg(struct swm_region *r, union arg *args) { + union arg a; struct swm_region *rr = NULL; int i, num_screens; @@ -3939,11 +4108,13 @@ cyclerg(struct swm_region *r, union arg *args) switch (args->id) { case SWM_ARG_ID_CYCLERG_UP: + case SWM_ARG_ID_CYCLERG_MOVE_UP: rr = TAILQ_NEXT(r, entry); if (rr == NULL) rr = TAILQ_FIRST(&screens[i].rl); break; case SWM_ARG_ID_CYCLERG_DOWN: + case SWM_ARG_ID_CYCLERG_MOVE_DOWN: rr = TAILQ_PREV(r, swm_region_list, entry); if (rr == NULL) rr = TAILQ_LAST(&screens[i].rl, swm_region_list); @@ -3954,8 +4125,22 @@ cyclerg(struct swm_region *r, union arg *args) if (rr == NULL) return; - focus_region(rr); - focus_flush(); + switch (args->id) { + case SWM_ARG_ID_CYCLERG_UP: + case SWM_ARG_ID_CYCLERG_DOWN: + focus_region(rr); + center_pointer(rr); + focus_flush(); + break; + case SWM_ARG_ID_CYCLERG_MOVE_UP: + case SWM_ARG_ID_CYCLERG_MOVE_DOWN: + a.id = rr->ws->idx; + switchws(r, &a); + break; + default: + return; + }; + DNPRINTF(SWM_D_FOCUS, "cyclerg: done\n"); } @@ -4088,6 +4273,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"); @@ -4241,7 +4427,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; @@ -4278,7 +4463,8 @@ focus(struct swm_region *r, union arg *args) } while (winfocus && (ICONIC(winfocus) || winfocus->id == cur_focus->transient || (cur_focus->transient != XCB_WINDOW_NONE && - winfocus->transient == cur_focus->transient))); + winfocus->transient == cur_focus->transient) || + (winfocus->quirks & SWM_Q_NOFOCUSCYCLE))); break; case SWM_ARG_ID_FOCUSNEXT: if (cur_focus == NULL) @@ -4294,7 +4480,8 @@ focus(struct swm_region *r, union arg *args) } while (winfocus && (ICONIC(winfocus) || winfocus->id == cur_focus->transient || (cur_focus->transient != XCB_WINDOW_NONE && - winfocus->transient == cur_focus->transient))); + winfocus->transient == cur_focus->transient) || + (winfocus->quirks & SWM_Q_NOFOCUSCYCLE))); break; case SWM_ARG_ID_FOCUSMAIN: if (cur_focus == NULL) @@ -4314,27 +4501,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); } @@ -4347,6 +4533,7 @@ focus(struct swm_region *r, union arg *args) stack(); focus_win(get_focus_magic(winfocus)); + center_pointer(r); focus_flush(); out: @@ -4374,6 +4561,7 @@ cycle_layout(struct swm_region *r, union arg *args) focus_win(get_region_focus(r)); + center_pointer(r); focus_flush(); } @@ -4395,6 +4583,7 @@ stack_config(struct swm_region *r, union arg *args) stack(); bar_draw(); + center_pointer(r); focus_flush(); } @@ -4532,7 +4721,7 @@ update_floater(struct ws_win *win) win->g = r->g; - if (bar_enabled && ws->bar_enabled) { + if (bar_enabled && ws->bar_enabled && !maximize_hide_bar) { if (!bar_at_bottom) Y(win) += bar_height; HEIGHT(win) -= bar_height; @@ -4550,9 +4739,11 @@ update_floater(struct ws_win *win) if (r != ws->old_r) load_float_geom(win); - if ((win->quirks & SWM_Q_FULLSCREEN) && - WIDTH(win) >= WIDTH(r) && HEIGHT(win) >= HEIGHT(r)) { - /* Remove border for FULLSCREEN quirk. */ + if (((win->quirks & SWM_Q_FULLSCREEN) && + WIDTH(win) >= WIDTH(r) && HEIGHT(win) >= HEIGHT(r)) || + ((!WS_FOCUSED(win->ws) || win->ws->focus != win) && + (win->quirks & SWM_Q_MINIMALBORDER))) { + /* Remove border */ win->bordered = false; } else if (!MANUAL(win)) { if (TRANS(win) && (win->quirks & SWM_Q_TRANSSZ)) { @@ -4758,7 +4949,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; @@ -4842,6 +5033,9 @@ vertical_config(struct workspace *ws, int id) if (ws->l_state.vertical_mwin > 0) ws->l_state.vertical_mwin--; break; + case SWM_ARG_ID_STACKBALANCE: + ws->l_state.vertical_msize = SWM_V_SLICE / (ws->l_state.vertical_stacks + 1); + break; case SWM_ARG_ID_STACKINC: ws->l_state.vertical_stacks++; break; @@ -4892,6 +5086,9 @@ horizontal_config(struct workspace *ws, int id) if (ws->l_state.horizontal_mwin > 0) ws->l_state.horizontal_mwin--; break; + case SWM_ARG_ID_STACKBALANCE: + ws->l_state.horizontal_msize = SWM_H_SLICE / (ws->l_state.horizontal_stacks + 1); + break; case SWM_ARG_ID_STACKINC: ws->l_state.horizontal_stacks++; break; @@ -4971,12 +5168,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); @@ -5106,6 +5304,7 @@ send_to_ws(struct swm_region *r, union arg *args) } } + center_pointer(r); focus_flush(); } @@ -5218,7 +5417,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) @@ -5229,9 +5428,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(); } @@ -5240,7 +5438,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) @@ -5693,10 +5892,13 @@ ewmh_update_current_desktop(void) int num_screens, i; num_screens = get_screen_count(); - for (i = 0; i < num_screens; ++i) - xcb_change_property(conn, XCB_PROP_MODE_REPLACE, - screens[i].root, ewmh[_NET_CURRENT_DESKTOP].atom, - XCB_ATOM_CARDINAL, 32, 1, &screens[i].r_focus->ws->idx); + for (i = 0; i < num_screens; ++i) { + if (screens[i].r_focus) + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, + screens[i].root, ewmh[_NET_CURRENT_DESKTOP].atom, + XCB_ATOM_CARDINAL, 32, 1, + &screens[i].r_focus->ws->idx); + } } void @@ -5921,6 +6123,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"); } @@ -5952,6 +6155,7 @@ floating_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, "floating_toggle: done\n"); } @@ -6300,6 +6504,7 @@ resize_step(struct swm_region *r, union arg *args) return; resize(win, args); + center_pointer(r); focus_flush(); } @@ -6499,6 +6704,7 @@ move_step(struct swm_region *r, union arg *args) return; move(win, args); + center_pointer(r); focus_flush(); } @@ -6575,6 +6781,8 @@ struct keyfunc { { "rg_7", focusrg, {.id = 6} }, { "rg_8", focusrg, {.id = 7} }, { "rg_9", focusrg, {.id = 8} }, + { "rg_move_next", cyclerg, {.id = SWM_ARG_ID_CYCLERG_MOVE_UP} }, + { "rg_move_prev", cyclerg, {.id = SWM_ARG_ID_CYCLERG_MOVE_DOWN} }, { "rg_next", cyclerg, {.id = SWM_ARG_ID_CYCLERG_UP} }, { "rg_prev", cyclerg, {.id = SWM_ARG_ID_CYCLERG_DOWN} }, { "screen_next", cyclerg, {.id = SWM_ARG_ID_CYCLERG_UP} }, @@ -6582,6 +6790,7 @@ struct keyfunc { { "search_win", search_win, {0} }, { "search_workspace", search_workspace, {0} }, { "spawn_custom", NULL, {0} }, + { "stack_balance", stack_config, {.id = SWM_ARG_ID_STACKBALANCE} }, { "stack_inc", stack_config, {.id = SWM_ARG_ID_STACKINC} }, { "stack_dec", stack_config, {.id = SWM_ARG_ID_STACKDEC} }, { "stack_reset", stack_config, {.id = SWM_ARG_ID_STACKRESET} }, @@ -6946,6 +7155,16 @@ spawn_remove(struct spawn_prog *sp) DNPRINTF(SWM_D_SPAWN, "spawn_remove: leave\n"); } +void +clear_spawns(void) +{ + struct spawn_prog *sp; + + while ((sp = TAILQ_FIRST(&spawns)) != NULL) { + spawn_remove(sp); + } +} + struct spawn_prog* spawn_find(const char *name) { @@ -7110,6 +7329,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) @@ -7557,12 +7778,14 @@ const char *quirkname[] = { "OBEYAPPFOCUSREQ", "IGNOREPID", "IGNORESPAWNWS", + "NOFOCUSCYCLE", + "MINIMALBORDER", }; -/* SWM_Q_WS: retain '|' for back compat for now (2009-08-11) */ -#define SWM_Q_WS "\n|+ \t" +/* SWM_Q_DELIM: retain '|' for back compat for now (2009-08-11) */ +#define SWM_Q_DELIM "\n|+ \t" int -parsequirks(const char *qstr, unsigned long *quirk) +parsequirks(const char *qstr, uint32_t *quirk, int *ws) { char *str, *cp, *name; int i; @@ -7575,9 +7798,16 @@ parsequirks(const char *qstr, unsigned long *quirk) cp = str; *quirk = 0; - while ((name = strsep(&cp, SWM_Q_WS)) != NULL) { + while ((name = strsep(&cp, SWM_Q_DELIM)) != NULL) { if (cp) - cp += (long)strspn(cp, SWM_Q_WS); + cp += (long)strspn(cp, SWM_Q_DELIM); + + if (sscanf(name, "WS[%d]", ws) == 1) { + if (*ws > 0) + *ws -= 1; + continue; + } + for (i = 0; i < LENGTH(quirkname); i++) { if (strncasecmp(name, quirkname[i], SWM_QUIRK_LEN) == 0) { @@ -7606,14 +7836,14 @@ parsequirks(const char *qstr, unsigned long *quirk) void quirk_insert(const char *class, const char *instance, const char *name, - unsigned long quirk) + uint32_t quirk, int ws) { struct quirk *qp; char *str; bool failed = false; DNPRINTF(SWM_D_QUIRK, "quirk_insert: class: %s, instance: %s, name: %s," - " value: %lu\n", class, instance, name, quirk); + " value: %u, ws: %d\n", class, instance, name, quirk, ws); if ((qp = malloc(sizeof *qp)) == NULL) err(1, "quirk_insert: malloc"); @@ -7660,6 +7890,7 @@ quirk_insert(const char *class, const char *instance, const char *name, quirk_free(qp); } else { qp->quirk = quirk; + qp->ws = ws; TAILQ_INSERT_TAIL(&quirks, qp, entry); } DNPRINTF(SWM_D_QUIRK, "quirk_insert: leave\n"); @@ -7668,7 +7899,7 @@ quirk_insert(const char *class, const char *instance, const char *name, void quirk_remove(struct quirk *qp) { - DNPRINTF(SWM_D_QUIRK, "quirk_remove: %s:%s [%lu]\n", qp->class, + DNPRINTF(SWM_D_QUIRK, "quirk_remove: %s:%s [%u]\n", qp->class, qp->name, qp->quirk); TAILQ_REMOVE(&quirks, qp, entry); @@ -7689,45 +7920,56 @@ quirk_free(struct quirk *qp) free(qp); } +void +clear_quirks(void) +{ + struct quirk *qp; + + while ((qp = TAILQ_FIRST(&quirks)) != NULL) { + quirk_remove(qp); + } +} + void quirk_replace(struct quirk *qp, const char *class, const char *instance, - const char *name, unsigned long quirk) + const char *name, uint32_t quirk, int ws) { - DNPRINTF(SWM_D_QUIRK, "quirk_replace: %s:%s:%s [%lu]\n", qp->class, - qp->instance, qp->name, qp->quirk); + DNPRINTF(SWM_D_QUIRK, "quirk_replace: %s:%s:%s [%u], ws: %d\n", qp->class, + qp->instance, qp->name, qp->quirk, qp->ws); quirk_remove(qp); - quirk_insert(class, instance, name, quirk); + quirk_insert(class, instance, name, quirk, ws); DNPRINTF(SWM_D_QUIRK, "quirk_replace: leave\n"); } void setquirk(const char *class, const char *instance, const char *name, - unsigned long quirk) + uint32_t quirk, int ws) { struct quirk *qp; - DNPRINTF(SWM_D_QUIRK, "setquirk: enter %s:%s:%s [%lu]\n", class, - instance, name, quirk); + DNPRINTF(SWM_D_QUIRK, "setquirk: enter %s:%s:%s [%u], ws: %d\n", class, + instance, name, quirk, ws); /* Remove/replace existing quirk. */ TAILQ_FOREACH(qp, &quirks, entry) { if (strcmp(qp->class, class) == 0 && strcmp(qp->instance, instance) == 0 && strcmp(qp->name, name) == 0) { - if (quirk == 0) + if (quirk == 0 && ws == -1) quirk_remove(qp); else - quirk_replace(qp, class, instance, name, quirk); + quirk_replace(qp, class, instance, name, quirk, + ws); DNPRINTF(SWM_D_QUIRK, "setquirk: leave\n"); return; } } - /* Only insert if quirk is not NONE. */ - if (quirk) - quirk_insert(class, instance, name, quirk); + /* Only insert if quirk is not NONE or forced ws is set. */ + if (quirk || ws != -1) + quirk_insert(class, instance, name, quirk, ws); DNPRINTF(SWM_D_QUIRK, "setquirk: leave\n"); } @@ -7753,8 +7995,8 @@ setconfquirk(const char *selector, const char *value, int flags) { char *str, *cp, *class; char *instance = NULL, *name = NULL; - int retval, count = 0; - unsigned long qrks; + int retval, count = 0, ws = -1; + uint32_t qrks; /* suppress unused warning since var is needed */ (void)flags; @@ -7797,8 +8039,8 @@ setconfquirk(const char *selector, const char *value, int flags) DNPRINTF(SWM_D_CONF, "setconfquirk: class: %s, instance: %s, " "name: %s\n", class, instance, name); - if ((retval = parsequirks(value, &qrks)) == 0) - setquirk(class, instance, name, qrks); + if ((retval = parsequirks(value, &qrks, &ws)) == 0) + setquirk(class, instance, name, qrks, ws); free(str); return (retval); @@ -7807,19 +8049,32 @@ setconfquirk(const char *selector, const char *value, int flags) void setup_quirks(void) { - setquirk("MPlayer", "xv", ".*", SWM_Q_FLOAT | SWM_Q_FULLSCREEN | SWM_Q_FOCUSPREV); - setquirk("OpenOffice.org 3.2", "VCLSalFrame", ".*", SWM_Q_FLOAT); - setquirk("Firefox-bin", "firefox-bin", ".*", SWM_Q_TRANSSZ); - setquirk("Firefox", "Dialog", ".*", SWM_Q_FLOAT); - setquirk("Gimp", "gimp", ".*", SWM_Q_FLOAT | SWM_Q_ANYWHERE); - setquirk("XTerm", "xterm", ".*", SWM_Q_XTERM_FONTADJ); - setquirk("xine", "Xine Window", ".*", SWM_Q_FLOAT | SWM_Q_ANYWHERE); - setquirk("Xitk", "Xitk Combo", ".*", SWM_Q_FLOAT | SWM_Q_ANYWHERE); - setquirk("xine", "xine Panel", ".*", SWM_Q_FLOAT | SWM_Q_ANYWHERE); - setquirk("Xitk", "Xine Window", ".*", SWM_Q_FLOAT | SWM_Q_ANYWHERE); - setquirk("xine", "xine Video Fullscreen Window", ".*", SWM_Q_FULLSCREEN | SWM_Q_FLOAT); - setquirk("pcb", "pcb", ".*", SWM_Q_FLOAT); - setquirk("SDL_App", "SDL_App", ".*", SWM_Q_FLOAT | SWM_Q_FULLSCREEN); + setquirk("MPlayer", "xv", ".*", + SWM_Q_FLOAT | SWM_Q_FULLSCREEN | SWM_Q_FOCUSPREV, -1); + setquirk("OpenOffice.org 3.2", "VCLSalFrame", ".*", + SWM_Q_FLOAT, -1); + setquirk("Firefox-bin", "firefox-bin", ".*", + SWM_Q_TRANSSZ, -1); + setquirk("Firefox", "Dialog", ".*", + SWM_Q_FLOAT, -1); + setquirk("Gimp", "gimp", ".*", + SWM_Q_FLOAT | SWM_Q_ANYWHERE, -1); + setquirk("XTerm", "xterm", ".*", + SWM_Q_XTERM_FONTADJ, -1); + setquirk("xine", "Xine Window", ".*", + SWM_Q_FLOAT | SWM_Q_ANYWHERE, -1); + setquirk("Xitk", "Xitk Combo", ".*", + SWM_Q_FLOAT | SWM_Q_ANYWHERE, -1); + setquirk("xine", "xine Panel", ".*", + SWM_Q_FLOAT | SWM_Q_ANYWHERE, -1); + setquirk("Xitk", "Xine Window", ".*", + SWM_Q_FLOAT | SWM_Q_ANYWHERE, -1); + setquirk("xine", "xine Video Fullscreen Window", ".*", + SWM_Q_FULLSCREEN | SWM_Q_FLOAT, -1); + setquirk("pcb", "pcb", ".*", + SWM_Q_FLOAT, -1); + setquirk("SDL_App", "SDL_App", ".*", + SWM_Q_FLOAT | SWM_Q_FULLSCREEN, -1); } /* conf file stuff */ @@ -7850,6 +8105,7 @@ enum { SWM_S_FOCUS_MODE, SWM_S_ICONIC_ENABLED, SWM_S_JAVA_WORKAROUND, + SWM_S_MAXIMIZE_HIDE_BAR, SWM_S_REGION_PADDING, SWM_S_SPAWN_ORDER, SWM_S_SPAWN_TERM, @@ -7858,11 +8114,15 @@ 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_FOCUS, + SWM_S_WARP_POINTER, SWM_S_WINDOW_CLASS_ENABLED, SWM_S_WINDOW_INSTANCE_ENABLED, SWM_S_WINDOW_NAME_ENABLED, + SWM_S_WORKSPACE_CLAMP, SWM_S_WORKSPACE_LIMIT, SWM_S_WORKSPACE_NAME, }; @@ -8021,6 +8281,9 @@ setconfvalue(const char *selector, const char *value, int flags) case SWM_S_JAVA_WORKAROUND: java_workaround = (atoi(value) != 0); break; + case SWM_S_MAXIMIZE_HIDE_BAR: + maximize_hide_bar = atoi(value); + break; case SWM_S_REGION_PADDING: region_padding = atoi(value); if (region_padding < 0) @@ -8059,6 +8322,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; @@ -8071,6 +8337,12 @@ setconfvalue(const char *selector, const char *value, int flags) layouts[i].l_string = plain_stacker; } break; + case SWM_S_WARP_FOCUS: + warp_focus = (atoi(value) != 0); + break; + case SWM_S_WARP_POINTER: + warp_pointer = (atoi(value) != 0); + break; case SWM_S_WINDOW_CLASS_ENABLED: window_class_enabled = (atoi(value) != 0); break; @@ -8080,6 +8352,9 @@ setconfvalue(const char *selector, const char *value, int flags) case SWM_S_WINDOW_NAME_ENABLED: window_name_enabled = (atoi(value) != 0); break; + case SWM_S_WORKSPACE_CLAMP: + workspace_clamp = (atoi(value) != 0); + break; case SWM_S_WORKSPACE_LIMIT: workspace_limit = atoi(value); if (workspace_limit > SWM_WS_MAX) @@ -8136,6 +8411,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); @@ -8388,6 +8665,7 @@ struct config_option configopt[] = { { "java_workaround", setconfvalue, SWM_S_JAVA_WORKAROUND }, { "keyboard_mapping", setkeymapping, 0 }, { "layout", setlayout, 0 }, + { "maximize_hide_bar", setconfvalue, SWM_S_MAXIMIZE_HIDE_BAR }, { "modkey", setconfmodkey, 0 }, { "program", setconfspawn, 0 }, { "quirk", setconfquirk, 0 }, @@ -8402,11 +8680,15 @@ 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_focus", setconfvalue, SWM_S_WARP_FOCUS }, + { "warp_pointer", setconfvalue, SWM_S_WARP_POINTER }, { "window_class_enabled", setconfvalue, SWM_S_WINDOW_CLASS_ENABLED }, { "window_instance_enabled", setconfvalue, SWM_S_WINDOW_INSTANCE_ENABLED }, { "window_name_enabled", setconfvalue, SWM_S_WINDOW_NAME_ENABLED }, + { "workspace_clamp", setconfvalue, SWM_S_WORKSPACE_CLAMP }, { "workspace_limit", setconfvalue, SWM_S_WORKSPACE_LIMIT }, { "name", setconfvalue, SWM_S_WORKSPACE_NAME }, }; @@ -8725,7 +9007,7 @@ manage_window(xcb_window_t id, int spawn_pos, bool mapped) xcb_get_geometry_reply_t *gr; xcb_window_t trans = XCB_WINDOW_NONE; uint32_t i, wa[2], new_flags; - int ws_idx; + int ws_idx, force_ws = -1; char *class, *instance, *name; if ((win = find_window(id)) != NULL) { @@ -8835,9 +9117,11 @@ manage_window(xcb_window_t id, int spawn_pos, bool mapped) regexec(&qp->regex_instance, instance, 0, NULL, 0) == 0 && regexec(&qp->regex_name, name, 0, NULL, 0) == 0) { DNPRINTF(SWM_D_CLASS, "manage_window: matched " - "quirk: %s:%s:%s mask: %#lx\n", qp->class, - qp->instance, qp->name, qp->quirk); + "quirk: %s:%s:%s mask: %#x, ws: %d\n", qp->class, + qp->instance, qp->name, qp->quirk, qp->ws); win->quirks = qp->quirk; + if (qp->ws >= 0 && qp->ws < workspace_limit) + force_ws = qp->ws; } } @@ -8869,6 +9153,9 @@ manage_window(xcb_window_t id, int spawn_pos, bool mapped) win->ws = r->ws; } + if (force_ws != -1) + win->ws = &r->s->ws[force_ws]; + /* Set the _NET_WM_DESKTOP atom. */ DNPRINTF(SWM_D_PROP, "manage_window: set _NET_WM_DESKTOP: %d\n", win->ws->idx); @@ -8889,7 +9176,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) @@ -8910,7 +9197,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); @@ -9459,6 +9747,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) { @@ -9536,6 +9830,7 @@ mapnotify(xcb_map_notify_event_t *e) if (ws->focus_pending == win) { focus_win(win); ws->focus_pending = NULL; + center_pointer(win->ws->r); focus_flush(); } } @@ -9798,6 +10093,7 @@ unmapnotify(xcb_unmap_notify_event_t *e) } } + center_pointer(ws->r); focus_flush(); } @@ -10523,10 +10819,17 @@ shutdown_cleanup(void) cursors_cleanup(); + clear_quirks(); + clear_spawns(); + clear_keys(); + teardown_ewmh(); num_screens = get_screen_count(); for (i = 0; i < num_screens; ++i) { + struct swm_region *r; + int j; + xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, screens[i].root, XCB_CURRENT_TIME); @@ -10538,13 +10841,45 @@ shutdown_cleanup(void) XftColorFree(display, DefaultVisual(display, i), DefaultColormap(display, i), &search_font_color); } + + for (j = 0; j < SWM_S_COLOR_MAX; ++j) { + free(screens[i].c[j].name); + } + + for (j = 0; j < SWM_WS_MAX; ++j) { + struct ws_win *win; + + free(screens[i].ws[j].name); + + while ((win = TAILQ_FIRST(&screens[i].ws[j].winlist)) != NULL) { + TAILQ_REMOVE(&screens[i].ws[j].winlist, win, entry); + free(win); + } + } + + while ((r = TAILQ_FIRST(&screens[i].rl)) != NULL) { + TAILQ_REMOVE(&screens[i].rl, r, entry); + free(r->bar); + free(r); + } + + while ((r = TAILQ_FIRST(&screens[i].orl)) != NULL) { + TAILQ_REMOVE(&screens[i].rl, r, entry); + free(r->bar); + free(r); + } } + free(screens); - if (bar_font_legacy) + free(bar_format); + free(bar_fonts); + free(clock_format); + free(startup_exception); + + if (bar_fs) XFreeFontSet(display, bar_fs); - else { + if (bar_font_legacy == false) XftFontClose(display, bar_font); - } xcb_key_symbols_free(syms); xcb_flush(conn); @@ -10627,10 +10962,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 */ @@ -10767,7 +11100,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))) { @@ -10791,18 +11128,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; }