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