JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
Remove path from Linux spectrwm.desktop.
[spectrwm.git] / spectrwm.c
index 1378638..5ad56a7 100644 (file)
@@ -610,6 +610,8 @@ struct quirk {
 #define SWM_Q_XTERM_FONTADJ    (1<<3)  /* adjust xterm fonts when resizing */
 #define SWM_Q_FULLSCREEN       (1<<4)  /* remove border */
 #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. */
 };
 TAILQ_HEAD(quirk_list, quirk);
 struct quirk_list              quirks = TAILQ_HEAD_INITIALIZER(quirks);
@@ -930,6 +932,7 @@ struct ws_win       *get_pointer_win(xcb_window_t);
 struct ws_win  *get_region_focus(struct swm_region *);
 int     get_region_index(struct swm_region *);
 xcb_screen_t   *get_screen(int);
+int     get_screen_count(void);
 #ifdef SWM_DEBUG
 char   *get_stack_mode_name(uint8_t);
 #endif
@@ -963,7 +966,7 @@ void         maprequest(xcb_map_request_event_t *);
 void    motionnotify(xcb_motion_notify_event_t *);
 void    move(struct ws_win *, union arg *);
 void    move_step(struct swm_region *, union arg *);
-uint32_t name_to_pixel(const char *);
+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(char *, unsigned int, unsigned int *, KeySym *);
@@ -1185,6 +1188,19 @@ get_screen(int screen)
 }
 
 int
+get_screen_count(void)
+{
+       const xcb_setup_t       *r;
+
+       if ((r = xcb_get_setup(conn)) == NULL) {
+               DNPRINTF(SWM_D_MISC, "get_screen_count: xcb_get_setup\n");
+               check_conn();
+       }
+
+       return xcb_setup_roots_length(r);
+}
+
+int
 get_region_index(struct swm_region *r)
 {
        struct swm_region       *rr;
@@ -1278,7 +1294,7 @@ setup_ewmh(void)
        for (i = 0; i < LENGTH(ewmh); i++)
                ewmh[i].atom = get_atom_from_string(ewmh[i].name);
 
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
        for (i = 0; i < num_screens; i++) {
                /* Support check window will be created by workaround(). */
 
@@ -1302,7 +1318,7 @@ teardown_ewmh(void)
 
        sup_check = get_atom_from_string("_NET_SUPPORTING_WM_CHECK");
        sup_list = get_atom_from_string("_NET_SUPPORTED");
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
 
        for (i = 0; i < num_screens; i++) {
                /* Get the support check window and destroy it */
@@ -1651,7 +1667,7 @@ find_pid(pid_t pid)
 }
 
 uint32_t
-name_to_pixel(const char *colorname)
+name_to_pixel(int sidx, const char *colorname)
 {
        uint32_t                        result = 0;
        char                            cname[32] = "#";
@@ -1661,7 +1677,7 @@ name_to_pixel(const char *colorname)
        xcb_alloc_named_color_reply_t   *nr;
        uint16_t                        rr, gg, bb;
 
-       screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
+       screen = get_screen(sidx);
        cmap = screen->default_colormap;
 
        /* color is in format rgb://rr/gg/bb */
@@ -1703,15 +1719,15 @@ setscreencolor(char *val, int i, int c)
 {
        int     num_screens;
 
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
        if (i > 0 && i <= num_screens) {
-               screens[i - 1].c[c].pixel = name_to_pixel(val);
+               screens[i - 1].c[c].pixel = name_to_pixel(i - 1, val);
                free(screens[i - 1].c[c].name);
                if ((screens[i - 1].c[c].name = strdup(val)) == NULL)
                        err(1, "strdup");
        } else if (i == -1) {
                for (i = 0; i < num_screens; i++) {
-                       screens[i].c[c].pixel = name_to_pixel(val);
+                       screens[i].c[c].pixel = name_to_pixel(0, val);
                        free(screens[i].c[c].name);
                        if ((screens[i].c[c].name = strdup(val)) == NULL)
                                err(1, "strdup");
@@ -1754,7 +1770,7 @@ custom_region(char *val)
        int                             sidx, num_screens;
        xcb_screen_t                    *screen;
 
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
        if (sscanf(val, "screen[%d]:%ux%u+%u+%u", &sidx, &w, &h, &x, &y) != 5)
                errx(1, "invalid custom region, "
                    "should be 'screen[<n>]:<n>x<n>+<n>+<n>");
@@ -1982,7 +1998,7 @@ bar_urgent(char *s, size_t sz)
        for (i = 0; i < workspace_limit; i++)
                urgent[i] = 0;
 
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       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) {
@@ -2232,7 +2248,7 @@ bar_draw(void)
        /* expand the format by first passing it through strftime(3) */
        bar_fmt_expand(fmtexp, sizeof fmtexp);
 
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
        for (i = 0; i < num_screens; i++) {
                TAILQ_FOREACH(r, &screens[i].rl, entry) {
                        if (r->bar == NULL)
@@ -2336,7 +2352,7 @@ bar_toggle(struct swm_region *r, union arg *args)
        }
 
        /* update bars as necessary */
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
        for (i = 0; i < num_screens; i++)
                TAILQ_FOREACH(tmpr, &screens[i].rl, entry)
                        if (tmpr->bar) {
@@ -2821,7 +2837,7 @@ unmap_all(void)
        struct ws_win           *win;
        int                     i, j, num_screens;
 
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       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)
@@ -2916,7 +2932,7 @@ root_to_region(xcb_window_t root, int check)
 
        DNPRINTF(SWM_D_MISC, "root_to_region: window: 0x%x\n", root);
 
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
        for (i = 0; i < num_screens; i++)
                if (screens[i].root == root)
                        break;
@@ -2968,7 +2984,7 @@ find_unmanaged_window(xcb_window_t id)
        struct ws_win           *win;
        int                     i, j, num_screens;
 
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       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].unmanagedlist,
@@ -2985,7 +3001,7 @@ find_window(xcb_window_t id)
        int                     i, j, num_screens;
        xcb_query_tree_reply_t  *r;
 
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       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)
@@ -3080,7 +3096,7 @@ kill_refs(struct ws_win *win)
        if (win == NULL)
                return;
 
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
        for (i = 0; i < num_screens; i++)
                TAILQ_FOREACH(r, &screens[i].rl, entry)
                        for (x = 0; x < workspace_limit; x++) {
@@ -3103,7 +3119,7 @@ validate_win(struct ws_win *testwin)
        if (testwin == NULL)
                return (0);
 
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
        for (i = 0; i < num_screens; i++)
                TAILQ_FOREACH(r, &screens[i].rl, entry)
                        for (x = 0; x < workspace_limit; x++) {
@@ -3123,7 +3139,7 @@ validate_ws(struct workspace *testws)
        int                     i, x, num_screens;
 
        /* validate all ws */
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
        for (i = 0; i < num_screens; i++)
                TAILQ_FOREACH(r, &screens[i].rl, entry)
                        for (x = 0; x < workspace_limit; x++) {
@@ -3543,7 +3559,7 @@ focusrg(struct swm_region *r, union arg *args)
        int                     ridx = args->id, i, num_screens;
        struct swm_region       *rr = NULL;
 
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
        /* do nothing if we don't have more than one screen */
        if (!(num_screens > 1 || outputs > 1))
                return;
@@ -3567,7 +3583,7 @@ cyclerg(struct swm_region *r, union arg *args)
        struct swm_region       *rr = NULL;
        int                     i, num_screens;
 
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
        /* do nothing if we don't have more than one screen */
        if (!(num_screens > 1 || outputs > 1))
                return;
@@ -3970,7 +3986,7 @@ stack(void) {
 
        DNPRINTF(SWM_D_STACK, "stack: begin\n");
 
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
        for (i = 0; i < num_screens; i++) {
 #ifdef SWM_DEBUG
                j = 0;
@@ -4545,7 +4561,7 @@ send_to_rg(struct swm_region *r, union arg *args)
        struct swm_region       *rr = NULL;
        union arg               a;
 
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
        /* do nothing if we don't have more than one screen */
        if (!(num_screens > 1 || outputs > 1))
                return;
@@ -5295,7 +5311,7 @@ resize(struct ws_win *win, union arg *args)
        int                     top = 0, left = 0, resizing;
        int                     dx, dy;
        xcb_cursor_t                    cursor;
-       xcb_query_pointer_reply_t       *xpr;
+       xcb_query_pointer_reply_t       *xpr = NULL;
        xcb_generic_event_t             *evt;
        xcb_motion_notify_event_t       *mne;
 
@@ -5325,6 +5341,12 @@ resize(struct ws_win *win, union arg *args)
 
        focus_flush();
 
+       /* It's possible for win to have been freed during focus_flush(). */
+       if (validate_win(win)) {
+               DNPRINTF(SWM_D_EVENT, "move: invalid win.\n");
+               goto out;
+       }
+
        switch (args->id) {
        case SWM_ARG_ID_WIDTHSHRINK:
                WIDTH(win) -= SWM_RESIZE_STEPS;
@@ -5381,7 +5403,7 @@ resize(struct ws_win *win, union arg *args)
 
        xcb_flush(conn);
        resizing = 1;
-       while ((evt = xcb_wait_for_event(conn)) && resizing) {
+       while (resizing && (evt = xcb_wait_for_event(conn))) {
                switch (XCB_EVENT_RESPONSE_TYPE(evt)) {
                case XCB_BUTTON_RELEASE:
                        DNPRINTF(SWM_D_EVENT, "resize: BUTTON_RELEASE\n");
@@ -5444,6 +5466,12 @@ resize(struct ws_win *win, union arg *args)
                        break;
                default:
                        event_handle(evt);
+
+                       /* It's possible for win to have been freed above. */
+                       if (validate_win(win)) {
+                               DNPRINTF(SWM_D_EVENT, "move: invalid win.\n");
+                               goto out;
+                       }
                        break;
                }
                free(evt);
@@ -5453,7 +5481,7 @@ resize(struct ws_win *win, union arg *args)
                xcb_flush(conn);
        }
        store_float_geom(win,r);
-
+out:
        xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
        free(xpr);
        DNPRINTF(SWM_D_EVENT, "resize: done.\n");
@@ -5481,7 +5509,7 @@ move(struct ws_win *win, union arg *args)
        xcb_timestamp_t         timestamp = 0;
        int                     move_stp = 0, moving;
        struct swm_region       *r = NULL;
-       xcb_query_pointer_reply_t       *qpr;
+       xcb_query_pointer_reply_t       *qpr = NULL;
        xcb_generic_event_t             *evt;
        xcb_motion_notify_event_t       *mne;
 
@@ -5512,6 +5540,12 @@ move(struct ws_win *win, union arg *args)
 
        focus_flush();
 
+       /* It's possible for win to have been freed during focus_flush(). */
+       if (validate_win(win)) {
+               DNPRINTF(SWM_D_EVENT, "move: invalid win.\n");
+               goto out;
+       }
+
        move_stp = 0;
        switch (args->id) {
        case SWM_ARG_ID_MOVELEFT:
@@ -5554,7 +5588,7 @@ move(struct ws_win *win, union arg *args)
 
        xcb_flush(conn);
        moving = 1;
-       while ((evt = xcb_wait_for_event(conn)) && moving) {
+       while (moving && (evt = xcb_wait_for_event(conn))) {
                switch (XCB_EVENT_RESPONSE_TYPE(evt)) {
                case XCB_BUTTON_RELEASE:
                        DNPRINTF(SWM_D_EVENT, "move: BUTTON_RELEASE\n");
@@ -5576,6 +5610,12 @@ move(struct ws_win *win, union arg *args)
                        break;
                default:
                        event_handle(evt);
+
+                       /* It's possible for win to have been freed above. */
+                       if (validate_win(win)) {
+                               DNPRINTF(SWM_D_EVENT, "move: invalid win.\n");
+                               goto out;
+                       }
                        break;
                }
                free(evt);
@@ -5585,6 +5625,7 @@ move(struct ws_win *win, union arg *args)
                xcb_flush(conn);
        }
        store_float_geom(win, r);
+out:
        free(qpr);
        xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
        DNPRINTF(SWM_D_EVENT, "move: done.\n");
@@ -6267,8 +6308,8 @@ setconfbinding(char *selector, char *value, int flags)
        for (kfid = 0; kfid < KF_INVALID; (kfid)++) {
                if (strncasecmp(selector, keyfuncs[kfid].name,
                    SWM_FUNCNAME_LEN) == 0) {
-                       DNPRINTF(SWM_D_KEY, "setconfbinding: %s: match\n",
-                           selector);
+                       DNPRINTF(SWM_D_KEY, "setconfbinding: %s: match "
+                           "keyfunc\n", selector);
                        if (parsekeys(value, mod_key, &mod, &ks) == 0) {
                                setkeybinding(mod, ks, kfid, NULL);
                                return (0);
@@ -6279,13 +6320,11 @@ setconfbinding(char *selector, char *value, int flags)
        /* search by custom spawn name */
        TAILQ_FOREACH(sp, &spawns, entry) {
                if (strcasecmp(selector, sp->name) == 0) {
-                       DNPRINTF(SWM_D_KEY, "setconfbinding: %s: match\n",
-                           selector);
+                       DNPRINTF(SWM_D_KEY, "setconfbinding: %s: match "
+                           "spawn\n", selector);
                        if (parsekeys(value, mod_key, &mod, &ks) == 0) {
                                setkeybinding(mod, ks, KF_SPAWN_CUSTOM,
                                    sp->name);
-                               /* Custom binding; validate spawn. */
-                               sp->flags ^= SWM_SPAWN_OPTIONAL;
                                return (0);
                        } else
                                return (1);
@@ -6434,24 +6473,25 @@ clear_keys(void)
 int
 setkeymapping(char *selector, char *value, int flags)
 {
-       char                    keymapping_file[PATH_MAX];
+       char                    *keymapping_file;
 
        /* suppress unused warnings since vars are needed */
        (void)selector;
        (void)flags;
 
        DNPRINTF(SWM_D_KEY, "setkeymapping: enter\n");
-       if (value[0] == '~')
-               snprintf(keymapping_file, sizeof keymapping_file, "%s/%s",
-                   pwd->pw_dir, &value[1]);
-       else
-               strlcpy(keymapping_file, value, sizeof keymapping_file);
+
+       keymapping_file = expand_tilde(value);
+
        clear_keys();
        /* load new key bindings; if it fails, revert to default bindings */
        if (conf_load(keymapping_file, SWM_CONF_KEYMAPPING)) {
                clear_keys();
                setup_keys();
        }
+
+       free(keymapping_file);
+
        DNPRINTF(SWM_D_KEY, "setkeymapping: leave\n");
        return (0);
 }
@@ -6502,7 +6542,7 @@ grabkeys(void)
        modifiers[2] = XCB_MOD_MASK_LOCK;
        modifiers[3] = numlockmask | XCB_MOD_MASK_LOCK;
 
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
        for (k = 0; k < num_screens; k++) {
                if (TAILQ_EMPTY(&screens[k].rl))
                        continue;
@@ -6555,6 +6595,8 @@ const char *quirkname[] = {
        "XTERM_FONTADJ",
        "FULLSCREEN",
        "FOCUSPREV",
+       "NOFOCUSONMAP",
+       "FOCUSONMAP_SINGLE",
 };
 
 /* SWM_Q_WS: retain '|' for back compat for now (2009-08-11) */
@@ -6786,7 +6828,7 @@ setconfvalue(char *selector, char *value, int flags)
                        errx(1, "setconfvalue: bar_enabled_ws: invalid "
                            "workspace %d.", ws_id + 1);
 
-               num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+               num_screens = get_screen_count();
                for (i = 0; i < num_screens; i++) {
                        ws = (struct workspace *)&screens[i].ws;
                        ws[ws_id].bar_enabled = atoi(value);
@@ -7117,7 +7159,7 @@ setlayout(char *selector, char *value, int flags)
                    "<master_grow>:<master_add>:<stack_inc>:<always_raise>:"
                    "<type>'");
 
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
        for (i = 0; i < num_screens; i++) {
                ws = (struct workspace *)&screens[i].ws;
                ws[ws_id].cur_layout = &layouts[st];
@@ -7257,6 +7299,9 @@ conf_load(const char *filename, int keymapping)
                warnx("conf_load: no filename");
                return (1);
        }
+
+       DNPRINTF(SWM_D_CONF, "conf_load: open %s\n", filename);
+
        if ((config = fopen(filename, "r")) == NULL) {
                warn("conf_load: fopen: %s", filename);
                return (1);
@@ -7762,7 +7807,7 @@ expose(xcb_expose_event_t *e)
 
        DNPRINTF(SWM_D_EVENT, "expose: window: 0x%x\n", e->window);
 
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
        for (i = 0; i < num_screens; i++)
                TAILQ_FOREACH(r, &screens[i].rl, entry)
                        if (e->window == WINID(r->bar))
@@ -8298,7 +8343,7 @@ mappingnotify(xcb_mapping_notify_event_t *e)
 void
 maprequest(xcb_map_request_event_t *e)
 {
-       struct ws_win           *win;
+       struct ws_win           *win, *w = NULL;
        xcb_get_window_attributes_reply_t *war;
 
        DNPRINTF(SWM_D_EVENT, "maprequest: win 0x%x\n",
@@ -8322,8 +8367,25 @@ maprequest(xcb_map_request_event_t *e)
            (war->map_state == XCB_MAP_STATE_VIEWABLE));
 
        /* The new window should get focus; prepare. */
-       if (focus_mode != SWM_FOCUS_FOLLOW)
-               win->ws->focus_pending = get_focus_magic(win);
+       if (focus_mode != SWM_FOCUS_FOLLOW &&
+           !(win->quirks & SWM_Q_NOFOCUSONMAP)) {
+               if (win->quirks & SWM_Q_FOCUSONMAP_SINGLE) {
+                       /* See if other wins of same type are already mapped. */
+                       TAILQ_FOREACH(w, &win->ws->winlist, entry) {
+                               if (w == win || !w->mapped)
+                                       continue;
+
+                               if (!strcmp(w->ch.class_name,
+                                   win->ch.class_name) &&
+                                   !strcmp(w->ch.instance_name,
+                                   win->ch.instance_name))
+                                       break;
+                       }
+               }
+
+               if (w == NULL)
+                       win->ws->focus_pending = get_focus_magic(win);
+       }
 
        /* All windows need to be mapped if they are in the current workspace.*/
        if (win->ws->r)
@@ -8353,7 +8415,7 @@ motionnotify(xcb_motion_notify_event_t *e)
 
        last_event_time = e->time;
 
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
        for (i = 0; i < num_screens; i++)
                if (screens[i].root == e->root)
                        break;
@@ -8645,7 +8707,7 @@ enable_wm(void)
        xcb_generic_error_t     *error;
 
        /* this causes an error if some other window manager is running */
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
        for (i = 0; i < num_screens; i++) {
                if ((sc = get_screen(i)) == NULL)
                        errx(1, "ERROR: can't get screen %d.", i);
@@ -8777,7 +8839,7 @@ scan_xrandr(int i)
        if ((screen = get_screen(i)) == NULL)
                errx(1, "ERROR: can't get screen %d.", i);
 
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
        if (i >= num_screens)
                errx(1, "scan_xrandr: invalid screen");
 
@@ -8858,7 +8920,7 @@ screenchange(xcb_randr_screen_change_notify_event_t *e)
 
        DNPRINTF(SWM_D_EVENT, "screenchange: root: 0x%x\n", e->root);
 
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
        /* silly event doesn't include the screen index */
        for (i = 0; i < num_screens; i++)
                if (screens[i].root == e->root)
@@ -8909,7 +8971,7 @@ grab_windows(void)
        xcb_get_property_cookie_t               pc;
 
        DNPRINTF(SWM_D_INIT, "grab_windows: begin\n");
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
        for (i = 0; i < num_screens; i++) {
                qtc = xcb_query_tree(conn, screens[i].root);
                qtr = xcb_query_tree_reply(conn, qtc, NULL);
@@ -9007,7 +9069,7 @@ setup_screens(void)
        xcb_randr_query_version_cookie_t        c;
        xcb_randr_query_version_reply_t         *r;
 
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
        if ((screens = calloc(num_screens,
             sizeof(struct swm_screen))) == NULL)
                err(1, "setup_screens: calloc: failed to allocate memory for "
@@ -9126,7 +9188,7 @@ workaround(void)
        /* work around sun jdk bugs, code from wmname */
        netwmcheck = get_atom_from_string("_NET_SUPPORTING_WM_CHECK");
 
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
        for (i = 0; i < num_screens; i++) {
                root = screens[i].root;
 
@@ -9161,7 +9223,7 @@ shutdown_cleanup(void)
 
        teardown_ewmh();
 
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
        for (i = 0; i < num_screens; ++i) {
                if (screens[i].bar_gc != 0)
                        xcb_free_gc(conn, screens[i].bar_gc);
@@ -9380,7 +9442,7 @@ noconfig:
                setenv("SWM_STARTED", "YES", 1);
 
        /* setup all bars */
-       num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
+       num_screens = get_screen_count();
        for (i = 0; i < num_screens; i++)
                TAILQ_FOREACH(r, &screens[i].rl, entry)
                        bar_setup(r);
@@ -9442,11 +9504,11 @@ noconfig:
 
                if (stdin_ready) {
                        stdin_ready = 0;
-                       if (bar_extra_update()) {
-                               bar_draw();
-                               xcb_flush(conn);
-                       }
+                       bar_extra_update();
                }
+
+               bar_draw();
+               xcb_flush(conn);
        }
 done:
        shutdown_cleanup();