tAdd multi-monitor support using XRandR extension - glazier - window management experiments
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) Submodules
(DIR) README
(DIR) LICENSE
---
(DIR) commit 2a1185aafa91b236b58db09e727327ffb0f6345c
(DIR) parent 66f4ae619cd318e730f1bee75a549195751923b0
(HTM) Author: Willy Goiffon <dev@z3bra.org>
Date: Tue, 9 Jun 2020 20:12:52 +0200
Add multi-monitor support using XRandR extension
Diffstat:
M config.mk | 2 +-
M glazier.c | 103 +++++++++++++++++++++++++++++--
2 files changed, 100 insertions(+), 5 deletions(-)
---
(DIR) diff --git a/config.mk b/config.mk
t@@ -7,4 +7,4 @@ MANDIR = ${PREFIX}/man
CPPFLAGS = -I./libwm
CFLAGS = -Wall -Wextra -pedantic -g
LDFLAGS = -L./libwm ${LIBS}
-LIBS = -lxcb -lxcb-cursor -lwm
+LIBS = -lxcb -lxcb-cursor -lxcb-randr -lwm
(DIR) diff --git a/glazier.c b/glazier.c
t@@ -2,6 +2,7 @@
#include <stdlib.h>
#include <xcb/xcb.h>
#include <xcb/xcb_cursor.h>
+#include <xcb/randr.h>
#include "arg.h"
#include "wm.h"
t@@ -21,6 +22,10 @@ struct cursor_t {
int mode;
};
+struct geom_t {
+ int x, y, w, h;
+};
+
enum {
XHAIR_DFLT,
XHAIR_MOVE,
t@@ -44,6 +49,11 @@ static int inflate(xcb_window_t, int);
static int outline(xcb_drawable_t, int, int, int, int);
static int ev_callback(xcb_generic_event_t *);
+/* XRandR specific functions */
+static struct geom_t * monitor(int, int);
+static int crossedge(xcb_window_t);
+static int snaptoedge(xcb_window_t);
+
/* XCB events callbacks */
static int cb_default(xcb_generic_event_t *);
static int cb_create(xcb_generic_event_t *);
t@@ -299,7 +309,6 @@ cb_create(xcb_generic_event_t *ev)
int
cb_mapreq(xcb_generic_event_t *ev)
{
- int x, y;
xcb_map_request_event_t *e;
e = (xcb_map_request_event_t *)ev;
t@@ -312,9 +321,8 @@ cb_mapreq(xcb_generic_event_t *ev)
wm_set_focus(e->window);
/* prevent window to pop outside the screen */
- x = wm_get_attribute(e->window, ATTR_X);
- y = wm_get_attribute(e->window, ATTR_Y);
- wm_move(e->window, ABSOLUTE, x, y);
+ if (crossedge(e->window))
+ snaptoedge(e->window);
return 0;
}
t@@ -664,6 +672,93 @@ ev_callback(xcb_generic_event_t *ev)
return cb_default(ev);
}
+/*
+ * Return the geometry of the monitor pointed to by the given coordinates
+ */
+struct geom_t *
+monitor(int x, int y)
+{
+ static struct geom_t m;
+ xcb_randr_get_monitors_cookie_t c;
+ xcb_randr_get_monitors_reply_t *r;
+ xcb_randr_monitor_info_iterator_t i;
+
+ /* get_active: ignore inactive monitors */
+ c = xcb_randr_get_monitors(conn, scrn->root, 1);
+ r = xcb_randr_get_monitors_reply(conn, c, NULL);
+ i = xcb_randr_get_monitors_monitors_iterator(r);
+
+ while (i.rem > 0) {
+ if (x >= i.data->x
+ && y >= i.data->y
+ && x <= i.data->width + i.data->x
+ && y <= i.data->height + i.data->y) {
+ m.x = i.data->x;
+ m.y = i.data->y;
+ m.w = i.data->width;
+ m.h = i.data->height;
+ return &m;
+ }
+ xcb_randr_monitor_info_next(&i);
+ }
+
+ return NULL;
+}
+
+/*
+ * Returns 1 is the given window's geometry crosses the monitor's edge,
+ * and 0 otherwise
+ */
+int
+crossedge(xcb_window_t wid)
+{
+ int b;
+ struct geom_t *m, w;
+
+ b = wm_get_attribute(wid, ATTR_B);
+ w.x = wm_get_attribute(wid, ATTR_X);
+ w.y = wm_get_attribute(wid, ATTR_Y);
+ w.w = wm_get_attribute(wid, ATTR_W);
+ w.h = wm_get_attribute(wid, ATTR_H);
+ m = monitor(w.x, w.y);
+
+ if ((w.x + w.w + 2*b > m->x + m->w)
+ || (w.y + w.h + 2*b > m->y + m->h))
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Moves a window so that its border doesn't cross the monitor's edge
+ */
+int
+snaptoedge(xcb_window_t wid)
+{
+ int tp, b;
+ struct geom_t *m, w;
+
+ b = wm_get_attribute(wid, ATTR_B);
+ w.x = wm_get_attribute(wid, ATTR_X);
+ w.y = wm_get_attribute(wid, ATTR_Y);
+ w.w = wm_get_attribute(wid, ATTR_W);
+ w.h = wm_get_attribute(wid, ATTR_H);
+ m = monitor(w.x, w.y);
+
+ tp = 0;
+
+ if (w.w + 2*b > m->w) { tp = 1; w.w = m->w - 2*b; }
+ if (w.h + 2*b > m->h) { tp = 1; w.h = m->h - 2*b; }
+
+ if (w.x + w.w + 2*b > m->x + m->w) { tp = 1; w.x = MAX(m->x + b, m->x + m->w - w.w - 2*b); }
+ if (w.y + w.h + 2*b > m->y + m->h) { tp = 1; w.y = MAX(m->y + b, m->y + m->h - w.h - 2*b); }
+
+ if (tp)
+ wm_teleport(wid, w.x, w.y, w.w, w.h);
+
+ return 0;
+}
+
int
main (int argc, char *argv[])
{