JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
Bad mcbride leaking memory and char * in the wrong spot.
[spectrwm.git] / scrotwm.c
index 7831835..6a73a7f 100644 (file)
--- a/scrotwm.c
+++ b/scrotwm.c
@@ -216,6 +216,7 @@ struct ws_win {
        struct workspace        *ws;    /* always valid */
        struct swm_screen       *s;     /* always valid, never changes */
        XWindowAttributes       wa;
+       XSizeHints              sh;
 };
 TAILQ_HEAD(ws_win_list, ws_win);
 
@@ -784,6 +785,8 @@ find_window(Window id)
 void
 spawn(struct swm_region *r, union arg *args)
 {
+       char                    *ret;
+
        DNPRINTF(SWM_D_MISC, "spawn: %s\n", args->argv[0]);
        /*
         * The double-fork construct avoids zombie processes and keeps the code
@@ -791,14 +794,17 @@ spawn(struct swm_region *r, union arg *args)
         */
        if (fork() == 0) {
                if (fork() == 0) {
-                       char *ret;
                        if (display)
                                close(ConnectionNumber(display));
                        setenv("LD_PRELOAD", SWM_LIB, 1);
-                       if (asprintf(&ret, "%d", r->ws->idx))
+                       if (asprintf(&ret, "%d", r->ws->idx)) {
                                setenv("_SWM_WS", ret, 1);
-                       if (asprintf(&ret, "%d", getpid()))
+                               free(ret);
+                       }
+                       if (asprintf(&ret, "%d", getpid())) {
                                setenv("_SWM_PID", ret, 1);
+                               free(ret);
+                       }
                        setsid();
                        execvp(args->argv[0], args->argv);
                        fprintf(stderr, "execvp failed\n");
@@ -1130,46 +1136,25 @@ stack_floater(struct ws_win *win, struct swm_region *r)
        XConfigureWindow(display, win->id, mask, &wc);
 }
 
+#define SWAPXY(g)      do {                            \
+       int tmp;                                        \
+       tmp = (g)->y; (g)->y = (g)->x; (g)->x = tmp;    \
+       tmp = (g)->h; (g)->h = (g)->w; (g)->w = tmp;    \
+} while (0)
 void
-vertical_config(struct workspace *ws, int id)
+stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip)
 {
-       DNPRINTF(SWM_D_STACK, "vertical_resize: workspace: %d\n", ws->idx);
-
-       switch (id) {
-       case SWM_ARG_ID_STACKRESET:
-       case SWM_ARG_ID_STACKINIT:
-               ws->l_state.vertical_msize = SWM_V_SLICE / 2;
-               ws->l_state.vertical_mwin = 1;
-               break;
-       case SWM_ARG_ID_MASTERSHRINK:
-               if (ws->l_state.vertical_msize > 1)
-                       ws->l_state.vertical_msize--;
-               break;
-       case SWM_ARG_ID_MASTERGROW:
-               if (ws->l_state.vertical_msize < SWM_V_SLICE - 1)
-                       ws->l_state.vertical_msize++;
-               break;
-       case SWM_ARG_ID_MASTERADD:
-               ws->l_state.vertical_mwin++;
-               break;
-       case SWM_ARG_ID_MASTERDEL:
-               if (ws->l_state.vertical_mwin > 0)
-                       ws->l_state.vertical_mwin--;
-               break;
-       default:
-               return;
-       }
-}
-
-void
-vertical_stack(struct workspace *ws, struct swm_geometry *g) {
        XWindowChanges          wc;
-       struct swm_geometry     gg = *g;
+       struct swm_geometry     win_g, r_g = *g;
        struct ws_win           *win, *winfocus;
-       int                     i, j, split, colno, hrh, winno, main_width;
+       int                     i, j, w_inc, h_inc, w_base, h_base;
+       int                     hrh, extra, h_slice, last_h = 0;
+       int                     split, colno, winno, mwin, msize, mscale;
+       int                     remain, missing, v_slice;;
        unsigned int            mask;
 
-       DNPRINTF(SWM_D_STACK, "vertical_stack: workspace: %d\n", ws->idx);
+       DNPRINTF(SWM_D_STACK, "stack_master: workspace: %d\n rot=%s flip=%s",
+           ws->idx, rot ? "yes" : "no", flip ? "yes" : "no");
 
        if ((winno = count_win(ws, 0)) == 0)
                return;
@@ -1178,48 +1163,112 @@ vertical_stack(struct workspace *ws, struct swm_geometry *g) {
                ws->focus = TAILQ_FIRST(&ws->winlist);
        winfocus = cur_focus ? cur_focus : ws->focus;
 
-       if (ws->l_state.vertical_mwin &&
-           winno > ws->l_state.vertical_mwin) {
-               split = ws->l_state.vertical_mwin;
+       win = TAILQ_FIRST(&ws->winlist);
+       if (rot) {
+               w_inc = win->sh.width_inc;
+               w_base = win->sh.base_width;
+               mwin = ws->l_state.horizontal_mwin;
+               mscale = ws->l_state.horizontal_msize;
+               SWAPXY(&r_g);
+       } else {
+               w_inc = win->sh.height_inc;
+               w_base = win->sh.base_height;
+               mwin = ws->l_state.vertical_mwin;
+               mscale = ws->l_state.vertical_msize;
+       }
+       win_g = r_g;
+
+       h_slice = r_g.h / SWM_H_SLICE;
+       if (mwin && winno > mwin) {
+               v_slice = r_g.w / SWM_V_SLICE;
+
+               split = mwin;
                colno = split;
-               main_width = (g->w / SWM_V_SLICE) *
-                  ws->l_state.vertical_msize;
-               gg.w = main_width;
+               msize = v_slice * mscale;
+
+               if (w_inc > 1 && w_inc < v_slice) {
+                       /* adjust for window's requested size increment */
+                       remain = (win_g.w - w_base) % w_inc;
+                       missing = w_inc - remain;
+
+                       if (missing <= extra || j == 0) {
+                               extra -= missing;
+                               win_g.w += missing;
+                       } else {
+                               win_g.w -= remain;
+                               extra += remain;
+                       }
+               }
+
+               win_g.w = msize;
+               if (flip) 
+                       win_g.x += r_g.w - msize;
        } else {
                colno = winno;
                split = 0;
        }
-       hrh = g->h / colno;
-       gg.h = hrh - 2;
+       hrh = r_g.h / colno;
+       extra = r_g.h - (colno * hrh);
+       win_g.h = hrh - 2;
 
        i = j = 0;
        TAILQ_FOREACH(win, &ws->winlist, entry) {
                if (split && i == split) {
                        colno = winno - split;
-                       hrh = (g->h / colno);
-                       gg.x += main_width + 2;
-                       gg.w = g->w - (main_width + 2);
-                       gg.h = hrh - 2;
+                       hrh = (r_g.h / colno);
+                       extra = r_g.h - (colno * hrh);
+                       if (flip)
+                               win_g.x = r_g.x;
+                       else
+                               win_g.x += msize + 2;
+                       win_g.w = r_g.w - (msize + 2);
                        j = 0;
                }
-               if (j == colno - 1)
-                       gg.h = (hrh + (g->h - (colno * hrh)));
+               win_g.h = hrh - 2;
+               if (rot) {
+                       h_inc = win->sh.width_inc;
+                       h_base = win->sh.base_width;
+               } else {
+                       h_inc = win->sh.height_inc;     
+                       h_base = win->sh.base_height;
+               }
+               if (j == colno - 1) {
+                       win_g.h = hrh + extra;
+               } else if (h_inc > 1 && h_inc < h_slice) {
+                       /* adjust for window's requested size increment */
+                       remain = (win_g.h - h_base) % h_inc;
+                       missing = h_inc - remain;
+
+                       if (missing <= extra || j == 0) {
+                               extra -= missing;
+                               win_g.h += missing;
+                       } else {
+                               win_g.h -= remain;
+                               extra += remain;
+                       }
+               }
                 
                if (j == 0)
-                       gg.y = g->y;
+                       win_g.y = r_g.y;
                else
-                       gg.y += hrh;
-
+                       win_g.y += last_h + 2;
 
                if (win->transient != 0 || win->floating != 0)
                        stack_floater(win, ws->r);
                else {
                        bzero(&wc, sizeof wc);
                        wc.border_width = 1;
-                       win->g.x = wc.x = gg.x;
-                       win->g.y = wc.y = gg.y;
-                       win->g.w = wc.width = gg.w;
-                       win->g.h = wc.height = gg.h;
+                       if (rot) {
+                               win->g.x = wc.x = win_g.y;
+                               win->g.y = wc.y = win_g.x;
+                               win->g.w = wc.width = win_g.h;
+                               win->g.h = wc.height = win_g.w;
+                       } else {
+                               win->g.x = wc.x = win_g.x;
+                               win->g.y = wc.y = win_g.y;
+                               win->g.w = wc.width = win_g.w;
+                               win->g.h = wc.height = win_g.h;
+                       }
                        mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
                        XConfigureWindow(display, win->id, mask, &wc);
                        /*
@@ -1228,6 +1277,7 @@ vertical_stack(struct workspace *ws, struct swm_geometry *g) {
                }
 
                XMapRaised(display, win->id);
+               last_h = win_g.h;
                i++;
                j++;
        }
@@ -1237,6 +1287,45 @@ vertical_stack(struct workspace *ws, struct swm_geometry *g) {
 }
 
 void
+vertical_config(struct workspace *ws, int id)
+{
+       DNPRINTF(SWM_D_STACK, "vertical_resize: workspace: %d\n", ws->idx);
+
+       switch (id) {
+       case SWM_ARG_ID_STACKRESET:
+       case SWM_ARG_ID_STACKINIT:
+               ws->l_state.vertical_msize = SWM_V_SLICE / 2;
+               ws->l_state.vertical_mwin = 1;
+               break;
+       case SWM_ARG_ID_MASTERSHRINK:
+               if (ws->l_state.vertical_msize > 1)
+                       ws->l_state.vertical_msize--;
+               break;
+       case SWM_ARG_ID_MASTERGROW:
+               if (ws->l_state.vertical_msize < SWM_V_SLICE - 1)
+                       ws->l_state.vertical_msize++;
+               break;
+       case SWM_ARG_ID_MASTERADD:
+               ws->l_state.vertical_mwin++;
+               break;
+       case SWM_ARG_ID_MASTERDEL:
+               if (ws->l_state.vertical_mwin > 0)
+                       ws->l_state.vertical_mwin--;
+               break;
+       default:
+               return;
+       }
+}
+
+void
+vertical_stack(struct workspace *ws, struct swm_geometry *g)
+{
+       DNPRINTF(SWM_D_STACK, "vertical_stack: workspace: %d\n", ws->idx);
+
+       stack_master(ws, g, 0, 0);
+}
+
+void
 horizontal_config(struct workspace *ws, int id)
 {
        DNPRINTF(SWM_D_STACK, "horizontal_config: workspace: %d\n", ws->idx);
@@ -1268,74 +1357,11 @@ horizontal_config(struct workspace *ws, int id)
 }
 
 void
-horizontal_stack(struct workspace *ws, struct swm_geometry *g) {
-       XWindowChanges          wc;
-       struct swm_geometry     gg = *g;
-       struct ws_win           *win, *winfocus;
-       int                     i, j, split, rowno, hrw, winno, main_height;
-       unsigned int            mask;
-
-       DNPRINTF(SWM_D_STACK, "horizontal_stack: workspace: %d\n", ws->idx);
-
-       if ((winno = count_win(ws, 0)) == 0)
-               return;
-
-       if (ws->focus == NULL)
-               ws->focus = TAILQ_FIRST(&ws->winlist);
-       winfocus = cur_focus ? cur_focus : ws->focus;
-
-       if (ws->l_state.horizontal_mwin &&
-           winno > ws->l_state.horizontal_mwin) {
-               split = ws->l_state.horizontal_mwin;
-               rowno = split;
-               main_height = (g->h / SWM_V_SLICE) *
-                  ws->l_state.horizontal_msize;
-               gg.h = main_height;
-       } else {
-               rowno = winno;
-               split = 0;
-       }
-       hrw = g->w / rowno;
-       gg.w = hrw - 2;
-
-       i = j = 0;
-       TAILQ_FOREACH(win, &ws->winlist, entry) {
-               if (split && i == split) {
-                       rowno = winno - split;
-                       hrw = (g->w / rowno);
-                       gg.y += main_height + 2;
-                       gg.h = g->h - (main_height + 2);
-                       gg.w = hrw - 2;
-                       j = 0;
-               }
-               if (j == rowno - 1)
-                       gg.w = (hrw + (g->w - (rowno * hrw)));
-
-               if (j == 0)
-                       gg.x = g->x;
-               else
-                       gg.x += hrw;
-
-               if (win->transient != 0 || win->floating != 0)
-                       stack_floater(win, ws->r);
-               else {
-                       bzero(&wc, sizeof wc);
-                       wc.border_width = 1;
-                       win->g.x = wc.x = gg.x;
-                       win->g.y = wc.y = gg.y;
-                       win->g.w = wc.width = gg.w;
-                       win->g.h = wc.height = gg.h;
-                       mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
-                       XConfigureWindow(display, win->id, mask, &wc);
-               }
-
-               XMapRaised(display, win->id);
-               j++;
-               i++;
-       }
+horizontal_stack(struct workspace *ws, struct swm_geometry *g)
+{
+       DNPRINTF(SWM_D_STACK, "vertical_stack: workspace: %d\n", ws->idx);
 
-       if (winfocus)
-               focus_win(winfocus); /* this has to be done outside of the loop */
+       stack_master(ws, g, 1, 0);
 }
 
 /* fullscreen view */
@@ -1686,6 +1712,7 @@ manage_window(Window id)
        Atom                    ws_idx_atom = 0, type;
        unsigned char           ws_idx_str[SWM_PROPLEN], *prop = NULL;
        struct swm_region       *r;
+       long                    mask;
 
        if ((win = find_window(id)) != NULL)
                        return (win);   /* already being managed */
@@ -1733,6 +1760,8 @@ manage_window(Window id)
        win->g.x = win->wa.x;
        win->g.y = win->wa.y;
 
+       XGetWMNormalHints(display, win->id, &win->sh, &mask);
+
        if (ws_idx_atom && prop == NULL &&
            snprintf(ws_idx_str, SWM_PROPLEN, "%d", ws->idx) < SWM_PROPLEN) {
                DNPRINTF(SWM_D_PROP, "setting property _SWM_WS to %s\n",