I often connect my laptop to an external monitor and use it to extend my 
desktop. This patch adds a new layout 'multihead' which uses Xrandr to detect 
the configuration of monitors, and adjusts window sizes accordingly.

Here is my X screen layout:
--------------
|     |      |
|     |      |
------+      |
      --------

The left screen is the internal (widescreen) monitor on my laptop with 1280x800 
resolution. The right one is my external monitor with 1280x1024 resolution. The 
standard dwm tile layout has the problem that it uses the dead space underneath 
the left screen, and I am unable to see anything there. This patch detects how 
many monitors I have connected via a call to xrandr, and tiles windows so that 
they fit fullscreen in each window. As soon as you have more windows than 
monitors, one monitor is used for stacking and the others are used for 
fullscreen.

There is a lot of missing functionality:
   * Add the ability to move a window to different screens. Right now you are 
stuck with where this layout places them.
   * Don't re-detect monitor layout each time we tile windows. Instead use the 
Xrandr event mechanisms.
   * Disable this layout automatically when there is only one monitor connected.
   * Decide on the order of monitors based on x/y positions instead of whatever 
order we get them from Xrandr.

The patch is against the latest hg tip (with all sources merged into one file). 
I'm pretty new to this so I welcome even the most basic feedback.

You will need the Xrandr extension and dev headers to compile this patch 
("apt-get install libxrandr-dev" in Ubuntu).

Cheers,
Tim

diff -r d036b2f17567 config.h
--- a/config.h  Sun Sep 16 13:42:37 2007 +0200
+++ b/config.h  Sun Sep 16 11:27:16 2007 -0700
@@ -21,9 +21,12 @@ static Rule rules[] = {
        { "Acroread",                   NULL,           True },
 };
 
+#include "multihead.c"
+
 /* layout(s) */
 static Layout layouts[] = {
        /* symbol               function */
+       { "UU=",                multihead }, /* first entry is default */
        { "[]=",                tile }, /* first entry is default */
        { "><>",                floating },
 };
diff -r d036b2f17567 config.mk
--- a/config.mk Sun Sep 16 13:42:37 2007 +0200
+++ b/config.mk Sun Sep 16 11:27:16 2007 -0700
@@ -12,7 +12,7 @@ X11LIB = /usr/X11R6/lib
 
 # includes and libs
 INCS = -I. -I/usr/include -I${X11INC}
-LIBS = -L/usr/lib -lc -L${X11LIB} -lX11
+LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lXrandr
 
 # flags
 CFLAGS = -Os ${INCS} -DVERSION=\"${VERSION}\"
diff -r d036b2f17567 multihead.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/multihead.c       Sun Sep 16 11:27:16 2007 -0700
@@ -0,0 +1,41 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdio.h>
+#include <X11/extensions/Xrandr.h>
+
+void
+multihead(void) {
+       unsigned int i, n, nw, nh, nx, ny;
+       Client *c;
+       XRRScreenResources  *res;
+       XRRCrtcInfo *crtc_info, *last_crtc_info;
+
+       for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
+               n++;
+
+       res = XRRGetScreenResources(dpy, root);
+       last_crtc_info = XRRGetCrtcInfo(dpy, res, res->crtcs[res->ncrtc-1]);
+
+       for(i = 0, c = nexttiled(clients); c; c = nexttiled(c->next), i++) {
+               c->ismax = False;
+               if(i < res->ncrtc - 1) { /* master */
+                       crtc_info = XRRGetCrtcInfo(dpy, res, res->crtcs[i]);
+
+                       nx = (wax > crtc_info->x) ? wax : crtc_info->x;
+                       nw = (crtc_info->x + crtc_info->width) - nx - 2 * 
c->border;
+                       ny = (way > crtc_info->y) ? way : crtc_info->y;
+                       nh = (crtc_info->y + crtc_info->height) - ny - 2 * 
c->border;
+               }
+               else {  /* tile window */
+                       nx = (wax > last_crtc_info->x) ? wax : 
last_crtc_info->x;
+                       nw = (last_crtc_info->x + last_crtc_info->width) - nx - 
2 * c->border;
+                       ny = (way > last_crtc_info->y) ? way : 
last_crtc_info->y;
+                       nh = (last_crtc_info->y + last_crtc_info->height) - ny 
- 2 * c->border;
+
+                       if(n - res->ncrtc != 0) {
+                               nh = nh / (n - res->ncrtc + 1);
+                               ny += (i - res->ncrtc + 1) * nh;
+                       }
+               }
+               resize(c, nx, ny, nw, nh, False);
+       }
+}

Reply via email to