summaryrefslogtreecommitdiffstats
path: root/desktop/bar/patches/bar-monitor-option.patch
blob: d5c5fafa0d14c688aa985bd836322ea6db44f5ac (plain)
diff --git a/README.pod b/README.pod
index 565f188..2d2075d 100644
--- a/README.pod
+++ b/README.pod
@@ -4,7 +4,7 @@ bar - bar ain't recursive
 
 =head1 SYNOPSIS
 
-I<bar> [-h | -g I<width>B<x>I<height>B<+>I<x> | -b | -d | -f I<font> | -p | -u I<pixel> | -B I<color> | -F I<color>]
+I<bar> [-h | -g I<width>B<x>I<height>B<+>I<x> | -m I<monitor>B<:>I<monitor>B<:>... | -b | -d | -f I<font> | -p | -u I<pixel> | -B I<color> | -F I<color>]
 
 =head1 DESCRIPTION
 
@@ -22,6 +22,10 @@ Display the help and exit.
 
 Set the window geometry. If a parameter is omitted it's filled with the default value.
 
+=item B<-m> I<monitor>B<:>I<monitor>B<:>I<...>
+
+Set monitors to be used and in what order. Positive numeric arguments only, separated by colons.
+
 =item B<-b>
 
 Dock the bar at the bottom of the screen.
diff --git a/bar.c b/bar.c
index 1ccc907..0f9f694 100644
--- a/bar.c
+++ b/bar.c
@@ -17,6 +17,8 @@
 #define max(a,b) ((a) > (b) ? (a) : (b))
 #define min(a,b) ((a) < (b) ? (a) : (b))
 #define indexof(c,s) (strchr((s),(c))-(s))
+#define MONITORS_MAX 32
+#define N 10
 
 typedef struct font_t {
     xcb_font_t ptr;
@@ -39,8 +41,6 @@ typedef struct area_t {
     char *cmd;
 } area_t;
 
-#define N 10
-
 typedef struct area_stack_t {
     int pos;
     area_t slot[N];
@@ -80,6 +80,9 @@ static char *mfont, *afont;
 static uint32_t fgc, bgc, ugc;
 static uint32_t dfgc, dbgc;
 static area_stack_t astack;
+static uint32_t mons = 0;
+static int nmons = 0;
+static int monlist[MONITORS_MAX];
 
 void
 update_gc (void)
@@ -302,7 +305,8 @@ parse (char *text)
 
     memset(&astack, 0, sizeof(area_stack_t));
 
-    fill_rect(cur_mon->pixmap, gc[GC_CLEAR], 0, 0, bw, bh);
+    for (monitor_t *m = monhead; m; m = m->next)
+        fill_rect(m->pixmap, gc[GC_CLEAR], 0, 0, bw, bh);
 
     for (;;) {
         if (*p == '\0' || *p == '\n')
@@ -356,7 +360,6 @@ parse (char *text)
 
                               p++;
                               pos_x = 0;
-                              fill_rect(cur_mon->pixmap, gc[GC_CLEAR], 0, 0, cur_mon->width, bh);
                               break;
 
                     /* In case of error keep parsing after the closing } */
@@ -562,14 +565,40 @@ rect_sort_cb (const void *p1, const void *p2)
 void
 monitor_create_chain (xcb_rectangle_t *rects, const int num)
 {
-    int width = bw;
+    int i, cnt;
+    int width = 0;
     int left = bx;
 
     /* Sort before use */
     qsort(rects, num, sizeof(xcb_rectangle_t), rect_sort_cb);
 
+    if (nmons) {
+        xcb_rectangle_t r[num];
+        /* Get combined width of specified monitors and set aside specified monitors */
+        for (i = cnt = 0; i < nmons; i++) {
+            if (monlist[i] >= num) {
+                fprintf(stderr, "Specified monitor %d not found\n", monlist[i]);
+                continue;
+            }
+            width += rects[monlist[i]].width;
+            memcpy(&r[cnt++], &rects[monlist[i]], sizeof(xcb_rectangle_t));
+        }
+        memcpy(rects, r, cnt * sizeof(xcb_rectangle_t));
+    }
+    else {
+        /* Else default to X screen width */
+        width = scr->width_in_pixels;
+        cnt = num;
+    }
+
+    /* If I fits I sits */
+    if (bw < 0)
+        bw = width - bx;
+    else
+        width = bw - bx;
+
     /* Left is a positive number or zero therefore monitors with zero width are excluded */
-    for (int i = 0; i < num; i++) {
+    for (int i = 0; i < cnt; i++) {
         if (rects[i].width > left) {
             monitor_t *mon = monitor_new(
                     rects[i].x + left,
@@ -598,7 +627,7 @@ get_randr_monitors (void)
 {
     xcb_randr_get_screen_resources_current_reply_t *rres_reply;
     xcb_randr_output_t *outputs;
-    int num, valid = 0;
+    int i, j, num, valid = 0;
 
     rres_reply = xcb_randr_get_screen_resources_current_reply(c,
             xcb_randr_get_screen_resources_current(c, scr->root), NULL);
@@ -621,7 +650,7 @@ get_randr_monitors (void)
     xcb_rectangle_t rects[num];
 
     /* Get all outputs */
-    for (int i = 0; i < num; i++) {
+    for (i = 0; i < num; i++) {
         xcb_randr_get_output_info_reply_t *oi_reply;
         xcb_randr_get_crtc_info_reply_t *ci_reply;
 
@@ -657,11 +686,11 @@ get_randr_monitors (void)
     free(rres_reply);
 
     /* Check for clones and inactive outputs */
-    for (int i = 0; i < num; i++) {
+    for (i = 0; i < num; i++) {
         if (rects[i].width == 0)
             continue;
 
-        for (int j = 0; j < num; j++) {
+        for (j = 0; j < num; j++) {
             /* Does I countain J ? */
 
             if (i != j && rects[j].width) {
@@ -679,7 +708,20 @@ get_randr_monitors (void)
         return;
     }
 
+    /* Use allocated array to pass to monitor_create_chain, the dynamic will out of scope */
+    xcb_rectangle_t *r = malloc(valid * sizeof(xcb_rectangle_t));
+    if (!r) {
+        fprintf(stderr, "Malloc failed!\n");
+        exit(EXIT_FAILURE);
+    }
+
+    /* Copy only used monitors */
+    for (i = j = 0; i < num && j < valid; i++)
+        if (rects[i].width)
+            memcpy(&r[j++], &rects[i], sizeof(xcb_rectangle_t));
+
     monitor_create_chain(rects, num);
+    free(r);
 }
 
 void
@@ -695,7 +737,11 @@ get_xinerama_monitors (void)
     iter = xcb_xinerama_query_screens_screen_info_iterator(xqs_reply);
     screens = iter.rem;
 
-    xcb_rectangle_t rects[screens];
+    xcb_rectangle_t *rects = malloc(screens * sizeof(xcb_rectangle_t));
+    if (!rects) {
+        fprintf(stderr, "Malloc failed!\n");
+        exit(EXIT_FAILURE);
+    }
 
     /* Fetch all the screens first */
     for (int i = 0; iter.rem; i++) {
@@ -709,6 +755,7 @@ get_xinerama_monitors (void)
     free(xqs_reply);
 
     monitor_create_chain(rects, screens);
+    free(rects);
 }
 
 xcb_visualid_t
@@ -755,10 +802,6 @@ xconn (void)
 void
 init (void)
 {
-    /* If I fits I sits */
-    if (bw < 0)
-        bw = scr->width_in_pixels - bx;
-
     /* Load the fonts */
     main_font = font_load(mfont ? mfont : "fixed");
     if (!main_font)
@@ -801,9 +844,14 @@ init (void)
         }
     }
 
-    if (!monhead)
+    if (!monhead) {
+        /* If I fits I sits */
+        if (bw < 0)
+            bw = scr->width_in_pixels - bx;
+
         /* If no RandR outputs or Xinerama screens, fall back to using whole screen */
         monhead = monitor_new(0, 0, bw, scr->height_in_pixels);
+    }
 
     if (!monhead)
         exit(EXIT_FAILURE);
@@ -921,6 +969,44 @@ parse_geometry_string (char *str, int *tmp)
     return true;
 }
 
+bool
+parse_monitor_string (char *str)
+{
+    char *p = str;
+    int i = 0, j;
+
+    if (!str || !*str)
+        return false;
+
+    while (*p) {
+        /* Skip separator */
+        if (*p == ':' || *p == ',')
+            if (!*++p)
+                break;
+        /* A digit must follow */
+        if (!isdigit(*p)) {
+            fprintf(stderr, "Invalid monitor specified\n");
+            return false;
+        }
+        /* Try to parse the number */
+        errno = 0;
+        j = strtoul(p, &p, 10);
+        if (errno || j >= MONITORS_MAX) {
+            fprintf(stderr, "Monitor value out of range\n");
+            return false;
+        }
+
+        if (j >= MONITORS_MAX || j < 0) {
+            fprintf(stderr, "Invalid monitor specified: %d\n", j);
+            continue;
+        }
+        mons |= 1 << j;
+        monlist[nmons++] = j;
+    }
+
+    return true;
+}
+
 void
 parse_font_list (char *str)
 {
@@ -968,12 +1054,13 @@ main (int argc, char **argv)
     ugc = fgc;
 
     char ch;
-    while ((ch = getopt(argc, argv, "hg:bdf:a:pu:B:F:")) != -1) {
+    while ((ch = getopt(argc, argv, "hg:m:bdf:a:pu:B:F:")) != -1) {
         switch (ch) {
             case 'h':
-                printf ("usage: %s [-h | -g | -b | -d | -f | -a | -p | -u | -B | -F]\n"
+                printf ("usage: %s [-h | -g | -m | -b | -d | -f | -a | -p | -u | -B | -F]\n"
                         "\t-h Show this help\n"
                         "\t-g Set the bar geometry {width}x{height})\n"
+                        "\t-m Set monitors to use and in what order {0:2:1...}\n"
                         "\t-b Put bar at the bottom of the screen\n"
                         "\t-d Force docking (use this if your WM isn't EWMH compliant)\n"
                         "\t-f Bar font list, comma separated\n"
@@ -983,6 +1070,7 @@ main (int argc, char **argv)
                         "\t-F Set foreground color in #AARRGGBB\n", argv[0]);
                 exit (EXIT_SUCCESS);
             case 'g': (void)parse_geometry_string(optarg, geom_v); break;
+            case 'm': (void)parse_monitor_string(optarg); break;
             case 'p': permanent = true; break;
             case 'b': topbar = false; break;
             case 'd': dock = true; break;
@@ -998,12 +1086,6 @@ main (int argc, char **argv)
     bh = geom_v[1];
     bx = geom_v[2];
 
-    /* Check the geometry */
-    if (bx >= scr->width_in_pixels || bx + bw > scr->width_in_pixels) {
-        fprintf(stderr, "The geometry specified doesn't fit the screen!\n");
-        return EXIT_FAILURE;
-    }
-
     /* Do the heavy lifting */
     init();
     /* Get the fd to Xserver */