]> git.lizzy.rs Git - bspwm.git/commitdiff
Handle monitors via RandR
authorBastien Dejean <nihilhill@gmail.com>
Tue, 28 May 2013 15:31:35 +0000 (17:31 +0200)
committerBastien Dejean <nihilhill@gmail.com>
Wed, 29 May 2013 06:35:13 +0000 (08:35 +0200)
Makefile
bspwm.c
bspwm.h
events.c
events.h
types.c
types.h

index a1811d2fbb9b7330f0bde9f63295d665e9983c12..8f0593bb6b624bacf838e9e1797ee5c6b3a475f9 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 0.6
 
 CC      = gcc
-LIBS    = -lm -lxcb -lxcb-icccm -lxcb-ewmh -lxcb-xinerama
+LIBS    = -lm -lxcb -lxcb-icccm -lxcb-ewmh -lxcb-randr
 CFLAGS  = -std=c99 -pedantic -Wall -Wextra -I$(PREFIX)/include
 CFLAGS  += -D_POSIX_C_SOURCE=200112L -DVERSION=\"$(VERSION)\"
 LDFLAGS = -L$(PREFIX)/lib
diff --git a/bspwm.c b/bspwm.c
index fa6f36393ef8896285ce70586bd2192c17306e99..1a6f1a78823331d0418d983d3101930b388e45b2 100644 (file)
--- a/bspwm.c
+++ b/bspwm.c
@@ -12,7 +12,7 @@
 #include <xcb/xcb.h>
 #include <xcb/xcb_event.h>
 #include <xcb/xcb_ewmh.h>
-#include <xcb/xinerama.h>
+#include <xcb/randr.h>
 #include "types.h"
 #include "settings.h"
 #include "messages.h"
@@ -49,8 +49,85 @@ void register_events(void)
     }
 }
 
+bool import_monitors(void)
+{
+    PUTS("import monitors");
+    xcb_randr_get_screen_resources_current_reply_t *sres = xcb_randr_get_screen_resources_current_reply(dpy, xcb_randr_get_screen_resources_current(dpy, root), NULL);
+    if (sres == NULL)
+        return false;
+
+    int len = xcb_randr_get_screen_resources_current_outputs_length(sres);
+    xcb_randr_output_t *outputs = xcb_randr_get_screen_resources_current_outputs(sres);
+
+    xcb_randr_get_output_info_cookie_t cookies[len];
+    for (int i = 0; i < len; i++)
+        cookies[i] = xcb_randr_get_output_info(dpy, outputs[i], XCB_CURRENT_TIME);
+
+    for (monitor_t *m = mon_head; m != NULL; m = m->next)
+        m->wired = false;
+
+    monitor_t *mm = NULL;
+    unsigned int num = 0;
+
+    for (int i = 0; i < len; i++) {
+        xcb_randr_get_output_info_reply_t *info = xcb_randr_get_output_info_reply(dpy, cookies[i], NULL);
+        if (info != NULL && info->crtc != XCB_NONE) {
+
+            xcb_randr_get_crtc_info_reply_t *cir = xcb_randr_get_crtc_info_reply(dpy, xcb_randr_get_crtc_info(dpy, info->crtc, XCB_CURRENT_TIME), NULL);
+            if (cir != NULL) {
+                xcb_rectangle_t rect = (xcb_rectangle_t) {cir->x, cir->y, cir->width, cir->height};
+                mm = get_monitor_by_id(outputs[i]);
+                if (mm != NULL) {
+                    mm->rectangle = rect;
+                    arrange(mm, mm->desk);
+                    mm->wired = true;
+                    PRINTF("update monitor %s\n", mm->name);
+                } else {
+                    mm = add_monitor(&rect);
+                    char *name = (char *)xcb_randr_get_output_info_name(info);
+                    size_t name_len = MIN(sizeof(mm->name), (size_t)xcb_randr_get_output_info_name_length(info));
+                    strncpy(mm->name, name, name_len);
+                    mm->name[name_len] = '\0';
+                    add_desktop(mm, NULL);
+                    PRINTF("add monitor %s\n", mm->name);
+                }
+                num++;
+            }
+            free(cir);
+        }
+        free(info);
+    }
+
+    monitor_t *m = mon_head;
+    while (m != NULL) {
+        monitor_t *next = m->next;
+        if (!m->wired) {
+            PRINTF("remove monitor %s\n", m->name);
+            transfer_desktops(mm, m);
+        }
+        m = next;
+    }
+
+    free(sres);
+    put_status();
+    return true;
+}
+
+void init(void)
+{
+    num_monitors = num_desktops = num_clients = 0;
+    monitor_uid = desktop_uid = client_uid = rule_uid = 0;
+    mon = last_mon = mon_head = mon_tail = NULL;
+    rule_head = rule_tail = NULL;
+    randr_base = 0;
+    split_mode = MODE_AUTOMATIC;
+    visible = true;
+    exit_status = 0;
+}
+
 void setup(void)
 {
+    init();
     ewmh_init();
     screen = xcb_setup_roots_iterator(xcb_get_setup(dpy)).data;
     if (screen == NULL)
@@ -93,46 +170,21 @@ void setup(void)
         free(iar);
     }
 
-    monitor_uid = desktop_uid = client_uid = rule_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);
-        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);
+    const xcb_query_extension_reply_t *qep = xcb_get_extension_data(dpy, &xcb_randr_id);
+    if (qep->present) {
+        randr_base = qep->first_event;
+        import_monitors();
+        xcb_randr_select_input(dpy, root, XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE);
     } else {
-        warn("Xinerama is inactive.");
+        warn("RandR is not available.\n");
         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();
     ewmh_update_current_desktop();
-    rule_head = rule_tail = NULL;
     frozen_pointer = make_pointer_state();
-    split_mode = MODE_AUTOMATIC;
-    visible = true;
-    exit_status = 0;
 }
 
 int main(int argc, char *argv[])
diff --git a/bspwm.h b/bspwm.h
index 3ec17033be72eee38d779657d8abe7a8a8374a2a..ba097e23621b27177069d05616b85ab4e243d9bc 100644 (file)
--- a/bspwm.h
+++ b/bspwm.h
@@ -41,6 +41,8 @@ bool visible;
 bool running;
 
 void register_events(void);
+bool import_monitors(void);
+void init(void);
 void setup(void);
 void cleanup(void);
 void quit(void);
index 94baa19290c754c00184869f8c8f2bf3a4536c1a..5d92640bf397d591d684503ea14052808ceb2b93 100644 (file)
--- a/events.c
+++ b/events.c
@@ -2,6 +2,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <xcb/xcb.h>
+#include <xcb/randr.h>
 #include <xcb/xcb_event.h>
 #include <xcb/xcb_icccm.h>
 #include "types.h"
@@ -16,7 +17,8 @@
 
 void handle_event(xcb_generic_event_t *evt)
 {
-    switch (XCB_EVENT_RESPONSE_TYPE(evt)) {
+    uint8_t resp_type = XCB_EVENT_RESPONSE_TYPE(evt);
+    switch (resp_type) {
         case XCB_MAP_REQUEST:
             map_request(evt);
             break;
@@ -42,6 +44,8 @@ void handle_event(xcb_generic_event_t *evt)
             motion_notify();
             break;
         default:
+            if (resp_type == randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY)
+                import_monitors();
             break;
     }
 }
index 9bb3493a620f91bab968d8674881675e14fcc87a..58fdf8ba08aa1b376fdb55379aa6ece8774a5357 100644 (file)
--- a/events.h
+++ b/events.h
@@ -4,6 +4,8 @@
 #include <xcb/xcb.h>
 #include <xcb/xcb_event.h>
 
+uint8_t randr_base;
+
 void handle_event(xcb_generic_event_t *);
 void map_request(xcb_generic_event_t *);
 void destroy_notify(xcb_generic_event_t *);
diff --git a/types.c b/types.c
index 350d04122713954c8921e908afbc5cc7c9fbba6e..cc9786fab80fc1bf9414c532c95cb0211a805ab4 100644 (file)
--- a/types.c
+++ b/types.c
@@ -31,6 +31,7 @@ monitor_t *make_monitor(xcb_rectangle_t *rect)
     else
         warn("no rectangle was given for monitor '%s'\n", m->name);
     m->top_padding = m->right_padding = m->bottom_padding = m->left_padding = 0;
+    m->wired = true;
     return m;
 }
 
@@ -42,7 +43,15 @@ monitor_t *find_monitor(char *name)
     return NULL;
 }
 
-void add_monitor(xcb_rectangle_t *rect)
+monitor_t *get_monitor_by_id(xcb_randr_output_t id)
+{
+    for (monitor_t *m = mon_head; m != NULL; m = m->next)
+        if (m->id == id)
+            return m;
+    return NULL;
+}
+
+monitor_t *add_monitor(xcb_rectangle_t *rect)
 {
     monitor_t *m = make_monitor(rect);
     if (mon == NULL) {
@@ -55,6 +64,7 @@ void add_monitor(xcb_rectangle_t *rect)
         mon_tail = m;
     }
     num_monitors++;
+    return m;
 }
 
 void remove_monitor(monitor_t *m)
@@ -75,6 +85,17 @@ void remove_monitor(monitor_t *m)
     num_monitors--;
 }
 
+void transfer_desktops(monitor_t *dst, monitor_t *src)
+{
+    if (dst == NULL || src == NULL)
+        return;
+    dst->desk_tail->next = src->desk_head;
+    src->desk_head->prev = dst->desk_tail;
+    dst->desk_tail = src->desk_tail;
+    src->desk = src->last_desk = src->desk_head = src->desk_tail = NULL;
+    remove_monitor(src);
+}
+
 desktop_t *make_desktop(const char *name)
 {
     desktop_t *d = malloc(sizeof(desktop_t));
diff --git a/types.h b/types.h
index ca620d4854af687207c08c214e70e6f09393b08d..4dd959cc7bcca0cbcdab84b3b13d96d82b4281f6 100644 (file)
--- a/types.h
+++ b/types.h
@@ -3,6 +3,7 @@
 
 #include <stdbool.h>
 #include <xcb/xcb.h>
+#include <xcb/randr.h>
 #include <xcb/xcb_event.h>
 #include "helpers.h"
 
@@ -174,7 +175,9 @@ struct desktop_t {
 typedef struct monitor_t monitor_t;
 struct monitor_t {
     char name[MAXLEN];
+    xcb_randr_output_t id;
     xcb_rectangle_t rectangle;
+    bool wired;
     int top_padding;
     int right_padding;
     int bottom_padding;
@@ -244,8 +247,10 @@ typedef struct {
 node_t *make_node(void);
 monitor_t *make_monitor(xcb_rectangle_t *);
 monitor_t *find_monitor(char *);
-void add_monitor(xcb_rectangle_t *);
+monitor_t *get_monitor_by_id(xcb_randr_output_t);
+monitor_t *add_monitor(xcb_rectangle_t *);
 void remove_monitor(monitor_t *);
+void transfer_desktops(monitor_t *, monitor_t *);
 desktop_t *make_desktop(const char *);
 void add_desktop(monitor_t *, char *);
 void empty_desktop(desktop_t *);