X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=spectrwm.c;h=059c2ac5182ab271ca5d3a6f71feca0b7fed9b5c;hb=fedd800f2a1e4dddc024d4559e2cec299e8c541c;hp=42c8bd22665a0d32b44307be8c43e2163378a8bd;hpb=3543a15189b01981db4666dfe2b7b8f9924a4f1b;p=spectrwm.git diff --git a/spectrwm.c b/spectrwm.c index 42c8bd2..059c2ac 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -386,6 +386,8 @@ int bar_font_legacy = 1; char *bar_fonts; XftColor bar_font_color; struct passwd *pwd; +char *startup_exception; +unsigned int nr_exceptions = 0; /* layout manager data */ struct swm_geometry { @@ -608,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); @@ -705,12 +709,15 @@ struct cursors { {"top_right_corner", XC_top_right_corner, XCB_CURSOR_NONE}, }; +#define SWM_SPAWN_OPTIONAL 0x1 + /* spawn */ struct spawn_prog { TAILQ_ENTRY(spawn_prog) entry; char *name; int argc; char **argv; + int flags; }; TAILQ_HEAD(spawn_list, spawn_prog); struct spawn_list spawns = TAILQ_HEAD_INITIALIZER(spawns); @@ -855,8 +862,7 @@ void bar_print(struct swm_region *, const char *); void bar_print_legacy(struct swm_region *, const char *); void bar_replace(char *, char *, struct swm_region *, size_t); void bar_replace_pad(char *, int *, size_t); -char * bar_replace_seq(char *, char *, struct swm_region *, size_t *, - size_t); +char *bar_replace_seq(char *, char *, struct swm_region *, size_t *, size_t); void bar_setup(struct swm_region *); void bar_title_name(char *, size_t, struct swm_region *); void bar_toggle(struct swm_region *, union arg *); @@ -1007,7 +1013,7 @@ int setkeymapping(char *, char *, int); int setlayout(char *, char *, int); void setquirk(const char *, const char *, unsigned long); void setscreencolor(char *, int, int); -void setspawn(const char *, const char *); +void setspawn(const char *, const char *, int); void setup_ewmh(void); void setup_globals(void); void setup_keys(void); @@ -1024,15 +1030,15 @@ void sort_windows(struct ws_win_list *); void spawn(int, union arg *, int); void spawn_custom(struct swm_region *, union arg *, const char *); int spawn_expand(struct swm_region *, union arg *, const char *, char ***); -void spawn_insert(const char *, const char *); +void spawn_insert(const char *, const char *, int); void spawn_remove(struct spawn_prog *); -void spawn_replace(struct spawn_prog *, const char *, const char *); +void spawn_replace(struct spawn_prog *, const char *, const char *, int); void spawn_select(struct swm_region *, union arg *, const char *, int *); void stack_config(struct swm_region *, union arg *); void stack_floater(struct ws_win *, struct swm_region *); void stack_master(struct workspace *, struct swm_geometry *, int, int); void store_float_geom(struct ws_win *, struct swm_region *); -char * strdupsafe(const char *); +char *strdupsafe(const char *); void swapwin(struct swm_region *, union arg *); void switchws(struct swm_region *, union arg *); void teardown_ewmh(void); @@ -1045,6 +1051,7 @@ void unmap_window(struct ws_win *); void updatenumlockmask(void); void update_modkey(unsigned int); void update_window(struct ws_win *); +void validate_spawns(void); int validate_win(struct ws_win *); int validate_ws(struct workspace *); /*void visibilitynotify(xcb_visibility_notify_event_t *);*/ @@ -1053,6 +1060,8 @@ pid_t window_get_pid(xcb_window_t); void wkill(struct swm_region *, union arg *); void workaround(void); void xft_init(struct swm_region *); +void _add_startup_exception(const char *, va_list); +void add_startup_exception(const char *, ...); RB_PROTOTYPE(key_tree, key, entry, key_cmp); RB_GENERATE(key_tree, key, entry, key_cmp); @@ -2238,8 +2247,15 @@ bar_draw(void) continue; } - bar_fmt(fmtexp, fmtnew, r, sizeof fmtnew); - bar_replace(fmtnew, fmtrep, r, sizeof fmtrep); + if (startup_exception) + snprintf(fmtrep, sizeof fmtrep, "total " + "exceptions: %d, first exception: %s", + nr_exceptions, + startup_exception); + else { + bar_fmt(fmtexp, fmtnew, r, sizeof fmtnew); + bar_replace(fmtnew, fmtrep, r, sizeof fmtrep); + } if (bar_font_legacy) bar_print_legacy(r, fmtrep); else @@ -2528,7 +2544,8 @@ bar_setup(struct swm_region *r) r->bar->id = xcb_generate_id(conn); wa[0] = r->s->c[SWM_S_COLOR_BAR].pixel; wa[1] = r->s->c[SWM_S_COLOR_BAR_BORDER_UNFOCUS].pixel; - wa[2] = XCB_EVENT_MASK_EXPOSURE; + wa[2] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_POINTER_MOTION | + XCB_EVENT_MASK_POINTER_MOTION_HINT; xcb_create_window(conn, XCB_COPY_FROM_PARENT, r->bar->id, r->s->root, X(r->bar), Y(r->bar), WIDTH(r->bar), HEIGHT(r->bar), @@ -4471,7 +4488,7 @@ max_stack(struct workspace *ws, struct swm_geometry *g) if (w->transient || w->iconic) continue; - if (!win->mapped && w != win) + if (!w->mapped && w != win) map_window(w); if (w->floating && !w->floatmaxed) { @@ -4712,7 +4729,7 @@ get_win_name(xcb_window_t win) free(r); /* Use WM_NAME instead; no UTF-8. */ c = xcb_get_property(conn, 0, win, XCB_ATOM_WM_NAME, - XCB_GET_PROPERTY_TYPE_ANY, 0, UINT_MAX); + XCB_GET_PROPERTY_TYPE_ANY, 0, UINT_MAX); r = xcb_get_property_reply(conn, c, NULL); if (!r) @@ -4724,7 +4741,7 @@ get_win_name(xcb_window_t win) } if (r->length > 0) name = strndup(xcb_get_property_value(r), - xcb_get_property_value_length(r)); + xcb_get_property_value_length(r)); free(r); } @@ -5310,6 +5327,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; @@ -5366,7 +5389,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"); @@ -5429,6 +5452,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); @@ -5438,7 +5467,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"); @@ -5497,6 +5526,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: @@ -5539,7 +5574,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"); @@ -5561,6 +5596,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); @@ -5570,6 +5611,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"); @@ -5914,7 +5956,7 @@ spawn_select(struct swm_region *r, union arg *args, const char *spawn_name, } void -spawn_insert(const char *name, const char *args) +spawn_insert(const char *name, const char *args, int flags) { char *arg, *cp, *ptr; struct spawn_prog *sp; @@ -5943,6 +5985,8 @@ spawn_insert(const char *name, const char *args) } free(cp); + sp->flags = flags; + TAILQ_INSERT_TAIL(&spawns, sp, entry); DNPRINTF(SWM_D_SPAWN, "spawn_insert: leave\n"); } @@ -5965,18 +6009,7 @@ spawn_remove(struct spawn_prog *sp) } void -spawn_replace(struct spawn_prog *sp, const char *name, const char *args) -{ - DNPRINTF(SWM_D_SPAWN, "spawn_replace: %s [%s]\n", sp->name, name); - - spawn_remove(sp); - spawn_insert(name, args); - - DNPRINTF(SWM_D_SPAWN, "spawn_replace: leave\n"); -} - -void -setspawn(const char *name, const char *args) +setspawn(const char *name, const char *args, int flags) { struct spawn_prog *sp; @@ -5985,38 +6018,31 @@ setspawn(const char *name, const char *args) if (name == NULL) return; - TAILQ_FOREACH(sp, &spawns, entry) { + /* Remove any old spawn under the same name. */ + TAILQ_FOREACH(sp, &spawns, entry) if (!strcmp(sp->name, name)) { - if (*args == '\0') - spawn_remove(sp); - else - spawn_replace(sp, name, args); - DNPRINTF(SWM_D_SPAWN, "setspawn: leave\n"); - return; + spawn_remove(sp); + break; } - } - if (*args == '\0') { + + if (*args != '\0') + spawn_insert(name, args, flags); + else warnx("error: setspawn: cannot find program: %s", name); - return; - } - spawn_insert(name, args); DNPRINTF(SWM_D_SPAWN, "setspawn: leave\n"); } int setconfspawn(char *selector, char *value, int flags) { - char *args; - - /* suppress unused warning since var is needed */ - (void)flags; + char *args; args = expand_tilde(value); DNPRINTF(SWM_D_SPAWN, "setconfspawn: [%s] [%s]\n", selector, args); - setspawn(selector, args); + setspawn(selector, args, flags); free(args); DNPRINTF(SWM_D_SPAWN, "setconfspawn: done.\n"); @@ -6024,20 +6050,57 @@ setconfspawn(char *selector, char *value, int flags) } void +validate_spawns(void) +{ + struct spawn_prog *sp; + char which[PATH_MAX]; + size_t i; + + struct key *kp; + + RB_FOREACH(kp, key_tree, &keys) { + if (kp->funcid != KF_SPAWN_CUSTOM) + continue; + + /* find program */ + TAILQ_FOREACH(sp, &spawns, entry) { + if (!strcasecmp(kp->spawn_name, sp->name)) + break; + } + + if (sp == NULL || sp->flags & SWM_SPAWN_OPTIONAL) + continue; + + /* verify we have the goods */ + snprintf(which, sizeof which, "which %s", sp->argv[0]); + DNPRINTF(SWM_D_CONF, "validate_spawns: which %s\n", + sp->argv[0]); + for (i = strlen("which "); i < strlen(which); i++) + if (which[i] == ' ') { + which[i] = '\0'; + break; + } + if (system(which) != 0) + add_startup_exception("could not find %s", + &which[strlen("which ")]); + } +} + +void setup_spawn(void) { + setconfspawn("lock", "xlock", 0); + setconfspawn("term", "xterm", 0); setconfspawn("spawn_term", "xterm", 0); - setconfspawn("screenshot_all", "screenshot.sh full", 0); - setconfspawn("screenshot_wind", "screenshot.sh window", 0); - setconfspawn("lock", "xlock", 0); - setconfspawn("initscr", "initscreen.sh", 0); + setconfspawn("menu", "dmenu_run" " -fn $bar_font" " -nb $bar_color" " -nf $bar_font_color" " -sb $bar_border" " -sf $bar_color", 0); + setconfspawn("search", "dmenu" " -i" " -fn $bar_font" @@ -6045,6 +6108,7 @@ setup_spawn(void) " -nf $bar_font_color" " -sb $bar_border" " -sf $bar_color", 0); + setconfspawn("name_workspace", "dmenu" " -p Workspace" " -fn $bar_font" @@ -6052,6 +6116,11 @@ setup_spawn(void) " -nf $bar_font_color" " -sb $bar_border" " -sf $bar_color", 0); + + /* These are not verified for existence, even with a binding set. */ + setconfspawn("screenshot_all", "screenshot.sh full", SWM_SPAWN_OPTIONAL); + setconfspawn("screenshot_wind", "screenshot.sh window", SWM_SPAWN_OPTIONAL); + setconfspawn("initscr", "initscreen.sh", SWM_SPAWN_OPTIONAL); } /* key bindings */ @@ -6225,8 +6294,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); @@ -6237,8 +6306,8 @@ 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); @@ -6390,24 +6459,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); } @@ -6511,6 +6581,8 @@ const char *quirkname[] = { "XTERM_FONTADJ", "FULLSCREEN", "FOCUSPREV", + "NOFOCUSONMAP", + "FOCUSONMAP_SINGLE", }; /* SWM_Q_WS: retain '|' for back compat for now (2009-08-11) */ @@ -7173,11 +7245,36 @@ struct config_option configopt[] = { { "workspace_limit", setconfvalue, SWM_S_WORKSPACE_LIMIT }, }; +void +_add_startup_exception(const char *fmt, va_list ap) +{ + if (vasprintf(&startup_exception, fmt, ap) == -1) + warn("%s: asprintf", __func__); +} + +void +add_startup_exception(const char *fmt, ...) +{ + va_list ap; + + nr_exceptions++; + + if (startup_exception) + return; + + /* force bar to be enabled due to exception */ + bar_enabled = 1; + + va_start(ap, fmt); + _add_startup_exception(fmt, ap); + va_end(ap); +} + int conf_load(const char *filename, int keymapping) { FILE *config; - char *line, *cp, *optsub, *optval; + char *line = NULL, *cp, *optsub, *optval = NULL; size_t linelen, lineno = 0; int wordlen, i, optidx; struct config_option *opt = NULL; @@ -7188,14 +7285,20 @@ 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); } while (!feof(config)) { - if ((line = fparseln(config, &linelen, &lineno, NULL, 0)) - == NULL) { + if (line) + free(line); + + if ((line = fparseln(config, &linelen, &lineno, NULL, + FPARSELN_UNESCCOMM | FPARSELN_UNESCCONT)) == NULL) { if (ferror(config)) err(1, "%s", filename); else @@ -7205,15 +7308,14 @@ conf_load(const char *filename, int keymapping) cp += strspn(cp, " \t\n"); /* eat whitespace */ if (cp[0] == '\0') { /* empty line */ - free(line); continue; } /* get config option */ wordlen = strcspn(cp, "=[ \t\n"); if (wordlen == 0) { - warnx("%s: line %zd: no option found", + add_startup_exception("%s: line %zd: no option found", filename, lineno); - goto out; + continue; } optidx = -1; for (i = 0; i < LENGTH(configopt); i++) { @@ -7225,17 +7327,20 @@ conf_load(const char *filename, int keymapping) } } if (optidx == -1) { - warnx("%s: line %zd: unknown option %.*s", - filename, lineno, wordlen, cp); - goto out; + add_startup_exception("%s: line %zd: unknown option " + "%.*s", filename, lineno, wordlen, cp); + continue; } if (keymapping && opt && strcmp(opt->optname, "bind")) { - warnx("%s: line %zd: invalid option %.*s", - filename, lineno, wordlen, cp); - goto out; + add_startup_exception("%s: line %zd: invalid option " + "%.*s", filename, lineno, wordlen, cp); + continue; } cp += wordlen; cp += strspn(cp, " \t\n"); /* eat whitespace */ + + /* from here on out we call goto invalid to continue */ + /* get [selector] if any */ optsub = NULL; if (*cp == '[') { @@ -7243,17 +7348,17 @@ conf_load(const char *filename, int keymapping) wordlen = strcspn(cp, "]"); if (*cp != ']') { if (wordlen == 0) { - warnx("%s: line %zd: syntax error", - filename, lineno); - goto out; + add_startup_exception("%s: line %zd: " + "syntax error", filename, lineno); + goto invalid; } if (asprintf(&optsub, "%.*s", wordlen, cp) == -1) { - warnx("%s: line %zd: unable to allocate" - "memory for selector", filename, - lineno); - goto out; + add_startup_exception("%s: line %zd: " + "unable to allocatememory for " + "selector", filename, lineno); + goto invalid; } } cp += wordlen; @@ -7262,27 +7367,36 @@ conf_load(const char *filename, int keymapping) cp += strspn(cp, "= \t\n"); /* eat trailing */ /* get RHS value */ optval = strdup(cp); + if (strlen(optval) == 0) { + add_startup_exception("%s: line %zd: must supply value " + "to %s", filename, lineno, + configopt[optidx].optname); + goto invalid; + } /* call function to deal with it all */ if (configopt[optidx].func(optsub, optval, - configopt[optidx].funcflags) != 0) - errx(1, "%s: line %zd: invalid data for %s", - filename, lineno, configopt[optidx].optname); - free(optval); - free(optsub); - free(line); + configopt[optidx].funcflags) != 0) { + add_startup_exception("%s: line %zd: invalid data for " + "%s", filename, lineno, configopt[optidx].optname); + goto invalid; + } +invalid: + if (optval) { + free(optval); + optval = NULL; + } + if (optsub) { + free(optsub); + optsub = NULL; + } } + if (line) + free(line); fclose(config); DNPRINTF(SWM_D_CONF, "conf_load: end\n"); return (0); - -out: - free(line); - fclose(config); - DNPRINTF(SWM_D_CONF, "conf_load: end with error.\n"); - - return (1); } void @@ -8146,7 +8260,7 @@ enternotify(xcb_enter_notify_event_t *e) /* If no windows on pointer region, then focus root. */ r = root_to_region(e->root, SWM_CK_POINTER); if (r == NULL) { - DNPRINTF(SWM_D_EVENT, "enterntoify: " + DNPRINTF(SWM_D_EVENT, "enternotify: " "NULL region; ignoring.\n"); return; } @@ -8161,7 +8275,7 @@ enternotify(xcb_enter_notify_event_t *e) focus_win(get_focus_magic(win)); } - focus_flush(); + xcb_flush(conn); } #ifdef SWM_DEBUG @@ -8215,7 +8329,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", @@ -8239,8 +8353,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) @@ -8680,6 +8811,7 @@ scan_xrandr(int i) int ncrtc = 0; #endif /* SWM_XRR_HAS_CRTC */ struct swm_region *r; + struct ws_win *win; int num_screens; xcb_randr_get_screen_resources_current_cookie_t src; xcb_randr_get_screen_resources_current_reply_t *srr; @@ -8753,6 +8885,16 @@ scan_xrandr(int i) screen->height_in_pixels); out: + /* Cleanup unused previously visible workspaces. */ + TAILQ_FOREACH(r, &screens[i].orl, entry) { + TAILQ_FOREACH(win, &r->ws->winlist, entry) + unmap_window(win); + + /* The screen shouldn't focus on an unused region. */ + if (screens[i].r_focus == r) + screens[i].r_focus = NULL; + } + DNPRINTF(SWM_D_MISC, "scan_xrandr: done.\n"); } @@ -8779,10 +8921,22 @@ screenchange(xcb_randr_screen_change_notify_event_t *e) print_win_geom(e->root); #endif /* add bars to all regions */ - for (i = 0; i < num_screens; i++) + for (i = 0; i < num_screens; i++) { TAILQ_FOREACH(r, &screens[i].rl, entry) bar_setup(r); + } + stack(); + + /* Make sure a region has focus on each screen. */ + for (i = 0; i < num_screens; i++) { + if (screens[i].r_focus == NULL) { + r = TAILQ_FIRST(&screens[i].rl); + if (r != NULL) + focus_region(r); + } + } + bar_draw(); focus_flush(); } @@ -9262,6 +9416,8 @@ noconfig: if (cfile) conf_load(cfile, SWM_CONF_DEFAULT); + validate_spawns(); + setup_ewmh(); /* set some values to work around bad programs */ workaround(); @@ -9334,11 +9490,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();