virtual.c revision 13496ba1
142542f5fSchristos/*
242542f5fSchristos * Copyright © 2013 Intel Corporation
342542f5fSchristos *
442542f5fSchristos * Permission is hereby granted, free of charge, to any person obtaining a
542542f5fSchristos * copy of this software and associated documentation files (the "Software"),
642542f5fSchristos * to deal in the Software without restriction, including without limitation
742542f5fSchristos * the rights to use, copy, modify, merge, publish, distribute, sublicense,
842542f5fSchristos * and/or sell copies of the Software, and to permit persons to whom the
942542f5fSchristos * Software is furnished to do so, subject to the following conditions:
1042542f5fSchristos *
1142542f5fSchristos * The above copyright notice and this permission notice (including the next
1242542f5fSchristos * paragraph) shall be included in all copies or substantial portions of the
1342542f5fSchristos * Software.
1442542f5fSchristos *
1542542f5fSchristos * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1642542f5fSchristos * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1742542f5fSchristos * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1842542f5fSchristos * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1942542f5fSchristos * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2042542f5fSchristos * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2142542f5fSchristos * IN THE SOFTWARE.
2242542f5fSchristos *
2342542f5fSchristos */
2442542f5fSchristos
2542542f5fSchristos#ifdef HAVE_CONFIG_H
2642542f5fSchristos#include "config.h"
2742542f5fSchristos#endif
2842542f5fSchristos
2942542f5fSchristos#include <X11/Xlib.h>
3042542f5fSchristos#include <X11/Xatom.h>
3142542f5fSchristos
3242542f5fSchristos#include <X11/Xlibint.h>
3342542f5fSchristos#include <X11/extensions/record.h>
3442542f5fSchristos#include <X11/extensions/XShm.h>
3542542f5fSchristos#if HAVE_X11_EXTENSIONS_SHMPROTO_H
3642542f5fSchristos#include <X11/extensions/shmproto.h>
3742542f5fSchristos#elif HAVE_X11_EXTENSIONS_SHMSTR_H
3842542f5fSchristos#include <X11/extensions/shmstr.h>
3942542f5fSchristos#else
4042542f5fSchristos#error Failed to find the right header for X11 MIT-SHM protocol definitions
4142542f5fSchristos#endif
4242542f5fSchristos#include <X11/extensions/Xdamage.h>
4342542f5fSchristos#if HAVE_X11_EXTENSIONS_XINERAMA_H
4442542f5fSchristos#include <X11/extensions/Xinerama.h>
4542542f5fSchristos#define USE_XINERAMA
4642542f5fSchristos#endif
4742542f5fSchristos#include <X11/extensions/Xrandr.h>
4842542f5fSchristos#include <X11/extensions/Xrender.h>
4942542f5fSchristos#include <X11/Xcursor/Xcursor.h>
5042542f5fSchristos#include <pixman.h>
5142542f5fSchristos
5242542f5fSchristos#include <sys/types.h>
5342542f5fSchristos#include <sys/ipc.h>
5442542f5fSchristos#include <sys/shm.h>
5542542f5fSchristos#include <sys/timerfd.h>
5642542f5fSchristos#include <sys/poll.h>
5742542f5fSchristos#include <sys/socket.h>
5842542f5fSchristos#include <sys/un.h>
5942542f5fSchristos
6042542f5fSchristos#include <stdarg.h>
6142542f5fSchristos#include <stdio.h>
6242542f5fSchristos#include <stdlib.h>
6342542f5fSchristos#include <stdint.h>
6442542f5fSchristos#include <signal.h>
6542542f5fSchristos#include <getopt.h>
6642542f5fSchristos#include <limits.h>
6742542f5fSchristos#include <unistd.h>
6842542f5fSchristos#include <fcntl.h>
6942542f5fSchristos#include <assert.h>
7042542f5fSchristos
7142542f5fSchristos#define FORCE_FULL_REDRAW 0
7242542f5fSchristos#define FORCE_16BIT_XFER 0
7342542f5fSchristos
7442542f5fSchristos#define DBG(v, x) if (verbose & v) printf x
7542542f5fSchristosstatic int verbose;
7642542f5fSchristos#define X11 0x1
7742542f5fSchristos#define XRR 0x1
7842542f5fSchristos#define TIMER 0x4
7942542f5fSchristos#define DRAW 0x8
8042542f5fSchristos#define DAMAGE 0x10
8142542f5fSchristos#define CURSOR 0x20
8242542f5fSchristos#define POLL 0x40
8342542f5fSchristos
8442542f5fSchristosstruct display {
8542542f5fSchristos	Display *dpy;
8642542f5fSchristos	struct clone *clone;
8742542f5fSchristos	struct context *ctx;
8842542f5fSchristos
8942542f5fSchristos	int damage_event, damage_error;
9042542f5fSchristos	int xfixes_event, xfixes_error;
9142542f5fSchristos	int rr_event, rr_error, rr_active;
9242542f5fSchristos	int xinerama_event, xinerama_error, xinerama_active;
9342542f5fSchristos	int dri3_active;
9442542f5fSchristos	Window root;
9542542f5fSchristos	Visual *visual;
9642542f5fSchristos	Damage damage;
9742542f5fSchristos
9842542f5fSchristos	int width;
9942542f5fSchristos	int height;
10042542f5fSchristos	int depth;
10142542f5fSchristos
10242542f5fSchristos	XRenderPictFormat *root_format;
10342542f5fSchristos	XRenderPictFormat *rgb16_format;
10442542f5fSchristos	XRenderPictFormat *rgb24_format;
10542542f5fSchristos
10642542f5fSchristos	int has_shm;
10742542f5fSchristos	int has_shm_pixmap;
10842542f5fSchristos	int shm_opcode;
10942542f5fSchristos	int shm_event;
11042542f5fSchristos
11142542f5fSchristos	Cursor invisible_cursor;
11242542f5fSchristos	Cursor visible_cursor;
11342542f5fSchristos
11442542f5fSchristos	XcursorImage cursor_image;
11542542f5fSchristos	int cursor_serial;
11642542f5fSchristos	int cursor_x;
11742542f5fSchristos	int cursor_y;
11842542f5fSchristos	int cursor_moved;
11942542f5fSchristos	int cursor_visible;
12042542f5fSchristos	int cursor;
12142542f5fSchristos
12242542f5fSchristos	int flush;
12342542f5fSchristos	int send;
12442542f5fSchristos	int skip_clone;
12542542f5fSchristos	int skip_frame;
12642542f5fSchristos};
12742542f5fSchristos
12842542f5fSchristosstruct output {
12942542f5fSchristos	struct display *display;
13042542f5fSchristos	Display *dpy;
13142542f5fSchristos	char *name;
13242542f5fSchristos	RROutput rr_output;
13342542f5fSchristos	RRCrtc rr_crtc;
13442542f5fSchristos	Window window;
13542542f5fSchristos	Picture win_picture;
13642542f5fSchristos	Picture pix_picture;
13742542f5fSchristos	Pixmap pixmap;
13842542f5fSchristos	GC gc;
13942542f5fSchristos
14042542f5fSchristos	long serial;
14142542f5fSchristos	int use_shm;
14242542f5fSchristos	int use_shm_pixmap;
14342542f5fSchristos	XShmSegmentInfo shm;
14442542f5fSchristos
14542542f5fSchristos	XRenderPictFormat *use_render;
14642542f5fSchristos
14742542f5fSchristos	int x, y;
14842542f5fSchristos	XRRModeInfo mode;
14942542f5fSchristos	Rotation rotation;
15042542f5fSchristos};
15142542f5fSchristos
15242542f5fSchristosstruct clone {
15342542f5fSchristos	struct clone *next;
15442542f5fSchristos	struct clone *active;
15542542f5fSchristos
15642542f5fSchristos	struct output src, dst;
15742542f5fSchristos	long timestamp;
15842542f5fSchristos
15942542f5fSchristos	XShmSegmentInfo shm;
16042542f5fSchristos	XImage image;
16142542f5fSchristos
16242542f5fSchristos	int width, height, depth;
16342542f5fSchristos	struct { int x1, x2, y1, y2; } damaged;
16442542f5fSchristos	int rr_update;
16542542f5fSchristos
16642542f5fSchristos	struct dri3_fence {
16742542f5fSchristos		XID xid;
16842542f5fSchristos		void *addr;
16942542f5fSchristos	} dri3;
17042542f5fSchristos};
17142542f5fSchristos
17242542f5fSchristosstruct context {
17342542f5fSchristos	struct display *display;
17442542f5fSchristos	struct clone *clones;
17542542f5fSchristos	struct clone *active;
17642542f5fSchristos	struct pollfd *pfd;
17742542f5fSchristos#define timer pfd[0].fd
17842542f5fSchristos	Display *record;
17942542f5fSchristos	int nclone;
18042542f5fSchristos	int ndisplay;
18142542f5fSchristos	int nfd;
18242542f5fSchristos
18342542f5fSchristos	int timer_active;
18442542f5fSchristos
18542542f5fSchristos	long timestamp;
18642542f5fSchristos	long configTimestamp;
18742542f5fSchristos
18842542f5fSchristos	Atom singleton;
18942542f5fSchristos	char command[1024];
19042542f5fSchristos	int command_continuation;
19142542f5fSchristos};
19242542f5fSchristos
19342542f5fSchristosstatic inline int is_power_of_2(unsigned long n)
19442542f5fSchristos{
19542542f5fSchristos	return n && ((n & (n - 1)) == 0);
19642542f5fSchristos}
19742542f5fSchristos
19842542f5fSchristosstatic int xlib_vendor_is_xorg(Display *dpy)
19942542f5fSchristos{
20042542f5fSchristos	const char *const vendor = ServerVendor(dpy);
20142542f5fSchristos	return strstr(vendor, "X.Org") || strstr(vendor, "Xorg");
20242542f5fSchristos}
20342542f5fSchristos
20442542f5fSchristosstatic inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window)
20542542f5fSchristos{
20642542f5fSchristos	XRRScreenResources *res;
20742542f5fSchristos
20842542f5fSchristos	res = XRRGetScreenResourcesCurrent(dpy, window);
20942542f5fSchristos	if (res == NULL)
21042542f5fSchristos		res = XRRGetScreenResources(dpy, window);
21142542f5fSchristos
21242542f5fSchristos	return res;
21342542f5fSchristos}
21442542f5fSchristos
21542542f5fSchristos#define XORG_VERSION_ENCODE(major,minor,patch,snap) \
21642542f5fSchristos    (((major) * 10000000) + ((minor) * 100000) + ((patch) * 1000) + snap)
21742542f5fSchristos
21842542f5fSchristosstatic int _x_error_occurred;
21942542f5fSchristos
22042542f5fSchristosstatic int
22142542f5fSchristos_check_error_handler(Display     *display,
22242542f5fSchristos		     XErrorEvent *event)
22342542f5fSchristos{
22442542f5fSchristos	DBG(X11, ("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n",
22542542f5fSchristos	     DisplayString(display),
22642542f5fSchristos	     event->serial,
22742542f5fSchristos	     event->error_code,
22842542f5fSchristos	     event->request_code,
22942542f5fSchristos	     event->minor_code));
23042542f5fSchristos	_x_error_occurred = 1;
23142542f5fSchristos	return False; /* ignored */
23242542f5fSchristos}
23342542f5fSchristos
23442542f5fSchristosstatic int
23542542f5fSchristoscan_use_shm(Display *dpy,
23642542f5fSchristos	    Window window,
23742542f5fSchristos	    int *shm_event,
23842542f5fSchristos	    int *shm_opcode,
23942542f5fSchristos	    int *shm_pixmap)
24042542f5fSchristos{
24142542f5fSchristos	XShmSegmentInfo shm;
24242542f5fSchristos	Status success;
24342542f5fSchristos	XExtCodes *codes;
24442542f5fSchristos	int major, minor, has_shm, has_pixmap;
24542542f5fSchristos
24642542f5fSchristos	if (!XShmQueryExtension(dpy))
24742542f5fSchristos		return 0;
24842542f5fSchristos
24942542f5fSchristos	XShmQueryVersion(dpy, &major, &minor, &has_pixmap);
25042542f5fSchristos
25142542f5fSchristos	shm.shmid = shmget(IPC_PRIVATE, 0x1000, IPC_CREAT | 0600);
25242542f5fSchristos	if (shm.shmid == -1)
25342542f5fSchristos		return 0;
25442542f5fSchristos
25542542f5fSchristos	shm.readOnly = 0;
25642542f5fSchristos	shm.shmaddr = shmat(shm.shmid, NULL, 0);
25742542f5fSchristos	if (shm.shmaddr == (char *) -1) {
25842542f5fSchristos		shmctl(shm.shmid, IPC_RMID, NULL);
25942542f5fSchristos		return 0;
26042542f5fSchristos	}
26142542f5fSchristos
26242542f5fSchristos	XSync(dpy, False);
26342542f5fSchristos	_x_error_occurred = 0;
26442542f5fSchristos
26542542f5fSchristos	success = XShmAttach(dpy, &shm);
26642542f5fSchristos
26742542f5fSchristos	XSync(dpy, False);
26842542f5fSchristos	has_shm = success && _x_error_occurred == 0;
26942542f5fSchristos
27042542f5fSchristos	/* As libXext sets the SEND_EVENT bit in the ShmCompletionEvent,
27142542f5fSchristos	 * the Xserver may crash if it does not take care when processing
27242542f5fSchristos	 * the event type. For instance versions of Xorg prior to 1.11.1
27342542f5fSchristos	 * exhibited this bug, and was fixed by:
27442542f5fSchristos	 *
27542542f5fSchristos	 * commit 2d2dce558d24eeea0eb011ec9ebaa6c5c2273c39
27642542f5fSchristos	 * Author: Sam Spilsbury <sam.spilsbury@canonical.com>
27742542f5fSchristos	 * Date:   Wed Sep 14 09:58:34 2011 +0800
27842542f5fSchristos	 *
27942542f5fSchristos	 * Remove the SendEvent bit (0x80) before doing range checks on event type.
28042542f5fSchristos	 */
28142542f5fSchristos	codes = 0;
28242542f5fSchristos	if (has_shm)
28342542f5fSchristos		codes = XInitExtension(dpy, SHMNAME);
28442542f5fSchristos	if (xlib_vendor_is_xorg(dpy) &&
28542542f5fSchristos	    VendorRelease(dpy) < XORG_VERSION_ENCODE(1,11,0,1))
28642542f5fSchristos		codes = 0;
28742542f5fSchristos	if (codes) {
28842542f5fSchristos		XShmCompletionEvent e;
28942542f5fSchristos
29042542f5fSchristos		memset(&e, 0, sizeof(e));
29142542f5fSchristos
29242542f5fSchristos		e.type = codes->first_event;
29342542f5fSchristos		e.send_event = 1;
29442542f5fSchristos		e.serial = 1;
29542542f5fSchristos		e.drawable = window;
29642542f5fSchristos		e.major_code = codes->major_opcode;
29742542f5fSchristos		e.minor_code = X_ShmPutImage;
29842542f5fSchristos
29942542f5fSchristos		e.shmseg = shm.shmid;
30042542f5fSchristos		e.offset = 0;
30142542f5fSchristos
30242542f5fSchristos		XSendEvent(dpy, e.drawable, False, 0, (XEvent *)&e);
30342542f5fSchristos		XSync(dpy, False);
30442542f5fSchristos
30542542f5fSchristos		if (_x_error_occurred == 0) {
30642542f5fSchristos			*shm_opcode = codes->major_opcode;
30742542f5fSchristos			*shm_event = codes->first_event;
30842542f5fSchristos			*shm_pixmap = has_pixmap;
30942542f5fSchristos		}
31042542f5fSchristos	}
31142542f5fSchristos
31242542f5fSchristos	XShmDetach(dpy, &shm);
31342542f5fSchristos	shmctl(shm.shmid, IPC_RMID, NULL);
31442542f5fSchristos	shmdt(shm.shmaddr);
31542542f5fSchristos
31642542f5fSchristos	return has_shm;
31742542f5fSchristos}
31842542f5fSchristos
31942542f5fSchristos#ifdef DRI3
32042542f5fSchristos#include <X11/Xlib-xcb.h>
32142542f5fSchristos#include <X11/xshmfence.h>
32242542f5fSchristos#include <xcb/xcb.h>
32342542f5fSchristos#include <xcb/dri3.h>
32442542f5fSchristos#include <xcb/sync.h>
32542542f5fSchristosstatic Pixmap dri3_create_pixmap(Display *dpy,
32642542f5fSchristos				 Drawable draw,
32742542f5fSchristos				 int width, int height, int depth,
32842542f5fSchristos				 int fd, int bpp, int stride, int size)
32942542f5fSchristos{
33042542f5fSchristos	xcb_connection_t *c = XGetXCBConnection(dpy);
33142542f5fSchristos	xcb_pixmap_t pixmap = xcb_generate_id(c);
33242542f5fSchristos	xcb_dri3_pixmap_from_buffer(c, pixmap, draw, size, width, height, stride, depth, bpp, fd);
33342542f5fSchristos	return pixmap;
33442542f5fSchristos}
33542542f5fSchristos
33642542f5fSchristosstatic int dri3_create_fd(Display *dpy,
33742542f5fSchristos			  Pixmap pixmap,
33842542f5fSchristos			  int *stride)
33942542f5fSchristos{
34042542f5fSchristos	xcb_connection_t *c = XGetXCBConnection(dpy);
34142542f5fSchristos	xcb_dri3_buffer_from_pixmap_cookie_t cookie;
34242542f5fSchristos	xcb_dri3_buffer_from_pixmap_reply_t *reply;
34342542f5fSchristos
34442542f5fSchristos	cookie = xcb_dri3_buffer_from_pixmap(c, pixmap);
34542542f5fSchristos	reply = xcb_dri3_buffer_from_pixmap_reply(c, cookie, NULL);
34642542f5fSchristos	if (!reply)
34742542f5fSchristos		return -1;
34842542f5fSchristos
34942542f5fSchristos	if (reply->nfd != 1)
35042542f5fSchristos		return -1;
35142542f5fSchristos
35242542f5fSchristos	*stride = reply->stride;
35342542f5fSchristos	return xcb_dri3_buffer_from_pixmap_reply_fds(c, reply)[0];
35442542f5fSchristos}
35542542f5fSchristos
35642542f5fSchristosstatic int dri3_query_version(Display *dpy, int *major, int *minor)
35742542f5fSchristos{
35842542f5fSchristos	xcb_connection_t *c = XGetXCBConnection(dpy);
35942542f5fSchristos	xcb_dri3_query_version_reply_t *reply;
36042542f5fSchristos
36142542f5fSchristos	*major = *minor = -1;
36242542f5fSchristos
36342542f5fSchristos	reply = xcb_dri3_query_version_reply(c,
36442542f5fSchristos					     xcb_dri3_query_version(c,
36542542f5fSchristos								    XCB_DRI3_MAJOR_VERSION,
36642542f5fSchristos								    XCB_DRI3_MINOR_VERSION),
36742542f5fSchristos					     NULL);
36842542f5fSchristos	if (reply == NULL)
36942542f5fSchristos		return -1;
37042542f5fSchristos
37142542f5fSchristos	*major = reply->major_version;
37242542f5fSchristos	*minor = reply->minor_version;
37342542f5fSchristos	free(reply);
37442542f5fSchristos
37542542f5fSchristos	return 0;
37642542f5fSchristos}
37742542f5fSchristos
37842542f5fSchristosstatic int dri3_exists(Display *dpy)
37942542f5fSchristos{
38042542f5fSchristos	int major, minor;
38142542f5fSchristos
38242542f5fSchristos	if (dri3_query_version(dpy, &major, &minor) < 0)
38342542f5fSchristos		return 0;
38442542f5fSchristos
38542542f5fSchristos	return major >= 0;
38642542f5fSchristos}
38742542f5fSchristos
38842542f5fSchristosstatic void dri3_create_fence(Display *dpy, Drawable d, struct dri3_fence *fence)
38942542f5fSchristos{
39042542f5fSchristos	xcb_connection_t *c = XGetXCBConnection(dpy);
39142542f5fSchristos	struct dri3_fence f;
39242542f5fSchristos	int fd;
39342542f5fSchristos
39442542f5fSchristos	fd = xshmfence_alloc_shm();
39542542f5fSchristos	if (fd < 0)
39642542f5fSchristos		return;
39742542f5fSchristos
39842542f5fSchristos	f.addr = xshmfence_map_shm(fd);
39942542f5fSchristos	if (f.addr == NULL) {
40042542f5fSchristos		close(fd);
40142542f5fSchristos		return;
40242542f5fSchristos	}
40342542f5fSchristos
40442542f5fSchristos	f.xid = xcb_generate_id(c);
40542542f5fSchristos	xcb_dri3_fence_from_fd(c, d, f.xid, 0, fd);
40642542f5fSchristos
40742542f5fSchristos	*fence = f;
40842542f5fSchristos}
40942542f5fSchristos
41042542f5fSchristosstatic void dri3_fence_flush(Display *dpy, struct dri3_fence *fence)
41142542f5fSchristos{
41242542f5fSchristos	xcb_sync_trigger_fence(XGetXCBConnection(dpy), fence->xid);
41342542f5fSchristos}
41442542f5fSchristos
41542542f5fSchristosstatic void dri3_fence_free(Display *dpy, struct dri3_fence *fence)
41642542f5fSchristos{
41742542f5fSchristos	xshmfence_unmap_shm(fence->addr);
41842542f5fSchristos	xcb_sync_destroy_fence(XGetXCBConnection(dpy), fence->xid);
41942542f5fSchristos}
42042542f5fSchristos
42142542f5fSchristos#else
42242542f5fSchristos
42342542f5fSchristosstatic int dri3_exists(Display *dpy)
42442542f5fSchristos{
42542542f5fSchristos	return 0;
42642542f5fSchristos}
42742542f5fSchristos
42842542f5fSchristosstatic void dri3_create_fence(Display *dpy, Drawable d, struct dri3_fence *fence)
42942542f5fSchristos{
43042542f5fSchristos}
43142542f5fSchristos
43242542f5fSchristosstatic void dri3_fence_flush(Display *dpy, struct dri3_fence *fence)
43342542f5fSchristos{
43442542f5fSchristos}
43542542f5fSchristos
43642542f5fSchristosstatic void dri3_fence_free(Display *dpy, struct dri3_fence *fence)
43742542f5fSchristos{
43842542f5fSchristos}
43942542f5fSchristos
44042542f5fSchristosstatic Pixmap dri3_create_pixmap(Display *dpy,
44142542f5fSchristos				 Drawable draw,
44242542f5fSchristos				 int width, int height, int depth,
44342542f5fSchristos				 int fd, int bpp, int stride, int size)
44442542f5fSchristos{
44542542f5fSchristos	return None;
44642542f5fSchristos}
44742542f5fSchristos
44842542f5fSchristosstatic int dri3_create_fd(Display *dpy,
44942542f5fSchristos			  Pixmap pixmap,
45042542f5fSchristos			  int *stride)
45142542f5fSchristos{
45242542f5fSchristos	return -1;
45342542f5fSchristos}
45442542f5fSchristos#endif
45542542f5fSchristos
45642542f5fSchristosstatic int timerfd(int hz)
45742542f5fSchristos{
45842542f5fSchristos	struct itimerspec it;
45942542f5fSchristos	int fd;
46042542f5fSchristos
46142542f5fSchristos	fd = -1;
46242542f5fSchristos#ifdef CLOCK_MONOTONIC_COARSE
46342542f5fSchristos	fd = timerfd_create(CLOCK_MONOTONIC_COARSE, TFD_NONBLOCK);
46442542f5fSchristos#endif
46542542f5fSchristos	if (fd < 0)
46642542f5fSchristos		fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
46742542f5fSchristos	if (fd < 0)
46842542f5fSchristos		return -ETIME;
46942542f5fSchristos
47042542f5fSchristos	it.it_interval.tv_sec = 0;
47142542f5fSchristos	it.it_interval.tv_nsec = 1000000000 / hz;
47242542f5fSchristos	it.it_value = it.it_interval;
47342542f5fSchristos	if (timerfd_settime(fd, 0, &it, NULL) < 0) {
47442542f5fSchristos		close(fd);
47542542f5fSchristos		return -ETIME;
47642542f5fSchristos	}
47742542f5fSchristos
47842542f5fSchristos	return fd;
47942542f5fSchristos}
48042542f5fSchristos
48142542f5fSchristosstatic int context_init(struct context *ctx)
48242542f5fSchristos{
48342542f5fSchristos	struct pollfd *pfd;
48442542f5fSchristos
48542542f5fSchristos	memset(ctx, 0, sizeof(*ctx));
48642542f5fSchristos
48742542f5fSchristos	ctx->pfd = malloc(2*sizeof(struct pollfd));
48842542f5fSchristos	if (ctx->pfd == NULL)
48942542f5fSchristos		return -ENOMEM;
49042542f5fSchristos
49142542f5fSchristos	ctx->clones = malloc(sizeof(struct clone));
49242542f5fSchristos	if (ctx->clones == NULL)
49342542f5fSchristos		return -ENOMEM;
49442542f5fSchristos
49542542f5fSchristos	ctx->display = malloc(sizeof(struct display));
49642542f5fSchristos	if (ctx->display == NULL)
49742542f5fSchristos		return -ENOMEM;
49842542f5fSchristos
49942542f5fSchristos	pfd = memset(&ctx->pfd[ctx->nfd++], 0, sizeof(struct pollfd));
50042542f5fSchristos	pfd->fd = timerfd(60);
50142542f5fSchristos	if (pfd->fd < 0)
50242542f5fSchristos		return pfd->fd;
50342542f5fSchristos	pfd->events = POLLIN;
50442542f5fSchristos
50542542f5fSchristos	return 0;
50642542f5fSchristos}
50742542f5fSchristos
50842542f5fSchristosstatic void context_enable_timer(struct context *ctx)
50942542f5fSchristos{
51042542f5fSchristos	uint64_t count;
51142542f5fSchristos
51242542f5fSchristos	DBG(TIMER, ("%s timer active? %d\n", __func__, ctx->timer_active));
51342542f5fSchristos
51442542f5fSchristos	if (ctx->timer_active)
51542542f5fSchristos		return;
51642542f5fSchristos
51742542f5fSchristos	/* reset timer */
51842542f5fSchristos	count = read(ctx->timer, &count, sizeof(count));
51942542f5fSchristos
52042542f5fSchristos	ctx->timer_active = 1;
52142542f5fSchristos}
52242542f5fSchristos
52342542f5fSchristosstatic int add_fd(struct context *ctx, int fd)
52442542f5fSchristos{
52542542f5fSchristos	struct pollfd *pfd;
52642542f5fSchristos
52742542f5fSchristos	if (fd < 0)
52842542f5fSchristos		return fd;
52942542f5fSchristos
53042542f5fSchristos	if (is_power_of_2(ctx->nfd)) {
53142542f5fSchristos		ctx->pfd = realloc(ctx->pfd, 2*ctx->nfd*sizeof(struct pollfd));
53242542f5fSchristos		if (ctx->pfd == NULL)
53342542f5fSchristos			return -ENOMEM;
53442542f5fSchristos	}
53542542f5fSchristos
53642542f5fSchristos	pfd = memset(&ctx->pfd[ctx->nfd++], 0, sizeof(struct pollfd));
53742542f5fSchristos	pfd->fd = fd;
53842542f5fSchristos	pfd->events = POLLIN;
53942542f5fSchristos	return 0;
54042542f5fSchristos}
54142542f5fSchristos
54242542f5fSchristosstatic void display_mark_flush(struct display *display)
54342542f5fSchristos{
54442542f5fSchristos	DBG(DRAW, ("%s mark flush (flush=%d)\n",
54542542f5fSchristos	     DisplayString(display->dpy), display->flush));
54642542f5fSchristos
54742542f5fSchristos	if (display->flush)
54842542f5fSchristos		return;
54942542f5fSchristos
55042542f5fSchristos	context_enable_timer(display->ctx);
55142542f5fSchristos	display->flush = 1;
55242542f5fSchristos}
55342542f5fSchristos
55442542f5fSchristosstatic int mode_equal(const XRRModeInfo *a, const XRRModeInfo *b)
55542542f5fSchristos{
55642542f5fSchristos	return (a->width == b->width &&
55742542f5fSchristos		a->height == b->height &&
55842542f5fSchristos		a->dotClock == b->dotClock &&
55942542f5fSchristos		a->hSyncStart == b->hSyncStart &&
56042542f5fSchristos		a->hSyncEnd == b->hSyncEnd &&
56142542f5fSchristos		a->hTotal == b->hTotal &&
56242542f5fSchristos		a->hSkew == b->hSkew &&
56342542f5fSchristos		a->vSyncStart == b->vSyncStart &&
56442542f5fSchristos		a->vSyncEnd == b->vSyncEnd &&
56542542f5fSchristos		a->vTotal == b->vTotal &&
56642542f5fSchristos		a->modeFlags == b->modeFlags);
56742542f5fSchristos}
56842542f5fSchristos
56942542f5fSchristosstatic XRRModeInfo *lookup_mode(XRRScreenResources *res, int id)
57042542f5fSchristos{
57142542f5fSchristos	int i;
57242542f5fSchristos
57342542f5fSchristos	for (i = 0; i < res->nmode; i++) {
57442542f5fSchristos		if (res->modes[i].id == id)
57542542f5fSchristos			return &res->modes[i];
57642542f5fSchristos	}
57742542f5fSchristos
57842542f5fSchristos	return NULL;
57942542f5fSchristos}
58042542f5fSchristos
58142542f5fSchristosstatic void clone_update_edid(struct clone *clone)
58242542f5fSchristos{
58342542f5fSchristos	unsigned long nitems, after;
58442542f5fSchristos	unsigned char *data;
58542542f5fSchristos	int format;
58642542f5fSchristos	Atom type;
58742542f5fSchristos
58842542f5fSchristos	if (XRRGetOutputProperty(clone->dst.dpy, clone->dst.rr_output,
58942542f5fSchristos				 XInternAtom(clone->dst.dpy, "EDID", False),
59042542f5fSchristos				 0, 100, False, False, AnyPropertyType,
59142542f5fSchristos				 &type, &format, &nitems, &after, &data) == Success) {
59242542f5fSchristos		XRRChangeOutputProperty(clone->src.dpy, clone->src.rr_output,
59342542f5fSchristos					XInternAtom(clone->src.dpy, "EDID", False),
59442542f5fSchristos					type, format, PropModeReplace, data, nitems);
59542542f5fSchristos	}
59642542f5fSchristos}
59742542f5fSchristos
59842542f5fSchristosstatic int disable_crtc(Display *dpy, XRRScreenResources *res, RRCrtc crtc)
59942542f5fSchristos{
60042542f5fSchristos	XRRPanning panning;
60142542f5fSchristos
60242542f5fSchristos	if (crtc) {
60342542f5fSchristos		XRRSetPanning(dpy, res, crtc, memset(&panning, 0, sizeof(panning)));
60442542f5fSchristos
60542542f5fSchristos		if (XRRSetCrtcConfig(dpy, res, crtc, CurrentTime, 0, 0, None, RR_Rotate_0, NULL, 0) != Success)
60642542f5fSchristos			return 0;
60742542f5fSchristos
60842542f5fSchristos		if (XRRSetPanning(dpy, res, crtc, memset(&panning, 0, sizeof(panning))) != Success) {
60942542f5fSchristos			DBG(XRR, ("%s failed to clear panning on CRTC:%ld\n", DisplayString(dpy), (long)crtc));
61042542f5fSchristos			if (verbose) {
61142542f5fSchristos				XRRCrtcInfo *c;
61242542f5fSchristos				XRRPanning *p;
61342542f5fSchristos
61442542f5fSchristos				c = XRRGetCrtcInfo(dpy, res, crtc);
61542542f5fSchristos				if (c) {
61642542f5fSchristos					DBG(XRR, ("%s CRTC:%ld x=%d, y=%d, rotation=%d, mode=%ld\n",
61742542f5fSchristos					     DisplayString(dpy), (long)crtc,
61842542f5fSchristos					     c->x, c->y, c->rotation, c->mode));
61942542f5fSchristos					XRRFreeCrtcInfo(c);
62042542f5fSchristos				}
62142542f5fSchristos
62242542f5fSchristos				p = XRRGetPanning(dpy, res, crtc);
62342542f5fSchristos				if (p) {
62442542f5fSchristos					DBG(XRR, ("%s CRTC:%ld panning (%d, %d)x(%d, %d), tracking (%d, %d)x(%d, %d), border (%d, %d),(%d, %d)\n",
62542542f5fSchristos					     DisplayString(dpy), (long)crtc,
62642542f5fSchristos					     p->left, p->top, p->width, p->height,
62742542f5fSchristos					     p->track_left, p->track_top, p->track_width, p->track_height,
62842542f5fSchristos					     p->border_left, p->border_top, p->border_right, p->border_bottom));
62942542f5fSchristos					XRRFreePanning(p);
63042542f5fSchristos				}
63142542f5fSchristos			}
63242542f5fSchristos		}
63342542f5fSchristos	}
63442542f5fSchristos
63542542f5fSchristos	return 1;
63642542f5fSchristos}
63742542f5fSchristos
63842542f5fSchristosstatic int clone_update_modes__randr(struct clone *clone)
63942542f5fSchristos{
64042542f5fSchristos	XRRScreenResources *from_res = NULL, *to_res = NULL;
64142542f5fSchristos	XRROutputInfo *from_info = NULL, *to_info = NULL;
64242542f5fSchristos	int i, j, ret = ENOENT;
64342542f5fSchristos
64442542f5fSchristos	assert(clone->src.rr_output);
64542542f5fSchristos	assert(clone->dst.rr_output);
64642542f5fSchristos	assert(clone->dst.display->rr_event);
64742542f5fSchristos
64842542f5fSchristos	from_res = _XRRGetScreenResourcesCurrent(clone->dst.dpy, clone->dst.window);
64942542f5fSchristos	if (from_res == NULL)
65042542f5fSchristos		goto err;
65142542f5fSchristos
65242542f5fSchristos	from_info = XRRGetOutputInfo(clone->dst.dpy, from_res, clone->dst.rr_output);
65342542f5fSchristos	if (from_info == NULL)
65442542f5fSchristos		goto err;
65542542f5fSchristos
65642542f5fSchristos	DBG(XRR, ("%s(%s-%s <- %s-%s): timestamp %ld (last %ld)\n", __func__,
65742542f5fSchristos	     DisplayString(clone->src.dpy), clone->src.name,
65842542f5fSchristos	     DisplayString(clone->dst.dpy), clone->dst.name,
65942542f5fSchristos	     from_info->timestamp, clone->timestamp));
66042542f5fSchristos
66142542f5fSchristos	to_res = _XRRGetScreenResourcesCurrent(clone->src.dpy, clone->src.window);
66242542f5fSchristos	if (to_res == NULL)
66342542f5fSchristos		goto err;
66442542f5fSchristos
66542542f5fSchristos	to_info = XRRGetOutputInfo(clone->src.dpy, to_res, clone->src.rr_output);
66642542f5fSchristos	if (to_info == NULL)
66742542f5fSchristos		goto err;
66842542f5fSchristos
66942542f5fSchristos	DBG(XRR, ("%s: dst.rr_crtc=%ld, now %ld\n",
67042542f5fSchristos	     __func__, (long)clone->dst.rr_crtc, (long)from_info->crtc));
67142542f5fSchristos	if (clone->dst.rr_crtc == from_info->crtc) {
67242542f5fSchristos		for (i = 0; i < to_info->nmode; i++) {
67342542f5fSchristos			XRRModeInfo *mode, *old;
67442542f5fSchristos
67542542f5fSchristos			mode = lookup_mode(to_res, to_info->modes[i]);
67642542f5fSchristos			if (mode == NULL)
67742542f5fSchristos				break;
67842542f5fSchristos
67942542f5fSchristos			DBG(XRR, ("%s(%s-%s): lookup mode %s\n", __func__,
68042542f5fSchristos			     DisplayString(clone->src.dpy), clone->src.name,
68142542f5fSchristos			     mode->name));
68242542f5fSchristos
68342542f5fSchristos			for (j = 0; j < from_info->nmode; j++) {
68442542f5fSchristos				old = lookup_mode(from_res, from_info->modes[j]);
68542542f5fSchristos				if (old && mode_equal(mode, old)) {
68642542f5fSchristos					mode = NULL;
68742542f5fSchristos					break;
68842542f5fSchristos				}
68942542f5fSchristos			}
69042542f5fSchristos			if (mode) {
69142542f5fSchristos				DBG(XRR, ("%s(%s-%s): unknown mode %s\n", __func__,
69242542f5fSchristos				     DisplayString(clone->src.dpy), clone->src.name,
69342542f5fSchristos				     mode->name));
69442542f5fSchristos				break;
69542542f5fSchristos			}
69642542f5fSchristos		}
69742542f5fSchristos		if (i == from_info->nmode && i == to_info->nmode) {
69842542f5fSchristos			DBG(XRR, ("%s(%s-%s): no change in output\n", __func__,
69942542f5fSchristos			     DisplayString(clone->src.dpy), clone->src.name));
70042542f5fSchristos			goto done;
70142542f5fSchristos		}
70242542f5fSchristos	}
70342542f5fSchristos
70442542f5fSchristos	/* Disable the remote output */
70542542f5fSchristos	if (from_info->crtc != clone->dst.rr_crtc) {
70642542f5fSchristos		DBG(XRR, ("%s(%s-%s): disabling active CRTC\n", __func__,
70742542f5fSchristos		     DisplayString(clone->dst.dpy), clone->dst.name));
70842542f5fSchristos		if (disable_crtc(clone->dst.dpy, from_res, from_info->crtc)) {
70942542f5fSchristos			clone->dst.rr_crtc = 0;
71042542f5fSchristos			clone->dst.mode.id = 0;
71142542f5fSchristos		} else {
71242542f5fSchristos			XRRCrtcInfo *c = XRRGetCrtcInfo(clone->dst.dpy, from_res, from_info->crtc);
71342542f5fSchristos			if (c) {
71442542f5fSchristos				clone->dst.x = c->x;
71542542f5fSchristos				clone->dst.y = c->y;
71642542f5fSchristos				clone->dst.rotation = c->rotation;
71742542f5fSchristos				clone->dst.mode.id = c->mode;
71842542f5fSchristos				XRRFreeCrtcInfo(c);
71942542f5fSchristos			}
72042542f5fSchristos		}
72142542f5fSchristos	}
72242542f5fSchristos
72342542f5fSchristos	/* Create matching modes for the real output on the virtual */
72442542f5fSchristos	XGrabServer(clone->src.dpy);
72542542f5fSchristos
72642542f5fSchristos	/* Clear all current UserModes on the output, including any active ones */
72742542f5fSchristos	if (to_info->crtc) {
72842542f5fSchristos		DBG(XRR, ("%s(%s-%s): disabling active CRTC\n", __func__,
72942542f5fSchristos		     DisplayString(clone->src.dpy), clone->src.name));
73042542f5fSchristos		disable_crtc(clone->src.dpy, to_res, to_info->crtc);
73142542f5fSchristos	}
73242542f5fSchristos	for (i = 0; i < to_info->nmode; i++) {
73342542f5fSchristos		DBG(XRR, ("%s(%s-%s): deleting mode %ld\n", __func__,
73442542f5fSchristos		     DisplayString(clone->src.dpy), clone->src.name, (long)to_info->modes[i]));
73542542f5fSchristos		XRRDeleteOutputMode(clone->src.dpy, clone->src.rr_output, to_info->modes[i]);
73642542f5fSchristos	}
73742542f5fSchristos
73842542f5fSchristos	clone->src.rr_crtc = 0;
73942542f5fSchristos
74042542f5fSchristos	for (i = 0; i < from_info->nmode; i++) {
74142542f5fSchristos		XRRModeInfo *mode, *old;
74242542f5fSchristos		RRMode id;
74342542f5fSchristos
74442542f5fSchristos		mode = lookup_mode(from_res, from_info->modes[i]);
74542542f5fSchristos		if (mode == NULL)
74642542f5fSchristos			continue;
74742542f5fSchristos		for (j = 0; j < i; j++) {
74842542f5fSchristos			old = lookup_mode(from_res, from_info->modes[j]);
74942542f5fSchristos			if (old && mode_equal(mode, old)) {
75042542f5fSchristos				mode = NULL;
75142542f5fSchristos				break;
75242542f5fSchristos			}
75342542f5fSchristos		}
75442542f5fSchristos		if (mode == NULL)
75542542f5fSchristos			continue;
75642542f5fSchristos
75742542f5fSchristos		id = 0;
75842542f5fSchristos		for (j = 0; j < to_res->nmode; j++) {
75942542f5fSchristos			old = &to_res->modes[j];
76042542f5fSchristos			if (mode_equal(mode, old)) {
76142542f5fSchristos				id = old->id;
76242542f5fSchristos				DBG(XRR, ("%s(%s-%s): reusing mode %ld: %s\n", __func__,
76342542f5fSchristos				     DisplayString(clone->src.dpy), clone->src.name, id, mode->name));
76442542f5fSchristos				break;
76542542f5fSchristos			}
76642542f5fSchristos		}
76742542f5fSchristos		if (id == 0) {
76842542f5fSchristos			XRRModeInfo m;
76942542f5fSchristos			char buf[256];
77042542f5fSchristos
77142542f5fSchristos			/* XXX User names must be unique! */
77242542f5fSchristos			m = *mode;
77342542f5fSchristos			m.nameLength = snprintf(buf, sizeof(buf),
77442542f5fSchristos						"%s.%ld-%s", clone->src.name, (long)from_info->modes[i], mode->name);
77542542f5fSchristos			m.name = buf;
77642542f5fSchristos
77742542f5fSchristos			id = XRRCreateMode(clone->src.dpy, clone->src.window, &m);
77842542f5fSchristos			DBG(XRR, ("%s(%s-%s): adding mode %ld: %s\n", __func__,
77942542f5fSchristos			     DisplayString(clone->src.dpy), clone->src.name, id, mode->name));
78042542f5fSchristos		}
78142542f5fSchristos
78242542f5fSchristos		XRRAddOutputMode(clone->src.dpy, clone->src.rr_output, id);
78342542f5fSchristos	}
78442542f5fSchristos	clone_update_edid(clone);
78542542f5fSchristos	XUngrabServer(clone->src.dpy);
78642542f5fSchristosdone:
78742542f5fSchristos	ret = 0;
78842542f5fSchristos	clone->timestamp = from_info->timestamp;
78942542f5fSchristos
79042542f5fSchristoserr:
79142542f5fSchristos	if (to_info)
79242542f5fSchristos		XRRFreeOutputInfo(to_info);
79342542f5fSchristos	if (to_res)
79442542f5fSchristos		XRRFreeScreenResources(to_res);
79542542f5fSchristos	if (from_info)
79642542f5fSchristos		XRRFreeOutputInfo(from_info);
79742542f5fSchristos	if (from_res)
79842542f5fSchristos		XRRFreeScreenResources(from_res);
79942542f5fSchristos
80042542f5fSchristos	return ret;
80142542f5fSchristos}
80242542f5fSchristos
80342542f5fSchristosstatic int clone_update_modes__fixed(struct clone *clone)
80442542f5fSchristos{
80542542f5fSchristos	char mode_name[80];
80642542f5fSchristos	XRRScreenResources *res = NULL;
80742542f5fSchristos	XRROutputInfo *info = NULL;
80842542f5fSchristos	XRRModeInfo mode;
80942542f5fSchristos	RRMode id;
81042542f5fSchristos	int i, j, ret = ENOENT;
81142542f5fSchristos
81242542f5fSchristos	assert(clone->src.rr_output);
81342542f5fSchristos
81442542f5fSchristos	res = _XRRGetScreenResourcesCurrent(clone->src.dpy, clone->src.window);
81542542f5fSchristos	if (res == NULL)
81642542f5fSchristos		goto err;
81742542f5fSchristos
81842542f5fSchristos	info = XRRGetOutputInfo(clone->src.dpy, res, clone->src.rr_output);
81942542f5fSchristos	if (info == NULL)
82042542f5fSchristos		goto err;
82142542f5fSchristos
82242542f5fSchristos	XGrabServer(clone->src.dpy);
82342542f5fSchristos
82442542f5fSchristos	/* Clear all current UserModes on the output, including any active ones */
82542542f5fSchristos	if (info->crtc) {
82642542f5fSchristos		DBG(XRR, ("%s(%s-%s): disabling active CRTC\n", __func__,
82742542f5fSchristos		     DisplayString(clone->src.dpy), clone->src.name));
82842542f5fSchristos		disable_crtc(clone->src.dpy, res, info->crtc);
82942542f5fSchristos	}
83042542f5fSchristos	for (i = 0; i < info->nmode; i++) {
83142542f5fSchristos		DBG(XRR, ("%s(%s-%s): deleting mode %ld\n", __func__,
83242542f5fSchristos		     DisplayString(clone->src.dpy), clone->src.name, (long)info->modes[i]));
83342542f5fSchristos		XRRDeleteOutputMode(clone->src.dpy, clone->src.rr_output, info->modes[i]);
83442542f5fSchristos	}
83542542f5fSchristos
83642542f5fSchristos	clone->src.rr_crtc = 0;
83742542f5fSchristos
83842542f5fSchristos	/* Create matching mode for the real output on the virtual */
83942542f5fSchristos	memset(&mode, 0, sizeof(mode));
84042542f5fSchristos	mode.width = clone->width;
84142542f5fSchristos	mode.height = clone->height;
84242542f5fSchristos	mode.nameLength = sprintf(mode_name, "FAKE-%dx%d", mode.width, mode.height);
84342542f5fSchristos	mode.name = mode_name;
84442542f5fSchristos
84542542f5fSchristos	id = 0;
84642542f5fSchristos	for (j = 0; j < res->nmode; j++) {
84742542f5fSchristos		if (mode_equal(&mode, &res->modes[j])) {
84842542f5fSchristos			id = res->modes[j].id;
84942542f5fSchristos			break;
85042542f5fSchristos		}
85142542f5fSchristos	}
85242542f5fSchristos	if (id == 0)
85342542f5fSchristos		id = XRRCreateMode(clone->src.dpy, clone->src.window, &mode);
85442542f5fSchristos
85542542f5fSchristos	XRRAddOutputMode(clone->src.dpy, clone->src.rr_output, id);
85642542f5fSchristos
85742542f5fSchristos	XUngrabServer(clone->src.dpy);
85842542f5fSchristos	ret = 0;
85942542f5fSchristoserr:
86042542f5fSchristos	if (info)
86142542f5fSchristos		XRRFreeOutputInfo(info);
86242542f5fSchristos	if (res)
86342542f5fSchristos		XRRFreeScreenResources(res);
86442542f5fSchristos
86542542f5fSchristos	return ret;
86642542f5fSchristos}
86742542f5fSchristos
86842542f5fSchristosstatic RROutput claim_virtual(struct display *display, char *output_name, int nclone)
86942542f5fSchristos{
87042542f5fSchristos	char mode_name[] = "ClaimVirtualHead";
87142542f5fSchristos	Display *dpy = display->dpy;
87242542f5fSchristos	XRRScreenResources *res;
87342542f5fSchristos	XRROutputInfo *output;
87442542f5fSchristos	XRRModeInfo mode;
87542542f5fSchristos	RRMode id;
87642542f5fSchristos	RROutput rr_output = 0;
87742542f5fSchristos	int i;
87842542f5fSchristos
87942542f5fSchristos	DBG(X11, ("%s(%d)\n", __func__, nclone));
88042542f5fSchristos	XGrabServer(dpy);
88142542f5fSchristos
88242542f5fSchristos	res = _XRRGetScreenResourcesCurrent(dpy, display->root);
88342542f5fSchristos	if (res == NULL)
88442542f5fSchristos		goto out;
88542542f5fSchristos
88642542f5fSchristos	sprintf(output_name, "VIRTUAL%d", nclone);
88742542f5fSchristos
88842542f5fSchristos	for (i = rr_output = 0; rr_output == 0 && i < res->noutput; i++) {
88942542f5fSchristos		output = XRRGetOutputInfo(dpy, res, res->outputs[i]);
89042542f5fSchristos		if (output == NULL)
89142542f5fSchristos			continue;
89242542f5fSchristos
89342542f5fSchristos		if (strcmp(output->name, output_name) == 0)
89442542f5fSchristos			rr_output = res->outputs[i];
89542542f5fSchristos
89642542f5fSchristos		XRRFreeOutputInfo(output);
89742542f5fSchristos	}
89842542f5fSchristos	for (i = id = 0; id == 0 && i < res->nmode; i++) {
89942542f5fSchristos		if (strcmp(res->modes[i].name, mode_name) == 0)
90042542f5fSchristos			id = res->modes[i].id;
90142542f5fSchristos	}
90242542f5fSchristos	XRRFreeScreenResources(res);
90342542f5fSchristos
90442542f5fSchristos	DBG(XRR, ("%s(%s): rr_output=%ld\n", __func__, output_name, (long)rr_output));
90542542f5fSchristos	if (rr_output == 0)
90642542f5fSchristos		goto out;
90742542f5fSchristos
90842542f5fSchristos	/* Set any mode on the VirtualHead to make the Xserver allocate another */
90942542f5fSchristos	memset(&mode, 0, sizeof(mode));
91042542f5fSchristos	mode.width = 1024;
91142542f5fSchristos	mode.height = 768;
91242542f5fSchristos	mode.name = mode_name;
91342542f5fSchristos	mode.nameLength = sizeof(mode_name) - 1;
91442542f5fSchristos
91542542f5fSchristos	if (id == 0)
91642542f5fSchristos		id = XRRCreateMode(dpy, display->root, &mode);
91742542f5fSchristos	XRRAddOutputMode(dpy, rr_output, id);
91842542f5fSchristos
91942542f5fSchristos	/* Force a redetection for the ddx to spot the new outputs */
92042542f5fSchristos	res = XRRGetScreenResources(dpy, display->root);
92142542f5fSchristos	if (res == NULL)
92242542f5fSchristos		goto out;
92342542f5fSchristos
92442542f5fSchristos	/* Some else may have interrupted us and installed that new mode! */
92542542f5fSchristos	output = XRRGetOutputInfo(dpy, res, rr_output);
92642542f5fSchristos	if (output) {
92742542f5fSchristos		disable_crtc(dpy, res, output->crtc);
92842542f5fSchristos		XRRFreeOutputInfo(output);
92942542f5fSchristos	}
93042542f5fSchristos	XRRFreeScreenResources(res);
93142542f5fSchristos
93242542f5fSchristos	XRRDeleteOutputMode(dpy, rr_output, id);
93342542f5fSchristos	XRRDestroyMode(dpy, id);
93442542f5fSchristos
93542542f5fSchristos	/* And hide it again */
93642542f5fSchristos	res = XRRGetScreenResources(dpy, display->root);
93742542f5fSchristos	if (res != NULL)
93842542f5fSchristos		XRRFreeScreenResources(res);
93942542f5fSchristosout:
94042542f5fSchristos	XUngrabServer(dpy);
94142542f5fSchristos
94242542f5fSchristos	return rr_output;
94342542f5fSchristos}
94442542f5fSchristos
94542542f5fSchristosstatic int stride_for_depth(int width, int depth)
94642542f5fSchristos{
94742542f5fSchristos	if (depth == 24)
94842542f5fSchristos		depth = 32;
94942542f5fSchristos	return ((width * depth + 7) / 8 + 3) & ~3;
95042542f5fSchristos}
95142542f5fSchristos
95242542f5fSchristosstatic void init_image(struct clone *clone)
95342542f5fSchristos{
95442542f5fSchristos	XImage *image = &clone->image;
95542542f5fSchristos	int ret;
95642542f5fSchristos
95742542f5fSchristos	image->width = clone->width;
95842542f5fSchristos	image->height = clone->height;
95942542f5fSchristos	image->format = ZPixmap;
96042542f5fSchristos	image->xoffset = 0;
96142542f5fSchristos	image->byte_order = LSBFirst;
96242542f5fSchristos	image->bitmap_unit = 32;
96342542f5fSchristos	image->bitmap_bit_order = LSBFirst;
96442542f5fSchristos	image->bitmap_pad = 32;
96542542f5fSchristos	image->data = clone->shm.shmaddr;
96642542f5fSchristos	image->bytes_per_line = stride_for_depth(clone->width, clone->depth);
96742542f5fSchristos	switch (clone->depth) {
96842542f5fSchristos	case 24:
96942542f5fSchristos		image->red_mask = 0xff << 16;
97042542f5fSchristos		image->green_mask = 0xff << 8;
97142542f5fSchristos		image->blue_mask = 0xff << 0;;
97242542f5fSchristos		image->depth = 24;
97342542f5fSchristos		image->bits_per_pixel = 32;
97442542f5fSchristos		break;
97542542f5fSchristos	case 16:
97642542f5fSchristos		image->red_mask = 0x1f << 11;
97742542f5fSchristos		image->green_mask = 0x3f << 5;
97842542f5fSchristos		image->blue_mask = 0x1f << 0;;
97942542f5fSchristos		image->depth = 16;
98042542f5fSchristos		image->bits_per_pixel = 16;
98142542f5fSchristos		break;
98242542f5fSchristos	}
98342542f5fSchristos
98442542f5fSchristos	ret = XInitImage(image);
98542542f5fSchristos	assert(ret);
98642542f5fSchristos	(void)ret;
98742542f5fSchristos}
98842542f5fSchristos
98942542f5fSchristosstatic int mode_height(const XRRModeInfo *mode, Rotation rotation)
99042542f5fSchristos{
99142542f5fSchristos	switch (rotation & 0xf) {
99242542f5fSchristos	case RR_Rotate_0:
99342542f5fSchristos	case RR_Rotate_180:
99442542f5fSchristos		return mode->height;
99542542f5fSchristos	case RR_Rotate_90:
99642542f5fSchristos	case RR_Rotate_270:
99742542f5fSchristos		return mode->width;
99842542f5fSchristos	default:
99942542f5fSchristos		return 0;
100042542f5fSchristos	}
100142542f5fSchristos}
100242542f5fSchristos
100342542f5fSchristosstatic int mode_width(const XRRModeInfo *mode, Rotation rotation)
100442542f5fSchristos{
100542542f5fSchristos	switch (rotation & 0xf) {
100642542f5fSchristos	case RR_Rotate_0:
100742542f5fSchristos	case RR_Rotate_180:
100842542f5fSchristos		return mode->width;
100942542f5fSchristos	case RR_Rotate_90:
101042542f5fSchristos	case RR_Rotate_270:
101142542f5fSchristos		return mode->height;
101242542f5fSchristos	default:
101342542f5fSchristos		return 0;
101442542f5fSchristos	}
101542542f5fSchristos}
101642542f5fSchristos
101742542f5fSchristosstatic void output_init_xfer(struct clone *clone, struct output *output)
101842542f5fSchristos{
101942542f5fSchristos	if (output->pixmap == None && output->use_shm_pixmap) {
102042542f5fSchristos		DBG(DRAW, ("%s-%s: creating shm pixmap\n", DisplayString(output->dpy), output->name));
102142542f5fSchristos		XSync(output->dpy, False);
102242542f5fSchristos		_x_error_occurred = 0;
102342542f5fSchristos
102442542f5fSchristos		output->pixmap = XShmCreatePixmap(output->dpy, output->window,
102542542f5fSchristos						  clone->shm.shmaddr, &output->shm,
102642542f5fSchristos						  clone->width, clone->height, clone->depth);
102742542f5fSchristos		if (output->pix_picture) {
102842542f5fSchristos			XRenderFreePicture(output->dpy, output->pix_picture);
102942542f5fSchristos			output->pix_picture = None;
103042542f5fSchristos		}
103142542f5fSchristos
103242542f5fSchristos		XSync(output->dpy, False);
103342542f5fSchristos		if (_x_error_occurred) {
103442542f5fSchristos			XFreePixmap(output->dpy, output->pixmap);
103542542f5fSchristos			output->pixmap = None;
103642542f5fSchristos			output->use_shm_pixmap = 0;
103742542f5fSchristos		}
103842542f5fSchristos	}
103942542f5fSchristos	if (output->use_render) {
104042542f5fSchristos		DBG(DRAW, ("%s-%s: creating picture\n", DisplayString(output->dpy), output->name));
104142542f5fSchristos		if (output->win_picture == None)
104242542f5fSchristos			output->win_picture = XRenderCreatePicture(output->dpy, output->window,
104342542f5fSchristos								   output->display->root_format, 0, NULL);
104442542f5fSchristos		if (output->pixmap == None)
104542542f5fSchristos			output->pixmap = XCreatePixmap(output->dpy, output->window,
104642542f5fSchristos						       clone->width, clone->height, clone->depth);
104742542f5fSchristos		if (output->pix_picture == None)
104842542f5fSchristos			output->pix_picture = XRenderCreatePicture(output->dpy, output->pixmap,
104942542f5fSchristos								   output->use_render, 0, NULL);
105042542f5fSchristos	}
105142542f5fSchristos
105242542f5fSchristos	if (output->gc == None) {
105342542f5fSchristos		XGCValues gcv;
105442542f5fSchristos
105542542f5fSchristos		DBG(DRAW, ("%s-%s: creating gc\n", DisplayString(output->dpy), output->name));
105642542f5fSchristos
105742542f5fSchristos		gcv.graphics_exposures = False;
105842542f5fSchristos		gcv.subwindow_mode = IncludeInferiors;
105942542f5fSchristos
106042542f5fSchristos		output->gc = XCreateGC(output->dpy, output->pixmap ?: output->window, GCGraphicsExposures | GCSubwindowMode, &gcv);
106142542f5fSchristos	}
106242542f5fSchristos}
106342542f5fSchristos
106442542f5fSchristosstatic int bpp_for_depth(int depth)
106542542f5fSchristos{
106642542f5fSchristos	switch (depth) {
106742542f5fSchristos	case 1: return 1;
106842542f5fSchristos	case 8: return 8;
106942542f5fSchristos	case 15: return 16;
107042542f5fSchristos	case 16: return 16;
107142542f5fSchristos	case 24: return 24;
107242542f5fSchristos	case 32: return 32;
107342542f5fSchristos	default: return 0;
107442542f5fSchristos	}
107542542f5fSchristos}
107642542f5fSchristos
107742542f5fSchristosstatic int clone_init_xfer(struct clone *clone)
107842542f5fSchristos{
107942542f5fSchristos	int width, height;
108042542f5fSchristos
108142542f5fSchristos	if (clone->dst.mode.id == 0) {
108213496ba1Ssnj		width = 0;
108313496ba1Ssnj		height = 0;
108442542f5fSchristos	} else if (clone->dri3.xid) {
108542542f5fSchristos		width = clone->dst.display->width;
108642542f5fSchristos		height = clone->dst.display->height;
108742542f5fSchristos	} else {
108842542f5fSchristos		width = mode_width(&clone->src.mode, clone->src.rotation);
108942542f5fSchristos		height = mode_height(&clone->src.mode, clone->src.rotation);
109042542f5fSchristos	}
109142542f5fSchristos
109242542f5fSchristos	if (width == clone->width && height == clone->height)
109342542f5fSchristos		return 0;
109442542f5fSchristos
109542542f5fSchristos	DBG(DRAW, ("%s-%s create xfer, %dx%d\n",
109642542f5fSchristos	     DisplayString(clone->dst.dpy), clone->dst.name,
109742542f5fSchristos	     width, height));
109842542f5fSchristos
109942542f5fSchristos	if (clone->shm.shmaddr) {
110042542f5fSchristos		if (clone->src.use_shm)
110142542f5fSchristos			XShmDetach(clone->src.dpy, &clone->src.shm);
110242542f5fSchristos		if (clone->dst.use_shm)
110342542f5fSchristos			XShmDetach(clone->dst.dpy, &clone->dst.shm);
110442542f5fSchristos
110542542f5fSchristos		shmdt(clone->shm.shmaddr);
110642542f5fSchristos		clone->shm.shmaddr = NULL;
110742542f5fSchristos	}
110842542f5fSchristos
110942542f5fSchristos	if (clone->src.pixmap) {
111042542f5fSchristos		XFreePixmap(clone->src.dpy, clone->src.pixmap);
111142542f5fSchristos		clone->src.pixmap = 0;
111242542f5fSchristos	}
111342542f5fSchristos
111442542f5fSchristos	if (clone->dst.pixmap) {
111542542f5fSchristos		XFreePixmap(clone->dst.dpy, clone->dst.pixmap);
111642542f5fSchristos		clone->dst.pixmap = 0;
111742542f5fSchristos	}
111842542f5fSchristos
111942542f5fSchristos	if ((width | height) == 0) {
112042542f5fSchristos		clone->damaged.x2 = clone->damaged.y2 = INT_MIN;
112142542f5fSchristos		clone->damaged.x1 = clone->damaged.y1 = INT_MAX;
112242542f5fSchristos		return 0;
112342542f5fSchristos	}
112442542f5fSchristos
112542542f5fSchristos	if (clone->dri3.xid) {
112642542f5fSchristos		int fd, stride;
112742542f5fSchristos		Pixmap src;
112842542f5fSchristos
112942542f5fSchristos		_x_error_occurred = 0;
113042542f5fSchristos
113142542f5fSchristos		DBG(DRAW, ("%s-%s create xfer, trying DRI3\n",
113242542f5fSchristos		     DisplayString(clone->dst.dpy), clone->dst.name));
113342542f5fSchristos
113442542f5fSchristos		fd = dri3_create_fd(clone->dst.dpy, clone->dst.window, &stride);
113542542f5fSchristos		if (fd < 0)
113642542f5fSchristos			goto disable_dri3;
113742542f5fSchristos
113842542f5fSchristos		DBG(DRAW, ("%s-%s create xfer, DRI3 fd=%d, stride=%d\n",
113942542f5fSchristos		     DisplayString(clone->dst.dpy), clone->dst.name,
114042542f5fSchristos		     fd, stride));
114142542f5fSchristos
114242542f5fSchristos		src = dri3_create_pixmap(clone->src.dpy, clone->src.window,
114342542f5fSchristos					 width, height, clone->depth,
114442542f5fSchristos					 fd, bpp_for_depth(clone->depth),
114542542f5fSchristos					 stride, lseek(fd, 0, SEEK_END));
114642542f5fSchristos
114742542f5fSchristos		XSync(clone->src.dpy, False);
114842542f5fSchristos		if (!_x_error_occurred) {
114942542f5fSchristos			clone->src.pixmap = src;
115042542f5fSchristos			clone->width = width;
115142542f5fSchristos			clone->height = height;
115242542f5fSchristos		} else {
115342542f5fSchristos			XFreePixmap(clone->src.dpy, src);
115442542f5fSchristos			close(fd);
115542542f5fSchristosdisable_dri3:
115642542f5fSchristos			dri3_fence_free(clone->src.dpy, &clone->dri3);
115742542f5fSchristos			clone->dri3.xid = 0;
115842542f5fSchristos
115942542f5fSchristos			DBG(DRAW, ("%s-%s create xfer, DRI3 failed\n",
116042542f5fSchristos			     DisplayString(clone->dst.dpy), clone->dst.name));
116142542f5fSchristos		}
116242542f5fSchristos	}
116342542f5fSchristos
116442542f5fSchristos	width = mode_width(&clone->src.mode, clone->src.rotation);
116542542f5fSchristos	height = mode_height(&clone->src.mode, clone->src.rotation);
116642542f5fSchristos
116742542f5fSchristos	if (!clone->dri3.xid) {
116842542f5fSchristos		DBG(DRAW, ("%s-%s create xfer, trying SHM\n",
116942542f5fSchristos		     DisplayString(clone->dst.dpy), clone->dst.name));
117042542f5fSchristos
117142542f5fSchristos		clone->shm.shmid = shmget(IPC_PRIVATE,
117242542f5fSchristos					  height * stride_for_depth(width, clone->depth),
117342542f5fSchristos					  IPC_CREAT | 0666);
117442542f5fSchristos		if (clone->shm.shmid == -1)
117542542f5fSchristos			return errno;
117642542f5fSchristos
117742542f5fSchristos		clone->shm.shmaddr = shmat(clone->shm.shmid, 0, 0);
117842542f5fSchristos		if (clone->shm.shmaddr == (char *) -1) {
117942542f5fSchristos			shmctl(clone->shm.shmid, IPC_RMID, NULL);
118042542f5fSchristos			return ENOMEM;
118142542f5fSchristos		}
118242542f5fSchristos
118342542f5fSchristos		if (clone->src.use_shm) {
118442542f5fSchristos			clone->src.shm = clone->shm;
118542542f5fSchristos			clone->src.shm.readOnly = False;
118642542f5fSchristos			XShmAttach(clone->src.dpy, &clone->src.shm);
118742542f5fSchristos			XSync(clone->src.dpy, False);
118842542f5fSchristos		}
118942542f5fSchristos		if (clone->dst.use_shm) {
119042542f5fSchristos			clone->dst.shm = clone->shm;
119142542f5fSchristos			clone->dst.shm.readOnly = !clone->dst.use_shm_pixmap;
119242542f5fSchristos			XShmAttach(clone->dst.dpy, &clone->dst.shm);
119342542f5fSchristos			XSync(clone->dst.dpy, False);
119442542f5fSchristos		}
119542542f5fSchristos
119642542f5fSchristos		shmctl(clone->shm.shmid, IPC_RMID, NULL);
119742542f5fSchristos
119842542f5fSchristos		clone->width = width;
119942542f5fSchristos		clone->height = height;
120042542f5fSchristos
120142542f5fSchristos		init_image(clone);
120242542f5fSchristos	}
120342542f5fSchristos
120442542f5fSchristos	output_init_xfer(clone, &clone->src);
120542542f5fSchristos	output_init_xfer(clone, &clone->dst);
120642542f5fSchristos
120742542f5fSchristos	clone->damaged.x1 = clone->src.x;
120842542f5fSchristos	clone->damaged.x2 = clone->src.x + width;
120942542f5fSchristos	clone->damaged.y1 = clone->src.y;
121042542f5fSchristos	clone->damaged.y2 = clone->src.y + height;
121142542f5fSchristos
121242542f5fSchristos	display_mark_flush(clone->dst.display);
121342542f5fSchristos	return 0;
121442542f5fSchristos}
121542542f5fSchristos
121642542f5fSchristosstatic void clone_update(struct clone *clone)
121742542f5fSchristos{
121842542f5fSchristos	if (!clone->rr_update)
121942542f5fSchristos		return;
122042542f5fSchristos
122142542f5fSchristos	DBG(X11, ("%s-%s cloning modes\n",
122242542f5fSchristos	     DisplayString(clone->dst.dpy), clone->dst.name));
122342542f5fSchristos
122442542f5fSchristos	clone_update_modes__randr(clone);
122542542f5fSchristos	clone->rr_update = 0;
122642542f5fSchristos}
122742542f5fSchristos
122842542f5fSchristosstatic int context_update(struct context *ctx)
122942542f5fSchristos{
123042542f5fSchristos	Display *dpy = ctx->display->dpy;
123142542f5fSchristos	XRRScreenResources *res;
123242542f5fSchristos	int context_changed = 0;
123342542f5fSchristos	int i, n;
123442542f5fSchristos
123542542f5fSchristos	DBG(X11, ("%s\n", __func__));
123642542f5fSchristos
123742542f5fSchristos	res = _XRRGetScreenResourcesCurrent(dpy, ctx->display->root);
123842542f5fSchristos	if (res == NULL)
123942542f5fSchristos		return 0;
124042542f5fSchristos
124142542f5fSchristos	DBG(XRR, ("%s timestamp %ld (last %ld), config %ld (last %ld)\n",
124242542f5fSchristos	     DisplayString(dpy),
124342542f5fSchristos	     res->timestamp, ctx->timestamp,
124442542f5fSchristos	     res->configTimestamp, ctx->configTimestamp));
124542542f5fSchristos	if (res->timestamp == ctx->timestamp &&
124642542f5fSchristos	    res->configTimestamp == ctx->configTimestamp &&
124742542f5fSchristos	    res->timestamp != res->configTimestamp) { /* mutter be damned */
124842542f5fSchristos		XRRFreeScreenResources(res);
124942542f5fSchristos		return 0;
125042542f5fSchristos	}
125142542f5fSchristos
125242542f5fSchristos	ctx->timestamp = res->timestamp;
125342542f5fSchristos	ctx->configTimestamp = res->configTimestamp;
125442542f5fSchristos
125542542f5fSchristos	for (n = 0; n < ctx->nclone; n++) {
125642542f5fSchristos		struct output *output = &ctx->clones[n].src;
125742542f5fSchristos		XRROutputInfo *o;
125842542f5fSchristos		XRRCrtcInfo *c;
125942542f5fSchristos		RRMode mode = 0;
126042542f5fSchristos		int changed = 0;
126142542f5fSchristos
126242542f5fSchristos		o = XRRGetOutputInfo(dpy, res, output->rr_output);
126342542f5fSchristos		if (o == NULL)
126442542f5fSchristos			continue;
126542542f5fSchristos
126642542f5fSchristos		c = NULL;
126742542f5fSchristos		if (o->crtc)
126842542f5fSchristos			c = XRRGetCrtcInfo(dpy, res, o->crtc);
126942542f5fSchristos		if (c) {
127042542f5fSchristos			DBG(XRR, ("%s-%s: (x=%d, y=%d, rotation=%d, mode=%ld) -> (x=%d, y=%d, rotation=%d, mode=%ld)\n",
127142542f5fSchristos			     DisplayString(dpy), output->name,
127242542f5fSchristos			     output->x, output->y, output->rotation, output->mode.id,
127342542f5fSchristos			     c->x, c->y, c->rotation, c->mode));
127442542f5fSchristos
127542542f5fSchristos			changed |= output->rotation != c->rotation;
127642542f5fSchristos			output->rotation = c->rotation;
127742542f5fSchristos
127842542f5fSchristos			changed |= output->x != c->x;
127942542f5fSchristos			output->x = c->x;
128042542f5fSchristos
128142542f5fSchristos			changed |= output->y != c->y;
128242542f5fSchristos			output->y = c->y;
128342542f5fSchristos
128442542f5fSchristos			changed |= output->mode.id != c->mode;
128542542f5fSchristos			mode = c->mode;
128642542f5fSchristos			XRRFreeCrtcInfo(c);
128742542f5fSchristos		} else {
128842542f5fSchristos			DBG(XRR, ("%s-%s: (x=%d, y=%d, rotation=%d, mode=%ld) -> off\n",
128942542f5fSchristos			     DisplayString(dpy), output->name,
129042542f5fSchristos			     output->x, output->y, output->rotation, output->mode.id));
129142542f5fSchristos		}
129242542f5fSchristos		output->rr_crtc = o->crtc;
129342542f5fSchristos		XRRFreeOutputInfo(o);
129442542f5fSchristos
129542542f5fSchristos		DBG(XRR, ("%s-%s crtc changed? %d\n",
129642542f5fSchristos		     DisplayString(ctx->clones[n].dst.display->dpy), ctx->clones[n].dst.name, changed));
129742542f5fSchristos
129842542f5fSchristos		if (mode) {
129942542f5fSchristos			if (output->mode.id != mode) {
130042542f5fSchristos				for (i = 0; i < res->nmode; i++) {
130142542f5fSchristos					if (res->modes[i].id == mode) {
130242542f5fSchristos						output->mode = res->modes[i];
130342542f5fSchristos						break;
130442542f5fSchristos					}
130542542f5fSchristos				}
130642542f5fSchristos			}
130742542f5fSchristos		} else {
130842542f5fSchristos			changed = output->mode.id != 0;
130942542f5fSchristos			output->mode.id = 0;
131042542f5fSchristos		}
131142542f5fSchristos
131242542f5fSchristos		DBG(XRR, ("%s-%s output changed? %d\n",
131342542f5fSchristos		     DisplayString(ctx->clones[n].dst.display->dpy), ctx->clones[n].dst.name, changed));
131442542f5fSchristos
131542542f5fSchristos		context_changed |= changed;
131642542f5fSchristos	}
131742542f5fSchristos	XRRFreeScreenResources(res);
131842542f5fSchristos
131942542f5fSchristos	DBG(XRR, ("%s changed? %d\n", DisplayString(dpy), context_changed));
132042542f5fSchristos	if (!context_changed)
132142542f5fSchristos		return 0;
132242542f5fSchristos
132342542f5fSchristos	for (n = 1; n < ctx->ndisplay; n++) {
132442542f5fSchristos		struct display *display = &ctx->display[n];
132542542f5fSchristos		struct clone *clone;
132642542f5fSchristos		int x1, x2, y1, y2;
132742542f5fSchristos
132842542f5fSchristos		if (display->rr_active == 0)
132942542f5fSchristos			continue;
133042542f5fSchristos
133142542f5fSchristos		x1 = y1 = INT_MAX;
133242542f5fSchristos		x2 = y2 = INT_MIN;
133342542f5fSchristos
133442542f5fSchristos		for (clone = display->clone; clone; clone = clone->next) {
133542542f5fSchristos			struct output *output = &clone->src;
133642542f5fSchristos			int v;
133742542f5fSchristos
133842542f5fSchristos			assert(clone->dst.display == display);
133942542f5fSchristos
134042542f5fSchristos			if (output->mode.id == 0)
134142542f5fSchristos				continue;
134242542f5fSchristos
134342542f5fSchristos			DBG(XRR, ("%s: source %s enabled (%d, %d)x(%d, %d)\n",
134442542f5fSchristos			     DisplayString(clone->dst.dpy), output->name,
134542542f5fSchristos			     output->x, output->y,
134642542f5fSchristos			     mode_width(&output->mode, output->rotation),
134742542f5fSchristos			     mode_height(&output->mode, output->rotation)));
134842542f5fSchristos
134942542f5fSchristos			if (output->x < x1)
135042542f5fSchristos				x1 = output->x;
135142542f5fSchristos			if (output->y < y1)
135242542f5fSchristos				y1 = output->y;
135342542f5fSchristos
135442542f5fSchristos			v = (int)output->x + mode_width(&output->mode, output->rotation);
135542542f5fSchristos			if (v > x2)
135642542f5fSchristos				x2 = v;
135742542f5fSchristos			v = (int)output->y + mode_height(&output->mode, output->rotation);
135842542f5fSchristos			if (v > y2)
135942542f5fSchristos				y2 = v;
136042542f5fSchristos		}
136142542f5fSchristos
136242542f5fSchristos		DBG(XRR, ("%s fb bounds (%d, %d)x(%d, %d)\n", DisplayString(display->dpy),
136342542f5fSchristos		     x1, y1, x2, y2));
136442542f5fSchristos
136542542f5fSchristos		XGrabServer(display->dpy);
136642542f5fSchristos		res = _XRRGetScreenResourcesCurrent(display->dpy, display->root);
136742542f5fSchristos		if (res == NULL)
136842542f5fSchristos			goto ungrab;
136942542f5fSchristos
137042542f5fSchristos		if (x2 <= x1 || y2 <= y1) {
137142542f5fSchristos			/* Nothing enabled, preserve the current fb, and turn everything off */
137242542f5fSchristos			for (clone = display->clone; clone; clone = clone->next) {
137342542f5fSchristos				struct output *dst = &clone->dst;
137442542f5fSchristos
137542542f5fSchristos				if (!dst->rr_crtc)
137642542f5fSchristos					continue;
137742542f5fSchristos
137842542f5fSchristos				DBG(XRR, ("%s: disabling output '%s'\n",
137942542f5fSchristos				     DisplayString(display->dpy), dst->name));
138042542f5fSchristos				assert(clone->dst.display == display);
138142542f5fSchristos				if (disable_crtc(display->dpy, res, dst->rr_crtc)) {
138242542f5fSchristos					dst->rr_crtc = 0;
138342542f5fSchristos					dst->mode.id = 0;
138442542f5fSchristos				}
138542542f5fSchristos			}
138642542f5fSchristos			goto free_res;
138742542f5fSchristos		}
138842542f5fSchristos
138942542f5fSchristos		x2 -= x1;
139042542f5fSchristos		y2 -= y1;
139142542f5fSchristos		DBG(XRR, ("%s: current size %dx%d, need %dx%d\n",
139242542f5fSchristos		     DisplayString(display->dpy),
139342542f5fSchristos		     display->width, display->height,
139442542f5fSchristos		     x2, y2));
139542542f5fSchristos
139642542f5fSchristos		if (display->width != x2 || display->height != y2) {
139742542f5fSchristos			/* When shrinking we have to manually resize the fb */
139842542f5fSchristos			for (clone = display->clone; clone; clone = clone->next) {
139942542f5fSchristos				struct output *dst = &clone->dst;
140042542f5fSchristos
140142542f5fSchristos				if (!dst->rr_crtc)
140242542f5fSchristos					continue;
140342542f5fSchristos
140442542f5fSchristos				DBG(XRR, ("%s: disabling output '%s'\n",
140542542f5fSchristos				     DisplayString(display->dpy), dst->name));
140642542f5fSchristos				assert(clone->dst.display == display);
140742542f5fSchristos				if (disable_crtc(display->dpy, res, dst->rr_crtc)) {
140842542f5fSchristos					dst->rr_crtc = 0;
140942542f5fSchristos					dst->mode.id = 0;
141042542f5fSchristos				}
141142542f5fSchristos			}
141242542f5fSchristos
141342542f5fSchristos			DBG(XRR, ("%s: XRRSetScreenSize %dx%d\n", DisplayString(display->dpy), x2, y2));
141442542f5fSchristos			XRRSetScreenSize(display->dpy, display->root, x2, y2, x2 * 96 / 25.4, y2 * 96 / 25.4);
141542542f5fSchristos			display->width = x2;
141642542f5fSchristos			display->height = y2;
141742542f5fSchristos		}
141842542f5fSchristos
141942542f5fSchristos		for (clone = display->clone; clone; clone = clone->next) {
142042542f5fSchristos			struct output *src = &clone->src;
142142542f5fSchristos			struct output *dst = &clone->dst;
142242542f5fSchristos			XRROutputInfo *o;
142342542f5fSchristos			XRRPanning panning;
142442542f5fSchristos			struct clone *set;
142542542f5fSchristos			RRCrtc rr_crtc;
142642542f5fSchristos			Status ret;
142742542f5fSchristos
142842542f5fSchristos			DBG(XRR, ("%s: copying configuration from %s (mode=%ld: %dx%d) to %s\n",
142942542f5fSchristos			     DisplayString(display->dpy),
143042542f5fSchristos			     src->name, (long)src->mode.id, src->mode.width, src->mode.height,
143142542f5fSchristos			     dst->name));
143242542f5fSchristos
143342542f5fSchristos			if (src->mode.id == 0) {
143442542f5fSchristoserr:
143542542f5fSchristos				if (dst->rr_crtc) {
143642542f5fSchristos					DBG(XRR, ("%s: disabling unused output '%s'\n",
143742542f5fSchristos					     DisplayString(display->dpy), dst->name));
143842542f5fSchristos					assert(clone->dst.display == display);
143942542f5fSchristos					if (disable_crtc(display->dpy, res, dst->rr_crtc)) {
144042542f5fSchristos						dst->rr_crtc = 0;
144142542f5fSchristos						dst->mode.id = 0;
144242542f5fSchristos					}
144342542f5fSchristos				}
144442542f5fSchristos				continue;
144542542f5fSchristos			}
144642542f5fSchristos
144742542f5fSchristos			dst->x = src->x - x1;
144842542f5fSchristos			dst->y = src->y - y1;
144942542f5fSchristos			dst->rotation = src->rotation;
145042542f5fSchristos			dst->mode = src->mode;
145142542f5fSchristos
145242542f5fSchristos			dst->mode.id = 0;
145342542f5fSchristos			for (i = 0; i < res->nmode; i++) {
145442542f5fSchristos				if (mode_equal(&src->mode, &res->modes[i])) {
145542542f5fSchristos					dst->mode.id = res->modes[i].id;
145642542f5fSchristos					break;
145742542f5fSchristos				}
145842542f5fSchristos			}
145942542f5fSchristos			if (dst->mode.id == 0) {
146042542f5fSchristos				XRRModeInfo m;
146142542f5fSchristos				char buf[256];
146242542f5fSchristos				RRMode id;
146342542f5fSchristos
146442542f5fSchristos				/* XXX User names must be unique! */
146542542f5fSchristos				m = src->mode;
146642542f5fSchristos				m.nameLength = snprintf(buf, sizeof(buf),
146742542f5fSchristos							"%s.%ld-%dx%d", src->name,
146842542f5fSchristos							(long)src->mode.id,
146942542f5fSchristos							src->mode.width,
147042542f5fSchristos							src->mode.height);
147142542f5fSchristos				m.name = buf;
147242542f5fSchristos
147342542f5fSchristos				id = XRRCreateMode(dst->dpy, dst->window, &m);
147442542f5fSchristos				if (id) {
147542542f5fSchristos					DBG(XRR, ("%s: adding mode %ld: %dx%d to %s, new mode %ld\n",
147642542f5fSchristos					     DisplayString(dst->dpy),
147742542f5fSchristos					     (long)src->mode.id,
147842542f5fSchristos					     src->mode.width,
147942542f5fSchristos					     src->mode.height,
148042542f5fSchristos					     dst->name, (long)id));
148142542f5fSchristos					XRRAddOutputMode(dst->dpy, dst->rr_output, id);
148242542f5fSchristos					dst->mode.id = id;
148342542f5fSchristos				} else {
148442542f5fSchristos					DBG(XRR, ("%s: failed to find suitable mode for %s\n",
148542542f5fSchristos					     DisplayString(dst->dpy), dst->name));
148642542f5fSchristos					goto err;
148742542f5fSchristos				}
148842542f5fSchristos			}
148942542f5fSchristos
149042542f5fSchristos			rr_crtc = dst->rr_crtc;
149142542f5fSchristos			if (rr_crtc) {
149242542f5fSchristos				for (set = display->clone; set != clone; set = set->next) {
149342542f5fSchristos					if (set->dst.rr_crtc == rr_crtc) {
149442542f5fSchristos						DBG(XRR, ("%s: CRTC reassigned from %s\n",
149542542f5fSchristos						     DisplayString(dst->dpy), dst->name));
149642542f5fSchristos						rr_crtc = 0;
149742542f5fSchristos						break;
149842542f5fSchristos					}
149942542f5fSchristos				}
150042542f5fSchristos			}
150142542f5fSchristos			if (rr_crtc == 0) {
150242542f5fSchristos				o = XRRGetOutputInfo(dst->dpy, res, dst->rr_output);
150342542f5fSchristos				for (i = 0; i < o->ncrtc; i++) {
150442542f5fSchristos					DBG(XRR, ("%s: checking whether CRTC:%ld is available\n",
150542542f5fSchristos					     DisplayString(dst->dpy), (long)o->crtcs[i]));
150642542f5fSchristos					for (set = display->clone; set != clone; set = set->next) {
150742542f5fSchristos						if (set->dst.rr_crtc == o->crtcs[i]) {
150842542f5fSchristos							DBG(XRR, ("%s: CRTC:%ld already assigned to %s\n",
150942542f5fSchristos							     DisplayString(dst->dpy), (long)o->crtcs[i], set->dst.name));
151042542f5fSchristos							break;
151142542f5fSchristos						}
151242542f5fSchristos					}
151342542f5fSchristos					if (set == clone) {
151442542f5fSchristos						rr_crtc = o->crtcs[i];
151542542f5fSchristos						break;
151642542f5fSchristos					}
151742542f5fSchristos				}
151842542f5fSchristos				XRRFreeOutputInfo(o);
151942542f5fSchristos			}
152042542f5fSchristos			if (rr_crtc == 0) {
152142542f5fSchristos				DBG(XRR, ("%s: failed to find available CRTC for %s\n",
152242542f5fSchristos				     DisplayString(dst->dpy), dst->name));
152342542f5fSchristos				goto err;
152442542f5fSchristos			}
152542542f5fSchristos
152642542f5fSchristos			DBG(XRR, ("%s: enabling output '%s' (%d,%d)x(%d,%d), rotation %d, on CRTC:%ld, using mode %ld\n",
152742542f5fSchristos			     DisplayString(dst->dpy), dst->name,
152842542f5fSchristos			     dst->x, dst->y, dst->mode.width, dst->mode.height,
152942542f5fSchristos			     dst->rotation, (long)rr_crtc, dst->mode.id));
153042542f5fSchristos
153142542f5fSchristos			ret = XRRSetPanning(dst->dpy, res, rr_crtc, memset(&panning, 0, sizeof(panning)));
153242542f5fSchristos			DBG(XRR, ("%s-%s: XRRSetPanning %s\n", DisplayString(dst->dpy), dst->name, ret ? "failed" : "success"));
153342542f5fSchristos			(void)ret;
153442542f5fSchristos
153542542f5fSchristos			ret = XRRSetCrtcConfig(dst->dpy, res, rr_crtc, CurrentTime,
153642542f5fSchristos					       dst->x, dst->y, dst->mode.id, dst->rotation,
153742542f5fSchristos					       &dst->rr_output, 1);
153842542f5fSchristos			DBG(XRR, ("%s-%s: XRRSetCrtcConfig %s\n", DisplayString(dst->dpy), dst->name, ret ? "failed" : "success"));
153942542f5fSchristos			if (ret)
154042542f5fSchristos				goto err;
154142542f5fSchristos
154242542f5fSchristos			if (verbose & XRR) {
154342542f5fSchristos				XRRCrtcInfo *c;
154442542f5fSchristos				XRRPanning *p;
154542542f5fSchristos
154642542f5fSchristos				c = XRRGetCrtcInfo(dst->dpy, res, rr_crtc);
154742542f5fSchristos				if (c) {
154842542f5fSchristos					DBG(XRR, ("%s-%s: x=%d, y=%d, rotation=%d, mode=%ld\n",
154942542f5fSchristos					     DisplayString(dst->dpy), dst->name,
155042542f5fSchristos					     c->x, c->y, c->rotation, c->mode));
155142542f5fSchristos					XRRFreeCrtcInfo(c);
155242542f5fSchristos				}
155342542f5fSchristos
155442542f5fSchristos				p = XRRGetPanning(dst->dpy, res, rr_crtc);
155542542f5fSchristos				if (p) {
155642542f5fSchristos					DBG(XRR, ("%s-%s: panning (%d, %d)x(%d, %d), tracking (%d, %d)x(%d, %d), border (%d, %d),(%d, %d)\n",
155742542f5fSchristos					     DisplayString(dst->dpy), dst->name,
155842542f5fSchristos					     p->left, p->top, p->width, p->height,
155942542f5fSchristos					     p->track_left, p->track_top, p->track_width, p->track_height,
156042542f5fSchristos					     p->border_left, p->border_top, p->border_right, p->border_bottom));
156142542f5fSchristos					XRRFreePanning(p);
156242542f5fSchristos				}
156342542f5fSchristos			}
156442542f5fSchristos
156542542f5fSchristos			dst->rr_crtc = rr_crtc;
156642542f5fSchristos		}
156742542f5fSchristosfree_res:
156842542f5fSchristos		XRRFreeScreenResources(res);
156942542f5fSchristosungrab:
157042542f5fSchristos		XUngrabServer(display->dpy);
157142542f5fSchristos	}
157242542f5fSchristos
157342542f5fSchristos	ctx->active = NULL;
157442542f5fSchristos	for (n = 0; n < ctx->nclone; n++) {
157542542f5fSchristos		struct clone *clone = &ctx->clones[n];
157642542f5fSchristos
157742542f5fSchristos		clone_init_xfer(clone);
157842542f5fSchristos
157942542f5fSchristos		if (clone->dst.rr_crtc == 0)
158042542f5fSchristos			continue;
158142542f5fSchristos
158242542f5fSchristos		DBG(XRR, ("%s-%s: added to active list\n",
158342542f5fSchristos		     DisplayString(clone->dst.display->dpy), clone->dst.name));
158442542f5fSchristos
158542542f5fSchristos		clone->active = ctx->active;
158642542f5fSchristos		ctx->active = clone;
158742542f5fSchristos	}
158842542f5fSchristos
158942542f5fSchristos	return 1;
159042542f5fSchristos}
159142542f5fSchristos
159242542f5fSchristosstatic Cursor display_load_invisible_cursor(struct display *display)
159342542f5fSchristos{
159442542f5fSchristos	char zero[8] = {};
159542542f5fSchristos	XColor black = {};
159642542f5fSchristos	Pixmap bitmap = XCreateBitmapFromData(display->dpy, display->root, zero, 8, 8);
159742542f5fSchristos	return XCreatePixmapCursor(display->dpy, bitmap, bitmap, &black, &black, 0, 0);
159842542f5fSchristos}
159942542f5fSchristos
160042542f5fSchristosstatic Cursor display_get_visible_cursor(struct display *display)
160142542f5fSchristos{
160242542f5fSchristos	if (display->cursor_serial != display->cursor_image.size) {
160342542f5fSchristos		DBG(CURSOR, ("%s updating cursor\n", DisplayString(display->dpy)));
160442542f5fSchristos
160542542f5fSchristos		if (display->visible_cursor)
160642542f5fSchristos			XFreeCursor(display->dpy, display->visible_cursor);
160742542f5fSchristos
160842542f5fSchristos		display->visible_cursor = XcursorImageLoadCursor(display->dpy, &display->cursor_image);
160942542f5fSchristos		display->cursor_serial = display->cursor_image.size;
161042542f5fSchristos	}
161142542f5fSchristos
161242542f5fSchristos	return display->visible_cursor;
161342542f5fSchristos}
161442542f5fSchristos
161542542f5fSchristosstatic void display_load_visible_cursor(struct display *display, XFixesCursorImage *cur)
161642542f5fSchristos{
161742542f5fSchristos	unsigned long *src; /* XXX deep sigh */
161842542f5fSchristos	XcursorPixel *dst;
161942542f5fSchristos	unsigned n;
162042542f5fSchristos
162142542f5fSchristos	if (cur->width != display->cursor_image.width ||
162242542f5fSchristos	    cur->height != display->cursor_image.height)
162342542f5fSchristos		display->cursor_image.pixels = realloc(display->cursor_image.pixels,
162442542f5fSchristos						       4 * cur->width * cur->height);
162542542f5fSchristos	if (display->cursor_image.pixels == NULL)
162642542f5fSchristos		return;
162742542f5fSchristos
162842542f5fSchristos	display->cursor_image.width  = cur->width;
162942542f5fSchristos	display->cursor_image.height = cur->height;
163042542f5fSchristos	display->cursor_image.xhot = cur->xhot;
163142542f5fSchristos	display->cursor_image.yhot = cur->yhot;
163242542f5fSchristos	display->cursor_image.size++;
163342542f5fSchristos
163442542f5fSchristos	n = cur->width*cur->height;
163542542f5fSchristos	src = cur->pixels;
163642542f5fSchristos	dst = display->cursor_image.pixels;
163742542f5fSchristos	while (n--)
163842542f5fSchristos		*dst++ = *src++;
163942542f5fSchristos
164042542f5fSchristos	DBG(CURSOR, ("%s marking cursor changed\n", DisplayString(display->dpy)));
164142542f5fSchristos	display->cursor_moved++;
164242542f5fSchristos	if (display->cursor != display->invisible_cursor) {
164342542f5fSchristos		display->cursor_visible++;
164442542f5fSchristos		context_enable_timer(display->ctx);
164542542f5fSchristos	}
164642542f5fSchristos}
164742542f5fSchristos
164842542f5fSchristosstatic void display_cursor_move(struct display *display, int x, int y, int visible)
164942542f5fSchristos{
165042542f5fSchristos	DBG(CURSOR, ("%s cursor moved (visible=%d, (%d, %d))\n",
165142542f5fSchristos	     DisplayString(display->dpy), visible, x, y));
165242542f5fSchristos	display->cursor_moved++;
165342542f5fSchristos	display->cursor_visible += visible;
165442542f5fSchristos	if (visible) {
165542542f5fSchristos		display->cursor_x = x;
165642542f5fSchristos		display->cursor_y = y;
165742542f5fSchristos	}
165842542f5fSchristos
165942542f5fSchristos	context_enable_timer(display->ctx);
166042542f5fSchristos}
166142542f5fSchristos
166242542f5fSchristosstatic void display_flush_cursor(struct display *display)
166342542f5fSchristos{
166442542f5fSchristos	Cursor cursor;
166542542f5fSchristos	int x, y;
166642542f5fSchristos
166742542f5fSchristos	if (!display->cursor_moved)
166842542f5fSchristos		return;
166942542f5fSchristos
167042542f5fSchristos	if (display->cursor_visible) {
167142542f5fSchristos		x = display->cursor_x;
167242542f5fSchristos		y = display->cursor_y;
167342542f5fSchristos	} else {
167442542f5fSchristos		x = display->cursor_x++ & 31;
167542542f5fSchristos		y = display->cursor_y++ & 31;
167642542f5fSchristos	}
167742542f5fSchristos
167842542f5fSchristos	DBG(CURSOR, ("%s setting cursor position (%d, %d), visible? %d\n",
167942542f5fSchristos	     DisplayString(display->dpy), x, y, display->cursor_visible));
168042542f5fSchristos	XWarpPointer(display->dpy, None, display->root, 0, 0, 0, 0, x, y);
168142542f5fSchristos
168242542f5fSchristos	cursor = None;
168342542f5fSchristos	if (display->cursor_visible)
168442542f5fSchristos		cursor = display_get_visible_cursor(display);
168542542f5fSchristos	if (cursor == None)
168642542f5fSchristos		cursor = display->invisible_cursor;
168742542f5fSchristos	if (cursor != display->cursor) {
168842542f5fSchristos		XDefineCursor(display->dpy, display->root, cursor);
168942542f5fSchristos		display->cursor = cursor;
169042542f5fSchristos	}
169142542f5fSchristos
169242542f5fSchristos	display_mark_flush(display);
169342542f5fSchristos
169442542f5fSchristos	display->cursor_moved = 0;
169542542f5fSchristos	display->cursor_visible = 0;
169642542f5fSchristos}
169742542f5fSchristos
169842542f5fSchristosstatic void clone_move_cursor(struct clone *c, int x, int y)
169942542f5fSchristos{
170042542f5fSchristos	int visible;
170142542f5fSchristos
170242542f5fSchristos	DBG(CURSOR, ("%s-%s moving cursor (%d, %d) [(%d, %d), (%d, %d)]\n",
170342542f5fSchristos	     DisplayString(c->dst.dpy), c->dst.name,
170442542f5fSchristos	     x, y,
170542542f5fSchristos	     c->src.x, c->src.y,
170642542f5fSchristos	     c->src.x + c->width, c->src.y + c->height));
170742542f5fSchristos
170842542f5fSchristos	visible = (x >= c->src.x && x < c->src.x + c->width &&
170942542f5fSchristos		   y >= c->src.y && y < c->src.y + c->height);
171042542f5fSchristos
171142542f5fSchristos	x += c->dst.x - c->src.x;
171242542f5fSchristos	y += c->dst.y - c->src.y;
171342542f5fSchristos
171442542f5fSchristos	display_cursor_move(c->dst.display, x, y, visible);
171542542f5fSchristos}
171642542f5fSchristos
171742542f5fSchristosstatic int clone_output_init(struct clone *clone, struct output *output,
171842542f5fSchristos			     struct display *display, const char *name,
171942542f5fSchristos			     RROutput rr_output)
172042542f5fSchristos{
172142542f5fSchristos	Display *dpy = display->dpy;
172242542f5fSchristos	int depth;
172342542f5fSchristos
172442542f5fSchristos	DBG(X11, ("%s(%s, %s)\n", __func__, DisplayString(dpy), name));
172542542f5fSchristos
172642542f5fSchristos	output->name = strdup(name);
172742542f5fSchristos	if (output->name == NULL)
172842542f5fSchristos		return -ENOMEM;
172942542f5fSchristos
173042542f5fSchristos	output->display = display;
173142542f5fSchristos	output->dpy = dpy;
173242542f5fSchristos
173342542f5fSchristos	output->rr_output = rr_output;
173442542f5fSchristos	output->rotation = RR_Rotate_0;
173542542f5fSchristos
173642542f5fSchristos	output->window = display->root;
173742542f5fSchristos	output->use_shm = display->has_shm;
173842542f5fSchristos	output->use_shm_pixmap = display->has_shm_pixmap;
173942542f5fSchristos
174042542f5fSchristos	DBG(X11, ("%s-%s use shm? %d (use shm pixmap? %d)\n",
174142542f5fSchristos	     DisplayString(dpy), name, display->has_shm, display->has_shm_pixmap));
174242542f5fSchristos
174342542f5fSchristos	depth = output->use_shm && !FORCE_16BIT_XFER ? display->depth : 16;
174442542f5fSchristos	if (depth < clone->depth)
174542542f5fSchristos		clone->depth = depth;
174642542f5fSchristos
174742542f5fSchristos	return 0;
174842542f5fSchristos}
174942542f5fSchristos
175042542f5fSchristosstatic void ximage_prepare(XImage *image, int width, int height)
175142542f5fSchristos{
175242542f5fSchristos	image->width = width;
175342542f5fSchristos	image->height = height;
175442542f5fSchristos	image->bytes_per_line = stride_for_depth(width, image->depth);
175542542f5fSchristos}
175642542f5fSchristos
175742542f5fSchristosstatic void get_src(struct clone *c, const XRectangle *clip)
175842542f5fSchristos{
175942542f5fSchristos	DBG(DRAW,("%s-%s get_src(%d,%d)x(%d,%d)\n", DisplayString(c->dst.dpy), c->dst.name,
176042542f5fSchristos	     clip->x, clip->y, clip->width, clip->height));
176142542f5fSchristos
176242542f5fSchristos	c->image.obdata = (char *)&c->src.shm;
176342542f5fSchristos
176442542f5fSchristos	if (c->src.use_render) {
176542542f5fSchristos		XRenderComposite(c->src.dpy, PictOpSrc,
176642542f5fSchristos				 c->src.win_picture, 0, c->src.pix_picture,
176742542f5fSchristos				 clip->x, clip->y,
176842542f5fSchristos				 0, 0,
176942542f5fSchristos				 0, 0,
177042542f5fSchristos				 clip->width, clip->height);
177142542f5fSchristos		if (c->src.use_shm_pixmap) {
177242542f5fSchristos			XSync(c->src.dpy, False);
177342542f5fSchristos		} else if (c->src.use_shm) {
177442542f5fSchristos			ximage_prepare(&c->image, clip->width, clip->height);
177542542f5fSchristos			XShmGetImage(c->src.dpy, c->src.pixmap, &c->image,
177642542f5fSchristos				     clip->x, clip->y, AllPlanes);
177742542f5fSchristos		} else {
177842542f5fSchristos			ximage_prepare(&c->image, c->width, c->height);
177942542f5fSchristos			XGetSubImage(c->src.dpy, c->src.pixmap,
178042542f5fSchristos				     clip->x, clip->y, clip->width, clip->height,
178142542f5fSchristos				     AllPlanes, ZPixmap,
178242542f5fSchristos				     &c->image, 0, 0);
178342542f5fSchristos		}
178442542f5fSchristos	} else if (c->src.pixmap) {
178542542f5fSchristos		XCopyArea(c->src.dpy, c->src.window, c->src.pixmap, c->src.gc,
178642542f5fSchristos			  clip->x, clip->y,
178742542f5fSchristos			  clip->width, clip->height,
178842542f5fSchristos			  0, 0);
178942542f5fSchristos		XSync(c->src.dpy, False);
179042542f5fSchristos	} else if (c->src.use_shm) {
179142542f5fSchristos		ximage_prepare(&c->image, clip->width, clip->height);
179242542f5fSchristos		XShmGetImage(c->src.dpy, c->src.window, &c->image,
179342542f5fSchristos			     clip->x, clip->y, AllPlanes);
179442542f5fSchristos	} else {
179542542f5fSchristos		ximage_prepare(&c->image, c->width, c->height);
179642542f5fSchristos		XGetSubImage(c->src.dpy, c->src.window,
179742542f5fSchristos			     clip->x, clip->y, clip->width, clip->height,
179842542f5fSchristos			     AllPlanes, ZPixmap,
179942542f5fSchristos			     &c->image, 0, 0);
180042542f5fSchristos	}
180142542f5fSchristos	c->src.display->flush = 0;
180242542f5fSchristos}
180342542f5fSchristos
180442542f5fSchristosstatic void put_dst(struct clone *c, const XRectangle *clip)
180542542f5fSchristos{
180642542f5fSchristos	DBG(DRAW, ("%s-%s put_dst(%d,%d)x(%d,%d)\n", DisplayString(c->dst.dpy), c->dst.name,
180742542f5fSchristos	     clip->x, clip->y, clip->width, clip->height));
180842542f5fSchristos
180942542f5fSchristos	c->image.obdata = (char *)&c->dst.shm;
181042542f5fSchristos
181142542f5fSchristos	if (c->dst.use_render) {
181242542f5fSchristos		if (c->dst.use_shm_pixmap) {
181342542f5fSchristos			DBG(DRAW, ("%s-%s using SHM pixmap composite\n",
181442542f5fSchristos			     DisplayString(c->dst.dpy), c->dst.name));
181542542f5fSchristos		} else if (c->dst.use_shm) {
181642542f5fSchristos			DBG(DRAW, ("%s-%s using SHM image composite\n",
181742542f5fSchristos			     DisplayString(c->dst.dpy), c->dst.name));
181842542f5fSchristos			XShmPutImage(c->dst.dpy, c->dst.pixmap, c->dst.gc, &c->image,
181942542f5fSchristos				     0, 0,
182042542f5fSchristos				     0, 0,
182142542f5fSchristos				     clip->width, clip->height,
182242542f5fSchristos				     False);
182342542f5fSchristos		} else {
182442542f5fSchristos			DBG(DRAW, ("%s-%s using composite\n",
182542542f5fSchristos			     DisplayString(c->dst.dpy), c->dst.name));
182642542f5fSchristos			XPutImage(c->dst.dpy, c->dst.pixmap, c->dst.gc, &c->image,
182742542f5fSchristos				  0, 0,
182842542f5fSchristos				  0, 0,
182942542f5fSchristos				  clip->width, clip->height);
183042542f5fSchristos		}
183142542f5fSchristos		if (c->dst.use_shm)
183242542f5fSchristos			c->dst.serial = NextRequest(c->dst.dpy);
183342542f5fSchristos		XRenderComposite(c->dst.dpy, PictOpSrc,
183442542f5fSchristos				 c->dst.pix_picture, 0, c->dst.win_picture,
183542542f5fSchristos				 0, 0,
183642542f5fSchristos				 0, 0,
183742542f5fSchristos				 clip->x, clip->y,
183842542f5fSchristos				 clip->width, clip->height);
183942542f5fSchristos		c->dst.display->send |= c->dst.use_shm;
184042542f5fSchristos	} else if (c->dst.pixmap) {
184142542f5fSchristos		DBG(DRAW, ("%s-%s using SHM pixmap\n",
184242542f5fSchristos		     DisplayString(c->dst.dpy), c->dst.name));
184342542f5fSchristos		c->dst.serial = NextRequest(c->dst.dpy);
184442542f5fSchristos		XCopyArea(c->dst.dpy, c->dst.pixmap, c->dst.window, c->dst.gc,
184542542f5fSchristos			  0, 0,
184642542f5fSchristos			  clip->width, clip->height,
184742542f5fSchristos			  clip->x, clip->y);
184842542f5fSchristos		c->dst.display->send = 1;
184942542f5fSchristos	} else if (c->dst.use_shm) {
185042542f5fSchristos		DBG(DRAW, ("%s-%s using SHM image\n",
185142542f5fSchristos		     DisplayString(c->dst.dpy), c->dst.name));
185242542f5fSchristos		c->dst.serial = NextRequest(c->dst.dpy);
185342542f5fSchristos		XShmPutImage(c->dst.dpy, c->dst.window, c->dst.gc, &c->image,
185442542f5fSchristos			     0, 0,
185542542f5fSchristos			     clip->x, clip->y,
185642542f5fSchristos			     clip->width, clip->height,
185742542f5fSchristos			     True);
185842542f5fSchristos	} else {
185942542f5fSchristos		DBG(DRAW, ("%s-%s using image\n",
186042542f5fSchristos		     DisplayString(c->dst.dpy), c->dst.name));
186142542f5fSchristos		XPutImage(c->dst.dpy, c->dst.window, c->dst.gc, &c->image,
186242542f5fSchristos			  0, 0,
186342542f5fSchristos			  clip->x, clip->y,
186442542f5fSchristos			  clip->width, clip->height);
186542542f5fSchristos		c->dst.serial = 0;
186642542f5fSchristos	}
186742542f5fSchristos}
186842542f5fSchristos
186942542f5fSchristosstatic int clone_paint(struct clone *c)
187042542f5fSchristos{
187142542f5fSchristos	XRectangle clip;
187242542f5fSchristos
187342542f5fSchristos	DBG(DRAW, ("%s-%s paint clone, damaged (%d, %d), (%d, %d) [(%d, %d), (%d,  %d)]\n",
187442542f5fSchristos	     DisplayString(c->dst.dpy), c->dst.name,
187542542f5fSchristos	     c->damaged.x1, c->damaged.y1,
187642542f5fSchristos	     c->damaged.x2, c->damaged.y2,
187742542f5fSchristos	     c->src.x, c->src.y,
187842542f5fSchristos	     c->src.x + c->width, c->src.y + c->height));
187942542f5fSchristos
188042542f5fSchristos	if (c->damaged.x1 < c->src.x)
188142542f5fSchristos		c->damaged.x1 = c->src.x;
188242542f5fSchristos	if (c->damaged.x2 > c->src.x + c->width)
188342542f5fSchristos		c->damaged.x2 = c->src.x + c->width;
188442542f5fSchristos	if (c->damaged.x2 <= c->damaged.x1)
188542542f5fSchristos		goto done;
188642542f5fSchristos
188742542f5fSchristos	if (c->damaged.y1 < c->src.y)
188842542f5fSchristos		c->damaged.y1 = c->src.y;
188942542f5fSchristos	if (c->damaged.y2 > c->src.y + c->height)
189042542f5fSchristos		c->damaged.y2 = c->src.y + c->height;
189142542f5fSchristos	if (c->damaged.y2 <= c->damaged.y1)
189242542f5fSchristos		goto done;
189342542f5fSchristos
189442542f5fSchristos	DBG(DRAW, ("%s-%s is damaged, last SHM serial: %ld, now %ld\n",
189542542f5fSchristos	     DisplayString(c->dst.dpy), c->dst.name,
189642542f5fSchristos	     (long)c->dst.serial, (long)LastKnownRequestProcessed(c->dst.dpy)));
189742542f5fSchristos	if (c->dst.serial > LastKnownRequestProcessed(c->dst.dpy)) {
189842542f5fSchristos		struct pollfd pfd;
189942542f5fSchristos
190042542f5fSchristos		pfd.fd = ConnectionNumber(c->dst.dpy);
190142542f5fSchristos		pfd.events = POLLIN;
190242542f5fSchristos		XEventsQueued(c->dst.dpy,
190342542f5fSchristos			      poll(&pfd, 1, 0) ? QueuedAfterReading : QueuedAfterFlush);
190442542f5fSchristos
190542542f5fSchristos		if (c->dst.serial > LastKnownRequestProcessed(c->dst.dpy)) {
190642542f5fSchristos			c->dst.display->skip_clone++;
190742542f5fSchristos			return EAGAIN;
190842542f5fSchristos		}
190942542f5fSchristos	}
191042542f5fSchristos
191142542f5fSchristos	c->dst.display->skip_clone = 0;
191242542f5fSchristos	c->dst.display->skip_frame = 0;
191342542f5fSchristos
191442542f5fSchristos	if (FORCE_FULL_REDRAW) {
191542542f5fSchristos		c->damaged.x1 = c->src.x;
191642542f5fSchristos		c->damaged.y1 = c->src.y;
191742542f5fSchristos		c->damaged.x2 = c->src.x + c->width;
191842542f5fSchristos		c->damaged.y2 = c->src.y + c->height;
191942542f5fSchristos	}
192042542f5fSchristos
192142542f5fSchristos	if (c->dri3.xid) {
192242542f5fSchristos		if (c->src.use_render) {
192342542f5fSchristos			XRenderComposite(c->src.dpy, PictOpSrc,
192442542f5fSchristos					 c->src.win_picture, 0, c->src.pix_picture,
192542542f5fSchristos					 c->damaged.x1, c->damaged.y1,
192642542f5fSchristos					 0, 0,
192742542f5fSchristos					 c->damaged.x1 + c->dst.x - c->src.x,
192842542f5fSchristos					 c->damaged.y1 + c->dst.y - c->src.y,
192942542f5fSchristos					 c->damaged.x2 - c->damaged.x1,
193042542f5fSchristos					 c->damaged.y2 - c->damaged.y1);
193142542f5fSchristos		} else {
193242542f5fSchristos			XCopyArea(c->src.dpy, c->src.window, c->src.pixmap, c->src.gc,
193342542f5fSchristos				  c->damaged.x1, c->damaged.y1,
193442542f5fSchristos				  c->damaged.x2 - c->damaged.x1,
193542542f5fSchristos				  c->damaged.y2 - c->damaged.y1,
193642542f5fSchristos				  c->damaged.x1 + c->dst.x - c->src.x,
193742542f5fSchristos				  c->damaged.y1 + c->dst.y - c->src.y);
193842542f5fSchristos		}
193942542f5fSchristos		dri3_fence_flush(c->src.dpy, &c->dri3);
194042542f5fSchristos	} else {
194142542f5fSchristos		clip.x = c->damaged.x1;
194242542f5fSchristos		clip.y = c->damaged.y1;
194342542f5fSchristos		clip.width  = c->damaged.x2 - c->damaged.x1;
194442542f5fSchristos		clip.height = c->damaged.y2 - c->damaged.y1;
194542542f5fSchristos		get_src(c, &clip);
194642542f5fSchristos
194742542f5fSchristos		clip.x += c->dst.x - c->src.x;
194842542f5fSchristos		clip.y += c->dst.y - c->src.y;
194942542f5fSchristos		put_dst(c, &clip);
195042542f5fSchristos	}
195142542f5fSchristos	display_mark_flush(c->dst.display);
195242542f5fSchristos
195342542f5fSchristosdone:
195442542f5fSchristos	c->damaged.x2 = c->damaged.y2 = INT_MIN;
195542542f5fSchristos	c->damaged.x1 = c->damaged.y1 = INT_MAX;
195642542f5fSchristos	return 0;
195742542f5fSchristos}
195842542f5fSchristos
195942542f5fSchristosstatic void clone_damage(struct clone *c, const XRectangle *rec)
196042542f5fSchristos{
196142542f5fSchristos	int v;
196242542f5fSchristos
196342542f5fSchristos	if ((v = rec->x) < c->damaged.x1)
196442542f5fSchristos		c->damaged.x1 = v;
196542542f5fSchristos	if ((v = (int)rec->x + rec->width) > c->damaged.x2)
196642542f5fSchristos		c->damaged.x2 = v;
196742542f5fSchristos	if ((v = rec->y) < c->damaged.y1)
196842542f5fSchristos		c->damaged.y1 = v;
196942542f5fSchristos	if ((v = (int)rec->y + rec->height) > c->damaged.y2)
197042542f5fSchristos		c->damaged.y2 = v;
197142542f5fSchristos
197242542f5fSchristos	DBG(DAMAGE, ("%s-%s damaged: (%d, %d), (%d, %d)\n",
197342542f5fSchristos	     DisplayString(c->dst.display->dpy), c->dst.name,
197442542f5fSchristos	     c->damaged.x1, c->damaged.y1,
197542542f5fSchristos	     c->damaged.x2, c->damaged.y2));
197642542f5fSchristos}
197742542f5fSchristos
197842542f5fSchristosstatic void usage(const char *arg0)
197942542f5fSchristos{
198042542f5fSchristos	printf("Usage: %s [OPTION]... [TARGET_DISPLAY]...\n", arg0);
198142542f5fSchristos	printf("  -d <source display>  source display\n");
198242542f5fSchristos	printf("  -f                   keep in foreground (do not detach from console and daemonize)\n");
198342542f5fSchristos	printf("  -b                   start bumblebee\n");
198442542f5fSchristos	printf("  -a                   connect to all local displays (e.g. :1, :2, etc)\n");
198542542f5fSchristos	printf("  -S                   disable use of a singleton and launch a fresh intel-virtual-output process\n");
198642542f5fSchristos	printf("  -v                   all verbose output, implies -f\n");
198742542f5fSchristos	printf("  -V <category>        specific verbose output, implies -f\n");
198842542f5fSchristos	printf("  -h                   this help\n");
198942542f5fSchristos	printf("If no target displays are parsed on the commandline, \n");
199042542f5fSchristos	printf("intel-virtual-output will attempt to connect to any local display\n");
199142542f5fSchristos	printf("and then start bumblebee.\n");
199242542f5fSchristos}
199342542f5fSchristos
199442542f5fSchristosstatic void record_callback(XPointer closure, XRecordInterceptData *data)
199542542f5fSchristos{
199642542f5fSchristos	struct context *ctx = (struct context *)closure;
199742542f5fSchristos
199842542f5fSchristos	DBG(X11, ("%s\n", __func__));
199942542f5fSchristos
200042542f5fSchristos	if (data->category == XRecordFromServer) {
200142542f5fSchristos		const xEvent *e = (const xEvent *)data->data;
200242542f5fSchristos
200342542f5fSchristos		DBG(X11, ("%s -- from server, event type %d, root %ld (ours? %d)\n",
200442542f5fSchristos		     __func__, e->u.u.type, (long)e->u.keyButtonPointer.root,
200542542f5fSchristos		     ctx->display->root == e->u.keyButtonPointer.root));
200642542f5fSchristos
200742542f5fSchristos		if (e->u.u.type == MotionNotify &&
200842542f5fSchristos		    e->u.keyButtonPointer.root == ctx->display->root) {
200942542f5fSchristos			struct clone *clone;
201042542f5fSchristos
201142542f5fSchristos			for (clone = ctx->active; clone; clone = clone->active)
201242542f5fSchristos				clone_move_cursor(clone,
201342542f5fSchristos						  e->u.keyButtonPointer.rootX,
201442542f5fSchristos						  e->u.keyButtonPointer.rootY);
201542542f5fSchristos		}
201642542f5fSchristos	}
201742542f5fSchristos
201842542f5fSchristos	XRecordFreeData(data);
201942542f5fSchristos}
202042542f5fSchristos
202142542f5fSchristosstatic int record_mouse(struct context *ctx)
202242542f5fSchristos{
202342542f5fSchristos	Display *dpy;
202442542f5fSchristos	XRecordRange *rr;
202542542f5fSchristos	XRecordClientSpec rcs;
202642542f5fSchristos	XRecordContext rc;
202742542f5fSchristos
202842542f5fSchristos	DBG(X11, ("%s(%s)\n", __func__, DisplayString(ctx->display->dpy)));
202942542f5fSchristos
203042542f5fSchristos	dpy = XOpenDisplay(DisplayString(ctx->display->dpy));
203142542f5fSchristos	if (dpy == NULL)
203242542f5fSchristos		return -ECONNREFUSED;
203342542f5fSchristos
203442542f5fSchristos	rr = XRecordAllocRange();
203542542f5fSchristos	if (rr == NULL)
203642542f5fSchristos		return -ENOMEM;
203742542f5fSchristos
203842542f5fSchristos	rr->device_events.first = rr->device_events.last = MotionNotify;
203942542f5fSchristos
204042542f5fSchristos	rcs = XRecordAllClients;
204142542f5fSchristos	rc = XRecordCreateContext(dpy, 0, &rcs, 1, &rr, 1);
204242542f5fSchristos
204342542f5fSchristos	XSync(dpy, False);
204442542f5fSchristos
204542542f5fSchristos	if (!XRecordEnableContextAsync(dpy, rc, record_callback, (XPointer)ctx))
204642542f5fSchristos		return -EINVAL;
204742542f5fSchristos
204842542f5fSchristos	ctx->record = dpy;
204942542f5fSchristos	return ConnectionNumber(dpy);
205042542f5fSchristos}
205142542f5fSchristos
205242542f5fSchristosstatic int bad_visual(Visual *visual, int depth)
205342542f5fSchristos{
205442542f5fSchristos	DBG(X11, ("%s? depth=%d, visual: class=%d, bits_per_rgb=%d, red_mask=%08lx, green_mask=%08lx, blue_mask=%08lx\n",
205542542f5fSchristos	     __func__, depth,
205642542f5fSchristos	     visual->class,
205742542f5fSchristos	     visual->bits_per_rgb,
205842542f5fSchristos	     visual->red_mask,
205942542f5fSchristos	     visual->green_mask,
206042542f5fSchristos	     visual->blue_mask));
206142542f5fSchristos
206242542f5fSchristos	if (!(visual->class == TrueColor || visual->class == DirectColor))
206342542f5fSchristos		return 1;
206442542f5fSchristos
206542542f5fSchristos	switch (depth) {
206642542f5fSchristos	case 16: return (/* visual->bits_per_rgb != 6          || */
206742542f5fSchristos			 visual->red_mask     != 0x1f << 11 ||
206842542f5fSchristos			 visual->green_mask   != 0x3f << 5  ||
206942542f5fSchristos			 visual->blue_mask    != 0x1f << 0);
207042542f5fSchristos
207142542f5fSchristos	case 24: return (/* visual->bits_per_rgb != 8          || */
207242542f5fSchristos			 visual->red_mask     != 0xff << 16 ||
207342542f5fSchristos			 visual->green_mask   != 0xff << 8  ||
207442542f5fSchristos			 visual->blue_mask    != 0xff << 0);
207542542f5fSchristos
207642542f5fSchristos	default: return 1;
207742542f5fSchristos	}
207842542f5fSchristos}
207942542f5fSchristos
208042542f5fSchristosstatic XRenderPictFormat *
208142542f5fSchristosfind_xrender_format(Display *dpy, pixman_format_code_t format)
208242542f5fSchristos{
208342542f5fSchristos    XRenderPictFormat tmpl;
208442542f5fSchristos    int mask;
208542542f5fSchristos
208642542f5fSchristos#define MASK(x) ((1<<(x))-1)
208742542f5fSchristos
208842542f5fSchristos    memset(&tmpl, 0, sizeof(tmpl));
208942542f5fSchristos
209042542f5fSchristos    tmpl.depth = PIXMAN_FORMAT_DEPTH(format);
209142542f5fSchristos    mask = PictFormatType | PictFormatDepth;
209242542f5fSchristos
209342542f5fSchristos    DBG(X11, ("%s(0x%08lx)\n", __func__, (long)format));
209442542f5fSchristos
209542542f5fSchristos    switch (PIXMAN_FORMAT_TYPE(format)) {
209642542f5fSchristos    case PIXMAN_TYPE_ARGB:
209742542f5fSchristos	tmpl.type = PictTypeDirect;
209842542f5fSchristos
209942542f5fSchristos	if (PIXMAN_FORMAT_A(format)) {
210042542f5fSchristos		tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
210142542f5fSchristos		tmpl.direct.alpha = (PIXMAN_FORMAT_R(format) +
210242542f5fSchristos				     PIXMAN_FORMAT_G(format) +
210342542f5fSchristos				     PIXMAN_FORMAT_B(format));
210442542f5fSchristos	}
210542542f5fSchristos
210642542f5fSchristos	tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
210742542f5fSchristos	tmpl.direct.red = (PIXMAN_FORMAT_G(format) +
210842542f5fSchristos			   PIXMAN_FORMAT_B(format));
210942542f5fSchristos
211042542f5fSchristos	tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
211142542f5fSchristos	tmpl.direct.green = PIXMAN_FORMAT_B(format);
211242542f5fSchristos
211342542f5fSchristos	tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
211442542f5fSchristos	tmpl.direct.blue = 0;
211542542f5fSchristos
211642542f5fSchristos	mask |= PictFormatRed | PictFormatRedMask;
211742542f5fSchristos	mask |= PictFormatGreen | PictFormatGreenMask;
211842542f5fSchristos	mask |= PictFormatBlue | PictFormatBlueMask;
211942542f5fSchristos	mask |= PictFormatAlpha | PictFormatAlphaMask;
212042542f5fSchristos	break;
212142542f5fSchristos
212242542f5fSchristos    case PIXMAN_TYPE_ABGR:
212342542f5fSchristos	tmpl.type = PictTypeDirect;
212442542f5fSchristos
212542542f5fSchristos	if (tmpl.direct.alphaMask) {
212642542f5fSchristos		tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
212742542f5fSchristos		tmpl.direct.alpha = (PIXMAN_FORMAT_B(format) +
212842542f5fSchristos				     PIXMAN_FORMAT_G(format) +
212942542f5fSchristos				     PIXMAN_FORMAT_R(format));
213042542f5fSchristos	}
213142542f5fSchristos
213242542f5fSchristos	tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
213342542f5fSchristos	tmpl.direct.blue = (PIXMAN_FORMAT_G(format) +
213442542f5fSchristos			    PIXMAN_FORMAT_R(format));
213542542f5fSchristos
213642542f5fSchristos	tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
213742542f5fSchristos	tmpl.direct.green = PIXMAN_FORMAT_R(format);
213842542f5fSchristos
213942542f5fSchristos	tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
214042542f5fSchristos	tmpl.direct.red = 0;
214142542f5fSchristos
214242542f5fSchristos	mask |= PictFormatRed | PictFormatRedMask;
214342542f5fSchristos	mask |= PictFormatGreen | PictFormatGreenMask;
214442542f5fSchristos	mask |= PictFormatBlue | PictFormatBlueMask;
214542542f5fSchristos	mask |= PictFormatAlpha | PictFormatAlphaMask;
214642542f5fSchristos	break;
214742542f5fSchristos
214842542f5fSchristos    case PIXMAN_TYPE_BGRA:
214942542f5fSchristos	tmpl.type = PictTypeDirect;
215042542f5fSchristos
215142542f5fSchristos	tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
215242542f5fSchristos	tmpl.direct.blue = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format));
215342542f5fSchristos
215442542f5fSchristos	tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
215542542f5fSchristos	tmpl.direct.green = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) -
215642542f5fSchristos			     PIXMAN_FORMAT_G(format));
215742542f5fSchristos
215842542f5fSchristos	tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
215942542f5fSchristos	tmpl.direct.red = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) -
216042542f5fSchristos			   PIXMAN_FORMAT_G(format) - PIXMAN_FORMAT_R(format));
216142542f5fSchristos
216242542f5fSchristos	if (tmpl.direct.alphaMask) {
216342542f5fSchristos		tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
216442542f5fSchristos		tmpl.direct.alpha = 0;
216542542f5fSchristos	}
216642542f5fSchristos
216742542f5fSchristos	mask |= PictFormatRed | PictFormatRedMask;
216842542f5fSchristos	mask |= PictFormatGreen | PictFormatGreenMask;
216942542f5fSchristos	mask |= PictFormatBlue | PictFormatBlueMask;
217042542f5fSchristos	mask |= PictFormatAlpha | PictFormatAlphaMask;
217142542f5fSchristos	break;
217242542f5fSchristos
217342542f5fSchristos    case PIXMAN_TYPE_A:
217442542f5fSchristos	tmpl.type = PictTypeDirect;
217542542f5fSchristos
217642542f5fSchristos	tmpl.direct.alpha = 0;
217742542f5fSchristos	tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
217842542f5fSchristos
217942542f5fSchristos	mask |= PictFormatAlpha | PictFormatAlphaMask;
218042542f5fSchristos	break;
218142542f5fSchristos
218242542f5fSchristos    case PIXMAN_TYPE_COLOR:
218342542f5fSchristos    case PIXMAN_TYPE_GRAY:
218442542f5fSchristos	/* XXX Find matching visual/colormap */
218542542f5fSchristos	tmpl.type = PictTypeIndexed;
218642542f5fSchristos	//tmpl.colormap = screen->visuals[PIXMAN_FORMAT_VIS(format)].vid;
218742542f5fSchristos	//mask |= PictFormatColormap;
218842542f5fSchristos	return NULL;
218942542f5fSchristos    }
219042542f5fSchristos#undef MASK
219142542f5fSchristos
219242542f5fSchristos    return XRenderFindFormat(dpy, mask, &tmpl, 0);
219342542f5fSchristos}
219442542f5fSchristos
219542542f5fSchristosstatic int display_init_render(struct display *display, int depth, XRenderPictFormat **use_render)
219642542f5fSchristos{
219742542f5fSchristos	Display *dpy = display->dpy;
219842542f5fSchristos	int major, minor;
219942542f5fSchristos
220042542f5fSchristos	DBG(X11, ("%s is depth %d, want %d\n", DisplayString(dpy), display->depth, depth));
220142542f5fSchristos
220242542f5fSchristos	*use_render = 0;
220342542f5fSchristos	if (depth == display->depth && !bad_visual(display->visual, depth))
220442542f5fSchristos		return 0;
220542542f5fSchristos
220642542f5fSchristos	if (display->root_format == 0) {
220742542f5fSchristos		if (!XRenderQueryVersion(dpy, &major, &minor)) {
220842542f5fSchristos			fprintf(stderr, "Render extension not supported by %s\n", DisplayString(dpy));
220942542f5fSchristos			return -EINVAL;
221042542f5fSchristos		}
221142542f5fSchristos
221242542f5fSchristos		display->root_format = XRenderFindVisualFormat(dpy, display->visual);
221342542f5fSchristos		display->rgb16_format = find_xrender_format(dpy, PIXMAN_r5g6b5);
221442542f5fSchristos		display->rgb24_format = XRenderFindStandardFormat(dpy, PictStandardRGB24);
221542542f5fSchristos
221642542f5fSchristos		DBG(X11, ("%s: root format=%lx, rgb16 format=%lx, rgb24 format=%lx\n",
221742542f5fSchristos		     DisplayString(dpy),
221842542f5fSchristos		     (long)display->root_format,
221942542f5fSchristos		     (long)display->rgb16_format,
222042542f5fSchristos		     (long)display->rgb24_format));
222142542f5fSchristos	}
222242542f5fSchristos
222342542f5fSchristos	switch (depth) {
222442542f5fSchristos	case 16: *use_render = display->rgb16_format; break;
222542542f5fSchristos	case 24: *use_render = display->rgb24_format; break;
222642542f5fSchristos	}
222742542f5fSchristos	if (*use_render == 0)
222842542f5fSchristos		return -ENOENT;
222942542f5fSchristos
223042542f5fSchristos	return 0;
223142542f5fSchristos}
223242542f5fSchristos
223342542f5fSchristosstatic int clone_init_depth(struct clone *clone)
223442542f5fSchristos{
223542542f5fSchristos	int ret, depth;
223642542f5fSchristos
223742542f5fSchristos	DBG(X11,("%s-%s wants depth %d\n",
223842542f5fSchristos	     DisplayString(clone->dst.dpy), clone->dst.name, clone->depth));
223942542f5fSchristos
224042542f5fSchristos	ret = -1;
224142542f5fSchristos	for (depth = clone->depth; depth <= 24; depth += 8) {
224242542f5fSchristos		ret = display_init_render(clone->src.display, depth, &clone->src.use_render);
224342542f5fSchristos		if (ret)
224442542f5fSchristos			continue;
224542542f5fSchristos
224642542f5fSchristos		ret = display_init_render(clone->dst.display, depth, &clone->dst.use_render);
224742542f5fSchristos		if (ret)
224842542f5fSchristos			continue;
224942542f5fSchristos
225042542f5fSchristos		break;
225142542f5fSchristos	}
225242542f5fSchristos	if (ret)
225342542f5fSchristos		return ret;
225442542f5fSchristos
225542542f5fSchristos	DBG(X11, ("%s-%s using depth %d, requires xrender for src? %d, for dst? %d\n",
225642542f5fSchristos	     DisplayString(clone->dst.dpy), clone->dst.name,
225742542f5fSchristos	     clone->depth,
225842542f5fSchristos	     clone->src.use_render != NULL,
225942542f5fSchristos	     clone->dst.use_render != NULL));
226042542f5fSchristos
226142542f5fSchristos	if (!clone->dst.use_render &&
226242542f5fSchristos	    clone->src.display->dri3_active &&
226342542f5fSchristos	    clone->dst.display->dri3_active)
226442542f5fSchristos		dri3_create_fence(clone->src.dpy, clone->src.window, &clone->dri3);
226542542f5fSchristos
226642542f5fSchristos	return 0;
226742542f5fSchristos}
226842542f5fSchristos
226942542f5fSchristos#if defined(USE_XINERAMA)
227042542f5fSchristosstatic int xinerama_active(struct display *display)
227142542f5fSchristos{
227242542f5fSchristos	int active = 0;
227342542f5fSchristos	if (XineramaQueryExtension(display->dpy, &display->xinerama_event, &display->xinerama_error))
227442542f5fSchristos		active = XineramaIsActive(display->dpy);
227542542f5fSchristos	return active;
227642542f5fSchristos}
227742542f5fSchristos#else
227842542f5fSchristos#define xinerama_active(d) 0
227942542f5fSchristos#endif
228042542f5fSchristos
228142542f5fSchristosstatic int add_display(struct context *ctx, Display *dpy)
228242542f5fSchristos{
228342542f5fSchristos	struct display *display;
228442542f5fSchristos	int first_display = ctx->ndisplay == 0;
228542542f5fSchristos
228642542f5fSchristos	if (is_power_of_2(ctx->ndisplay)) {
228742542f5fSchristos		struct display *new_display;
228842542f5fSchristos
228942542f5fSchristos		new_display = realloc(ctx->display, 2*ctx->ndisplay*sizeof(struct display));
229042542f5fSchristos		if (new_display == NULL)
229142542f5fSchristos			return -ENOMEM;
229242542f5fSchristos
229342542f5fSchristos		if (new_display != ctx->display) {
229442542f5fSchristos			int n;
229542542f5fSchristos
229642542f5fSchristos			for (n = 0; n < ctx->nclone; n++) {
229742542f5fSchristos				struct clone *clone = &ctx->clones[n];
229842542f5fSchristos				clone->src.display = new_display + (clone->src.display - ctx->display);
229942542f5fSchristos				clone->dst.display = new_display + (clone->dst.display - ctx->display);
230042542f5fSchristos			}
230142542f5fSchristos		}
230242542f5fSchristos
230342542f5fSchristos		ctx->display = new_display;
230442542f5fSchristos	}
230542542f5fSchristos
230642542f5fSchristos	display = memset(&ctx->display[ctx->ndisplay++], 0, sizeof(struct display));
230742542f5fSchristos
230842542f5fSchristos	display->dpy = dpy;
230942542f5fSchristos	display->ctx = ctx;
231042542f5fSchristos
231142542f5fSchristos	display->root = DefaultRootWindow(dpy);
231242542f5fSchristos	display->depth = DefaultDepth(dpy, DefaultScreen(dpy));
231342542f5fSchristos	display->visual = DefaultVisual(dpy, DefaultScreen(dpy));
231442542f5fSchristos
231542542f5fSchristos	display->has_shm = can_use_shm(dpy, display->root,
231642542f5fSchristos				       &display->shm_event,
231742542f5fSchristos				       &display->shm_opcode,
231842542f5fSchristos				       &display->has_shm_pixmap);
231942542f5fSchristos	DBG(X11, ("%s: has_shm?=%d, event=%d, opcode=%d, has_pixmap?=%d\n",
232042542f5fSchristos	     DisplayString(dpy),
232142542f5fSchristos	     display->has_shm,
232242542f5fSchristos	     display->shm_event,
232342542f5fSchristos	     display->shm_opcode,
232442542f5fSchristos	     display->has_shm_pixmap));
232542542f5fSchristos
232642542f5fSchristos	display->rr_active = XRRQueryExtension(dpy, &display->rr_event, &display->rr_error);
232742542f5fSchristos	DBG(X11, ("%s: randr_active?=%d, event=%d, error=%d\n",
232842542f5fSchristos	     DisplayString(dpy),
232942542f5fSchristos	     display->rr_active,
233042542f5fSchristos	     display->rr_event,
233142542f5fSchristos	     display->rr_error));
233242542f5fSchristos
233342542f5fSchristos	display->xinerama_active = xinerama_active(display);
233442542f5fSchristos	DBG(X11, ("%s: xinerama_active?=%d, event=%d, error=%d\n",
233542542f5fSchristos	     DisplayString(dpy),
233642542f5fSchristos	     display->xinerama_active,
233742542f5fSchristos	     display->xinerama_event,
233842542f5fSchristos	     display->xinerama_error));
233942542f5fSchristos
234042542f5fSchristos	display->dri3_active = dri3_exists(dpy);
234142542f5fSchristos	DBG(X11, ("%s: dri3_active?=%d\n",
234242542f5fSchristos	     DisplayString(dpy),
234342542f5fSchristos	     display->dri3_active));
234442542f5fSchristos
234542542f5fSchristos	/* first display (source) is slightly special */
234642542f5fSchristos	if (!first_display) {
234742542f5fSchristos		display->invisible_cursor = display_load_invisible_cursor(display);
234842542f5fSchristos		display_cursor_move(display, 0, 0, 0);
234942542f5fSchristos	}
235042542f5fSchristos
235142542f5fSchristos	return ConnectionNumber(dpy);
235242542f5fSchristos}
235342542f5fSchristos
235442542f5fSchristosstatic int display_open(struct context *ctx, const char *name)
235542542f5fSchristos{
235642542f5fSchristos	Display *dpy;
235742542f5fSchristos	int n;
235842542f5fSchristos
235942542f5fSchristos	DBG(X11, ("%s(%s)\n", __func__, name));
236042542f5fSchristos
236142542f5fSchristos	dpy = XOpenDisplay(name);
236242542f5fSchristos	if (dpy == NULL)
236342542f5fSchristos		return -ECONNREFUSED;
236442542f5fSchristos
236542542f5fSchristos	/* Prevent cloning the same display twice */
236642542f5fSchristos	for (n = 0; n < ctx->ndisplay; n++) {
236742542f5fSchristos		if (strcmp(DisplayString(dpy), DisplayString(ctx->display[n].dpy)) == 0) {
236842542f5fSchristos			DBG(X11, ("%s %s is already connected\n", __func__, name));
236942542f5fSchristos			XCloseDisplay(dpy);
237042542f5fSchristos			return -EBUSY;
237142542f5fSchristos		}
237242542f5fSchristos	}
237342542f5fSchristos
237442542f5fSchristos	return add_display(ctx, dpy);
237542542f5fSchristos}
237642542f5fSchristos
237742542f5fSchristosstatic int bumblebee_open(struct context *ctx)
237842542f5fSchristos{
237942542f5fSchristos	char buf[256];
238042542f5fSchristos	struct sockaddr_un addr;
238142542f5fSchristos	int fd, len;
238242542f5fSchristos
238342542f5fSchristos	fd = socket(PF_UNIX, SOCK_STREAM, 0);
238442542f5fSchristos	if (fd < 0) {
238542542f5fSchristos		DBG(X11, ("%s unable to create a socket: %d\n", __func__, errno));
238642542f5fSchristos		return -ECONNREFUSED;
238742542f5fSchristos	}
238842542f5fSchristos
238942542f5fSchristos	addr.sun_family = AF_UNIX;
239042542f5fSchristos	snprintf(addr.sun_path, sizeof(addr.sun_path), "%s",
239142542f5fSchristos		 optarg && *optarg ? optarg : "/var/run/bumblebee.socket");
239242542f5fSchristos	if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
239342542f5fSchristos		DBG(X11, ("%s unable to create a socket: %d\n", __func__, errno));
239442542f5fSchristos		goto err;
239542542f5fSchristos	}
239642542f5fSchristos
239742542f5fSchristos	/* Ask bumblebee to start the second server */
239842542f5fSchristos	buf[0] = 'C';
239942542f5fSchristos	if (send(fd, &buf, 1, 0) != 1 || (len = recv(fd, &buf, 255, 0)) <= 0) {
240042542f5fSchristos		DBG(X11, ("%s startup send/recv failed: %d\n", __func__, errno));
240142542f5fSchristos		goto err;
240242542f5fSchristos	}
240342542f5fSchristos	buf[len] = '\0';
240442542f5fSchristos
240542542f5fSchristos	/* Query the display name */
240642542f5fSchristos	strcpy(buf, "Q VirtualDisplay");
240742542f5fSchristos	if (send(fd, buf, 17, 0) != 17 || (len = recv(fd, buf, 255, 0)) <= 0) {
240842542f5fSchristos		DBG(X11, ("%s query send/recv failed: %d\n", __func__, errno));
240942542f5fSchristos		goto err;
241042542f5fSchristos	}
241142542f5fSchristos	buf[len] = '\0';
241242542f5fSchristos
241342542f5fSchristos	DBG(X11, ("%s query result '%s'\n", __func__, buf));
241442542f5fSchristos
241542542f5fSchristos	if (strncmp(buf, "Value: ", 7))
241642542f5fSchristos		goto err;
241742542f5fSchristos
241842542f5fSchristos	len = 7;
241942542f5fSchristos	while (buf[len] != '\n' && buf[len] != '\0')
242042542f5fSchristos		len++;
242142542f5fSchristos	buf[len] = '\0';
242242542f5fSchristos
242342542f5fSchristos	/* XXX We must keep the control socket open whilst we want to keep
242442542f5fSchristos	 * the display around.
242542542f5fSchristos	 *
242642542f5fSchristos	 * So what we need to do is listen for new bumblee Xservers and
242742542f5fSchristos	 * bind only for their duration.
242842542f5fSchristos	 */
242942542f5fSchristos
243042542f5fSchristos	return display_open(ctx, buf+7);
243142542f5fSchristos
243242542f5fSchristoserr:
243342542f5fSchristos	close(fd);
243442542f5fSchristos	return -ECONNREFUSED;
243542542f5fSchristos}
243642542f5fSchristos
243742542f5fSchristosstatic int display_init_damage(struct display *display)
243842542f5fSchristos{
243942542f5fSchristos	DBG(X11, ("%s(%s)\n", __func__, DisplayString(display->dpy)));
244042542f5fSchristos
244142542f5fSchristos	if (!XDamageQueryExtension(display->dpy, &display->damage_event, &display->damage_error) ||
244242542f5fSchristos	    !XFixesQueryExtension(display->dpy, &display->xfixes_event, &display->xfixes_error)) {
244342542f5fSchristos		fprintf(stderr, "Damage/Fixes extension not supported by %s\n", DisplayString(display->dpy));
244442542f5fSchristos		return EINVAL;
244542542f5fSchristos	}
244642542f5fSchristos
244742542f5fSchristos	display->damage = XDamageCreate(display->dpy, display->root, XDamageReportBoundingBox);
244842542f5fSchristos	if (display->damage == 0)
244942542f5fSchristos		return EACCES;
245042542f5fSchristos
245142542f5fSchristos	return 0;
245242542f5fSchristos}
245342542f5fSchristos
245442542f5fSchristosstatic void display_reset_damage(struct display *display)
245542542f5fSchristos{
245642542f5fSchristos	Damage damage;
245742542f5fSchristos
245842542f5fSchristos	damage = XDamageCreate(display->dpy, display->root, XDamageReportBoundingBox);
245942542f5fSchristos	if (damage) {
246042542f5fSchristos		XDamageDestroy(display->dpy, display->damage);
246142542f5fSchristos		display->damage = damage;
246242542f5fSchristos		XFlush(display->dpy);
246342542f5fSchristos		display->flush = 0;
246442542f5fSchristos	}
246542542f5fSchristos}
246642542f5fSchristos
246742542f5fSchristosstatic void display_init_randr_hpd(struct display *display)
246842542f5fSchristos{
246942542f5fSchristos	int major, minor;
247042542f5fSchristos
247142542f5fSchristos	DBG(X11,("%s(%s)\n", __func__, DisplayString(display->dpy)));
247242542f5fSchristos
247342542f5fSchristos	if (!XRRQueryVersion(display->dpy, &major, &minor))
247442542f5fSchristos		return;
247542542f5fSchristos
247642542f5fSchristos	DBG(X11, ("%s - randr version %d.%d\n", DisplayString(display->dpy), major, minor));
247742542f5fSchristos	if (major > 1 || (major == 1 && minor >= 2))
247842542f5fSchristos		XRRSelectInput(display->dpy, display->root, RROutputChangeNotifyMask);
247942542f5fSchristos}
248042542f5fSchristos
248142542f5fSchristosstatic void rebuild_clones(struct context *ctx, struct clone *new_clones)
248242542f5fSchristos{
248342542f5fSchristos	int n, m;
248442542f5fSchristos
248542542f5fSchristos	for (n = 1; n < ctx->ndisplay; n++) {
248642542f5fSchristos		struct display *d = &ctx->display[n];
248742542f5fSchristos
248842542f5fSchristos		d->clone = NULL;
248942542f5fSchristos		for (m = 0; m < ctx->nclone; m++) {
249042542f5fSchristos			struct clone *c = &new_clones[m];
249142542f5fSchristos
249242542f5fSchristos			if (c->dst.display != d)
249342542f5fSchristos				continue;
249442542f5fSchristos
249542542f5fSchristos			c->next = d->clone;
249642542f5fSchristos			d->clone = c;
249742542f5fSchristos		}
249842542f5fSchristos	}
249942542f5fSchristos
250042542f5fSchristos	ctx->clones = new_clones;
250142542f5fSchristos}
250242542f5fSchristos
250342542f5fSchristosstatic struct clone *add_clone(struct context *ctx)
250442542f5fSchristos{
250542542f5fSchristos	if (is_power_of_2(ctx->nclone)) {
250642542f5fSchristos		struct clone *new_clones;
250742542f5fSchristos
250842542f5fSchristos		new_clones = realloc(ctx->clones, 2*ctx->nclone*sizeof(struct clone));
250942542f5fSchristos		if (new_clones == NULL)
251042542f5fSchristos			return NULL;
251142542f5fSchristos
251242542f5fSchristos		if (new_clones != ctx->clones)
251342542f5fSchristos			rebuild_clones(ctx, new_clones);
251442542f5fSchristos	}
251542542f5fSchristos
251642542f5fSchristos	return memset(&ctx->clones[ctx->nclone++], 0, sizeof(struct clone));
251742542f5fSchristos}
251842542f5fSchristos
251942542f5fSchristosstatic struct display *last_display(struct context *ctx)
252042542f5fSchristos{
252142542f5fSchristos	return &ctx->display[ctx->ndisplay-1];
252242542f5fSchristos}
252342542f5fSchristos
252442542f5fSchristosstatic void reverse_clone_list(struct display *display)
252542542f5fSchristos{
252642542f5fSchristos	struct clone *list = NULL;
252742542f5fSchristos
252842542f5fSchristos	while (display->clone) {
252942542f5fSchristos		struct clone *clone = display->clone;
253042542f5fSchristos		display->clone = clone->next;
253142542f5fSchristos		clone->next = list;
253242542f5fSchristos		list = clone;
253342542f5fSchristos	}
253442542f5fSchristos
253542542f5fSchristos	display->clone = list;
253642542f5fSchristos}
253742542f5fSchristos
253842542f5fSchristosstatic int last_display_add_clones__randr(struct context *ctx)
253942542f5fSchristos{
254042542f5fSchristos	struct display *display = last_display(ctx);
254142542f5fSchristos	XRRScreenResources *res;
254242542f5fSchristos	char buf[80];
254342542f5fSchristos	int i, ret;
254442542f5fSchristos
254542542f5fSchristos	DBG(X11, ("%s(%s)\n", __func__, DisplayString(display->dpy)));
254642542f5fSchristos
254742542f5fSchristos	display_init_randr_hpd(display);
254842542f5fSchristos
254942542f5fSchristos	/* Force a probe of outputs on initial connection */
255042542f5fSchristos	res = XRRGetScreenResources(display->dpy, display->root);
255142542f5fSchristos	if (res == NULL)
255242542f5fSchristos		return -ENOMEM;
255342542f5fSchristos
255442542f5fSchristos	DBG(X11, ("%s - noutputs=%d\n", DisplayString(display->dpy), res->noutput));
255542542f5fSchristos	for (i = 0; i < res->noutput; i++) {
255642542f5fSchristos		XRROutputInfo *o = XRRGetOutputInfo(display->dpy, res, res->outputs[i]);
255742542f5fSchristos		struct clone *clone = add_clone(ctx);
255842542f5fSchristos		RROutput id;
255942542f5fSchristos
256042542f5fSchristos		if (clone == NULL)
256142542f5fSchristos			return -ENOMEM;
256242542f5fSchristos
256342542f5fSchristos		clone->depth = 24;
256442542f5fSchristos		clone->next = display->clone;
256542542f5fSchristos		display->clone = clone;
256642542f5fSchristos
256742542f5fSchristos		id = claim_virtual(ctx->display, buf, ctx->nclone);
256842542f5fSchristos		if (id == 0) {
256942542f5fSchristos			fprintf(stderr, "Failed to find available VirtualHead \"%s\" for \"%s\" on display \"%s\"\n",
257042542f5fSchristos				buf, o->name, DisplayString(display->dpy));
257142542f5fSchristos			return -ENOSPC;
257242542f5fSchristos		}
257342542f5fSchristos
257442542f5fSchristos		ret = clone_output_init(clone, &clone->src, ctx->display, buf, id);
257542542f5fSchristos		if (ret) {
257642542f5fSchristos			fprintf(stderr, "Failed to add output \"%s\" on display \"%s\"\n",
257742542f5fSchristos				buf, DisplayString(ctx->display->dpy));
257842542f5fSchristos			return ret;
257942542f5fSchristos		}
258042542f5fSchristos
258142542f5fSchristos		ret = clone_output_init(clone, &clone->dst, display, o->name, res->outputs[i]);
258242542f5fSchristos		if (ret) {
258342542f5fSchristos			fprintf(stderr, "Failed to add output \"%s\" on display \"%s\"\n",
258442542f5fSchristos				o->name, DisplayString(display->dpy));
258542542f5fSchristos			return ret;
258642542f5fSchristos		}
258742542f5fSchristos
258842542f5fSchristos		ret = clone_init_depth(clone);
258942542f5fSchristos		if (ret) {
259042542f5fSchristos			fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n",
259142542f5fSchristos				DisplayString(display->dpy));
259242542f5fSchristos			return ret;
259342542f5fSchristos		}
259442542f5fSchristos
259542542f5fSchristos		ret = clone_update_modes__randr(clone);
259642542f5fSchristos		if (ret) {
259742542f5fSchristos			fprintf(stderr, "Failed to clone output \"%s\" from display \"%s\"\n",
259842542f5fSchristos				o->name, DisplayString(display->dpy));
259942542f5fSchristos			return ret;
260042542f5fSchristos		}
260142542f5fSchristos
260242542f5fSchristos
260342542f5fSchristos		if (o->crtc) {
260442542f5fSchristos			DBG(X11, ("%s - disabling active output\n", DisplayString(display->dpy)));
260542542f5fSchristos			disable_crtc(display->dpy, res, o->crtc);
260642542f5fSchristos		}
260742542f5fSchristos
260842542f5fSchristos		XRRFreeOutputInfo(o);
260942542f5fSchristos	}
261042542f5fSchristos	XRRFreeScreenResources(res);
261142542f5fSchristos
261242542f5fSchristos	reverse_clone_list(display);
261342542f5fSchristos	return 0;
261442542f5fSchristos}
261542542f5fSchristos
261642542f5fSchristos#if defined(USE_XINERAMA)
261742542f5fSchristosstatic int last_display_add_clones__xinerama(struct context *ctx)
261842542f5fSchristos{
261942542f5fSchristos	struct display *display = last_display(ctx);
262042542f5fSchristos	Display *dpy = display->dpy;
262142542f5fSchristos	XineramaScreenInfo *xi;
262242542f5fSchristos	char buf[80];
262342542f5fSchristos	int n, count, ret;
262442542f5fSchristos
262542542f5fSchristos	DBG(X11, ("%s(%s)\n", __func__, DisplayString(display->dpy)));
262642542f5fSchristos
262742542f5fSchristos	count = 0;
262842542f5fSchristos	xi = XineramaQueryScreens(dpy, &count);
262942542f5fSchristos	for (n = 0; n < count; n++) {
263042542f5fSchristos		struct clone *clone = add_clone(ctx);
263142542f5fSchristos		RROutput id;
263242542f5fSchristos
263342542f5fSchristos		if (clone == NULL)
263442542f5fSchristos			return -ENOMEM;
263542542f5fSchristos
263642542f5fSchristos		if (xi[n].width == 0 || xi[n].height == 0)
263742542f5fSchristos			continue;
263842542f5fSchristos
263942542f5fSchristos		clone->depth = 24;
264042542f5fSchristos		clone->next = display->clone;
264142542f5fSchristos		display->clone = clone;
264242542f5fSchristos
264342542f5fSchristos		id = claim_virtual(ctx->display, buf, ctx->nclone);
264442542f5fSchristos		if (id == 0) {
264542542f5fSchristos			fprintf(stderr, "Failed to find available VirtualHead \"%s\" for Xinerama screen %d on display \"%s\"\n",
264642542f5fSchristos				buf, n, DisplayString(dpy));
264742542f5fSchristos		}
264842542f5fSchristos		ret = clone_output_init(clone, &clone->src, ctx->display, buf, id);
264942542f5fSchristos		if (ret) {
265042542f5fSchristos			fprintf(stderr, "Failed to add Xinerama screen %d on display \"%s\"\n",
265142542f5fSchristos				n, DisplayString(ctx->display->dpy));
265242542f5fSchristos			return ret;
265342542f5fSchristos		}
265442542f5fSchristos
265542542f5fSchristos		sprintf(buf, "XINERAMA%d", n);
265642542f5fSchristos		ret = clone_output_init(clone, &clone->dst, display, buf, 0);
265742542f5fSchristos		if (ret) {
265842542f5fSchristos			fprintf(stderr, "Failed to add Xinerama screen %d on display \"%s\"\n",
265942542f5fSchristos				n, DisplayString(dpy));
266042542f5fSchristos			return ret;
266142542f5fSchristos		}
266242542f5fSchristos
266342542f5fSchristos		ret = clone_init_depth(clone);
266442542f5fSchristos		if (ret) {
266542542f5fSchristos			fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n",
266642542f5fSchristos				DisplayString(display->dpy));
266742542f5fSchristos			return ret;
266842542f5fSchristos		}
266942542f5fSchristos
267042542f5fSchristos		/* Replace the modes on the local VIRTUAL output with the remote Screen */
267142542f5fSchristos		clone->width = xi[n].width;
267242542f5fSchristos		clone->height = xi[n].height;
267342542f5fSchristos		clone->dst.x = xi[n].x_org;
267442542f5fSchristos		clone->dst.y = xi[n].y_org;
267542542f5fSchristos		clone->dst.rr_crtc = -1;
267642542f5fSchristos		ret = clone_update_modes__fixed(clone);
267742542f5fSchristos		if (ret) {
267842542f5fSchristos			fprintf(stderr, "Failed to clone Xinerama screen %d from display \"%s\"\n",
267942542f5fSchristos				n, DisplayString(display->dpy));
268042542f5fSchristos			return ret;
268142542f5fSchristos		}
268242542f5fSchristos
268342542f5fSchristos		clone->active = ctx->active;
268442542f5fSchristos		ctx->active = clone;
268542542f5fSchristos	}
268642542f5fSchristos	XFree(xi);
268742542f5fSchristos
268842542f5fSchristos	reverse_clone_list(display);
268942542f5fSchristos	return 0;
269042542f5fSchristos}
269142542f5fSchristos#else
269242542f5fSchristos#define last_display_add_clones__xinerama(ctx) -1
269342542f5fSchristos#endif
269442542f5fSchristos
269542542f5fSchristosstatic int last_display_add_clones__display(struct context *ctx)
269642542f5fSchristos{
269742542f5fSchristos	struct display *display = last_display(ctx);
269842542f5fSchristos	Display *dpy = display->dpy;
269942542f5fSchristos	struct clone *clone;
270042542f5fSchristos	Screen *scr;
270142542f5fSchristos	char buf[80];
270242542f5fSchristos	int ret;
270342542f5fSchristos	RROutput id;
270442542f5fSchristos
270542542f5fSchristos
270642542f5fSchristos	DBG(X11, ("%s(%s)\n", __func__, DisplayString(dpy)));
270742542f5fSchristos	clone = add_clone(ctx);
270842542f5fSchristos	if (clone == NULL)
270942542f5fSchristos		return -ENOMEM;
271042542f5fSchristos
271142542f5fSchristos	clone->depth = 24;
271242542f5fSchristos	clone->next = display->clone;
271342542f5fSchristos	display->clone = clone;
271442542f5fSchristos
271542542f5fSchristos	id = claim_virtual(ctx->display, buf, ctx->nclone);
271642542f5fSchristos	if (id == 0) {
271742542f5fSchristos		fprintf(stderr, "Failed to find available VirtualHead \"%s\" for on display \"%s\"\n",
271842542f5fSchristos			buf, DisplayString(dpy));
271942542f5fSchristos	}
272042542f5fSchristos	ret = clone_output_init(clone, &clone->src, ctx->display, buf, id);
272142542f5fSchristos	if (ret) {
272242542f5fSchristos		fprintf(stderr, "Failed to add display \"%s\"\n",
272342542f5fSchristos			DisplayString(ctx->display->dpy));
272442542f5fSchristos		return ret;
272542542f5fSchristos	}
272642542f5fSchristos
272742542f5fSchristos	sprintf(buf, "WHOLE");
272842542f5fSchristos	ret = clone_output_init(clone, &clone->dst, display, buf, 0);
272942542f5fSchristos	if (ret) {
273042542f5fSchristos		fprintf(stderr, "Failed to add display \"%s\"\n",
273142542f5fSchristos			DisplayString(dpy));
273242542f5fSchristos		return ret;
273342542f5fSchristos	}
273442542f5fSchristos
273542542f5fSchristos	ret = clone_init_depth(clone);
273642542f5fSchristos	if (ret) {
273742542f5fSchristos		fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n",
273842542f5fSchristos			DisplayString(dpy));
273942542f5fSchristos		return ret;
274042542f5fSchristos	}
274142542f5fSchristos
274242542f5fSchristos	/* Replace the modes on the local VIRTUAL output with the remote Screen */
274342542f5fSchristos	scr = ScreenOfDisplay(dpy, DefaultScreen(dpy));
274442542f5fSchristos	clone->width = scr->width;
274542542f5fSchristos	clone->height = scr->height;
274642542f5fSchristos	clone->dst.x = 0;
274742542f5fSchristos	clone->dst.y = 0;
274842542f5fSchristos	clone->dst.rr_crtc = -1;
274942542f5fSchristos	ret = clone_update_modes__fixed(clone);
275042542f5fSchristos	if (ret) {
275142542f5fSchristos		fprintf(stderr, "Failed to clone display \"%s\"\n",
275242542f5fSchristos			DisplayString(dpy));
275342542f5fSchristos		return ret;
275442542f5fSchristos	}
275542542f5fSchristos
275642542f5fSchristos	clone->active = ctx->active;
275742542f5fSchristos	ctx->active = clone;
275842542f5fSchristos
275942542f5fSchristos	return 0;
276042542f5fSchristos}
276142542f5fSchristos
276242542f5fSchristosstatic int last_display_add_clones(struct context *ctx)
276342542f5fSchristos{
276442542f5fSchristos	struct display *display = last_display(ctx);
276542542f5fSchristos
276642542f5fSchristos	display->width = DisplayWidth(display->dpy, DefaultScreen(display->dpy));
276742542f5fSchristos	display->height = DisplayHeight(display->dpy, DefaultScreen(display->dpy));
276842542f5fSchristos	DBG(X11, ("%s - initial size %dx%d\n", DisplayString(display->dpy), display->width, display->height));
276942542f5fSchristos
277042542f5fSchristos	if (display->rr_active)
277142542f5fSchristos		return last_display_add_clones__randr(ctx);
277242542f5fSchristos
277342542f5fSchristos	if (display->xinerama_active)
277442542f5fSchristos		return last_display_add_clones__xinerama(ctx);
277542542f5fSchristos
277642542f5fSchristos	return last_display_add_clones__display(ctx);
277742542f5fSchristos}
277842542f5fSchristos
277942542f5fSchristosstatic int last_display_clone(struct context *ctx, int fd)
278042542f5fSchristos{
278142542f5fSchristos	fd = add_fd(ctx, fd);
278242542f5fSchristos	if (fd < 0)
278342542f5fSchristos		return fd;
278442542f5fSchristos
278542542f5fSchristos	fd = last_display_add_clones(ctx);
278642542f5fSchristos	if (fd)
278742542f5fSchristos		return fd;
278842542f5fSchristos
278942542f5fSchristos	return 0;
279042542f5fSchristos}
279142542f5fSchristos
279242542f5fSchristosstatic int first_display_has_singleton(struct context *ctx)
279342542f5fSchristos{
279442542f5fSchristos	struct display *display = ctx->display;
279542542f5fSchristos	unsigned long nitems, bytes;
279642542f5fSchristos	unsigned char *prop;
279742542f5fSchristos	int format;
279842542f5fSchristos	Atom type;
279942542f5fSchristos
280042542f5fSchristos	ctx->singleton = XInternAtom(display->dpy, "intel-virtual-output-singleton", False);
280142542f5fSchristos
280242542f5fSchristos	XGetWindowProperty(display->dpy, display->root, ctx->singleton,
280342542f5fSchristos			   0, 0, 0, AnyPropertyType, &type, &format, &nitems, &bytes, &prop);
280442542f5fSchristos	DBG(X11, ("%s: singleton registered? %d\n", DisplayString(display->dpy), type != None));
280542542f5fSchristos	return type != None;
280642542f5fSchristos}
280742542f5fSchristos
280842542f5fSchristosstatic int first_display_wait_for_ack(struct context *ctx, int timeout, int id)
280942542f5fSchristos{
281042542f5fSchristos	struct display *display = ctx->display;
281142542f5fSchristos	struct pollfd pfd;
281242542f5fSchristos	char expect[6]; /* "1234R\0" */
281342542f5fSchristos
281442542f5fSchristos	sprintf(expect, "%04xR", id);
281542542f5fSchristos	DBG(X11, ("%s: wait for act '%c%c%c%c%c'\n",
281642542f5fSchristos	     DisplayString(display->dpy),
281742542f5fSchristos	     expect[0], expect[1], expect[2], expect[3], expect[4]));
281842542f5fSchristos
281942542f5fSchristos	XFlush(display->dpy);
282042542f5fSchristos
282142542f5fSchristos	pfd.fd = ConnectionNumber(display->dpy);
282242542f5fSchristos	pfd.events = POLLIN;
282342542f5fSchristos	do {
282442542f5fSchristos		if (poll(&pfd, 1, timeout) <= 0)
282542542f5fSchristos			return -ETIME;
282642542f5fSchristos
282742542f5fSchristos		while (XPending(display->dpy)) {
282842542f5fSchristos			XEvent e;
282942542f5fSchristos			XClientMessageEvent *cme;
283042542f5fSchristos
283142542f5fSchristos			XNextEvent(display->dpy, &e);
283242542f5fSchristos			DBG(X11, ("%s: reading event type %d\n", DisplayString(display->dpy), e.type));
283342542f5fSchristos
283442542f5fSchristos			if (e.type != ClientMessage)
283542542f5fSchristos				continue;
283642542f5fSchristos
283742542f5fSchristos			cme = (XClientMessageEvent *)&e;
283842542f5fSchristos			if (cme->message_type != ctx->singleton)
283942542f5fSchristos				continue;
284042542f5fSchristos			if (cme->format != 8)
284142542f5fSchristos				continue;
284242542f5fSchristos
284342542f5fSchristos			DBG(X11, ("%s: client message '%c%c%c%c%c'\n",
284442542f5fSchristos			     DisplayString(display->dpy),
284542542f5fSchristos			     cme->data.b[0],
284642542f5fSchristos			     cme->data.b[1],
284742542f5fSchristos			     cme->data.b[2],
284842542f5fSchristos			     cme->data.b[3],
284942542f5fSchristos			     cme->data.b[4]));
285042542f5fSchristos			if (memcmp(cme->data.b, expect, 5))
285142542f5fSchristos				continue;
285242542f5fSchristos
285342542f5fSchristos			return -atoi(cme->data.b + 5);
285442542f5fSchristos		}
285542542f5fSchristos	} while (1);
285642542f5fSchristos}
285742542f5fSchristos
285842542f5fSchristos#if defined(__GNUC__) && (__GNUC__ > 3)
285942542f5fSchristos__attribute__((format(gnu_printf, 3, 4)))
286042542f5fSchristos#endif
286142542f5fSchristosstatic int first_display_send_command(struct context *ctx, int timeout,
286242542f5fSchristos				      const char *format,
286342542f5fSchristos				      ...)
286442542f5fSchristos{
286542542f5fSchristos	struct display *display = ctx->display;
286642542f5fSchristos	char buf[1024], *b;
286742542f5fSchristos	int len, id;
286842542f5fSchristos	va_list va;
286942542f5fSchristos
287042542f5fSchristos	id = rand() & 0xffff;
287142542f5fSchristos	sprintf(buf, "%04x", id);
287242542f5fSchristos	va_start(va, format);
287342542f5fSchristos	len = vsnprintf(buf+4, sizeof(buf)-4, format, va)+5;
287442542f5fSchristos	va_end(va);
287542542f5fSchristos	assert(len < sizeof(buf));
287642542f5fSchristos
287742542f5fSchristos	DBG(X11, ("%s: send command '%s'\n", DisplayString(display->dpy), buf));
287842542f5fSchristos
287942542f5fSchristos	b = buf;
288042542f5fSchristos	while (len) {
288142542f5fSchristos		XClientMessageEvent msg;
288242542f5fSchristos		int n = len;
288342542f5fSchristos		if (n > sizeof(msg.data.b))
288442542f5fSchristos			n = sizeof(msg.data.b);
288542542f5fSchristos		len -= n;
288642542f5fSchristos
288742542f5fSchristos		msg.type = ClientMessage;
288842542f5fSchristos		msg.serial = 0;
288942542f5fSchristos		msg.message_type = ctx->singleton;
289042542f5fSchristos		msg.format = 8;
289142542f5fSchristos		memcpy(msg.data.b, b, n);
289242542f5fSchristos		b += n;
289342542f5fSchristos
289442542f5fSchristos		XSendEvent(display->dpy, display->root, False, PropertyChangeMask, (XEvent *)&msg);
289542542f5fSchristos	}
289642542f5fSchristos
289742542f5fSchristos	return first_display_wait_for_ack(ctx, timeout, id);
289842542f5fSchristos}
289942542f5fSchristos
290042542f5fSchristosstatic void first_display_reply(struct context *ctx, int result)
290142542f5fSchristos{
290242542f5fSchristos	struct display *display = ctx->display;
290342542f5fSchristos	XClientMessageEvent msg;
290442542f5fSchristos
290542542f5fSchristos	sprintf(msg.data.b, "%c%c%c%cR%d",
290642542f5fSchristos	     ctx->command[0],
290742542f5fSchristos	     ctx->command[1],
290842542f5fSchristos	     ctx->command[2],
290942542f5fSchristos	     ctx->command[3],
291042542f5fSchristos	     -result);
291142542f5fSchristos
291242542f5fSchristos	DBG(X11, ("%s: send reply '%s'\n", DisplayString(display->dpy), msg.data.b));
291342542f5fSchristos
291442542f5fSchristos	msg.type = ClientMessage;
291542542f5fSchristos	msg.serial = 0;
291642542f5fSchristos	msg.message_type = ctx->singleton;
291742542f5fSchristos	msg.format = 8;
291842542f5fSchristos
291942542f5fSchristos	XSendEvent(display->dpy, display->root, False, PropertyChangeMask, (XEvent *)&msg);
292042542f5fSchristos	XFlush(display->dpy);
292142542f5fSchristos}
292242542f5fSchristos
292342542f5fSchristosstatic void first_display_handle_command(struct context *ctx,
292442542f5fSchristos					 const char *msg)
292542542f5fSchristos{
292642542f5fSchristos	int len;
292742542f5fSchristos
292842542f5fSchristos	DBG(X11, ("client message!\n"));
292942542f5fSchristos
293042542f5fSchristos	for (len = 0; len < 20 && msg[len]; len++)
293142542f5fSchristos		;
293242542f5fSchristos
293342542f5fSchristos	if (ctx->command_continuation + len > sizeof(ctx->command)) {
293442542f5fSchristos		ctx->command_continuation = 0;
293542542f5fSchristos		return;
293642542f5fSchristos	}
293742542f5fSchristos
293842542f5fSchristos	memcpy(ctx->command + ctx->command_continuation, msg, len);
293942542f5fSchristos	ctx->command_continuation += len;
294042542f5fSchristos
294142542f5fSchristos	if (len < 20) {
294242542f5fSchristos		ctx->command[ctx->command_continuation] = 0;
294342542f5fSchristos		DBG(X11, ("client command complete! '%s'\n", ctx->command));
294442542f5fSchristos		switch (ctx->command[4]) {
294542542f5fSchristos		case 'B':
294642542f5fSchristos			first_display_reply(ctx, last_display_clone(ctx, bumblebee_open(ctx)));
294742542f5fSchristos			break;
294842542f5fSchristos		case 'C':
294942542f5fSchristos			first_display_reply(ctx, last_display_clone(ctx, display_open(ctx, ctx->command + 5)));
295042542f5fSchristos			break;
295142542f5fSchristos		case 'P':
295242542f5fSchristos			first_display_reply(ctx, 0);
295342542f5fSchristos			break;
295442542f5fSchristos		case 'R':
295542542f5fSchristos			break;
295642542f5fSchristos		}
295742542f5fSchristos		ctx->command_continuation = 0;
295842542f5fSchristos		return;
295942542f5fSchristos	}
296042542f5fSchristos}
296142542f5fSchristos
296242542f5fSchristosstatic int first_display_register_as_singleton(struct context *ctx)
296342542f5fSchristos{
296442542f5fSchristos	struct display *display = ctx->display;
296542542f5fSchristos	struct pollfd pfd;
296642542f5fSchristos
296742542f5fSchristos	XChangeProperty(display->dpy, display->root, ctx->singleton,
296842542f5fSchristos			XA_STRING, 8, PropModeReplace, (unsigned char *)".", 1);
296942542f5fSchristos	XFlush(display->dpy);
297042542f5fSchristos
297142542f5fSchristos	/* And eat the notify (presuming that it is ours!) */
297242542f5fSchristos
297342542f5fSchristos	pfd.fd = ConnectionNumber(display->dpy);
297442542f5fSchristos	pfd.events = POLLIN;
297542542f5fSchristos	do {
297642542f5fSchristos		if (poll(&pfd, 1, 1000) <= 0) {
297742542f5fSchristos			fprintf(stderr, "Failed to register as singleton\n");
297842542f5fSchristos			return EBUSY;
297942542f5fSchristos		}
298042542f5fSchristos
298142542f5fSchristos		while (XPending(display->dpy)) {
298242542f5fSchristos			XEvent e;
298342542f5fSchristos
298442542f5fSchristos			XNextEvent(display->dpy, &e);
298542542f5fSchristos			DBG(X11, ("%s: reading event type %d\n", DisplayString(display->dpy), e.type));
298642542f5fSchristos
298742542f5fSchristos			if (e.type == PropertyNotify &&
298842542f5fSchristos			    ((XPropertyEvent *)&e)->atom == ctx->singleton)
298942542f5fSchristos				return 0;
299042542f5fSchristos		}
299142542f5fSchristos	} while (1);
299242542f5fSchristos}
299342542f5fSchristos
299442542f5fSchristosstatic void display_flush_send(struct display *display)
299542542f5fSchristos{
299642542f5fSchristos	XShmCompletionEvent e;
299742542f5fSchristos
299842542f5fSchristos	if (!display->send)
299942542f5fSchristos		return;
300042542f5fSchristos
300142542f5fSchristos	DBG(X11, ("%s flushing send (serial now %ld) (has shm send? %d)\n",
300242542f5fSchristos	     DisplayString(display->dpy),
300342542f5fSchristos	     (long)NextRequest(display->dpy),
300442542f5fSchristos	     display->shm_event));
300542542f5fSchristos
300642542f5fSchristos	display->send = 0;
300742542f5fSchristos
300842542f5fSchristos	if (display->shm_event == 0) {
300942542f5fSchristos		XSync(display->dpy, False);
301042542f5fSchristos		display->flush = 0;
301142542f5fSchristos		return;
301242542f5fSchristos	}
301342542f5fSchristos
301442542f5fSchristos	memset(&e, 0, sizeof(e));
301542542f5fSchristos	e.type = display->shm_event;
301642542f5fSchristos	e.send_event = 1;
301742542f5fSchristos	e.drawable = display->root;
301842542f5fSchristos	e.major_code = display->shm_opcode;
301942542f5fSchristos	e.minor_code = X_ShmPutImage;
302042542f5fSchristos
302142542f5fSchristos	XSendEvent(display->dpy, display->root, False, 0, (XEvent *)&e);
302242542f5fSchristos	display_mark_flush(display);
302342542f5fSchristos}
302442542f5fSchristos
302542542f5fSchristosstatic void display_sync(struct display *display)
302642542f5fSchristos{
302742542f5fSchristos	if (display->skip_clone == 0)
302842542f5fSchristos		return;
302942542f5fSchristos
303042542f5fSchristos	if (display->skip_frame++ < 2)
303142542f5fSchristos		return;
303242542f5fSchristos
303342542f5fSchristos	DBG(X11, ("%s forcing sync\n", DisplayString(display->dpy)));
303442542f5fSchristos	XSync(display->dpy, False);
303542542f5fSchristos
303642542f5fSchristos	display->flush = 0;
303742542f5fSchristos	display->send = 0;
303842542f5fSchristos
303942542f5fSchristos	/* Event tracking proven unreliable, disable */
304042542f5fSchristos	display->shm_event = 0;
304142542f5fSchristos}
304242542f5fSchristos
304342542f5fSchristosstatic void display_flush(struct display *display)
304442542f5fSchristos{
304542542f5fSchristos	display_flush_cursor(display);
304642542f5fSchristos	display_flush_send(display);
304742542f5fSchristos
304842542f5fSchristos	display_sync(display);
304942542f5fSchristos
305042542f5fSchristos	if (!display->flush)
305142542f5fSchristos		return;
305242542f5fSchristos
305342542f5fSchristos	DBG(X11, ("%s(%s)\n", __func__, DisplayString(display->dpy)));
305442542f5fSchristos
305542542f5fSchristos	XFlush(display->dpy);
305642542f5fSchristos	display->flush = 0;
305742542f5fSchristos}
305842542f5fSchristos
305942542f5fSchristosstatic int first_display_first_sibling(struct context *ctx)
306042542f5fSchristos{
306142542f5fSchristos	const char *str, *colon;
306242542f5fSchristos	int dpy, scr, len;
306342542f5fSchristos
306442542f5fSchristos	str = DisplayString(ctx->display->dpy);
306542542f5fSchristos	colon = strrchr(str, ':');
306642542f5fSchristos	if (colon == NULL)
306742542f5fSchristos		return -1;
306842542f5fSchristos
306942542f5fSchristos	if (sscanf(colon + 1, "%d.%d", &dpy, &scr) == 1)
307042542f5fSchristos		scr = 0;
307142542f5fSchristos
307242542f5fSchristos	len = (colon - str) + 1;
307342542f5fSchristos	memcpy(ctx->command, str, len);
307442542f5fSchristos	len += sprintf(ctx->command + len, "%d.", dpy);
307542542f5fSchristos	ctx->command_continuation = len;
307642542f5fSchristos
307742542f5fSchristos	return scr + 1;
307842542f5fSchristos}
307942542f5fSchristos
308042542f5fSchristosstatic int first_display_sibling(struct context *ctx, int i)
308142542f5fSchristos{
308242542f5fSchristos	if (i < 0)
308342542f5fSchristos		return 0;
308442542f5fSchristos
308542542f5fSchristos	sprintf(ctx->command + ctx->command_continuation, "%d", i);
308642542f5fSchristos	return 1;
308742542f5fSchristos}
308842542f5fSchristos
308942542f5fSchristos#define first_display_for_each_sibling(CTX, i) \
309042542f5fSchristos	for (i = first_display_first_sibling(CTX); first_display_sibling(CTX, i); i++)
309142542f5fSchristos
309242542f5fSchristosstatic void display_cleanup(struct display *display)
309342542f5fSchristos{
309442542f5fSchristos	Display *dpy = display->dpy;
309542542f5fSchristos	XRRScreenResources *res;
309642542f5fSchristos	int n;
309742542f5fSchristos
309842542f5fSchristos	XGrabServer(dpy);
309942542f5fSchristos
310042542f5fSchristos	res = _XRRGetScreenResourcesCurrent(dpy, display->root);
310142542f5fSchristos	if (res != NULL) {
310242542f5fSchristos		for (n = 0; n < res->ncrtc; n++)
310342542f5fSchristos			disable_crtc(display->dpy, res, res->crtcs[n]);
310442542f5fSchristos
310542542f5fSchristos		XRRFreeScreenResources(res);
310642542f5fSchristos	}
310742542f5fSchristos
310842542f5fSchristos	XUngrabServer(dpy);
310942542f5fSchristos}
311042542f5fSchristos
311142542f5fSchristosstatic void context_cleanup(struct context *ctx)
311242542f5fSchristos{
311342542f5fSchristos	Display *dpy = ctx->display->dpy;
311442542f5fSchristos	XRRScreenResources *res;
311542542f5fSchristos	int i, j;
311642542f5fSchristos
311742542f5fSchristos	for (i = 1; i < ctx->ndisplay; i++)
311842542f5fSchristos		display_cleanup(&ctx->display[i]);
311942542f5fSchristos
312013496ba1Ssnj	if (dpy == NULL)
312113496ba1Ssnj		return;
312213496ba1Ssnj
312342542f5fSchristos	res = _XRRGetScreenResourcesCurrent(dpy, ctx->display->root);
312442542f5fSchristos	if (res == NULL)
312542542f5fSchristos		return;
312642542f5fSchristos
312742542f5fSchristos	XGrabServer(dpy);
312842542f5fSchristos
312942542f5fSchristos	for (i = 0; i < ctx->nclone; i++) {
313042542f5fSchristos		struct clone *clone = &ctx->clones[i];
313142542f5fSchristos		XRROutputInfo *output;
313242542f5fSchristos
313342542f5fSchristos		assert(clone->src.display == ctx->display);
313442542f5fSchristos
313542542f5fSchristos		output = XRRGetOutputInfo(dpy, res, clone->src.rr_output);
313642542f5fSchristos		if (output == NULL)
313742542f5fSchristos			continue;
313842542f5fSchristos
313942542f5fSchristos		disable_crtc(dpy, res, output->crtc);
314042542f5fSchristos		for (j = 0; j < output->nmode; j++)
314142542f5fSchristos			XRRDeleteOutputMode(dpy, clone->src.rr_output, output->modes[j]);
314242542f5fSchristos
314342542f5fSchristos		XRRFreeOutputInfo(output);
314442542f5fSchristos	}
314542542f5fSchristos
314642542f5fSchristos	for (i = 0; i < res->nmode; i++) {
314742542f5fSchristos		if (strncmp(res->modes[i].name, "VIRTUAL", 7) == 0) {
314842542f5fSchristos			XRRDestroyMode(dpy, res->modes[i].id);
314942542f5fSchristos			continue;
315042542f5fSchristos		}
315142542f5fSchristos
315242542f5fSchristos		if (strcmp(res->modes[i].name, "ClaimVirtualHead") == 0) {
315342542f5fSchristos			XRRDestroyMode(dpy, res->modes[i].id);
315442542f5fSchristos			continue;
315542542f5fSchristos		}
315642542f5fSchristos	}
315742542f5fSchristos	XRRFreeScreenResources(res);
315842542f5fSchristos
315942542f5fSchristos	/* And hide them again */
316042542f5fSchristos	res = XRRGetScreenResources(dpy, ctx->display->root);
316142542f5fSchristos	if (res != NULL)
316242542f5fSchristos		XRRFreeScreenResources(res);
316342542f5fSchristos
316442542f5fSchristos	XUngrabServer(dpy);
316542542f5fSchristos
316642542f5fSchristos	if (ctx->singleton)
316742542f5fSchristos		XDeleteProperty(dpy, ctx->display->root, ctx->singleton);
316842542f5fSchristos	XCloseDisplay(dpy);
316942542f5fSchristos}
317042542f5fSchristos
317142542f5fSchristosstatic int done;
317242542f5fSchristos
317342542f5fSchristosstatic void signal_handler(int sig)
317442542f5fSchristos{
317542542f5fSchristos	done = sig;
317642542f5fSchristos}
317742542f5fSchristos
317842542f5fSchristosint main(int argc, char **argv)
317942542f5fSchristos{
318042542f5fSchristos	struct context ctx;
318142542f5fSchristos	const char *src_name = NULL;
318242542f5fSchristos	uint64_t count;
318342542f5fSchristos	int daemonize = 1, bumblebee = 0, siblings = 0, singleton = 1;
318442542f5fSchristos	int i, ret, open, fail;
318542542f5fSchristos
318642542f5fSchristos	signal(SIGPIPE, SIG_IGN);
318742542f5fSchristos
318842542f5fSchristos	while ((i = getopt(argc, argv, "abd:fhSvV:")) != -1) {
318942542f5fSchristos		switch (i) {
319042542f5fSchristos		case 'd':
319142542f5fSchristos			src_name = optarg;
319242542f5fSchristos			break;
319342542f5fSchristos		case 'f':
319442542f5fSchristos			daemonize = 0;
319542542f5fSchristos			break;
319642542f5fSchristos		case 'b':
319742542f5fSchristos			bumblebee = 1;
319842542f5fSchristos			break;
319942542f5fSchristos		case 's':
320042542f5fSchristos			siblings = 1;
320142542f5fSchristos			break;
320242542f5fSchristos		case 'S':
320342542f5fSchristos			singleton = 0;
320442542f5fSchristos			break;
320542542f5fSchristos		case 'v':
320642542f5fSchristos			verbose = ~0;
320742542f5fSchristos			daemonize = 0;
320842542f5fSchristos			break;
320942542f5fSchristos		case 'V':
321042542f5fSchristos			verbose = strtol(optarg, NULL, 0);
321142542f5fSchristos			daemonize = 0;
321242542f5fSchristos			break;
321342542f5fSchristos		case 'h':
321442542f5fSchristos		default:
321542542f5fSchristos			usage(argv[0]);
321642542f5fSchristos			exit(0);
321742542f5fSchristos		}
321842542f5fSchristos	}
321942542f5fSchristos
322013496ba1Ssnj	if (verbose)
322113496ba1Ssnj		printf("intel-virtual-output: version %d.%d.%d\n",
322213496ba1Ssnj		       PACKAGE_VERSION_MAJOR,
322313496ba1Ssnj		       PACKAGE_VERSION_MINOR,
322413496ba1Ssnj		       PACKAGE_VERSION_PATCHLEVEL);
322513496ba1Ssnj
322642542f5fSchristos	ret = context_init(&ctx);
322742542f5fSchristos	if (ret)
322842542f5fSchristos		return -ret;
322942542f5fSchristos
323042542f5fSchristos	XSetErrorHandler(_check_error_handler);
323142542f5fSchristos
323242542f5fSchristos	ret = add_fd(&ctx, display_open(&ctx, src_name));
323342542f5fSchristos	if (ret) {
323442542f5fSchristos		fprintf(stderr, "Unable to connect to \"%s\".\n", src_name ?: getenv("DISPLAY") ?:
323542542f5fSchristos			"<unspecified>, set either the DISPLAY environment variable or pass -d <display name> on the commandline");
323642542f5fSchristos		ret = -ret;
323742542f5fSchristos		goto out;
323842542f5fSchristos	}
323942542f5fSchristos
324042542f5fSchristos	if (singleton) {
324142542f5fSchristos		XSelectInput(ctx.display->dpy, ctx.display->root, PropertyChangeMask);
324242542f5fSchristos		if (first_display_has_singleton(&ctx)) {
324342542f5fSchristos			DBG(X11, ("%s: pinging singleton\n", DisplayString(ctx.display->dpy)));
324442542f5fSchristos			ret = first_display_send_command(&ctx, 2000, "P");
324542542f5fSchristos			if (ret) {
324642542f5fSchristos				if (ret != -ETIME) {
324742542f5fSchristos					ret = -ret;
324842542f5fSchristos					goto out;
324942542f5fSchristos				}
325042542f5fSchristos				DBG(X11, ("No reply from singleton; assuming control\n"));
325142542f5fSchristos			} else {
325242542f5fSchristos				DBG(X11, ("%s: singleton active, sending open commands\n", DisplayString(ctx.display->dpy)));
325342542f5fSchristos
325442542f5fSchristos				open = fail = 0;
325542542f5fSchristos				for (i = optind; i < argc; i++) {
325642542f5fSchristos					ret = first_display_send_command(&ctx, 5000, "C%s", argv[i]);
325742542f5fSchristos					if (ret && ret != -EBUSY) {
325842542f5fSchristos						fprintf(stderr, "Unable to connect to \"%s\".\n", argv[i]);
325942542f5fSchristos						fail++;
326042542f5fSchristos					} else
326142542f5fSchristos						open++;
326242542f5fSchristos				}
326342542f5fSchristos				if (siblings || (optind == argc && !bumblebee)) {
326442542f5fSchristos					first_display_for_each_sibling(&ctx, i) {
326542542f5fSchristos						ret = first_display_send_command(&ctx, 5000, "C%s", ctx.command);
326642542f5fSchristos						if (ret && ret != -EBUSY)
326742542f5fSchristos							break;
326842542f5fSchristos						else
326942542f5fSchristos							open++;
327042542f5fSchristos					}
327142542f5fSchristos				}
327242542f5fSchristos				if (bumblebee || (optind == argc && !siblings)) {
327342542f5fSchristos					ret = first_display_send_command(&ctx, 5000, "B");
327442542f5fSchristos					if (ret && ret != -EBUSY) {
327542542f5fSchristos						if (bumblebee)
327642542f5fSchristos							fprintf(stderr, "Unable to connect to bumblebee.\n");
327742542f5fSchristos						fail++;
327842542f5fSchristos					} else
327942542f5fSchristos						open++;
328042542f5fSchristos				}
328142542f5fSchristos				ret = open || !fail ? 0 : ECONNREFUSED;
328242542f5fSchristos				goto out;
328342542f5fSchristos			}
328442542f5fSchristos		}
328542542f5fSchristos		ret = first_display_register_as_singleton(&ctx);
328642542f5fSchristos		if (ret)
328742542f5fSchristos			goto out;
328842542f5fSchristos	}
328942542f5fSchristos
329042542f5fSchristos	ret = display_init_damage(ctx.display);
329142542f5fSchristos	if (ret)
329242542f5fSchristos		goto out;
329342542f5fSchristos
329442542f5fSchristos	if ((ctx.display->rr_event | ctx.display->rr_error) == 0) {
329542542f5fSchristos		fprintf(stderr, "RandR extension not supported by %s\n", DisplayString(ctx.display->dpy));
329642542f5fSchristos		ret = EINVAL;
329742542f5fSchristos		goto out;
329842542f5fSchristos	}
329942542f5fSchristos	XRRSelectInput(ctx.display->dpy, ctx.display->root, RRScreenChangeNotifyMask);
330042542f5fSchristos	XFixesSelectCursorInput(ctx.display->dpy, ctx.display->root, XFixesDisplayCursorNotifyMask);
330142542f5fSchristos
330242542f5fSchristos	ret = add_fd(&ctx, record_mouse(&ctx));
330342542f5fSchristos	if (ret) {
330442542f5fSchristos		fprintf(stderr, "XTEST extension not supported by display \"%s\"\n", DisplayString(ctx.display->dpy));
330542542f5fSchristos		ret = -ret;
330642542f5fSchristos		goto out;
330742542f5fSchristos	}
330842542f5fSchristos
330942542f5fSchristos	open = fail = 0;
331042542f5fSchristos	for (i = optind; i < argc; i++) {
331142542f5fSchristos		ret = last_display_clone(&ctx, display_open(&ctx, argv[i]));
331242542f5fSchristos		if (ret && ret != -EBUSY) {
331342542f5fSchristos			fprintf(stderr, "Unable to connect to \"%s\".\n", argv[i]);
331442542f5fSchristos			fail++;
331542542f5fSchristos		} else
331642542f5fSchristos			open++;
331742542f5fSchristos	}
331842542f5fSchristos	if (siblings || (optind == argc && !bumblebee)) {
331942542f5fSchristos		first_display_for_each_sibling(&ctx, i) {
332042542f5fSchristos			ret = last_display_clone(&ctx, display_open(&ctx, ctx.command));
332142542f5fSchristos			if (ret && ret != -EBUSY)
332242542f5fSchristos				break;
332342542f5fSchristos			else
332442542f5fSchristos				open++;
332542542f5fSchristos		}
332642542f5fSchristos	}
332742542f5fSchristos	if (bumblebee || (optind == argc && !siblings)) {
332842542f5fSchristos		ret = last_display_clone(&ctx, bumblebee_open(&ctx));
332942542f5fSchristos		if (ret && ret != -EBUSY) {
333042542f5fSchristos			if (bumblebee)
333142542f5fSchristos				fprintf(stderr, "Unable to connect to bumblebee.\n");
333242542f5fSchristos			fail++;
333342542f5fSchristos		} else
333442542f5fSchristos			open++;
333542542f5fSchristos	}
333642542f5fSchristos	if (open == 0) {
333742542f5fSchristos		ret = fail ? ECONNREFUSED : 0;
333842542f5fSchristos		goto out;
333942542f5fSchristos	}
334042542f5fSchristos
334142542f5fSchristos	if (daemonize && daemon(0, 0)) {
334242542f5fSchristos		ret = EINVAL;
334342542f5fSchristos		goto out;
334442542f5fSchristos	}
334542542f5fSchristos
334642542f5fSchristos	signal(SIGHUP, signal_handler);
334742542f5fSchristos	signal(SIGINT, signal_handler);
334842542f5fSchristos	signal(SIGTERM, signal_handler);
334942542f5fSchristos
335042542f5fSchristos	ctx.command_continuation = 0;
335142542f5fSchristos	while (!done) {
335242542f5fSchristos		XEvent e;
335342542f5fSchristos		int reconfigure = 0;
335442542f5fSchristos		int rr_update = 0;
335542542f5fSchristos
335642542f5fSchristos		DBG(POLL, ("polling - enable timer? %d, nfd=%d, ndisplay=%d\n", ctx.timer_active, ctx.nfd, ctx.ndisplay));
335742542f5fSchristos		ret = poll(ctx.pfd + !ctx.timer_active, ctx.nfd - !ctx.timer_active, -1);
335842542f5fSchristos		if (ret <= 0)
335942542f5fSchristos			break;
336042542f5fSchristos
336142542f5fSchristos		/* pfd[0] is the timer, pfd[1] is the local display, pfd[2] is the mouse, pfd[3+] are the remotes */
336242542f5fSchristos
336342542f5fSchristos		DBG(POLL, ("poll reports %d fd awake\n", ret));
336442542f5fSchristos		if (ctx.pfd[1].revents || XPending(ctx.display[0].dpy)) {
336542542f5fSchristos			DBG(POLL,("%s woken up\n", DisplayString(ctx.display[0].dpy)));
336642542f5fSchristos			do {
336742542f5fSchristos				XNextEvent(ctx.display->dpy, &e);
336842542f5fSchristos
336942542f5fSchristos				if (e.type == ctx.display->damage_event + XDamageNotify ) {
337042542f5fSchristos					const XDamageNotifyEvent *de = (const XDamageNotifyEvent *)&e;
337142542f5fSchristos					struct clone *clone;
337242542f5fSchristos
337342542f5fSchristos					DBG(DAMAGE, ("%s damaged: (%d, %d)x(%d, %d)\n",
337442542f5fSchristos					     DisplayString(ctx.display->dpy),
337542542f5fSchristos					     de->area.x, de->area.y, de->area.width, de->area.height));
337642542f5fSchristos
337742542f5fSchristos					for (clone = ctx.active; clone; clone = clone->active)
337842542f5fSchristos						clone_damage(clone, &de->area);
337942542f5fSchristos
338042542f5fSchristos					if (ctx.active)
338142542f5fSchristos						context_enable_timer(&ctx);
338242542f5fSchristos				} else if (e.type == ctx.display->xfixes_event + XFixesCursorNotify) {
338342542f5fSchristos					XFixesCursorImage *cur;
338442542f5fSchristos
338542542f5fSchristos					DBG(CURSOR, ("%s cursor changed\n",
338642542f5fSchristos					     DisplayString(ctx.display->dpy)));
338742542f5fSchristos
338842542f5fSchristos					cur = XFixesGetCursorImage(ctx.display->dpy);
338942542f5fSchristos					if (cur == NULL)
339042542f5fSchristos						continue;
339142542f5fSchristos
339242542f5fSchristos					for (i = 1; i < ctx.ndisplay; i++)
339342542f5fSchristos						display_load_visible_cursor(&ctx.display[i], cur);
339442542f5fSchristos
339542542f5fSchristos					XFree(cur);
339642542f5fSchristos				} else if (e.type == ctx.display->rr_event + RRScreenChangeNotify) {
339742542f5fSchristos					DBG(XRR, ("%s screen changed (reconfigure pending? %d)\n",
339842542f5fSchristos					     DisplayString(ctx.display->dpy), reconfigure));
339942542f5fSchristos					reconfigure = 1;
340042542f5fSchristos				} else if (e.type == PropertyNotify) {
340142542f5fSchristos					XPropertyEvent *pe = (XPropertyEvent *)&e;
340242542f5fSchristos					if (pe->atom == ctx.singleton) {
340342542f5fSchristos						DBG(X11, ("lost control of singleton\n"));
340442542f5fSchristos						return 0;
340542542f5fSchristos					}
340642542f5fSchristos				} else if (e.type == ClientMessage) {
340742542f5fSchristos					XClientMessageEvent *cme;
340842542f5fSchristos
340942542f5fSchristos					DBG(X11, ("%s client message\n",
341042542f5fSchristos					     DisplayString(ctx.display->dpy)));
341142542f5fSchristos
341242542f5fSchristos					cme = (XClientMessageEvent *)&e;
341342542f5fSchristos					if (cme->message_type != ctx.singleton)
341442542f5fSchristos						continue;
341542542f5fSchristos					if (cme->format != 8)
341642542f5fSchristos						continue;
341742542f5fSchristos
341842542f5fSchristos					first_display_handle_command(&ctx, cme->data.b);
341942542f5fSchristos				} else {
342042542f5fSchristos					DBG(X11, ("unknown event %d\n", e.type));
342142542f5fSchristos				}
342242542f5fSchristos			} while (XEventsQueued(ctx.display->dpy, QueuedAfterReading));
342342542f5fSchristos		}
342442542f5fSchristos
342542542f5fSchristos		for (i = 1; i < ctx.ndisplay; i++) {
342642542f5fSchristos			if (ctx.pfd[i+2].revents == 0 && !XPending(ctx.display[i].dpy))
342742542f5fSchristos				continue;
342842542f5fSchristos
342942542f5fSchristos			DBG(POLL, ("%s woken up\n", DisplayString(ctx.display[i].dpy)));
343042542f5fSchristos			do {
343142542f5fSchristos				XNextEvent(ctx.display[i].dpy, &e);
343242542f5fSchristos
343342542f5fSchristos				DBG(POLL, ("%s received event %d\n", DisplayString(ctx.display[i].dpy), e.type));
343442542f5fSchristos				if (ctx.display[i].rr_active && e.type == ctx.display[i].rr_event + RRNotify) {
343542542f5fSchristos					XRRNotifyEvent *re = (XRRNotifyEvent *)&e;
343642542f5fSchristos
343742542f5fSchristos					DBG(XRR, ("%s received RRNotify, type %d\n", DisplayString(ctx.display[i].dpy), re->subtype));
343842542f5fSchristos					if (re->subtype == RRNotify_OutputChange) {
343942542f5fSchristos						XRROutputPropertyNotifyEvent *ro = (XRROutputPropertyNotifyEvent *)re;
344042542f5fSchristos						struct clone *clone;
344142542f5fSchristos
344242542f5fSchristos						DBG(XRR, ("%s RRNotify_OutputChange, timestamp %ld\n", DisplayString(ctx.display[i].dpy), ro->timestamp));
344342542f5fSchristos						for (clone = ctx.display[i].clone; clone; clone = clone->next) {
344442542f5fSchristos							if (clone->dst.rr_output == ro->output)
344542542f5fSchristos								rr_update = clone->rr_update = 1;
344642542f5fSchristos						}
344742542f5fSchristos					}
344842542f5fSchristos				}
344942542f5fSchristos			} while (XEventsQueued(ctx.display[i].dpy, QueuedAfterReading));
345042542f5fSchristos		}
345142542f5fSchristos
345242542f5fSchristos		if (rr_update) {
345342542f5fSchristos			for (i = 0; i < ctx.nclone; i++)
345442542f5fSchristos				clone_update(&ctx.clones[i]);
345542542f5fSchristos		}
345642542f5fSchristos
345742542f5fSchristos		if (reconfigure && context_update(&ctx))
345842542f5fSchristos			display_reset_damage(ctx.display);
345942542f5fSchristos
346042542f5fSchristos		while (XPending(ctx.record)) /* discard all implicit events */
346142542f5fSchristos			XNextEvent(ctx.record, &e);
346242542f5fSchristos
346342542f5fSchristos		if (ctx.timer_active && read(ctx.timer, &count, sizeof(count)) > 0) {
346442542f5fSchristos			struct clone *clone;
346542542f5fSchristos
346642542f5fSchristos			DBG(TIMER, ("%s timer expired (count=%ld)\n", DisplayString(ctx.display->dpy), (long)count));
346742542f5fSchristos			ret = 0;
346842542f5fSchristos
346942542f5fSchristos			if (ctx.active) {
347042542f5fSchristos				DBG(DAMAGE, ("%s clearing damage\n", DisplayString(ctx.display->dpy)));
347142542f5fSchristos				XDamageSubtract(ctx.display->dpy, ctx.display->damage, None, None);
347242542f5fSchristos				ctx.display->flush = 1;
347342542f5fSchristos			}
347442542f5fSchristos
347542542f5fSchristos			for (clone = ctx.active; clone; clone = clone->active)
347642542f5fSchristos				ret |= clone_paint(clone);
347742542f5fSchristos
347842542f5fSchristos			for (i = 0; i < ctx.ndisplay; i++)
347942542f5fSchristos				display_flush(&ctx.display[i]);
348042542f5fSchristos
348142542f5fSchristos			DBG(TIMER, ("%s timer still active? %d\n", DisplayString(ctx.display->dpy), ret != 0));
348242542f5fSchristos			ctx.timer_active = ret != 0;
348342542f5fSchristos		}
348442542f5fSchristos	}
348542542f5fSchristos
348642542f5fSchristos	ret = 0;
348742542f5fSchristosout:
348842542f5fSchristos	context_cleanup(&ctx);
348942542f5fSchristos	return ret;
349042542f5fSchristos}
3491