1 /* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
2  * See LICENSE file for license details.
3  */
4 #define _X11_VISIBLE
5 #include "dat.h"
6 #include <X11/extensions/Xrender.h>
7 #include <X11/extensions/Xinerama.h>
8 #include "fns.h"
9 
10 #if RANDR_MAJOR < 1
11 #  error XRandR versions less than 1.0 are not supported
12 #endif
13 
14 static void	randr_screenchange(XRRScreenChangeNotifyEvent*);
15 static bool	randr_event_p(XEvent *e);
16 static void	randr_init(void);
17 static void	render_init(void);
18 static void	xinerama_init(void);
19 
20 typedef void (*EvHandler)(XEvent*);
21 static EvHandler	randr_handlers[RRNumberEvents];
22 
23 bool	have_RandR;
24 bool	have_render;
25 bool	have_xinerama;
26 int	randr_eventbase;
27 
28 static void
handle(XEvent * e,EvHandler h[],int base)29 handle(XEvent *e, EvHandler h[], int base) {
30 
31 	if(h[e->type-base])
32 		h[e->type-base](e);
33 }
34 
35 void
xext_init(void)36 xext_init(void) {
37 	randr_init();
38 	render_init();
39 	xinerama_init();
40 }
41 
42 void
xext_event(XEvent * e)43 xext_event(XEvent *e) {
44 
45 	if(randr_event_p(e))
46 		handle(e, randr_handlers, randr_eventbase);
47 }
48 
49 static void
randr_init(void)50 randr_init(void) {
51 	int errorbase, major, minor;
52 
53 	have_RandR = XRRQueryExtension(display, &randr_eventbase, &errorbase);
54 	if(have_RandR)
55 		if(XRRQueryVersion(display, &major, &minor) && major < 1)
56 			have_RandR = false;
57 	if(have_RandR)
58 		XRRSelectInput(display, scr.root.xid, RRScreenChangeNotifyMask);
59 }
60 
61 static bool
randr_event_p(XEvent * e)62 randr_event_p(XEvent *e) {
63 	return have_RandR
64 	    && (uint)e->type - randr_eventbase < RRNumberEvents;
65 }
66 
67 static void
randr_screenchange(XRRScreenChangeNotifyEvent * ev)68 randr_screenchange(XRRScreenChangeNotifyEvent *ev) {
69 
70 	XRRUpdateConfiguration((XEvent*)ev);
71 	if(ev->rotation*90 % 180)
72 		scr.rect = Rect(0, 0, ev->width, ev->height);
73 	else
74 		scr.rect = Rect(0, 0, ev->height, ev->width);
75 	init_screens();
76 }
77 
78 static EvHandler randr_handlers[] = {
79 	[RRScreenChangeNotify] = (EvHandler)randr_screenchange,
80 };
81 
82 /* Ripped most graciously from ecore_x. XRender documentation
83  * is sparse.
84  */
85 static void
render_init(void)86 render_init(void) {
87 	XVisualInfo *vip;
88 	XVisualInfo vi;
89 	int base, i, n;
90 
91 	have_render = XRenderQueryExtension(display, &base, &base);
92 	if(!have_render)
93 		return;
94 
95 	vi.class = TrueColor;
96 	vi.depth = 32;
97 	vi.screen = scr.screen;
98 	vip = XGetVisualInfo(display, VisualClassMask
99 				    | VisualDepthMask
100 				    | VisualScreenMask,
101 				    &vi, &n);
102 	for(i=0; i < n; i++)
103 		if(render_argb_p(vip[i].visual)) {
104 			render_visual = vip[i].visual;
105 			scr.visual32 = render_visual;
106 			break;
107 		}
108 	XFree(vip);
109 }
110 
111 bool
render_argb_p(Visual * v)112 render_argb_p(Visual *v) {
113 	XRenderPictFormat *f;
114 
115 	if(!have_render)
116 		return false;
117 	f = XRenderFindVisualFormat(display, v);
118 	return f
119 	    && f->type == PictTypeDirect
120 	    && f->direct.alphaMask;
121 }
122 
123 static void
xinerama_init(void)124 xinerama_init(void) {
125 	int base;
126 
127 	have_xinerama = XineramaQueryExtension(display, &base, &base);
128 }
129 
130 static bool
xinerama_active(void)131 xinerama_active(void) {
132 	return have_xinerama && XineramaIsActive(display);
133 }
134 
135 Rectangle*
xinerama_screens(int * np)136 xinerama_screens(int *np) {
137 	static Rectangle *rects;
138 	XineramaScreenInfo *res;
139 	int i, n;
140 
141 	if(!xinerama_active()) {
142 		*np = 1;
143 		return &scr.rect;
144 	}
145 
146 	free(rects);
147 	res = XineramaQueryScreens(display, &n);
148 	rects = emalloc(n * sizeof *rects);
149 	for(i=0; i < n; i++) {
150 		rects[i].min.x = res[i].x_org;
151 		rects[i].min.y = res[i].y_org;
152 		rects[i].max.x = res[i].x_org + res[i].width;
153 		rects[i].max.y = res[i].y_org + res[i].height;
154 	}
155 	XFree(res);
156 
157 	*np = n;
158 	return rects;
159 }
160 
161