JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
Support user-defined regions. Lets you split monster monitors into multiple
authorRyan McBride <mcbride@countersiege.com>
Sun, 1 Feb 2009 11:59:40 +0000 (11:59 +0000)
committerRyan McBride <mcbride@countersiege.com>
Sun, 1 Feb 2009 11:59:40 +0000 (11:59 +0000)
regions, or override scrotwm's multi-head autodetection (such as on video
drivers that do multihead without telling X).

Also a big step towards dynamic Xrandr support.

scrotwm.1
scrotwm.c
scrotwm.conf

index 02c3e47..a113d9b 100644 (file)
--- a/scrotwm.1
+++ b/scrotwm.1
@@ -184,6 +184,10 @@ is used.
 Some applications have dialogue windows that are too small to be useful.
 This ratio is the screen size to what they will be resized.
 For example, 0.6 is 60% of the physical screen size.
 Some applications have dialogue windows that are too small to be useful.
 This ratio is the screen size to what they will be resized.
 For example, 0.6 is 60% of the physical screen size.
+.It Cm region
+Allocates a custom region, removing any autodetected regions which occupy the same
+space on the screen.
+Defined in the format screen[<idx>]:WIDTHxHEIGHT+X+Y, e.g. screen[1]:800x1200+0+0.
 .It Cm screenshot_enabled
 Enable or disable screenshot capability.
 .It Cm screenshot_app
 .It Cm screenshot_enabled
 Enable or disable screenshot capability.
 .It Cm screenshot_app
index e129b42..572be96 100644 (file)
--- a/scrotwm.c
+++ b/scrotwm.c
@@ -206,9 +206,9 @@ struct workspace;
 struct swm_region {
        TAILQ_ENTRY(swm_region) entry;
        struct swm_geometry     g;
 struct swm_region {
        TAILQ_ENTRY(swm_region) entry;
        struct swm_geometry     g;
-       Window                  bar_window;
        struct workspace        *ws;    /* current workspace on this region */
        struct swm_screen       *s;     /* screen idx */
        struct workspace        *ws;    /* current workspace on this region */
        struct swm_screen       *s;     /* screen idx */
+       Window                  bar_window;
 }; 
 TAILQ_HEAD(swm_region_list, swm_region);
 
 }; 
 TAILQ_HEAD(swm_region_list, swm_region);
 
@@ -404,6 +404,36 @@ setscreencolor(char *val, int i, int c)
                    i, ScreenCount(display));
 }
 
                    i, ScreenCount(display));
 }
 
+void           new_region(struct swm_screen *, struct workspace *,
+                           int, int, int, int);
+
+void
+custom_region(char *val)
+{
+       unsigned int                    sidx, x, y, w, h;
+
+       if (sscanf(val, "screen[%u]:%ux%u+%u+%u", &sidx, &w, &h, &x, &y) != 5)
+               errx(1, "invalid custom region, "
+                   "should be 'screen[<n>]:<n>x<n>+<n>+<n>\n");
+       if (sidx < 1 || sidx > ScreenCount(display))
+               errx(1, "invalid screen index: %d out of bounds (maximum %d)\n",
+                   sidx, ScreenCount(display));
+       sidx--;
+
+       if (w < 1 || h < 1)
+               errx(1, "region %ux%u+%u+%u too small\n", w, h, x, y);
+
+       if (x  < 0 || x > DisplayWidth(display, sidx) ||
+           y < 0 || y > DisplayHeight(display, sidx) ||
+           w + x > DisplayWidth(display, sidx) ||
+           h + y > DisplayHeight(display, sidx))
+               errx(1, "region %ux%u+%u+%u not within screen boundaries "
+                   "(%ux%u)\n", w, h, x, y,
+                   DisplayWidth(display, sidx), DisplayHeight(display, sidx));
+           
+       new_region(&screens[sidx], NULL, x, y, w, h);
+}
+
 int
 varmatch(char *var, char *name, int *index)
 {
 int
 varmatch(char *var, char *name, int *index)
 {
@@ -510,6 +540,13 @@ conf_load(char *filename)
                                goto bad;
                        break;
 
                                goto bad;
                        break;
 
+               case 'r':
+                       if (!strncmp(var, "region", strlen("region")))
+                               custom_region(val);
+                       else
+                               goto bad;
+                       break;
+
                case 's':
                        if (!strncmp(var, "spawn_term", strlen("spawn_term")))
                                asprintf(&spawn_term[0], "%s", val);
                case 's':
                        if (!strncmp(var, "spawn_term", strlen("spawn_term")))
                                asprintf(&spawn_term[0], "%s", val);
@@ -975,7 +1012,7 @@ switchws(struct swm_region *r, union arg *args)
        old_ws = this_r->ws;
        new_ws = &this_r->s->ws[wsid];
 
        old_ws = this_r->ws;
        new_ws = &this_r->s->ws[wsid];
 
-       DNPRINTF(SWM_D_WS, "switchws screen %d region %dx%d+%d+%d: "
+       DNPRINTF(SWM_D_WS, "switchws screen[%d]:%dx%d+%d+%d: "
            "%d -> %d\n", r->s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r),
            old_ws->idx, wsid);
 
            "%d -> %d\n", r->s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r),
            old_ws->idx, wsid);
 
@@ -1015,7 +1052,7 @@ cyclews(struct swm_region *r, union arg *args)
        struct swm_screen       *s = r->s;
 
        DNPRINTF(SWM_D_WS, "cyclews id %d "
        struct swm_screen       *s = r->s;
 
        DNPRINTF(SWM_D_WS, "cyclews id %d "
-           "in screen %d region %dx%d+%d+%d ws %d\n", args->id,
+           "in screen[%d]:%dx%d+%d+%d ws %d\n", args->id,
            r->s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r), r->ws->idx);
 
        a.id = r->ws->idx;
            r->s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r), r->ws->idx);
 
        a.id = r->ws->idx;
@@ -2358,13 +2395,59 @@ getstate(Window w)
 }
 
 void
 }
 
 void
+remove_region(struct swm_region *r) 
+{
+       struct swm_screen       *s = r->s;
+       struct ws_win           *win;
+
+       DNPRINTF(SWM_D_MISC, "removing region: screen[%d]:%dx%d+%d+%d\n",
+            s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r));
+
+       TAILQ_FOREACH(win, &r->ws->winlist, entry)
+               XUnmapWindow(display, win->id);
+       r->ws->r = NULL;
+
+       XDestroyWindow(display, r->bar_window);
+       TAILQ_REMOVE(&s->rl, r, entry);
+       free(r);
+}
+
+void
 new_region(struct swm_screen *s, struct workspace *ws,
     int x, int y, int w, int h)
 {
 new_region(struct swm_screen *s, struct workspace *ws,
     int x, int y, int w, int h)
 {
-       struct swm_region       *r;
+       struct swm_region       *r, *n;
+       int                     i;
+
+       DNPRINTF(SWM_D_MISC, "new region: screen[%d]:%dx%d+%d+%d\n",
+            s->idx, w, h, x, y);
+
+       /* remove any conflicting regions */
+       n = TAILQ_FIRST(&s->rl);
+       while (n) {
+               r = n;
+               n = TAILQ_NEXT(r, entry);
+               if (X(r) < (x + w) &&
+                   (X(r) + WIDTH(r)) > x &&
+                   Y(r) < (y + h) &&
+                   (Y(r) + HEIGHT(r)) > y) {
+                       if (ws == NULL)
+                               ws = r->ws;
+                       remove_region(r);
+               }
+       }
 
 
-       DNPRINTF(SWM_D_MISC, "new region on screen %d: %dx%d (%d, %d)\n",
-            s->idx, x, y, w, h);
+       /* pick an appropriate workspace */
+       if (ws == NULL) {
+               for (i = 0; i < SWM_WS_MAX; i++)
+                       if (s->ws[i].r == NULL) {
+                               ws = &s->ws[i];
+                               break;
+                       }
+
+               if (ws == NULL)
+                       errx(1, "no free regions\n");
+       }
 
        if ((r = calloc(1, sizeof(struct swm_region))) == NULL)
                errx(1, "calloc: failed to allocate memory for screen");
 
        if ((r = calloc(1, sizeof(struct swm_region))) == NULL)
                errx(1, "calloc: failed to allocate memory for screen");
index 5dd4057..58047ac 100644 (file)
@@ -22,3 +22,8 @@ dialog_ratio          = 0.6
 # screen shots
 # screenshot_enabled   = 1
 # screenshot_app       = screenshot.sh
 # screen shots
 # screenshot_enabled   = 1
 # screenshot_app       = screenshot.sh
+
+# Split a non-Xrandr dual head setup into one region per monitor
+# (non-standard driver-based multihead is not seen by scrotwm)
+# region               = screen[1]:1280x1024+0+0
+# region               = screen[1]:1280x1024+1280+0