summaryrefslogtreecommitdiff
path: root/cmd/wmii/xext.c
blob: ba851e5cba44462c7983c81b198e111d713dfa42 (plain)
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
151
152
153
154
155
156
157
158
159
160
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
 * See LICENSE file for license details.
 */
#define _X11_VISIBLE
#include "dat.h"
#include <X11/extensions/Xrender.h>
#include <X11/extensions/Xinerama.h>
#include "fns.h"

#if RANDR_MAJOR < 1
#  error XRandR versions less than 1.0 are not supported
#endif

static void	randr_screenchange(XRRScreenChangeNotifyEvent*);
static bool	randr_event_p(XEvent *e);
static void	randr_init(void);
static void	render_init(void);
static void	xinerama_init(void);

typedef void (*EvHandler)(XEvent*);
static EvHandler	randr_handlers[RRNumberEvents];

bool	have_RandR;
bool	have_render;
bool	have_xinerama;
int	randr_eventbase;

static void
handle(XEvent *e, EvHandler h[], int base) {

	if(h[e->type-base])
		h[e->type-base](e);
}

void
xext_init(void) {
	randr_init();
	render_init();
	xinerama_init();
}

void
xext_event(XEvent *e) {

	if(randr_event_p(e))
		handle(e, randr_handlers, randr_eventbase);
}

static void
randr_init(void) {
	int errorbase, major, minor;

	have_RandR = XRRQueryExtension(display, &randr_eventbase, &errorbase);
	if(have_RandR)
		if(XRRQueryVersion(display, &major, &minor) && major < 1)
			have_RandR = false;
	if(have_RandR)
		XRRSelectInput(display, scr.root.xid, RRScreenChangeNotifyMask);
}

static bool
randr_event_p(XEvent *e) {
	return have_RandR
	    && (uint)e->type - randr_eventbase < RRNumberEvents;
}

static void
randr_screenchange(XRRScreenChangeNotifyEvent *ev) {

	XRRUpdateConfiguration((XEvent*)ev);
	if(ev->rotation*90 % 180)
		scr.rect = Rect(0, 0, ev->width, ev->height);
	else
		scr.rect = Rect(0, 0, ev->height, ev->width);
	init_screens();
}

static EvHandler randr_handlers[] = {
	[RRScreenChangeNotify] = (EvHandler)randr_screenchange,
};

/* Ripped most graciously from ecore_x. XRender documentation
 * is sparse.
 */
static void
render_init(void) {
	XVisualInfo *vip;
	XVisualInfo vi;
	int base, i, n;

	have_render = XRenderQueryExtension(display, &base, &base);
	if(!have_render)
		return;

	vi.class = TrueColor;
	vi.depth = 32;
	vi.screen = scr.screen;
	vip = XGetVisualInfo(display, VisualClassMask
				    | VisualDepthMask
				    | VisualScreenMask,
				    &vi, &n);
	for(i=0; i < n; i++)
		if(render_argb_p(vip[i].visual)) {
			render_visual = vip[i].visual;
			scr.visual32 = render_visual;
			break;
		}
	XFree(vip);
}

bool
render_argb_p(Visual *v) {
	XRenderPictFormat *f;

	if(!have_render)
		return false;
	f = XRenderFindVisualFormat(display, v);
	return f
	    && f->type == PictTypeDirect
	    && f->direct.alphaMask;
}

static void
xinerama_init(void) {
	int base;

	have_xinerama = XineramaQueryExtension(display, &base, &base);
}

static bool
xinerama_active(void) {
	return have_xinerama && XineramaIsActive(display);
}

Rectangle*
xinerama_screens(int *np) {
	static Rectangle *rects;
	XineramaScreenInfo *res;
	int i, n;

	if(!xinerama_active()) {
		*np = 1;
		return &scr.rect;
	}

	free(rects);
	res = XineramaQueryScreens(display, &n);
	rects = emalloc(n * sizeof *rects);
	for(i=0; i < n; i++) {
		rects[i].min.x = res[i].x_org;
		rects[i].min.y = res[i].y_org;
		rects[i].max.x = res[i].x_org + res[i].width;
		rects[i].max.y = res[i].y_org + res[i].height;
	}
	XFree(res);

	*np = n;
	return rects;
}