]> git.lizzy.rs Git - bspwm.git/commitdiff
Added support for multiple monitors
authorBastien Dejean <nihilhill@gmail.com>
Wed, 17 Oct 2012 14:18:40 +0000 (16:18 +0200)
committerBastien Dejean <nihilhill@gmail.com>
Wed, 17 Oct 2012 14:18:40 +0000 (16:18 +0200)
16 files changed:
Makefile
README.md
bspwm.c
bspwm.h
events.c
ewmh.c
messages.c
messages.h
settings.c
settings.h
tree.c
tree.h
types.c
types.h
window.c
window.h

index d7afac1ee00f0da6dc9e4818cc7284e869041a9e..386c77ec21cb16b65bdd5473c1bac1fa45c7c8bb 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 0.1
 
 CC      = gcc
-LIBS    = -lm -lxcb -lxcb-icccm -lxcb-ewmh
+LIBS    = -lm -lxcb -lxcb-icccm -lxcb-ewmh -lxcb-xinerama
 CFLAGS  = -std=c99 -pedantic -Wall -Wextra
 LDFLAGS = $(LIBS)
 
index 494cad0dbdfddfd83404a671f300527987e223c9..d1bb23ceede79939d44f77875f3bd2f25bad90a5 100644 (file)
--- a/README.md
+++ b/README.md
@@ -83,8 +83,11 @@ The following messages are handled:
     dump
         Output the internal representation of the window tree.
 
-    list
-        Perform a dump of each desktop.
+    list_monitors [--quiet]
+        Perform a dump of each monitor.
+
+    list [--quiet]
+        Perform a dump of each desktop for the current monitor.
 
     windows
         Return the list of managed windows (i.e. their identifiers).
@@ -128,18 +131,30 @@ The following messages are handled:
     send_to DESKTOP_NAME
         Send the focused window to the given desktop.
 
+    use_monitor MONITOR_NAME
+        Select the given monitor.
+
     use DESKTOP_NAME
         Select the given desktop.
     
+    alternate_monitor
+        Alternate between the current and the last focused monitor.
+
     alternate
         Alternate between the current and the last focused desktop.
 
     add DESKTOP_NAME
         Make a new desktop with the given name.
 
+    rename_monitor CURRENT_NAME NEW_NAME
+        Rename the monitor named CURRENT_NAME to NEW_NAME.
+
     rename CURRENT_NAME NEW_NAME
         Rename the desktop named CURRENT_NAME to NEW_NAME.
 
+    cycle_monitor CYC
+        Select the next or previous monitor.
+
     cycle_desktop CYC
         Select the next or previous desktop.
         
@@ -182,8 +197,11 @@ Where
 
 Colors are either [X color names](http://en.wikipedia.org/wiki/X11_color_names) or '#RRGGBB', booleans are 'true' or 'false'.
 
+    focused_border_color
+        Color of the main border of a focused window of a focused monitor.
+
     active_border_color
-        Color of the main border of a focused window.
+        Color of the main border of a focused window of an unfocused monitor.
 
     normal_border_color
         Color of the main border of an unfocused window.
@@ -197,8 +215,11 @@ Colors are either [X color names](http://en.wikipedia.org/wiki/X11_color_names)
     presel_border_color
         Color of the *presel* message feedback.
 
+    focused_locked_border_color
+        Color of the main border of a focused locked window of a focused monitor.
+
     active_locked_border_color
-        Color of the main border of a focused locked window.
+        Color of the main border of a focused locked window of an unfocused monitor.
 
     normal_locked_border_color
         Color of the main border of an unfocused locked window.
diff --git a/bspwm.c b/bspwm.c
index a5b5741f16710c10da0b8cee5edcea38e407d48c..8deef0d7621b407feb84c7a9e49cc0ff282fdf6b 100644 (file)
--- a/bspwm.c
+++ b/bspwm.c
@@ -12,6 +12,7 @@
 #include <xcb/xcb.h>
 #include <xcb/xcb_event.h>
 #include <xcb/xcb_ewmh.h>
+#include <xcb/xinerama.h>
 #include "types.h"
 #include "settings.h"
 #include "messages.h"
@@ -71,11 +72,38 @@ void setup(void)
 
     xcb_ewmh_set_supported(ewmh, default_screen, LENGTH(net_atoms), net_atoms);
 
-    desk = make_desktop(DEFAULT_DESK_NAME);
-    last_desk = NULL;
-    desk_head = desk;
-    desk_tail = desk;
-    num_desktops++;
+    monitor_uid = desktop_uid = 0;
+    mon = last_mon = mon_head = mon_tail = NULL;
+
+    bool xinerama_is_active = false;
+
+    if (xcb_get_extension_data(dpy, &xcb_xinerama_id)->present) {
+        xcb_xinerama_is_active_reply_t *xia = xcb_xinerama_is_active_reply(dpy, xcb_xinerama_is_active(dpy), NULL);
+        if (xia != NULL) {
+            xinerama_is_active = xia->state;
+            free(xia);
+        }
+    }
+
+    if (xinerama_is_active) {
+        xcb_xinerama_query_screens_reply_t *xsq = xcb_xinerama_query_screens_reply(dpy, xcb_xinerama_query_screens(dpy), NULL);
+        xcb_xinerama_screen_info_t *xsi = xcb_xinerama_query_screens_screen_info(xsq);
+        int n = xcb_xinerama_query_screens_screen_info_length(xsq);
+        PRINTF("number of monitors: %d\n", n);
+        for (int i = 0; i < n; i++) {
+            xcb_xinerama_screen_info_t info = xsi[i];
+            xcb_rectangle_t rect = (xcb_rectangle_t) {info.x_org, info.y_org, info.width, info.height};
+            add_monitor(&rect);
+        }
+        free(xsq);
+    } else {
+        warn("Xinerama is inactive");
+        xcb_rectangle_t rect = (xcb_rectangle_t) {0, 0, screen_width, screen_height};
+        add_monitor(&rect);
+    }
+
+    for (monitor_t *m = mon_head; m != NULL; m = m->next)
+        add_desktop(m, NULL);
 
     ewmh_update_number_of_desktops();
     ewmh_update_desktop_names();
diff --git a/bspwm.h b/bspwm.h
index a557dee9733cd6433a7bae2525b4a33cf7f67d7b..2b0feef723a1a34745a4d10b2ee734d13f8fc3e7 100644 (file)
--- a/bspwm.h
+++ b/bspwm.h
@@ -9,18 +9,21 @@
 
 xcb_connection_t *dpy;
 int default_screen, screen_width, screen_height;
-unsigned int num_clients;
+uint32_t num_clients;
 uint32_t num_desktops;
+unsigned int num_monitors;
+unsigned int monitor_uid;
+unsigned int desktop_uid;
 xcb_screen_t *screen;
 xcb_rectangle_t root_rect;
 uint8_t root_depth;
 
 split_mode_t split_mode;
 direction_t split_dir;
-desktop_t *desk;
-desktop_t *last_desk;
-desktop_t *desk_head;
-desktop_t *desk_tail;
+monitor_t *mon;
+monitor_t *last_mon;
+monitor_t *mon_head;
+monitor_t *mon_tail;
 rule_t *rule_head;
 pointer_state_t *frozen_pointer;
 
index d32ba78032b19c48fd330f236d376c68dd13e338..ff4096adf872344feb28e5dacb15014e789e5fe4 100644 (file)
--- a/events.c
+++ b/events.c
@@ -77,6 +77,7 @@ void map_request(xcb_generic_event_t *evt)
         return;
     }
 
+    desktop_t *desk = mon->desk;
     client_t *c = make_client(win);
     update_floating_rectangle(c);
 
@@ -109,10 +110,10 @@ void map_request(xcb_generic_event_t *evt)
     c->transient = transient;
 
     if (takes_focus)
-        focus_node(desk, birth, false);
-
-    apply_layout(desk, desk->root, root_rect);
+        focus_node(mon, desk, birth, false);
 
+    fit_monitor(mon, birth->client);
+    arrange(mon, desk);
     window_show(c->window);
 
     if (takes_focus)
@@ -185,7 +186,7 @@ void configure_request(xcb_generic_event_t *evt)
 
         xcb_configure_window(dpy, e->window, mask, values);
         if (is_managed)
-            window_draw_border(loc.node, (loc.node == loc.desktop->focus));
+            window_draw_border(loc.node, loc.node == loc.desktop->focus, loc.monitor == mon);
     } else {
         xcb_configure_notify_event_t evt;
         xcb_rectangle_t rect;
@@ -224,7 +225,7 @@ void destroy_notify(xcb_generic_event_t *evt)
     window_location_t loc;
     if (locate_window(e->window, &loc)) {
         remove_node(loc.desktop, loc.node);
-        apply_layout(loc.desktop, loc.desktop->root, root_rect);
+        arrange(loc.monitor, loc.desktop);
     }
 }
 
@@ -237,7 +238,7 @@ void unmap_notify(xcb_generic_event_t *evt)
     window_location_t loc;
     if (locate_window(e->window, &loc)) {
         remove_node(loc.desktop, loc.node);
-        apply_layout(loc.desktop, loc.desktop->root, root_rect);
+        arrange(loc.monitor, loc.desktop);
     }
 }
 
@@ -257,8 +258,8 @@ void property_notify(xcb_generic_event_t *evt)
             return;
         if (xcb_icccm_get_wm_hints_reply(dpy, xcb_icccm_get_wm_hints(dpy, e->window), &hints, NULL) == 1) {
             loc.node->client->urgent = (hints.flags & XCB_ICCCM_WM_HINT_X_URGENCY);
-            if (desk == loc.desktop)
-                apply_layout(loc.desktop, loc.desktop->root, root_rect);
+            if (loc.monitor->desk == loc.desktop)
+                arrange(loc.monitor, loc.desktop);
         }
     }
 }
@@ -280,11 +281,11 @@ void client_message(xcb_generic_event_t *evt)
     } else if (e->type == ewmh->_NET_ACTIVE_WINDOW) {
         if (loc.desktop->focus->client->fullscreen && loc.desktop->focus != loc.node)
             toggle_fullscreen(loc.desktop->focus->client);
-        if (desk != loc.desktop) {
-            apply_layout(loc.desktop, loc.desktop->root, root_rect);
+        if (loc.monitor->desk != loc.desktop) {
+            arrange(loc.monitor, loc.desktop);
             select_desktop(loc.desktop);
         }
-        focus_node(loc.desktop, loc.node, true);
+        focus_node(loc.monitor, loc.desktop, loc.node, true);
     }
 }
 
@@ -300,7 +301,7 @@ void button_press(xcb_generic_event_t *evt)
         client_t *c = loc.node->client;
         switch (e->detail)  {
             case XCB_BUTTON_INDEX_2:
-                focus_node(loc.desktop, loc.node, true);
+                focus_node(loc.monitor, loc.desktop, loc.node, true);
                 break;
             case XCB_BUTTON_INDEX_1:
             case XCB_BUTTON_INDEX_3:
@@ -340,6 +341,7 @@ void motion_notify(xcb_generic_event_t *evt)
     int16_t delta_x, delta_y, x, y, w, h;
     uint16_t width, height;
 
+    monitor_t *m = frozen_pointer->monitor;
     desktop_t *d = frozen_pointer->desktop;
     node_t *n = frozen_pointer->node;
     client_t *c = n->client;
@@ -389,7 +391,7 @@ void motion_notify(xcb_generic_event_t *evt)
             height = MAX(1, h);
             window_move_resize(win, x, y, width, height);
             c->floating_rectangle = (xcb_rectangle_t) {x, y, width, height};
-            window_draw_border(n, (d->focus == n));
+            window_draw_border(n, d->focus == n, mon == m);
     }
 }
 
@@ -409,7 +411,7 @@ void handle_state(node_t *n, xcb_atom_t state, unsigned int action)
                 || (fs && action == XCB_EWMH_WM_STATE_REMOVE)
                 || (!fs && action == XCB_EWMH_WM_STATE_ADD)) {
             toggle_fullscreen(n->client);
-            apply_layout(desk, desk->root, root_rect);
+            arrange(mon, mon->desk);
         }
     }
 }
diff --git a/ewmh.c b/ewmh.c
index 8364ad4cdda35881b609d5ebdcf66ae6d5ab0c9f..87550a51c554d151e6b3c3eb29e98409ca1047fa 100644 (file)
--- a/ewmh.c
+++ b/ewmh.c
@@ -23,7 +23,7 @@ void ewmh_update_wm_name(void)
 
 void ewmh_update_active_window(void)
 {
-    xcb_window_t win = (desk->focus == NULL ? XCB_NONE : desk->focus->client->window);
+    xcb_window_t win = (mon->desk->focus == NULL ? XCB_NONE : mon->desk->focus->client->window);
     xcb_ewmh_set_active_window(ewmh, default_screen, win);
 }
 
@@ -34,21 +34,19 @@ void ewmh_update_number_of_desktops(void)
 
 uint32_t ewmh_get_desktop_index(desktop_t *d)
 {
-   desktop_t *cd = desk_head;
-   uint32_t i;
+    uint32_t i = 0;
+    for (monitor_t *m = mon_head; m != NULL; m = m->next)
+        for (desktop_t *cd = m->desk_head; cd != NULL; cd = cd->next, i++)
+            if (d == cd)
+                return i;
 
-   for (i = 0; cd != NULL && i < num_desktops; i++, cd = cd->next) {
-       if (d == cd)
-           break;
-   }
-
-   return i;
+    return 0;
 }
 
 void ewmh_update_current_desktop(void)
 {
-   uint32_t i = ewmh_get_desktop_index(desk);
-   xcb_ewmh_set_current_desktop(ewmh, default_screen, i);
+    uint32_t i = ewmh_get_desktop_index(mon->desk);
+    xcb_ewmh_set_current_desktop(ewmh, default_screen, i);
 }
 
 void ewmh_set_wm_desktop(node_t *n, desktop_t *d)
@@ -59,28 +57,33 @@ void ewmh_set_wm_desktop(node_t *n, desktop_t *d)
 
 void ewmh_update_desktop_names(void)
 {
-   char names[MAXLEN];
-   desktop_t *d = desk_head;
-   unsigned int pos, i;
-
-   pos = i = 0;
+    char names[MAXLEN];
+    monitor_t *m = mon_head;
+    unsigned int pos, i;
+    pos = i = 0;
+
+    while (m != NULL) {
+        desktop_t *d = m->desk_head;
+
+        while (d != NULL && i < num_desktops) {
+            for (unsigned int j = 0; j < strlen(d->name); j++)
+                names[pos + j] = d->name[j];
+            pos += strlen(d->name);
+            names[pos] = '\0';
+            pos++;
+            d = d->next;
+            i++;
+        }
 
-   while (d != NULL && i < num_desktops) {
-       for (unsigned int j = 0; j < strlen(d->name); j++)
-           names[pos + j] = d->name[j];
-       pos += strlen(d->name);
-       names[pos] = '\0';
-       pos++;
-       d = d->next;
-       i++;
-   }
+        m = m->next;
+    }
 
-   if (i != num_desktops)
-       return;
+    if (i != num_desktops)
+        return;
 
-   pos--;
+    pos--;
 
-   xcb_ewmh_set_desktop_names(ewmh, default_screen, pos, names);
+    xcb_ewmh_set_desktop_names(ewmh, default_screen, pos, names);
 }
 
 void ewmh_update_client_list(void)
@@ -91,17 +94,12 @@ void ewmh_update_client_list(void)
     }
 
     xcb_window_t wins[num_clients];
-    desktop_t *d = desk_head;
     unsigned int i = 0;
 
-    while (d != NULL && i < num_clients) {
-        node_t *n = first_extrema(d->root);
-        while (n != NULL) {
-            wins[i++] = n->client->window;
-            n = next_leaf(n);
-        }
-        d = d->next;
-    }
+    for (monitor_t *m = mon_head; m != NULL; m = m->next)
+        for (desktop_t *d = m->desk_head; d != NULL; d = d->next)
+            for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n))
+                wins[i++] = n->client->window;
 
     if (i != num_clients)
         return;
index b196b43668446f927d7ff59899df8c30b51934a5..eaecad2d5ade9b29a9c73e29bbae74890e5f5723 100644 (file)
@@ -28,25 +28,34 @@ void process_message(char *msg, char *rsp)
         set_setting(name, value, rsp);
         return;
     } else if (strcmp(cmd, "dump") == 0) {
-        dump_tree(desk, desk->root, rsp, 0);
+        dump_tree(mon->desk, mon->desk->root, rsp, 0);
+        return;
+    } else if (strcmp(cmd, "list_monitors") == 0) {
+        char *arg = strtok(NULL, TOKEN_SEP);
+        list_option_t opt;
+        if (parse_list_option(arg, &opt))
+            list_monitors(opt, rsp);
         return;
     } else if (strcmp(cmd, "list") == 0) {
-        list_desktops(rsp);
+        char *arg = strtok(NULL, TOKEN_SEP);
+        list_option_t opt;
+        if (parse_list_option(arg, &opt))
+            list_desktops(mon, opt, 0, rsp);
         return;
     } else if (strcmp(cmd, "windows") == 0) {
         list_windows(rsp);
         return;
     } else if (strcmp(cmd, "close") == 0) {
-        window_close(desk->focus);
+        window_close(mon->desk->focus);
         return;
     } else if (strcmp(cmd, "kill") == 0) {
-        window_kill(desk, desk->focus);
+        window_kill(mon->desk, mon->desk->focus);
     } else if (strcmp(cmd, "magnetise") == 0) {
         char *cor = strtok(NULL, TOKEN_SEP);
         if (cor != NULL) {
             corner_t c;
             if (parse_corner(cor, &c)) {
-                magnetise_tree(desk->root, c);
+                magnetise_tree(mon->desk->root, c);
             }
         }
     } else if (strcmp(cmd, "rotate") == 0) {
@@ -54,7 +63,7 @@ void process_message(char *msg, char *rsp)
         if (deg != NULL) {
             rotate_t r;
             if (parse_rotate(deg, &r)) {
-                rotate_tree(desk->root, r);
+                rotate_tree(mon->desk->root, r);
             }
         }
     } else if (strcmp(cmd, "layout") == 0) {
@@ -62,41 +71,41 @@ void process_message(char *msg, char *rsp)
         if (lyt != NULL) {
             layout_t l;
             if (parse_layout(lyt, &l)) {
-                desk->layout = l;
+                mon->desk->layout = l;
             }
         }
     } else if (strcmp(cmd, "cycle_layout") == 0) {
-        if (desk->layout == LAYOUT_MONOCLE)
-            desk->layout = LAYOUT_TILED;
+        if (mon->desk->layout == LAYOUT_MONOCLE)
+            mon->desk->layout = LAYOUT_TILED;
         else
-            desk->layout = LAYOUT_MONOCLE;
+            mon->desk->layout = LAYOUT_MONOCLE;
     } else if (strcmp(cmd, "shift") == 0) {
         char *dir = strtok(NULL, TOKEN_SEP);
         if (dir != NULL) {
             direction_t d;
             if (parse_direction(dir, &d)) {
-                swap_nodes(desk->focus, find_neighbor(desk->focus, d));
+                swap_nodes(mon->desk->focus, find_neighbor(mon->desk->focus, d));
             }
         }
     } else if (strcmp(cmd, "toggle_fullscreen") == 0) {
-        if (desk->focus != NULL)
-            toggle_fullscreen(desk->focus->client);
+        if (mon->desk->focus != NULL)
+            toggle_fullscreen(mon->desk->focus->client);
     } else if (strcmp(cmd, "toggle_floating") == 0) {
         split_mode = MODE_AUTOMATIC;
-        toggle_floating(desk->focus);
+        toggle_floating(mon->desk->focus);
     } else if (strcmp(cmd, "toggle_locked") == 0) {
-        if (desk->focus != NULL)
-            toggle_locked(desk->focus->client);
+        if (mon->desk->focus != NULL)
+            toggle_locked(mon->desk->focus->client);
     } else if (strcmp(cmd, "ratio") == 0) {
         char *value = strtok(NULL, TOKEN_SEP);
-        if (value != NULL && desk->focus != NULL)
-            sscanf(value, "%lf", &desk->focus->split_ratio);
+        if (value != NULL && mon->desk->focus != NULL)
+            sscanf(value, "%lf", &mon->desk->focus->split_ratio);
     } else if (strcmp(cmd, "cancel") == 0) {
         split_mode = MODE_AUTOMATIC;
-        window_draw_border(desk->focus, true);
+        window_draw_border(mon->desk->focus, true, true);
         return;
     } else if (strcmp(cmd, "presel") == 0) {
-        if (desk->focus == NULL || !is_tiled(desk->focus->client) || desk->layout != LAYOUT_TILED)
+        if (mon->desk->focus == NULL || !is_tiled(mon->desk->focus->client) || mon->desk->layout != LAYOUT_TILED)
             return;
         char *dir = strtok(NULL, TOKEN_SEP);
         if (dir != NULL) {
@@ -104,7 +113,7 @@ void process_message(char *msg, char *rsp)
             if (parse_direction(dir, &d)) {
                 split_mode = MODE_MANUAL;
                 split_dir = d;
-                window_draw_border(desk->focus, true);
+                window_draw_border(mon->desk->focus, true, true);
             }
         }
         return;
@@ -114,43 +123,84 @@ void process_message(char *msg, char *rsp)
             fence_move_t m;
             direction_t d;
             if (parse_fence_move(cmd, &m) && parse_direction(dir, &d)) {
-                move_fence(desk->focus, d, m);
+                move_fence(mon->desk->focus, d, m);
+            }
+        }
+    } else if (strcmp(cmd, "send_to_monitor") == 0) {
+        char *name = strtok(NULL, TOKEN_SEP);
+        if (name != NULL) {
+            desktop_location_t loc;
+            if (locate_desktop(name, &loc)) {
+                transfer_node(mon, mon->desk, loc.monitor, loc.desktop, mon->desk->focus);
+                if (mon != loc.monitor && loc.monitor->desk == loc.desktop)
+                    arrange(loc.monitor, loc.desktop);
             }
         }
     } else if (strcmp(cmd, "send_to") == 0) {
         char *name = strtok(NULL, TOKEN_SEP);
         if (name != NULL) {
-            desktop_t *d = find_desktop(name);
-            transfer_node(desk, d, desk->focus);
+            desktop_location_t loc;
+            if (locate_desktop(name, &loc)) {
+                transfer_node(mon, mon->desk, loc.monitor, loc.desktop, mon->desk->focus);
+                if (mon != loc.monitor && loc.monitor->desk == loc.desktop)
+                    arrange(loc.monitor, loc.desktop);
+            }
+        }
+    } else if (strcmp(cmd, "rename_monitor") == 0) {
+        char *cur_name = strtok(NULL, TOKEN_SEP);
+        if (cur_name != NULL) {
+            monitor_t *m = find_monitor(cur_name);
+            if (m != NULL) {
+                char *new_name = strtok(NULL, TOKEN_SEP);
+                if (new_name != NULL) {
+                    strncpy(m->name, new_name, sizeof(m->name));
+                }
+            }
         }
     } else if (strcmp(cmd, "rename") == 0) {
         char *cur_name = strtok(NULL, TOKEN_SEP);
         if (cur_name != NULL) {
-            desktop_t *d = find_desktop(cur_name);
-            if (d != NULL) {
+            desktop_location_t loc;
+            if (locate_desktop(cur_name, &loc)) {
                 char *new_name = strtok(NULL, TOKEN_SEP);
                 if (new_name != NULL) {
-                    strncpy(d->name, new_name, sizeof(d->name));
+                    strncpy(loc.desktop->name, new_name, sizeof(loc.desktop->name));
                     ewmh_update_desktop_names();
                 }
             }
         }
+    } else if (strcmp(cmd, "use_monitor") == 0) {
+        char *name = strtok(NULL, TOKEN_SEP);
+        if (name != NULL) {
+            monitor_t *m = find_monitor(name);
+            if (m != NULL)
+                select_monitor(m);
+        }
     } else if (strcmp(cmd, "use") == 0) {
         char *name = strtok(NULL, TOKEN_SEP);
         if (name != NULL) {
-            desktop_t *d = find_desktop(name);
-            select_desktop(d);
+            desktop_location_t loc;
+            if (locate_desktop(name, &loc)) {
+                select_monitor(loc.monitor);
+                select_desktop(loc.desktop);
+            }
+        }
+    } else if (strcmp(cmd, "cycle_monitor") == 0) {
+        char *dir = strtok(NULL, TOKEN_SEP);
+        if (dir != NULL) {
+            cycle_dir_t d;
+            if (parse_cycle_direction(dir, &d))
+                cycle_monitor(d);
         }
     } else if (strcmp(cmd, "cycle_desktop") == 0) {
         char *dir = strtok(NULL, TOKEN_SEP);
         if (dir != NULL) {
             cycle_dir_t d;
-            if (parse_cycle_direction(dir, &d)) {
+            if (parse_cycle_direction(dir, &d))
                 cycle_desktop(d);
-            }
         }
     } else if (strcmp(cmd, "cycle") == 0) {
-        if (desk->focus != NULL && desk->focus->client->fullscreen)
+        if (mon->desk->focus != NULL && mon->desk->focus->client->fullscreen)
             return;
         char *dir = strtok(NULL, TOKEN_SEP);
         if (dir != NULL) {
@@ -159,7 +209,7 @@ void process_message(char *msg, char *rsp)
                 skip_client_t k;
                 char *skip = strtok(NULL, TOKEN_SEP);
                 if (parse_skip_client(skip, &k))
-                    cycle_leaf(desk, desk->focus, d, k);
+                    cycle_leaf(d, k);
             }
         }
         return;
@@ -178,23 +228,25 @@ void process_message(char *msg, char *rsp)
             rule_head = rule;
         }
         return;
+    } else if (strcmp(cmd, "alternate_monitor") == 0) {
+        select_monitor(last_mon);
     } else if (strcmp(cmd, "alternate") == 0) {
-        select_desktop(last_desk);
+        select_desktop(mon->last_desk);
     } else if (strcmp(cmd, "add") == 0) {
         char *name = strtok(NULL, TOKEN_SEP);
         if (name != NULL) {
-            add_desktop(name);
+            add_desktop(mon, name);
         }
         return;
     } else if (strcmp(cmd, "focus") == 0) {
-        if (desk->focus != NULL && desk->focus->client->fullscreen)
+        if (mon->desk->focus != NULL && mon->desk->focus->client->fullscreen)
             return;
         char *dir = strtok(NULL, TOKEN_SEP);
         if (dir != NULL) {
             direction_t d;
             if (parse_direction(dir, &d)) {
-                node_t *n = find_neighbor(desk->focus, d);
-                focus_node(desk, n, true);
+                node_t *n = find_neighbor(mon->desk->focus, d);
+                focus_node(mon, mon->desk, n, true);
             }
         }
         return;
@@ -213,7 +265,7 @@ void process_message(char *msg, char *rsp)
         return;
     }
 
-    apply_layout(desk, desk->root, root_rect);
+    arrange(mon, mon->desk);
 }
 
 void set_setting(char *name, char *value, char *rsp)
@@ -245,6 +297,9 @@ void set_setting(char *name, char *value, char *rsp)
     } else if (strcmp(name, "bottom_padding") == 0) {
         sscanf(value, "%i", &bottom_padding);
         update_root_dimensions();
+    } else if (strcmp(name, "focused_border_color") == 0) {
+        strncpy(focused_border_color, value, sizeof(focused_border_color));
+        focused_border_color_pxl = get_color(focused_border_color);
     } else if (strcmp(name, "active_border_color") == 0) {
         strncpy(active_border_color, value, sizeof(active_border_color));
         active_border_color_pxl = get_color(active_border_color);
@@ -260,6 +315,9 @@ void set_setting(char *name, char *value, char *rsp)
     } else if (strcmp(name, "presel_border_color") == 0) {
         strncpy(presel_border_color, value, sizeof(presel_border_color));
         presel_border_color_pxl = get_color(presel_border_color);
+    } else if (strcmp(name, "focused_locked_border_color") == 0) {
+        strncpy(focused_locked_border_color, value, sizeof(focused_locked_border_color));
+        focused_locked_border_color_pxl = get_color(focused_locked_border_color);
     } else if (strcmp(name, "active_locked_border_color") == 0) {
         strncpy(active_locked_border_color, value, sizeof(active_locked_border_color));
         active_locked_border_color_pxl = get_color(active_locked_border_color);
@@ -282,7 +340,7 @@ void set_setting(char *name, char *value, char *rsp)
         return;
     }
 
-    apply_layout(desk, desk->root, root_rect);
+    arrange(mon, mon->desk);
 }
 
 void get_setting(char *name, char* rsp)
@@ -308,6 +366,8 @@ void get_setting(char *name, char* rsp)
         snprintf(rsp, BUFSIZ, "%i", top_padding);
     else if (strcmp(name, "bottom_padding") == 0)
         snprintf(rsp, BUFSIZ, "%i", bottom_padding);
+    else if (strcmp(name, "focused_border_color") == 0)
+        snprintf(rsp, BUFSIZ, "%s (%06X)", focused_border_color, focused_border_color_pxl);
     else if (strcmp(name, "active_border_color") == 0)
         snprintf(rsp, BUFSIZ, "%s (%06X)", active_border_color, active_border_color_pxl);
     else if (strcmp(name, "normal_border_color") == 0)
@@ -318,6 +378,8 @@ void get_setting(char *name, char* rsp)
         snprintf(rsp, BUFSIZ, "%s (%06X)", outer_border_color, outer_border_color_pxl);
     else if (strcmp(name, "presel_border_color") == 0)
         snprintf(rsp, BUFSIZ, "%s (%06X)", presel_border_color, presel_border_color_pxl);
+    else if (strcmp(name, "focused_locked_border_color") == 0)
+        snprintf(rsp, BUFSIZ, "%s (%06X)", focused_locked_border_color, focused_locked_border_color_pxl);
     else if (strcmp(name, "active_locked_border_color") == 0)
         snprintf(rsp, BUFSIZ, "%s (%06X)", active_locked_border_color, active_locked_border_color_pxl);
     else if (strcmp(name, "normal_locked_border_color") == 0)
@@ -332,7 +394,6 @@ void get_setting(char *name, char* rsp)
         snprintf(rsp, BUFSIZ, "unknown setting: %s", name);
 }
 
-
 bool parse_bool(char *value, bool *b)
 {
     if (strcmp(value, "true") == 0) {
@@ -408,6 +469,18 @@ bool parse_skip_client(char *s, skip_client_t *k)
     return false;
 }
 
+bool parse_list_option(char *s, list_option_t *o)
+{
+    if (s == NULL || strcmp(s, "--verbose") == 0) {
+        *o = LIST_OPTION_VERBOSE;
+        return true;
+    } else if (strcmp(s, "--quiet") == 0) {
+        *o = LIST_OPTION_QUIET;
+        return true;
+    }
+    return false;
+}
+
 bool parse_corner(char *s, corner_t *c)
 {
     if (strcmp(s, "top_left") == 0) {
@@ -452,4 +525,3 @@ bool parse_fence_move(char *s, fence_move_t *m)
     }
     return false;
 }
-
index 7e57e5ade4c51e22e97e0784cab698fa857167ba..b9ec1e6c2d6d2cfe7d30a6ad757c2a42c3cd59f3 100644 (file)
@@ -10,6 +10,7 @@ bool parse_bool(char *, bool *);
 bool parse_layout(char *, layout_t *);
 bool parse_direction(char *, direction_t *);
 bool parse_cycle_direction(char *, cycle_dir_t *);
+bool parse_list_option(char *, list_option_t *);
 bool parse_skip_client(char *, skip_client_t *);
 bool parse_corner(char *, corner_t *);
 bool parse_rotate(char *, rotate_t *);
index 94f1ea88b24b96fa29ee4e1afc22ce4a9e7dfcf0..3fc492c04d959f35b843c4e3889ac4c26b8ddbcc 100644 (file)
@@ -31,19 +31,23 @@ void run_autostart(void)
 void load_settings(void)
 {
     strncpy(normal_border_color, NORMAL_BORDER_COLOR, sizeof(normal_border_color));
+    strncpy(focused_border_color, FOCUSED_BORDER_COLOR, sizeof(focused_border_color));
     strncpy(active_border_color, ACTIVE_BORDER_COLOR, sizeof(active_border_color));
     strncpy(inner_border_color, INNER_BORDER_COLOR, sizeof(inner_border_color));
     strncpy(outer_border_color, OUTER_BORDER_COLOR, sizeof(outer_border_color));
     strncpy(presel_border_color, PRESEL_BORDER_COLOR, sizeof(presel_border_color));
+    strncpy(focused_locked_border_color, FOCUSED_LOCKED_BORDER_COLOR, sizeof(focused_locked_border_color));
     strncpy(active_locked_border_color, ACTIVE_LOCKED_BORDER_COLOR, sizeof(active_locked_border_color));
     strncpy(normal_locked_border_color, NORMAL_LOCKED_BORDER_COLOR, sizeof(normal_locked_border_color));
     strncpy(urgent_border_color, URGENT_BORDER_COLOR, sizeof(urgent_border_color));
 
     normal_border_color_pxl = get_color(normal_border_color);
+    focused_border_color_pxl = get_color(active_border_color);
     active_border_color_pxl = get_color(active_border_color);
     inner_border_color_pxl = get_color(inner_border_color);
     outer_border_color_pxl = get_color(outer_border_color);
     presel_border_color_pxl = get_color(presel_border_color);
+    focused_locked_border_color_pxl = get_color(active_locked_border_color);
     active_locked_border_color_pxl = get_color(active_locked_border_color);
     normal_locked_border_color_pxl = get_color(normal_locked_border_color);
     urgent_border_color_pxl = get_color(urgent_border_color);
index 94c54ec4025b24766385022bd312bed5358dc3f8..9f69be6fc036017dc5895d3ca04b8a40029aaa4e 100644 (file)
@@ -6,11 +6,13 @@
 #define WM_NAME             "bspwm"
 #define AUTOSTART_FILE      "autostart"
 
+#define FOCUSED_BORDER_COLOR        "#7D7F8A"
 #define ACTIVE_BORDER_COLOR         "#7D7F8A"
 #define NORMAL_BORDER_COLOR         "#3F3E3B"
 #define INNER_BORDER_COLOR          "#32312E"
 #define OUTER_BORDER_COLOR          "#32312E"
 #define PRESEL_BORDER_COLOR         "#97AE71"
+#define FOCUSED_LOCKED_BORDER_COLOR "#B6A56A"
 #define ACTIVE_LOCKED_BORDER_COLOR  "#B6A56A"
 #define NORMAL_LOCKED_BORDER_COLOR  "#8D7E45"
 #define URGENT_BORDER_COLOR         "#DE928B"
 
 #define BORDERLESS_MONOCLE  false
 
+char focused_border_color[MAXLEN];
 char active_border_color[MAXLEN];
 char normal_border_color[MAXLEN];
 char inner_border_color[MAXLEN];
 char outer_border_color[MAXLEN];
 char presel_border_color[MAXLEN];
+char focused_locked_border_color[MAXLEN];
 char active_locked_border_color[MAXLEN];
 char normal_locked_border_color[MAXLEN];
 char urgent_border_color[MAXLEN];
 
+uint32_t focused_border_color_pxl;
 uint32_t active_border_color_pxl;
 uint32_t normal_border_color_pxl;
 uint32_t inner_border_color_pxl;
 uint32_t outer_border_color_pxl;
 uint32_t presel_border_color_pxl;
+uint32_t focused_locked_border_color_pxl;
 uint32_t active_locked_border_color_pxl;
 uint32_t normal_locked_border_color_pxl;
 uint32_t urgent_border_color_pxl;
diff --git a/tree.c b/tree.c
index 8ba7df0132751aed88851217d2dbf0222f63b665..c9d70c0d4e6f9ba61097d97cdcd4b127fb193d13 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -194,14 +194,14 @@ void magnetise_tree(node_t *n, corner_t corner)
     magnetise_tree(n->second_child, corner);
 }
 
-void dump_tree(desktop_t *d, node_t *n, char *rsp, int depth)
+void dump_tree(desktop_t *d, node_t *n, char *rsp, unsigned int depth)
 {
     if (n == NULL)
         return;
 
     char line[MAXLEN];
 
-    for (int i = 0; i < depth; i++)
+    for (unsigned int i = 0; i < depth; i++)
         strncat(rsp, "  ", REMLEN(rsp));
 
     if (is_leaf(n))
@@ -221,23 +221,42 @@ void dump_tree(desktop_t *d, node_t *n, char *rsp, int depth)
 }
 
 void refresh_current(void) {
-    if (desk->focus == NULL)
+    if (mon->desk->focus == NULL)
         ewmh_update_active_window();
     else
-        focus_node(desk, desk->focus, true);
+        focus_node(mon, mon->desk, mon->desk->focus, true);
 }
 
-void list_desktops(char *rsp)
+void list_monitors(list_option_t opt, char *rsp)
 {
-    desktop_t *d = desk_head;
+    monitor_t *m = mon_head;
+
+    while (m != NULL) {
+        strncat(rsp, m->name, REMLEN(rsp));
+        if (mon == m)
+            strncat(rsp, " #\n", REMLEN(rsp));
+        else
+            strncat(rsp, "\n", REMLEN(rsp));
+        if (opt == LIST_OPTION_VERBOSE)
+            list_desktops(m, opt, 1, rsp);
+        m = m->next;
+    }
+}
+
+void list_desktops(monitor_t *m, list_option_t opt, unsigned int depth, char *rsp)
+{
+    desktop_t *d = m->desk_head;
 
     while (d != NULL) {
+        for (unsigned int i = 0; i < depth; i++)
+            strncat(rsp, "  ", REMLEN(rsp));
         strncat(rsp, d->name, REMLEN(rsp));
-        if (desk == d)
+        if (m->desk == d)
             strncat(rsp, " @\n", REMLEN(rsp));
         else
             strncat(rsp, "\n", REMLEN(rsp));
-        dump_tree(d, d->root, rsp, 1);
+        if (opt == LIST_OPTION_VERBOSE)
+            dump_tree(d, d->root, rsp, depth + 1);
         d = d->next;
     }
 }
@@ -250,9 +269,19 @@ void update_root_dimensions(void)
     root_rect.height = screen_height - (top_padding + bottom_padding + window_gap);
 }
 
-void apply_layout(desktop_t *d, node_t *n, xcb_rectangle_t rect)
+void arrange(monitor_t *m, desktop_t *d)
 {
-    if (d == NULL || n == NULL)
+    xcb_rectangle_t rect = m->rectangle;
+    rect.x += left_padding + window_gap;
+    rect.y += top_padding + window_gap;
+    rect.width -= left_padding + right_padding + window_gap;
+    rect.height -= top_padding + bottom_padding + window_gap;
+    apply_layout(m, d, d->root, rect);
+}
+
+void apply_layout(monitor_t *m, desktop_t *d, node_t *n, xcb_rectangle_t rect)
+{
+    if (n == NULL)
         return;
 
     n->rectangle = rect;
@@ -288,7 +317,7 @@ void apply_layout(desktop_t *d, node_t *n, xcb_rectangle_t rect)
 
         window_move_resize(n->client->window, r.x, r.y, r.width, r.height);
         window_border_width(n->client->window, n->client->border_width);
-        window_draw_border(n, n == d->focus);
+        window_draw_border(n, n == d->focus, m == mon);
 
         if (d->layout == LAYOUT_MONOCLE && n == d->focus)
             window_raise(n->client->window);
@@ -313,8 +342,8 @@ void apply_layout(desktop_t *d, node_t *n, xcb_rectangle_t rect)
             }
         }
 
-        apply_layout(d, n->first_child, first_rect);
-        apply_layout(d, n->second_child, second_rect);
+        apply_layout(m, d, n->first_child, first_rect);
+        apply_layout(m, d, n->second_child, second_rect);
     }
 }
 
@@ -412,7 +441,7 @@ void insert_node(desktop_t *d, node_t *n)
     }
 }
 
-void focus_node(desktop_t *d, node_t *n, bool is_mapped)
+void focus_node(monitor_t *m, desktop_t *d, node_t *n, bool is_mapped)
 {
     if (n == NULL)
         return;
@@ -423,9 +452,9 @@ void focus_node(desktop_t *d, node_t *n, bool is_mapped)
     n->client->urgent = false;
 
     if (is_mapped) {
-        if (d->focus != n) {
-            window_draw_border(d->focus, false);
-            window_draw_border(n, true);
+        if (mon != m || d->focus != n) {
+            window_draw_border(d->focus, m != mon, m == mon);
+            window_draw_border(n, true, true);
         }
         xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_POINTER_ROOT, n->client->window, XCB_CURRENT_TIME);
     }
@@ -440,16 +469,15 @@ void focus_node(desktop_t *d, node_t *n, bool is_mapped)
         d->focus = n;
     }
 
-    if (d == desk)
-        ewmh_update_active_window();
+    ewmh_update_active_window();
 }
 
 void update_current(void)
 {
-    if (desk->focus == NULL)
+    if (mon->desk->focus == NULL)
         ewmh_update_active_window();
     else
-        focus_node(desk, desk->focus, true);
+        focus_node(mon, mon->desk, mon->desk->focus, true);
 }
 
 void unlink_node(desktop_t *d, node_t *n)
@@ -519,7 +547,7 @@ void remove_node(desktop_t *d, node_t *n)
     num_clients--;
     ewmh_update_client_list();
 
-    if (desk == d)
+    if (mon->desk == d)
         update_current();
 }
 
@@ -559,9 +587,30 @@ void swap_nodes(node_t *n1, node_t *n2)
     }
 }
 
-void transfer_node(desktop_t *ds, desktop_t *dd, node_t *n)
+void fit_monitor(monitor_t *m, client_t *c)
+{
+    xcb_rectangle_t cr = c->floating_rectangle;
+    xcb_rectangle_t mr = m->rectangle;
+    if (cr.x < mr.x)
+        cr.x += mr.x;
+    if (cr.y < mr.y)
+        cr.y += mr.y;
+}
+
+void translate_coordinates(monitor_t *ms, monitor_t *md, client_t *c)
+{
+    if (ms == md)
+        return;
+
+    uint32_t vx = md->rectangle.x - ms->rectangle.x;
+    uint32_t vy = md->rectangle.y - ms->rectangle.y;
+    c->floating_rectangle.x += vx;
+    c->floating_rectangle.y += vy;
+}
+
+void transfer_node(monitor_t *ms, desktop_t *ds, monitor_t *md, desktop_t *dd, node_t *n)
 {
-    if (n == NULL || ds == NULL || dd == NULL || dd == ds)
+    if (n == NULL || ds == NULL || dd == NULL || ms == NULL || md == NULL || (ms == md && dd == ds))
         return;
 
     PRINTF("transfer node %X\n", n->client->window);
@@ -570,24 +619,43 @@ void transfer_node(desktop_t *ds, desktop_t *dd, node_t *n)
     insert_node(dd, n);
     ewmh_set_wm_desktop(n, dd);
 
-    if (ds == desk) {
+    if (ds == ms->desk && dd != md->desk) {
         window_hide(n->client->window);
     }
 
-    if (dd == desk) {
+    translate_coordinates(ms, md, n->client);
+    if (n->client->fullscreen)
+        window_move_resize(n->client->window, md->rectangle.x, md->rectangle.y, md->rectangle.width, md->rectangle.height);
+
+    if (ds != ms->desk && dd == md->desk) {
         window_show(n->client->window);
-        focus_node(dd, n, true);
+        focus_node(md, dd, n, true);
     } else {
-        focus_node(dd, n, false);
+        focus_node(md, dd, n, false);
     }
 
-    if (ds == desk || dd == desk)
+    if (ds == ms->desk || dd == md->desk)
         update_current();
 }
 
+void select_monitor(monitor_t *m)
+{
+    if (m == NULL || mon == m)
+        return;
+
+    PRINTF("select monitor %s\n", m->name);
+
+    focus_node(m, m->desk, m->desk->focus, true);
+
+    last_mon = mon;
+    mon = m;
+
+    ewmh_update_current_desktop();
+}
+
 void select_desktop(desktop_t *d)
 {
-    if (d == NULL || d == desk)
+    if (d == NULL || d == mon->desk)
         return;
 
     PRINTF("select desktop %s\n", d->name);
@@ -599,30 +667,41 @@ void select_desktop(desktop_t *d)
         n = next_leaf(n);
     }
 
-    n = first_extrema(desk->root);
+    n = first_extrema(mon->desk->root);
 
     while (n != NULL) {
         window_hide(n->client->window);
         n = next_leaf(n);
     }
 
-    last_desk = desk;
-    desk = d;
+    mon->last_desk = mon->desk;
+    mon->desk = d;
 
     update_current();
     ewmh_update_current_desktop();
 }
 
+void cycle_monitor(cycle_dir_t dir)
+{
+    if (dir == CYCLE_NEXT)
+        select_monitor((mon->next == NULL ? mon_head : mon->next));
+    else if (dir == CYCLE_PREV)
+        select_monitor((mon->prev == NULL ? mon_tail : mon->prev));
+}
+
 void cycle_desktop(cycle_dir_t dir)
 {
     if (dir == CYCLE_NEXT)
-        select_desktop((desk->next == NULL ? desk_head : desk->next));
+        select_desktop((mon->desk->next == NULL ? mon->desk_head : mon->desk->next));
     else if (dir == CYCLE_PREV)
-        select_desktop((desk->prev == NULL ? desk_tail : desk->prev));
+        select_desktop((mon->desk->prev == NULL ? mon->desk_tail : mon->desk->prev));
 }
 
-void cycle_leaf(desktop_t *d, node_t *n, cycle_dir_t dir, skip_client_t skip)
+void cycle_leaf(cycle_dir_t dir, skip_client_t skip)
 {
+    desktop_t *d = mon->desk;
+    node_t *n = mon->desk->focus;
+
     if (n == NULL)
         return;
 
@@ -637,7 +716,7 @@ void cycle_leaf(desktop_t *d, node_t *n, cycle_dir_t dir, skip_client_t skip)
         if (skip == SKIP_NONE || (skip == SKIP_TILED && !tiled) || (skip == SKIP_FLOATING && tiled)
                 || (skip == SKIP_CLASS_DIFFER && strcmp(f->client->class_name, n->client->class_name) == 0)
                 || (skip == SKIP_CLASS_EQUAL && strcmp(f->client->class_name, n->client->class_name) != 0)) {
-            focus_node(d, f, true);
+            focus_node(mon, d, f, true);
             return;
         }
         f = (dir == CYCLE_PREV ? prev_leaf(f) : next_leaf(f));
@@ -662,24 +741,42 @@ void update_vacant_state(node_t *n)
     }
 }
 
-desktop_t *find_desktop(char *name)
+monitor_t *find_monitor(char *name)
 {
-    desktop_t *d = desk_head;
-    while (d != NULL) {
-        if (strcmp(d->name, name) == 0)
-            return d;
-        d = d->next;
-    }
+    for (monitor_t *m = mon_head; m != NULL; m = m->next)
+        if (strcmp(m->name, name) == 0)
+            return m;
     return NULL;
 }
 
-void add_desktop(char *name)
+void add_desktop(monitor_t *m, char *name)
 {
     desktop_t *d = make_desktop(name);
-    desk_tail->next = d;
-    d->prev = desk_tail;
-    desk_tail = d;
+    if (m->desk == NULL) {
+        m->desk = d;
+        m->desk_head = d;
+        m->desk_tail = d;
+    } else {
+        m->desk_tail->next = d;
+        d->prev = m->desk_tail;
+        m->desk_tail = d;
+    }
     num_desktops++;
     ewmh_update_number_of_desktops();
     ewmh_update_desktop_names();
 }
+
+void add_monitor(xcb_rectangle_t *rect)
+{
+    monitor_t *m = make_monitor(rect);
+    if (mon == NULL) {
+        mon = m;
+        mon_head = m;
+        mon_tail = m;
+    } else {
+        mon_tail->next = m;
+        m->prev = mon_tail;
+        mon_tail = m;
+    }
+    num_monitors++;
+}
diff --git a/tree.h b/tree.h
index 6720c37f258db284d4c521b24bd931f073a53df9..52abb4c85da72a6ba2badbd1e0f000c48fce7792 100644 (file)
--- a/tree.h
+++ b/tree.h
@@ -20,21 +20,28 @@ void move_fence(node_t *, direction_t, fence_move_t);
 void rotate_tree(node_t *, rotate_t);
 void magnetise_tree(node_t *, corner_t);
 void update_root_dimensions(void);
-void apply_layout(desktop_t *, node_t *, xcb_rectangle_t);
+void arrange(monitor_t *, desktop_t *);
+void apply_layout(monitor_t *, desktop_t *, node_t *, xcb_rectangle_t);
 void insert_node(desktop_t *, node_t *);
-void dump_tree(desktop_t *, node_t *, char *, int);
-void list_desktops(char *);
-void focus_node(desktop_t *, node_t *, bool);
+void dump_tree(desktop_t *, node_t *, char *, unsigned int);
+void list_desktops(monitor_t *, list_option_t, unsigned int, char *);
+void list_monitors(list_option_t, char *);
+void focus_node(monitor_t *, desktop_t *, node_t *, bool);
 void update_current(void);
 void unlink_node(desktop_t *, node_t *);
 void remove_node(desktop_t *, node_t *);
 void swap_nodes(node_t *, node_t *);
-void transfer_node(desktop_t *, desktop_t *, node_t *);
+void fit_monitor(monitor_t *, client_t *);
+void translate_coordinates(monitor_t *, monitor_t *, client_t *);
+void transfer_node(monitor_t *, desktop_t *, monitor_t *, desktop_t *, node_t *);
+void select_monitor(monitor_t *);
 void select_desktop(desktop_t *);
+void cycle_monitor(cycle_dir_t);
 void cycle_desktop(cycle_dir_t);
-void cycle_leaf(desktop_t *, node_t *, cycle_dir_t, skip_client_t);
+void cycle_leaf(cycle_dir_t, skip_client_t);
 void update_vacant_state(node_t *);
-desktop_t *find_desktop(char *);
-void add_desktop(char *);
+monitor_t *find_monitor(char *);
+void add_desktop(monitor_t *, char *);
+void add_monitor(xcb_rectangle_t *);
 
 #endif
diff --git a/types.c b/types.c
index ee307027639271208ef27a58dce4e22b1debc421..d3576bd5c3a9995224d3f04d6553b73ac5fa7181 100644 (file)
--- a/types.c
+++ b/types.c
@@ -2,6 +2,7 @@
 #include <string.h>
 #include <xcb/xcb.h>
 #include <xcb/xcb_event.h>
+#include "bspwm.h"
 #include "settings.h"
 #include "types.h"
 
@@ -16,10 +17,26 @@ node_t *make_node(void)
     return n;
 }
 
+monitor_t *make_monitor(xcb_rectangle_t *rect)
+{
+    monitor_t *m = malloc(sizeof(monitor_t));
+    snprintf(m->name, sizeof(m->name), "%s%02d", DEFAULT_MON_NAME, ++monitor_uid);
+    m->prev = m->next = NULL;
+    m->desk = m->last_desk = NULL;
+    if (rect != NULL)
+        m->rectangle = *rect;
+    else
+        warn("no rectangle was given for monitor '%s'\n", m->name);
+    return m;
+}
+
 desktop_t *make_desktop(const char *name)
 {
     desktop_t *d = malloc(sizeof(desktop_t));
-    strncpy(d->name, name, sizeof(d->name));
+    if (name == NULL)
+        snprintf(d->name, sizeof(d->name), "%s%02d", DEFAULT_DESK_NAME, ++desktop_uid);
+    else
+        strncpy(d->name, name, sizeof(d->name));
     d->layout = LAYOUT_TILED;
     d->prev = d->next = NULL;
     d->root = d->focus = d->last_focus = NULL;
diff --git a/types.h b/types.h
index 5698f9c717c6a7e97d6c066be4d54e21b277354f..6321801be277e0735d0c3a7a8f3bbcc9b43d7098 100644 (file)
--- a/types.h
+++ b/types.h
@@ -7,7 +7,8 @@
 #include "helpers.h"
 
 #define SPLIT_RATIO  0.5
-#define DEFAULT_DESK_NAME    "One"
+#define DEFAULT_DESK_NAME    "Desktop"
+#define DEFAULT_MON_NAME     "Monitor"
 #define MISSING_VALUE        "N/A"
 
 typedef enum {
@@ -35,6 +36,11 @@ typedef enum {
     CHANGE_DECREASE
 } value_change_t;
 
+typedef enum {
+    LIST_OPTION_VERBOSE,
+    LIST_OPTION_QUIET
+} list_option_t;
+
 typedef enum {
     SKIP_NONE,
     SKIP_FLOATING,
@@ -105,6 +111,18 @@ struct desktop_t {
     desktop_t *next;
 };
 
+typedef struct monitor_t monitor_t;
+struct monitor_t {
+    char name[MAXLEN];
+    xcb_rectangle_t rectangle;
+    desktop_t *desk;
+    desktop_t *last_desk;
+    desktop_t *desk_head;
+    desktop_t *desk_tail;
+    monitor_t *prev;
+    monitor_t *next;
+};
+
 typedef struct {
     char name[MAXLEN];
 } rule_cause_t;
@@ -123,18 +141,26 @@ struct rule_t {
 typedef struct {
     node_t *node;
     desktop_t *desktop;
+    monitor_t *monitor;
 } window_location_t;
 
+typedef struct {
+    desktop_t *desktop;
+    monitor_t *monitor;
+} desktop_location_t;
+
 typedef struct {
     xcb_point_t position;
     xcb_button_t button;
     xcb_rectangle_t rectangle;
+    monitor_t *monitor;
     desktop_t *desktop;
     node_t *node;
     corner_t corner;
 } pointer_state_t;
 
 node_t *make_node(void);
+monitor_t *make_monitor(xcb_rectangle_t *);
 desktop_t *make_desktop(const char *);
 client_t *make_client(xcb_window_t);
 rule_t *make_rule(void);
index fcc601a14b7d569dad69950187b76e7b0ee8bc0d..143abf52ade99f108bcec897d8404a95f8cce191 100644 (file)
--- a/window.c
+++ b/window.c
 
 bool locate_window(xcb_window_t win, window_location_t *loc)
 {
-    node_t *n;
-    desktop_t *d = desk_head;
-
-    if (d == NULL)
-        return false;
+    monitor_t *m = mon_head;
+    while (m != NULL) {
+        desktop_t *d = m->desk_head;
+        while (d != NULL) {
+            node_t *n = first_extrema(d->root);
+            while (n != NULL) {
+                if (n->client->window == win) {
+                    loc->monitor = m;
+                    loc->desktop = d;
+                    loc->node = n;
+                    return true;
+                }
+                n = next_leaf(n);
+            }
+            d = d->next;
+        }
+        m = m->next;
+    }
+    return false;
+}
 
-    while (d != NULL) {
-        n = first_extrema(d->root);
-        while (n != NULL) {
-            if (n->client->window == win) {
+bool locate_desktop(char *name, desktop_location_t *loc)
+{
+    monitor_t *m = mon_head;
+    while (m != NULL) {
+        desktop_t *d = m->desk_head;
+        while (d != NULL) {
+            if (strcmp(d->name, name) == 0) {
+                loc->monitor = m;
                 loc->desktop = d;
-                loc->node = n;
                 return true;
             }
-            n = next_leaf(n);
+            d = d->next;
         }
-        d = d->next;
+        m = m->next;
     }
-
     return false;
 }
 
-void window_draw_border(node_t *n, bool focused)
+void window_draw_border(node_t *n, bool focused_window, bool focused_monitor)
 {
     if (n == NULL)
         return;
@@ -81,7 +98,7 @@ void window_draw_border(node_t *n, bool focused)
     xcb_gcontext_t gc = xcb_generate_id(dpy);
     xcb_create_gc(dpy, gc, pix, 0, NULL);
 
-    uint32_t main_border_color_pxl = get_main_border_color(n->client, focused);
+    uint32_t main_border_color_pxl = get_main_border_color(n->client, focused_window, focused_monitor);
 
     /* inner border */
     if (inner_border_width > 0) {
@@ -101,7 +118,7 @@ void window_draw_border(node_t *n, bool focused)
         xcb_poly_fill_rectangle(dpy, pix, gc, LENGTH(outer_rectangles), outer_rectangles);
     }
 
-    if (split_mode == MODE_MANUAL && focused) {
+    if (split_mode == MODE_MANUAL && focused_monitor && focused_window) {
         uint16_t fence = (int16_t) (n->split_ratio * ((split_dir == DIR_UP || split_dir == DIR_DOWN) ? height : width));
         presel_rectangles = malloc(2 * sizeof(xcb_rectangle_t));
         switch (split_dir) {
@@ -222,25 +239,25 @@ void list_windows(char *rsp)
 {
     char line[MAXLEN];
 
-    desktop_t *d = desk_head;
-
-    while (d != NULL) {
-        node_t *n = first_extrema(d->root);
-        while (n != NULL) {
-            snprintf(line, sizeof(line), "0x%X\n", n->client->window);
-            strncat(rsp, line, REMLEN(rsp));
-            n = next_leaf(n);
-        }
-        d = d->next;
-    }
+    for (monitor_t *m = mon_head; m != NULL; m = m->next)
+        for (desktop_t *d = m->desk_head; d != NULL; d = d->next)
+            for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n)) {
+                snprintf(line, sizeof(line), "0x%X\n", n->client->window);
+                strncat(rsp, line, REMLEN(rsp));
+            }
 }
 
-uint32_t get_main_border_color(client_t *c, bool focused)
+uint32_t get_main_border_color(client_t *c, bool focused_window, bool focused_monitor)
 {
     if (c == NULL)
         return 0;
 
-    if (focused) {
+    if (focused_monitor && focused_window) {
+        if (c->locked)
+            return focused_locked_border_color_pxl;
+        else
+            return focused_border_color_pxl;
+    } else if (focused_window) {
         if (c->locked)
             return active_locked_border_color_pxl;
         else
@@ -263,7 +280,7 @@ void update_floating_rectangle(client_t *c)
         c->floating_rectangle = (xcb_rectangle_t) {geom->x, geom->y, geom->width, geom->height};
         free(geom);
     } else {
-        c->floating_rectangle = (xcb_rectangle_t) {0, 0, 1, 1};
+        c->floating_rectangle = (xcb_rectangle_t) {0, 0, 32, 24};
     }
 }
 
index 5ecaf8c9b603d6e3fceef48ac8436b5918df22d2..9acdfbee1f750b86de67aafeb72620f58a5b2c99 100644 (file)
--- a/window.h
+++ b/window.h
@@ -7,7 +7,8 @@
 #include "types.h"
 
 bool locate_window(xcb_window_t, window_location_t *);
-void window_draw_border(node_t *, bool);
+bool locate_desktop(char *, desktop_location_t *);
+void window_draw_border(node_t *, bool, bool);
 void window_close(node_t *);
 void window_kill(desktop_t *, node_t *);
 void toggle_fullscreen(client_t *);
@@ -21,7 +22,7 @@ void window_lower(xcb_window_t);
 void window_set_visibility(xcb_window_t, bool);
 void window_hide(xcb_window_t);
 void window_show(xcb_window_t);
-uint32_t get_main_border_color(client_t *, bool);
+uint32_t get_main_border_color(client_t *, bool, bool);
 void update_floating_rectangle(client_t *);
 void list_windows(char *);