1428d7b3dSmrg/*
2428d7b3dSmrg * Copyright © 2013 Intel Corporation
3428d7b3dSmrg *
4428d7b3dSmrg * Permission is hereby granted, free of charge, to any person obtaining a
5428d7b3dSmrg * copy of this software and associated documentation files (the "Software"),
6428d7b3dSmrg * to deal in the Software without restriction, including without limitation
7428d7b3dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8428d7b3dSmrg * and/or sell copies of the Software, and to permit persons to whom the
9428d7b3dSmrg * Software is furnished to do so, subject to the following conditions:
10428d7b3dSmrg *
11428d7b3dSmrg * The above copyright notice and this permission notice (including the next
12428d7b3dSmrg * paragraph) shall be included in all copies or substantial portions of the
13428d7b3dSmrg * Software.
14428d7b3dSmrg *
15428d7b3dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16428d7b3dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17428d7b3dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18428d7b3dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19428d7b3dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20428d7b3dSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21428d7b3dSmrg * IN THE SOFTWARE.
22428d7b3dSmrg *
23428d7b3dSmrg */
24428d7b3dSmrg
25428d7b3dSmrg#ifdef HAVE_CONFIG_H
26428d7b3dSmrg#include "config.h"
27428d7b3dSmrg#endif
28428d7b3dSmrg
29428d7b3dSmrg#include <X11/Xlib.h>
30428d7b3dSmrg#include <X11/Xatom.h>
31428d7b3dSmrg
32428d7b3dSmrg#include <X11/Xlibint.h>
33428d7b3dSmrg#include <X11/extensions/record.h>
34428d7b3dSmrg#include <X11/extensions/XShm.h>
35428d7b3dSmrg#if HAVE_X11_EXTENSIONS_SHMPROTO_H
36428d7b3dSmrg#include <X11/extensions/shmproto.h>
37428d7b3dSmrg#elif HAVE_X11_EXTENSIONS_SHMSTR_H
38428d7b3dSmrg#include <X11/extensions/shmstr.h>
39428d7b3dSmrg#else
40428d7b3dSmrg#error Failed to find the right header for X11 MIT-SHM protocol definitions
41428d7b3dSmrg#endif
42428d7b3dSmrg#include <X11/extensions/Xdamage.h>
43428d7b3dSmrg#if HAVE_X11_EXTENSIONS_XINERAMA_H
44428d7b3dSmrg#include <X11/extensions/Xinerama.h>
45428d7b3dSmrg#define USE_XINERAMA
46428d7b3dSmrg#endif
47428d7b3dSmrg#include <X11/extensions/Xrandr.h>
48428d7b3dSmrg#include <X11/extensions/Xrender.h>
49428d7b3dSmrg#include <X11/Xcursor/Xcursor.h>
50428d7b3dSmrg#include <pixman.h>
51428d7b3dSmrg
52428d7b3dSmrg#include <sys/types.h>
53428d7b3dSmrg#include <sys/ipc.h>
54428d7b3dSmrg#include <sys/shm.h>
55428d7b3dSmrg#include <sys/timerfd.h>
56428d7b3dSmrg#include <sys/poll.h>
57428d7b3dSmrg#include <sys/socket.h>
58428d7b3dSmrg#include <sys/un.h>
59428d7b3dSmrg
60428d7b3dSmrg#include <stdarg.h>
61428d7b3dSmrg#include <stdio.h>
62428d7b3dSmrg#include <stdlib.h>
63428d7b3dSmrg#include <stdint.h>
64428d7b3dSmrg#include <signal.h>
65428d7b3dSmrg#include <getopt.h>
66428d7b3dSmrg#include <limits.h>
67428d7b3dSmrg#include <unistd.h>
68428d7b3dSmrg#include <fcntl.h>
69428d7b3dSmrg#include <assert.h>
70428d7b3dSmrg
71428d7b3dSmrg#define FORCE_FULL_REDRAW 0
72428d7b3dSmrg#define FORCE_16BIT_XFER 0
73428d7b3dSmrg
74428d7b3dSmrg#define DBG(v, x) if (verbose & v) printf x
75428d7b3dSmrgstatic int verbose;
76428d7b3dSmrg#define X11 0x1
77428d7b3dSmrg#define XRR 0x1
78428d7b3dSmrg#define TIMER 0x4
79428d7b3dSmrg#define DRAW 0x8
80428d7b3dSmrg#define DAMAGE 0x10
81428d7b3dSmrg#define CURSOR 0x20
82428d7b3dSmrg#define POLL 0x40
83428d7b3dSmrg
84428d7b3dSmrgstruct display {
85428d7b3dSmrg	Display *dpy;
86428d7b3dSmrg	struct clone *clone;
87428d7b3dSmrg	struct context *ctx;
88428d7b3dSmrg
89428d7b3dSmrg	int damage_event, damage_error;
90428d7b3dSmrg	int xfixes_event, xfixes_error;
91428d7b3dSmrg	int rr_event, rr_error, rr_active;
92428d7b3dSmrg	int xinerama_event, xinerama_error, xinerama_active;
93428d7b3dSmrg	int dri3_active;
94428d7b3dSmrg	Window root;
95428d7b3dSmrg	Visual *visual;
96428d7b3dSmrg	Damage damage;
97428d7b3dSmrg
98428d7b3dSmrg	int width;
99428d7b3dSmrg	int height;
100428d7b3dSmrg	int depth;
101428d7b3dSmrg
102428d7b3dSmrg	XRenderPictFormat *root_format;
103428d7b3dSmrg	XRenderPictFormat *rgb16_format;
104428d7b3dSmrg	XRenderPictFormat *rgb24_format;
105428d7b3dSmrg
106428d7b3dSmrg	int has_shm;
107428d7b3dSmrg	int has_shm_pixmap;
108428d7b3dSmrg	int shm_opcode;
109428d7b3dSmrg	int shm_event;
110428d7b3dSmrg
111428d7b3dSmrg	Cursor invisible_cursor;
112428d7b3dSmrg	Cursor visible_cursor;
113428d7b3dSmrg
114428d7b3dSmrg	XcursorImage cursor_image;
115428d7b3dSmrg	int cursor_serial;
116428d7b3dSmrg	int cursor_x;
117428d7b3dSmrg	int cursor_y;
118428d7b3dSmrg	int cursor_moved;
119428d7b3dSmrg	int cursor_visible;
120428d7b3dSmrg	int cursor;
121428d7b3dSmrg
122428d7b3dSmrg	int flush;
123428d7b3dSmrg	int send;
124428d7b3dSmrg	int skip_clone;
125428d7b3dSmrg	int skip_frame;
126428d7b3dSmrg};
127428d7b3dSmrg
128428d7b3dSmrgstruct output {
129428d7b3dSmrg	struct display *display;
130428d7b3dSmrg	Display *dpy;
131428d7b3dSmrg	char *name;
132428d7b3dSmrg	RROutput rr_output;
133428d7b3dSmrg	RRCrtc rr_crtc;
134428d7b3dSmrg	Window window;
135428d7b3dSmrg	Picture win_picture;
136428d7b3dSmrg	Picture pix_picture;
137428d7b3dSmrg	Pixmap pixmap;
138428d7b3dSmrg	GC gc;
139428d7b3dSmrg
140428d7b3dSmrg	long serial;
141428d7b3dSmrg	int use_shm;
142428d7b3dSmrg	int use_shm_pixmap;
143428d7b3dSmrg	XShmSegmentInfo shm;
144428d7b3dSmrg
145428d7b3dSmrg	XRenderPictFormat *use_render;
146428d7b3dSmrg
147428d7b3dSmrg	int x, y;
148428d7b3dSmrg	XRRModeInfo mode;
149428d7b3dSmrg	Rotation rotation;
150428d7b3dSmrg};
151428d7b3dSmrg
152428d7b3dSmrgstruct clone {
153428d7b3dSmrg	struct clone *next;
154428d7b3dSmrg	struct clone *active;
155428d7b3dSmrg
156428d7b3dSmrg	struct output src, dst;
157428d7b3dSmrg	long timestamp;
158428d7b3dSmrg
159428d7b3dSmrg	XShmSegmentInfo shm;
160428d7b3dSmrg	XImage image;
161428d7b3dSmrg
162428d7b3dSmrg	int width, height, depth;
163428d7b3dSmrg	struct { int x1, x2, y1, y2; } damaged;
164428d7b3dSmrg	int rr_update;
165428d7b3dSmrg
166428d7b3dSmrg	struct dri3_fence {
167428d7b3dSmrg		XID xid;
168428d7b3dSmrg		void *addr;
169428d7b3dSmrg	} dri3;
170428d7b3dSmrg};
171428d7b3dSmrg
172428d7b3dSmrgstruct context {
173428d7b3dSmrg	struct display *display;
174428d7b3dSmrg	struct clone *clones;
175428d7b3dSmrg	struct clone *active;
176428d7b3dSmrg	struct pollfd *pfd;
177428d7b3dSmrg#define timer pfd[0].fd
178428d7b3dSmrg	Display *record;
179428d7b3dSmrg	int nclone;
180428d7b3dSmrg	int ndisplay;
181428d7b3dSmrg	int nfd;
182428d7b3dSmrg
183428d7b3dSmrg	int timer_active;
184428d7b3dSmrg
185428d7b3dSmrg	long timestamp;
186428d7b3dSmrg	long configTimestamp;
187428d7b3dSmrg
188428d7b3dSmrg	Atom singleton;
189428d7b3dSmrg	char command[1024];
190428d7b3dSmrg	int command_continuation;
191428d7b3dSmrg};
192428d7b3dSmrg
193428d7b3dSmrgstatic inline int is_power_of_2(unsigned long n)
194428d7b3dSmrg{
195428d7b3dSmrg	return n && ((n & (n - 1)) == 0);
196428d7b3dSmrg}
197428d7b3dSmrg
198428d7b3dSmrgstatic int xlib_vendor_is_xorg(Display *dpy)
199428d7b3dSmrg{
200428d7b3dSmrg	const char *const vendor = ServerVendor(dpy);
201428d7b3dSmrg	return strstr(vendor, "X.Org") || strstr(vendor, "Xorg");
202428d7b3dSmrg}
203428d7b3dSmrg
204428d7b3dSmrgstatic inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window)
205428d7b3dSmrg{
206428d7b3dSmrg	XRRScreenResources *res;
207428d7b3dSmrg
208428d7b3dSmrg	res = XRRGetScreenResourcesCurrent(dpy, window);
209428d7b3dSmrg	if (res == NULL)
210428d7b3dSmrg		res = XRRGetScreenResources(dpy, window);
211428d7b3dSmrg
212428d7b3dSmrg	return res;
213428d7b3dSmrg}
214428d7b3dSmrg
215428d7b3dSmrg#define XORG_VERSION_ENCODE(major,minor,patch,snap) \
216428d7b3dSmrg    (((major) * 10000000) + ((minor) * 100000) + ((patch) * 1000) + snap)
217428d7b3dSmrg
218428d7b3dSmrgstatic int _x_error_occurred;
219428d7b3dSmrg
220428d7b3dSmrgstatic int
221428d7b3dSmrg_check_error_handler(Display     *display,
222428d7b3dSmrg		     XErrorEvent *event)
223428d7b3dSmrg{
224428d7b3dSmrg	DBG(X11, ("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n",
225428d7b3dSmrg	     DisplayString(display),
226428d7b3dSmrg	     event->serial,
227428d7b3dSmrg	     event->error_code,
228428d7b3dSmrg	     event->request_code,
229428d7b3dSmrg	     event->minor_code));
230428d7b3dSmrg	_x_error_occurred = 1;
231428d7b3dSmrg	return False; /* ignored */
232428d7b3dSmrg}
233428d7b3dSmrg
234428d7b3dSmrgstatic int
235428d7b3dSmrgcan_use_shm(Display *dpy,
236428d7b3dSmrg	    Window window,
237428d7b3dSmrg	    int *shm_event,
238428d7b3dSmrg	    int *shm_opcode,
239428d7b3dSmrg	    int *shm_pixmap)
240428d7b3dSmrg{
241428d7b3dSmrg	XShmSegmentInfo shm;
242428d7b3dSmrg	Status success;
243428d7b3dSmrg	XExtCodes *codes;
244428d7b3dSmrg	int major, minor, has_shm, has_pixmap;
245428d7b3dSmrg
246428d7b3dSmrg	if (!XShmQueryExtension(dpy))
247428d7b3dSmrg		return 0;
248428d7b3dSmrg
249428d7b3dSmrg	XShmQueryVersion(dpy, &major, &minor, &has_pixmap);
250428d7b3dSmrg
251428d7b3dSmrg	shm.shmid = shmget(IPC_PRIVATE, 0x1000, IPC_CREAT | 0600);
252428d7b3dSmrg	if (shm.shmid == -1)
253428d7b3dSmrg		return 0;
254428d7b3dSmrg
255428d7b3dSmrg	shm.readOnly = 0;
256428d7b3dSmrg	shm.shmaddr = shmat(shm.shmid, NULL, 0);
257428d7b3dSmrg	if (shm.shmaddr == (char *) -1) {
258428d7b3dSmrg		shmctl(shm.shmid, IPC_RMID, NULL);
259428d7b3dSmrg		return 0;
260428d7b3dSmrg	}
261428d7b3dSmrg
262428d7b3dSmrg	XSync(dpy, False);
263428d7b3dSmrg	_x_error_occurred = 0;
264428d7b3dSmrg
265428d7b3dSmrg	success = XShmAttach(dpy, &shm);
266428d7b3dSmrg
267428d7b3dSmrg	XSync(dpy, False);
268428d7b3dSmrg	has_shm = success && _x_error_occurred == 0;
269428d7b3dSmrg
270428d7b3dSmrg	/* As libXext sets the SEND_EVENT bit in the ShmCompletionEvent,
271428d7b3dSmrg	 * the Xserver may crash if it does not take care when processing
272428d7b3dSmrg	 * the event type. For instance versions of Xorg prior to 1.11.1
273428d7b3dSmrg	 * exhibited this bug, and was fixed by:
274428d7b3dSmrg	 *
275428d7b3dSmrg	 * commit 2d2dce558d24eeea0eb011ec9ebaa6c5c2273c39
276428d7b3dSmrg	 * Author: Sam Spilsbury <sam.spilsbury@canonical.com>
277428d7b3dSmrg	 * Date:   Wed Sep 14 09:58:34 2011 +0800
278428d7b3dSmrg	 *
279428d7b3dSmrg	 * Remove the SendEvent bit (0x80) before doing range checks on event type.
280428d7b3dSmrg	 */
281428d7b3dSmrg	codes = 0;
282428d7b3dSmrg	if (has_shm)
283428d7b3dSmrg		codes = XInitExtension(dpy, SHMNAME);
284428d7b3dSmrg	if (xlib_vendor_is_xorg(dpy) &&
285428d7b3dSmrg	    VendorRelease(dpy) < XORG_VERSION_ENCODE(1,11,0,1))
286428d7b3dSmrg		codes = 0;
287428d7b3dSmrg	if (codes) {
288428d7b3dSmrg		XShmCompletionEvent e;
289428d7b3dSmrg
290428d7b3dSmrg		memset(&e, 0, sizeof(e));
291428d7b3dSmrg
292428d7b3dSmrg		e.type = codes->first_event;
293428d7b3dSmrg		e.send_event = 1;
294428d7b3dSmrg		e.serial = 1;
295428d7b3dSmrg		e.drawable = window;
296428d7b3dSmrg		e.major_code = codes->major_opcode;
297428d7b3dSmrg		e.minor_code = X_ShmPutImage;
298428d7b3dSmrg
299428d7b3dSmrg		e.shmseg = shm.shmid;
300428d7b3dSmrg		e.offset = 0;
301428d7b3dSmrg
302428d7b3dSmrg		XSendEvent(dpy, e.drawable, False, 0, (XEvent *)&e);
303428d7b3dSmrg		XSync(dpy, False);
304428d7b3dSmrg
305428d7b3dSmrg		if (_x_error_occurred == 0) {
306428d7b3dSmrg			*shm_opcode = codes->major_opcode;
307428d7b3dSmrg			*shm_event = codes->first_event;
308428d7b3dSmrg			*shm_pixmap = has_pixmap;
309428d7b3dSmrg		}
310428d7b3dSmrg	}
311428d7b3dSmrg
312428d7b3dSmrg	XShmDetach(dpy, &shm);
313428d7b3dSmrg	shmctl(shm.shmid, IPC_RMID, NULL);
314428d7b3dSmrg	shmdt(shm.shmaddr);
315428d7b3dSmrg
316428d7b3dSmrg	return has_shm;
317428d7b3dSmrg}
318428d7b3dSmrg
319428d7b3dSmrg#ifdef DRI3
320428d7b3dSmrg#include <X11/Xlib-xcb.h>
321428d7b3dSmrg#include <X11/xshmfence.h>
322428d7b3dSmrg#include <xcb/xcb.h>
323428d7b3dSmrg#include <xcb/dri3.h>
324428d7b3dSmrg#include <xcb/sync.h>
325428d7b3dSmrgstatic Pixmap dri3_create_pixmap(Display *dpy,
326428d7b3dSmrg				 Drawable draw,
327428d7b3dSmrg				 int width, int height, int depth,
328428d7b3dSmrg				 int fd, int bpp, int stride, int size)
329428d7b3dSmrg{
330428d7b3dSmrg	xcb_connection_t *c = XGetXCBConnection(dpy);
331428d7b3dSmrg	xcb_pixmap_t pixmap = xcb_generate_id(c);
332428d7b3dSmrg	xcb_dri3_pixmap_from_buffer(c, pixmap, draw, size, width, height, stride, depth, bpp, fd);
333428d7b3dSmrg	return pixmap;
334428d7b3dSmrg}
335428d7b3dSmrg
336428d7b3dSmrgstatic int dri3_create_fd(Display *dpy,
337428d7b3dSmrg			  Pixmap pixmap,
338428d7b3dSmrg			  int *stride)
339428d7b3dSmrg{
340428d7b3dSmrg	xcb_connection_t *c = XGetXCBConnection(dpy);
341428d7b3dSmrg	xcb_dri3_buffer_from_pixmap_cookie_t cookie;
342428d7b3dSmrg	xcb_dri3_buffer_from_pixmap_reply_t *reply;
343428d7b3dSmrg
344428d7b3dSmrg	cookie = xcb_dri3_buffer_from_pixmap(c, pixmap);
345428d7b3dSmrg	reply = xcb_dri3_buffer_from_pixmap_reply(c, cookie, NULL);
346428d7b3dSmrg	if (!reply)
347428d7b3dSmrg		return -1;
348428d7b3dSmrg
349428d7b3dSmrg	if (reply->nfd != 1)
350428d7b3dSmrg		return -1;
351428d7b3dSmrg
352428d7b3dSmrg	*stride = reply->stride;
353428d7b3dSmrg	return xcb_dri3_buffer_from_pixmap_reply_fds(c, reply)[0];
354428d7b3dSmrg}
355428d7b3dSmrg
356428d7b3dSmrgstatic int dri3_query_version(Display *dpy, int *major, int *minor)
357428d7b3dSmrg{
358428d7b3dSmrg	xcb_connection_t *c = XGetXCBConnection(dpy);
359428d7b3dSmrg	xcb_dri3_query_version_reply_t *reply;
360428d7b3dSmrg
361428d7b3dSmrg	*major = *minor = -1;
362428d7b3dSmrg
363428d7b3dSmrg	reply = xcb_dri3_query_version_reply(c,
364428d7b3dSmrg					     xcb_dri3_query_version(c,
365428d7b3dSmrg								    XCB_DRI3_MAJOR_VERSION,
366428d7b3dSmrg								    XCB_DRI3_MINOR_VERSION),
367428d7b3dSmrg					     NULL);
368428d7b3dSmrg	if (reply == NULL)
369428d7b3dSmrg		return -1;
370428d7b3dSmrg
371428d7b3dSmrg	*major = reply->major_version;
372428d7b3dSmrg	*minor = reply->minor_version;
373428d7b3dSmrg	free(reply);
374428d7b3dSmrg
375428d7b3dSmrg	return 0;
376428d7b3dSmrg}
377428d7b3dSmrg
378428d7b3dSmrgstatic int dri3_exists(Display *dpy)
379428d7b3dSmrg{
380428d7b3dSmrg	int major, minor;
381428d7b3dSmrg
382428d7b3dSmrg	if (dri3_query_version(dpy, &major, &minor) < 0)
383428d7b3dSmrg		return 0;
384428d7b3dSmrg
385428d7b3dSmrg	return major >= 0;
386428d7b3dSmrg}
387428d7b3dSmrg
388428d7b3dSmrgstatic void dri3_create_fence(Display *dpy, Drawable d, struct dri3_fence *fence)
389428d7b3dSmrg{
390428d7b3dSmrg	xcb_connection_t *c = XGetXCBConnection(dpy);
391428d7b3dSmrg	struct dri3_fence f;
392428d7b3dSmrg	int fd;
393428d7b3dSmrg
394428d7b3dSmrg	fd = xshmfence_alloc_shm();
395428d7b3dSmrg	if (fd < 0)
396428d7b3dSmrg		return;
397428d7b3dSmrg
398428d7b3dSmrg	f.addr = xshmfence_map_shm(fd);
399428d7b3dSmrg	if (f.addr == NULL) {
400428d7b3dSmrg		close(fd);
401428d7b3dSmrg		return;
402428d7b3dSmrg	}
403428d7b3dSmrg
404428d7b3dSmrg	f.xid = xcb_generate_id(c);
405428d7b3dSmrg	xcb_dri3_fence_from_fd(c, d, f.xid, 0, fd);
406428d7b3dSmrg
407428d7b3dSmrg	*fence = f;
408428d7b3dSmrg}
409428d7b3dSmrg
410428d7b3dSmrgstatic void dri3_fence_flush(Display *dpy, struct dri3_fence *fence)
411428d7b3dSmrg{
412428d7b3dSmrg	xcb_sync_trigger_fence(XGetXCBConnection(dpy), fence->xid);
413428d7b3dSmrg}
414428d7b3dSmrg
415428d7b3dSmrgstatic void dri3_fence_free(Display *dpy, struct dri3_fence *fence)
416428d7b3dSmrg{
417428d7b3dSmrg	xshmfence_unmap_shm(fence->addr);
418428d7b3dSmrg	xcb_sync_destroy_fence(XGetXCBConnection(dpy), fence->xid);
419428d7b3dSmrg}
420428d7b3dSmrg
421428d7b3dSmrg#else
422428d7b3dSmrg
423428d7b3dSmrgstatic int dri3_exists(Display *dpy)
424428d7b3dSmrg{
425428d7b3dSmrg	return 0;
426428d7b3dSmrg}
427428d7b3dSmrg
428428d7b3dSmrgstatic void dri3_create_fence(Display *dpy, Drawable d, struct dri3_fence *fence)
429428d7b3dSmrg{
430428d7b3dSmrg}
431428d7b3dSmrg
432428d7b3dSmrgstatic void dri3_fence_flush(Display *dpy, struct dri3_fence *fence)
433428d7b3dSmrg{
434428d7b3dSmrg}
435428d7b3dSmrg
436428d7b3dSmrgstatic void dri3_fence_free(Display *dpy, struct dri3_fence *fence)
437428d7b3dSmrg{
438428d7b3dSmrg}
439428d7b3dSmrg
440428d7b3dSmrgstatic Pixmap dri3_create_pixmap(Display *dpy,
441428d7b3dSmrg				 Drawable draw,
442428d7b3dSmrg				 int width, int height, int depth,
443428d7b3dSmrg				 int fd, int bpp, int stride, int size)
444428d7b3dSmrg{
445428d7b3dSmrg	return None;
446428d7b3dSmrg}
447428d7b3dSmrg
448428d7b3dSmrgstatic int dri3_create_fd(Display *dpy,
449428d7b3dSmrg			  Pixmap pixmap,
450428d7b3dSmrg			  int *stride)
451428d7b3dSmrg{
452428d7b3dSmrg	return -1;
453428d7b3dSmrg}
454428d7b3dSmrg#endif
455428d7b3dSmrg
456428d7b3dSmrgstatic int timerfd(int hz)
457428d7b3dSmrg{
458428d7b3dSmrg	struct itimerspec it;
459428d7b3dSmrg	int fd;
460428d7b3dSmrg
461428d7b3dSmrg	fd = -1;
462428d7b3dSmrg#ifdef CLOCK_MONOTONIC_COARSE
463428d7b3dSmrg	fd = timerfd_create(CLOCK_MONOTONIC_COARSE, TFD_NONBLOCK);
464428d7b3dSmrg#endif
465428d7b3dSmrg	if (fd < 0)
466428d7b3dSmrg		fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
467428d7b3dSmrg	if (fd < 0)
468428d7b3dSmrg		return -ETIME;
469428d7b3dSmrg
470428d7b3dSmrg	it.it_interval.tv_sec = 0;
471428d7b3dSmrg	it.it_interval.tv_nsec = 1000000000 / hz;
472428d7b3dSmrg	it.it_value = it.it_interval;
473428d7b3dSmrg	if (timerfd_settime(fd, 0, &it, NULL) < 0) {
474428d7b3dSmrg		close(fd);
475428d7b3dSmrg		return -ETIME;
476428d7b3dSmrg	}
477428d7b3dSmrg
478428d7b3dSmrg	return fd;
479428d7b3dSmrg}
480428d7b3dSmrg
481428d7b3dSmrgstatic int context_init(struct context *ctx)
482428d7b3dSmrg{
483428d7b3dSmrg	struct pollfd *pfd;
484428d7b3dSmrg
485428d7b3dSmrg	memset(ctx, 0, sizeof(*ctx));
486428d7b3dSmrg
487428d7b3dSmrg	ctx->pfd = malloc(2*sizeof(struct pollfd));
488428d7b3dSmrg	if (ctx->pfd == NULL)
489428d7b3dSmrg		return -ENOMEM;
490428d7b3dSmrg
491428d7b3dSmrg	ctx->clones = malloc(sizeof(struct clone));
492428d7b3dSmrg	if (ctx->clones == NULL)
493428d7b3dSmrg		return -ENOMEM;
494428d7b3dSmrg
495428d7b3dSmrg	ctx->display = malloc(sizeof(struct display));
496428d7b3dSmrg	if (ctx->display == NULL)
497428d7b3dSmrg		return -ENOMEM;
498428d7b3dSmrg
499428d7b3dSmrg	pfd = memset(&ctx->pfd[ctx->nfd++], 0, sizeof(struct pollfd));
500428d7b3dSmrg	pfd->fd = timerfd(60);
501428d7b3dSmrg	if (pfd->fd < 0)
502428d7b3dSmrg		return pfd->fd;
503428d7b3dSmrg	pfd->events = POLLIN;
504428d7b3dSmrg
505428d7b3dSmrg	return 0;
506428d7b3dSmrg}
507428d7b3dSmrg
508428d7b3dSmrgstatic void context_enable_timer(struct context *ctx)
509428d7b3dSmrg{
510428d7b3dSmrg	uint64_t count;
511428d7b3dSmrg
512428d7b3dSmrg	DBG(TIMER, ("%s timer active? %d\n", __func__, ctx->timer_active));
513428d7b3dSmrg
514428d7b3dSmrg	if (ctx->timer_active)
515428d7b3dSmrg		return;
516428d7b3dSmrg
517428d7b3dSmrg	/* reset timer */
518428d7b3dSmrg	count = read(ctx->timer, &count, sizeof(count));
519428d7b3dSmrg
520428d7b3dSmrg	ctx->timer_active = 1;
521428d7b3dSmrg}
522428d7b3dSmrg
523428d7b3dSmrgstatic int add_fd(struct context *ctx, int fd)
524428d7b3dSmrg{
525428d7b3dSmrg	struct pollfd *pfd;
526428d7b3dSmrg
527428d7b3dSmrg	if (fd < 0)
528428d7b3dSmrg		return fd;
529428d7b3dSmrg
530428d7b3dSmrg	if (is_power_of_2(ctx->nfd)) {
531428d7b3dSmrg		ctx->pfd = realloc(ctx->pfd, 2*ctx->nfd*sizeof(struct pollfd));
532428d7b3dSmrg		if (ctx->pfd == NULL)
533428d7b3dSmrg			return -ENOMEM;
534428d7b3dSmrg	}
535428d7b3dSmrg
536428d7b3dSmrg	pfd = memset(&ctx->pfd[ctx->nfd++], 0, sizeof(struct pollfd));
537428d7b3dSmrg	pfd->fd = fd;
538428d7b3dSmrg	pfd->events = POLLIN;
539428d7b3dSmrg	return 0;
540428d7b3dSmrg}
541428d7b3dSmrg
542428d7b3dSmrgstatic void display_mark_flush(struct display *display)
543428d7b3dSmrg{
544428d7b3dSmrg	DBG(DRAW, ("%s mark flush (flush=%d)\n",
545428d7b3dSmrg	     DisplayString(display->dpy), display->flush));
546428d7b3dSmrg
547428d7b3dSmrg	if (display->flush)
548428d7b3dSmrg		return;
549428d7b3dSmrg
550428d7b3dSmrg	context_enable_timer(display->ctx);
551428d7b3dSmrg	display->flush = 1;
552428d7b3dSmrg}
553428d7b3dSmrg
554428d7b3dSmrgstatic int mode_equal(const XRRModeInfo *a, const XRRModeInfo *b)
555428d7b3dSmrg{
556428d7b3dSmrg	return (a->width == b->width &&
557428d7b3dSmrg		a->height == b->height &&
558428d7b3dSmrg		a->dotClock == b->dotClock &&
559428d7b3dSmrg		a->hSyncStart == b->hSyncStart &&
560428d7b3dSmrg		a->hSyncEnd == b->hSyncEnd &&
561428d7b3dSmrg		a->hTotal == b->hTotal &&
562428d7b3dSmrg		a->hSkew == b->hSkew &&
563428d7b3dSmrg		a->vSyncStart == b->vSyncStart &&
564428d7b3dSmrg		a->vSyncEnd == b->vSyncEnd &&
565428d7b3dSmrg		a->vTotal == b->vTotal &&
566428d7b3dSmrg		a->modeFlags == b->modeFlags);
567428d7b3dSmrg}
568428d7b3dSmrg
569428d7b3dSmrgstatic XRRModeInfo *lookup_mode(XRRScreenResources *res, int id)
570428d7b3dSmrg{
571428d7b3dSmrg	int i;
572428d7b3dSmrg
573428d7b3dSmrg	for (i = 0; i < res->nmode; i++) {
574428d7b3dSmrg		if (res->modes[i].id == id)
575428d7b3dSmrg			return &res->modes[i];
576428d7b3dSmrg	}
577428d7b3dSmrg
578428d7b3dSmrg	return NULL;
579428d7b3dSmrg}
580428d7b3dSmrg
581428d7b3dSmrgstatic void clone_update_edid(struct clone *clone)
582428d7b3dSmrg{
583428d7b3dSmrg	unsigned long nitems, after;
584428d7b3dSmrg	unsigned char *data;
585428d7b3dSmrg	int format;
586428d7b3dSmrg	Atom type;
587428d7b3dSmrg
588428d7b3dSmrg	if (XRRGetOutputProperty(clone->dst.dpy, clone->dst.rr_output,
589428d7b3dSmrg				 XInternAtom(clone->dst.dpy, "EDID", False),
590428d7b3dSmrg				 0, 100, False, False, AnyPropertyType,
591428d7b3dSmrg				 &type, &format, &nitems, &after, &data) == Success) {
592428d7b3dSmrg		XRRChangeOutputProperty(clone->src.dpy, clone->src.rr_output,
593428d7b3dSmrg					XInternAtom(clone->src.dpy, "EDID", False),
594428d7b3dSmrg					type, format, PropModeReplace, data, nitems);
595428d7b3dSmrg	}
596428d7b3dSmrg}
597428d7b3dSmrg
598428d7b3dSmrgstatic int disable_crtc(Display *dpy, XRRScreenResources *res, RRCrtc crtc)
599428d7b3dSmrg{
600428d7b3dSmrg	XRRPanning panning;
601428d7b3dSmrg
602428d7b3dSmrg	if (crtc) {
603428d7b3dSmrg		XRRSetPanning(dpy, res, crtc, memset(&panning, 0, sizeof(panning)));
604428d7b3dSmrg
605428d7b3dSmrg		if (XRRSetCrtcConfig(dpy, res, crtc, CurrentTime, 0, 0, None, RR_Rotate_0, NULL, 0) != Success)
606428d7b3dSmrg			return 0;
607428d7b3dSmrg
608428d7b3dSmrg		if (XRRSetPanning(dpy, res, crtc, memset(&panning, 0, sizeof(panning))) != Success) {
609428d7b3dSmrg			DBG(XRR, ("%s failed to clear panning on CRTC:%ld\n", DisplayString(dpy), (long)crtc));
610428d7b3dSmrg			if (verbose) {
611428d7b3dSmrg				XRRCrtcInfo *c;
612428d7b3dSmrg				XRRPanning *p;
613428d7b3dSmrg
614428d7b3dSmrg				c = XRRGetCrtcInfo(dpy, res, crtc);
615428d7b3dSmrg				if (c) {
616428d7b3dSmrg					DBG(XRR, ("%s CRTC:%ld x=%d, y=%d, rotation=%d, mode=%ld\n",
617428d7b3dSmrg					     DisplayString(dpy), (long)crtc,
618428d7b3dSmrg					     c->x, c->y, c->rotation, c->mode));
619428d7b3dSmrg					XRRFreeCrtcInfo(c);
620428d7b3dSmrg				}
621428d7b3dSmrg
622428d7b3dSmrg				p = XRRGetPanning(dpy, res, crtc);
623428d7b3dSmrg				if (p) {
624428d7b3dSmrg					DBG(XRR, ("%s CRTC:%ld panning (%d, %d)x(%d, %d), tracking (%d, %d)x(%d, %d), border (%d, %d),(%d, %d)\n",
625428d7b3dSmrg					     DisplayString(dpy), (long)crtc,
626428d7b3dSmrg					     p->left, p->top, p->width, p->height,
627428d7b3dSmrg					     p->track_left, p->track_top, p->track_width, p->track_height,
628428d7b3dSmrg					     p->border_left, p->border_top, p->border_right, p->border_bottom));
629428d7b3dSmrg					XRRFreePanning(p);
630428d7b3dSmrg				}
631428d7b3dSmrg			}
632428d7b3dSmrg		}
633428d7b3dSmrg	}
634428d7b3dSmrg
635428d7b3dSmrg	return 1;
636428d7b3dSmrg}
637428d7b3dSmrg
638428d7b3dSmrgstatic int clone_update_modes__randr(struct clone *clone)
639428d7b3dSmrg{
640428d7b3dSmrg	XRRScreenResources *from_res = NULL, *to_res = NULL;
641428d7b3dSmrg	XRROutputInfo *from_info = NULL, *to_info = NULL;
642428d7b3dSmrg	int i, j, ret = ENOENT;
643428d7b3dSmrg
644428d7b3dSmrg	assert(clone->src.rr_output);
645428d7b3dSmrg	assert(clone->dst.rr_output);
646428d7b3dSmrg	assert(clone->dst.display->rr_event);
647428d7b3dSmrg
648428d7b3dSmrg	from_res = _XRRGetScreenResourcesCurrent(clone->dst.dpy, clone->dst.window);
649428d7b3dSmrg	if (from_res == NULL)
650428d7b3dSmrg		goto err;
651428d7b3dSmrg
652428d7b3dSmrg	from_info = XRRGetOutputInfo(clone->dst.dpy, from_res, clone->dst.rr_output);
653428d7b3dSmrg	if (from_info == NULL)
654428d7b3dSmrg		goto err;
655428d7b3dSmrg
656428d7b3dSmrg	DBG(XRR, ("%s(%s-%s <- %s-%s): timestamp %ld (last %ld)\n", __func__,
657428d7b3dSmrg	     DisplayString(clone->src.dpy), clone->src.name,
658428d7b3dSmrg	     DisplayString(clone->dst.dpy), clone->dst.name,
659428d7b3dSmrg	     from_info->timestamp, clone->timestamp));
660428d7b3dSmrg
661428d7b3dSmrg	to_res = _XRRGetScreenResourcesCurrent(clone->src.dpy, clone->src.window);
662428d7b3dSmrg	if (to_res == NULL)
663428d7b3dSmrg		goto err;
664428d7b3dSmrg
665428d7b3dSmrg	to_info = XRRGetOutputInfo(clone->src.dpy, to_res, clone->src.rr_output);
666428d7b3dSmrg	if (to_info == NULL)
667428d7b3dSmrg		goto err;
668428d7b3dSmrg
669428d7b3dSmrg	DBG(XRR, ("%s: dst.rr_crtc=%ld, now %ld\n",
670428d7b3dSmrg	     __func__, (long)clone->dst.rr_crtc, (long)from_info->crtc));
671428d7b3dSmrg	if (clone->dst.rr_crtc == from_info->crtc) {
672428d7b3dSmrg		for (i = 0; i < to_info->nmode; i++) {
673428d7b3dSmrg			XRRModeInfo *mode, *old;
674428d7b3dSmrg
675428d7b3dSmrg			mode = lookup_mode(to_res, to_info->modes[i]);
676428d7b3dSmrg			if (mode == NULL)
677428d7b3dSmrg				break;
678428d7b3dSmrg
679428d7b3dSmrg			DBG(XRR, ("%s(%s-%s): lookup mode %s\n", __func__,
680428d7b3dSmrg			     DisplayString(clone->src.dpy), clone->src.name,
681428d7b3dSmrg			     mode->name));
682428d7b3dSmrg
683428d7b3dSmrg			for (j = 0; j < from_info->nmode; j++) {
684428d7b3dSmrg				old = lookup_mode(from_res, from_info->modes[j]);
685428d7b3dSmrg				if (old && mode_equal(mode, old)) {
686428d7b3dSmrg					mode = NULL;
687428d7b3dSmrg					break;
688428d7b3dSmrg				}
689428d7b3dSmrg			}
690428d7b3dSmrg			if (mode) {
691428d7b3dSmrg				DBG(XRR, ("%s(%s-%s): unknown mode %s\n", __func__,
692428d7b3dSmrg				     DisplayString(clone->src.dpy), clone->src.name,
693428d7b3dSmrg				     mode->name));
694428d7b3dSmrg				break;
695428d7b3dSmrg			}
696428d7b3dSmrg		}
697428d7b3dSmrg		if (i == from_info->nmode && i == to_info->nmode) {
698428d7b3dSmrg			DBG(XRR, ("%s(%s-%s): no change in output\n", __func__,
699428d7b3dSmrg			     DisplayString(clone->src.dpy), clone->src.name));
700428d7b3dSmrg			goto done;
701428d7b3dSmrg		}
702428d7b3dSmrg	}
703428d7b3dSmrg
704428d7b3dSmrg	/* Disable the remote output */
705428d7b3dSmrg	if (from_info->crtc != clone->dst.rr_crtc) {
706428d7b3dSmrg		DBG(XRR, ("%s(%s-%s): disabling active CRTC\n", __func__,
707428d7b3dSmrg		     DisplayString(clone->dst.dpy), clone->dst.name));
708428d7b3dSmrg		if (disable_crtc(clone->dst.dpy, from_res, from_info->crtc)) {
709428d7b3dSmrg			clone->dst.rr_crtc = 0;
710428d7b3dSmrg			clone->dst.mode.id = 0;
711428d7b3dSmrg		} else {
712428d7b3dSmrg			XRRCrtcInfo *c = XRRGetCrtcInfo(clone->dst.dpy, from_res, from_info->crtc);
713428d7b3dSmrg			if (c) {
714428d7b3dSmrg				clone->dst.x = c->x;
715428d7b3dSmrg				clone->dst.y = c->y;
716428d7b3dSmrg				clone->dst.rotation = c->rotation;
717428d7b3dSmrg				clone->dst.mode.id = c->mode;
718428d7b3dSmrg				XRRFreeCrtcInfo(c);
719428d7b3dSmrg			}
720428d7b3dSmrg		}
721428d7b3dSmrg	}
722428d7b3dSmrg
723428d7b3dSmrg	/* Create matching modes for the real output on the virtual */
724428d7b3dSmrg	XGrabServer(clone->src.dpy);
725428d7b3dSmrg
726428d7b3dSmrg	/* Clear all current UserModes on the output, including any active ones */
727428d7b3dSmrg	if (to_info->crtc) {
728428d7b3dSmrg		DBG(XRR, ("%s(%s-%s): disabling active CRTC\n", __func__,
729428d7b3dSmrg		     DisplayString(clone->src.dpy), clone->src.name));
730428d7b3dSmrg		disable_crtc(clone->src.dpy, to_res, to_info->crtc);
731428d7b3dSmrg	}
732428d7b3dSmrg	for (i = 0; i < to_info->nmode; i++) {
733428d7b3dSmrg		DBG(XRR, ("%s(%s-%s): deleting mode %ld\n", __func__,
734428d7b3dSmrg		     DisplayString(clone->src.dpy), clone->src.name, (long)to_info->modes[i]));
735428d7b3dSmrg		XRRDeleteOutputMode(clone->src.dpy, clone->src.rr_output, to_info->modes[i]);
736428d7b3dSmrg	}
737428d7b3dSmrg
738428d7b3dSmrg	clone->src.rr_crtc = 0;
739428d7b3dSmrg
740428d7b3dSmrg	for (i = 0; i < from_info->nmode; i++) {
741428d7b3dSmrg		XRRModeInfo *mode, *old;
742428d7b3dSmrg		RRMode id;
743428d7b3dSmrg
744428d7b3dSmrg		mode = lookup_mode(from_res, from_info->modes[i]);
745428d7b3dSmrg		if (mode == NULL)
746428d7b3dSmrg			continue;
747428d7b3dSmrg		for (j = 0; j < i; j++) {
748428d7b3dSmrg			old = lookup_mode(from_res, from_info->modes[j]);
749428d7b3dSmrg			if (old && mode_equal(mode, old)) {
750428d7b3dSmrg				mode = NULL;
751428d7b3dSmrg				break;
752428d7b3dSmrg			}
753428d7b3dSmrg		}
754428d7b3dSmrg		if (mode == NULL)
755428d7b3dSmrg			continue;
756428d7b3dSmrg
757428d7b3dSmrg		id = 0;
758428d7b3dSmrg		for (j = 0; j < to_res->nmode; j++) {
759428d7b3dSmrg			old = &to_res->modes[j];
760428d7b3dSmrg			if (mode_equal(mode, old)) {
761428d7b3dSmrg				id = old->id;
762428d7b3dSmrg				DBG(XRR, ("%s(%s-%s): reusing mode %ld: %s\n", __func__,
763428d7b3dSmrg				     DisplayString(clone->src.dpy), clone->src.name, id, mode->name));
764428d7b3dSmrg				break;
765428d7b3dSmrg			}
766428d7b3dSmrg		}
767428d7b3dSmrg		if (id == 0) {
768428d7b3dSmrg			XRRModeInfo m;
769428d7b3dSmrg			char buf[256];
770428d7b3dSmrg
771428d7b3dSmrg			/* XXX User names must be unique! */
772428d7b3dSmrg			m = *mode;
773428d7b3dSmrg			m.nameLength = snprintf(buf, sizeof(buf),
774428d7b3dSmrg						"%s.%ld-%s", clone->src.name, (long)from_info->modes[i], mode->name);
775428d7b3dSmrg			m.name = buf;
776428d7b3dSmrg
777428d7b3dSmrg			id = XRRCreateMode(clone->src.dpy, clone->src.window, &m);
778428d7b3dSmrg			DBG(XRR, ("%s(%s-%s): adding mode %ld: %s\n", __func__,
779428d7b3dSmrg			     DisplayString(clone->src.dpy), clone->src.name, id, mode->name));
780428d7b3dSmrg		}
781428d7b3dSmrg
782428d7b3dSmrg		XRRAddOutputMode(clone->src.dpy, clone->src.rr_output, id);
783428d7b3dSmrg	}
784428d7b3dSmrg	clone_update_edid(clone);
785428d7b3dSmrg	XUngrabServer(clone->src.dpy);
786428d7b3dSmrgdone:
787428d7b3dSmrg	ret = 0;
788428d7b3dSmrg	clone->timestamp = from_info->timestamp;
789428d7b3dSmrg
790428d7b3dSmrgerr:
791428d7b3dSmrg	if (to_info)
792428d7b3dSmrg		XRRFreeOutputInfo(to_info);
793428d7b3dSmrg	if (to_res)
794428d7b3dSmrg		XRRFreeScreenResources(to_res);
795428d7b3dSmrg	if (from_info)
796428d7b3dSmrg		XRRFreeOutputInfo(from_info);
797428d7b3dSmrg	if (from_res)
798428d7b3dSmrg		XRRFreeScreenResources(from_res);
799428d7b3dSmrg
800428d7b3dSmrg	return ret;
801428d7b3dSmrg}
802428d7b3dSmrg
803428d7b3dSmrgstatic int clone_update_modes__fixed(struct clone *clone)
804428d7b3dSmrg{
805428d7b3dSmrg	char mode_name[80];
806428d7b3dSmrg	XRRScreenResources *res = NULL;
807428d7b3dSmrg	XRROutputInfo *info = NULL;
808428d7b3dSmrg	XRRModeInfo mode;
809428d7b3dSmrg	RRMode id;
810428d7b3dSmrg	int i, j, ret = ENOENT;
811428d7b3dSmrg
812428d7b3dSmrg	assert(clone->src.rr_output);
813428d7b3dSmrg
814428d7b3dSmrg	res = _XRRGetScreenResourcesCurrent(clone->src.dpy, clone->src.window);
815428d7b3dSmrg	if (res == NULL)
816428d7b3dSmrg		goto err;
817428d7b3dSmrg
818428d7b3dSmrg	info = XRRGetOutputInfo(clone->src.dpy, res, clone->src.rr_output);
819428d7b3dSmrg	if (info == NULL)
820428d7b3dSmrg		goto err;
821428d7b3dSmrg
822428d7b3dSmrg	XGrabServer(clone->src.dpy);
823428d7b3dSmrg
824428d7b3dSmrg	/* Clear all current UserModes on the output, including any active ones */
825428d7b3dSmrg	if (info->crtc) {
826428d7b3dSmrg		DBG(XRR, ("%s(%s-%s): disabling active CRTC\n", __func__,
827428d7b3dSmrg		     DisplayString(clone->src.dpy), clone->src.name));
828428d7b3dSmrg		disable_crtc(clone->src.dpy, res, info->crtc);
829428d7b3dSmrg	}
830428d7b3dSmrg	for (i = 0; i < info->nmode; i++) {
831428d7b3dSmrg		DBG(XRR, ("%s(%s-%s): deleting mode %ld\n", __func__,
832428d7b3dSmrg		     DisplayString(clone->src.dpy), clone->src.name, (long)info->modes[i]));
833428d7b3dSmrg		XRRDeleteOutputMode(clone->src.dpy, clone->src.rr_output, info->modes[i]);
834428d7b3dSmrg	}
835428d7b3dSmrg
836428d7b3dSmrg	clone->src.rr_crtc = 0;
837428d7b3dSmrg
838428d7b3dSmrg	/* Create matching mode for the real output on the virtual */
839428d7b3dSmrg	memset(&mode, 0, sizeof(mode));
840428d7b3dSmrg	mode.width = clone->width;
841428d7b3dSmrg	mode.height = clone->height;
842428d7b3dSmrg	mode.nameLength = sprintf(mode_name, "FAKE-%dx%d", mode.width, mode.height);
843428d7b3dSmrg	mode.name = mode_name;
844428d7b3dSmrg
845428d7b3dSmrg	id = 0;
846428d7b3dSmrg	for (j = 0; j < res->nmode; j++) {
847428d7b3dSmrg		if (mode_equal(&mode, &res->modes[j])) {
848428d7b3dSmrg			id = res->modes[j].id;
849428d7b3dSmrg			break;
850428d7b3dSmrg		}
851428d7b3dSmrg	}
852428d7b3dSmrg	if (id == 0)
853428d7b3dSmrg		id = XRRCreateMode(clone->src.dpy, clone->src.window, &mode);
854428d7b3dSmrg
855428d7b3dSmrg	XRRAddOutputMode(clone->src.dpy, clone->src.rr_output, id);
856428d7b3dSmrg
857428d7b3dSmrg	XUngrabServer(clone->src.dpy);
858428d7b3dSmrg	ret = 0;
859428d7b3dSmrgerr:
860428d7b3dSmrg	if (info)
861428d7b3dSmrg		XRRFreeOutputInfo(info);
862428d7b3dSmrg	if (res)
863428d7b3dSmrg		XRRFreeScreenResources(res);
864428d7b3dSmrg
865428d7b3dSmrg	return ret;
866428d7b3dSmrg}
867428d7b3dSmrg
868428d7b3dSmrgstatic RROutput claim_virtual(struct display *display, char *output_name, int nclone)
869428d7b3dSmrg{
870428d7b3dSmrg	char mode_name[] = "ClaimVirtualHead";
871428d7b3dSmrg	Display *dpy = display->dpy;
872428d7b3dSmrg	XRRScreenResources *res;
873428d7b3dSmrg	XRROutputInfo *output;
874428d7b3dSmrg	XRRModeInfo mode;
875428d7b3dSmrg	RRMode id;
876428d7b3dSmrg	RROutput rr_output = 0;
877428d7b3dSmrg	int i;
878428d7b3dSmrg
879428d7b3dSmrg	DBG(X11, ("%s(%d)\n", __func__, nclone));
880428d7b3dSmrg	XGrabServer(dpy);
881428d7b3dSmrg
882428d7b3dSmrg	res = _XRRGetScreenResourcesCurrent(dpy, display->root);
883428d7b3dSmrg	if (res == NULL)
884428d7b3dSmrg		goto out;
885428d7b3dSmrg
886428d7b3dSmrg	sprintf(output_name, "VIRTUAL%d", nclone);
887428d7b3dSmrg
888428d7b3dSmrg	for (i = rr_output = 0; rr_output == 0 && i < res->noutput; i++) {
889428d7b3dSmrg		output = XRRGetOutputInfo(dpy, res, res->outputs[i]);
890428d7b3dSmrg		if (output == NULL)
891428d7b3dSmrg			continue;
892428d7b3dSmrg
893428d7b3dSmrg		if (strcmp(output->name, output_name) == 0)
894428d7b3dSmrg			rr_output = res->outputs[i];
895428d7b3dSmrg
896428d7b3dSmrg		XRRFreeOutputInfo(output);
897428d7b3dSmrg	}
898428d7b3dSmrg	for (i = id = 0; id == 0 && i < res->nmode; i++) {
899428d7b3dSmrg		if (strcmp(res->modes[i].name, mode_name) == 0)
900428d7b3dSmrg			id = res->modes[i].id;
901428d7b3dSmrg	}
902428d7b3dSmrg	XRRFreeScreenResources(res);
903428d7b3dSmrg
904428d7b3dSmrg	DBG(XRR, ("%s(%s): rr_output=%ld\n", __func__, output_name, (long)rr_output));
905428d7b3dSmrg	if (rr_output == 0)
906428d7b3dSmrg		goto out;
907428d7b3dSmrg
908428d7b3dSmrg	/* Set any mode on the VirtualHead to make the Xserver allocate another */
909428d7b3dSmrg	memset(&mode, 0, sizeof(mode));
910428d7b3dSmrg	mode.width = 1024;
911428d7b3dSmrg	mode.height = 768;
912428d7b3dSmrg	mode.name = mode_name;
913428d7b3dSmrg	mode.nameLength = sizeof(mode_name) - 1;
914428d7b3dSmrg
915428d7b3dSmrg	if (id == 0)
916428d7b3dSmrg		id = XRRCreateMode(dpy, display->root, &mode);
917428d7b3dSmrg	XRRAddOutputMode(dpy, rr_output, id);
918428d7b3dSmrg
919428d7b3dSmrg	/* Force a redetection for the ddx to spot the new outputs */
920428d7b3dSmrg	res = XRRGetScreenResources(dpy, display->root);
921428d7b3dSmrg	if (res == NULL)
922428d7b3dSmrg		goto out;
923428d7b3dSmrg
924428d7b3dSmrg	/* Some else may have interrupted us and installed that new mode! */
925428d7b3dSmrg	output = XRRGetOutputInfo(dpy, res, rr_output);
926428d7b3dSmrg	if (output) {
927428d7b3dSmrg		disable_crtc(dpy, res, output->crtc);
928428d7b3dSmrg		XRRFreeOutputInfo(output);
929428d7b3dSmrg	}
930428d7b3dSmrg	XRRFreeScreenResources(res);
931428d7b3dSmrg
932428d7b3dSmrg	XRRDeleteOutputMode(dpy, rr_output, id);
933428d7b3dSmrg	XRRDestroyMode(dpy, id);
934428d7b3dSmrg
935428d7b3dSmrg	/* And hide it again */
936428d7b3dSmrg	res = XRRGetScreenResources(dpy, display->root);
937428d7b3dSmrg	if (res != NULL)
938428d7b3dSmrg		XRRFreeScreenResources(res);
939428d7b3dSmrgout:
940428d7b3dSmrg	XUngrabServer(dpy);
941428d7b3dSmrg
942428d7b3dSmrg	return rr_output;
943428d7b3dSmrg}
944428d7b3dSmrg
945428d7b3dSmrgstatic int stride_for_depth(int width, int depth)
946428d7b3dSmrg{
947428d7b3dSmrg	if (depth == 24)
948428d7b3dSmrg		depth = 32;
949428d7b3dSmrg	return ((width * depth + 7) / 8 + 3) & ~3;
950428d7b3dSmrg}
951428d7b3dSmrg
952428d7b3dSmrgstatic void init_image(struct clone *clone)
953428d7b3dSmrg{
954428d7b3dSmrg	XImage *image = &clone->image;
955428d7b3dSmrg	int ret;
956428d7b3dSmrg
957428d7b3dSmrg	image->width = clone->width;
958428d7b3dSmrg	image->height = clone->height;
959428d7b3dSmrg	image->format = ZPixmap;
960428d7b3dSmrg	image->xoffset = 0;
961428d7b3dSmrg	image->byte_order = LSBFirst;
962428d7b3dSmrg	image->bitmap_unit = 32;
963428d7b3dSmrg	image->bitmap_bit_order = LSBFirst;
964428d7b3dSmrg	image->bitmap_pad = 32;
965428d7b3dSmrg	image->data = clone->shm.shmaddr;
966428d7b3dSmrg	image->bytes_per_line = stride_for_depth(clone->width, clone->depth);
967428d7b3dSmrg	switch (clone->depth) {
968428d7b3dSmrg	case 24:
969428d7b3dSmrg		image->red_mask = 0xff << 16;
970428d7b3dSmrg		image->green_mask = 0xff << 8;
971428d7b3dSmrg		image->blue_mask = 0xff << 0;;
972428d7b3dSmrg		image->depth = 24;
973428d7b3dSmrg		image->bits_per_pixel = 32;
974428d7b3dSmrg		break;
975428d7b3dSmrg	case 16:
976428d7b3dSmrg		image->red_mask = 0x1f << 11;
977428d7b3dSmrg		image->green_mask = 0x3f << 5;
978428d7b3dSmrg		image->blue_mask = 0x1f << 0;;
979428d7b3dSmrg		image->depth = 16;
980428d7b3dSmrg		image->bits_per_pixel = 16;
981428d7b3dSmrg		break;
982428d7b3dSmrg	}
983428d7b3dSmrg
984428d7b3dSmrg	ret = XInitImage(image);
985428d7b3dSmrg	assert(ret);
986428d7b3dSmrg	(void)ret;
987428d7b3dSmrg}
988428d7b3dSmrg
989428d7b3dSmrgstatic int mode_height(const XRRModeInfo *mode, Rotation rotation)
990428d7b3dSmrg{
991428d7b3dSmrg	switch (rotation & 0xf) {
992428d7b3dSmrg	case RR_Rotate_0:
993428d7b3dSmrg	case RR_Rotate_180:
994428d7b3dSmrg		return mode->height;
995428d7b3dSmrg	case RR_Rotate_90:
996428d7b3dSmrg	case RR_Rotate_270:
997428d7b3dSmrg		return mode->width;
998428d7b3dSmrg	default:
999428d7b3dSmrg		return 0;
1000428d7b3dSmrg	}
1001428d7b3dSmrg}
1002428d7b3dSmrg
1003428d7b3dSmrgstatic int mode_width(const XRRModeInfo *mode, Rotation rotation)
1004428d7b3dSmrg{
1005428d7b3dSmrg	switch (rotation & 0xf) {
1006428d7b3dSmrg	case RR_Rotate_0:
1007428d7b3dSmrg	case RR_Rotate_180:
1008428d7b3dSmrg		return mode->width;
1009428d7b3dSmrg	case RR_Rotate_90:
1010428d7b3dSmrg	case RR_Rotate_270:
1011428d7b3dSmrg		return mode->height;
1012428d7b3dSmrg	default:
1013428d7b3dSmrg		return 0;
1014428d7b3dSmrg	}
1015428d7b3dSmrg}
1016428d7b3dSmrg
1017428d7b3dSmrgstatic void output_init_xfer(struct clone *clone, struct output *output)
1018428d7b3dSmrg{
1019428d7b3dSmrg	if (output->pixmap == None && output->use_shm_pixmap) {
1020428d7b3dSmrg		DBG(DRAW, ("%s-%s: creating shm pixmap\n", DisplayString(output->dpy), output->name));
1021428d7b3dSmrg		XSync(output->dpy, False);
1022428d7b3dSmrg		_x_error_occurred = 0;
1023428d7b3dSmrg
1024428d7b3dSmrg		output->pixmap = XShmCreatePixmap(output->dpy, output->window,
1025428d7b3dSmrg						  clone->shm.shmaddr, &output->shm,
1026428d7b3dSmrg						  clone->width, clone->height, clone->depth);
1027428d7b3dSmrg		if (output->pix_picture) {
1028428d7b3dSmrg			XRenderFreePicture(output->dpy, output->pix_picture);
1029428d7b3dSmrg			output->pix_picture = None;
1030428d7b3dSmrg		}
1031428d7b3dSmrg
1032428d7b3dSmrg		XSync(output->dpy, False);
1033428d7b3dSmrg		if (_x_error_occurred) {
1034428d7b3dSmrg			XFreePixmap(output->dpy, output->pixmap);
1035428d7b3dSmrg			output->pixmap = None;
1036428d7b3dSmrg			output->use_shm_pixmap = 0;
1037428d7b3dSmrg		}
1038428d7b3dSmrg	}
1039428d7b3dSmrg	if (output->use_render) {
1040428d7b3dSmrg		DBG(DRAW, ("%s-%s: creating picture\n", DisplayString(output->dpy), output->name));
1041428d7b3dSmrg		if (output->win_picture == None)
1042428d7b3dSmrg			output->win_picture = XRenderCreatePicture(output->dpy, output->window,
1043428d7b3dSmrg								   output->display->root_format, 0, NULL);
1044428d7b3dSmrg		if (output->pixmap == None)
1045428d7b3dSmrg			output->pixmap = XCreatePixmap(output->dpy, output->window,
1046428d7b3dSmrg						       clone->width, clone->height, clone->depth);
1047428d7b3dSmrg		if (output->pix_picture == None)
1048428d7b3dSmrg			output->pix_picture = XRenderCreatePicture(output->dpy, output->pixmap,
1049428d7b3dSmrg								   output->use_render, 0, NULL);
1050428d7b3dSmrg	}
1051428d7b3dSmrg
1052428d7b3dSmrg	if (output->gc == None) {
1053428d7b3dSmrg		XGCValues gcv;
1054428d7b3dSmrg
1055428d7b3dSmrg		DBG(DRAW, ("%s-%s: creating gc\n", DisplayString(output->dpy), output->name));
1056428d7b3dSmrg
1057428d7b3dSmrg		gcv.graphics_exposures = False;
1058428d7b3dSmrg		gcv.subwindow_mode = IncludeInferiors;
1059428d7b3dSmrg
1060428d7b3dSmrg		output->gc = XCreateGC(output->dpy, output->pixmap ?: output->window, GCGraphicsExposures | GCSubwindowMode, &gcv);
1061428d7b3dSmrg	}
1062428d7b3dSmrg}
1063428d7b3dSmrg
1064428d7b3dSmrgstatic int bpp_for_depth(int depth)
1065428d7b3dSmrg{
1066428d7b3dSmrg	switch (depth) {
1067428d7b3dSmrg	case 1: return 1;
1068428d7b3dSmrg	case 8: return 8;
1069428d7b3dSmrg	case 15: return 16;
1070428d7b3dSmrg	case 16: return 16;
1071428d7b3dSmrg	case 24: return 24;
1072428d7b3dSmrg	case 32: return 32;
1073428d7b3dSmrg	default: return 0;
1074428d7b3dSmrg	}
1075428d7b3dSmrg}
1076428d7b3dSmrg
1077428d7b3dSmrgstatic int clone_init_xfer(struct clone *clone)
1078428d7b3dSmrg{
1079428d7b3dSmrg	int width, height;
1080428d7b3dSmrg
1081428d7b3dSmrg	if (clone->dst.mode.id == 0) {
1082428d7b3dSmrg		width = 0;
1083428d7b3dSmrg		height = 0;
1084428d7b3dSmrg	} else if (clone->dri3.xid) {
1085428d7b3dSmrg		width = clone->dst.display->width;
1086428d7b3dSmrg		height = clone->dst.display->height;
1087428d7b3dSmrg	} else {
1088428d7b3dSmrg		width = mode_width(&clone->src.mode, clone->src.rotation);
1089428d7b3dSmrg		height = mode_height(&clone->src.mode, clone->src.rotation);
1090428d7b3dSmrg	}
1091428d7b3dSmrg
1092428d7b3dSmrg	if (width == clone->width && height == clone->height)
1093428d7b3dSmrg		return 0;
1094428d7b3dSmrg
1095428d7b3dSmrg	DBG(DRAW, ("%s-%s create xfer, %dx%d\n",
1096428d7b3dSmrg	     DisplayString(clone->dst.dpy), clone->dst.name,
1097428d7b3dSmrg	     width, height));
1098428d7b3dSmrg
1099428d7b3dSmrg	if (clone->shm.shmaddr) {
1100428d7b3dSmrg		if (clone->src.use_shm)
1101428d7b3dSmrg			XShmDetach(clone->src.dpy, &clone->src.shm);
1102428d7b3dSmrg		if (clone->dst.use_shm)
1103428d7b3dSmrg			XShmDetach(clone->dst.dpy, &clone->dst.shm);
1104428d7b3dSmrg
1105428d7b3dSmrg		shmdt(clone->shm.shmaddr);
1106428d7b3dSmrg		clone->shm.shmaddr = NULL;
1107428d7b3dSmrg	}
1108428d7b3dSmrg
1109428d7b3dSmrg	if (clone->src.pixmap) {
1110428d7b3dSmrg		XFreePixmap(clone->src.dpy, clone->src.pixmap);
1111428d7b3dSmrg		clone->src.pixmap = 0;
1112428d7b3dSmrg	}
1113428d7b3dSmrg
1114428d7b3dSmrg	if (clone->dst.pixmap) {
1115428d7b3dSmrg		XFreePixmap(clone->dst.dpy, clone->dst.pixmap);
1116428d7b3dSmrg		clone->dst.pixmap = 0;
1117428d7b3dSmrg	}
1118428d7b3dSmrg
1119428d7b3dSmrg	if ((width | height) == 0) {
1120428d7b3dSmrg		clone->damaged.x2 = clone->damaged.y2 = INT_MIN;
1121428d7b3dSmrg		clone->damaged.x1 = clone->damaged.y1 = INT_MAX;
1122428d7b3dSmrg		return 0;
1123428d7b3dSmrg	}
1124428d7b3dSmrg
1125428d7b3dSmrg	if (clone->dri3.xid) {
1126428d7b3dSmrg		int fd, stride;
1127428d7b3dSmrg		Pixmap src;
1128428d7b3dSmrg
1129428d7b3dSmrg		_x_error_occurred = 0;
1130428d7b3dSmrg
1131428d7b3dSmrg		DBG(DRAW, ("%s-%s create xfer, trying DRI3\n",
1132428d7b3dSmrg		     DisplayString(clone->dst.dpy), clone->dst.name));
1133428d7b3dSmrg
1134428d7b3dSmrg		fd = dri3_create_fd(clone->dst.dpy, clone->dst.window, &stride);
1135428d7b3dSmrg		if (fd < 0)
1136428d7b3dSmrg			goto disable_dri3;
1137428d7b3dSmrg
1138428d7b3dSmrg		DBG(DRAW, ("%s-%s create xfer, DRI3 fd=%d, stride=%d\n",
1139428d7b3dSmrg		     DisplayString(clone->dst.dpy), clone->dst.name,
1140428d7b3dSmrg		     fd, stride));
1141428d7b3dSmrg
1142428d7b3dSmrg		src = dri3_create_pixmap(clone->src.dpy, clone->src.window,
1143428d7b3dSmrg					 width, height, clone->depth,
1144428d7b3dSmrg					 fd, bpp_for_depth(clone->depth),
1145428d7b3dSmrg					 stride, lseek(fd, 0, SEEK_END));
1146428d7b3dSmrg
1147428d7b3dSmrg		XSync(clone->src.dpy, False);
1148428d7b3dSmrg		if (!_x_error_occurred) {
1149428d7b3dSmrg			clone->src.pixmap = src;
1150428d7b3dSmrg			clone->width = width;
1151428d7b3dSmrg			clone->height = height;
1152428d7b3dSmrg		} else {
1153428d7b3dSmrg			XFreePixmap(clone->src.dpy, src);
1154428d7b3dSmrg			close(fd);
1155428d7b3dSmrgdisable_dri3:
1156428d7b3dSmrg			dri3_fence_free(clone->src.dpy, &clone->dri3);
1157428d7b3dSmrg			clone->dri3.xid = 0;
1158428d7b3dSmrg
1159428d7b3dSmrg			DBG(DRAW, ("%s-%s create xfer, DRI3 failed\n",
1160428d7b3dSmrg			     DisplayString(clone->dst.dpy), clone->dst.name));
1161428d7b3dSmrg		}
1162428d7b3dSmrg	}
1163428d7b3dSmrg
1164428d7b3dSmrg	width = mode_width(&clone->src.mode, clone->src.rotation);
1165428d7b3dSmrg	height = mode_height(&clone->src.mode, clone->src.rotation);
1166428d7b3dSmrg
1167428d7b3dSmrg	if (!clone->dri3.xid) {
1168428d7b3dSmrg		DBG(DRAW, ("%s-%s create xfer, trying SHM\n",
1169428d7b3dSmrg		     DisplayString(clone->dst.dpy), clone->dst.name));
1170428d7b3dSmrg
1171428d7b3dSmrg		clone->shm.shmid = shmget(IPC_PRIVATE,
1172428d7b3dSmrg					  height * stride_for_depth(width, clone->depth),
1173428d7b3dSmrg					  IPC_CREAT | 0666);
1174428d7b3dSmrg		if (clone->shm.shmid == -1)
1175428d7b3dSmrg			return errno;
1176428d7b3dSmrg
1177428d7b3dSmrg		clone->shm.shmaddr = shmat(clone->shm.shmid, 0, 0);
1178428d7b3dSmrg		if (clone->shm.shmaddr == (char *) -1) {
1179428d7b3dSmrg			shmctl(clone->shm.shmid, IPC_RMID, NULL);
1180428d7b3dSmrg			return ENOMEM;
1181428d7b3dSmrg		}
1182428d7b3dSmrg
1183428d7b3dSmrg		if (clone->src.use_shm) {
1184428d7b3dSmrg			clone->src.shm = clone->shm;
1185428d7b3dSmrg			clone->src.shm.readOnly = False;
1186428d7b3dSmrg			XShmAttach(clone->src.dpy, &clone->src.shm);
1187428d7b3dSmrg			XSync(clone->src.dpy, False);
1188428d7b3dSmrg		}
1189428d7b3dSmrg		if (clone->dst.use_shm) {
1190428d7b3dSmrg			clone->dst.shm = clone->shm;
1191428d7b3dSmrg			clone->dst.shm.readOnly = !clone->dst.use_shm_pixmap;
1192428d7b3dSmrg			XShmAttach(clone->dst.dpy, &clone->dst.shm);
1193428d7b3dSmrg			XSync(clone->dst.dpy, False);
1194428d7b3dSmrg		}
1195428d7b3dSmrg
1196428d7b3dSmrg		shmctl(clone->shm.shmid, IPC_RMID, NULL);
1197428d7b3dSmrg
1198428d7b3dSmrg		clone->width = width;
1199428d7b3dSmrg		clone->height = height;
1200428d7b3dSmrg
1201428d7b3dSmrg		init_image(clone);
1202428d7b3dSmrg	}
1203428d7b3dSmrg
1204428d7b3dSmrg	output_init_xfer(clone, &clone->src);
1205428d7b3dSmrg	output_init_xfer(clone, &clone->dst);
1206428d7b3dSmrg
1207428d7b3dSmrg	clone->damaged.x1 = clone->src.x;
1208428d7b3dSmrg	clone->damaged.x2 = clone->src.x + width;
1209428d7b3dSmrg	clone->damaged.y1 = clone->src.y;
1210428d7b3dSmrg	clone->damaged.y2 = clone->src.y + height;
1211428d7b3dSmrg
1212428d7b3dSmrg	display_mark_flush(clone->dst.display);
1213428d7b3dSmrg	return 0;
1214428d7b3dSmrg}
1215428d7b3dSmrg
1216428d7b3dSmrgstatic void clone_update(struct clone *clone)
1217428d7b3dSmrg{
1218428d7b3dSmrg	if (!clone->rr_update)
1219428d7b3dSmrg		return;
1220428d7b3dSmrg
1221428d7b3dSmrg	DBG(X11, ("%s-%s cloning modes\n",
1222428d7b3dSmrg	     DisplayString(clone->dst.dpy), clone->dst.name));
1223428d7b3dSmrg
1224428d7b3dSmrg	clone_update_modes__randr(clone);
1225428d7b3dSmrg	clone->rr_update = 0;
1226428d7b3dSmrg}
1227428d7b3dSmrg
1228428d7b3dSmrgstatic int context_update(struct context *ctx)
1229428d7b3dSmrg{
1230428d7b3dSmrg	Display *dpy = ctx->display->dpy;
1231428d7b3dSmrg	XRRScreenResources *res;
1232428d7b3dSmrg	int context_changed = 0;
1233428d7b3dSmrg	int i, n;
1234428d7b3dSmrg
1235428d7b3dSmrg	DBG(X11, ("%s\n", __func__));
1236428d7b3dSmrg
1237428d7b3dSmrg	res = _XRRGetScreenResourcesCurrent(dpy, ctx->display->root);
1238428d7b3dSmrg	if (res == NULL)
1239428d7b3dSmrg		return 0;
1240428d7b3dSmrg
1241428d7b3dSmrg	DBG(XRR, ("%s timestamp %ld (last %ld), config %ld (last %ld)\n",
1242428d7b3dSmrg	     DisplayString(dpy),
1243428d7b3dSmrg	     res->timestamp, ctx->timestamp,
1244428d7b3dSmrg	     res->configTimestamp, ctx->configTimestamp));
1245428d7b3dSmrg	if (res->timestamp == ctx->timestamp &&
1246428d7b3dSmrg	    res->configTimestamp == ctx->configTimestamp &&
1247428d7b3dSmrg	    res->timestamp != res->configTimestamp) { /* mutter be damned */
1248428d7b3dSmrg		XRRFreeScreenResources(res);
1249428d7b3dSmrg		return 0;
1250428d7b3dSmrg	}
1251428d7b3dSmrg
1252428d7b3dSmrg	ctx->timestamp = res->timestamp;
1253428d7b3dSmrg	ctx->configTimestamp = res->configTimestamp;
1254428d7b3dSmrg
1255428d7b3dSmrg	for (n = 0; n < ctx->nclone; n++) {
1256428d7b3dSmrg		struct output *output = &ctx->clones[n].src;
1257428d7b3dSmrg		XRROutputInfo *o;
1258428d7b3dSmrg		XRRCrtcInfo *c;
1259428d7b3dSmrg		RRMode mode = 0;
1260428d7b3dSmrg		int changed = 0;
1261428d7b3dSmrg
1262428d7b3dSmrg		o = XRRGetOutputInfo(dpy, res, output->rr_output);
1263428d7b3dSmrg		if (o == NULL)
1264428d7b3dSmrg			continue;
1265428d7b3dSmrg
1266428d7b3dSmrg		c = NULL;
1267428d7b3dSmrg		if (o->crtc)
1268428d7b3dSmrg			c = XRRGetCrtcInfo(dpy, res, o->crtc);
1269428d7b3dSmrg		if (c) {
1270428d7b3dSmrg			DBG(XRR, ("%s-%s: (x=%d, y=%d, rotation=%d, mode=%ld) -> (x=%d, y=%d, rotation=%d, mode=%ld)\n",
1271428d7b3dSmrg			     DisplayString(dpy), output->name,
1272428d7b3dSmrg			     output->x, output->y, output->rotation, output->mode.id,
1273428d7b3dSmrg			     c->x, c->y, c->rotation, c->mode));
1274428d7b3dSmrg
1275428d7b3dSmrg			changed |= output->rotation != c->rotation;
1276428d7b3dSmrg			output->rotation = c->rotation;
1277428d7b3dSmrg
1278428d7b3dSmrg			changed |= output->x != c->x;
1279428d7b3dSmrg			output->x = c->x;
1280428d7b3dSmrg
1281428d7b3dSmrg			changed |= output->y != c->y;
1282428d7b3dSmrg			output->y = c->y;
1283428d7b3dSmrg
1284428d7b3dSmrg			changed |= output->mode.id != c->mode;
1285428d7b3dSmrg			mode = c->mode;
1286428d7b3dSmrg			XRRFreeCrtcInfo(c);
1287428d7b3dSmrg		} else {
1288428d7b3dSmrg			DBG(XRR, ("%s-%s: (x=%d, y=%d, rotation=%d, mode=%ld) -> off\n",
1289428d7b3dSmrg			     DisplayString(dpy), output->name,
1290428d7b3dSmrg			     output->x, output->y, output->rotation, output->mode.id));
1291428d7b3dSmrg		}
1292428d7b3dSmrg		output->rr_crtc = o->crtc;
1293428d7b3dSmrg		XRRFreeOutputInfo(o);
1294428d7b3dSmrg
1295428d7b3dSmrg		DBG(XRR, ("%s-%s crtc changed? %d\n",
1296428d7b3dSmrg		     DisplayString(ctx->clones[n].dst.display->dpy), ctx->clones[n].dst.name, changed));
1297428d7b3dSmrg
1298428d7b3dSmrg		if (mode) {
1299428d7b3dSmrg			if (output->mode.id != mode) {
1300428d7b3dSmrg				for (i = 0; i < res->nmode; i++) {
1301428d7b3dSmrg					if (res->modes[i].id == mode) {
1302428d7b3dSmrg						output->mode = res->modes[i];
1303428d7b3dSmrg						break;
1304428d7b3dSmrg					}
1305428d7b3dSmrg				}
1306428d7b3dSmrg			}
1307428d7b3dSmrg		} else {
1308428d7b3dSmrg			changed = output->mode.id != 0;
1309428d7b3dSmrg			output->mode.id = 0;
1310428d7b3dSmrg		}
1311428d7b3dSmrg
1312428d7b3dSmrg		DBG(XRR, ("%s-%s output changed? %d\n",
1313428d7b3dSmrg		     DisplayString(ctx->clones[n].dst.display->dpy), ctx->clones[n].dst.name, changed));
1314428d7b3dSmrg
1315428d7b3dSmrg		context_changed |= changed;
1316428d7b3dSmrg	}
1317428d7b3dSmrg	XRRFreeScreenResources(res);
1318428d7b3dSmrg
1319428d7b3dSmrg	DBG(XRR, ("%s changed? %d\n", DisplayString(dpy), context_changed));
1320428d7b3dSmrg	if (!context_changed)
1321428d7b3dSmrg		return 0;
1322428d7b3dSmrg
1323428d7b3dSmrg	for (n = 1; n < ctx->ndisplay; n++) {
1324428d7b3dSmrg		struct display *display = &ctx->display[n];
1325428d7b3dSmrg		struct clone *clone;
1326428d7b3dSmrg		int x1, x2, y1, y2;
1327428d7b3dSmrg
1328428d7b3dSmrg		if (display->rr_active == 0)
1329428d7b3dSmrg			continue;
1330428d7b3dSmrg
1331428d7b3dSmrg		x1 = y1 = INT_MAX;
1332428d7b3dSmrg		x2 = y2 = INT_MIN;
1333428d7b3dSmrg
1334428d7b3dSmrg		for (clone = display->clone; clone; clone = clone->next) {
1335428d7b3dSmrg			struct output *output = &clone->src;
1336428d7b3dSmrg			int v;
1337428d7b3dSmrg
1338428d7b3dSmrg			assert(clone->dst.display == display);
1339428d7b3dSmrg
1340428d7b3dSmrg			if (output->mode.id == 0)
1341428d7b3dSmrg				continue;
1342428d7b3dSmrg
1343428d7b3dSmrg			DBG(XRR, ("%s: source %s enabled (%d, %d)x(%d, %d)\n",
1344428d7b3dSmrg			     DisplayString(clone->dst.dpy), output->name,
1345428d7b3dSmrg			     output->x, output->y,
1346428d7b3dSmrg			     mode_width(&output->mode, output->rotation),
1347428d7b3dSmrg			     mode_height(&output->mode, output->rotation)));
1348428d7b3dSmrg
1349428d7b3dSmrg			if (output->x < x1)
1350428d7b3dSmrg				x1 = output->x;
1351428d7b3dSmrg			if (output->y < y1)
1352428d7b3dSmrg				y1 = output->y;
1353428d7b3dSmrg
1354428d7b3dSmrg			v = (int)output->x + mode_width(&output->mode, output->rotation);
1355428d7b3dSmrg			if (v > x2)
1356428d7b3dSmrg				x2 = v;
1357428d7b3dSmrg			v = (int)output->y + mode_height(&output->mode, output->rotation);
1358428d7b3dSmrg			if (v > y2)
1359428d7b3dSmrg				y2 = v;
1360428d7b3dSmrg		}
1361428d7b3dSmrg
1362428d7b3dSmrg		DBG(XRR, ("%s fb bounds (%d, %d)x(%d, %d)\n", DisplayString(display->dpy),
1363428d7b3dSmrg		     x1, y1, x2, y2));
1364428d7b3dSmrg
1365428d7b3dSmrg		XGrabServer(display->dpy);
1366428d7b3dSmrg		res = _XRRGetScreenResourcesCurrent(display->dpy, display->root);
1367428d7b3dSmrg		if (res == NULL)
1368428d7b3dSmrg			goto ungrab;
1369428d7b3dSmrg
1370428d7b3dSmrg		if (x2 <= x1 || y2 <= y1) {
1371428d7b3dSmrg			/* Nothing enabled, preserve the current fb, and turn everything off */
1372428d7b3dSmrg			for (clone = display->clone; clone; clone = clone->next) {
1373428d7b3dSmrg				struct output *dst = &clone->dst;
1374428d7b3dSmrg
1375428d7b3dSmrg				if (!dst->rr_crtc)
1376428d7b3dSmrg					continue;
1377428d7b3dSmrg
1378428d7b3dSmrg				DBG(XRR, ("%s: disabling output '%s'\n",
1379428d7b3dSmrg				     DisplayString(display->dpy), dst->name));
1380428d7b3dSmrg				assert(clone->dst.display == display);
1381428d7b3dSmrg				if (disable_crtc(display->dpy, res, dst->rr_crtc)) {
1382428d7b3dSmrg					dst->rr_crtc = 0;
1383428d7b3dSmrg					dst->mode.id = 0;
1384428d7b3dSmrg				}
1385428d7b3dSmrg			}
1386428d7b3dSmrg			goto free_res;
1387428d7b3dSmrg		}
1388428d7b3dSmrg
1389428d7b3dSmrg		x2 -= x1;
1390428d7b3dSmrg		y2 -= y1;
1391428d7b3dSmrg		DBG(XRR, ("%s: current size %dx%d, need %dx%d\n",
1392428d7b3dSmrg		     DisplayString(display->dpy),
1393428d7b3dSmrg		     display->width, display->height,
1394428d7b3dSmrg		     x2, y2));
1395428d7b3dSmrg
1396428d7b3dSmrg		if (display->width != x2 || display->height != y2) {
1397428d7b3dSmrg			/* When shrinking we have to manually resize the fb */
1398428d7b3dSmrg			for (clone = display->clone; clone; clone = clone->next) {
1399428d7b3dSmrg				struct output *dst = &clone->dst;
1400428d7b3dSmrg
1401428d7b3dSmrg				if (!dst->rr_crtc)
1402428d7b3dSmrg					continue;
1403428d7b3dSmrg
1404428d7b3dSmrg				DBG(XRR, ("%s: disabling output '%s'\n",
1405428d7b3dSmrg				     DisplayString(display->dpy), dst->name));
1406428d7b3dSmrg				assert(clone->dst.display == display);
1407428d7b3dSmrg				if (disable_crtc(display->dpy, res, dst->rr_crtc)) {
1408428d7b3dSmrg					dst->rr_crtc = 0;
1409428d7b3dSmrg					dst->mode.id = 0;
1410428d7b3dSmrg				}
1411428d7b3dSmrg			}
1412428d7b3dSmrg
1413428d7b3dSmrg			DBG(XRR, ("%s: XRRSetScreenSize %dx%d\n", DisplayString(display->dpy), x2, y2));
1414428d7b3dSmrg			XRRSetScreenSize(display->dpy, display->root, x2, y2, x2 * 96 / 25.4, y2 * 96 / 25.4);
1415428d7b3dSmrg			display->width = x2;
1416428d7b3dSmrg			display->height = y2;
1417428d7b3dSmrg		}
1418428d7b3dSmrg
1419428d7b3dSmrg		for (clone = display->clone; clone; clone = clone->next) {
1420428d7b3dSmrg			struct output *src = &clone->src;
1421428d7b3dSmrg			struct output *dst = &clone->dst;
1422428d7b3dSmrg			XRROutputInfo *o;
1423428d7b3dSmrg			XRRPanning panning;
1424428d7b3dSmrg			struct clone *set;
1425428d7b3dSmrg			RRCrtc rr_crtc;
1426428d7b3dSmrg			Status ret;
1427428d7b3dSmrg
1428428d7b3dSmrg			DBG(XRR, ("%s: copying configuration from %s (mode=%ld: %dx%d) to %s\n",
1429428d7b3dSmrg			     DisplayString(display->dpy),
1430428d7b3dSmrg			     src->name, (long)src->mode.id, src->mode.width, src->mode.height,
1431428d7b3dSmrg			     dst->name));
1432428d7b3dSmrg
1433428d7b3dSmrg			if (src->mode.id == 0) {
1434428d7b3dSmrgerr:
1435428d7b3dSmrg				if (dst->rr_crtc) {
1436428d7b3dSmrg					DBG(XRR, ("%s: disabling unused output '%s'\n",
1437428d7b3dSmrg					     DisplayString(display->dpy), dst->name));
1438428d7b3dSmrg					assert(clone->dst.display == display);
1439428d7b3dSmrg					if (disable_crtc(display->dpy, res, dst->rr_crtc)) {
1440428d7b3dSmrg						dst->rr_crtc = 0;
1441428d7b3dSmrg						dst->mode.id = 0;
1442428d7b3dSmrg					}
1443428d7b3dSmrg				}
1444428d7b3dSmrg				continue;
1445428d7b3dSmrg			}
1446428d7b3dSmrg
1447428d7b3dSmrg			dst->x = src->x - x1;
1448428d7b3dSmrg			dst->y = src->y - y1;
1449428d7b3dSmrg			dst->rotation = src->rotation;
1450428d7b3dSmrg			dst->mode = src->mode;
1451428d7b3dSmrg
1452428d7b3dSmrg			dst->mode.id = 0;
1453428d7b3dSmrg			for (i = 0; i < res->nmode; i++) {
1454428d7b3dSmrg				if (mode_equal(&src->mode, &res->modes[i])) {
1455428d7b3dSmrg					dst->mode.id = res->modes[i].id;
1456428d7b3dSmrg					break;
1457428d7b3dSmrg				}
1458428d7b3dSmrg			}
1459428d7b3dSmrg			if (dst->mode.id == 0) {
1460428d7b3dSmrg				XRRModeInfo m;
1461428d7b3dSmrg				char buf[256];
1462428d7b3dSmrg				RRMode id;
1463428d7b3dSmrg
1464428d7b3dSmrg				/* XXX User names must be unique! */
1465428d7b3dSmrg				m = src->mode;
1466428d7b3dSmrg				m.nameLength = snprintf(buf, sizeof(buf),
1467428d7b3dSmrg							"%s.%ld-%dx%d", src->name,
1468428d7b3dSmrg							(long)src->mode.id,
1469428d7b3dSmrg							src->mode.width,
1470428d7b3dSmrg							src->mode.height);
1471428d7b3dSmrg				m.name = buf;
1472428d7b3dSmrg
1473428d7b3dSmrg				id = XRRCreateMode(dst->dpy, dst->window, &m);
1474428d7b3dSmrg				if (id) {
1475428d7b3dSmrg					DBG(XRR, ("%s: adding mode %ld: %dx%d to %s, new mode %ld\n",
1476428d7b3dSmrg					     DisplayString(dst->dpy),
1477428d7b3dSmrg					     (long)src->mode.id,
1478428d7b3dSmrg					     src->mode.width,
1479428d7b3dSmrg					     src->mode.height,
1480428d7b3dSmrg					     dst->name, (long)id));
1481428d7b3dSmrg					XRRAddOutputMode(dst->dpy, dst->rr_output, id);
1482428d7b3dSmrg					dst->mode.id = id;
1483428d7b3dSmrg				} else {
1484428d7b3dSmrg					DBG(XRR, ("%s: failed to find suitable mode for %s\n",
1485428d7b3dSmrg					     DisplayString(dst->dpy), dst->name));
1486428d7b3dSmrg					goto err;
1487428d7b3dSmrg				}
1488428d7b3dSmrg			}
1489428d7b3dSmrg
1490428d7b3dSmrg			rr_crtc = dst->rr_crtc;
1491428d7b3dSmrg			if (rr_crtc) {
1492428d7b3dSmrg				for (set = display->clone; set != clone; set = set->next) {
1493428d7b3dSmrg					if (set->dst.rr_crtc == rr_crtc) {
1494428d7b3dSmrg						DBG(XRR, ("%s: CRTC reassigned from %s\n",
1495428d7b3dSmrg						     DisplayString(dst->dpy), dst->name));
1496428d7b3dSmrg						rr_crtc = 0;
1497428d7b3dSmrg						break;
1498428d7b3dSmrg					}
1499428d7b3dSmrg				}
1500428d7b3dSmrg			}
1501428d7b3dSmrg			if (rr_crtc == 0) {
1502428d7b3dSmrg				o = XRRGetOutputInfo(dst->dpy, res, dst->rr_output);
1503428d7b3dSmrg				for (i = 0; i < o->ncrtc; i++) {
1504428d7b3dSmrg					DBG(XRR, ("%s: checking whether CRTC:%ld is available\n",
1505428d7b3dSmrg					     DisplayString(dst->dpy), (long)o->crtcs[i]));
1506428d7b3dSmrg					for (set = display->clone; set != clone; set = set->next) {
1507428d7b3dSmrg						if (set->dst.rr_crtc == o->crtcs[i]) {
1508428d7b3dSmrg							DBG(XRR, ("%s: CRTC:%ld already assigned to %s\n",
1509428d7b3dSmrg							     DisplayString(dst->dpy), (long)o->crtcs[i], set->dst.name));
1510428d7b3dSmrg							break;
1511428d7b3dSmrg						}
1512428d7b3dSmrg					}
1513428d7b3dSmrg					if (set == clone) {
1514428d7b3dSmrg						rr_crtc = o->crtcs[i];
1515428d7b3dSmrg						break;
1516428d7b3dSmrg					}
1517428d7b3dSmrg				}
1518428d7b3dSmrg				XRRFreeOutputInfo(o);
1519428d7b3dSmrg			}
1520428d7b3dSmrg			if (rr_crtc == 0) {
1521428d7b3dSmrg				DBG(XRR, ("%s: failed to find available CRTC for %s\n",
1522428d7b3dSmrg				     DisplayString(dst->dpy), dst->name));
1523428d7b3dSmrg				goto err;
1524428d7b3dSmrg			}
1525428d7b3dSmrg
1526428d7b3dSmrg			DBG(XRR, ("%s: enabling output '%s' (%d,%d)x(%d,%d), rotation %d, on CRTC:%ld, using mode %ld\n",
1527428d7b3dSmrg			     DisplayString(dst->dpy), dst->name,
1528428d7b3dSmrg			     dst->x, dst->y, dst->mode.width, dst->mode.height,
1529428d7b3dSmrg			     dst->rotation, (long)rr_crtc, dst->mode.id));
1530428d7b3dSmrg
1531428d7b3dSmrg			ret = XRRSetPanning(dst->dpy, res, rr_crtc, memset(&panning, 0, sizeof(panning)));
1532428d7b3dSmrg			DBG(XRR, ("%s-%s: XRRSetPanning %s\n", DisplayString(dst->dpy), dst->name, ret ? "failed" : "success"));
1533428d7b3dSmrg			(void)ret;
1534428d7b3dSmrg
1535428d7b3dSmrg			ret = XRRSetCrtcConfig(dst->dpy, res, rr_crtc, CurrentTime,
1536428d7b3dSmrg					       dst->x, dst->y, dst->mode.id, dst->rotation,
1537428d7b3dSmrg					       &dst->rr_output, 1);
1538428d7b3dSmrg			DBG(XRR, ("%s-%s: XRRSetCrtcConfig %s\n", DisplayString(dst->dpy), dst->name, ret ? "failed" : "success"));
1539428d7b3dSmrg			if (ret)
1540428d7b3dSmrg				goto err;
1541428d7b3dSmrg
1542428d7b3dSmrg			if (verbose & XRR) {
1543428d7b3dSmrg				XRRCrtcInfo *c;
1544428d7b3dSmrg				XRRPanning *p;
1545428d7b3dSmrg
1546428d7b3dSmrg				c = XRRGetCrtcInfo(dst->dpy, res, rr_crtc);
1547428d7b3dSmrg				if (c) {
1548428d7b3dSmrg					DBG(XRR, ("%s-%s: x=%d, y=%d, rotation=%d, mode=%ld\n",
1549428d7b3dSmrg					     DisplayString(dst->dpy), dst->name,
1550428d7b3dSmrg					     c->x, c->y, c->rotation, c->mode));
1551428d7b3dSmrg					XRRFreeCrtcInfo(c);
1552428d7b3dSmrg				}
1553428d7b3dSmrg
1554428d7b3dSmrg				p = XRRGetPanning(dst->dpy, res, rr_crtc);
1555428d7b3dSmrg				if (p) {
1556428d7b3dSmrg					DBG(XRR, ("%s-%s: panning (%d, %d)x(%d, %d), tracking (%d, %d)x(%d, %d), border (%d, %d),(%d, %d)\n",
1557428d7b3dSmrg					     DisplayString(dst->dpy), dst->name,
1558428d7b3dSmrg					     p->left, p->top, p->width, p->height,
1559428d7b3dSmrg					     p->track_left, p->track_top, p->track_width, p->track_height,
1560428d7b3dSmrg					     p->border_left, p->border_top, p->border_right, p->border_bottom));
1561428d7b3dSmrg					XRRFreePanning(p);
1562428d7b3dSmrg				}
1563428d7b3dSmrg			}
1564428d7b3dSmrg
1565428d7b3dSmrg			dst->rr_crtc = rr_crtc;
1566428d7b3dSmrg		}
1567428d7b3dSmrgfree_res:
1568428d7b3dSmrg		XRRFreeScreenResources(res);
1569428d7b3dSmrgungrab:
1570428d7b3dSmrg		XUngrabServer(display->dpy);
1571428d7b3dSmrg	}
1572428d7b3dSmrg
1573428d7b3dSmrg	ctx->active = NULL;
1574428d7b3dSmrg	for (n = 0; n < ctx->nclone; n++) {
1575428d7b3dSmrg		struct clone *clone = &ctx->clones[n];
1576428d7b3dSmrg
1577428d7b3dSmrg		clone_init_xfer(clone);
1578428d7b3dSmrg
1579428d7b3dSmrg		if (clone->dst.rr_crtc == 0)
1580428d7b3dSmrg			continue;
1581428d7b3dSmrg
1582428d7b3dSmrg		DBG(XRR, ("%s-%s: added to active list\n",
1583428d7b3dSmrg		     DisplayString(clone->dst.display->dpy), clone->dst.name));
1584428d7b3dSmrg
1585428d7b3dSmrg		clone->active = ctx->active;
1586428d7b3dSmrg		ctx->active = clone;
1587428d7b3dSmrg	}
1588428d7b3dSmrg
1589428d7b3dSmrg	return 1;
1590428d7b3dSmrg}
1591428d7b3dSmrg
1592428d7b3dSmrgstatic Cursor display_load_invisible_cursor(struct display *display)
1593428d7b3dSmrg{
1594428d7b3dSmrg	char zero[8] = {};
1595428d7b3dSmrg	XColor black = {};
1596428d7b3dSmrg	Pixmap bitmap = XCreateBitmapFromData(display->dpy, display->root, zero, 8, 8);
1597428d7b3dSmrg	return XCreatePixmapCursor(display->dpy, bitmap, bitmap, &black, &black, 0, 0);
1598428d7b3dSmrg}
1599428d7b3dSmrg
1600428d7b3dSmrgstatic Cursor display_get_visible_cursor(struct display *display)
1601428d7b3dSmrg{
1602428d7b3dSmrg	if (display->cursor_serial != display->cursor_image.size) {
1603428d7b3dSmrg		DBG(CURSOR, ("%s updating cursor\n", DisplayString(display->dpy)));
1604428d7b3dSmrg
1605428d7b3dSmrg		if (display->visible_cursor)
1606428d7b3dSmrg			XFreeCursor(display->dpy, display->visible_cursor);
1607428d7b3dSmrg
1608428d7b3dSmrg		display->visible_cursor = XcursorImageLoadCursor(display->dpy, &display->cursor_image);
1609428d7b3dSmrg		display->cursor_serial = display->cursor_image.size;
1610428d7b3dSmrg	}
1611428d7b3dSmrg
1612428d7b3dSmrg	return display->visible_cursor;
1613428d7b3dSmrg}
1614428d7b3dSmrg
1615428d7b3dSmrgstatic void display_load_visible_cursor(struct display *display, XFixesCursorImage *cur)
1616428d7b3dSmrg{
1617428d7b3dSmrg	unsigned long *src; /* XXX deep sigh */
1618428d7b3dSmrg	XcursorPixel *dst;
1619428d7b3dSmrg	unsigned n;
1620428d7b3dSmrg
1621428d7b3dSmrg	if (cur->width != display->cursor_image.width ||
1622428d7b3dSmrg	    cur->height != display->cursor_image.height)
1623428d7b3dSmrg		display->cursor_image.pixels = realloc(display->cursor_image.pixels,
1624428d7b3dSmrg						       4 * cur->width * cur->height);
1625428d7b3dSmrg	if (display->cursor_image.pixels == NULL)
1626428d7b3dSmrg		return;
1627428d7b3dSmrg
1628428d7b3dSmrg	display->cursor_image.width  = cur->width;
1629428d7b3dSmrg	display->cursor_image.height = cur->height;
1630428d7b3dSmrg	display->cursor_image.xhot = cur->xhot;
1631428d7b3dSmrg	display->cursor_image.yhot = cur->yhot;
1632428d7b3dSmrg	display->cursor_image.size++;
1633428d7b3dSmrg
1634428d7b3dSmrg	n = cur->width*cur->height;
1635428d7b3dSmrg	src = cur->pixels;
1636428d7b3dSmrg	dst = display->cursor_image.pixels;
1637428d7b3dSmrg	while (n--)
1638428d7b3dSmrg		*dst++ = *src++;
1639428d7b3dSmrg
1640428d7b3dSmrg	DBG(CURSOR, ("%s marking cursor changed\n", DisplayString(display->dpy)));
1641428d7b3dSmrg	display->cursor_moved++;
1642428d7b3dSmrg	if (display->cursor != display->invisible_cursor) {
1643428d7b3dSmrg		display->cursor_visible++;
1644428d7b3dSmrg		context_enable_timer(display->ctx);
1645428d7b3dSmrg	}
1646428d7b3dSmrg}
1647428d7b3dSmrg
1648428d7b3dSmrgstatic void display_cursor_move(struct display *display, int x, int y, int visible)
1649428d7b3dSmrg{
1650428d7b3dSmrg	DBG(CURSOR, ("%s cursor moved (visible=%d, (%d, %d))\n",
1651428d7b3dSmrg	     DisplayString(display->dpy), visible, x, y));
1652428d7b3dSmrg	display->cursor_moved++;
1653428d7b3dSmrg	display->cursor_visible += visible;
1654428d7b3dSmrg	if (visible) {
1655428d7b3dSmrg		display->cursor_x = x;
1656428d7b3dSmrg		display->cursor_y = y;
1657428d7b3dSmrg	}
1658428d7b3dSmrg
1659428d7b3dSmrg	context_enable_timer(display->ctx);
1660428d7b3dSmrg}
1661428d7b3dSmrg
1662428d7b3dSmrgstatic void display_flush_cursor(struct display *display)
1663428d7b3dSmrg{
1664428d7b3dSmrg	Cursor cursor;
1665428d7b3dSmrg	int x, y;
1666428d7b3dSmrg
1667428d7b3dSmrg	if (!display->cursor_moved)
1668428d7b3dSmrg		return;
1669428d7b3dSmrg
1670428d7b3dSmrg	if (display->cursor_visible) {
1671428d7b3dSmrg		x = display->cursor_x;
1672428d7b3dSmrg		y = display->cursor_y;
1673428d7b3dSmrg	} else {
1674428d7b3dSmrg		x = display->cursor_x++ & 31;
1675428d7b3dSmrg		y = display->cursor_y++ & 31;
1676428d7b3dSmrg	}
1677428d7b3dSmrg
1678428d7b3dSmrg	DBG(CURSOR, ("%s setting cursor position (%d, %d), visible? %d\n",
1679428d7b3dSmrg	     DisplayString(display->dpy), x, y, display->cursor_visible));
1680428d7b3dSmrg	XWarpPointer(display->dpy, None, display->root, 0, 0, 0, 0, x, y);
1681428d7b3dSmrg
1682428d7b3dSmrg	cursor = None;
1683428d7b3dSmrg	if (display->cursor_visible)
1684428d7b3dSmrg		cursor = display_get_visible_cursor(display);
1685428d7b3dSmrg	if (cursor == None)
1686428d7b3dSmrg		cursor = display->invisible_cursor;
1687428d7b3dSmrg	if (cursor != display->cursor) {
1688428d7b3dSmrg		XDefineCursor(display->dpy, display->root, cursor);
1689428d7b3dSmrg		display->cursor = cursor;
1690428d7b3dSmrg	}
1691428d7b3dSmrg
1692428d7b3dSmrg	display_mark_flush(display);
1693428d7b3dSmrg
1694428d7b3dSmrg	display->cursor_moved = 0;
1695428d7b3dSmrg	display->cursor_visible = 0;
1696428d7b3dSmrg}
1697428d7b3dSmrg
1698428d7b3dSmrgstatic void clone_move_cursor(struct clone *c, int x, int y)
1699428d7b3dSmrg{
1700428d7b3dSmrg	int visible;
1701428d7b3dSmrg
1702428d7b3dSmrg	DBG(CURSOR, ("%s-%s moving cursor (%d, %d) [(%d, %d), (%d, %d)]\n",
1703428d7b3dSmrg	     DisplayString(c->dst.dpy), c->dst.name,
1704428d7b3dSmrg	     x, y,
1705428d7b3dSmrg	     c->src.x, c->src.y,
1706428d7b3dSmrg	     c->src.x + c->width, c->src.y + c->height));
1707428d7b3dSmrg
1708428d7b3dSmrg	visible = (x >= c->src.x && x < c->src.x + c->width &&
1709428d7b3dSmrg		   y >= c->src.y && y < c->src.y + c->height);
1710428d7b3dSmrg
1711428d7b3dSmrg	x += c->dst.x - c->src.x;
1712428d7b3dSmrg	y += c->dst.y - c->src.y;
1713428d7b3dSmrg
1714428d7b3dSmrg	display_cursor_move(c->dst.display, x, y, visible);
1715428d7b3dSmrg}
1716428d7b3dSmrg
1717428d7b3dSmrgstatic int clone_output_init(struct clone *clone, struct output *output,
1718428d7b3dSmrg			     struct display *display, const char *name,
1719428d7b3dSmrg			     RROutput rr_output)
1720428d7b3dSmrg{
1721428d7b3dSmrg	Display *dpy = display->dpy;
1722428d7b3dSmrg	int depth;
1723428d7b3dSmrg
1724428d7b3dSmrg	DBG(X11, ("%s(%s, %s)\n", __func__, DisplayString(dpy), name));
1725428d7b3dSmrg
1726428d7b3dSmrg	output->name = strdup(name);
1727428d7b3dSmrg	if (output->name == NULL)
1728428d7b3dSmrg		return -ENOMEM;
1729428d7b3dSmrg
1730428d7b3dSmrg	output->display = display;
1731428d7b3dSmrg	output->dpy = dpy;
1732428d7b3dSmrg
1733428d7b3dSmrg	output->rr_output = rr_output;
1734428d7b3dSmrg	output->rotation = RR_Rotate_0;
1735428d7b3dSmrg
1736428d7b3dSmrg	output->window = display->root;
1737428d7b3dSmrg	output->use_shm = display->has_shm;
1738428d7b3dSmrg	output->use_shm_pixmap = display->has_shm_pixmap;
1739428d7b3dSmrg
1740428d7b3dSmrg	DBG(X11, ("%s-%s use shm? %d (use shm pixmap? %d)\n",
1741428d7b3dSmrg	     DisplayString(dpy), name, display->has_shm, display->has_shm_pixmap));
1742428d7b3dSmrg
1743428d7b3dSmrg	depth = output->use_shm && !FORCE_16BIT_XFER ? display->depth : 16;
1744428d7b3dSmrg	if (depth < clone->depth)
1745428d7b3dSmrg		clone->depth = depth;
1746428d7b3dSmrg
1747428d7b3dSmrg	return 0;
1748428d7b3dSmrg}
1749428d7b3dSmrg
1750428d7b3dSmrgstatic void ximage_prepare(XImage *image, int width, int height)
1751428d7b3dSmrg{
1752428d7b3dSmrg	image->width = width;
1753428d7b3dSmrg	image->height = height;
1754428d7b3dSmrg	image->bytes_per_line = stride_for_depth(width, image->depth);
1755428d7b3dSmrg}
1756428d7b3dSmrg
1757428d7b3dSmrgstatic void get_src(struct clone *c, const XRectangle *clip)
1758428d7b3dSmrg{
1759428d7b3dSmrg	DBG(DRAW,("%s-%s get_src(%d,%d)x(%d,%d)\n", DisplayString(c->dst.dpy), c->dst.name,
1760428d7b3dSmrg	     clip->x, clip->y, clip->width, clip->height));
1761428d7b3dSmrg
1762428d7b3dSmrg	c->image.obdata = (char *)&c->src.shm;
1763428d7b3dSmrg
1764428d7b3dSmrg	if (c->src.use_render) {
1765428d7b3dSmrg		XRenderComposite(c->src.dpy, PictOpSrc,
1766428d7b3dSmrg				 c->src.win_picture, 0, c->src.pix_picture,
1767428d7b3dSmrg				 clip->x, clip->y,
1768428d7b3dSmrg				 0, 0,
1769428d7b3dSmrg				 0, 0,
1770428d7b3dSmrg				 clip->width, clip->height);
1771428d7b3dSmrg		if (c->src.use_shm_pixmap) {
1772428d7b3dSmrg			XSync(c->src.dpy, False);
1773428d7b3dSmrg		} else if (c->src.use_shm) {
1774428d7b3dSmrg			ximage_prepare(&c->image, clip->width, clip->height);
1775428d7b3dSmrg			XShmGetImage(c->src.dpy, c->src.pixmap, &c->image,
1776428d7b3dSmrg				     clip->x, clip->y, AllPlanes);
1777428d7b3dSmrg		} else {
1778428d7b3dSmrg			ximage_prepare(&c->image, c->width, c->height);
1779428d7b3dSmrg			XGetSubImage(c->src.dpy, c->src.pixmap,
1780428d7b3dSmrg				     clip->x, clip->y, clip->width, clip->height,
1781428d7b3dSmrg				     AllPlanes, ZPixmap,
1782428d7b3dSmrg				     &c->image, 0, 0);
1783428d7b3dSmrg		}
1784428d7b3dSmrg	} else if (c->src.pixmap) {
1785428d7b3dSmrg		XCopyArea(c->src.dpy, c->src.window, c->src.pixmap, c->src.gc,
1786428d7b3dSmrg			  clip->x, clip->y,
1787428d7b3dSmrg			  clip->width, clip->height,
1788428d7b3dSmrg			  0, 0);
1789428d7b3dSmrg		XSync(c->src.dpy, False);
1790428d7b3dSmrg	} else if (c->src.use_shm) {
1791428d7b3dSmrg		ximage_prepare(&c->image, clip->width, clip->height);
1792428d7b3dSmrg		XShmGetImage(c->src.dpy, c->src.window, &c->image,
1793428d7b3dSmrg			     clip->x, clip->y, AllPlanes);
1794428d7b3dSmrg	} else {
1795428d7b3dSmrg		ximage_prepare(&c->image, c->width, c->height);
1796428d7b3dSmrg		XGetSubImage(c->src.dpy, c->src.window,
1797428d7b3dSmrg			     clip->x, clip->y, clip->width, clip->height,
1798428d7b3dSmrg			     AllPlanes, ZPixmap,
1799428d7b3dSmrg			     &c->image, 0, 0);
1800428d7b3dSmrg	}
1801428d7b3dSmrg	c->src.display->flush = 0;
1802428d7b3dSmrg}
1803428d7b3dSmrg
1804428d7b3dSmrgstatic void put_dst(struct clone *c, const XRectangle *clip)
1805428d7b3dSmrg{
1806428d7b3dSmrg	DBG(DRAW, ("%s-%s put_dst(%d,%d)x(%d,%d)\n", DisplayString(c->dst.dpy), c->dst.name,
1807428d7b3dSmrg	     clip->x, clip->y, clip->width, clip->height));
1808428d7b3dSmrg
1809428d7b3dSmrg	c->image.obdata = (char *)&c->dst.shm;
1810428d7b3dSmrg
1811428d7b3dSmrg	if (c->dst.use_render) {
1812428d7b3dSmrg		if (c->dst.use_shm_pixmap) {
1813428d7b3dSmrg			DBG(DRAW, ("%s-%s using SHM pixmap composite\n",
1814428d7b3dSmrg			     DisplayString(c->dst.dpy), c->dst.name));
1815428d7b3dSmrg		} else if (c->dst.use_shm) {
1816428d7b3dSmrg			DBG(DRAW, ("%s-%s using SHM image composite\n",
1817428d7b3dSmrg			     DisplayString(c->dst.dpy), c->dst.name));
1818428d7b3dSmrg			XShmPutImage(c->dst.dpy, c->dst.pixmap, c->dst.gc, &c->image,
1819428d7b3dSmrg				     0, 0,
1820428d7b3dSmrg				     0, 0,
1821428d7b3dSmrg				     clip->width, clip->height,
1822428d7b3dSmrg				     False);
1823428d7b3dSmrg		} else {
1824428d7b3dSmrg			DBG(DRAW, ("%s-%s using composite\n",
1825428d7b3dSmrg			     DisplayString(c->dst.dpy), c->dst.name));
1826428d7b3dSmrg			XPutImage(c->dst.dpy, c->dst.pixmap, c->dst.gc, &c->image,
1827428d7b3dSmrg				  0, 0,
1828428d7b3dSmrg				  0, 0,
1829428d7b3dSmrg				  clip->width, clip->height);
1830428d7b3dSmrg		}
1831428d7b3dSmrg		if (c->dst.use_shm)
1832428d7b3dSmrg			c->dst.serial = NextRequest(c->dst.dpy);
1833428d7b3dSmrg		XRenderComposite(c->dst.dpy, PictOpSrc,
1834428d7b3dSmrg				 c->dst.pix_picture, 0, c->dst.win_picture,
1835428d7b3dSmrg				 0, 0,
1836428d7b3dSmrg				 0, 0,
1837428d7b3dSmrg				 clip->x, clip->y,
1838428d7b3dSmrg				 clip->width, clip->height);
1839428d7b3dSmrg		c->dst.display->send |= c->dst.use_shm;
1840428d7b3dSmrg	} else if (c->dst.pixmap) {
1841428d7b3dSmrg		DBG(DRAW, ("%s-%s using SHM pixmap\n",
1842428d7b3dSmrg		     DisplayString(c->dst.dpy), c->dst.name));
1843428d7b3dSmrg		c->dst.serial = NextRequest(c->dst.dpy);
1844428d7b3dSmrg		XCopyArea(c->dst.dpy, c->dst.pixmap, c->dst.window, c->dst.gc,
1845428d7b3dSmrg			  0, 0,
1846428d7b3dSmrg			  clip->width, clip->height,
1847428d7b3dSmrg			  clip->x, clip->y);
1848428d7b3dSmrg		c->dst.display->send = 1;
1849428d7b3dSmrg	} else if (c->dst.use_shm) {
1850428d7b3dSmrg		DBG(DRAW, ("%s-%s using SHM image\n",
1851428d7b3dSmrg		     DisplayString(c->dst.dpy), c->dst.name));
1852428d7b3dSmrg		c->dst.serial = NextRequest(c->dst.dpy);
1853428d7b3dSmrg		XShmPutImage(c->dst.dpy, c->dst.window, c->dst.gc, &c->image,
1854428d7b3dSmrg			     0, 0,
1855428d7b3dSmrg			     clip->x, clip->y,
1856428d7b3dSmrg			     clip->width, clip->height,
1857428d7b3dSmrg			     True);
1858428d7b3dSmrg	} else {
1859428d7b3dSmrg		DBG(DRAW, ("%s-%s using image\n",
1860428d7b3dSmrg		     DisplayString(c->dst.dpy), c->dst.name));
1861428d7b3dSmrg		XPutImage(c->dst.dpy, c->dst.window, c->dst.gc, &c->image,
1862428d7b3dSmrg			  0, 0,
1863428d7b3dSmrg			  clip->x, clip->y,
1864428d7b3dSmrg			  clip->width, clip->height);
1865428d7b3dSmrg		c->dst.serial = 0;
1866428d7b3dSmrg	}
1867428d7b3dSmrg}
1868428d7b3dSmrg
1869428d7b3dSmrgstatic int clone_paint(struct clone *c)
1870428d7b3dSmrg{
1871428d7b3dSmrg	XRectangle clip;
1872428d7b3dSmrg
1873428d7b3dSmrg	DBG(DRAW, ("%s-%s paint clone, damaged (%d, %d), (%d, %d) [(%d, %d), (%d,  %d)]\n",
1874428d7b3dSmrg	     DisplayString(c->dst.dpy), c->dst.name,
1875428d7b3dSmrg	     c->damaged.x1, c->damaged.y1,
1876428d7b3dSmrg	     c->damaged.x2, c->damaged.y2,
1877428d7b3dSmrg	     c->src.x, c->src.y,
1878428d7b3dSmrg	     c->src.x + c->width, c->src.y + c->height));
1879428d7b3dSmrg
1880428d7b3dSmrg	if (c->damaged.x1 < c->src.x)
1881428d7b3dSmrg		c->damaged.x1 = c->src.x;
1882428d7b3dSmrg	if (c->damaged.x2 > c->src.x + c->width)
1883428d7b3dSmrg		c->damaged.x2 = c->src.x + c->width;
1884428d7b3dSmrg	if (c->damaged.x2 <= c->damaged.x1)
1885428d7b3dSmrg		goto done;
1886428d7b3dSmrg
1887428d7b3dSmrg	if (c->damaged.y1 < c->src.y)
1888428d7b3dSmrg		c->damaged.y1 = c->src.y;
1889428d7b3dSmrg	if (c->damaged.y2 > c->src.y + c->height)
1890428d7b3dSmrg		c->damaged.y2 = c->src.y + c->height;
1891428d7b3dSmrg	if (c->damaged.y2 <= c->damaged.y1)
1892428d7b3dSmrg		goto done;
1893428d7b3dSmrg
1894428d7b3dSmrg	DBG(DRAW, ("%s-%s is damaged, last SHM serial: %ld, now %ld\n",
1895428d7b3dSmrg	     DisplayString(c->dst.dpy), c->dst.name,
1896428d7b3dSmrg	     (long)c->dst.serial, (long)LastKnownRequestProcessed(c->dst.dpy)));
1897428d7b3dSmrg	if (c->dst.serial > LastKnownRequestProcessed(c->dst.dpy)) {
1898428d7b3dSmrg		struct pollfd pfd;
1899428d7b3dSmrg
1900428d7b3dSmrg		pfd.fd = ConnectionNumber(c->dst.dpy);
1901428d7b3dSmrg		pfd.events = POLLIN;
1902428d7b3dSmrg		XEventsQueued(c->dst.dpy,
1903428d7b3dSmrg			      poll(&pfd, 1, 0) ? QueuedAfterReading : QueuedAfterFlush);
1904428d7b3dSmrg
1905428d7b3dSmrg		if (c->dst.serial > LastKnownRequestProcessed(c->dst.dpy)) {
1906428d7b3dSmrg			c->dst.display->skip_clone++;
1907428d7b3dSmrg			return EAGAIN;
1908428d7b3dSmrg		}
1909428d7b3dSmrg	}
1910428d7b3dSmrg
1911428d7b3dSmrg	c->dst.display->skip_clone = 0;
1912428d7b3dSmrg	c->dst.display->skip_frame = 0;
1913428d7b3dSmrg
1914428d7b3dSmrg	if (FORCE_FULL_REDRAW) {
1915428d7b3dSmrg		c->damaged.x1 = c->src.x;
1916428d7b3dSmrg		c->damaged.y1 = c->src.y;
1917428d7b3dSmrg		c->damaged.x2 = c->src.x + c->width;
1918428d7b3dSmrg		c->damaged.y2 = c->src.y + c->height;
1919428d7b3dSmrg	}
1920428d7b3dSmrg
1921428d7b3dSmrg	if (c->dri3.xid) {
1922428d7b3dSmrg		if (c->src.use_render) {
1923428d7b3dSmrg			XRenderComposite(c->src.dpy, PictOpSrc,
1924428d7b3dSmrg					 c->src.win_picture, 0, c->src.pix_picture,
1925428d7b3dSmrg					 c->damaged.x1, c->damaged.y1,
1926428d7b3dSmrg					 0, 0,
1927428d7b3dSmrg					 c->damaged.x1 + c->dst.x - c->src.x,
1928428d7b3dSmrg					 c->damaged.y1 + c->dst.y - c->src.y,
1929428d7b3dSmrg					 c->damaged.x2 - c->damaged.x1,
1930428d7b3dSmrg					 c->damaged.y2 - c->damaged.y1);
1931428d7b3dSmrg		} else {
1932428d7b3dSmrg			XCopyArea(c->src.dpy, c->src.window, c->src.pixmap, c->src.gc,
1933428d7b3dSmrg				  c->damaged.x1, c->damaged.y1,
1934428d7b3dSmrg				  c->damaged.x2 - c->damaged.x1,
1935428d7b3dSmrg				  c->damaged.y2 - c->damaged.y1,
1936428d7b3dSmrg				  c->damaged.x1 + c->dst.x - c->src.x,
1937428d7b3dSmrg				  c->damaged.y1 + c->dst.y - c->src.y);
1938428d7b3dSmrg		}
1939428d7b3dSmrg		dri3_fence_flush(c->src.dpy, &c->dri3);
1940428d7b3dSmrg	} else {
1941428d7b3dSmrg		clip.x = c->damaged.x1;
1942428d7b3dSmrg		clip.y = c->damaged.y1;
1943428d7b3dSmrg		clip.width  = c->damaged.x2 - c->damaged.x1;
1944428d7b3dSmrg		clip.height = c->damaged.y2 - c->damaged.y1;
1945428d7b3dSmrg		get_src(c, &clip);
1946428d7b3dSmrg
1947428d7b3dSmrg		clip.x += c->dst.x - c->src.x;
1948428d7b3dSmrg		clip.y += c->dst.y - c->src.y;
1949428d7b3dSmrg		put_dst(c, &clip);
1950428d7b3dSmrg	}
1951428d7b3dSmrg	display_mark_flush(c->dst.display);
1952428d7b3dSmrg
1953428d7b3dSmrgdone:
1954428d7b3dSmrg	c->damaged.x2 = c->damaged.y2 = INT_MIN;
1955428d7b3dSmrg	c->damaged.x1 = c->damaged.y1 = INT_MAX;
1956428d7b3dSmrg	return 0;
1957428d7b3dSmrg}
1958428d7b3dSmrg
1959428d7b3dSmrgstatic void clone_damage(struct clone *c, const XRectangle *rec)
1960428d7b3dSmrg{
1961428d7b3dSmrg	int v;
1962428d7b3dSmrg
1963428d7b3dSmrg	if ((v = rec->x) < c->damaged.x1)
1964428d7b3dSmrg		c->damaged.x1 = v;
1965428d7b3dSmrg	if ((v = (int)rec->x + rec->width) > c->damaged.x2)
1966428d7b3dSmrg		c->damaged.x2 = v;
1967428d7b3dSmrg	if ((v = rec->y) < c->damaged.y1)
1968428d7b3dSmrg		c->damaged.y1 = v;
1969428d7b3dSmrg	if ((v = (int)rec->y + rec->height) > c->damaged.y2)
1970428d7b3dSmrg		c->damaged.y2 = v;
1971428d7b3dSmrg
1972428d7b3dSmrg	DBG(DAMAGE, ("%s-%s damaged: (%d, %d), (%d, %d)\n",
1973428d7b3dSmrg	     DisplayString(c->dst.display->dpy), c->dst.name,
1974428d7b3dSmrg	     c->damaged.x1, c->damaged.y1,
1975428d7b3dSmrg	     c->damaged.x2, c->damaged.y2));
1976428d7b3dSmrg}
1977428d7b3dSmrg
1978428d7b3dSmrgstatic void usage(const char *arg0)
1979428d7b3dSmrg{
1980428d7b3dSmrg	printf("Usage: %s [OPTION]... [TARGET_DISPLAY]...\n", arg0);
1981428d7b3dSmrg	printf("  -d <source display>  source display\n");
1982428d7b3dSmrg	printf("  -f                   keep in foreground (do not detach from console and daemonize)\n");
1983428d7b3dSmrg	printf("  -b                   start bumblebee\n");
1984428d7b3dSmrg	printf("  -a                   connect to all local displays (e.g. :1, :2, etc)\n");
1985428d7b3dSmrg	printf("  -S                   disable use of a singleton and launch a fresh intel-virtual-output process\n");
1986428d7b3dSmrg	printf("  -v                   all verbose output, implies -f\n");
1987428d7b3dSmrg	printf("  -V <category>        specific verbose output, implies -f\n");
1988428d7b3dSmrg	printf("  -h                   this help\n");
1989428d7b3dSmrg	printf("If no target displays are parsed on the commandline, \n");
1990428d7b3dSmrg	printf("intel-virtual-output will attempt to connect to any local display\n");
1991428d7b3dSmrg	printf("and then start bumblebee.\n");
1992428d7b3dSmrg}
1993428d7b3dSmrg
1994428d7b3dSmrgstatic void record_callback(XPointer closure, XRecordInterceptData *data)
1995428d7b3dSmrg{
1996428d7b3dSmrg	struct context *ctx = (struct context *)closure;
1997428d7b3dSmrg
1998428d7b3dSmrg	DBG(X11, ("%s\n", __func__));
1999428d7b3dSmrg
2000428d7b3dSmrg	if (data->category == XRecordFromServer) {
2001428d7b3dSmrg		const xEvent *e = (const xEvent *)data->data;
2002428d7b3dSmrg
2003428d7b3dSmrg		DBG(X11, ("%s -- from server, event type %d, root %ld (ours? %d)\n",
2004428d7b3dSmrg		     __func__, e->u.u.type, (long)e->u.keyButtonPointer.root,
2005428d7b3dSmrg		     ctx->display->root == e->u.keyButtonPointer.root));
2006428d7b3dSmrg
2007428d7b3dSmrg		if (e->u.u.type == MotionNotify &&
2008428d7b3dSmrg		    e->u.keyButtonPointer.root == ctx->display->root) {
2009428d7b3dSmrg			struct clone *clone;
2010428d7b3dSmrg
2011428d7b3dSmrg			for (clone = ctx->active; clone; clone = clone->active)
2012428d7b3dSmrg				clone_move_cursor(clone,
2013428d7b3dSmrg						  e->u.keyButtonPointer.rootX,
2014428d7b3dSmrg						  e->u.keyButtonPointer.rootY);
2015428d7b3dSmrg		}
2016428d7b3dSmrg	}
2017428d7b3dSmrg
2018428d7b3dSmrg	XRecordFreeData(data);
2019428d7b3dSmrg}
2020428d7b3dSmrg
2021428d7b3dSmrgstatic int record_mouse(struct context *ctx)
2022428d7b3dSmrg{
2023428d7b3dSmrg	Display *dpy;
2024428d7b3dSmrg	XRecordRange *rr;
2025428d7b3dSmrg	XRecordClientSpec rcs;
2026428d7b3dSmrg	XRecordContext rc;
2027428d7b3dSmrg
2028428d7b3dSmrg	DBG(X11, ("%s(%s)\n", __func__, DisplayString(ctx->display->dpy)));
2029428d7b3dSmrg
2030428d7b3dSmrg	dpy = XOpenDisplay(DisplayString(ctx->display->dpy));
2031428d7b3dSmrg	if (dpy == NULL)
2032428d7b3dSmrg		return -ECONNREFUSED;
2033428d7b3dSmrg
2034428d7b3dSmrg	rr = XRecordAllocRange();
2035428d7b3dSmrg	if (rr == NULL)
2036428d7b3dSmrg		return -ENOMEM;
2037428d7b3dSmrg
2038428d7b3dSmrg	rr->device_events.first = rr->device_events.last = MotionNotify;
2039428d7b3dSmrg
2040428d7b3dSmrg	rcs = XRecordAllClients;
2041428d7b3dSmrg	rc = XRecordCreateContext(dpy, 0, &rcs, 1, &rr, 1);
2042428d7b3dSmrg
2043428d7b3dSmrg	XSync(dpy, False);
2044428d7b3dSmrg
2045428d7b3dSmrg	if (!XRecordEnableContextAsync(dpy, rc, record_callback, (XPointer)ctx))
2046428d7b3dSmrg		return -EINVAL;
2047428d7b3dSmrg
2048428d7b3dSmrg	ctx->record = dpy;
2049428d7b3dSmrg	return ConnectionNumber(dpy);
2050428d7b3dSmrg}
2051428d7b3dSmrg
2052428d7b3dSmrgstatic int bad_visual(Visual *visual, int depth)
2053428d7b3dSmrg{
2054428d7b3dSmrg	DBG(X11, ("%s? depth=%d, visual: class=%d, bits_per_rgb=%d, red_mask=%08lx, green_mask=%08lx, blue_mask=%08lx\n",
2055428d7b3dSmrg	     __func__, depth,
2056428d7b3dSmrg	     visual->class,
2057428d7b3dSmrg	     visual->bits_per_rgb,
2058428d7b3dSmrg	     visual->red_mask,
2059428d7b3dSmrg	     visual->green_mask,
2060428d7b3dSmrg	     visual->blue_mask));
2061428d7b3dSmrg
2062428d7b3dSmrg	if (!(visual->class == TrueColor || visual->class == DirectColor))
2063428d7b3dSmrg		return 1;
2064428d7b3dSmrg
2065428d7b3dSmrg	switch (depth) {
2066428d7b3dSmrg	case 16: return (/* visual->bits_per_rgb != 6          || */
2067428d7b3dSmrg			 visual->red_mask     != 0x1f << 11 ||
2068428d7b3dSmrg			 visual->green_mask   != 0x3f << 5  ||
2069428d7b3dSmrg			 visual->blue_mask    != 0x1f << 0);
2070428d7b3dSmrg
2071428d7b3dSmrg	case 24: return (/* visual->bits_per_rgb != 8          || */
2072428d7b3dSmrg			 visual->red_mask     != 0xff << 16 ||
2073428d7b3dSmrg			 visual->green_mask   != 0xff << 8  ||
2074428d7b3dSmrg			 visual->blue_mask    != 0xff << 0);
2075428d7b3dSmrg
2076428d7b3dSmrg	default: return 1;
2077428d7b3dSmrg	}
2078428d7b3dSmrg}
2079428d7b3dSmrg
2080428d7b3dSmrgstatic XRenderPictFormat *
2081428d7b3dSmrgfind_xrender_format(Display *dpy, pixman_format_code_t format)
2082428d7b3dSmrg{
2083428d7b3dSmrg    XRenderPictFormat tmpl;
2084428d7b3dSmrg    int mask;
2085428d7b3dSmrg
2086428d7b3dSmrg#define MASK(x) ((1<<(x))-1)
2087428d7b3dSmrg
2088428d7b3dSmrg    memset(&tmpl, 0, sizeof(tmpl));
2089428d7b3dSmrg
2090428d7b3dSmrg    tmpl.depth = PIXMAN_FORMAT_DEPTH(format);
2091428d7b3dSmrg    mask = PictFormatType | PictFormatDepth;
2092428d7b3dSmrg
2093428d7b3dSmrg    DBG(X11, ("%s(0x%08lx)\n", __func__, (long)format));
2094428d7b3dSmrg
2095428d7b3dSmrg    switch (PIXMAN_FORMAT_TYPE(format)) {
2096428d7b3dSmrg    case PIXMAN_TYPE_ARGB:
2097428d7b3dSmrg	tmpl.type = PictTypeDirect;
2098428d7b3dSmrg
2099428d7b3dSmrg	if (PIXMAN_FORMAT_A(format)) {
2100428d7b3dSmrg		tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
2101428d7b3dSmrg		tmpl.direct.alpha = (PIXMAN_FORMAT_R(format) +
2102428d7b3dSmrg				     PIXMAN_FORMAT_G(format) +
2103428d7b3dSmrg				     PIXMAN_FORMAT_B(format));
2104428d7b3dSmrg	}
2105428d7b3dSmrg
2106428d7b3dSmrg	tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
2107428d7b3dSmrg	tmpl.direct.red = (PIXMAN_FORMAT_G(format) +
2108428d7b3dSmrg			   PIXMAN_FORMAT_B(format));
2109428d7b3dSmrg
2110428d7b3dSmrg	tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
2111428d7b3dSmrg	tmpl.direct.green = PIXMAN_FORMAT_B(format);
2112428d7b3dSmrg
2113428d7b3dSmrg	tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
2114428d7b3dSmrg	tmpl.direct.blue = 0;
2115428d7b3dSmrg
2116428d7b3dSmrg	mask |= PictFormatRed | PictFormatRedMask;
2117428d7b3dSmrg	mask |= PictFormatGreen | PictFormatGreenMask;
2118428d7b3dSmrg	mask |= PictFormatBlue | PictFormatBlueMask;
2119428d7b3dSmrg	mask |= PictFormatAlpha | PictFormatAlphaMask;
2120428d7b3dSmrg	break;
2121428d7b3dSmrg
2122428d7b3dSmrg    case PIXMAN_TYPE_ABGR:
2123428d7b3dSmrg	tmpl.type = PictTypeDirect;
2124428d7b3dSmrg
2125428d7b3dSmrg	if (tmpl.direct.alphaMask) {
2126428d7b3dSmrg		tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
2127428d7b3dSmrg		tmpl.direct.alpha = (PIXMAN_FORMAT_B(format) +
2128428d7b3dSmrg				     PIXMAN_FORMAT_G(format) +
2129428d7b3dSmrg				     PIXMAN_FORMAT_R(format));
2130428d7b3dSmrg	}
2131428d7b3dSmrg
2132428d7b3dSmrg	tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
2133428d7b3dSmrg	tmpl.direct.blue = (PIXMAN_FORMAT_G(format) +
2134428d7b3dSmrg			    PIXMAN_FORMAT_R(format));
2135428d7b3dSmrg
2136428d7b3dSmrg	tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
2137428d7b3dSmrg	tmpl.direct.green = PIXMAN_FORMAT_R(format);
2138428d7b3dSmrg
2139428d7b3dSmrg	tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
2140428d7b3dSmrg	tmpl.direct.red = 0;
2141428d7b3dSmrg
2142428d7b3dSmrg	mask |= PictFormatRed | PictFormatRedMask;
2143428d7b3dSmrg	mask |= PictFormatGreen | PictFormatGreenMask;
2144428d7b3dSmrg	mask |= PictFormatBlue | PictFormatBlueMask;
2145428d7b3dSmrg	mask |= PictFormatAlpha | PictFormatAlphaMask;
2146428d7b3dSmrg	break;
2147428d7b3dSmrg
2148428d7b3dSmrg    case PIXMAN_TYPE_BGRA:
2149428d7b3dSmrg	tmpl.type = PictTypeDirect;
2150428d7b3dSmrg
2151428d7b3dSmrg	tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
2152428d7b3dSmrg	tmpl.direct.blue = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format));
2153428d7b3dSmrg
2154428d7b3dSmrg	tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
2155428d7b3dSmrg	tmpl.direct.green = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) -
2156428d7b3dSmrg			     PIXMAN_FORMAT_G(format));
2157428d7b3dSmrg
2158428d7b3dSmrg	tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
2159428d7b3dSmrg	tmpl.direct.red = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) -
2160428d7b3dSmrg			   PIXMAN_FORMAT_G(format) - PIXMAN_FORMAT_R(format));
2161428d7b3dSmrg
2162428d7b3dSmrg	if (tmpl.direct.alphaMask) {
2163428d7b3dSmrg		tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
2164428d7b3dSmrg		tmpl.direct.alpha = 0;
2165428d7b3dSmrg	}
2166428d7b3dSmrg
2167428d7b3dSmrg	mask |= PictFormatRed | PictFormatRedMask;
2168428d7b3dSmrg	mask |= PictFormatGreen | PictFormatGreenMask;
2169428d7b3dSmrg	mask |= PictFormatBlue | PictFormatBlueMask;
2170428d7b3dSmrg	mask |= PictFormatAlpha | PictFormatAlphaMask;
2171428d7b3dSmrg	break;
2172428d7b3dSmrg
2173428d7b3dSmrg    case PIXMAN_TYPE_A:
2174428d7b3dSmrg	tmpl.type = PictTypeDirect;
2175428d7b3dSmrg
2176428d7b3dSmrg	tmpl.direct.alpha = 0;
2177428d7b3dSmrg	tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
2178428d7b3dSmrg
2179428d7b3dSmrg	mask |= PictFormatAlpha | PictFormatAlphaMask;
2180428d7b3dSmrg	break;
2181428d7b3dSmrg
2182428d7b3dSmrg    case PIXMAN_TYPE_COLOR:
2183428d7b3dSmrg    case PIXMAN_TYPE_GRAY:
2184428d7b3dSmrg	/* XXX Find matching visual/colormap */
2185428d7b3dSmrg	tmpl.type = PictTypeIndexed;
2186428d7b3dSmrg	//tmpl.colormap = screen->visuals[PIXMAN_FORMAT_VIS(format)].vid;
2187428d7b3dSmrg	//mask |= PictFormatColormap;
2188428d7b3dSmrg	return NULL;
2189428d7b3dSmrg    }
2190428d7b3dSmrg#undef MASK
2191428d7b3dSmrg
2192428d7b3dSmrg    return XRenderFindFormat(dpy, mask, &tmpl, 0);
2193428d7b3dSmrg}
2194428d7b3dSmrg
2195428d7b3dSmrgstatic int display_init_render(struct display *display, int depth, XRenderPictFormat **use_render)
2196428d7b3dSmrg{
2197428d7b3dSmrg	Display *dpy = display->dpy;
2198428d7b3dSmrg	int major, minor;
2199428d7b3dSmrg
2200428d7b3dSmrg	DBG(X11, ("%s is depth %d, want %d\n", DisplayString(dpy), display->depth, depth));
2201428d7b3dSmrg
2202428d7b3dSmrg	*use_render = 0;
2203428d7b3dSmrg	if (depth == display->depth && !bad_visual(display->visual, depth))
2204428d7b3dSmrg		return 0;
2205428d7b3dSmrg
2206428d7b3dSmrg	if (display->root_format == 0) {
2207428d7b3dSmrg		if (!XRenderQueryVersion(dpy, &major, &minor)) {
2208428d7b3dSmrg			fprintf(stderr, "Render extension not supported by %s\n", DisplayString(dpy));
2209428d7b3dSmrg			return -EINVAL;
2210428d7b3dSmrg		}
2211428d7b3dSmrg
2212428d7b3dSmrg		display->root_format = XRenderFindVisualFormat(dpy, display->visual);
2213428d7b3dSmrg		display->rgb16_format = find_xrender_format(dpy, PIXMAN_r5g6b5);
2214428d7b3dSmrg		display->rgb24_format = XRenderFindStandardFormat(dpy, PictStandardRGB24);
2215428d7b3dSmrg
2216428d7b3dSmrg		DBG(X11, ("%s: root format=%lx, rgb16 format=%lx, rgb24 format=%lx\n",
2217428d7b3dSmrg		     DisplayString(dpy),
2218428d7b3dSmrg		     (long)display->root_format,
2219428d7b3dSmrg		     (long)display->rgb16_format,
2220428d7b3dSmrg		     (long)display->rgb24_format));
2221428d7b3dSmrg	}
2222428d7b3dSmrg
2223428d7b3dSmrg	switch (depth) {
2224428d7b3dSmrg	case 16: *use_render = display->rgb16_format; break;
2225428d7b3dSmrg	case 24: *use_render = display->rgb24_format; break;
2226428d7b3dSmrg	}
2227428d7b3dSmrg	if (*use_render == 0)
2228428d7b3dSmrg		return -ENOENT;
2229428d7b3dSmrg
2230428d7b3dSmrg	return 0;
2231428d7b3dSmrg}
2232428d7b3dSmrg
2233428d7b3dSmrgstatic int clone_init_depth(struct clone *clone)
2234428d7b3dSmrg{
2235428d7b3dSmrg	int ret, depth;
2236428d7b3dSmrg
2237428d7b3dSmrg	DBG(X11,("%s-%s wants depth %d\n",
2238428d7b3dSmrg	     DisplayString(clone->dst.dpy), clone->dst.name, clone->depth));
2239428d7b3dSmrg
2240428d7b3dSmrg	ret = -1;
2241428d7b3dSmrg	for (depth = clone->depth; depth <= 24; depth += 8) {
2242428d7b3dSmrg		ret = display_init_render(clone->src.display, depth, &clone->src.use_render);
2243428d7b3dSmrg		if (ret)
2244428d7b3dSmrg			continue;
2245428d7b3dSmrg
2246428d7b3dSmrg		ret = display_init_render(clone->dst.display, depth, &clone->dst.use_render);
2247428d7b3dSmrg		if (ret)
2248428d7b3dSmrg			continue;
2249428d7b3dSmrg
2250428d7b3dSmrg		break;
2251428d7b3dSmrg	}
2252428d7b3dSmrg	if (ret)
2253428d7b3dSmrg		return ret;
2254428d7b3dSmrg
2255428d7b3dSmrg	DBG(X11, ("%s-%s using depth %d, requires xrender for src? %d, for dst? %d\n",
2256428d7b3dSmrg	     DisplayString(clone->dst.dpy), clone->dst.name,
2257428d7b3dSmrg	     clone->depth,
2258428d7b3dSmrg	     clone->src.use_render != NULL,
2259428d7b3dSmrg	     clone->dst.use_render != NULL));
2260428d7b3dSmrg
2261428d7b3dSmrg	if (!clone->dst.use_render &&
2262428d7b3dSmrg	    clone->src.display->dri3_active &&
2263428d7b3dSmrg	    clone->dst.display->dri3_active)
2264428d7b3dSmrg		dri3_create_fence(clone->src.dpy, clone->src.window, &clone->dri3);
2265428d7b3dSmrg
2266428d7b3dSmrg	return 0;
2267428d7b3dSmrg}
2268428d7b3dSmrg
2269428d7b3dSmrg#if defined(USE_XINERAMA)
2270428d7b3dSmrgstatic int xinerama_active(struct display *display)
2271428d7b3dSmrg{
2272428d7b3dSmrg	int active = 0;
2273428d7b3dSmrg	if (XineramaQueryExtension(display->dpy, &display->xinerama_event, &display->xinerama_error))
2274428d7b3dSmrg		active = XineramaIsActive(display->dpy);
2275428d7b3dSmrg	return active;
2276428d7b3dSmrg}
2277428d7b3dSmrg#else
2278428d7b3dSmrg#define xinerama_active(d) 0
2279428d7b3dSmrg#endif
2280428d7b3dSmrg
2281428d7b3dSmrgstatic int add_display(struct context *ctx, Display *dpy)
2282428d7b3dSmrg{
2283428d7b3dSmrg	struct display *display;
2284428d7b3dSmrg	int first_display = ctx->ndisplay == 0;
2285428d7b3dSmrg
2286428d7b3dSmrg	if (is_power_of_2(ctx->ndisplay)) {
2287428d7b3dSmrg		struct display *new_display;
2288428d7b3dSmrg
2289428d7b3dSmrg		new_display = realloc(ctx->display, 2*ctx->ndisplay*sizeof(struct display));
2290428d7b3dSmrg		if (new_display == NULL)
2291428d7b3dSmrg			return -ENOMEM;
2292428d7b3dSmrg
2293428d7b3dSmrg		if (new_display != ctx->display) {
2294428d7b3dSmrg			int n;
2295428d7b3dSmrg
2296428d7b3dSmrg			for (n = 0; n < ctx->nclone; n++) {
2297428d7b3dSmrg				struct clone *clone = &ctx->clones[n];
2298428d7b3dSmrg				clone->src.display = new_display + (clone->src.display - ctx->display);
2299428d7b3dSmrg				clone->dst.display = new_display + (clone->dst.display - ctx->display);
2300428d7b3dSmrg			}
2301428d7b3dSmrg		}
2302428d7b3dSmrg
2303428d7b3dSmrg		ctx->display = new_display;
2304428d7b3dSmrg	}
2305428d7b3dSmrg
2306428d7b3dSmrg	display = memset(&ctx->display[ctx->ndisplay++], 0, sizeof(struct display));
2307428d7b3dSmrg
2308428d7b3dSmrg	display->dpy = dpy;
2309428d7b3dSmrg	display->ctx = ctx;
2310428d7b3dSmrg
2311428d7b3dSmrg	display->root = DefaultRootWindow(dpy);
2312428d7b3dSmrg	display->depth = DefaultDepth(dpy, DefaultScreen(dpy));
2313428d7b3dSmrg	display->visual = DefaultVisual(dpy, DefaultScreen(dpy));
2314428d7b3dSmrg
2315428d7b3dSmrg	display->has_shm = can_use_shm(dpy, display->root,
2316428d7b3dSmrg				       &display->shm_event,
2317428d7b3dSmrg				       &display->shm_opcode,
2318428d7b3dSmrg				       &display->has_shm_pixmap);
2319428d7b3dSmrg	DBG(X11, ("%s: has_shm?=%d, event=%d, opcode=%d, has_pixmap?=%d\n",
2320428d7b3dSmrg	     DisplayString(dpy),
2321428d7b3dSmrg	     display->has_shm,
2322428d7b3dSmrg	     display->shm_event,
2323428d7b3dSmrg	     display->shm_opcode,
2324428d7b3dSmrg	     display->has_shm_pixmap));
2325428d7b3dSmrg
2326428d7b3dSmrg	display->rr_active = XRRQueryExtension(dpy, &display->rr_event, &display->rr_error);
2327428d7b3dSmrg	DBG(X11, ("%s: randr_active?=%d, event=%d, error=%d\n",
2328428d7b3dSmrg	     DisplayString(dpy),
2329428d7b3dSmrg	     display->rr_active,
2330428d7b3dSmrg	     display->rr_event,
2331428d7b3dSmrg	     display->rr_error));
2332428d7b3dSmrg
2333428d7b3dSmrg	display->xinerama_active = xinerama_active(display);
2334428d7b3dSmrg	DBG(X11, ("%s: xinerama_active?=%d, event=%d, error=%d\n",
2335428d7b3dSmrg	     DisplayString(dpy),
2336428d7b3dSmrg	     display->xinerama_active,
2337428d7b3dSmrg	     display->xinerama_event,
2338428d7b3dSmrg	     display->xinerama_error));
2339428d7b3dSmrg
2340428d7b3dSmrg	display->dri3_active = dri3_exists(dpy);
2341428d7b3dSmrg	DBG(X11, ("%s: dri3_active?=%d\n",
2342428d7b3dSmrg	     DisplayString(dpy),
2343428d7b3dSmrg	     display->dri3_active));
2344428d7b3dSmrg
2345428d7b3dSmrg	/* first display (source) is slightly special */
2346428d7b3dSmrg	if (!first_display) {
2347428d7b3dSmrg		display->invisible_cursor = display_load_invisible_cursor(display);
2348428d7b3dSmrg		display_cursor_move(display, 0, 0, 0);
2349428d7b3dSmrg	}
2350428d7b3dSmrg
2351428d7b3dSmrg	return ConnectionNumber(dpy);
2352428d7b3dSmrg}
2353428d7b3dSmrg
2354428d7b3dSmrgstatic int display_open(struct context *ctx, const char *name)
2355428d7b3dSmrg{
2356428d7b3dSmrg	Display *dpy;
2357428d7b3dSmrg	int n;
2358428d7b3dSmrg
2359428d7b3dSmrg	DBG(X11, ("%s(%s)\n", __func__, name));
2360428d7b3dSmrg
2361428d7b3dSmrg	dpy = XOpenDisplay(name);
2362428d7b3dSmrg	if (dpy == NULL)
2363428d7b3dSmrg		return -ECONNREFUSED;
2364428d7b3dSmrg
2365428d7b3dSmrg	/* Prevent cloning the same display twice */
2366428d7b3dSmrg	for (n = 0; n < ctx->ndisplay; n++) {
2367428d7b3dSmrg		if (strcmp(DisplayString(dpy), DisplayString(ctx->display[n].dpy)) == 0) {
2368428d7b3dSmrg			DBG(X11, ("%s %s is already connected\n", __func__, name));
2369428d7b3dSmrg			XCloseDisplay(dpy);
2370428d7b3dSmrg			return -EBUSY;
2371428d7b3dSmrg		}
2372428d7b3dSmrg	}
2373428d7b3dSmrg
2374428d7b3dSmrg	return add_display(ctx, dpy);
2375428d7b3dSmrg}
2376428d7b3dSmrg
2377428d7b3dSmrgstatic int bumblebee_open(struct context *ctx)
2378428d7b3dSmrg{
2379428d7b3dSmrg	char buf[256];
2380428d7b3dSmrg	struct sockaddr_un addr;
2381428d7b3dSmrg	int fd, len;
2382428d7b3dSmrg
2383428d7b3dSmrg	fd = socket(PF_UNIX, SOCK_STREAM, 0);
2384428d7b3dSmrg	if (fd < 0) {
2385428d7b3dSmrg		DBG(X11, ("%s unable to create a socket: %d\n", __func__, errno));
2386428d7b3dSmrg		return -ECONNREFUSED;
2387428d7b3dSmrg	}
2388428d7b3dSmrg
2389428d7b3dSmrg	addr.sun_family = AF_UNIX;
2390428d7b3dSmrg	snprintf(addr.sun_path, sizeof(addr.sun_path), "%s",
2391428d7b3dSmrg		 optarg && *optarg ? optarg : "/var/run/bumblebee.socket");
2392428d7b3dSmrg	if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
2393428d7b3dSmrg		DBG(X11, ("%s unable to create a socket: %d\n", __func__, errno));
2394428d7b3dSmrg		goto err;
2395428d7b3dSmrg	}
2396428d7b3dSmrg
2397428d7b3dSmrg	/* Ask bumblebee to start the second server */
2398428d7b3dSmrg	buf[0] = 'C';
2399428d7b3dSmrg	if (send(fd, &buf, 1, 0) != 1 || (len = recv(fd, &buf, 255, 0)) <= 0) {
2400428d7b3dSmrg		DBG(X11, ("%s startup send/recv failed: %d\n", __func__, errno));
2401428d7b3dSmrg		goto err;
2402428d7b3dSmrg	}
2403428d7b3dSmrg	buf[len] = '\0';
2404428d7b3dSmrg
2405428d7b3dSmrg	/* Query the display name */
2406428d7b3dSmrg	strcpy(buf, "Q VirtualDisplay");
2407428d7b3dSmrg	if (send(fd, buf, 17, 0) != 17 || (len = recv(fd, buf, 255, 0)) <= 0) {
2408428d7b3dSmrg		DBG(X11, ("%s query send/recv failed: %d\n", __func__, errno));
2409428d7b3dSmrg		goto err;
2410428d7b3dSmrg	}
2411428d7b3dSmrg	buf[len] = '\0';
2412428d7b3dSmrg
2413428d7b3dSmrg	DBG(X11, ("%s query result '%s'\n", __func__, buf));
2414428d7b3dSmrg
2415428d7b3dSmrg	if (strncmp(buf, "Value: ", 7))
2416428d7b3dSmrg		goto err;
2417428d7b3dSmrg
2418428d7b3dSmrg	len = 7;
2419428d7b3dSmrg	while (buf[len] != '\n' && buf[len] != '\0')
2420428d7b3dSmrg		len++;
2421428d7b3dSmrg	buf[len] = '\0';
2422428d7b3dSmrg
2423428d7b3dSmrg	/* XXX We must keep the control socket open whilst we want to keep
2424428d7b3dSmrg	 * the display around.
2425428d7b3dSmrg	 *
2426428d7b3dSmrg	 * So what we need to do is listen for new bumblee Xservers and
2427428d7b3dSmrg	 * bind only for their duration.
2428428d7b3dSmrg	 */
2429428d7b3dSmrg
2430428d7b3dSmrg	return display_open(ctx, buf+7);
2431428d7b3dSmrg
2432428d7b3dSmrgerr:
2433428d7b3dSmrg	close(fd);
2434428d7b3dSmrg	return -ECONNREFUSED;
2435428d7b3dSmrg}
2436428d7b3dSmrg
2437428d7b3dSmrgstatic int display_init_damage(struct display *display)
2438428d7b3dSmrg{
2439428d7b3dSmrg	DBG(X11, ("%s(%s)\n", __func__, DisplayString(display->dpy)));
2440428d7b3dSmrg
2441428d7b3dSmrg	if (!XDamageQueryExtension(display->dpy, &display->damage_event, &display->damage_error) ||
2442428d7b3dSmrg	    !XFixesQueryExtension(display->dpy, &display->xfixes_event, &display->xfixes_error)) {
2443428d7b3dSmrg		fprintf(stderr, "Damage/Fixes extension not supported by %s\n", DisplayString(display->dpy));
2444428d7b3dSmrg		return EINVAL;
2445428d7b3dSmrg	}
2446428d7b3dSmrg
2447428d7b3dSmrg	display->damage = XDamageCreate(display->dpy, display->root, XDamageReportBoundingBox);
2448428d7b3dSmrg	if (display->damage == 0)
2449428d7b3dSmrg		return EACCES;
2450428d7b3dSmrg
2451428d7b3dSmrg	return 0;
2452428d7b3dSmrg}
2453428d7b3dSmrg
2454428d7b3dSmrgstatic void display_reset_damage(struct display *display)
2455428d7b3dSmrg{
2456428d7b3dSmrg	Damage damage;
2457428d7b3dSmrg
2458428d7b3dSmrg	damage = XDamageCreate(display->dpy, display->root, XDamageReportBoundingBox);
2459428d7b3dSmrg	if (damage) {
2460428d7b3dSmrg		XDamageDestroy(display->dpy, display->damage);
2461428d7b3dSmrg		display->damage = damage;
2462428d7b3dSmrg		XFlush(display->dpy);
2463428d7b3dSmrg		display->flush = 0;
2464428d7b3dSmrg	}
2465428d7b3dSmrg}
2466428d7b3dSmrg
2467428d7b3dSmrgstatic void display_init_randr_hpd(struct display *display)
2468428d7b3dSmrg{
2469428d7b3dSmrg	int major, minor;
2470428d7b3dSmrg
2471428d7b3dSmrg	DBG(X11,("%s(%s)\n", __func__, DisplayString(display->dpy)));
2472428d7b3dSmrg
2473428d7b3dSmrg	if (!XRRQueryVersion(display->dpy, &major, &minor))
2474428d7b3dSmrg		return;
2475428d7b3dSmrg
2476428d7b3dSmrg	DBG(X11, ("%s - randr version %d.%d\n", DisplayString(display->dpy), major, minor));
2477428d7b3dSmrg	if (major > 1 || (major == 1 && minor >= 2))
2478428d7b3dSmrg		XRRSelectInput(display->dpy, display->root, RROutputChangeNotifyMask);
2479428d7b3dSmrg}
2480428d7b3dSmrg
2481428d7b3dSmrgstatic void rebuild_clones(struct context *ctx, struct clone *new_clones)
2482428d7b3dSmrg{
2483428d7b3dSmrg	int n, m;
2484428d7b3dSmrg
2485428d7b3dSmrg	for (n = 1; n < ctx->ndisplay; n++) {
2486428d7b3dSmrg		struct display *d = &ctx->display[n];
2487428d7b3dSmrg
2488428d7b3dSmrg		d->clone = NULL;
2489428d7b3dSmrg		for (m = 0; m < ctx->nclone; m++) {
2490428d7b3dSmrg			struct clone *c = &new_clones[m];
2491428d7b3dSmrg
2492428d7b3dSmrg			if (c->dst.display != d)
2493428d7b3dSmrg				continue;
2494428d7b3dSmrg
2495428d7b3dSmrg			c->next = d->clone;
2496428d7b3dSmrg			d->clone = c;
2497428d7b3dSmrg		}
2498428d7b3dSmrg	}
2499428d7b3dSmrg
2500428d7b3dSmrg	ctx->clones = new_clones;
2501428d7b3dSmrg}
2502428d7b3dSmrg
2503428d7b3dSmrgstatic struct clone *add_clone(struct context *ctx)
2504428d7b3dSmrg{
2505428d7b3dSmrg	if (is_power_of_2(ctx->nclone)) {
2506428d7b3dSmrg		struct clone *new_clones;
2507428d7b3dSmrg
2508428d7b3dSmrg		new_clones = realloc(ctx->clones, 2*ctx->nclone*sizeof(struct clone));
2509428d7b3dSmrg		if (new_clones == NULL)
2510428d7b3dSmrg			return NULL;
2511428d7b3dSmrg
2512428d7b3dSmrg		if (new_clones != ctx->clones)
2513428d7b3dSmrg			rebuild_clones(ctx, new_clones);
2514428d7b3dSmrg	}
2515428d7b3dSmrg
2516428d7b3dSmrg	return memset(&ctx->clones[ctx->nclone++], 0, sizeof(struct clone));
2517428d7b3dSmrg}
2518428d7b3dSmrg
2519428d7b3dSmrgstatic struct display *last_display(struct context *ctx)
2520428d7b3dSmrg{
2521428d7b3dSmrg	return &ctx->display[ctx->ndisplay-1];
2522428d7b3dSmrg}
2523428d7b3dSmrg
2524428d7b3dSmrgstatic void reverse_clone_list(struct display *display)
2525428d7b3dSmrg{
2526428d7b3dSmrg	struct clone *list = NULL;
2527428d7b3dSmrg
2528428d7b3dSmrg	while (display->clone) {
2529428d7b3dSmrg		struct clone *clone = display->clone;
2530428d7b3dSmrg		display->clone = clone->next;
2531428d7b3dSmrg		clone->next = list;
2532428d7b3dSmrg		list = clone;
2533428d7b3dSmrg	}
2534428d7b3dSmrg
2535428d7b3dSmrg	display->clone = list;
2536428d7b3dSmrg}
2537428d7b3dSmrg
2538428d7b3dSmrgstatic int last_display_add_clones__randr(struct context *ctx)
2539428d7b3dSmrg{
2540428d7b3dSmrg	struct display *display = last_display(ctx);
2541428d7b3dSmrg	XRRScreenResources *res;
2542428d7b3dSmrg	char buf[80];
2543428d7b3dSmrg	int i, ret;
2544428d7b3dSmrg
2545428d7b3dSmrg	DBG(X11, ("%s(%s)\n", __func__, DisplayString(display->dpy)));
2546428d7b3dSmrg
2547428d7b3dSmrg	display_init_randr_hpd(display);
2548428d7b3dSmrg
2549428d7b3dSmrg	/* Force a probe of outputs on initial connection */
2550428d7b3dSmrg	res = XRRGetScreenResources(display->dpy, display->root);
2551428d7b3dSmrg	if (res == NULL)
2552428d7b3dSmrg		return -ENOMEM;
2553428d7b3dSmrg
2554428d7b3dSmrg	DBG(X11, ("%s - noutputs=%d\n", DisplayString(display->dpy), res->noutput));
2555428d7b3dSmrg	for (i = 0; i < res->noutput; i++) {
2556428d7b3dSmrg		XRROutputInfo *o = XRRGetOutputInfo(display->dpy, res, res->outputs[i]);
2557428d7b3dSmrg		struct clone *clone = add_clone(ctx);
2558428d7b3dSmrg		RROutput id;
2559428d7b3dSmrg
2560428d7b3dSmrg		if (clone == NULL)
2561428d7b3dSmrg			return -ENOMEM;
2562428d7b3dSmrg
2563428d7b3dSmrg		clone->depth = 24;
2564428d7b3dSmrg		clone->next = display->clone;
2565428d7b3dSmrg		display->clone = clone;
2566428d7b3dSmrg
2567428d7b3dSmrg		id = claim_virtual(ctx->display, buf, ctx->nclone);
2568428d7b3dSmrg		if (id == 0) {
2569428d7b3dSmrg			fprintf(stderr, "Failed to find available VirtualHead \"%s\" for \"%s\" on display \"%s\"\n",
2570428d7b3dSmrg				buf, o->name, DisplayString(display->dpy));
2571428d7b3dSmrg			return -ENOSPC;
2572428d7b3dSmrg		}
2573428d7b3dSmrg
2574428d7b3dSmrg		ret = clone_output_init(clone, &clone->src, ctx->display, buf, id);
2575428d7b3dSmrg		if (ret) {
2576428d7b3dSmrg			fprintf(stderr, "Failed to add output \"%s\" on display \"%s\"\n",
2577428d7b3dSmrg				buf, DisplayString(ctx->display->dpy));
2578428d7b3dSmrg			return ret;
2579428d7b3dSmrg		}
2580428d7b3dSmrg
2581428d7b3dSmrg		ret = clone_output_init(clone, &clone->dst, display, o->name, res->outputs[i]);
2582428d7b3dSmrg		if (ret) {
2583428d7b3dSmrg			fprintf(stderr, "Failed to add output \"%s\" on display \"%s\"\n",
2584428d7b3dSmrg				o->name, DisplayString(display->dpy));
2585428d7b3dSmrg			return ret;
2586428d7b3dSmrg		}
2587428d7b3dSmrg
2588428d7b3dSmrg		ret = clone_init_depth(clone);
2589428d7b3dSmrg		if (ret) {
2590428d7b3dSmrg			fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n",
2591428d7b3dSmrg				DisplayString(display->dpy));
2592428d7b3dSmrg			return ret;
2593428d7b3dSmrg		}
2594428d7b3dSmrg
2595428d7b3dSmrg		ret = clone_update_modes__randr(clone);
2596428d7b3dSmrg		if (ret) {
2597428d7b3dSmrg			fprintf(stderr, "Failed to clone output \"%s\" from display \"%s\"\n",
2598428d7b3dSmrg				o->name, DisplayString(display->dpy));
2599428d7b3dSmrg			return ret;
2600428d7b3dSmrg		}
2601428d7b3dSmrg
2602428d7b3dSmrg
2603428d7b3dSmrg		if (o->crtc) {
2604428d7b3dSmrg			DBG(X11, ("%s - disabling active output\n", DisplayString(display->dpy)));
2605428d7b3dSmrg			disable_crtc(display->dpy, res, o->crtc);
2606428d7b3dSmrg		}
2607428d7b3dSmrg
2608428d7b3dSmrg		XRRFreeOutputInfo(o);
2609428d7b3dSmrg	}
2610428d7b3dSmrg	XRRFreeScreenResources(res);
2611428d7b3dSmrg
2612428d7b3dSmrg	reverse_clone_list(display);
2613428d7b3dSmrg	return 0;
2614428d7b3dSmrg}
2615428d7b3dSmrg
2616428d7b3dSmrg#if defined(USE_XINERAMA)
2617428d7b3dSmrgstatic int last_display_add_clones__xinerama(struct context *ctx)
2618428d7b3dSmrg{
2619428d7b3dSmrg	struct display *display = last_display(ctx);
2620428d7b3dSmrg	Display *dpy = display->dpy;
2621428d7b3dSmrg	XineramaScreenInfo *xi;
2622428d7b3dSmrg	char buf[80];
2623428d7b3dSmrg	int n, count, ret;
2624428d7b3dSmrg
2625428d7b3dSmrg	DBG(X11, ("%s(%s)\n", __func__, DisplayString(display->dpy)));
2626428d7b3dSmrg
2627428d7b3dSmrg	count = 0;
2628428d7b3dSmrg	xi = XineramaQueryScreens(dpy, &count);
2629428d7b3dSmrg	for (n = 0; n < count; n++) {
2630428d7b3dSmrg		struct clone *clone = add_clone(ctx);
2631428d7b3dSmrg		RROutput id;
2632428d7b3dSmrg
2633428d7b3dSmrg		if (clone == NULL)
2634428d7b3dSmrg			return -ENOMEM;
2635428d7b3dSmrg
2636428d7b3dSmrg		if (xi[n].width == 0 || xi[n].height == 0)
2637428d7b3dSmrg			continue;
2638428d7b3dSmrg
2639428d7b3dSmrg		clone->depth = 24;
2640428d7b3dSmrg		clone->next = display->clone;
2641428d7b3dSmrg		display->clone = clone;
2642428d7b3dSmrg
2643428d7b3dSmrg		id = claim_virtual(ctx->display, buf, ctx->nclone);
2644428d7b3dSmrg		if (id == 0) {
2645428d7b3dSmrg			fprintf(stderr, "Failed to find available VirtualHead \"%s\" for Xinerama screen %d on display \"%s\"\n",
2646428d7b3dSmrg				buf, n, DisplayString(dpy));
2647428d7b3dSmrg		}
2648428d7b3dSmrg		ret = clone_output_init(clone, &clone->src, ctx->display, buf, id);
2649428d7b3dSmrg		if (ret) {
2650428d7b3dSmrg			fprintf(stderr, "Failed to add Xinerama screen %d on display \"%s\"\n",
2651428d7b3dSmrg				n, DisplayString(ctx->display->dpy));
2652428d7b3dSmrg			return ret;
2653428d7b3dSmrg		}
2654428d7b3dSmrg
2655428d7b3dSmrg		sprintf(buf, "XINERAMA%d", n);
2656428d7b3dSmrg		ret = clone_output_init(clone, &clone->dst, display, buf, 0);
2657428d7b3dSmrg		if (ret) {
2658428d7b3dSmrg			fprintf(stderr, "Failed to add Xinerama screen %d on display \"%s\"\n",
2659428d7b3dSmrg				n, DisplayString(dpy));
2660428d7b3dSmrg			return ret;
2661428d7b3dSmrg		}
2662428d7b3dSmrg
2663428d7b3dSmrg		ret = clone_init_depth(clone);
2664428d7b3dSmrg		if (ret) {
2665428d7b3dSmrg			fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n",
2666428d7b3dSmrg				DisplayString(display->dpy));
2667428d7b3dSmrg			return ret;
2668428d7b3dSmrg		}
2669428d7b3dSmrg
2670428d7b3dSmrg		/* Replace the modes on the local VIRTUAL output with the remote Screen */
2671428d7b3dSmrg		clone->width = xi[n].width;
2672428d7b3dSmrg		clone->height = xi[n].height;
2673428d7b3dSmrg		clone->dst.x = xi[n].x_org;
2674428d7b3dSmrg		clone->dst.y = xi[n].y_org;
2675428d7b3dSmrg		clone->dst.rr_crtc = -1;
2676428d7b3dSmrg		ret = clone_update_modes__fixed(clone);
2677428d7b3dSmrg		if (ret) {
2678428d7b3dSmrg			fprintf(stderr, "Failed to clone Xinerama screen %d from display \"%s\"\n",
2679428d7b3dSmrg				n, DisplayString(display->dpy));
2680428d7b3dSmrg			return ret;
2681428d7b3dSmrg		}
2682428d7b3dSmrg
2683428d7b3dSmrg		clone->active = ctx->active;
2684428d7b3dSmrg		ctx->active = clone;
2685428d7b3dSmrg	}
2686428d7b3dSmrg	XFree(xi);
2687428d7b3dSmrg
2688428d7b3dSmrg	reverse_clone_list(display);
2689428d7b3dSmrg	return 0;
2690428d7b3dSmrg}
2691428d7b3dSmrg#else
2692428d7b3dSmrg#define last_display_add_clones__xinerama(ctx) -1
2693428d7b3dSmrg#endif
2694428d7b3dSmrg
2695428d7b3dSmrgstatic int last_display_add_clones__display(struct context *ctx)
2696428d7b3dSmrg{
2697428d7b3dSmrg	struct display *display = last_display(ctx);
2698428d7b3dSmrg	Display *dpy = display->dpy;
2699428d7b3dSmrg	struct clone *clone;
2700428d7b3dSmrg	Screen *scr;
2701428d7b3dSmrg	char buf[80];
2702428d7b3dSmrg	int ret;
2703428d7b3dSmrg	RROutput id;
2704428d7b3dSmrg
2705428d7b3dSmrg
2706428d7b3dSmrg	DBG(X11, ("%s(%s)\n", __func__, DisplayString(dpy)));
2707428d7b3dSmrg	clone = add_clone(ctx);
2708428d7b3dSmrg	if (clone == NULL)
2709428d7b3dSmrg		return -ENOMEM;
2710428d7b3dSmrg
2711428d7b3dSmrg	clone->depth = 24;
2712428d7b3dSmrg	clone->next = display->clone;
2713428d7b3dSmrg	display->clone = clone;
2714428d7b3dSmrg
2715428d7b3dSmrg	id = claim_virtual(ctx->display, buf, ctx->nclone);
2716428d7b3dSmrg	if (id == 0) {
2717428d7b3dSmrg		fprintf(stderr, "Failed to find available VirtualHead \"%s\" for on display \"%s\"\n",
2718428d7b3dSmrg			buf, DisplayString(dpy));
2719428d7b3dSmrg	}
2720428d7b3dSmrg	ret = clone_output_init(clone, &clone->src, ctx->display, buf, id);
2721428d7b3dSmrg	if (ret) {
2722428d7b3dSmrg		fprintf(stderr, "Failed to add display \"%s\"\n",
2723428d7b3dSmrg			DisplayString(ctx->display->dpy));
2724428d7b3dSmrg		return ret;
2725428d7b3dSmrg	}
2726428d7b3dSmrg
2727428d7b3dSmrg	sprintf(buf, "WHOLE");
2728428d7b3dSmrg	ret = clone_output_init(clone, &clone->dst, display, buf, 0);
2729428d7b3dSmrg	if (ret) {
2730428d7b3dSmrg		fprintf(stderr, "Failed to add display \"%s\"\n",
2731428d7b3dSmrg			DisplayString(dpy));
2732428d7b3dSmrg		return ret;
2733428d7b3dSmrg	}
2734428d7b3dSmrg
2735428d7b3dSmrg	ret = clone_init_depth(clone);
2736428d7b3dSmrg	if (ret) {
2737428d7b3dSmrg		fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n",
2738428d7b3dSmrg			DisplayString(dpy));
2739428d7b3dSmrg		return ret;
2740428d7b3dSmrg	}
2741428d7b3dSmrg
2742428d7b3dSmrg	/* Replace the modes on the local VIRTUAL output with the remote Screen */
2743428d7b3dSmrg	scr = ScreenOfDisplay(dpy, DefaultScreen(dpy));
2744428d7b3dSmrg	clone->width = scr->width;
2745428d7b3dSmrg	clone->height = scr->height;
2746428d7b3dSmrg	clone->dst.x = 0;
2747428d7b3dSmrg	clone->dst.y = 0;
2748428d7b3dSmrg	clone->dst.rr_crtc = -1;
2749428d7b3dSmrg	ret = clone_update_modes__fixed(clone);
2750428d7b3dSmrg	if (ret) {
2751428d7b3dSmrg		fprintf(stderr, "Failed to clone display \"%s\"\n",
2752428d7b3dSmrg			DisplayString(dpy));
2753428d7b3dSmrg		return ret;
2754428d7b3dSmrg	}
2755428d7b3dSmrg
2756428d7b3dSmrg	clone->active = ctx->active;
2757428d7b3dSmrg	ctx->active = clone;
2758428d7b3dSmrg
2759428d7b3dSmrg	return 0;
2760428d7b3dSmrg}
2761428d7b3dSmrg
2762428d7b3dSmrgstatic int last_display_add_clones(struct context *ctx)
2763428d7b3dSmrg{
2764428d7b3dSmrg	struct display *display = last_display(ctx);
2765428d7b3dSmrg
2766428d7b3dSmrg	display->width = DisplayWidth(display->dpy, DefaultScreen(display->dpy));
2767428d7b3dSmrg	display->height = DisplayHeight(display->dpy, DefaultScreen(display->dpy));
2768428d7b3dSmrg	DBG(X11, ("%s - initial size %dx%d\n", DisplayString(display->dpy), display->width, display->height));
2769428d7b3dSmrg
2770428d7b3dSmrg	if (display->rr_active)
2771428d7b3dSmrg		return last_display_add_clones__randr(ctx);
2772428d7b3dSmrg
2773428d7b3dSmrg	if (display->xinerama_active)
2774428d7b3dSmrg		return last_display_add_clones__xinerama(ctx);
2775428d7b3dSmrg
2776428d7b3dSmrg	return last_display_add_clones__display(ctx);
2777428d7b3dSmrg}
2778428d7b3dSmrg
2779428d7b3dSmrgstatic int last_display_clone(struct context *ctx, int fd)
2780428d7b3dSmrg{
2781428d7b3dSmrg	fd = add_fd(ctx, fd);
2782428d7b3dSmrg	if (fd < 0)
2783428d7b3dSmrg		return fd;
2784428d7b3dSmrg
2785428d7b3dSmrg	fd = last_display_add_clones(ctx);
2786428d7b3dSmrg	if (fd)
2787428d7b3dSmrg		return fd;
2788428d7b3dSmrg
2789428d7b3dSmrg	return 0;
2790428d7b3dSmrg}
2791428d7b3dSmrg
2792428d7b3dSmrgstatic int first_display_has_singleton(struct context *ctx)
2793428d7b3dSmrg{
2794428d7b3dSmrg	struct display *display = ctx->display;
2795428d7b3dSmrg	unsigned long nitems, bytes;
2796428d7b3dSmrg	unsigned char *prop;
2797428d7b3dSmrg	int format;
2798428d7b3dSmrg	Atom type;
2799428d7b3dSmrg
2800428d7b3dSmrg	ctx->singleton = XInternAtom(display->dpy, "intel-virtual-output-singleton", False);
2801428d7b3dSmrg
2802428d7b3dSmrg	XGetWindowProperty(display->dpy, display->root, ctx->singleton,
2803428d7b3dSmrg			   0, 0, 0, AnyPropertyType, &type, &format, &nitems, &bytes, &prop);
2804428d7b3dSmrg	DBG(X11, ("%s: singleton registered? %d\n", DisplayString(display->dpy), type != None));
2805428d7b3dSmrg	return type != None;
2806428d7b3dSmrg}
2807428d7b3dSmrg
2808428d7b3dSmrgstatic int first_display_wait_for_ack(struct context *ctx, int timeout, int id)
2809428d7b3dSmrg{
2810428d7b3dSmrg	struct display *display = ctx->display;
2811428d7b3dSmrg	struct pollfd pfd;
2812428d7b3dSmrg	char expect[6]; /* "1234R\0" */
2813428d7b3dSmrg
2814428d7b3dSmrg	sprintf(expect, "%04xR", id);
2815428d7b3dSmrg	DBG(X11, ("%s: wait for act '%c%c%c%c%c'\n",
2816428d7b3dSmrg	     DisplayString(display->dpy),
2817428d7b3dSmrg	     expect[0], expect[1], expect[2], expect[3], expect[4]));
2818428d7b3dSmrg
2819428d7b3dSmrg	XFlush(display->dpy);
2820428d7b3dSmrg
2821428d7b3dSmrg	pfd.fd = ConnectionNumber(display->dpy);
2822428d7b3dSmrg	pfd.events = POLLIN;
2823428d7b3dSmrg	do {
2824428d7b3dSmrg		if (poll(&pfd, 1, timeout) <= 0)
2825428d7b3dSmrg			return -ETIME;
2826428d7b3dSmrg
2827428d7b3dSmrg		while (XPending(display->dpy)) {
2828428d7b3dSmrg			XEvent e;
2829428d7b3dSmrg			XClientMessageEvent *cme;
2830428d7b3dSmrg
2831428d7b3dSmrg			XNextEvent(display->dpy, &e);
2832428d7b3dSmrg			DBG(X11, ("%s: reading event type %d\n", DisplayString(display->dpy), e.type));
2833428d7b3dSmrg
2834428d7b3dSmrg			if (e.type != ClientMessage)
2835428d7b3dSmrg				continue;
2836428d7b3dSmrg
2837428d7b3dSmrg			cme = (XClientMessageEvent *)&e;
2838428d7b3dSmrg			if (cme->message_type != ctx->singleton)
2839428d7b3dSmrg				continue;
2840428d7b3dSmrg			if (cme->format != 8)
2841428d7b3dSmrg				continue;
2842428d7b3dSmrg
2843428d7b3dSmrg			DBG(X11, ("%s: client message '%c%c%c%c%c'\n",
2844428d7b3dSmrg			     DisplayString(display->dpy),
2845428d7b3dSmrg			     cme->data.b[0],
2846428d7b3dSmrg			     cme->data.b[1],
2847428d7b3dSmrg			     cme->data.b[2],
2848428d7b3dSmrg			     cme->data.b[3],
2849428d7b3dSmrg			     cme->data.b[4]));
2850428d7b3dSmrg			if (memcmp(cme->data.b, expect, 5))
2851428d7b3dSmrg				continue;
2852428d7b3dSmrg
2853428d7b3dSmrg			return -atoi(cme->data.b + 5);
2854428d7b3dSmrg		}
2855428d7b3dSmrg	} while (1);
2856428d7b3dSmrg}
2857428d7b3dSmrg
2858428d7b3dSmrg#if defined(__GNUC__) && (__GNUC__ > 3)
2859428d7b3dSmrg__attribute__((format(gnu_printf, 3, 4)))
2860428d7b3dSmrg#endif
2861428d7b3dSmrgstatic int first_display_send_command(struct context *ctx, int timeout,
2862428d7b3dSmrg				      const char *format,
2863428d7b3dSmrg				      ...)
2864428d7b3dSmrg{
2865428d7b3dSmrg	struct display *display = ctx->display;
2866428d7b3dSmrg	char buf[1024], *b;
2867428d7b3dSmrg	int len, id;
2868428d7b3dSmrg	va_list va;
2869428d7b3dSmrg
2870428d7b3dSmrg	id = rand() & 0xffff;
2871428d7b3dSmrg	sprintf(buf, "%04x", id);
2872428d7b3dSmrg	va_start(va, format);
2873428d7b3dSmrg	len = vsnprintf(buf+4, sizeof(buf)-4, format, va)+5;
2874428d7b3dSmrg	va_end(va);
2875428d7b3dSmrg	assert(len < sizeof(buf));
2876428d7b3dSmrg
2877428d7b3dSmrg	DBG(X11, ("%s: send command '%s'\n", DisplayString(display->dpy), buf));
2878428d7b3dSmrg
2879428d7b3dSmrg	b = buf;
2880428d7b3dSmrg	while (len) {
2881428d7b3dSmrg		XClientMessageEvent msg;
2882428d7b3dSmrg		int n = len;
2883428d7b3dSmrg		if (n > sizeof(msg.data.b))
2884428d7b3dSmrg			n = sizeof(msg.data.b);
2885428d7b3dSmrg		len -= n;
2886428d7b3dSmrg
2887428d7b3dSmrg		msg.type = ClientMessage;
2888428d7b3dSmrg		msg.serial = 0;
2889428d7b3dSmrg		msg.message_type = ctx->singleton;
2890428d7b3dSmrg		msg.format = 8;
2891428d7b3dSmrg		memcpy(msg.data.b, b, n);
2892428d7b3dSmrg		b += n;
2893428d7b3dSmrg
2894428d7b3dSmrg		XSendEvent(display->dpy, display->root, False, PropertyChangeMask, (XEvent *)&msg);
2895428d7b3dSmrg	}
2896428d7b3dSmrg
2897428d7b3dSmrg	return first_display_wait_for_ack(ctx, timeout, id);
2898428d7b3dSmrg}
2899428d7b3dSmrg
2900428d7b3dSmrgstatic void first_display_reply(struct context *ctx, int result)
2901428d7b3dSmrg{
2902428d7b3dSmrg	struct display *display = ctx->display;
2903428d7b3dSmrg	XClientMessageEvent msg;
2904428d7b3dSmrg
2905428d7b3dSmrg	sprintf(msg.data.b, "%c%c%c%cR%d",
2906428d7b3dSmrg	     ctx->command[0],
2907428d7b3dSmrg	     ctx->command[1],
2908428d7b3dSmrg	     ctx->command[2],
2909428d7b3dSmrg	     ctx->command[3],
2910428d7b3dSmrg	     -result);
2911428d7b3dSmrg
2912428d7b3dSmrg	DBG(X11, ("%s: send reply '%s'\n", DisplayString(display->dpy), msg.data.b));
2913428d7b3dSmrg
2914428d7b3dSmrg	msg.type = ClientMessage;
2915428d7b3dSmrg	msg.serial = 0;
2916428d7b3dSmrg	msg.message_type = ctx->singleton;
2917428d7b3dSmrg	msg.format = 8;
2918428d7b3dSmrg
2919428d7b3dSmrg	XSendEvent(display->dpy, display->root, False, PropertyChangeMask, (XEvent *)&msg);
2920428d7b3dSmrg	XFlush(display->dpy);
2921428d7b3dSmrg}
2922428d7b3dSmrg
2923428d7b3dSmrgstatic void first_display_handle_command(struct context *ctx,
2924428d7b3dSmrg					 const char *msg)
2925428d7b3dSmrg{
2926428d7b3dSmrg	int len;
2927428d7b3dSmrg
2928428d7b3dSmrg	DBG(X11, ("client message!\n"));
2929428d7b3dSmrg
2930428d7b3dSmrg	for (len = 0; len < 20 && msg[len]; len++)
2931428d7b3dSmrg		;
2932428d7b3dSmrg
2933428d7b3dSmrg	if (ctx->command_continuation + len > sizeof(ctx->command)) {
2934428d7b3dSmrg		ctx->command_continuation = 0;
2935428d7b3dSmrg		return;
2936428d7b3dSmrg	}
2937428d7b3dSmrg
2938428d7b3dSmrg	memcpy(ctx->command + ctx->command_continuation, msg, len);
2939428d7b3dSmrg	ctx->command_continuation += len;
2940428d7b3dSmrg
2941428d7b3dSmrg	if (len < 20) {
2942428d7b3dSmrg		ctx->command[ctx->command_continuation] = 0;
2943428d7b3dSmrg		DBG(X11, ("client command complete! '%s'\n", ctx->command));
2944428d7b3dSmrg		switch (ctx->command[4]) {
2945428d7b3dSmrg		case 'B':
2946428d7b3dSmrg			first_display_reply(ctx, last_display_clone(ctx, bumblebee_open(ctx)));
2947428d7b3dSmrg			break;
2948428d7b3dSmrg		case 'C':
2949428d7b3dSmrg			first_display_reply(ctx, last_display_clone(ctx, display_open(ctx, ctx->command + 5)));
2950428d7b3dSmrg			break;
2951428d7b3dSmrg		case 'P':
2952428d7b3dSmrg			first_display_reply(ctx, 0);
2953428d7b3dSmrg			break;
2954428d7b3dSmrg		case 'R':
2955428d7b3dSmrg			break;
2956428d7b3dSmrg		}
2957428d7b3dSmrg		ctx->command_continuation = 0;
2958428d7b3dSmrg		return;
2959428d7b3dSmrg	}
2960428d7b3dSmrg}
2961428d7b3dSmrg
2962428d7b3dSmrgstatic int first_display_register_as_singleton(struct context *ctx)
2963428d7b3dSmrg{
2964428d7b3dSmrg	struct display *display = ctx->display;
2965428d7b3dSmrg	struct pollfd pfd;
2966428d7b3dSmrg
2967428d7b3dSmrg	XChangeProperty(display->dpy, display->root, ctx->singleton,
2968428d7b3dSmrg			XA_STRING, 8, PropModeReplace, (unsigned char *)".", 1);
2969428d7b3dSmrg	XFlush(display->dpy);
2970428d7b3dSmrg
2971428d7b3dSmrg	/* And eat the notify (presuming that it is ours!) */
2972428d7b3dSmrg
2973428d7b3dSmrg	pfd.fd = ConnectionNumber(display->dpy);
2974428d7b3dSmrg	pfd.events = POLLIN;
2975428d7b3dSmrg	do {
2976428d7b3dSmrg		if (poll(&pfd, 1, 1000) <= 0) {
2977428d7b3dSmrg			fprintf(stderr, "Failed to register as singleton\n");
2978428d7b3dSmrg			return EBUSY;
2979428d7b3dSmrg		}
2980428d7b3dSmrg
2981428d7b3dSmrg		while (XPending(display->dpy)) {
2982428d7b3dSmrg			XEvent e;
2983428d7b3dSmrg
2984428d7b3dSmrg			XNextEvent(display->dpy, &e);
2985428d7b3dSmrg			DBG(X11, ("%s: reading event type %d\n", DisplayString(display->dpy), e.type));
2986428d7b3dSmrg
2987428d7b3dSmrg			if (e.type == PropertyNotify &&
2988428d7b3dSmrg			    ((XPropertyEvent *)&e)->atom == ctx->singleton)
2989428d7b3dSmrg				return 0;
2990428d7b3dSmrg		}
2991428d7b3dSmrg	} while (1);
2992428d7b3dSmrg}
2993428d7b3dSmrg
2994428d7b3dSmrgstatic void display_flush_send(struct display *display)
2995428d7b3dSmrg{
2996428d7b3dSmrg	XShmCompletionEvent e;
2997428d7b3dSmrg
2998428d7b3dSmrg	if (!display->send)
2999428d7b3dSmrg		return;
3000428d7b3dSmrg
3001428d7b3dSmrg	DBG(X11, ("%s flushing send (serial now %ld) (has shm send? %d)\n",
3002428d7b3dSmrg	     DisplayString(display->dpy),
3003428d7b3dSmrg	     (long)NextRequest(display->dpy),
3004428d7b3dSmrg	     display->shm_event));
3005428d7b3dSmrg
3006428d7b3dSmrg	display->send = 0;
3007428d7b3dSmrg
3008428d7b3dSmrg	if (display->shm_event == 0) {
3009428d7b3dSmrg		XSync(display->dpy, False);
3010428d7b3dSmrg		display->flush = 0;
3011428d7b3dSmrg		return;
3012428d7b3dSmrg	}
3013428d7b3dSmrg
3014428d7b3dSmrg	memset(&e, 0, sizeof(e));
3015428d7b3dSmrg	e.type = display->shm_event;
3016428d7b3dSmrg	e.send_event = 1;
3017428d7b3dSmrg	e.drawable = display->root;
3018428d7b3dSmrg	e.major_code = display->shm_opcode;
3019428d7b3dSmrg	e.minor_code = X_ShmPutImage;
3020428d7b3dSmrg
3021428d7b3dSmrg	XSendEvent(display->dpy, display->root, False, 0, (XEvent *)&e);
3022428d7b3dSmrg	display_mark_flush(display);
3023428d7b3dSmrg}
3024428d7b3dSmrg
3025428d7b3dSmrgstatic void display_sync(struct display *display)
3026428d7b3dSmrg{
3027428d7b3dSmrg	if (display->skip_clone == 0)
3028428d7b3dSmrg		return;
3029428d7b3dSmrg
3030428d7b3dSmrg	if (display->skip_frame++ < 2)
3031428d7b3dSmrg		return;
3032428d7b3dSmrg
3033428d7b3dSmrg	DBG(X11, ("%s forcing sync\n", DisplayString(display->dpy)));
3034428d7b3dSmrg	XSync(display->dpy, False);
3035428d7b3dSmrg
3036428d7b3dSmrg	display->flush = 0;
3037428d7b3dSmrg	display->send = 0;
3038428d7b3dSmrg
3039428d7b3dSmrg	/* Event tracking proven unreliable, disable */
3040428d7b3dSmrg	display->shm_event = 0;
3041428d7b3dSmrg}
3042428d7b3dSmrg
3043428d7b3dSmrgstatic void display_flush(struct display *display)
3044428d7b3dSmrg{
3045428d7b3dSmrg	display_flush_cursor(display);
3046428d7b3dSmrg	display_flush_send(display);
3047428d7b3dSmrg
3048428d7b3dSmrg	display_sync(display);
3049428d7b3dSmrg
3050428d7b3dSmrg	if (!display->flush)
3051428d7b3dSmrg		return;
3052428d7b3dSmrg
3053428d7b3dSmrg	DBG(X11, ("%s(%s)\n", __func__, DisplayString(display->dpy)));
3054428d7b3dSmrg
3055428d7b3dSmrg	XFlush(display->dpy);
3056428d7b3dSmrg	display->flush = 0;
3057428d7b3dSmrg}
3058428d7b3dSmrg
3059428d7b3dSmrgstatic int first_display_first_sibling(struct context *ctx)
3060428d7b3dSmrg{
3061428d7b3dSmrg	const char *str, *colon;
3062428d7b3dSmrg	int dpy, scr, len;
3063428d7b3dSmrg
3064428d7b3dSmrg	str = DisplayString(ctx->display->dpy);
3065428d7b3dSmrg	colon = strrchr(str, ':');
3066428d7b3dSmrg	if (colon == NULL)
3067428d7b3dSmrg		return -1;
3068428d7b3dSmrg
3069428d7b3dSmrg	if (sscanf(colon + 1, "%d.%d", &dpy, &scr) == 1)
3070428d7b3dSmrg		scr = 0;
3071428d7b3dSmrg
3072428d7b3dSmrg	len = (colon - str) + 1;
3073428d7b3dSmrg	memcpy(ctx->command, str, len);
3074428d7b3dSmrg	len += sprintf(ctx->command + len, "%d.", dpy);
3075428d7b3dSmrg	ctx->command_continuation = len;
3076428d7b3dSmrg
3077428d7b3dSmrg	return scr + 1;
3078428d7b3dSmrg}
3079428d7b3dSmrg
3080428d7b3dSmrgstatic int first_display_sibling(struct context *ctx, int i)
3081428d7b3dSmrg{
3082428d7b3dSmrg	if (i < 0)
3083428d7b3dSmrg		return 0;
3084428d7b3dSmrg
3085428d7b3dSmrg	sprintf(ctx->command + ctx->command_continuation, "%d", i);
3086428d7b3dSmrg	return 1;
3087428d7b3dSmrg}
3088428d7b3dSmrg
3089428d7b3dSmrg#define first_display_for_each_sibling(CTX, i) \
3090428d7b3dSmrg	for (i = first_display_first_sibling(CTX); first_display_sibling(CTX, i); i++)
3091428d7b3dSmrg
3092428d7b3dSmrgstatic void display_cleanup(struct display *display)
3093428d7b3dSmrg{
3094428d7b3dSmrg	Display *dpy = display->dpy;
3095428d7b3dSmrg	XRRScreenResources *res;
3096428d7b3dSmrg	int n;
3097428d7b3dSmrg
3098428d7b3dSmrg	XGrabServer(dpy);
3099428d7b3dSmrg
3100428d7b3dSmrg	res = _XRRGetScreenResourcesCurrent(dpy, display->root);
3101428d7b3dSmrg	if (res != NULL) {
3102428d7b3dSmrg		for (n = 0; n < res->ncrtc; n++)
3103428d7b3dSmrg			disable_crtc(display->dpy, res, res->crtcs[n]);
3104428d7b3dSmrg
3105428d7b3dSmrg		XRRFreeScreenResources(res);
3106428d7b3dSmrg	}
3107428d7b3dSmrg
3108428d7b3dSmrg	XUngrabServer(dpy);
3109428d7b3dSmrg}
3110428d7b3dSmrg
3111428d7b3dSmrgstatic void context_cleanup(struct context *ctx)
3112428d7b3dSmrg{
3113428d7b3dSmrg	Display *dpy = ctx->display->dpy;
3114428d7b3dSmrg	XRRScreenResources *res;
3115428d7b3dSmrg	int i, j;
3116428d7b3dSmrg
3117428d7b3dSmrg	for (i = 1; i < ctx->ndisplay; i++)
3118428d7b3dSmrg		display_cleanup(&ctx->display[i]);
3119428d7b3dSmrg
3120428d7b3dSmrg	if (dpy == NULL)
3121428d7b3dSmrg		return;
3122428d7b3dSmrg
3123428d7b3dSmrg	res = _XRRGetScreenResourcesCurrent(dpy, ctx->display->root);
3124428d7b3dSmrg	if (res == NULL)
3125428d7b3dSmrg		return;
3126428d7b3dSmrg
3127428d7b3dSmrg	XGrabServer(dpy);
3128428d7b3dSmrg
3129428d7b3dSmrg	for (i = 0; i < ctx->nclone; i++) {
3130428d7b3dSmrg		struct clone *clone = &ctx->clones[i];
3131428d7b3dSmrg		XRROutputInfo *output;
3132428d7b3dSmrg
3133428d7b3dSmrg		assert(clone->src.display == ctx->display);
3134428d7b3dSmrg
3135428d7b3dSmrg		output = XRRGetOutputInfo(dpy, res, clone->src.rr_output);
3136428d7b3dSmrg		if (output == NULL)
3137428d7b3dSmrg			continue;
3138428d7b3dSmrg
3139428d7b3dSmrg		disable_crtc(dpy, res, output->crtc);
3140428d7b3dSmrg		for (j = 0; j < output->nmode; j++)
3141428d7b3dSmrg			XRRDeleteOutputMode(dpy, clone->src.rr_output, output->modes[j]);
3142428d7b3dSmrg
3143428d7b3dSmrg		XRRFreeOutputInfo(output);
3144428d7b3dSmrg	}
3145428d7b3dSmrg
3146428d7b3dSmrg	for (i = 0; i < res->nmode; i++) {
3147428d7b3dSmrg		if (strncmp(res->modes[i].name, "VIRTUAL", 7) == 0) {
3148428d7b3dSmrg			XRRDestroyMode(dpy, res->modes[i].id);
3149428d7b3dSmrg			continue;
3150428d7b3dSmrg		}
3151428d7b3dSmrg
3152428d7b3dSmrg		if (strcmp(res->modes[i].name, "ClaimVirtualHead") == 0) {
3153428d7b3dSmrg			XRRDestroyMode(dpy, res->modes[i].id);
3154428d7b3dSmrg			continue;
3155428d7b3dSmrg		}
3156428d7b3dSmrg	}
3157428d7b3dSmrg	XRRFreeScreenResources(res);
3158428d7b3dSmrg
3159428d7b3dSmrg	/* And hide them again */
3160428d7b3dSmrg	res = XRRGetScreenResources(dpy, ctx->display->root);
3161428d7b3dSmrg	if (res != NULL)
3162428d7b3dSmrg		XRRFreeScreenResources(res);
3163428d7b3dSmrg
3164428d7b3dSmrg	XUngrabServer(dpy);
3165428d7b3dSmrg
3166428d7b3dSmrg	if (ctx->singleton)
3167428d7b3dSmrg		XDeleteProperty(dpy, ctx->display->root, ctx->singleton);
3168428d7b3dSmrg	XCloseDisplay(dpy);
3169428d7b3dSmrg}
3170428d7b3dSmrg
3171428d7b3dSmrgstatic int done;
3172428d7b3dSmrg
3173428d7b3dSmrgstatic void signal_handler(int sig)
3174428d7b3dSmrg{
3175428d7b3dSmrg	done = sig;
3176428d7b3dSmrg}
3177428d7b3dSmrg
3178428d7b3dSmrgint main(int argc, char **argv)
3179428d7b3dSmrg{
3180428d7b3dSmrg	struct context ctx;
3181428d7b3dSmrg	const char *src_name = NULL;
3182428d7b3dSmrg	uint64_t count;
3183428d7b3dSmrg	int daemonize = 1, bumblebee = 0, siblings = 0, singleton = 1;
3184428d7b3dSmrg	int i, ret, open, fail;
3185428d7b3dSmrg
3186428d7b3dSmrg	signal(SIGPIPE, SIG_IGN);
3187428d7b3dSmrg
3188428d7b3dSmrg	while ((i = getopt(argc, argv, "abd:fhSvV:")) != -1) {
3189428d7b3dSmrg		switch (i) {
3190428d7b3dSmrg		case 'd':
3191428d7b3dSmrg			src_name = optarg;
3192428d7b3dSmrg			break;
3193428d7b3dSmrg		case 'f':
3194428d7b3dSmrg			daemonize = 0;
3195428d7b3dSmrg			break;
3196428d7b3dSmrg		case 'b':
3197428d7b3dSmrg			bumblebee = 1;
3198428d7b3dSmrg			break;
3199428d7b3dSmrg		case 's':
3200428d7b3dSmrg			siblings = 1;
3201428d7b3dSmrg			break;
3202428d7b3dSmrg		case 'S':
3203428d7b3dSmrg			singleton = 0;
3204428d7b3dSmrg			break;
3205428d7b3dSmrg		case 'v':
3206428d7b3dSmrg			verbose = ~0;
3207428d7b3dSmrg			daemonize = 0;
3208428d7b3dSmrg			break;
3209428d7b3dSmrg		case 'V':
3210428d7b3dSmrg			verbose = strtol(optarg, NULL, 0);
3211428d7b3dSmrg			daemonize = 0;
3212428d7b3dSmrg			break;
3213428d7b3dSmrg		case 'h':
3214428d7b3dSmrg		default:
3215428d7b3dSmrg			usage(argv[0]);
3216428d7b3dSmrg			exit(0);
3217428d7b3dSmrg		}
3218428d7b3dSmrg	}
3219428d7b3dSmrg
3220428d7b3dSmrg	if (verbose)
3221428d7b3dSmrg		printf("intel-virtual-output: version %d.%d.%d\n",
3222428d7b3dSmrg		       PACKAGE_VERSION_MAJOR,
3223428d7b3dSmrg		       PACKAGE_VERSION_MINOR,
3224428d7b3dSmrg		       PACKAGE_VERSION_PATCHLEVEL);
3225428d7b3dSmrg
3226428d7b3dSmrg	ret = context_init(&ctx);
3227428d7b3dSmrg	if (ret)
3228428d7b3dSmrg		return -ret;
3229428d7b3dSmrg
3230428d7b3dSmrg	XSetErrorHandler(_check_error_handler);
3231428d7b3dSmrg
3232428d7b3dSmrg	ret = add_fd(&ctx, display_open(&ctx, src_name));
3233428d7b3dSmrg	if (ret) {
3234428d7b3dSmrg		fprintf(stderr, "Unable to connect to \"%s\".\n", src_name ?: getenv("DISPLAY") ?:
3235428d7b3dSmrg			"<unspecified>, set either the DISPLAY environment variable or pass -d <display name> on the commandline");
3236428d7b3dSmrg		ret = -ret;
3237428d7b3dSmrg		goto out;
3238428d7b3dSmrg	}
3239428d7b3dSmrg
3240428d7b3dSmrg	if (singleton) {
3241428d7b3dSmrg		XSelectInput(ctx.display->dpy, ctx.display->root, PropertyChangeMask);
3242428d7b3dSmrg		if (first_display_has_singleton(&ctx)) {
3243428d7b3dSmrg			DBG(X11, ("%s: pinging singleton\n", DisplayString(ctx.display->dpy)));
3244428d7b3dSmrg			ret = first_display_send_command(&ctx, 2000, "P");
3245428d7b3dSmrg			if (ret) {
3246428d7b3dSmrg				if (ret != -ETIME) {
3247428d7b3dSmrg					ret = -ret;
3248428d7b3dSmrg					goto out;
3249428d7b3dSmrg				}
3250428d7b3dSmrg				DBG(X11, ("No reply from singleton; assuming control\n"));
3251428d7b3dSmrg			} else {
3252428d7b3dSmrg				DBG(X11, ("%s: singleton active, sending open commands\n", DisplayString(ctx.display->dpy)));
3253428d7b3dSmrg
3254428d7b3dSmrg				open = fail = 0;
3255428d7b3dSmrg				for (i = optind; i < argc; i++) {
3256428d7b3dSmrg					ret = first_display_send_command(&ctx, 5000, "C%s", argv[i]);
3257428d7b3dSmrg					if (ret && ret != -EBUSY) {
3258428d7b3dSmrg						fprintf(stderr, "Unable to connect to \"%s\".\n", argv[i]);
3259428d7b3dSmrg						fail++;
3260428d7b3dSmrg					} else
3261428d7b3dSmrg						open++;
3262428d7b3dSmrg				}
3263428d7b3dSmrg				if (siblings || (optind == argc && !bumblebee)) {
3264428d7b3dSmrg					first_display_for_each_sibling(&ctx, i) {
3265428d7b3dSmrg						ret = first_display_send_command(&ctx, 5000, "C%s", ctx.command);
3266428d7b3dSmrg						if (ret && ret != -EBUSY)
3267428d7b3dSmrg							break;
3268428d7b3dSmrg						else
3269428d7b3dSmrg							open++;
3270428d7b3dSmrg					}
3271428d7b3dSmrg				}
3272428d7b3dSmrg				if (bumblebee || (optind == argc && !siblings)) {
3273428d7b3dSmrg					ret = first_display_send_command(&ctx, 5000, "B");
3274428d7b3dSmrg					if (ret && ret != -EBUSY) {
3275428d7b3dSmrg						if (bumblebee)
3276428d7b3dSmrg							fprintf(stderr, "Unable to connect to bumblebee.\n");
3277428d7b3dSmrg						fail++;
3278428d7b3dSmrg					} else
3279428d7b3dSmrg						open++;
3280428d7b3dSmrg				}
3281428d7b3dSmrg				ret = open || !fail ? 0 : ECONNREFUSED;
3282428d7b3dSmrg				goto out;
3283428d7b3dSmrg			}
3284428d7b3dSmrg		}
3285428d7b3dSmrg		ret = first_display_register_as_singleton(&ctx);
3286428d7b3dSmrg		if (ret)
3287428d7b3dSmrg			goto out;
3288428d7b3dSmrg	}
3289428d7b3dSmrg
3290428d7b3dSmrg	ret = display_init_damage(ctx.display);
3291428d7b3dSmrg	if (ret)
3292428d7b3dSmrg		goto out;
3293428d7b3dSmrg
3294428d7b3dSmrg	if ((ctx.display->rr_event | ctx.display->rr_error) == 0) {
3295428d7b3dSmrg		fprintf(stderr, "RandR extension not supported by %s\n", DisplayString(ctx.display->dpy));
3296428d7b3dSmrg		ret = EINVAL;
3297428d7b3dSmrg		goto out;
3298428d7b3dSmrg	}
3299428d7b3dSmrg	XRRSelectInput(ctx.display->dpy, ctx.display->root, RRScreenChangeNotifyMask);
3300428d7b3dSmrg	XFixesSelectCursorInput(ctx.display->dpy, ctx.display->root, XFixesDisplayCursorNotifyMask);
3301428d7b3dSmrg
3302428d7b3dSmrg	ret = add_fd(&ctx, record_mouse(&ctx));
3303428d7b3dSmrg	if (ret) {
3304428d7b3dSmrg		fprintf(stderr, "XTEST extension not supported by display \"%s\"\n", DisplayString(ctx.display->dpy));
3305428d7b3dSmrg		ret = -ret;
3306428d7b3dSmrg		goto out;
3307428d7b3dSmrg	}
3308428d7b3dSmrg
3309428d7b3dSmrg	open = fail = 0;
3310428d7b3dSmrg	for (i = optind; i < argc; i++) {
3311428d7b3dSmrg		ret = last_display_clone(&ctx, display_open(&ctx, argv[i]));
3312428d7b3dSmrg		if (ret && ret != -EBUSY) {
3313428d7b3dSmrg			fprintf(stderr, "Unable to connect to \"%s\".\n", argv[i]);
3314428d7b3dSmrg			fail++;
3315428d7b3dSmrg		} else
3316428d7b3dSmrg			open++;
3317428d7b3dSmrg	}
3318428d7b3dSmrg	if (siblings || (optind == argc && !bumblebee)) {
3319428d7b3dSmrg		first_display_for_each_sibling(&ctx, i) {
3320428d7b3dSmrg			ret = last_display_clone(&ctx, display_open(&ctx, ctx.command));
3321428d7b3dSmrg			if (ret && ret != -EBUSY)
3322428d7b3dSmrg				break;
3323428d7b3dSmrg			else
3324428d7b3dSmrg				open++;
3325428d7b3dSmrg		}
3326428d7b3dSmrg	}
3327428d7b3dSmrg	if (bumblebee || (optind == argc && !siblings)) {
3328428d7b3dSmrg		ret = last_display_clone(&ctx, bumblebee_open(&ctx));
3329428d7b3dSmrg		if (ret && ret != -EBUSY) {
3330428d7b3dSmrg			if (bumblebee)
3331428d7b3dSmrg				fprintf(stderr, "Unable to connect to bumblebee.\n");
3332428d7b3dSmrg			fail++;
3333428d7b3dSmrg		} else
3334428d7b3dSmrg			open++;
3335428d7b3dSmrg	}
3336428d7b3dSmrg	if (open == 0) {
3337428d7b3dSmrg		ret = fail ? ECONNREFUSED : 0;
3338428d7b3dSmrg		goto out;
3339428d7b3dSmrg	}
3340428d7b3dSmrg
3341428d7b3dSmrg	if (daemonize && daemon(0, 0)) {
3342428d7b3dSmrg		ret = EINVAL;
3343428d7b3dSmrg		goto out;
3344428d7b3dSmrg	}
3345428d7b3dSmrg
3346428d7b3dSmrg	signal(SIGHUP, signal_handler);
3347428d7b3dSmrg	signal(SIGINT, signal_handler);
3348428d7b3dSmrg	signal(SIGTERM, signal_handler);
3349428d7b3dSmrg
3350428d7b3dSmrg	ctx.command_continuation = 0;
3351428d7b3dSmrg	while (!done) {
3352428d7b3dSmrg		XEvent e;
3353428d7b3dSmrg		int reconfigure = 0;
3354428d7b3dSmrg		int rr_update = 0;
3355428d7b3dSmrg
3356428d7b3dSmrg		DBG(POLL, ("polling - enable timer? %d, nfd=%d, ndisplay=%d\n", ctx.timer_active, ctx.nfd, ctx.ndisplay));
3357428d7b3dSmrg		ret = poll(ctx.pfd + !ctx.timer_active, ctx.nfd - !ctx.timer_active, -1);
3358428d7b3dSmrg		if (ret <= 0)
3359428d7b3dSmrg			break;
3360428d7b3dSmrg
3361428d7b3dSmrg		/* pfd[0] is the timer, pfd[1] is the local display, pfd[2] is the mouse, pfd[3+] are the remotes */
3362428d7b3dSmrg
3363428d7b3dSmrg		DBG(POLL, ("poll reports %d fd awake\n", ret));
3364428d7b3dSmrg		if (ctx.pfd[1].revents || XPending(ctx.display[0].dpy)) {
3365428d7b3dSmrg			DBG(POLL,("%s woken up\n", DisplayString(ctx.display[0].dpy)));
3366428d7b3dSmrg			do {
3367428d7b3dSmrg				XNextEvent(ctx.display->dpy, &e);
3368428d7b3dSmrg
3369428d7b3dSmrg				if (e.type == ctx.display->damage_event + XDamageNotify ) {
3370428d7b3dSmrg					const XDamageNotifyEvent *de = (const XDamageNotifyEvent *)&e;
3371428d7b3dSmrg					struct clone *clone;
3372428d7b3dSmrg
3373428d7b3dSmrg					DBG(DAMAGE, ("%s damaged: (%d, %d)x(%d, %d)\n",
3374428d7b3dSmrg					     DisplayString(ctx.display->dpy),
3375428d7b3dSmrg					     de->area.x, de->area.y, de->area.width, de->area.height));
3376428d7b3dSmrg
3377428d7b3dSmrg					for (clone = ctx.active; clone; clone = clone->active)
3378428d7b3dSmrg						clone_damage(clone, &de->area);
3379428d7b3dSmrg
3380428d7b3dSmrg					if (ctx.active)
3381428d7b3dSmrg						context_enable_timer(&ctx);
3382428d7b3dSmrg				} else if (e.type == ctx.display->xfixes_event + XFixesCursorNotify) {
3383428d7b3dSmrg					XFixesCursorImage *cur;
3384428d7b3dSmrg
3385428d7b3dSmrg					DBG(CURSOR, ("%s cursor changed\n",
3386428d7b3dSmrg					     DisplayString(ctx.display->dpy)));
3387428d7b3dSmrg
3388428d7b3dSmrg					cur = XFixesGetCursorImage(ctx.display->dpy);
3389428d7b3dSmrg					if (cur == NULL)
3390428d7b3dSmrg						continue;
3391428d7b3dSmrg
3392428d7b3dSmrg					for (i = 1; i < ctx.ndisplay; i++)
3393428d7b3dSmrg						display_load_visible_cursor(&ctx.display[i], cur);
3394428d7b3dSmrg
3395428d7b3dSmrg					XFree(cur);
3396428d7b3dSmrg				} else if (e.type == ctx.display->rr_event + RRScreenChangeNotify) {
3397428d7b3dSmrg					DBG(XRR, ("%s screen changed (reconfigure pending? %d)\n",
3398428d7b3dSmrg					     DisplayString(ctx.display->dpy), reconfigure));
3399428d7b3dSmrg					reconfigure = 1;
3400428d7b3dSmrg				} else if (e.type == PropertyNotify) {
3401428d7b3dSmrg					XPropertyEvent *pe = (XPropertyEvent *)&e;
3402428d7b3dSmrg					if (pe->atom == ctx.singleton) {
3403428d7b3dSmrg						DBG(X11, ("lost control of singleton\n"));
3404428d7b3dSmrg						return 0;
3405428d7b3dSmrg					}
3406428d7b3dSmrg				} else if (e.type == ClientMessage) {
3407428d7b3dSmrg					XClientMessageEvent *cme;
3408428d7b3dSmrg
3409428d7b3dSmrg					DBG(X11, ("%s client message\n",
3410428d7b3dSmrg					     DisplayString(ctx.display->dpy)));
3411428d7b3dSmrg
3412428d7b3dSmrg					cme = (XClientMessageEvent *)&e;
3413428d7b3dSmrg					if (cme->message_type != ctx.singleton)
3414428d7b3dSmrg						continue;
3415428d7b3dSmrg					if (cme->format != 8)
3416428d7b3dSmrg						continue;
3417428d7b3dSmrg
3418428d7b3dSmrg					first_display_handle_command(&ctx, cme->data.b);
3419428d7b3dSmrg				} else {
3420428d7b3dSmrg					DBG(X11, ("unknown event %d\n", e.type));
3421428d7b3dSmrg				}
3422428d7b3dSmrg			} while (XEventsQueued(ctx.display->dpy, QueuedAfterReading));
3423428d7b3dSmrg		}
3424428d7b3dSmrg
3425428d7b3dSmrg		for (i = 1; i < ctx.ndisplay; i++) {
3426428d7b3dSmrg			if (ctx.pfd[i+2].revents == 0 && !XPending(ctx.display[i].dpy))
3427428d7b3dSmrg				continue;
3428428d7b3dSmrg
3429428d7b3dSmrg			DBG(POLL, ("%s woken up\n", DisplayString(ctx.display[i].dpy)));
3430428d7b3dSmrg			do {
3431428d7b3dSmrg				XNextEvent(ctx.display[i].dpy, &e);
3432428d7b3dSmrg
3433428d7b3dSmrg				DBG(POLL, ("%s received event %d\n", DisplayString(ctx.display[i].dpy), e.type));
3434428d7b3dSmrg				if (ctx.display[i].rr_active && e.type == ctx.display[i].rr_event + RRNotify) {
3435428d7b3dSmrg					XRRNotifyEvent *re = (XRRNotifyEvent *)&e;
3436428d7b3dSmrg
3437428d7b3dSmrg					DBG(XRR, ("%s received RRNotify, type %d\n", DisplayString(ctx.display[i].dpy), re->subtype));
3438428d7b3dSmrg					if (re->subtype == RRNotify_OutputChange) {
3439428d7b3dSmrg						XRROutputPropertyNotifyEvent *ro = (XRROutputPropertyNotifyEvent *)re;
3440428d7b3dSmrg						struct clone *clone;
3441428d7b3dSmrg
3442428d7b3dSmrg						DBG(XRR, ("%s RRNotify_OutputChange, timestamp %ld\n", DisplayString(ctx.display[i].dpy), ro->timestamp));
3443428d7b3dSmrg						for (clone = ctx.display[i].clone; clone; clone = clone->next) {
3444428d7b3dSmrg							if (clone->dst.rr_output == ro->output)
3445428d7b3dSmrg								rr_update = clone->rr_update = 1;
3446428d7b3dSmrg						}
3447428d7b3dSmrg					}
3448428d7b3dSmrg				}
3449428d7b3dSmrg			} while (XEventsQueued(ctx.display[i].dpy, QueuedAfterReading));
3450428d7b3dSmrg		}
3451428d7b3dSmrg
3452428d7b3dSmrg		if (rr_update) {
3453428d7b3dSmrg			for (i = 0; i < ctx.nclone; i++)
3454428d7b3dSmrg				clone_update(&ctx.clones[i]);
3455428d7b3dSmrg		}
3456428d7b3dSmrg
3457428d7b3dSmrg		if (reconfigure && context_update(&ctx))
3458428d7b3dSmrg			display_reset_damage(ctx.display);
3459428d7b3dSmrg
3460428d7b3dSmrg		while (XPending(ctx.record)) /* discard all implicit events */
3461428d7b3dSmrg			XNextEvent(ctx.record, &e);
3462428d7b3dSmrg
3463428d7b3dSmrg		if (ctx.timer_active && read(ctx.timer, &count, sizeof(count)) > 0) {
3464428d7b3dSmrg			struct clone *clone;
3465428d7b3dSmrg
3466428d7b3dSmrg			DBG(TIMER, ("%s timer expired (count=%ld)\n", DisplayString(ctx.display->dpy), (long)count));
3467428d7b3dSmrg			ret = 0;
3468428d7b3dSmrg
3469428d7b3dSmrg			if (ctx.active) {
3470428d7b3dSmrg				DBG(DAMAGE, ("%s clearing damage\n", DisplayString(ctx.display->dpy)));
3471428d7b3dSmrg				XDamageSubtract(ctx.display->dpy, ctx.display->damage, None, None);
3472428d7b3dSmrg				ctx.display->flush = 1;
3473428d7b3dSmrg			}
3474428d7b3dSmrg
3475428d7b3dSmrg			for (clone = ctx.active; clone; clone = clone->active)
3476428d7b3dSmrg				ret |= clone_paint(clone);
3477428d7b3dSmrg
3478428d7b3dSmrg			for (i = 0; i < ctx.ndisplay; i++)
3479428d7b3dSmrg				display_flush(&ctx.display[i]);
3480428d7b3dSmrg
3481428d7b3dSmrg			DBG(TIMER, ("%s timer still active? %d\n", DisplayString(ctx.display->dpy), ret != 0));
3482428d7b3dSmrg			ctx.timer_active = ret != 0;
3483428d7b3dSmrg		}
3484428d7b3dSmrg	}
3485428d7b3dSmrg
3486428d7b3dSmrg	ret = 0;
3487428d7b3dSmrgout:
3488428d7b3dSmrg	context_cleanup(&ctx);
3489428d7b3dSmrg	return ret;
3490428d7b3dSmrg}
3491