[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] xrandr: subscribe to RRScreenChange event



When Xrandr is available at compile and at run time, herbstluftwm
subscribes to the screen change events. These events are send, when
configuration of the monitors changes. The event is propagated to all
herbstclients via the hook.

    randr_screen_change	4108552	1497	724

An additional script can listen to those events and can start the
reconfiguration of the herbstluftwm monitors. This is especially useful
for using herbstluftwm within a virtual machine, whose screen size can
change quite often.
---
 Hopefully my mail client didn't fuckup the patch.

 config.mk            |  7 +++--
 doc/herbstluftwm.txt |  5 +++
 src/main.c           | 41 +++++++++++++++---------
 src/randr.c          | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/randr.h          | 17 ++++++++++
 5 files changed, 142 insertions(+), 17 deletions(-)
 create mode 100644 src/randr.c
 create mode 100644 src/randr.h

diff --git a/config.mk b/config.mk
index 2890dfb..d00645a 100644
--- a/config.mk
+++ b/config.mk
@@ -6,8 +6,11 @@ X11LIB = /usr/X11R6/lib
 XINERAMALIBS = `pkg-config --silence-errors --libs xinerama`
 XINERAMAFLAGS = `pkg-config --exists xinerama && echo -DXINERAMA`
 
+XRANDRLIBS = `pkg-config --silence-errors --libs xrandr`
+XRANDRFLAGS = `pkg-config --exists xrandr && echo -DXRANDR`
+
 INCS = -Isrc/ -I/usr/include -I${X11INC}  `pkg-config --cflags glib-2.0`
-LIBS = -lc -L${X11LIB} -lXext -lX11 $(XINERAMALIBS) `pkg-config --libs glib-2.0`
+LIBS = -lc -L${X11LIB} -lXext -lX11 $(XINERAMALIBS) ${XRANDRLIBS} `pkg-config --libs glib-2.0`
 
 ifeq ($(shell uname),Linux)
 LIBS += -lrt
@@ -24,7 +27,7 @@ VERSIONFLAGS = \
     -D HERBSTLUFT_VERSION_MINOR=$(VERSION_MINOR) \
     -D HERBSTLUFT_VERSION_PATCH=$(VERSION_PATCH)
 CPPFLAGS ?=
-CPPFLAGS += $(INCS) -D _XOPEN_SOURCE=600 $(VERSIONFLAGS) $(XINERAMAFLAGS)
+CPPFLAGS += $(INCS) -D _XOPEN_SOURCE=600 $(VERSIONFLAGS) $(XINERAMAFLAGS) ${XRANDRFLAGS}
 CPPFLAGS += -D HERBSTLUFT_GLOBAL_AUTOSTART=\"$(CONFIGDIR)/autostart\"
 LDFLAGS ?= -g
 DESTDIR =
diff --git a/doc/herbstluftwm.txt b/doc/herbstluftwm.txt
index 409a43b..7c6b0db 100644
--- a/doc/herbstluftwm.txt
+++ b/doc/herbstluftwm.txt
@@ -1521,6 +1521,11 @@ rule 'NAME' 'WINID'::
     A window with the id 'WINID' appeared which triggerd a rule with the
     consequence hook='NAME'.
 
+randr_screen_change 'TIMESTAMP' 'WIDTH' 'HEIGHT'::
+   When the xrandr extension was available at compile time and the X server does support it, this
+   hook is emitted, when the screen configuration has changed. This hook can be used to rearrange
+   the herbstluftwm monitors.
+
 There are also other useful hooks, which never will be emitted by herbstluftwm
 itself, but which can be emitted with the *emit_hook* command:
 
diff --git a/src/main.c b/src/main.c
index 7d42c2e..257de1b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -20,6 +20,7 @@
 #include "stack.h"
 #include "object.h"
 #include "decoration.h"
+#include "randr.h"
 // standard
 #include <string.h>
 #include <stdio.h>
@@ -765,22 +766,24 @@ static HandlerTable g_default_handler = {
 static struct {
     void (*init)();
     void (*destroy)();
+    bool (*xevent)(XEvent *);
 } g_modules[] = {
-    { ipc_init,         ipc_destroy         },
-    { object_tree_init, object_tree_destroy },
-    { key_init,         key_destroy         },
-    { settings_init,    settings_destroy    },
-    { floating_init,    floating_destroy    },
-    { stacklist_init,   stacklist_destroy   },
-    { layout_init,      layout_destroy      },
-    { tag_init,         tag_destroy         },
-    { clientlist_init,  clientlist_destroy  },
-    { decorations_init, decorations_destroy },
-    { monitor_init,     monitor_destroy     },
-    { ewmh_init,        ewmh_destroy        },
-    { mouse_init,       mouse_destroy       },
-    { hook_init,        hook_destroy        },
-    { rules_init,       rules_destroy       },
+    { ipc_init,         ipc_destroy         , 0},
+    { object_tree_init, object_tree_destroy , 0},
+    { key_init,         key_destroy         , 0},
+    { settings_init,    settings_destroy    , 0},
+    { floating_init,    floating_destroy    , 0},
+    { stacklist_init,   stacklist_destroy   , 0},
+    { layout_init,      layout_destroy      , 0},
+    { tag_init,         tag_destroy         , 0},
+    { clientlist_init,  clientlist_destroy  , 0},
+    { decorations_init, decorations_destroy , 0},
+    { monitor_init,     monitor_destroy     , 0},
+    { ewmh_init,        ewmh_destroy        , 0},
+    { mouse_init,       mouse_destroy       , 0},
+    { hook_init,        hook_destroy        , 0},
+    { rules_init,       rules_destroy       , 0},
+    { randr_init,       randr_destroy       , randr_xevent},
 };
 
 /* ----------------------------- */
@@ -1009,6 +1012,14 @@ int main(int argc, char* argv[]) {
             void (*handler) (XEvent*) = g_default_handler[event.type];
             if (handler != NULL) {
                 handler(&event);
+            } else {
+                // query all subsystems for the xevent
+                for (int i = LENGTH(g_modules); i --> 0;) {
+                    if (g_modules[i].xevent) {
+                        bool handled = g_modules[i].xevent(&event);
+                        if (handled) break;
+                    }
+                }
             }
         }
     }
diff --git a/src/randr.c b/src/randr.c
new file mode 100644
index 0000000..fda2d09
--- /dev/null
+++ b/src/randr.c
@@ -0,0 +1,89 @@
+/** Copyright 2014 Christian Dietrich. All rights reserved.
+ *
+ * This software is licensed under the "Simplified BSD License".
+ * See LICENSE for details */
+
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef XRANDR
+#include <X11/extensions/Xrandr.h>
+
+static Time rr_last_timestamp;
+#endif
+
+#include "globals.h"
+#include "hook.h"
+
+/// GLOBALS ///
+static int rr_event_base;
+
+
+/// FUNCTIONS ///
+void randr_init() {
+    rr_event_base = -1;
+
+#ifdef XRANDR
+    int ignore;
+
+    /* Query whether the xrandr extension is available in a version >= 1.2 */
+    if (XRRQueryExtension (g_display, &rr_event_base, &ignore)) {
+        // priv->randr_event_base = event_base;
+
+        int major_version;
+        int minor_version;
+
+        XRRQueryVersion (g_display, &major_version, &minor_version);
+        if (major_version < 1 || (major_version == 1 && minor_version < 2)) {
+            HSDebug("randr: xrandr version is too old (%d.%d); no screen notify events will be availabe",
+                    major_version, minor_version);
+            rr_event_base = -1;
+            return;
+        }
+
+        XRRSelectInput (g_display, g_root, RRScreenChangeNotifyMask);
+        HSDebug("randr: requested xrandr events for root window\n");
+        return;
+    } else {
+        HSDebug("randr: xrandr extension is not available");
+    }
+#else
+    HSDebug("randr: not linked against xrandr library\n");
+#endif
+}
+
+void randr_destroy() {
+}
+
+
+bool randr_xevent(XEvent * xevent) {
+#ifdef XRANDR
+    /* randr module didn't initialize correctly */
+    if (rr_event_base == -1) {
+        return false;
+    }
+
+    int event_num = xevent->type - rr_event_base;
+
+    if (event_num == RRScreenChangeNotify) {
+        XRRScreenChangeNotifyEvent *rr_event = (XRRScreenChangeNotifyEvent *) xevent;
+        if (rr_last_timestamp != rr_event->timestamp) {
+            rr_last_timestamp = rr_event->timestamp;
+
+            HSDebug("randr: screen change notify %u %d %d\n", 
+                    (guint32) rr_event->timestamp,
+                    rr_event->width, rr_event->height);
+
+            char timestamp[30] , width[30], height[30];
+            snprintf(timestamp, sizeof(timestamp), "%u", (guint32) rr_event->timestamp);
+            snprintf(width, sizeof(width), "%d", rr_event->width);
+            snprintf(height, sizeof(height), "%d", rr_event->height);
+
+            hook_emit_list("randr_screen_change", timestamp, width, height, NULL);
+        }
+
+        return true;
+    }
+#endif
+    return false;
+}
diff --git a/src/randr.h b/src/randr.h
new file mode 100644
index 0000000..6e26870
--- /dev/null
+++ b/src/randr.h
@@ -0,0 +1,17 @@
+/** Copyright 2014 Christian Dietrich. All rights reserved.
+ *
+ * This software is licensed under the "Simplified BSD License".
+ * See LICENSE for details */
+