JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
Roll version for release
[spectrwm.git] / scrotwm.c
index 49dec92..7145108 100644 (file)
--- a/scrotwm.c
+++ b/scrotwm.c
@@ -1,6 +1,6 @@
 /* $scrotwm$ */
 /*
- * Copyright (c) 2009 Marco Peereboom <marco@peereboom.us>
+ * Copyright (c) 2009-2010 Marco Peereboom <marco@peereboom.us>
  * Copyright (c) 2009 Ryan McBride <mcbride@countersiege.com>
  * Copyright (c) 2009 Darrin Chandler <dwchandler@stilyagin.com>
  * Copyright (c) 2009 Pierre-Yves Ritschard <pyr@spootnik.org>
@@ -52,7 +52,7 @@
 
 static const char      *cvstag = "$scrotwm$";
 
-#define        SWM_VERSION     "0.9.25"
+#define        SWM_VERSION     "0.9.26"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -66,6 +66,7 @@ static const char     *cvstag = "$scrotwm$";
 #include <string.h>
 #include <util.h>
 #include <pwd.h>
+#include <paths.h>
 #include <ctype.h>
 
 #include <sys/types.h>
@@ -197,6 +198,7 @@ int                 bar_version = 0;
 sig_atomic_t           bar_alarm = 0;
 int                    bar_delay = 30;
 int                    bar_enabled = 1;
+int                    bar_at_bottom = 0;
 int                    bar_extra = 1;
 int                    bar_extra_running = 0;
 int                    bar_verbose = 1;
@@ -920,7 +922,12 @@ bar_refresh(void)
 void
 bar_setup(struct swm_region *r)
 {
-       int                     i;
+       int                     i, x, y;
+
+       if (bar_fs) {
+               XFreeFont(display, bar_fs);
+               bar_fs = NULL;
+       }
 
        for (i = 0; bar_fonts[i] != NULL; i++) {
                bar_fs = XLoadQueryFont(display, bar_fonts[i]);
@@ -931,10 +938,15 @@ bar_setup(struct swm_region *r)
        }
        if (bar_fonts[i] == NULL)
                        errx(1, "couldn't load font");
+       if (bar_fs == NULL)
+               errx(1, "couldn't create font structure");
+
        bar_height = bar_fs->ascent + bar_fs->descent + 3;
+       x = X(r);
+       y = bar_at_bottom ? (Y(r) + HEIGHT(r) - bar_height) : Y(r);
 
        r->bar_window = XCreateSimpleWindow(display,
-           r->s->root, X(r), Y(r), WIDTH(r) - 2, bar_height - 2,
+           r->s->root, x, y, WIDTH(r) - 2, bar_height - 2,
            1, r->s->c[SWM_S_COLOR_BAR_BORDER].color,
            r->s->c[SWM_S_COLOR_BAR].color);
        bar_gc = XCreateGC(display, r->bar_window, 0, &bar_gcv);
@@ -1097,9 +1109,8 @@ unmap_window(struct ws_win *win)
        set_win_state(win, IconicState);
 
        XUnmapWindow(display, win->id);
-       if (win->ws->r)
-               XSetWindowBorder(display, win->id,
-                   win->ws->r->s->c[SWM_S_COLOR_UNFOCUS].color);
+       XSetWindowBorder(display, win->id,
+           win->s->c[SWM_S_COLOR_UNFOCUS].color); 
 }
 
 void
@@ -1243,39 +1254,56 @@ find_window(Window id)
 void
 spawn(struct swm_region *r, union arg *args)
 {
-       char                    *ret;
-       int                     si;
+       int                     fd;
+       char                    *ret = NULL;
 
        DNPRINTF(SWM_D_MISC, "spawn: %s\n", args->argv[0]);
-       /*
-        * The double-fork construct avoids zombie processes and keeps the code
-        * clean from stupid signal handlers.
-        */
+
        if (fork() == 0) {
-               if (fork() == 0) {
-                       if (display)
-                               close(ConnectionNumber(display));
-                       setenv("LD_PRELOAD", SWM_LIB, 1);
-                       if (asprintf(&ret, "%d", r->ws->idx)) {
-                               setenv("_SWM_WS", ret, 1);
-                               free(ret);
-                       }
-                       if (asprintf(&ret, "%d", getpid())) {
-                               setenv("_SWM_PID", ret, 1);
-                               free(ret);
-                       }
-                       setsid();
-                       /* kill stdin, mplayer, ssh-add etc. need that */
-                       si = open("/dev/null", O_RDONLY, 0);
-                       if (si == -1)
-                               err(1, "open /dev/null");
-                       if (dup2(si, 0) == -1)
-                               err(1, "dup2 /dev/null");
-                       execvp(args->argv[0], args->argv);
-                       fprintf(stderr, "execvp failed\n");
-                       perror(" failed");
+               if (display)
+                       close(ConnectionNumber(display));
+
+               setenv("LD_PRELOAD", SWM_LIB, 1);
+
+               if (asprintf(&ret, "%d", r->ws->idx) == -1) {
+                       perror("_SWM_WS");
+                       _exit(1);
+               }
+               setenv("_SWM_WS", ret, 1);
+               free(ret);
+               ret = NULL;
+
+               if (asprintf(&ret, "%d", getpid()) == -1) {
+                       perror("_SWM_PID");
+                       _exit(1);
                }
-               exit(0);
+               setenv("_SWM_PID", ret, 1);
+               free(ret);
+               ret = NULL;
+
+               if (setsid() == -1) {
+                       perror("setsid");
+                       _exit(1);
+               }
+
+               /*
+                * close stdin and stdout to prevent interaction between apps
+                * and the baraction script
+                * leave stderr open to record errors
+               */
+               if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1) {
+                       perror("open");
+                       _exit(1);
+               }
+               dup2(fd, STDIN_FILENO);
+               dup2(fd, STDOUT_FILENO);
+               if (fd > 2)
+                       close(fd);
+
+               execvp(args->argv[0], args->argv);
+
+               perror("execvp");
+               _exit(1);
        }
 }
 
@@ -1363,7 +1391,7 @@ unfocus_win(struct ws_win *win)
                return;
 
        if (validate_ws(win->ws))
-               abort();
+               abort(); /* XXX replace with return at some point */
 
        if (win->ws->r == NULL)
                return;
@@ -1428,7 +1456,8 @@ focus_win(struct ws_win *win)
                return;
 
        if (validate_ws(win->ws))
-               abort();
+               abort(); /* XXX replace with return at some point */
+
        if (validate_win(win)) {
                kill_refs(win);
                return;
@@ -1597,7 +1626,7 @@ cyclescr(struct swm_region *r, union arg *args)
 
        /* move mouse to region */
        x = rr->g.x + 1;
-       y = rr->g.y + 1 + bar_enabled ? bar_height : 0;
+       y = rr->g.y + 1 + (bar_enabled ? bar_height : 0);
        XWarpPointer(display, None, rr->s[i].root, 0, 0, 0, 0, x, y);
 
        a.id = SWM_ARG_ID_FOCUSCUR;
@@ -1714,10 +1743,10 @@ focus_prev(struct ws_win *win)
 
        /* if in max_stack try harder */
        if (ws->cur_layout->flags & SWM_L_FOCUSPREV) {
-               if (cur_focus != ws->focus_prev)
-                       winfocus = ws->focus_prev;
-               else if (cur_focus != ws->focus)
-                       winfocus = ws->focus;
+               if (cur_focus != ws->focus_prev)
+                       winfocus = ws->focus_prev;
+               else if (cur_focus != ws->focus)
+                       winfocus = ws->focus;
                else
                        winfocus = TAILQ_PREV(win, ws_win_list, entry);
                if (winfocus)
@@ -1771,7 +1800,7 @@ focus(struct swm_region *r, union arg *args)
        winlostfocus = cur_focus;
 
        switch (args->id) {
-       case SWM_ARG_ID_FOCUSPREV:
+       case SWM_ARG_ID_FOCUSPREV:
                winfocus = TAILQ_PREV(cur_focus, ws_win_list, entry);
                if (winfocus == NULL)
                        winfocus = TAILQ_LAST(wl, ws_win_list);
@@ -1854,7 +1883,8 @@ stack(void) {
                        g.w -= 2;
                        g.h -= 2;
                        if (bar_enabled) {
-                               g.y += bar_height;
+                               if (!bar_at_bottom)
+                                       g.y += bar_height;
                                g.h -= bar_height;
                        }
                        r->ws->cur_layout->l_stack(r->ws, &g);
@@ -3529,7 +3559,8 @@ enum      { SWM_S_BAR_DELAY, SWM_S_BAR_ENABLED, SWM_S_STACK_ENABLED,
          SWM_S_CYCLE_VISIBLE, SWM_S_SS_ENABLED, SWM_S_TERM_WIDTH,
          SWM_S_TITLE_CLASS_ENABLED, SWM_S_TITLE_NAME_ENABLED,
          SWM_S_FOCUS_MODE, SWM_S_DISABLE_BORDER, SWM_S_BAR_FONT,
-         SWM_S_BAR_ACTION, SWM_S_SPAWN_TERM, SWM_S_SS_APP, SWM_S_DIALOG_RATIO
+         SWM_S_BAR_ACTION, SWM_S_SPAWN_TERM, SWM_S_SS_APP, SWM_S_DIALOG_RATIO,
+         SWM_S_BAR_AT_BOTTOM
        };
 
 int
@@ -3542,6 +3573,9 @@ setconfvalue(char *selector, char *value, int flags)
        case SWM_S_BAR_ENABLED:
                bar_enabled = atoi(value);
                break;
+       case SWM_S_BAR_AT_BOTTOM:
+               bar_at_bottom = atoi(value);
+               break;
        case SWM_S_STACK_ENABLED:
                stack_enabled = atoi(value);
                break;
@@ -3652,6 +3686,7 @@ struct config_option {
 };
 struct config_option configopt[] = {
        { "bar_enabled",                setconfvalue,   SWM_S_BAR_ENABLED },
+       { "bar_at_bottom",              setconfvalue,   SWM_S_BAR_AT_BOTTOM },
        { "bar_border",                 setconfcolor,   SWM_S_COLOR_BAR_BORDER },
        { "bar_color",                  setconfcolor,   SWM_S_COLOR_BAR },
        { "bar_font_color",             setconfcolor,   SWM_S_COLOR_BAR_FONT },
@@ -4036,9 +4071,17 @@ focus_magic(struct ws_win *win, int do_trans)
                        if (win->child_trans->take_focus)
                                client_msg(win, takefocus);
                } else {
-                       focus_win(win->child_trans);
-                       if (win->child_trans->take_focus)
-                               client_msg(win->child_trans, takefocus);
+                       /* make sure transient hasn't dissapeared */
+                       if (validate_win(win->child_trans) == 0) {
+                               focus_win(win->child_trans);
+                               if (win->child_trans->take_focus)
+                                       client_msg(win->child_trans, takefocus);
+                       } else {
+                               win->child_trans = NULL;
+                               focus_win(win);
+                               if (win->take_focus)
+                                       client_msg(win, takefocus);
+                       }
                }
        } else {
                /* regular focus */
@@ -4571,6 +4614,7 @@ new_region(struct swm_screen *s, int x, int y, int w, int h)
        r->ws = ws;
        r->ws_prior = NULL;
        ws->r = r;
+       outputs++;
        TAILQ_INSERT_TAIL(&s->rl, r, entry);
 }
 
@@ -4596,10 +4640,10 @@ scan_xrandr(int i)
                TAILQ_REMOVE(&screens[i].rl, r, entry);
                TAILQ_INSERT_TAIL(&screens[i].orl, r, entry);
        }
+       outputs = 0;
 
        /* map virtual screens onto physical screens */
 #ifdef SWM_XRR_HAS_CRTC
-       outputs = 0;
        if (xrandr_support) {
                sr = XRRGetScreenResources(display, screens[i].root);
                if (sr == NULL)
@@ -4613,7 +4657,6 @@ scan_xrandr(int i)
                        ci = XRRGetCrtcInfo(display, sr, sr->crtcs[c]);
                        if (ci->noutput == 0)
                                continue;
-                       outputs++;
 
                        if (ci != NULL && ci->mode == None)
                                new_region(&screens[i], 0, 0,
@@ -4930,7 +4973,7 @@ main(int argc, char *argv[])
                        if (ScreenCount(display) > 1 || outputs > 1)
                                XWarpPointer(display, None, rr->s[0].root,
                                    0, 0, 0, 0, rr->g.x,
-                                   rr->g.y + bar_enabled ? bar_height : 0);
+                                   rr->g.y + (bar_enabled ? bar_height : 0));
 
                        a.id = SWM_ARG_ID_FOCUSCUR;
                        focus(rr, &a);