summaryrefslogtreecommitdiffstats
path: root/wm-addons/jgmenu/xrandr.patch
blob: 71047a30a8b9532ed2a64a9599cbe1003f8544cc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
From f8ccef404fe8436e4473e48cfa66d8389286e234 Mon Sep 17 00:00:00 2001
From: Johan Malm <jgm323@gmail.com>
Date: Sat, 11 Aug 2018 13:45:35 +0100
Subject: [PATCH] x11-ui.c: replace xinerama with xrandr (issue #60)

xinerama has been reported to segfault with some new graphics cards.

Suggested-by: @vaygr
---
 Makefile.inc |  2 +-
 x11-ui.c     | 91 +++++++++++++++++++++++++++++++++++-----------------
 2 files changed, 63 insertions(+), 30 deletions(-)

diff --git a/Makefile.inc b/Makefile.inc
index b33b399..9f362c8 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -23,7 +23,7 @@ jgmenu-ob:  CFLAGS  += `xml2-config --cflags`
 jgmenu-xdg: CFLAGS  += `xml2-config --cflags`
 jgmenu-lx:  CFLAGS  += `pkg-config --cflags glib-2.0 libmenu-cache`
 
-jgmenu:     LIBS += `pkg-config x11 xinerama cairo pango pangocairo librsvg-2.0 --libs`
+jgmenu:     LIBS += `pkg-config x11 xrandr cairo pango pangocairo librsvg-2.0 --libs`
 jgmenu:     LIBS += -pthread -lrt -lpng
 jgmenu-ob:  LIBS += `xml2-config --libs`
 jgmenu-xdg: LIBS += `xml2-config --libs`
diff --git a/x11-ui.c b/x11-ui.c
index 7ed7678..e6df14d 100644
--- a/x11-ui.c
+++ b/x11-ui.c
@@ -16,7 +16,7 @@
 #include <X11/Xlib.h>
 #include <X11/Xatom.h>
 #include <X11/Xutil.h>
-#include <X11/extensions/Xinerama.h>
+#include <X11/extensions/Xrandr.h>
 #include <unistd.h>		/* for usleep */
 
 #include "x11-ui.h"
@@ -131,49 +131,82 @@ void ui_init(void)
 	ui->root = RootWindow(ui->dpy, ui->screen);
 }
 
-static void print_screen_info(int n, XineramaScreenInfo *screen_info)
+static void print_screen_info(void)
 {
-	int i;
-
-	info("%d monitor(s) detected", n);
-	for (i = 0; i < n; i++)
-		printf("        - monitor-%d: x0=%d; y0=%d; w=%d; h=%d\n",
-		       i + 1, screen_info[i].x_org, screen_info[i].y_org,
-		       screen_info[i].width, screen_info[i].height);
+	int i, n;
+	XRRScreenResources *sr;
+	XRRCrtcInfo *ci = NULL;
+
+	sr = XRRGetScreenResources(ui->dpy, DefaultRootWindow(ui->dpy));
+	n = sr->noutput;
+	info("%d xrandr outputs(s) detected", n);
+	for (i = 0; i < n; i++) {
+		ci = XRRGetCrtcInfo(ui->dpy, sr, sr->crtcs[i]);
+		if (!ci->width || !ci->height)
+			printf("    - monitor-%d: not connected\n", i + 1);
+		else
+			printf("    - monitor-%d: x0=%d; y0=%d; w=%d; h=%d\n",
+			       i + 1, ci->x, ci->y, ci->width, ci->height);
+	}
+	XRRFreeCrtcInfo(ci);
+	XRRFreeScreenResources(sr);
 }
 
-#define INTERSECT(x, y, w, h, r)  (MAX(0, MIN((x) + (w), (r).x_org + (r).width)  - \
-				   MAX((x), (r).x_org)) &&\
-				   MAX(0, MIN((y) + (h), (r).y_org + (r).height) - \
-				   MAX((y), (r).y_org)))
+static int intersect(int x, int y, int w, int h, XRRCrtcInfo *ci)
+{
+	return MAX(0, MIN(x + w, (int)ci->x + (int)ci->width) - MAX(x, (int)ci->x)) &&
+	       MAX(0, MIN(y + h, (int)ci->y + (int)ci->height) - MAX(y, (int)ci->y));
+}
 
 void ui_get_screen_res(int *x0, int *y0, int *width, int *height, int monitor)
 {
 	int i, n, x, y, di;
 	unsigned int du;
 	Window dw;
-	XineramaScreenInfo *screen_info;
+	XRRScreenResources *sr;
+	XRRCrtcInfo *ci = NULL;
 
-	screen_info = XineramaQueryScreens(ui->dpy, &n);
-	BUG_ON(!screen_info);
-	XQueryPointer(ui->dpy, ui->root, &dw, &dw, &x, &y, &di, &di, &du);
 	if (getenv("JGMENU_SCREEN_INFO"))
-		print_screen_info(n, screen_info);
-	for (i = 0; i < n; i++)
-		if (INTERSECT(x, y, 1, 1, screen_info[i]))
-			break;
+		print_screen_info();
+	sr = XRRGetScreenResources(ui->dpy, DefaultRootWindow(ui->dpy));
+	BUG_ON(!sr);
+	n = sr->noutput;
 
-	/* handle user specified monitor (from config file) */
+	/*
+	 * Global variable config.monitor let's the user specify a monitor.
+	 * If not set, we use the current pointer position
+	 */
 	if (monitor) {
 		if (monitor > n)
-			die("cannot connect to monitor '%d' (max %d)", monitor, n);
-		i = monitor - 1;
+			die("cannot connect to monitor '%d'", monitor);
+		ci = XRRGetCrtcInfo(ui->dpy, sr, sr->crtcs[monitor - 1]);
+		if (!ci->width || !ci->height)
+			die("cannot connect to monitor '%d'", monitor);
+		info("using user specified monitor '%d'", monitor);
+		goto monitor_selected;
+	}
+
+	XQueryPointer(ui->dpy, ui->root, &dw, &dw, &x, &y, &di, &di, &du);
+	for (i = 0; i < n; i++) {
+		ci = XRRGetCrtcInfo(ui->dpy, sr, sr->crtcs[i]);
+		BUG_ON(!ci);
+		if (!ci->width || !ci->height)
+			continue;
+		if (intersect(x, y, 1, 1, ci)) {
+			info("using monitor '%d'", i + 1);
+			break;
+		}
 	}
-	*x0 = screen_info[i].x_org;
-	*y0 = screen_info[i].y_org;
-	*width = screen_info[i].width;
-	*height = screen_info[i].height;
-	XFree(screen_info);
+
+monitor_selected:
+	if (!ci)
+		die("connection could be established to monitor");
+	*x0 = ci->x;
+	*y0 = ci->y;
+	*width = ci->width;
+	*height = ci->height;
+	XRRFreeCrtcInfo(ci);
+	XRRFreeScreenResources(sr);
 }
 
 void set_wm_class(void)