]> code.delx.au - spectrwm/blobdiff - spectrwm.c
Prepare for release 2.1.1.
[spectrwm] / spectrwm.c
index 16cb8b397f01c4284230ed27a87d59acb23e2b1c..606dcbe4ed9cfd11c72bfd872e837aa0350f3f74 100644 (file)
@@ -707,12 +707,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);
@@ -857,8 +860,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 *);
@@ -1009,7 +1011,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);
@@ -1026,15 +1028,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);
@@ -1047,6 +1049,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 *);*/
@@ -5322,6 +5325,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;
@@ -5378,7 +5387,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");
@@ -5441,6 +5450,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);
@@ -5450,7 +5465,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");
@@ -5509,6 +5524,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:
@@ -5551,7 +5572,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");
@@ -5573,6 +5594,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);
@@ -5582,6 +5609,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");
@@ -5926,7 +5954,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;
@@ -5955,6 +5983,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");
 }
@@ -5977,18 +6007,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;
 
@@ -5997,22 +6016,18 @@ 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");
 }
 
@@ -6020,42 +6035,70 @@ int
 setconfspawn(char *selector, char *value, int flags)
 {
        char            *args;
-       char            which[PATH_MAX];
-       size_t          i;
 
        args = expand_tilde(value);
 
        DNPRINTF(SWM_D_SPAWN, "setconfspawn: [%s] [%s]\n", selector, args);
 
-       /* verify we have the goods */
-       snprintf(which, sizeof which, "which %s", value);
-       for (i = strlen("which "); i < strlen(which); i++)
-               if (which[i] == ' ') {
-                       which[i] = '\0';
-                       break;
-               }
-       if (flags == 0 && system(which) != 0)
-               add_startup_exception("could not find %s",
-                   &which[strlen("which ")]);
-
-       setspawn(selector, args);
+       setspawn(selector, args, flags);
        free(args);
 
        DNPRINTF(SWM_D_SPAWN, "setconfspawn: done.\n");
        return (0);
 }
 
+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("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"
@@ -6063,6 +6106,7 @@ setup_spawn(void)
                                        " -nf $bar_font_color"
                                        " -sb $bar_border"
                                        " -sf $bar_color",      0);
+
        setconfspawn("name_workspace",  "dmenu"
                                        " -p Workspace"
                                        " -fn $bar_font"
@@ -6071,11 +6115,10 @@ setup_spawn(void)
                                        " -sb $bar_border"
                                        " -sf $bar_color",      0);
 
-       /* these are not verified for existence */
-       setconfspawn("lock",            "xlock",                1);
-       setconfspawn("screenshot_all",  "screenshot.sh full",   1);
-       setconfspawn("screenshot_wind", "screenshot.sh window", 1);
-       setconfspawn("initscr",         "initscreen.sh",        1);
+        /* 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 */
@@ -6266,6 +6309,8 @@ setconfbinding(char *selector, char *value, int flags)
                        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);
@@ -7226,7 +7271,7 @@ int
 conf_load(const char *filename, int keymapping)
 {
        FILE                    *config;
-       char                    *line = NULL, *cp, *optsub, *optval;
+       char                    *line = NULL, *cp, *optsub, *optval = NULL;
        size_t                  linelen, lineno = 0;
        int                     wordlen, i, optidx;
        struct config_option    *opt = NULL;
@@ -7246,8 +7291,8 @@ conf_load(const char *filename, int keymapping)
                if (line)
                        free(line);
 
-               if ((line = fparseln(config, &linelen, &lineno, NULL, 0))
-                   == NULL) {
+               if ((line = fparseln(config, &linelen, &lineno, NULL,
+                   FPARSELN_UNESCCOMM | FPARSELN_UNESCCONT)) == NULL) {
                        if (ferror(config))
                                err(1, "%s", filename);
                        else
@@ -8209,7 +8254,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;
                        }
@@ -8224,7 +8269,7 @@ enternotify(xcb_enter_notify_event_t *e)
                focus_win(get_focus_magic(win));
        }
 
-       focus_flush();
+       xcb_flush(conn);
 }
 
 #ifdef SWM_DEBUG
@@ -9348,6 +9393,8 @@ noconfig:
        if (cfile)
                conf_load(cfile, SWM_CONF_DEFAULT);
 
+       validate_spawns();
+
        setup_ewmh();
        /* set some values to work around bad programs */
        workaround();
@@ -9420,11 +9467,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();