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>
34fe8aea9eSmrg#include <X11/extensions/scrnsaver.h>
3542542f5fSchristos#include <X11/extensions/XShm.h>
3642542f5fSchristos#if HAVE_X11_EXTENSIONS_SHMPROTO_H
3742542f5fSchristos#include <X11/extensions/shmproto.h>
3842542f5fSchristos#elif HAVE_X11_EXTENSIONS_SHMSTR_H
3942542f5fSchristos#include <X11/extensions/shmstr.h>
4042542f5fSchristos#else
4142542f5fSchristos#error Failed to find the right header for X11 MIT-SHM protocol definitions
4242542f5fSchristos#endif
4342542f5fSchristos#include <X11/extensions/Xdamage.h>
4442542f5fSchristos#if HAVE_X11_EXTENSIONS_XINERAMA_H
4542542f5fSchristos#include <X11/extensions/Xinerama.h>
4642542f5fSchristos#define USE_XINERAMA
4742542f5fSchristos#endif
4842542f5fSchristos#include <X11/extensions/Xrandr.h>
4942542f5fSchristos#include <X11/extensions/Xrender.h>
5042542f5fSchristos#include <X11/Xcursor/Xcursor.h>
5142542f5fSchristos#include <pixman.h>
5242542f5fSchristos
5342542f5fSchristos#include <sys/types.h>
5442542f5fSchristos#include <sys/ipc.h>
5542542f5fSchristos#include <sys/shm.h>
5642542f5fSchristos#include <sys/timerfd.h>
5742542f5fSchristos#include <sys/poll.h>
5842542f5fSchristos#include <sys/socket.h>
5942542f5fSchristos#include <sys/un.h>
6042542f5fSchristos
6142542f5fSchristos#include <stdarg.h>
6242542f5fSchristos#include <stdio.h>
6342542f5fSchristos#include <stdlib.h>
6442542f5fSchristos#include <stdint.h>
6542542f5fSchristos#include <signal.h>
6642542f5fSchristos#include <getopt.h>
6742542f5fSchristos#include <limits.h>
6842542f5fSchristos#include <unistd.h>
6942542f5fSchristos#include <fcntl.h>
7042542f5fSchristos#include <assert.h>
7142542f5fSchristos
7242542f5fSchristos#define FORCE_FULL_REDRAW 0
7342542f5fSchristos#define FORCE_16BIT_XFER 0
7442542f5fSchristos
7542542f5fSchristos#define DBG(v, x) if (verbose & v) printf x
7642542f5fSchristosstatic int verbose;
7742542f5fSchristos#define X11 0x1
7842542f5fSchristos#define XRR 0x1
7942542f5fSchristos#define TIMER 0x4
8042542f5fSchristos#define DRAW 0x8
8142542f5fSchristos#define DAMAGE 0x10
8242542f5fSchristos#define CURSOR 0x20
83fe8aea9eSmrg#define SCREEN 0x40
84fe8aea9eSmrg#define POLL 0x80
8542542f5fSchristos
8642542f5fSchristosstruct display {
8742542f5fSchristos	Display *dpy;
8842542f5fSchristos	struct clone *clone;
8942542f5fSchristos	struct context *ctx;
9042542f5fSchristos
91fe8aea9eSmrg	int saver_event, saver_error, saver_active;
9242542f5fSchristos	int damage_event, damage_error;
9342542f5fSchristos	int xfixes_event, xfixes_error;
9442542f5fSchristos	int rr_event, rr_error, rr_active;
9542542f5fSchristos	int xinerama_event, xinerama_error, xinerama_active;
9642542f5fSchristos	int dri3_active;
9742542f5fSchristos	Window root;
9842542f5fSchristos	Visual *visual;
9942542f5fSchristos	Damage damage;
10042542f5fSchristos
10142542f5fSchristos	int width;
10242542f5fSchristos	int height;
10342542f5fSchristos	int depth;
104fe8aea9eSmrg	int active;
10542542f5fSchristos
10642542f5fSchristos	XRenderPictFormat *root_format;
10742542f5fSchristos	XRenderPictFormat *rgb16_format;
10842542f5fSchristos	XRenderPictFormat *rgb24_format;
10942542f5fSchristos
11042542f5fSchristos	int has_shm;
11142542f5fSchristos	int has_shm_pixmap;
11242542f5fSchristos	int shm_opcode;
11342542f5fSchristos	int shm_event;
11442542f5fSchristos
11542542f5fSchristos	Cursor invisible_cursor;
11642542f5fSchristos	Cursor visible_cursor;
11742542f5fSchristos
118fe8aea9eSmrg	XcursorImage cursor_image; /* first only */
11942542f5fSchristos	int cursor_serial;
12042542f5fSchristos	int cursor_x;
12142542f5fSchristos	int cursor_y;
12242542f5fSchristos	int cursor_moved;
12342542f5fSchristos	int cursor_visible;
12442542f5fSchristos	int cursor;
12542542f5fSchristos
12642542f5fSchristos	int flush;
12742542f5fSchristos	int send;
12842542f5fSchristos	int skip_clone;
12942542f5fSchristos	int skip_frame;
130fe8aea9eSmrg
131fe8aea9eSmrg	struct {
132fe8aea9eSmrg		int timeout;
133fe8aea9eSmrg		int interval;
134fe8aea9eSmrg		int prefer_blank;
135fe8aea9eSmrg		int allow_exp;
136fe8aea9eSmrg	} saver;
13742542f5fSchristos};
13842542f5fSchristos
13942542f5fSchristosstruct output {
14042542f5fSchristos	struct display *display;
14142542f5fSchristos	Display *dpy;
14242542f5fSchristos	char *name;
14342542f5fSchristos	RROutput rr_output;
14442542f5fSchristos	RRCrtc rr_crtc;
14542542f5fSchristos	Window window;
14642542f5fSchristos	Picture win_picture;
14742542f5fSchristos	Picture pix_picture;
14842542f5fSchristos	Pixmap pixmap;
14942542f5fSchristos	GC gc;
15042542f5fSchristos
15142542f5fSchristos	long serial;
15242542f5fSchristos	int use_shm;
15342542f5fSchristos	int use_shm_pixmap;
15442542f5fSchristos	XShmSegmentInfo shm;
15542542f5fSchristos
15642542f5fSchristos	XRenderPictFormat *use_render;
15742542f5fSchristos
15842542f5fSchristos	int x, y;
159fe8aea9eSmrg	int width, height;
16042542f5fSchristos	XRRModeInfo mode;
16142542f5fSchristos	Rotation rotation;
16242542f5fSchristos};
16342542f5fSchristos
16442542f5fSchristosstruct clone {
16542542f5fSchristos	struct clone *next;
16642542f5fSchristos	struct clone *active;
16742542f5fSchristos
16842542f5fSchristos	struct output src, dst;
16942542f5fSchristos	long timestamp;
17042542f5fSchristos
17142542f5fSchristos	XShmSegmentInfo shm;
17242542f5fSchristos	XImage image;
17342542f5fSchristos
17442542f5fSchristos	int width, height, depth;
17542542f5fSchristos	struct { int x1, x2, y1, y2; } damaged;
17642542f5fSchristos	int rr_update;
17742542f5fSchristos
17842542f5fSchristos	struct dri3_fence {
17942542f5fSchristos		XID xid;
18042542f5fSchristos		void *addr;
18142542f5fSchristos	} dri3;
18242542f5fSchristos};
18342542f5fSchristos
18442542f5fSchristosstruct context {
18542542f5fSchristos	struct display *display;
18642542f5fSchristos	struct clone *clones;
18742542f5fSchristos	struct clone *active;
18842542f5fSchristos	struct pollfd *pfd;
18942542f5fSchristos#define timer pfd[0].fd
19042542f5fSchristos	Display *record;
19142542f5fSchristos	int nclone;
19242542f5fSchristos	int ndisplay;
19342542f5fSchristos	int nfd;
19442542f5fSchristos
19542542f5fSchristos	int timer_active;
19642542f5fSchristos
19742542f5fSchristos	long timestamp;
19842542f5fSchristos	long configTimestamp;
19942542f5fSchristos
20042542f5fSchristos	Atom singleton;
20142542f5fSchristos	char command[1024];
20242542f5fSchristos	int command_continuation;
20342542f5fSchristos};
20442542f5fSchristos
20542542f5fSchristosstatic inline int is_power_of_2(unsigned long n)
20642542f5fSchristos{
20742542f5fSchristos	return n && ((n & (n - 1)) == 0);
20842542f5fSchristos}
20942542f5fSchristos
21042542f5fSchristosstatic int xlib_vendor_is_xorg(Display *dpy)
21142542f5fSchristos{
21242542f5fSchristos	const char *const vendor = ServerVendor(dpy);
21342542f5fSchristos	return strstr(vendor, "X.Org") || strstr(vendor, "Xorg");
21442542f5fSchristos}
21542542f5fSchristos
21642542f5fSchristosstatic inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window)
21742542f5fSchristos{
21842542f5fSchristos	XRRScreenResources *res;
21942542f5fSchristos
22042542f5fSchristos	res = XRRGetScreenResourcesCurrent(dpy, window);
22142542f5fSchristos	if (res == NULL)
22242542f5fSchristos		res = XRRGetScreenResources(dpy, window);
22342542f5fSchristos
22442542f5fSchristos	return res;
22542542f5fSchristos}
22642542f5fSchristos
22742542f5fSchristos#define XORG_VERSION_ENCODE(major,minor,patch,snap) \
22842542f5fSchristos    (((major) * 10000000) + ((minor) * 100000) + ((patch) * 1000) + snap)
22942542f5fSchristos
23042542f5fSchristosstatic int _x_error_occurred;
23142542f5fSchristos
232fe8aea9eSmrgstatic int
233fe8aea9eSmrg_io_error_handler(Display *display)
234fe8aea9eSmrg{
235fe8aea9eSmrg	fprintf(stderr, "XIO error on display %s\n", DisplayString(display));
236fe8aea9eSmrg	abort();
237fe8aea9eSmrg}
238fe8aea9eSmrg
23942542f5fSchristosstatic int
24042542f5fSchristos_check_error_handler(Display     *display,
24142542f5fSchristos		     XErrorEvent *event)
24242542f5fSchristos{
24342542f5fSchristos	DBG(X11, ("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n",
24442542f5fSchristos	     DisplayString(display),
24542542f5fSchristos	     event->serial,
24642542f5fSchristos	     event->error_code,
24742542f5fSchristos	     event->request_code,
24842542f5fSchristos	     event->minor_code));
24942542f5fSchristos	_x_error_occurred = 1;
25042542f5fSchristos	return False; /* ignored */
25142542f5fSchristos}
25242542f5fSchristos
25342542f5fSchristosstatic int
25442542f5fSchristoscan_use_shm(Display *dpy,
25542542f5fSchristos	    Window window,
25642542f5fSchristos	    int *shm_event,
25742542f5fSchristos	    int *shm_opcode,
25842542f5fSchristos	    int *shm_pixmap)
25942542f5fSchristos{
26042542f5fSchristos	XShmSegmentInfo shm;
26142542f5fSchristos	Status success;
26242542f5fSchristos	XExtCodes *codes;
26342542f5fSchristos	int major, minor, has_shm, has_pixmap;
26442542f5fSchristos
265fe8aea9eSmrg	*shm_event = 0;
266fe8aea9eSmrg	*shm_opcode = 0;
267fe8aea9eSmrg	*shm_pixmap = 0;
268fe8aea9eSmrg
26942542f5fSchristos	if (!XShmQueryExtension(dpy))
27042542f5fSchristos		return 0;
27142542f5fSchristos
27242542f5fSchristos	XShmQueryVersion(dpy, &major, &minor, &has_pixmap);
27342542f5fSchristos
27442542f5fSchristos	shm.shmid = shmget(IPC_PRIVATE, 0x1000, IPC_CREAT | 0600);
27542542f5fSchristos	if (shm.shmid == -1)
27642542f5fSchristos		return 0;
27742542f5fSchristos
27842542f5fSchristos	shm.readOnly = 0;
27942542f5fSchristos	shm.shmaddr = shmat(shm.shmid, NULL, 0);
28042542f5fSchristos	if (shm.shmaddr == (char *) -1) {
28142542f5fSchristos		shmctl(shm.shmid, IPC_RMID, NULL);
28242542f5fSchristos		return 0;
28342542f5fSchristos	}
28442542f5fSchristos
28542542f5fSchristos	XSync(dpy, False);
28642542f5fSchristos	_x_error_occurred = 0;
28742542f5fSchristos
28842542f5fSchristos	success = XShmAttach(dpy, &shm);
28942542f5fSchristos
29042542f5fSchristos	XSync(dpy, False);
29142542f5fSchristos	has_shm = success && _x_error_occurred == 0;
29242542f5fSchristos
29342542f5fSchristos	/* As libXext sets the SEND_EVENT bit in the ShmCompletionEvent,
29442542f5fSchristos	 * the Xserver may crash if it does not take care when processing
29542542f5fSchristos	 * the event type. For instance versions of Xorg prior to 1.11.1
29642542f5fSchristos	 * exhibited this bug, and was fixed by:
29742542f5fSchristos	 *
29842542f5fSchristos	 * commit 2d2dce558d24eeea0eb011ec9ebaa6c5c2273c39
29942542f5fSchristos	 * Author: Sam Spilsbury <sam.spilsbury@canonical.com>
30042542f5fSchristos	 * Date:   Wed Sep 14 09:58:34 2011 +0800
30142542f5fSchristos	 *
30242542f5fSchristos	 * Remove the SendEvent bit (0x80) before doing range checks on event type.
30342542f5fSchristos	 */
30442542f5fSchristos	codes = 0;
30542542f5fSchristos	if (has_shm)
30642542f5fSchristos		codes = XInitExtension(dpy, SHMNAME);
30742542f5fSchristos	if (xlib_vendor_is_xorg(dpy) &&
30842542f5fSchristos	    VendorRelease(dpy) < XORG_VERSION_ENCODE(1,11,0,1))
30942542f5fSchristos		codes = 0;
31042542f5fSchristos	if (codes) {
31142542f5fSchristos		XShmCompletionEvent e;
31242542f5fSchristos
31342542f5fSchristos		memset(&e, 0, sizeof(e));
31442542f5fSchristos
31542542f5fSchristos		e.type = codes->first_event;
31642542f5fSchristos		e.send_event = 1;
31742542f5fSchristos		e.serial = 1;
31842542f5fSchristos		e.drawable = window;
31942542f5fSchristos		e.major_code = codes->major_opcode;
32042542f5fSchristos		e.minor_code = X_ShmPutImage;
32142542f5fSchristos
32242542f5fSchristos		e.shmseg = shm.shmid;
32342542f5fSchristos		e.offset = 0;
32442542f5fSchristos
32542542f5fSchristos		XSendEvent(dpy, e.drawable, False, 0, (XEvent *)&e);
32642542f5fSchristos		XSync(dpy, False);
32742542f5fSchristos
32842542f5fSchristos		if (_x_error_occurred == 0) {
32942542f5fSchristos			*shm_opcode = codes->major_opcode;
33042542f5fSchristos			*shm_event = codes->first_event;
33142542f5fSchristos			*shm_pixmap = has_pixmap;
33242542f5fSchristos		}
33342542f5fSchristos	}
33442542f5fSchristos
33542542f5fSchristos	XShmDetach(dpy, &shm);
33642542f5fSchristos	shmctl(shm.shmid, IPC_RMID, NULL);
33742542f5fSchristos	shmdt(shm.shmaddr);
33842542f5fSchristos
33942542f5fSchristos	return has_shm;
34042542f5fSchristos}
34142542f5fSchristos
34242542f5fSchristos#ifdef DRI3
34342542f5fSchristos#include <X11/Xlib-xcb.h>
34442542f5fSchristos#include <X11/xshmfence.h>
34542542f5fSchristos#include <xcb/xcb.h>
346fe8aea9eSmrg#include <xcb/xcbext.h>
34742542f5fSchristos#include <xcb/dri3.h>
34842542f5fSchristos#include <xcb/sync.h>
34942542f5fSchristosstatic Pixmap dri3_create_pixmap(Display *dpy,
35042542f5fSchristos				 Drawable draw,
35142542f5fSchristos				 int width, int height, int depth,
35242542f5fSchristos				 int fd, int bpp, int stride, int size)
35342542f5fSchristos{
35442542f5fSchristos	xcb_connection_t *c = XGetXCBConnection(dpy);
35542542f5fSchristos	xcb_pixmap_t pixmap = xcb_generate_id(c);
35642542f5fSchristos	xcb_dri3_pixmap_from_buffer(c, pixmap, draw, size, width, height, stride, depth, bpp, fd);
35742542f5fSchristos	return pixmap;
35842542f5fSchristos}
35942542f5fSchristos
36042542f5fSchristosstatic int dri3_create_fd(Display *dpy,
36142542f5fSchristos			  Pixmap pixmap,
36242542f5fSchristos			  int *stride)
36342542f5fSchristos{
36442542f5fSchristos	xcb_connection_t *c = XGetXCBConnection(dpy);
36542542f5fSchristos	xcb_dri3_buffer_from_pixmap_cookie_t cookie;
36642542f5fSchristos	xcb_dri3_buffer_from_pixmap_reply_t *reply;
36742542f5fSchristos
36842542f5fSchristos	cookie = xcb_dri3_buffer_from_pixmap(c, pixmap);
36942542f5fSchristos	reply = xcb_dri3_buffer_from_pixmap_reply(c, cookie, NULL);
37042542f5fSchristos	if (!reply)
37142542f5fSchristos		return -1;
37242542f5fSchristos
37342542f5fSchristos	if (reply->nfd != 1)
37442542f5fSchristos		return -1;
37542542f5fSchristos
37642542f5fSchristos	*stride = reply->stride;
37742542f5fSchristos	return xcb_dri3_buffer_from_pixmap_reply_fds(c, reply)[0];
37842542f5fSchristos}
37942542f5fSchristos
38042542f5fSchristosstatic int dri3_query_version(Display *dpy, int *major, int *minor)
38142542f5fSchristos{
38242542f5fSchristos	xcb_connection_t *c = XGetXCBConnection(dpy);
38342542f5fSchristos	xcb_dri3_query_version_reply_t *reply;
384fe8aea9eSmrg	xcb_generic_error_t *error;
38542542f5fSchristos
38642542f5fSchristos	*major = *minor = -1;
38742542f5fSchristos
38842542f5fSchristos	reply = xcb_dri3_query_version_reply(c,
38942542f5fSchristos					     xcb_dri3_query_version(c,
39042542f5fSchristos								    XCB_DRI3_MAJOR_VERSION,
39142542f5fSchristos								    XCB_DRI3_MINOR_VERSION),
392fe8aea9eSmrg					     &error);
393fe8aea9eSmrg	free(error);
39442542f5fSchristos	if (reply == NULL)
39542542f5fSchristos		return -1;
39642542f5fSchristos
39742542f5fSchristos	*major = reply->major_version;
39842542f5fSchristos	*minor = reply->minor_version;
39942542f5fSchristos	free(reply);
40042542f5fSchristos
40142542f5fSchristos	return 0;
40242542f5fSchristos}
40342542f5fSchristos
40442542f5fSchristosstatic int dri3_exists(Display *dpy)
40542542f5fSchristos{
406fe8aea9eSmrg	const xcb_query_extension_reply_t *ext;
40742542f5fSchristos	int major, minor;
40842542f5fSchristos
409fe8aea9eSmrg	ext = xcb_get_extension_data(XGetXCBConnection(dpy), &xcb_dri3_id);
410fe8aea9eSmrg	if (ext == NULL || !ext->present)
411fe8aea9eSmrg		return 0;
412fe8aea9eSmrg
41342542f5fSchristos	if (dri3_query_version(dpy, &major, &minor) < 0)
41442542f5fSchristos		return 0;
41542542f5fSchristos
41642542f5fSchristos	return major >= 0;
41742542f5fSchristos}
41842542f5fSchristos
41942542f5fSchristosstatic void dri3_create_fence(Display *dpy, Drawable d, struct dri3_fence *fence)
42042542f5fSchristos{
42142542f5fSchristos	xcb_connection_t *c = XGetXCBConnection(dpy);
42242542f5fSchristos	struct dri3_fence f;
42342542f5fSchristos	int fd;
42442542f5fSchristos
42542542f5fSchristos	fd = xshmfence_alloc_shm();
42642542f5fSchristos	if (fd < 0)
42742542f5fSchristos		return;
42842542f5fSchristos
42942542f5fSchristos	f.addr = xshmfence_map_shm(fd);
43042542f5fSchristos	if (f.addr == NULL) {
43142542f5fSchristos		close(fd);
43242542f5fSchristos		return;
43342542f5fSchristos	}
43442542f5fSchristos
43542542f5fSchristos	f.xid = xcb_generate_id(c);
43642542f5fSchristos	xcb_dri3_fence_from_fd(c, d, f.xid, 0, fd);
43742542f5fSchristos
43842542f5fSchristos	*fence = f;
43942542f5fSchristos}
44042542f5fSchristos
44142542f5fSchristosstatic void dri3_fence_flush(Display *dpy, struct dri3_fence *fence)
44242542f5fSchristos{
44342542f5fSchristos	xcb_sync_trigger_fence(XGetXCBConnection(dpy), fence->xid);
44442542f5fSchristos}
44542542f5fSchristos
44642542f5fSchristosstatic void dri3_fence_free(Display *dpy, struct dri3_fence *fence)
44742542f5fSchristos{
44842542f5fSchristos	xshmfence_unmap_shm(fence->addr);
44942542f5fSchristos	xcb_sync_destroy_fence(XGetXCBConnection(dpy), fence->xid);
45042542f5fSchristos}
45142542f5fSchristos
45242542f5fSchristos#else
45342542f5fSchristos
45442542f5fSchristosstatic int dri3_exists(Display *dpy)
45542542f5fSchristos{
45642542f5fSchristos	return 0;
45742542f5fSchristos}
45842542f5fSchristos
45942542f5fSchristosstatic void dri3_create_fence(Display *dpy, Drawable d, struct dri3_fence *fence)
46042542f5fSchristos{
46142542f5fSchristos}
46242542f5fSchristos
46342542f5fSchristosstatic void dri3_fence_flush(Display *dpy, struct dri3_fence *fence)
46442542f5fSchristos{
46542542f5fSchristos}
46642542f5fSchristos
46742542f5fSchristosstatic void dri3_fence_free(Display *dpy, struct dri3_fence *fence)
46842542f5fSchristos{
46942542f5fSchristos}
47042542f5fSchristos
47142542f5fSchristosstatic Pixmap dri3_create_pixmap(Display *dpy,
47242542f5fSchristos				 Drawable draw,
47342542f5fSchristos				 int width, int height, int depth,
47442542f5fSchristos				 int fd, int bpp, int stride, int size)
47542542f5fSchristos{
47642542f5fSchristos	return None;
47742542f5fSchristos}
47842542f5fSchristos
47942542f5fSchristosstatic int dri3_create_fd(Display *dpy,
48042542f5fSchristos			  Pixmap pixmap,
48142542f5fSchristos			  int *stride)
48242542f5fSchristos{
48342542f5fSchristos	return -1;
48442542f5fSchristos}
48542542f5fSchristos#endif
48642542f5fSchristos
48742542f5fSchristosstatic int timerfd(int hz)
48842542f5fSchristos{
48942542f5fSchristos	struct itimerspec it;
49042542f5fSchristos	int fd;
49142542f5fSchristos
49242542f5fSchristos	fd = -1;
49342542f5fSchristos#ifdef CLOCK_MONOTONIC_COARSE
49442542f5fSchristos	fd = timerfd_create(CLOCK_MONOTONIC_COARSE, TFD_NONBLOCK);
49542542f5fSchristos#endif
49642542f5fSchristos	if (fd < 0)
49742542f5fSchristos		fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
49842542f5fSchristos	if (fd < 0)
49942542f5fSchristos		return -ETIME;
50042542f5fSchristos
50142542f5fSchristos	it.it_interval.tv_sec = 0;
50242542f5fSchristos	it.it_interval.tv_nsec = 1000000000 / hz;
50342542f5fSchristos	it.it_value = it.it_interval;
50442542f5fSchristos	if (timerfd_settime(fd, 0, &it, NULL) < 0) {
50542542f5fSchristos		close(fd);
50642542f5fSchristos		return -ETIME;
50742542f5fSchristos	}
50842542f5fSchristos
50942542f5fSchristos	return fd;
51042542f5fSchristos}
51142542f5fSchristos
51242542f5fSchristosstatic int context_init(struct context *ctx)
51342542f5fSchristos{
51442542f5fSchristos	struct pollfd *pfd;
51542542f5fSchristos
51642542f5fSchristos	memset(ctx, 0, sizeof(*ctx));
51742542f5fSchristos
51842542f5fSchristos	ctx->pfd = malloc(2*sizeof(struct pollfd));
51942542f5fSchristos	if (ctx->pfd == NULL)
52042542f5fSchristos		return -ENOMEM;
52142542f5fSchristos
52242542f5fSchristos	ctx->clones = malloc(sizeof(struct clone));
52342542f5fSchristos	if (ctx->clones == NULL)
52442542f5fSchristos		return -ENOMEM;
52542542f5fSchristos
52642542f5fSchristos	ctx->display = malloc(sizeof(struct display));
52742542f5fSchristos	if (ctx->display == NULL)
52842542f5fSchristos		return -ENOMEM;
52942542f5fSchristos
53042542f5fSchristos	pfd = memset(&ctx->pfd[ctx->nfd++], 0, sizeof(struct pollfd));
53142542f5fSchristos	pfd->fd = timerfd(60);
53242542f5fSchristos	if (pfd->fd < 0)
53342542f5fSchristos		return pfd->fd;
53442542f5fSchristos	pfd->events = POLLIN;
53542542f5fSchristos
53642542f5fSchristos	return 0;
53742542f5fSchristos}
53842542f5fSchristos
53942542f5fSchristosstatic void context_enable_timer(struct context *ctx)
54042542f5fSchristos{
54142542f5fSchristos	uint64_t count;
54242542f5fSchristos
54342542f5fSchristos	DBG(TIMER, ("%s timer active? %d\n", __func__, ctx->timer_active));
54442542f5fSchristos
54542542f5fSchristos	if (ctx->timer_active)
54642542f5fSchristos		return;
54742542f5fSchristos
54842542f5fSchristos	/* reset timer */
54942542f5fSchristos	count = read(ctx->timer, &count, sizeof(count));
55042542f5fSchristos
55142542f5fSchristos	ctx->timer_active = 1;
55242542f5fSchristos}
55342542f5fSchristos
55442542f5fSchristosstatic int add_fd(struct context *ctx, int fd)
55542542f5fSchristos{
55642542f5fSchristos	struct pollfd *pfd;
55742542f5fSchristos
55842542f5fSchristos	if (fd < 0)
55942542f5fSchristos		return fd;
56042542f5fSchristos
56142542f5fSchristos	if (is_power_of_2(ctx->nfd)) {
56242542f5fSchristos		ctx->pfd = realloc(ctx->pfd, 2*ctx->nfd*sizeof(struct pollfd));
56342542f5fSchristos		if (ctx->pfd == NULL)
56442542f5fSchristos			return -ENOMEM;
56542542f5fSchristos	}
56642542f5fSchristos
56742542f5fSchristos	pfd = memset(&ctx->pfd[ctx->nfd++], 0, sizeof(struct pollfd));
56842542f5fSchristos	pfd->fd = fd;
56942542f5fSchristos	pfd->events = POLLIN;
57042542f5fSchristos	return 0;
57142542f5fSchristos}
57242542f5fSchristos
57342542f5fSchristosstatic void display_mark_flush(struct display *display)
57442542f5fSchristos{
57542542f5fSchristos	DBG(DRAW, ("%s mark flush (flush=%d)\n",
57642542f5fSchristos	     DisplayString(display->dpy), display->flush));
57742542f5fSchristos
57842542f5fSchristos	if (display->flush)
57942542f5fSchristos		return;
58042542f5fSchristos
58142542f5fSchristos	context_enable_timer(display->ctx);
58242542f5fSchristos	display->flush = 1;
58342542f5fSchristos}
58442542f5fSchristos
58542542f5fSchristosstatic int mode_equal(const XRRModeInfo *a, const XRRModeInfo *b)
58642542f5fSchristos{
58742542f5fSchristos	return (a->width == b->width &&
58842542f5fSchristos		a->height == b->height &&
58942542f5fSchristos		a->dotClock == b->dotClock &&
59042542f5fSchristos		a->hSyncStart == b->hSyncStart &&
59142542f5fSchristos		a->hSyncEnd == b->hSyncEnd &&
59242542f5fSchristos		a->hTotal == b->hTotal &&
59342542f5fSchristos		a->hSkew == b->hSkew &&
59442542f5fSchristos		a->vSyncStart == b->vSyncStart &&
59542542f5fSchristos		a->vSyncEnd == b->vSyncEnd &&
59642542f5fSchristos		a->vTotal == b->vTotal &&
59742542f5fSchristos		a->modeFlags == b->modeFlags);
59842542f5fSchristos}
59942542f5fSchristos
60042542f5fSchristosstatic XRRModeInfo *lookup_mode(XRRScreenResources *res, int id)
60142542f5fSchristos{
60242542f5fSchristos	int i;
60342542f5fSchristos
60442542f5fSchristos	for (i = 0; i < res->nmode; i++) {
60542542f5fSchristos		if (res->modes[i].id == id)
60642542f5fSchristos			return &res->modes[i];
60742542f5fSchristos	}
60842542f5fSchristos
60942542f5fSchristos	return NULL;
61042542f5fSchristos}
61142542f5fSchristos
61242542f5fSchristosstatic void clone_update_edid(struct clone *clone)
61342542f5fSchristos{
61442542f5fSchristos	unsigned long nitems, after;
61542542f5fSchristos	unsigned char *data;
61642542f5fSchristos	int format;
61742542f5fSchristos	Atom type;
61842542f5fSchristos
61942542f5fSchristos	if (XRRGetOutputProperty(clone->dst.dpy, clone->dst.rr_output,
62042542f5fSchristos				 XInternAtom(clone->dst.dpy, "EDID", False),
62142542f5fSchristos				 0, 100, False, False, AnyPropertyType,
62242542f5fSchristos				 &type, &format, &nitems, &after, &data) == Success) {
62342542f5fSchristos		XRRChangeOutputProperty(clone->src.dpy, clone->src.rr_output,
62442542f5fSchristos					XInternAtom(clone->src.dpy, "EDID", False),
62542542f5fSchristos					type, format, PropModeReplace, data, nitems);
62642542f5fSchristos	}
62742542f5fSchristos}
62842542f5fSchristos
62942542f5fSchristosstatic int disable_crtc(Display *dpy, XRRScreenResources *res, RRCrtc crtc)
63042542f5fSchristos{
63142542f5fSchristos	XRRPanning panning;
63242542f5fSchristos
63342542f5fSchristos	if (crtc) {
63442542f5fSchristos		XRRSetPanning(dpy, res, crtc, memset(&panning, 0, sizeof(panning)));
63542542f5fSchristos
63642542f5fSchristos		if (XRRSetCrtcConfig(dpy, res, crtc, CurrentTime, 0, 0, None, RR_Rotate_0, NULL, 0) != Success)
63742542f5fSchristos			return 0;
63842542f5fSchristos
63942542f5fSchristos		if (XRRSetPanning(dpy, res, crtc, memset(&panning, 0, sizeof(panning))) != Success) {
64042542f5fSchristos			DBG(XRR, ("%s failed to clear panning on CRTC:%ld\n", DisplayString(dpy), (long)crtc));
64142542f5fSchristos			if (verbose) {
64242542f5fSchristos				XRRCrtcInfo *c;
64342542f5fSchristos				XRRPanning *p;
64442542f5fSchristos
64542542f5fSchristos				c = XRRGetCrtcInfo(dpy, res, crtc);
64642542f5fSchristos				if (c) {
64742542f5fSchristos					DBG(XRR, ("%s CRTC:%ld x=%d, y=%d, rotation=%d, mode=%ld\n",
64842542f5fSchristos					     DisplayString(dpy), (long)crtc,
64942542f5fSchristos					     c->x, c->y, c->rotation, c->mode));
65042542f5fSchristos					XRRFreeCrtcInfo(c);
65142542f5fSchristos				}
65242542f5fSchristos
65342542f5fSchristos				p = XRRGetPanning(dpy, res, crtc);
65442542f5fSchristos				if (p) {
65542542f5fSchristos					DBG(XRR, ("%s CRTC:%ld panning (%d, %d)x(%d, %d), tracking (%d, %d)x(%d, %d), border (%d, %d),(%d, %d)\n",
65642542f5fSchristos					     DisplayString(dpy), (long)crtc,
65742542f5fSchristos					     p->left, p->top, p->width, p->height,
65842542f5fSchristos					     p->track_left, p->track_top, p->track_width, p->track_height,
65942542f5fSchristos					     p->border_left, p->border_top, p->border_right, p->border_bottom));
66042542f5fSchristos					XRRFreePanning(p);
66142542f5fSchristos				}
66242542f5fSchristos			}
66342542f5fSchristos		}
66442542f5fSchristos	}
66542542f5fSchristos
66642542f5fSchristos	return 1;
66742542f5fSchristos}
66842542f5fSchristos
66942542f5fSchristosstatic int clone_update_modes__randr(struct clone *clone)
67042542f5fSchristos{
67142542f5fSchristos	XRRScreenResources *from_res = NULL, *to_res = NULL;
67242542f5fSchristos	XRROutputInfo *from_info = NULL, *to_info = NULL;
67342542f5fSchristos	int i, j, ret = ENOENT;
67442542f5fSchristos
67542542f5fSchristos	assert(clone->src.rr_output);
67642542f5fSchristos	assert(clone->dst.rr_output);
67742542f5fSchristos	assert(clone->dst.display->rr_event);
67842542f5fSchristos
67942542f5fSchristos	from_res = _XRRGetScreenResourcesCurrent(clone->dst.dpy, clone->dst.window);
68042542f5fSchristos	if (from_res == NULL)
68142542f5fSchristos		goto err;
68242542f5fSchristos
68342542f5fSchristos	from_info = XRRGetOutputInfo(clone->dst.dpy, from_res, clone->dst.rr_output);
68442542f5fSchristos	if (from_info == NULL)
68542542f5fSchristos		goto err;
68642542f5fSchristos
68742542f5fSchristos	DBG(XRR, ("%s(%s-%s <- %s-%s): timestamp %ld (last %ld)\n", __func__,
68842542f5fSchristos	     DisplayString(clone->src.dpy), clone->src.name,
68942542f5fSchristos	     DisplayString(clone->dst.dpy), clone->dst.name,
69042542f5fSchristos	     from_info->timestamp, clone->timestamp));
69142542f5fSchristos
69242542f5fSchristos	to_res = _XRRGetScreenResourcesCurrent(clone->src.dpy, clone->src.window);
69342542f5fSchristos	if (to_res == NULL)
69442542f5fSchristos		goto err;
69542542f5fSchristos
69642542f5fSchristos	to_info = XRRGetOutputInfo(clone->src.dpy, to_res, clone->src.rr_output);
69742542f5fSchristos	if (to_info == NULL)
69842542f5fSchristos		goto err;
69942542f5fSchristos
70042542f5fSchristos	DBG(XRR, ("%s: dst.rr_crtc=%ld, now %ld\n",
70142542f5fSchristos	     __func__, (long)clone->dst.rr_crtc, (long)from_info->crtc));
70242542f5fSchristos	if (clone->dst.rr_crtc == from_info->crtc) {
70342542f5fSchristos		for (i = 0; i < to_info->nmode; i++) {
70442542f5fSchristos			XRRModeInfo *mode, *old;
70542542f5fSchristos
70642542f5fSchristos			mode = lookup_mode(to_res, to_info->modes[i]);
70742542f5fSchristos			if (mode == NULL)
70842542f5fSchristos				break;
70942542f5fSchristos
71042542f5fSchristos			DBG(XRR, ("%s(%s-%s): lookup mode %s\n", __func__,
71142542f5fSchristos			     DisplayString(clone->src.dpy), clone->src.name,
71242542f5fSchristos			     mode->name));
71342542f5fSchristos
71442542f5fSchristos			for (j = 0; j < from_info->nmode; j++) {
71542542f5fSchristos				old = lookup_mode(from_res, from_info->modes[j]);
71642542f5fSchristos				if (old && mode_equal(mode, old)) {
71742542f5fSchristos					mode = NULL;
71842542f5fSchristos					break;
71942542f5fSchristos				}
72042542f5fSchristos			}
72142542f5fSchristos			if (mode) {
72242542f5fSchristos				DBG(XRR, ("%s(%s-%s): unknown mode %s\n", __func__,
72342542f5fSchristos				     DisplayString(clone->src.dpy), clone->src.name,
72442542f5fSchristos				     mode->name));
72542542f5fSchristos				break;
72642542f5fSchristos			}
72742542f5fSchristos		}
72842542f5fSchristos		if (i == from_info->nmode && i == to_info->nmode) {
72942542f5fSchristos			DBG(XRR, ("%s(%s-%s): no change in output\n", __func__,
73042542f5fSchristos			     DisplayString(clone->src.dpy), clone->src.name));
73142542f5fSchristos			goto done;
73242542f5fSchristos		}
73342542f5fSchristos	}
73442542f5fSchristos
73542542f5fSchristos	/* Disable the remote output */
73642542f5fSchristos	if (from_info->crtc != clone->dst.rr_crtc) {
73742542f5fSchristos		DBG(XRR, ("%s(%s-%s): disabling active CRTC\n", __func__,
73842542f5fSchristos		     DisplayString(clone->dst.dpy), clone->dst.name));
73942542f5fSchristos		if (disable_crtc(clone->dst.dpy, from_res, from_info->crtc)) {
74042542f5fSchristos			clone->dst.rr_crtc = 0;
74142542f5fSchristos			clone->dst.mode.id = 0;
74242542f5fSchristos		} else {
74342542f5fSchristos			XRRCrtcInfo *c = XRRGetCrtcInfo(clone->dst.dpy, from_res, from_info->crtc);
74442542f5fSchristos			if (c) {
74542542f5fSchristos				clone->dst.x = c->x;
74642542f5fSchristos				clone->dst.y = c->y;
74742542f5fSchristos				clone->dst.rotation = c->rotation;
74842542f5fSchristos				clone->dst.mode.id = c->mode;
74942542f5fSchristos				XRRFreeCrtcInfo(c);
75042542f5fSchristos			}
75142542f5fSchristos		}
75242542f5fSchristos	}
75342542f5fSchristos
75442542f5fSchristos	/* Create matching modes for the real output on the virtual */
75542542f5fSchristos	XGrabServer(clone->src.dpy);
75642542f5fSchristos
75742542f5fSchristos	/* Clear all current UserModes on the output, including any active ones */
75842542f5fSchristos	if (to_info->crtc) {
75942542f5fSchristos		DBG(XRR, ("%s(%s-%s): disabling active CRTC\n", __func__,
76042542f5fSchristos		     DisplayString(clone->src.dpy), clone->src.name));
76142542f5fSchristos		disable_crtc(clone->src.dpy, to_res, to_info->crtc);
76242542f5fSchristos	}
76342542f5fSchristos	for (i = 0; i < to_info->nmode; i++) {
76442542f5fSchristos		DBG(XRR, ("%s(%s-%s): deleting mode %ld\n", __func__,
76542542f5fSchristos		     DisplayString(clone->src.dpy), clone->src.name, (long)to_info->modes[i]));
76642542f5fSchristos		XRRDeleteOutputMode(clone->src.dpy, clone->src.rr_output, to_info->modes[i]);
76742542f5fSchristos	}
76842542f5fSchristos
76942542f5fSchristos	clone->src.rr_crtc = 0;
77042542f5fSchristos
77142542f5fSchristos	for (i = 0; i < from_info->nmode; i++) {
77242542f5fSchristos		XRRModeInfo *mode, *old;
77342542f5fSchristos		RRMode id;
77442542f5fSchristos
77542542f5fSchristos		mode = lookup_mode(from_res, from_info->modes[i]);
77642542f5fSchristos		if (mode == NULL)
77742542f5fSchristos			continue;
77842542f5fSchristos		for (j = 0; j < i; j++) {
77942542f5fSchristos			old = lookup_mode(from_res, from_info->modes[j]);
78042542f5fSchristos			if (old && mode_equal(mode, old)) {
78142542f5fSchristos				mode = NULL;
78242542f5fSchristos				break;
78342542f5fSchristos			}
78442542f5fSchristos		}
78542542f5fSchristos		if (mode == NULL)
78642542f5fSchristos			continue;
78742542f5fSchristos
78842542f5fSchristos		id = 0;
78942542f5fSchristos		for (j = 0; j < to_res->nmode; j++) {
79042542f5fSchristos			old = &to_res->modes[j];
79142542f5fSchristos			if (mode_equal(mode, old)) {
79242542f5fSchristos				id = old->id;
79342542f5fSchristos				DBG(XRR, ("%s(%s-%s): reusing mode %ld: %s\n", __func__,
79442542f5fSchristos				     DisplayString(clone->src.dpy), clone->src.name, id, mode->name));
79542542f5fSchristos				break;
79642542f5fSchristos			}
79742542f5fSchristos		}
79842542f5fSchristos		if (id == 0) {
79942542f5fSchristos			XRRModeInfo m;
80042542f5fSchristos			char buf[256];
80142542f5fSchristos
80242542f5fSchristos			/* XXX User names must be unique! */
80342542f5fSchristos			m = *mode;
80442542f5fSchristos			m.nameLength = snprintf(buf, sizeof(buf),
80542542f5fSchristos						"%s.%ld-%s", clone->src.name, (long)from_info->modes[i], mode->name);
80642542f5fSchristos			m.name = buf;
80742542f5fSchristos
80842542f5fSchristos			id = XRRCreateMode(clone->src.dpy, clone->src.window, &m);
80942542f5fSchristos			DBG(XRR, ("%s(%s-%s): adding mode %ld: %s\n", __func__,
81042542f5fSchristos			     DisplayString(clone->src.dpy), clone->src.name, id, mode->name));
81142542f5fSchristos		}
81242542f5fSchristos
81342542f5fSchristos		XRRAddOutputMode(clone->src.dpy, clone->src.rr_output, id);
81442542f5fSchristos	}
81542542f5fSchristos	clone_update_edid(clone);
81642542f5fSchristos	XUngrabServer(clone->src.dpy);
81742542f5fSchristosdone:
81842542f5fSchristos	ret = 0;
81942542f5fSchristos	clone->timestamp = from_info->timestamp;
82042542f5fSchristos
82142542f5fSchristoserr:
82242542f5fSchristos	if (to_info)
82342542f5fSchristos		XRRFreeOutputInfo(to_info);
82442542f5fSchristos	if (to_res)
82542542f5fSchristos		XRRFreeScreenResources(to_res);
82642542f5fSchristos	if (from_info)
82742542f5fSchristos		XRRFreeOutputInfo(from_info);
82842542f5fSchristos	if (from_res)
82942542f5fSchristos		XRRFreeScreenResources(from_res);
83042542f5fSchristos
83142542f5fSchristos	return ret;
83242542f5fSchristos}
83342542f5fSchristos
83442542f5fSchristosstatic int clone_update_modes__fixed(struct clone *clone)
83542542f5fSchristos{
83642542f5fSchristos	char mode_name[80];
83742542f5fSchristos	XRRScreenResources *res = NULL;
83842542f5fSchristos	XRROutputInfo *info = NULL;
83942542f5fSchristos	XRRModeInfo mode;
84042542f5fSchristos	RRMode id;
84142542f5fSchristos	int i, j, ret = ENOENT;
84242542f5fSchristos
843fe8aea9eSmrg	DBG(X11, ("%s-%s cloning modes fixed %dx%d\n",
844fe8aea9eSmrg	     DisplayString(clone->dst.dpy), clone->dst.name,
845fe8aea9eSmrg	     clone->dst.width, clone->dst.height));
846fe8aea9eSmrg
84742542f5fSchristos	assert(clone->src.rr_output);
84842542f5fSchristos
84942542f5fSchristos	res = _XRRGetScreenResourcesCurrent(clone->src.dpy, clone->src.window);
85042542f5fSchristos	if (res == NULL)
85142542f5fSchristos		goto err;
85242542f5fSchristos
85342542f5fSchristos	info = XRRGetOutputInfo(clone->src.dpy, res, clone->src.rr_output);
85442542f5fSchristos	if (info == NULL)
85542542f5fSchristos		goto err;
85642542f5fSchristos
85742542f5fSchristos	XGrabServer(clone->src.dpy);
85842542f5fSchristos
85942542f5fSchristos	/* Clear all current UserModes on the output, including any active ones */
86042542f5fSchristos	if (info->crtc) {
86142542f5fSchristos		DBG(XRR, ("%s(%s-%s): disabling active CRTC\n", __func__,
86242542f5fSchristos		     DisplayString(clone->src.dpy), clone->src.name));
86342542f5fSchristos		disable_crtc(clone->src.dpy, res, info->crtc);
86442542f5fSchristos	}
86542542f5fSchristos	for (i = 0; i < info->nmode; i++) {
86642542f5fSchristos		DBG(XRR, ("%s(%s-%s): deleting mode %ld\n", __func__,
86742542f5fSchristos		     DisplayString(clone->src.dpy), clone->src.name, (long)info->modes[i]));
86842542f5fSchristos		XRRDeleteOutputMode(clone->src.dpy, clone->src.rr_output, info->modes[i]);
86942542f5fSchristos	}
87042542f5fSchristos
87142542f5fSchristos	clone->src.rr_crtc = 0;
87242542f5fSchristos
87342542f5fSchristos	/* Create matching mode for the real output on the virtual */
87442542f5fSchristos	memset(&mode, 0, sizeof(mode));
875fe8aea9eSmrg	mode.width = clone->dst.width;
876fe8aea9eSmrg	mode.height = clone->dst.height;
87742542f5fSchristos	mode.nameLength = sprintf(mode_name, "FAKE-%dx%d", mode.width, mode.height);
87842542f5fSchristos	mode.name = mode_name;
87942542f5fSchristos
88042542f5fSchristos	id = 0;
88142542f5fSchristos	for (j = 0; j < res->nmode; j++) {
88242542f5fSchristos		if (mode_equal(&mode, &res->modes[j])) {
88342542f5fSchristos			id = res->modes[j].id;
88442542f5fSchristos			break;
88542542f5fSchristos		}
88642542f5fSchristos	}
88742542f5fSchristos	if (id == 0)
88842542f5fSchristos		id = XRRCreateMode(clone->src.dpy, clone->src.window, &mode);
88942542f5fSchristos
89042542f5fSchristos	XRRAddOutputMode(clone->src.dpy, clone->src.rr_output, id);
89142542f5fSchristos
89242542f5fSchristos	XUngrabServer(clone->src.dpy);
89342542f5fSchristos	ret = 0;
89442542f5fSchristoserr:
89542542f5fSchristos	if (info)
89642542f5fSchristos		XRRFreeOutputInfo(info);
89742542f5fSchristos	if (res)
89842542f5fSchristos		XRRFreeScreenResources(res);
89942542f5fSchristos
90042542f5fSchristos	return ret;
90142542f5fSchristos}
90242542f5fSchristos
90342542f5fSchristosstatic RROutput claim_virtual(struct display *display, char *output_name, int nclone)
90442542f5fSchristos{
90542542f5fSchristos	char mode_name[] = "ClaimVirtualHead";
90642542f5fSchristos	Display *dpy = display->dpy;
90742542f5fSchristos	XRRScreenResources *res;
90842542f5fSchristos	XRROutputInfo *output;
90942542f5fSchristos	XRRModeInfo mode;
91042542f5fSchristos	RRMode id;
91142542f5fSchristos	RROutput rr_output = 0;
91242542f5fSchristos	int i;
91342542f5fSchristos
91442542f5fSchristos	DBG(X11, ("%s(%d)\n", __func__, nclone));
91542542f5fSchristos	XGrabServer(dpy);
91642542f5fSchristos
91742542f5fSchristos	res = _XRRGetScreenResourcesCurrent(dpy, display->root);
91842542f5fSchristos	if (res == NULL)
91942542f5fSchristos		goto out;
92042542f5fSchristos
92142542f5fSchristos	sprintf(output_name, "VIRTUAL%d", nclone);
92242542f5fSchristos
92342542f5fSchristos	for (i = rr_output = 0; rr_output == 0 && i < res->noutput; i++) {
92442542f5fSchristos		output = XRRGetOutputInfo(dpy, res, res->outputs[i]);
92542542f5fSchristos		if (output == NULL)
92642542f5fSchristos			continue;
92742542f5fSchristos
92842542f5fSchristos		if (strcmp(output->name, output_name) == 0)
92942542f5fSchristos			rr_output = res->outputs[i];
93042542f5fSchristos
93142542f5fSchristos		XRRFreeOutputInfo(output);
93242542f5fSchristos	}
93342542f5fSchristos	for (i = id = 0; id == 0 && i < res->nmode; i++) {
93442542f5fSchristos		if (strcmp(res->modes[i].name, mode_name) == 0)
93542542f5fSchristos			id = res->modes[i].id;
93642542f5fSchristos	}
93742542f5fSchristos	XRRFreeScreenResources(res);
93842542f5fSchristos
93942542f5fSchristos	DBG(XRR, ("%s(%s): rr_output=%ld\n", __func__, output_name, (long)rr_output));
94042542f5fSchristos	if (rr_output == 0)
94142542f5fSchristos		goto out;
94242542f5fSchristos
94342542f5fSchristos	/* Set any mode on the VirtualHead to make the Xserver allocate another */
94442542f5fSchristos	memset(&mode, 0, sizeof(mode));
94542542f5fSchristos	mode.width = 1024;
94642542f5fSchristos	mode.height = 768;
94742542f5fSchristos	mode.name = mode_name;
94842542f5fSchristos	mode.nameLength = sizeof(mode_name) - 1;
94942542f5fSchristos
95042542f5fSchristos	if (id == 0)
95142542f5fSchristos		id = XRRCreateMode(dpy, display->root, &mode);
95242542f5fSchristos	XRRAddOutputMode(dpy, rr_output, id);
95342542f5fSchristos
95442542f5fSchristos	/* Force a redetection for the ddx to spot the new outputs */
95542542f5fSchristos	res = XRRGetScreenResources(dpy, display->root);
95642542f5fSchristos	if (res == NULL)
95742542f5fSchristos		goto out;
95842542f5fSchristos
95942542f5fSchristos	/* Some else may have interrupted us and installed that new mode! */
96042542f5fSchristos	output = XRRGetOutputInfo(dpy, res, rr_output);
96142542f5fSchristos	if (output) {
96242542f5fSchristos		disable_crtc(dpy, res, output->crtc);
96342542f5fSchristos		XRRFreeOutputInfo(output);
96442542f5fSchristos	}
96542542f5fSchristos	XRRFreeScreenResources(res);
96642542f5fSchristos
96742542f5fSchristos	XRRDeleteOutputMode(dpy, rr_output, id);
96842542f5fSchristos	XRRDestroyMode(dpy, id);
96942542f5fSchristos
97042542f5fSchristos	/* And hide it again */
97142542f5fSchristos	res = XRRGetScreenResources(dpy, display->root);
97242542f5fSchristos	if (res != NULL)
97342542f5fSchristos		XRRFreeScreenResources(res);
97442542f5fSchristosout:
97542542f5fSchristos	XUngrabServer(dpy);
97642542f5fSchristos
97742542f5fSchristos	return rr_output;
97842542f5fSchristos}
97942542f5fSchristos
980fe8aea9eSmrgstatic int check_virtual(struct display *display)
981fe8aea9eSmrg{
982fe8aea9eSmrg	XRRScreenResources *res;
983fe8aea9eSmrg	int found = -ENOENT;
984fe8aea9eSmrg	int i;
985fe8aea9eSmrg
986fe8aea9eSmrg	res = _XRRGetScreenResourcesCurrent(display->dpy, display->root);
987fe8aea9eSmrg	if (res == NULL)
988fe8aea9eSmrg		return -ENOMEM;
989fe8aea9eSmrg
990fe8aea9eSmrg	for (i = 0; found == -ENOENT && i < res->noutput; i++) {
991fe8aea9eSmrg		XRROutputInfo *output;
992fe8aea9eSmrg
993fe8aea9eSmrg		output = XRRGetOutputInfo(display->dpy, res, res->outputs[i]);
994fe8aea9eSmrg		if (output == NULL)
995fe8aea9eSmrg			continue;
996fe8aea9eSmrg
997fe8aea9eSmrg		if (strcmp(output->name, "VIRTUAL1") == 0)
998fe8aea9eSmrg			found = 0;
999fe8aea9eSmrg
1000fe8aea9eSmrg		XRRFreeOutputInfo(output);
1001fe8aea9eSmrg	}
1002fe8aea9eSmrg	XRRFreeScreenResources(res);
1003fe8aea9eSmrg
1004fe8aea9eSmrg	DBG(XRR, ("%s(%s): has VIRTUAL1? %d\n",
1005fe8aea9eSmrg		  __func__, DisplayString(display->dpy), found));
1006fe8aea9eSmrg	return found;
1007fe8aea9eSmrg}
1008fe8aea9eSmrg
100942542f5fSchristosstatic int stride_for_depth(int width, int depth)
101042542f5fSchristos{
101142542f5fSchristos	if (depth == 24)
101242542f5fSchristos		depth = 32;
101342542f5fSchristos	return ((width * depth + 7) / 8 + 3) & ~3;
101442542f5fSchristos}
101542542f5fSchristos
101642542f5fSchristosstatic void init_image(struct clone *clone)
101742542f5fSchristos{
101842542f5fSchristos	XImage *image = &clone->image;
101942542f5fSchristos	int ret;
102042542f5fSchristos
102142542f5fSchristos	image->width = clone->width;
102242542f5fSchristos	image->height = clone->height;
102342542f5fSchristos	image->format = ZPixmap;
102442542f5fSchristos	image->xoffset = 0;
102542542f5fSchristos	image->byte_order = LSBFirst;
102642542f5fSchristos	image->bitmap_unit = 32;
102742542f5fSchristos	image->bitmap_bit_order = LSBFirst;
102842542f5fSchristos	image->bitmap_pad = 32;
102942542f5fSchristos	image->data = clone->shm.shmaddr;
103042542f5fSchristos	image->bytes_per_line = stride_for_depth(clone->width, clone->depth);
103142542f5fSchristos	switch (clone->depth) {
103242542f5fSchristos	case 24:
103342542f5fSchristos		image->red_mask = 0xff << 16;
103442542f5fSchristos		image->green_mask = 0xff << 8;
103542542f5fSchristos		image->blue_mask = 0xff << 0;;
103642542f5fSchristos		image->depth = 24;
103742542f5fSchristos		image->bits_per_pixel = 32;
103842542f5fSchristos		break;
103942542f5fSchristos	case 16:
104042542f5fSchristos		image->red_mask = 0x1f << 11;
104142542f5fSchristos		image->green_mask = 0x3f << 5;
104242542f5fSchristos		image->blue_mask = 0x1f << 0;;
104342542f5fSchristos		image->depth = 16;
104442542f5fSchristos		image->bits_per_pixel = 16;
104542542f5fSchristos		break;
104642542f5fSchristos	}
104742542f5fSchristos
104842542f5fSchristos	ret = XInitImage(image);
104942542f5fSchristos	assert(ret);
105042542f5fSchristos	(void)ret;
105142542f5fSchristos}
105242542f5fSchristos
105342542f5fSchristosstatic int mode_height(const XRRModeInfo *mode, Rotation rotation)
105442542f5fSchristos{
105542542f5fSchristos	switch (rotation & 0xf) {
105642542f5fSchristos	case RR_Rotate_0:
105742542f5fSchristos	case RR_Rotate_180:
105842542f5fSchristos		return mode->height;
105942542f5fSchristos	case RR_Rotate_90:
106042542f5fSchristos	case RR_Rotate_270:
106142542f5fSchristos		return mode->width;
106242542f5fSchristos	default:
106342542f5fSchristos		return 0;
106442542f5fSchristos	}
106542542f5fSchristos}
106642542f5fSchristos
106742542f5fSchristosstatic int mode_width(const XRRModeInfo *mode, Rotation rotation)
106842542f5fSchristos{
106942542f5fSchristos	switch (rotation & 0xf) {
107042542f5fSchristos	case RR_Rotate_0:
107142542f5fSchristos	case RR_Rotate_180:
107242542f5fSchristos		return mode->width;
107342542f5fSchristos	case RR_Rotate_90:
107442542f5fSchristos	case RR_Rotate_270:
107542542f5fSchristos		return mode->height;
107642542f5fSchristos	default:
107742542f5fSchristos		return 0;
107842542f5fSchristos	}
107942542f5fSchristos}
108042542f5fSchristos
108142542f5fSchristosstatic void output_init_xfer(struct clone *clone, struct output *output)
108242542f5fSchristos{
108342542f5fSchristos	if (output->pixmap == None && output->use_shm_pixmap) {
108442542f5fSchristos		DBG(DRAW, ("%s-%s: creating shm pixmap\n", DisplayString(output->dpy), output->name));
108542542f5fSchristos		XSync(output->dpy, False);
108642542f5fSchristos		_x_error_occurred = 0;
108742542f5fSchristos
108842542f5fSchristos		output->pixmap = XShmCreatePixmap(output->dpy, output->window,
108942542f5fSchristos						  clone->shm.shmaddr, &output->shm,
109042542f5fSchristos						  clone->width, clone->height, clone->depth);
109142542f5fSchristos		if (output->pix_picture) {
109242542f5fSchristos			XRenderFreePicture(output->dpy, output->pix_picture);
109342542f5fSchristos			output->pix_picture = None;
109442542f5fSchristos		}
109542542f5fSchristos
109642542f5fSchristos		XSync(output->dpy, False);
109742542f5fSchristos		if (_x_error_occurred) {
109842542f5fSchristos			XFreePixmap(output->dpy, output->pixmap);
109942542f5fSchristos			output->pixmap = None;
110042542f5fSchristos			output->use_shm_pixmap = 0;
110142542f5fSchristos		}
110242542f5fSchristos	}
110342542f5fSchristos	if (output->use_render) {
110442542f5fSchristos		DBG(DRAW, ("%s-%s: creating picture\n", DisplayString(output->dpy), output->name));
110542542f5fSchristos		if (output->win_picture == None)
110642542f5fSchristos			output->win_picture = XRenderCreatePicture(output->dpy, output->window,
110742542f5fSchristos								   output->display->root_format, 0, NULL);
110842542f5fSchristos		if (output->pixmap == None)
110942542f5fSchristos			output->pixmap = XCreatePixmap(output->dpy, output->window,
111042542f5fSchristos						       clone->width, clone->height, clone->depth);
111142542f5fSchristos		if (output->pix_picture == None)
111242542f5fSchristos			output->pix_picture = XRenderCreatePicture(output->dpy, output->pixmap,
111342542f5fSchristos								   output->use_render, 0, NULL);
111442542f5fSchristos	}
111542542f5fSchristos
111642542f5fSchristos	if (output->gc == None) {
111742542f5fSchristos		XGCValues gcv;
111842542f5fSchristos
111942542f5fSchristos		DBG(DRAW, ("%s-%s: creating gc\n", DisplayString(output->dpy), output->name));
112042542f5fSchristos
112142542f5fSchristos		gcv.graphics_exposures = False;
112242542f5fSchristos		gcv.subwindow_mode = IncludeInferiors;
112342542f5fSchristos
112442542f5fSchristos		output->gc = XCreateGC(output->dpy, output->pixmap ?: output->window, GCGraphicsExposures | GCSubwindowMode, &gcv);
112542542f5fSchristos	}
112642542f5fSchristos}
112742542f5fSchristos
112842542f5fSchristosstatic int bpp_for_depth(int depth)
112942542f5fSchristos{
113042542f5fSchristos	switch (depth) {
113142542f5fSchristos	case 1: return 1;
113242542f5fSchristos	case 8: return 8;
113342542f5fSchristos	case 15: return 16;
113442542f5fSchristos	case 16: return 16;
113542542f5fSchristos	case 24: return 24;
113642542f5fSchristos	case 32: return 32;
113742542f5fSchristos	default: return 0;
113842542f5fSchristos	}
113942542f5fSchristos}
114042542f5fSchristos
114142542f5fSchristosstatic int clone_init_xfer(struct clone *clone)
114242542f5fSchristos{
114342542f5fSchristos	int width, height;
114442542f5fSchristos
114542542f5fSchristos	if (clone->dst.mode.id == 0) {
114613496ba1Ssnj		width = 0;
114713496ba1Ssnj		height = 0;
114842542f5fSchristos	} else if (clone->dri3.xid) {
1149fe8aea9eSmrg		width = clone->dst.width;
1150fe8aea9eSmrg		height = clone->dst.height;
115142542f5fSchristos	} else {
115242542f5fSchristos		width = mode_width(&clone->src.mode, clone->src.rotation);
115342542f5fSchristos		height = mode_height(&clone->src.mode, clone->src.rotation);
115442542f5fSchristos	}
115542542f5fSchristos
1156fe8aea9eSmrg	DBG(DRAW, ("%s-%s create xfer, %dx%d (currently %dx%d)\n",
1157fe8aea9eSmrg	     DisplayString(clone->dst.dpy), clone->dst.name,
1158fe8aea9eSmrg	     width, height, clone->width, clone->height));
1159fe8aea9eSmrg
116042542f5fSchristos	if (width == clone->width && height == clone->height)
116142542f5fSchristos		return 0;
116242542f5fSchristos
116342542f5fSchristos	if (clone->shm.shmaddr) {
116442542f5fSchristos		if (clone->src.use_shm)
116542542f5fSchristos			XShmDetach(clone->src.dpy, &clone->src.shm);
116642542f5fSchristos		if (clone->dst.use_shm)
116742542f5fSchristos			XShmDetach(clone->dst.dpy, &clone->dst.shm);
116842542f5fSchristos
116942542f5fSchristos		shmdt(clone->shm.shmaddr);
117042542f5fSchristos		clone->shm.shmaddr = NULL;
117142542f5fSchristos	}
117242542f5fSchristos
117342542f5fSchristos	if (clone->src.pixmap) {
117442542f5fSchristos		XFreePixmap(clone->src.dpy, clone->src.pixmap);
117542542f5fSchristos		clone->src.pixmap = 0;
117642542f5fSchristos	}
117742542f5fSchristos
117842542f5fSchristos	if (clone->dst.pixmap) {
117942542f5fSchristos		XFreePixmap(clone->dst.dpy, clone->dst.pixmap);
118042542f5fSchristos		clone->dst.pixmap = 0;
118142542f5fSchristos	}
118242542f5fSchristos
118342542f5fSchristos	if ((width | height) == 0) {
118442542f5fSchristos		clone->damaged.x2 = clone->damaged.y2 = INT_MIN;
118542542f5fSchristos		clone->damaged.x1 = clone->damaged.y1 = INT_MAX;
118642542f5fSchristos		return 0;
118742542f5fSchristos	}
118842542f5fSchristos
118942542f5fSchristos	if (clone->dri3.xid) {
119042542f5fSchristos		int fd, stride;
119142542f5fSchristos		Pixmap src;
119242542f5fSchristos
119342542f5fSchristos		_x_error_occurred = 0;
119442542f5fSchristos
119542542f5fSchristos		DBG(DRAW, ("%s-%s create xfer, trying DRI3\n",
119642542f5fSchristos		     DisplayString(clone->dst.dpy), clone->dst.name));
119742542f5fSchristos
119842542f5fSchristos		fd = dri3_create_fd(clone->dst.dpy, clone->dst.window, &stride);
119942542f5fSchristos		if (fd < 0)
120042542f5fSchristos			goto disable_dri3;
120142542f5fSchristos
120242542f5fSchristos		DBG(DRAW, ("%s-%s create xfer, DRI3 fd=%d, stride=%d\n",
120342542f5fSchristos		     DisplayString(clone->dst.dpy), clone->dst.name,
120442542f5fSchristos		     fd, stride));
120542542f5fSchristos
120642542f5fSchristos		src = dri3_create_pixmap(clone->src.dpy, clone->src.window,
120742542f5fSchristos					 width, height, clone->depth,
120842542f5fSchristos					 fd, bpp_for_depth(clone->depth),
120942542f5fSchristos					 stride, lseek(fd, 0, SEEK_END));
121042542f5fSchristos
121142542f5fSchristos		XSync(clone->src.dpy, False);
121242542f5fSchristos		if (!_x_error_occurred) {
121342542f5fSchristos			clone->src.pixmap = src;
121442542f5fSchristos			clone->width = width;
121542542f5fSchristos			clone->height = height;
121642542f5fSchristos		} else {
121742542f5fSchristos			XFreePixmap(clone->src.dpy, src);
121842542f5fSchristos			close(fd);
121942542f5fSchristosdisable_dri3:
122042542f5fSchristos			dri3_fence_free(clone->src.dpy, &clone->dri3);
122142542f5fSchristos			clone->dri3.xid = 0;
122242542f5fSchristos
122342542f5fSchristos			DBG(DRAW, ("%s-%s create xfer, DRI3 failed\n",
122442542f5fSchristos			     DisplayString(clone->dst.dpy), clone->dst.name));
122542542f5fSchristos		}
122642542f5fSchristos	}
122742542f5fSchristos
122842542f5fSchristos	width = mode_width(&clone->src.mode, clone->src.rotation);
122942542f5fSchristos	height = mode_height(&clone->src.mode, clone->src.rotation);
123042542f5fSchristos
123142542f5fSchristos	if (!clone->dri3.xid) {
123242542f5fSchristos		DBG(DRAW, ("%s-%s create xfer, trying SHM\n",
123342542f5fSchristos		     DisplayString(clone->dst.dpy), clone->dst.name));
123442542f5fSchristos
123542542f5fSchristos		clone->shm.shmid = shmget(IPC_PRIVATE,
123642542f5fSchristos					  height * stride_for_depth(width, clone->depth),
123742542f5fSchristos					  IPC_CREAT | 0666);
123842542f5fSchristos		if (clone->shm.shmid == -1)
123942542f5fSchristos			return errno;
124042542f5fSchristos
124142542f5fSchristos		clone->shm.shmaddr = shmat(clone->shm.shmid, 0, 0);
124242542f5fSchristos		if (clone->shm.shmaddr == (char *) -1) {
124342542f5fSchristos			shmctl(clone->shm.shmid, IPC_RMID, NULL);
124442542f5fSchristos			return ENOMEM;
124542542f5fSchristos		}
124642542f5fSchristos
124742542f5fSchristos		if (clone->src.use_shm) {
124842542f5fSchristos			clone->src.shm = clone->shm;
124942542f5fSchristos			clone->src.shm.readOnly = False;
125042542f5fSchristos			XShmAttach(clone->src.dpy, &clone->src.shm);
125142542f5fSchristos			XSync(clone->src.dpy, False);
125242542f5fSchristos		}
125342542f5fSchristos		if (clone->dst.use_shm) {
125442542f5fSchristos			clone->dst.shm = clone->shm;
125542542f5fSchristos			clone->dst.shm.readOnly = !clone->dst.use_shm_pixmap;
125642542f5fSchristos			XShmAttach(clone->dst.dpy, &clone->dst.shm);
125742542f5fSchristos			XSync(clone->dst.dpy, False);
125842542f5fSchristos		}
125942542f5fSchristos
126042542f5fSchristos		shmctl(clone->shm.shmid, IPC_RMID, NULL);
126142542f5fSchristos
126242542f5fSchristos		clone->width = width;
126342542f5fSchristos		clone->height = height;
126442542f5fSchristos
126542542f5fSchristos		init_image(clone);
126642542f5fSchristos	}
126742542f5fSchristos
126842542f5fSchristos	output_init_xfer(clone, &clone->src);
126942542f5fSchristos	output_init_xfer(clone, &clone->dst);
127042542f5fSchristos
127142542f5fSchristos	clone->damaged.x1 = clone->src.x;
127242542f5fSchristos	clone->damaged.x2 = clone->src.x + width;
127342542f5fSchristos	clone->damaged.y1 = clone->src.y;
127442542f5fSchristos	clone->damaged.y2 = clone->src.y + height;
127542542f5fSchristos
127642542f5fSchristos	display_mark_flush(clone->dst.display);
127742542f5fSchristos	return 0;
127842542f5fSchristos}
127942542f5fSchristos
128042542f5fSchristosstatic void clone_update(struct clone *clone)
128142542f5fSchristos{
128242542f5fSchristos	if (!clone->rr_update)
128342542f5fSchristos		return;
128442542f5fSchristos
128542542f5fSchristos	DBG(X11, ("%s-%s cloning modes\n",
128642542f5fSchristos	     DisplayString(clone->dst.dpy), clone->dst.name));
128742542f5fSchristos
128842542f5fSchristos	clone_update_modes__randr(clone);
128942542f5fSchristos	clone->rr_update = 0;
129042542f5fSchristos}
129142542f5fSchristos
1292fe8aea9eSmrgstatic void screensaver_save(struct display *display)
1293fe8aea9eSmrg{
1294fe8aea9eSmrg	display->saver_active =
1295fe8aea9eSmrg		XScreenSaverQueryExtension(display->dpy,
1296fe8aea9eSmrg					   &display->saver_event,
1297fe8aea9eSmrg					   &display->saver_error);
1298fe8aea9eSmrg	DBG(SCREEN,
1299fe8aea9eSmrg	    ("%s screen saver active? %d [event=%d, error=%d]\n",
1300fe8aea9eSmrg	     DisplayString(display->dpy),
1301fe8aea9eSmrg	     display->saver_active,
1302fe8aea9eSmrg	     display->saver_event,
1303fe8aea9eSmrg	     display->saver_error));
1304fe8aea9eSmrg
1305fe8aea9eSmrg	XGetScreenSaver(display->dpy,
1306fe8aea9eSmrg			&display->saver.timeout,
1307fe8aea9eSmrg			&display->saver.interval,
1308fe8aea9eSmrg			&display->saver.prefer_blank,
1309fe8aea9eSmrg			&display->saver.allow_exp);
1310fe8aea9eSmrg
1311fe8aea9eSmrg	DBG(SCREEN,
1312fe8aea9eSmrg	    ("%s saving screen saver defaults: timeout=%d interval=%d prefer_blank=%d allow_exp=%d\n",
1313fe8aea9eSmrg	     DisplayString(display->dpy),
1314fe8aea9eSmrg	     display->saver.timeout,
1315fe8aea9eSmrg	     display->saver.interval,
1316fe8aea9eSmrg	     display->saver.prefer_blank,
1317fe8aea9eSmrg	     display->saver.allow_exp));
1318fe8aea9eSmrg}
1319fe8aea9eSmrg
1320fe8aea9eSmrgstatic void screensaver_disable(struct display *display)
1321fe8aea9eSmrg{
1322fe8aea9eSmrg	DBG(SCREEN,
1323fe8aea9eSmrg	    ("%s disabling screen saver\n", DisplayString(display->dpy)));
1324fe8aea9eSmrg
1325fe8aea9eSmrg	XSetScreenSaver(display->dpy, 0, 0, DefaultBlanking, DefaultExposures);
1326fe8aea9eSmrg	display_mark_flush(display);
1327fe8aea9eSmrg}
1328fe8aea9eSmrg
1329fe8aea9eSmrgstatic void screensaver_restore(struct display *display)
1330fe8aea9eSmrg{
1331fe8aea9eSmrg	DBG(SCREEN,
1332fe8aea9eSmrg	    ("%s restoring screen saver\n", DisplayString(display->dpy)));
1333fe8aea9eSmrg
1334fe8aea9eSmrg	XSetScreenSaver(display->dpy,
1335fe8aea9eSmrg			display->saver.timeout,
1336fe8aea9eSmrg			display->saver.interval,
1337fe8aea9eSmrg			display->saver.prefer_blank,
1338fe8aea9eSmrg			display->saver.allow_exp);
1339fe8aea9eSmrg	display_mark_flush(display);
1340fe8aea9eSmrg}
1341fe8aea9eSmrg
134242542f5fSchristosstatic int context_update(struct context *ctx)
134342542f5fSchristos{
134442542f5fSchristos	Display *dpy = ctx->display->dpy;
134542542f5fSchristos	XRRScreenResources *res;
134642542f5fSchristos	int context_changed = 0;
134742542f5fSchristos	int i, n;
134842542f5fSchristos
134942542f5fSchristos	DBG(X11, ("%s\n", __func__));
135042542f5fSchristos
135142542f5fSchristos	res = _XRRGetScreenResourcesCurrent(dpy, ctx->display->root);
135242542f5fSchristos	if (res == NULL)
135342542f5fSchristos		return 0;
135442542f5fSchristos
135542542f5fSchristos	DBG(XRR, ("%s timestamp %ld (last %ld), config %ld (last %ld)\n",
135642542f5fSchristos	     DisplayString(dpy),
135742542f5fSchristos	     res->timestamp, ctx->timestamp,
135842542f5fSchristos	     res->configTimestamp, ctx->configTimestamp));
135942542f5fSchristos	if (res->timestamp == ctx->timestamp &&
136042542f5fSchristos	    res->configTimestamp == ctx->configTimestamp &&
136142542f5fSchristos	    res->timestamp != res->configTimestamp) { /* mutter be damned */
136242542f5fSchristos		XRRFreeScreenResources(res);
136342542f5fSchristos		return 0;
136442542f5fSchristos	}
136542542f5fSchristos
136642542f5fSchristos	ctx->timestamp = res->timestamp;
136742542f5fSchristos	ctx->configTimestamp = res->configTimestamp;
136842542f5fSchristos
136942542f5fSchristos	for (n = 0; n < ctx->nclone; n++) {
137042542f5fSchristos		struct output *output = &ctx->clones[n].src;
137142542f5fSchristos		XRROutputInfo *o;
137242542f5fSchristos		XRRCrtcInfo *c;
137342542f5fSchristos		RRMode mode = 0;
137442542f5fSchristos		int changed = 0;
137542542f5fSchristos
137642542f5fSchristos		o = XRRGetOutputInfo(dpy, res, output->rr_output);
137742542f5fSchristos		if (o == NULL)
137842542f5fSchristos			continue;
137942542f5fSchristos
138042542f5fSchristos		c = NULL;
138142542f5fSchristos		if (o->crtc)
138242542f5fSchristos			c = XRRGetCrtcInfo(dpy, res, o->crtc);
138342542f5fSchristos		if (c) {
138442542f5fSchristos			DBG(XRR, ("%s-%s: (x=%d, y=%d, rotation=%d, mode=%ld) -> (x=%d, y=%d, rotation=%d, mode=%ld)\n",
138542542f5fSchristos			     DisplayString(dpy), output->name,
138642542f5fSchristos			     output->x, output->y, output->rotation, output->mode.id,
138742542f5fSchristos			     c->x, c->y, c->rotation, c->mode));
138842542f5fSchristos
138942542f5fSchristos			changed |= output->rotation != c->rotation;
139042542f5fSchristos			output->rotation = c->rotation;
139142542f5fSchristos
139242542f5fSchristos			changed |= output->x != c->x;
139342542f5fSchristos			output->x = c->x;
139442542f5fSchristos
139542542f5fSchristos			changed |= output->y != c->y;
139642542f5fSchristos			output->y = c->y;
139742542f5fSchristos
139842542f5fSchristos			changed |= output->mode.id != c->mode;
139942542f5fSchristos			mode = c->mode;
140042542f5fSchristos			XRRFreeCrtcInfo(c);
140142542f5fSchristos		} else {
140242542f5fSchristos			DBG(XRR, ("%s-%s: (x=%d, y=%d, rotation=%d, mode=%ld) -> off\n",
140342542f5fSchristos			     DisplayString(dpy), output->name,
140442542f5fSchristos			     output->x, output->y, output->rotation, output->mode.id));
140542542f5fSchristos		}
140642542f5fSchristos		output->rr_crtc = o->crtc;
140742542f5fSchristos		XRRFreeOutputInfo(o);
140842542f5fSchristos
140942542f5fSchristos		DBG(XRR, ("%s-%s crtc changed? %d\n",
141042542f5fSchristos		     DisplayString(ctx->clones[n].dst.display->dpy), ctx->clones[n].dst.name, changed));
141142542f5fSchristos
141242542f5fSchristos		if (mode) {
141342542f5fSchristos			if (output->mode.id != mode) {
141442542f5fSchristos				for (i = 0; i < res->nmode; i++) {
141542542f5fSchristos					if (res->modes[i].id == mode) {
141642542f5fSchristos						output->mode = res->modes[i];
141742542f5fSchristos						break;
141842542f5fSchristos					}
141942542f5fSchristos				}
142042542f5fSchristos			}
142142542f5fSchristos		} else {
142242542f5fSchristos			changed = output->mode.id != 0;
142342542f5fSchristos			output->mode.id = 0;
142442542f5fSchristos		}
142542542f5fSchristos
142642542f5fSchristos		DBG(XRR, ("%s-%s output changed? %d\n",
142742542f5fSchristos		     DisplayString(ctx->clones[n].dst.display->dpy), ctx->clones[n].dst.name, changed));
142842542f5fSchristos
142942542f5fSchristos		context_changed |= changed;
143042542f5fSchristos	}
143142542f5fSchristos	XRRFreeScreenResources(res);
143242542f5fSchristos
143342542f5fSchristos	DBG(XRR, ("%s changed? %d\n", DisplayString(dpy), context_changed));
143442542f5fSchristos	if (!context_changed)
143542542f5fSchristos		return 0;
143642542f5fSchristos
143742542f5fSchristos	for (n = 1; n < ctx->ndisplay; n++) {
143842542f5fSchristos		struct display *display = &ctx->display[n];
143942542f5fSchristos		struct clone *clone;
144042542f5fSchristos		int x1, x2, y1, y2;
144142542f5fSchristos
1442fe8aea9eSmrg		if (display->rr_active == 0) {
1443fe8aea9eSmrg			for (clone = display->clone; clone; clone = clone->next) {
1444fe8aea9eSmrg				struct output *output = &clone->src;
1445fe8aea9eSmrg				if (output->mode.id) {
1446fe8aea9eSmrg					clone->dst.mode.id = -1;
1447fe8aea9eSmrg					clone->dst.rr_crtc = -1;
1448fe8aea9eSmrg				} else {
1449fe8aea9eSmrg					clone->dst.mode.id = 0;
1450fe8aea9eSmrg					clone->dst.rr_crtc = 0;
1451fe8aea9eSmrg				}
1452fe8aea9eSmrg			}
145342542f5fSchristos			continue;
1454fe8aea9eSmrg		}
145542542f5fSchristos
145642542f5fSchristos		x1 = y1 = INT_MAX;
145742542f5fSchristos		x2 = y2 = INT_MIN;
145842542f5fSchristos
145942542f5fSchristos		for (clone = display->clone; clone; clone = clone->next) {
146042542f5fSchristos			struct output *output = &clone->src;
146142542f5fSchristos			int v;
146242542f5fSchristos
146342542f5fSchristos			assert(clone->dst.display == display);
146442542f5fSchristos
146542542f5fSchristos			if (output->mode.id == 0)
146642542f5fSchristos				continue;
146742542f5fSchristos
146842542f5fSchristos			DBG(XRR, ("%s: source %s enabled (%d, %d)x(%d, %d)\n",
146942542f5fSchristos			     DisplayString(clone->dst.dpy), output->name,
147042542f5fSchristos			     output->x, output->y,
147142542f5fSchristos			     mode_width(&output->mode, output->rotation),
147242542f5fSchristos			     mode_height(&output->mode, output->rotation)));
147342542f5fSchristos
147442542f5fSchristos			if (output->x < x1)
147542542f5fSchristos				x1 = output->x;
147642542f5fSchristos			if (output->y < y1)
147742542f5fSchristos				y1 = output->y;
147842542f5fSchristos
147942542f5fSchristos			v = (int)output->x + mode_width(&output->mode, output->rotation);
148042542f5fSchristos			if (v > x2)
148142542f5fSchristos				x2 = v;
148242542f5fSchristos			v = (int)output->y + mode_height(&output->mode, output->rotation);
148342542f5fSchristos			if (v > y2)
148442542f5fSchristos				y2 = v;
148542542f5fSchristos		}
148642542f5fSchristos
148742542f5fSchristos		DBG(XRR, ("%s fb bounds (%d, %d)x(%d, %d)\n", DisplayString(display->dpy),
148842542f5fSchristos		     x1, y1, x2, y2));
148942542f5fSchristos
149042542f5fSchristos		XGrabServer(display->dpy);
149142542f5fSchristos		res = _XRRGetScreenResourcesCurrent(display->dpy, display->root);
149242542f5fSchristos		if (res == NULL)
149342542f5fSchristos			goto ungrab;
149442542f5fSchristos
149542542f5fSchristos		if (x2 <= x1 || y2 <= y1) {
149642542f5fSchristos			/* Nothing enabled, preserve the current fb, and turn everything off */
149742542f5fSchristos			for (clone = display->clone; clone; clone = clone->next) {
149842542f5fSchristos				struct output *dst = &clone->dst;
149942542f5fSchristos
150042542f5fSchristos				if (!dst->rr_crtc)
150142542f5fSchristos					continue;
150242542f5fSchristos
150342542f5fSchristos				DBG(XRR, ("%s: disabling output '%s'\n",
150442542f5fSchristos				     DisplayString(display->dpy), dst->name));
150542542f5fSchristos				assert(clone->dst.display == display);
150642542f5fSchristos				if (disable_crtc(display->dpy, res, dst->rr_crtc)) {
150742542f5fSchristos					dst->rr_crtc = 0;
150842542f5fSchristos					dst->mode.id = 0;
150942542f5fSchristos				}
151042542f5fSchristos			}
151142542f5fSchristos			goto free_res;
151242542f5fSchristos		}
151342542f5fSchristos
151442542f5fSchristos		x2 -= x1;
151542542f5fSchristos		y2 -= y1;
151642542f5fSchristos		DBG(XRR, ("%s: current size %dx%d, need %dx%d\n",
151742542f5fSchristos		     DisplayString(display->dpy),
151842542f5fSchristos		     display->width, display->height,
151942542f5fSchristos		     x2, y2));
152042542f5fSchristos
152142542f5fSchristos		if (display->width != x2 || display->height != y2) {
152242542f5fSchristos			/* When shrinking we have to manually resize the fb */
152342542f5fSchristos			for (clone = display->clone; clone; clone = clone->next) {
152442542f5fSchristos				struct output *dst = &clone->dst;
152542542f5fSchristos
152642542f5fSchristos				if (!dst->rr_crtc)
152742542f5fSchristos					continue;
152842542f5fSchristos
152942542f5fSchristos				DBG(XRR, ("%s: disabling output '%s'\n",
153042542f5fSchristos				     DisplayString(display->dpy), dst->name));
153142542f5fSchristos				assert(clone->dst.display == display);
153242542f5fSchristos				if (disable_crtc(display->dpy, res, dst->rr_crtc)) {
153342542f5fSchristos					dst->rr_crtc = 0;
153442542f5fSchristos					dst->mode.id = 0;
153542542f5fSchristos				}
153642542f5fSchristos			}
153742542f5fSchristos
153842542f5fSchristos			DBG(XRR, ("%s: XRRSetScreenSize %dx%d\n", DisplayString(display->dpy), x2, y2));
153942542f5fSchristos			XRRSetScreenSize(display->dpy, display->root, x2, y2, x2 * 96 / 25.4, y2 * 96 / 25.4);
154042542f5fSchristos			display->width = x2;
154142542f5fSchristos			display->height = y2;
154242542f5fSchristos		}
154342542f5fSchristos
154442542f5fSchristos		for (clone = display->clone; clone; clone = clone->next) {
154542542f5fSchristos			struct output *src = &clone->src;
154642542f5fSchristos			struct output *dst = &clone->dst;
154742542f5fSchristos			XRROutputInfo *o;
154842542f5fSchristos			XRRPanning panning;
154942542f5fSchristos			struct clone *set;
155042542f5fSchristos			RRCrtc rr_crtc;
155142542f5fSchristos			Status ret;
155242542f5fSchristos
155342542f5fSchristos			DBG(XRR, ("%s: copying configuration from %s (mode=%ld: %dx%d) to %s\n",
155442542f5fSchristos			     DisplayString(display->dpy),
155542542f5fSchristos			     src->name, (long)src->mode.id, src->mode.width, src->mode.height,
155642542f5fSchristos			     dst->name));
155742542f5fSchristos
155842542f5fSchristos			if (src->mode.id == 0) {
155942542f5fSchristoserr:
156042542f5fSchristos				if (dst->rr_crtc) {
156142542f5fSchristos					DBG(XRR, ("%s: disabling unused output '%s'\n",
156242542f5fSchristos					     DisplayString(display->dpy), dst->name));
156342542f5fSchristos					assert(clone->dst.display == display);
156442542f5fSchristos					if (disable_crtc(display->dpy, res, dst->rr_crtc)) {
156542542f5fSchristos						dst->rr_crtc = 0;
156642542f5fSchristos						dst->mode.id = 0;
156742542f5fSchristos					}
156842542f5fSchristos				}
156942542f5fSchristos				continue;
157042542f5fSchristos			}
157142542f5fSchristos
157242542f5fSchristos			dst->x = src->x - x1;
157342542f5fSchristos			dst->y = src->y - y1;
157442542f5fSchristos			dst->rotation = src->rotation;
157542542f5fSchristos			dst->mode = src->mode;
157642542f5fSchristos
157742542f5fSchristos			dst->mode.id = 0;
157842542f5fSchristos			for (i = 0; i < res->nmode; i++) {
157942542f5fSchristos				if (mode_equal(&src->mode, &res->modes[i])) {
158042542f5fSchristos					dst->mode.id = res->modes[i].id;
158142542f5fSchristos					break;
158242542f5fSchristos				}
158342542f5fSchristos			}
158442542f5fSchristos			if (dst->mode.id == 0) {
158542542f5fSchristos				XRRModeInfo m;
158642542f5fSchristos				char buf[256];
158742542f5fSchristos				RRMode id;
158842542f5fSchristos
158942542f5fSchristos				/* XXX User names must be unique! */
159042542f5fSchristos				m = src->mode;
159142542f5fSchristos				m.nameLength = snprintf(buf, sizeof(buf),
159242542f5fSchristos							"%s.%ld-%dx%d", src->name,
159342542f5fSchristos							(long)src->mode.id,
159442542f5fSchristos							src->mode.width,
159542542f5fSchristos							src->mode.height);
159642542f5fSchristos				m.name = buf;
159742542f5fSchristos
159842542f5fSchristos				id = XRRCreateMode(dst->dpy, dst->window, &m);
159942542f5fSchristos				if (id) {
160042542f5fSchristos					DBG(XRR, ("%s: adding mode %ld: %dx%d to %s, new mode %ld\n",
160142542f5fSchristos					     DisplayString(dst->dpy),
160242542f5fSchristos					     (long)src->mode.id,
160342542f5fSchristos					     src->mode.width,
160442542f5fSchristos					     src->mode.height,
160542542f5fSchristos					     dst->name, (long)id));
160642542f5fSchristos					XRRAddOutputMode(dst->dpy, dst->rr_output, id);
160742542f5fSchristos					dst->mode.id = id;
160842542f5fSchristos				} else {
160942542f5fSchristos					DBG(XRR, ("%s: failed to find suitable mode for %s\n",
161042542f5fSchristos					     DisplayString(dst->dpy), dst->name));
161142542f5fSchristos					goto err;
161242542f5fSchristos				}
161342542f5fSchristos			}
161442542f5fSchristos
161542542f5fSchristos			rr_crtc = dst->rr_crtc;
161642542f5fSchristos			if (rr_crtc) {
161742542f5fSchristos				for (set = display->clone; set != clone; set = set->next) {
161842542f5fSchristos					if (set->dst.rr_crtc == rr_crtc) {
161942542f5fSchristos						DBG(XRR, ("%s: CRTC reassigned from %s\n",
162042542f5fSchristos						     DisplayString(dst->dpy), dst->name));
162142542f5fSchristos						rr_crtc = 0;
162242542f5fSchristos						break;
162342542f5fSchristos					}
162442542f5fSchristos				}
162542542f5fSchristos			}
162642542f5fSchristos			if (rr_crtc == 0) {
162742542f5fSchristos				o = XRRGetOutputInfo(dst->dpy, res, dst->rr_output);
162842542f5fSchristos				for (i = 0; i < o->ncrtc; i++) {
162942542f5fSchristos					DBG(XRR, ("%s: checking whether CRTC:%ld is available\n",
163042542f5fSchristos					     DisplayString(dst->dpy), (long)o->crtcs[i]));
163142542f5fSchristos					for (set = display->clone; set != clone; set = set->next) {
163242542f5fSchristos						if (set->dst.rr_crtc == o->crtcs[i]) {
163342542f5fSchristos							DBG(XRR, ("%s: CRTC:%ld already assigned to %s\n",
163442542f5fSchristos							     DisplayString(dst->dpy), (long)o->crtcs[i], set->dst.name));
163542542f5fSchristos							break;
163642542f5fSchristos						}
163742542f5fSchristos					}
163842542f5fSchristos					if (set == clone) {
163942542f5fSchristos						rr_crtc = o->crtcs[i];
164042542f5fSchristos						break;
164142542f5fSchristos					}
164242542f5fSchristos				}
164342542f5fSchristos				XRRFreeOutputInfo(o);
164442542f5fSchristos			}
164542542f5fSchristos			if (rr_crtc == 0) {
164642542f5fSchristos				DBG(XRR, ("%s: failed to find available CRTC for %s\n",
164742542f5fSchristos				     DisplayString(dst->dpy), dst->name));
164842542f5fSchristos				goto err;
164942542f5fSchristos			}
165042542f5fSchristos
165142542f5fSchristos			DBG(XRR, ("%s: enabling output '%s' (%d,%d)x(%d,%d), rotation %d, on CRTC:%ld, using mode %ld\n",
165242542f5fSchristos			     DisplayString(dst->dpy), dst->name,
165342542f5fSchristos			     dst->x, dst->y, dst->mode.width, dst->mode.height,
165442542f5fSchristos			     dst->rotation, (long)rr_crtc, dst->mode.id));
165542542f5fSchristos
165642542f5fSchristos			ret = XRRSetPanning(dst->dpy, res, rr_crtc, memset(&panning, 0, sizeof(panning)));
165742542f5fSchristos			DBG(XRR, ("%s-%s: XRRSetPanning %s\n", DisplayString(dst->dpy), dst->name, ret ? "failed" : "success"));
165842542f5fSchristos			(void)ret;
165942542f5fSchristos
166042542f5fSchristos			ret = XRRSetCrtcConfig(dst->dpy, res, rr_crtc, CurrentTime,
166142542f5fSchristos					       dst->x, dst->y, dst->mode.id, dst->rotation,
166242542f5fSchristos					       &dst->rr_output, 1);
166342542f5fSchristos			DBG(XRR, ("%s-%s: XRRSetCrtcConfig %s\n", DisplayString(dst->dpy), dst->name, ret ? "failed" : "success"));
166442542f5fSchristos			if (ret)
166542542f5fSchristos				goto err;
166642542f5fSchristos
166742542f5fSchristos			if (verbose & XRR) {
166842542f5fSchristos				XRRCrtcInfo *c;
166942542f5fSchristos				XRRPanning *p;
167042542f5fSchristos
167142542f5fSchristos				c = XRRGetCrtcInfo(dst->dpy, res, rr_crtc);
167242542f5fSchristos				if (c) {
167342542f5fSchristos					DBG(XRR, ("%s-%s: x=%d, y=%d, rotation=%d, mode=%ld\n",
167442542f5fSchristos					     DisplayString(dst->dpy), dst->name,
167542542f5fSchristos					     c->x, c->y, c->rotation, c->mode));
167642542f5fSchristos					XRRFreeCrtcInfo(c);
167742542f5fSchristos				}
167842542f5fSchristos
167942542f5fSchristos				p = XRRGetPanning(dst->dpy, res, rr_crtc);
168042542f5fSchristos				if (p) {
168142542f5fSchristos					DBG(XRR, ("%s-%s: panning (%d, %d)x(%d, %d), tracking (%d, %d)x(%d, %d), border (%d, %d),(%d, %d)\n",
168242542f5fSchristos					     DisplayString(dst->dpy), dst->name,
168342542f5fSchristos					     p->left, p->top, p->width, p->height,
168442542f5fSchristos					     p->track_left, p->track_top, p->track_width, p->track_height,
168542542f5fSchristos					     p->border_left, p->border_top, p->border_right, p->border_bottom));
168642542f5fSchristos					XRRFreePanning(p);
168742542f5fSchristos				}
168842542f5fSchristos			}
168942542f5fSchristos
169042542f5fSchristos			dst->rr_crtc = rr_crtc;
169142542f5fSchristos		}
169242542f5fSchristosfree_res:
169342542f5fSchristos		XRRFreeScreenResources(res);
169442542f5fSchristosungrab:
169542542f5fSchristos		XUngrabServer(display->dpy);
169642542f5fSchristos	}
169742542f5fSchristos
1698fe8aea9eSmrg	for (n = 1; n < ctx->ndisplay; n++) {
1699fe8aea9eSmrg		struct display *display = &ctx->display[n];
1700fe8aea9eSmrg
1701fe8aea9eSmrg		display->active = 0;
1702fe8aea9eSmrg		screensaver_restore(display);
1703fe8aea9eSmrg	}
1704fe8aea9eSmrg
170542542f5fSchristos	ctx->active = NULL;
170642542f5fSchristos	for (n = 0; n < ctx->nclone; n++) {
170742542f5fSchristos		struct clone *clone = &ctx->clones[n];
170842542f5fSchristos
170942542f5fSchristos		clone_init_xfer(clone);
171042542f5fSchristos
171142542f5fSchristos		if (clone->dst.rr_crtc == 0)
171242542f5fSchristos			continue;
171342542f5fSchristos
171442542f5fSchristos		DBG(XRR, ("%s-%s: added to active list\n",
1715fe8aea9eSmrg			  DisplayString(clone->dst.display->dpy), clone->dst.name));
1716fe8aea9eSmrg
1717fe8aea9eSmrg		if (clone->dst.display->active++ == 0)
1718fe8aea9eSmrg			screensaver_disable(clone->dst.display);
171942542f5fSchristos
172042542f5fSchristos		clone->active = ctx->active;
172142542f5fSchristos		ctx->active = clone;
172242542f5fSchristos	}
172342542f5fSchristos
172442542f5fSchristos	return 1;
172542542f5fSchristos}
172642542f5fSchristos
172742542f5fSchristosstatic Cursor display_load_invisible_cursor(struct display *display)
172842542f5fSchristos{
172942542f5fSchristos	char zero[8] = {};
173042542f5fSchristos	XColor black = {};
173142542f5fSchristos	Pixmap bitmap = XCreateBitmapFromData(display->dpy, display->root, zero, 8, 8);
173242542f5fSchristos	return XCreatePixmapCursor(display->dpy, bitmap, bitmap, &black, &black, 0, 0);
173342542f5fSchristos}
173442542f5fSchristos
173542542f5fSchristosstatic Cursor display_get_visible_cursor(struct display *display)
173642542f5fSchristos{
1737fe8aea9eSmrg	struct display *first = display->ctx->display;
1738fe8aea9eSmrg
1739fe8aea9eSmrg	if (display->cursor_serial != first->cursor_serial) {
1740fe8aea9eSmrg		DBG(CURSOR, ("%s updating cursor %dx%d, serial %d\n",
1741fe8aea9eSmrg		    DisplayString(display->dpy), first->cursor_image.width, first->cursor_image.height, first->cursor_serial));
174242542f5fSchristos
174342542f5fSchristos		if (display->visible_cursor)
174442542f5fSchristos			XFreeCursor(display->dpy, display->visible_cursor);
174542542f5fSchristos
1746fe8aea9eSmrg		display->visible_cursor = XcursorImageLoadCursor(display->dpy, &first->cursor_image);
1747fe8aea9eSmrg		display->cursor_serial = first->cursor_serial;
174842542f5fSchristos	}
174942542f5fSchristos
175042542f5fSchristos	return display->visible_cursor;
175142542f5fSchristos}
175242542f5fSchristos
175342542f5fSchristosstatic void display_load_visible_cursor(struct display *display, XFixesCursorImage *cur)
175442542f5fSchristos{
175542542f5fSchristos	unsigned long *src; /* XXX deep sigh */
175642542f5fSchristos	XcursorPixel *dst;
175742542f5fSchristos	unsigned n;
175842542f5fSchristos
175942542f5fSchristos	if (cur->width != display->cursor_image.width ||
176042542f5fSchristos	    cur->height != display->cursor_image.height)
176142542f5fSchristos		display->cursor_image.pixels = realloc(display->cursor_image.pixels,
176242542f5fSchristos						       4 * cur->width * cur->height);
176342542f5fSchristos	if (display->cursor_image.pixels == NULL)
176442542f5fSchristos		return;
176542542f5fSchristos
176642542f5fSchristos	display->cursor_image.width  = cur->width;
176742542f5fSchristos	display->cursor_image.height = cur->height;
176842542f5fSchristos	display->cursor_image.xhot = cur->xhot;
176942542f5fSchristos	display->cursor_image.yhot = cur->yhot;
1770fe8aea9eSmrg	display->cursor_serial++;
177142542f5fSchristos
177242542f5fSchristos	n = cur->width*cur->height;
177342542f5fSchristos	src = cur->pixels;
177442542f5fSchristos	dst = display->cursor_image.pixels;
177542542f5fSchristos	while (n--)
177642542f5fSchristos		*dst++ = *src++;
177742542f5fSchristos
1778fe8aea9eSmrg	if (verbose & CURSOR) {
1779fe8aea9eSmrg		int x, y;
1780fe8aea9eSmrg
1781fe8aea9eSmrg		printf("%s cursor image %dx%d, serial %d:\n",
1782fe8aea9eSmrg		       DisplayString(display->dpy),
1783fe8aea9eSmrg		       cur->width, cur->height,
1784fe8aea9eSmrg		       display->cursor_serial);
1785fe8aea9eSmrg		dst = display->cursor_image.pixels;
1786fe8aea9eSmrg		for (y = 0; y < cur->height; y++) {
1787fe8aea9eSmrg			for (x = 0; x < cur->width; x++) {
1788fe8aea9eSmrg				if (x == cur->xhot && y == cur->yhot)
1789fe8aea9eSmrg					printf("+");
1790fe8aea9eSmrg				else
1791fe8aea9eSmrg					printf("%c", *dst ? *dst >> 24 >= 127 ? 'x' : '.' : ' ');
1792fe8aea9eSmrg				dst++;
1793fe8aea9eSmrg			}
1794fe8aea9eSmrg			printf("\n");
1795fe8aea9eSmrg		}
179642542f5fSchristos	}
179742542f5fSchristos}
179842542f5fSchristos
179942542f5fSchristosstatic void display_cursor_move(struct display *display, int x, int y, int visible)
180042542f5fSchristos{
180142542f5fSchristos	DBG(CURSOR, ("%s cursor moved (visible=%d, (%d, %d))\n",
180242542f5fSchristos	     DisplayString(display->dpy), visible, x, y));
180342542f5fSchristos	display->cursor_moved++;
180442542f5fSchristos	display->cursor_visible += visible;
180542542f5fSchristos	if (visible) {
180642542f5fSchristos		display->cursor_x = x;
180742542f5fSchristos		display->cursor_y = y;
180842542f5fSchristos	}
180942542f5fSchristos
181042542f5fSchristos	context_enable_timer(display->ctx);
181142542f5fSchristos}
181242542f5fSchristos
181342542f5fSchristosstatic void display_flush_cursor(struct display *display)
181442542f5fSchristos{
181542542f5fSchristos	Cursor cursor;
181642542f5fSchristos	int x, y;
181742542f5fSchristos
181842542f5fSchristos	if (!display->cursor_moved)
181942542f5fSchristos		return;
182042542f5fSchristos
182142542f5fSchristos	if (display->cursor_visible) {
182242542f5fSchristos		x = display->cursor_x;
182342542f5fSchristos		y = display->cursor_y;
182442542f5fSchristos	} else {
182542542f5fSchristos		x = display->cursor_x++ & 31;
182642542f5fSchristos		y = display->cursor_y++ & 31;
182742542f5fSchristos	}
182842542f5fSchristos
182942542f5fSchristos	DBG(CURSOR, ("%s setting cursor position (%d, %d), visible? %d\n",
183042542f5fSchristos	     DisplayString(display->dpy), x, y, display->cursor_visible));
183142542f5fSchristos	XWarpPointer(display->dpy, None, display->root, 0, 0, 0, 0, x, y);
183242542f5fSchristos
183342542f5fSchristos	cursor = None;
183442542f5fSchristos	if (display->cursor_visible)
183542542f5fSchristos		cursor = display_get_visible_cursor(display);
183642542f5fSchristos	if (cursor == None)
183742542f5fSchristos		cursor = display->invisible_cursor;
183842542f5fSchristos	if (cursor != display->cursor) {
1839fe8aea9eSmrg		DBG(CURSOR, ("%s setting cursor shape %lx\n",
1840fe8aea9eSmrg		    DisplayString(display->dpy), (long)cursor));
184142542f5fSchristos		XDefineCursor(display->dpy, display->root, cursor);
184242542f5fSchristos		display->cursor = cursor;
184342542f5fSchristos	}
184442542f5fSchristos
184542542f5fSchristos	display_mark_flush(display);
184642542f5fSchristos
184742542f5fSchristos	display->cursor_moved = 0;
184842542f5fSchristos	display->cursor_visible = 0;
184942542f5fSchristos}
185042542f5fSchristos
185142542f5fSchristosstatic void clone_move_cursor(struct clone *c, int x, int y)
185242542f5fSchristos{
185342542f5fSchristos	int visible;
185442542f5fSchristos
185542542f5fSchristos	DBG(CURSOR, ("%s-%s moving cursor (%d, %d) [(%d, %d), (%d, %d)]\n",
185642542f5fSchristos	     DisplayString(c->dst.dpy), c->dst.name,
185742542f5fSchristos	     x, y,
185842542f5fSchristos	     c->src.x, c->src.y,
185942542f5fSchristos	     c->src.x + c->width, c->src.y + c->height));
186042542f5fSchristos
186142542f5fSchristos	visible = (x >= c->src.x && x < c->src.x + c->width &&
186242542f5fSchristos		   y >= c->src.y && y < c->src.y + c->height);
186342542f5fSchristos
186442542f5fSchristos	x += c->dst.x - c->src.x;
186542542f5fSchristos	y += c->dst.y - c->src.y;
186642542f5fSchristos
186742542f5fSchristos	display_cursor_move(c->dst.display, x, y, visible);
186842542f5fSchristos}
186942542f5fSchristos
187042542f5fSchristosstatic int clone_output_init(struct clone *clone, struct output *output,
187142542f5fSchristos			     struct display *display, const char *name,
187242542f5fSchristos			     RROutput rr_output)
187342542f5fSchristos{
187442542f5fSchristos	Display *dpy = display->dpy;
187542542f5fSchristos	int depth;
187642542f5fSchristos
187742542f5fSchristos	DBG(X11, ("%s(%s, %s)\n", __func__, DisplayString(dpy), name));
187842542f5fSchristos
187942542f5fSchristos	output->name = strdup(name);
188042542f5fSchristos	if (output->name == NULL)
188142542f5fSchristos		return -ENOMEM;
188242542f5fSchristos
188342542f5fSchristos	output->display = display;
188442542f5fSchristos	output->dpy = dpy;
188542542f5fSchristos
188642542f5fSchristos	output->rr_output = rr_output;
188742542f5fSchristos	output->rotation = RR_Rotate_0;
188842542f5fSchristos
188942542f5fSchristos	output->window = display->root;
189042542f5fSchristos	output->use_shm = display->has_shm;
189142542f5fSchristos	output->use_shm_pixmap = display->has_shm_pixmap;
189242542f5fSchristos
189342542f5fSchristos	DBG(X11, ("%s-%s use shm? %d (use shm pixmap? %d)\n",
189442542f5fSchristos	     DisplayString(dpy), name, display->has_shm, display->has_shm_pixmap));
189542542f5fSchristos
189642542f5fSchristos	depth = output->use_shm && !FORCE_16BIT_XFER ? display->depth : 16;
189742542f5fSchristos	if (depth < clone->depth)
189842542f5fSchristos		clone->depth = depth;
189942542f5fSchristos
190042542f5fSchristos	return 0;
190142542f5fSchristos}
190242542f5fSchristos
190342542f5fSchristosstatic void ximage_prepare(XImage *image, int width, int height)
190442542f5fSchristos{
190542542f5fSchristos	image->width = width;
190642542f5fSchristos	image->height = height;
190742542f5fSchristos	image->bytes_per_line = stride_for_depth(width, image->depth);
190842542f5fSchristos}
190942542f5fSchristos
191042542f5fSchristosstatic void get_src(struct clone *c, const XRectangle *clip)
191142542f5fSchristos{
191242542f5fSchristos	DBG(DRAW,("%s-%s get_src(%d,%d)x(%d,%d)\n", DisplayString(c->dst.dpy), c->dst.name,
191342542f5fSchristos	     clip->x, clip->y, clip->width, clip->height));
191442542f5fSchristos
191542542f5fSchristos	c->image.obdata = (char *)&c->src.shm;
191642542f5fSchristos
191742542f5fSchristos	if (c->src.use_render) {
1918fe8aea9eSmrg		DBG(DRAW, ("%s-%s get_src via XRender\n",
1919fe8aea9eSmrg			   DisplayString(c->dst.dpy), c->dst.name));
192042542f5fSchristos		XRenderComposite(c->src.dpy, PictOpSrc,
192142542f5fSchristos				 c->src.win_picture, 0, c->src.pix_picture,
192242542f5fSchristos				 clip->x, clip->y,
192342542f5fSchristos				 0, 0,
192442542f5fSchristos				 0, 0,
192542542f5fSchristos				 clip->width, clip->height);
192642542f5fSchristos		if (c->src.use_shm_pixmap) {
192742542f5fSchristos			XSync(c->src.dpy, False);
192842542f5fSchristos		} else if (c->src.use_shm) {
192942542f5fSchristos			ximage_prepare(&c->image, clip->width, clip->height);
193042542f5fSchristos			XShmGetImage(c->src.dpy, c->src.pixmap, &c->image,
193142542f5fSchristos				     clip->x, clip->y, AllPlanes);
193242542f5fSchristos		} else {
193342542f5fSchristos			ximage_prepare(&c->image, c->width, c->height);
193442542f5fSchristos			XGetSubImage(c->src.dpy, c->src.pixmap,
193542542f5fSchristos				     clip->x, clip->y, clip->width, clip->height,
193642542f5fSchristos				     AllPlanes, ZPixmap,
193742542f5fSchristos				     &c->image, 0, 0);
193842542f5fSchristos		}
193942542f5fSchristos	} else if (c->src.pixmap) {
1940fe8aea9eSmrg		DBG(DRAW, ("%s-%s get_src XCopyArea (SHM/DRI3)\n",
1941fe8aea9eSmrg			   DisplayString(c->dst.dpy), c->dst.name));
194242542f5fSchristos		XCopyArea(c->src.dpy, c->src.window, c->src.pixmap, c->src.gc,
194342542f5fSchristos			  clip->x, clip->y,
194442542f5fSchristos			  clip->width, clip->height,
194542542f5fSchristos			  0, 0);
194642542f5fSchristos		XSync(c->src.dpy, False);
194742542f5fSchristos	} else if (c->src.use_shm) {
1948fe8aea9eSmrg		DBG(DRAW, ("%s-%s get_src XShmGetImage\n",
1949fe8aea9eSmrg			   DisplayString(c->dst.dpy), c->dst.name));
195042542f5fSchristos		ximage_prepare(&c->image, clip->width, clip->height);
195142542f5fSchristos		XShmGetImage(c->src.dpy, c->src.window, &c->image,
195242542f5fSchristos			     clip->x, clip->y, AllPlanes);
195342542f5fSchristos	} else {
1954fe8aea9eSmrg		DBG(DRAW, ("%s-%s get_src XGetSubImage (slow)\n",
1955fe8aea9eSmrg			   DisplayString(c->dst.dpy), c->dst.name));
195642542f5fSchristos		ximage_prepare(&c->image, c->width, c->height);
195742542f5fSchristos		XGetSubImage(c->src.dpy, c->src.window,
195842542f5fSchristos			     clip->x, clip->y, clip->width, clip->height,
195942542f5fSchristos			     AllPlanes, ZPixmap,
196042542f5fSchristos			     &c->image, 0, 0);
196142542f5fSchristos	}
196242542f5fSchristos	c->src.display->flush = 0;
196342542f5fSchristos}
196442542f5fSchristos
196542542f5fSchristosstatic void put_dst(struct clone *c, const XRectangle *clip)
196642542f5fSchristos{
196742542f5fSchristos	DBG(DRAW, ("%s-%s put_dst(%d,%d)x(%d,%d)\n", DisplayString(c->dst.dpy), c->dst.name,
196842542f5fSchristos	     clip->x, clip->y, clip->width, clip->height));
196942542f5fSchristos
197042542f5fSchristos	c->image.obdata = (char *)&c->dst.shm;
197142542f5fSchristos
197242542f5fSchristos	if (c->dst.use_render) {
197342542f5fSchristos		if (c->dst.use_shm_pixmap) {
197442542f5fSchristos			DBG(DRAW, ("%s-%s using SHM pixmap composite\n",
197542542f5fSchristos			     DisplayString(c->dst.dpy), c->dst.name));
197642542f5fSchristos		} else if (c->dst.use_shm) {
197742542f5fSchristos			DBG(DRAW, ("%s-%s using SHM image composite\n",
197842542f5fSchristos			     DisplayString(c->dst.dpy), c->dst.name));
197942542f5fSchristos			XShmPutImage(c->dst.dpy, c->dst.pixmap, c->dst.gc, &c->image,
198042542f5fSchristos				     0, 0,
198142542f5fSchristos				     0, 0,
198242542f5fSchristos				     clip->width, clip->height,
198342542f5fSchristos				     False);
198442542f5fSchristos		} else {
198542542f5fSchristos			DBG(DRAW, ("%s-%s using composite\n",
198642542f5fSchristos			     DisplayString(c->dst.dpy), c->dst.name));
198742542f5fSchristos			XPutImage(c->dst.dpy, c->dst.pixmap, c->dst.gc, &c->image,
198842542f5fSchristos				  0, 0,
198942542f5fSchristos				  0, 0,
199042542f5fSchristos				  clip->width, clip->height);
199142542f5fSchristos		}
199242542f5fSchristos		if (c->dst.use_shm)
199342542f5fSchristos			c->dst.serial = NextRequest(c->dst.dpy);
199442542f5fSchristos		XRenderComposite(c->dst.dpy, PictOpSrc,
199542542f5fSchristos				 c->dst.pix_picture, 0, c->dst.win_picture,
199642542f5fSchristos				 0, 0,
199742542f5fSchristos				 0, 0,
199842542f5fSchristos				 clip->x, clip->y,
199942542f5fSchristos				 clip->width, clip->height);
200042542f5fSchristos		c->dst.display->send |= c->dst.use_shm;
200142542f5fSchristos	} else if (c->dst.pixmap) {
2002fe8aea9eSmrg		DBG(DRAW, ("%s-%s using SHM or DRI3 pixmap\n",
200342542f5fSchristos		     DisplayString(c->dst.dpy), c->dst.name));
200442542f5fSchristos		c->dst.serial = NextRequest(c->dst.dpy);
200542542f5fSchristos		XCopyArea(c->dst.dpy, c->dst.pixmap, c->dst.window, c->dst.gc,
200642542f5fSchristos			  0, 0,
200742542f5fSchristos			  clip->width, clip->height,
200842542f5fSchristos			  clip->x, clip->y);
200942542f5fSchristos		c->dst.display->send = 1;
201042542f5fSchristos	} else if (c->dst.use_shm) {
201142542f5fSchristos		DBG(DRAW, ("%s-%s using SHM image\n",
201242542f5fSchristos		     DisplayString(c->dst.dpy), c->dst.name));
201342542f5fSchristos		c->dst.serial = NextRequest(c->dst.dpy);
201442542f5fSchristos		XShmPutImage(c->dst.dpy, c->dst.window, c->dst.gc, &c->image,
201542542f5fSchristos			     0, 0,
201642542f5fSchristos			     clip->x, clip->y,
201742542f5fSchristos			     clip->width, clip->height,
201842542f5fSchristos			     True);
201942542f5fSchristos	} else {
202042542f5fSchristos		DBG(DRAW, ("%s-%s using image\n",
202142542f5fSchristos		     DisplayString(c->dst.dpy), c->dst.name));
202242542f5fSchristos		XPutImage(c->dst.dpy, c->dst.window, c->dst.gc, &c->image,
202342542f5fSchristos			  0, 0,
202442542f5fSchristos			  clip->x, clip->y,
202542542f5fSchristos			  clip->width, clip->height);
202642542f5fSchristos		c->dst.serial = 0;
202742542f5fSchristos	}
202842542f5fSchristos}
202942542f5fSchristos
203042542f5fSchristosstatic int clone_paint(struct clone *c)
203142542f5fSchristos{
203242542f5fSchristos	XRectangle clip;
203342542f5fSchristos
2034fe8aea9eSmrg	if (c->width == 0 || c->height == 0)
2035fe8aea9eSmrg		return 0;
2036fe8aea9eSmrg
203742542f5fSchristos	DBG(DRAW, ("%s-%s paint clone, damaged (%d, %d), (%d, %d) [(%d, %d), (%d,  %d)]\n",
203842542f5fSchristos	     DisplayString(c->dst.dpy), c->dst.name,
203942542f5fSchristos	     c->damaged.x1, c->damaged.y1,
204042542f5fSchristos	     c->damaged.x2, c->damaged.y2,
204142542f5fSchristos	     c->src.x, c->src.y,
204242542f5fSchristos	     c->src.x + c->width, c->src.y + c->height));
204342542f5fSchristos
204442542f5fSchristos	if (c->damaged.x1 < c->src.x)
204542542f5fSchristos		c->damaged.x1 = c->src.x;
204642542f5fSchristos	if (c->damaged.x2 > c->src.x + c->width)
204742542f5fSchristos		c->damaged.x2 = c->src.x + c->width;
204842542f5fSchristos	if (c->damaged.x2 <= c->damaged.x1)
204942542f5fSchristos		goto done;
205042542f5fSchristos
205142542f5fSchristos	if (c->damaged.y1 < c->src.y)
205242542f5fSchristos		c->damaged.y1 = c->src.y;
205342542f5fSchristos	if (c->damaged.y2 > c->src.y + c->height)
205442542f5fSchristos		c->damaged.y2 = c->src.y + c->height;
205542542f5fSchristos	if (c->damaged.y2 <= c->damaged.y1)
205642542f5fSchristos		goto done;
205742542f5fSchristos
205842542f5fSchristos	DBG(DRAW, ("%s-%s is damaged, last SHM serial: %ld, now %ld\n",
205942542f5fSchristos	     DisplayString(c->dst.dpy), c->dst.name,
206042542f5fSchristos	     (long)c->dst.serial, (long)LastKnownRequestProcessed(c->dst.dpy)));
206142542f5fSchristos	if (c->dst.serial > LastKnownRequestProcessed(c->dst.dpy)) {
206242542f5fSchristos		struct pollfd pfd;
206342542f5fSchristos
206442542f5fSchristos		pfd.fd = ConnectionNumber(c->dst.dpy);
206542542f5fSchristos		pfd.events = POLLIN;
206642542f5fSchristos		XEventsQueued(c->dst.dpy,
206742542f5fSchristos			      poll(&pfd, 1, 0) ? QueuedAfterReading : QueuedAfterFlush);
206842542f5fSchristos
206942542f5fSchristos		if (c->dst.serial > LastKnownRequestProcessed(c->dst.dpy)) {
207042542f5fSchristos			c->dst.display->skip_clone++;
207142542f5fSchristos			return EAGAIN;
207242542f5fSchristos		}
207342542f5fSchristos	}
207442542f5fSchristos
207542542f5fSchristos	c->dst.display->skip_clone = 0;
207642542f5fSchristos	c->dst.display->skip_frame = 0;
207742542f5fSchristos
207842542f5fSchristos	if (FORCE_FULL_REDRAW) {
207942542f5fSchristos		c->damaged.x1 = c->src.x;
208042542f5fSchristos		c->damaged.y1 = c->src.y;
208142542f5fSchristos		c->damaged.x2 = c->src.x + c->width;
208242542f5fSchristos		c->damaged.y2 = c->src.y + c->height;
208342542f5fSchristos	}
208442542f5fSchristos
208542542f5fSchristos	if (c->dri3.xid) {
208642542f5fSchristos		if (c->src.use_render) {
208742542f5fSchristos			XRenderComposite(c->src.dpy, PictOpSrc,
208842542f5fSchristos					 c->src.win_picture, 0, c->src.pix_picture,
208942542f5fSchristos					 c->damaged.x1, c->damaged.y1,
209042542f5fSchristos					 0, 0,
209142542f5fSchristos					 c->damaged.x1 + c->dst.x - c->src.x,
209242542f5fSchristos					 c->damaged.y1 + c->dst.y - c->src.y,
209342542f5fSchristos					 c->damaged.x2 - c->damaged.x1,
209442542f5fSchristos					 c->damaged.y2 - c->damaged.y1);
209542542f5fSchristos		} else {
209642542f5fSchristos			XCopyArea(c->src.dpy, c->src.window, c->src.pixmap, c->src.gc,
209742542f5fSchristos				  c->damaged.x1, c->damaged.y1,
209842542f5fSchristos				  c->damaged.x2 - c->damaged.x1,
209942542f5fSchristos				  c->damaged.y2 - c->damaged.y1,
210042542f5fSchristos				  c->damaged.x1 + c->dst.x - c->src.x,
210142542f5fSchristos				  c->damaged.y1 + c->dst.y - c->src.y);
210242542f5fSchristos		}
210342542f5fSchristos		dri3_fence_flush(c->src.dpy, &c->dri3);
210442542f5fSchristos	} else {
210542542f5fSchristos		clip.x = c->damaged.x1;
210642542f5fSchristos		clip.y = c->damaged.y1;
210742542f5fSchristos		clip.width  = c->damaged.x2 - c->damaged.x1;
210842542f5fSchristos		clip.height = c->damaged.y2 - c->damaged.y1;
210942542f5fSchristos		get_src(c, &clip);
211042542f5fSchristos
2111fe8aea9eSmrg		DBG(DRAW, ("%s-%s target offset %dx%d\n",
2112fe8aea9eSmrg			   DisplayString(c->dst.dpy), c->dst.name,
2113fe8aea9eSmrg			   c->dst.x - c->src.x, c->dst.y - c->src.y));
2114fe8aea9eSmrg
211542542f5fSchristos		clip.x += c->dst.x - c->src.x;
211642542f5fSchristos		clip.y += c->dst.y - c->src.y;
211742542f5fSchristos		put_dst(c, &clip);
211842542f5fSchristos	}
211942542f5fSchristos	display_mark_flush(c->dst.display);
212042542f5fSchristos
212142542f5fSchristosdone:
212242542f5fSchristos	c->damaged.x2 = c->damaged.y2 = INT_MIN;
212342542f5fSchristos	c->damaged.x1 = c->damaged.y1 = INT_MAX;
212442542f5fSchristos	return 0;
212542542f5fSchristos}
212642542f5fSchristos
212742542f5fSchristosstatic void clone_damage(struct clone *c, const XRectangle *rec)
212842542f5fSchristos{
212942542f5fSchristos	int v;
213042542f5fSchristos
213142542f5fSchristos	if ((v = rec->x) < c->damaged.x1)
213242542f5fSchristos		c->damaged.x1 = v;
213342542f5fSchristos	if ((v = (int)rec->x + rec->width) > c->damaged.x2)
213442542f5fSchristos		c->damaged.x2 = v;
213542542f5fSchristos	if ((v = rec->y) < c->damaged.y1)
213642542f5fSchristos		c->damaged.y1 = v;
213742542f5fSchristos	if ((v = (int)rec->y + rec->height) > c->damaged.y2)
213842542f5fSchristos		c->damaged.y2 = v;
213942542f5fSchristos
2140fe8aea9eSmrg	DBG(DAMAGE, ("%s-%s damaged: +(%d,%d)x(%d, %d) -> (%d, %d), (%d, %d)\n",
214142542f5fSchristos	     DisplayString(c->dst.display->dpy), c->dst.name,
2142fe8aea9eSmrg	     rec->x, rec->y, rec->width, rec->height,
214342542f5fSchristos	     c->damaged.x1, c->damaged.y1,
214442542f5fSchristos	     c->damaged.x2, c->damaged.y2));
214542542f5fSchristos}
214642542f5fSchristos
214742542f5fSchristosstatic void usage(const char *arg0)
214842542f5fSchristos{
214942542f5fSchristos	printf("Usage: %s [OPTION]... [TARGET_DISPLAY]...\n", arg0);
215042542f5fSchristos	printf("  -d <source display>  source display\n");
215142542f5fSchristos	printf("  -f                   keep in foreground (do not detach from console and daemonize)\n");
215242542f5fSchristos	printf("  -b                   start bumblebee\n");
215342542f5fSchristos	printf("  -a                   connect to all local displays (e.g. :1, :2, etc)\n");
215442542f5fSchristos	printf("  -S                   disable use of a singleton and launch a fresh intel-virtual-output process\n");
215542542f5fSchristos	printf("  -v                   all verbose output, implies -f\n");
215642542f5fSchristos	printf("  -V <category>        specific verbose output, implies -f\n");
215742542f5fSchristos	printf("  -h                   this help\n");
215842542f5fSchristos	printf("If no target displays are parsed on the commandline, \n");
215942542f5fSchristos	printf("intel-virtual-output will attempt to connect to any local display\n");
216042542f5fSchristos	printf("and then start bumblebee.\n");
216142542f5fSchristos}
216242542f5fSchristos
216342542f5fSchristosstatic void record_callback(XPointer closure, XRecordInterceptData *data)
216442542f5fSchristos{
216542542f5fSchristos	struct context *ctx = (struct context *)closure;
216642542f5fSchristos
216742542f5fSchristos	DBG(X11, ("%s\n", __func__));
216842542f5fSchristos
216942542f5fSchristos	if (data->category == XRecordFromServer) {
217042542f5fSchristos		const xEvent *e = (const xEvent *)data->data;
217142542f5fSchristos
217242542f5fSchristos		DBG(X11, ("%s -- from server, event type %d, root %ld (ours? %d)\n",
217342542f5fSchristos		     __func__, e->u.u.type, (long)e->u.keyButtonPointer.root,
217442542f5fSchristos		     ctx->display->root == e->u.keyButtonPointer.root));
217542542f5fSchristos
217642542f5fSchristos		if (e->u.u.type == MotionNotify &&
217742542f5fSchristos		    e->u.keyButtonPointer.root == ctx->display->root) {
217842542f5fSchristos			struct clone *clone;
217942542f5fSchristos
218042542f5fSchristos			for (clone = ctx->active; clone; clone = clone->active)
218142542f5fSchristos				clone_move_cursor(clone,
218242542f5fSchristos						  e->u.keyButtonPointer.rootX,
218342542f5fSchristos						  e->u.keyButtonPointer.rootY);
218442542f5fSchristos		}
218542542f5fSchristos	}
218642542f5fSchristos
218742542f5fSchristos	XRecordFreeData(data);
218842542f5fSchristos}
218942542f5fSchristos
219042542f5fSchristosstatic int record_mouse(struct context *ctx)
219142542f5fSchristos{
219242542f5fSchristos	Display *dpy;
219342542f5fSchristos	XRecordRange *rr;
219442542f5fSchristos	XRecordClientSpec rcs;
219542542f5fSchristos	XRecordContext rc;
219642542f5fSchristos
219742542f5fSchristos	DBG(X11, ("%s(%s)\n", __func__, DisplayString(ctx->display->dpy)));
219842542f5fSchristos
219942542f5fSchristos	dpy = XOpenDisplay(DisplayString(ctx->display->dpy));
220042542f5fSchristos	if (dpy == NULL)
220142542f5fSchristos		return -ECONNREFUSED;
220242542f5fSchristos
220342542f5fSchristos	rr = XRecordAllocRange();
220442542f5fSchristos	if (rr == NULL)
220542542f5fSchristos		return -ENOMEM;
220642542f5fSchristos
220742542f5fSchristos	rr->device_events.first = rr->device_events.last = MotionNotify;
220842542f5fSchristos
220942542f5fSchristos	rcs = XRecordAllClients;
221042542f5fSchristos	rc = XRecordCreateContext(dpy, 0, &rcs, 1, &rr, 1);
221142542f5fSchristos
221242542f5fSchristos	XSync(dpy, False);
221342542f5fSchristos
221442542f5fSchristos	if (!XRecordEnableContextAsync(dpy, rc, record_callback, (XPointer)ctx))
221542542f5fSchristos		return -EINVAL;
221642542f5fSchristos
221742542f5fSchristos	ctx->record = dpy;
221842542f5fSchristos	return ConnectionNumber(dpy);
221942542f5fSchristos}
222042542f5fSchristos
222142542f5fSchristosstatic int bad_visual(Visual *visual, int depth)
222242542f5fSchristos{
222342542f5fSchristos	DBG(X11, ("%s? depth=%d, visual: class=%d, bits_per_rgb=%d, red_mask=%08lx, green_mask=%08lx, blue_mask=%08lx\n",
222442542f5fSchristos	     __func__, depth,
222542542f5fSchristos	     visual->class,
222642542f5fSchristos	     visual->bits_per_rgb,
222742542f5fSchristos	     visual->red_mask,
222842542f5fSchristos	     visual->green_mask,
222942542f5fSchristos	     visual->blue_mask));
223042542f5fSchristos
223142542f5fSchristos	if (!(visual->class == TrueColor || visual->class == DirectColor))
223242542f5fSchristos		return 1;
223342542f5fSchristos
223442542f5fSchristos	switch (depth) {
223542542f5fSchristos	case 16: return (/* visual->bits_per_rgb != 6          || */
223642542f5fSchristos			 visual->red_mask     != 0x1f << 11 ||
223742542f5fSchristos			 visual->green_mask   != 0x3f << 5  ||
223842542f5fSchristos			 visual->blue_mask    != 0x1f << 0);
223942542f5fSchristos
224042542f5fSchristos	case 24: return (/* visual->bits_per_rgb != 8          || */
224142542f5fSchristos			 visual->red_mask     != 0xff << 16 ||
224242542f5fSchristos			 visual->green_mask   != 0xff << 8  ||
224342542f5fSchristos			 visual->blue_mask    != 0xff << 0);
224442542f5fSchristos
224542542f5fSchristos	default: return 1;
224642542f5fSchristos	}
224742542f5fSchristos}
224842542f5fSchristos
224942542f5fSchristosstatic XRenderPictFormat *
225042542f5fSchristosfind_xrender_format(Display *dpy, pixman_format_code_t format)
225142542f5fSchristos{
225242542f5fSchristos    XRenderPictFormat tmpl;
225342542f5fSchristos    int mask;
225442542f5fSchristos
225542542f5fSchristos#define MASK(x) ((1<<(x))-1)
225642542f5fSchristos
225742542f5fSchristos    memset(&tmpl, 0, sizeof(tmpl));
225842542f5fSchristos
225942542f5fSchristos    tmpl.depth = PIXMAN_FORMAT_DEPTH(format);
226042542f5fSchristos    mask = PictFormatType | PictFormatDepth;
226142542f5fSchristos
226242542f5fSchristos    DBG(X11, ("%s(0x%08lx)\n", __func__, (long)format));
226342542f5fSchristos
226442542f5fSchristos    switch (PIXMAN_FORMAT_TYPE(format)) {
226542542f5fSchristos    case PIXMAN_TYPE_ARGB:
226642542f5fSchristos	tmpl.type = PictTypeDirect;
226742542f5fSchristos
226842542f5fSchristos	if (PIXMAN_FORMAT_A(format)) {
226942542f5fSchristos		tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
227042542f5fSchristos		tmpl.direct.alpha = (PIXMAN_FORMAT_R(format) +
227142542f5fSchristos				     PIXMAN_FORMAT_G(format) +
227242542f5fSchristos				     PIXMAN_FORMAT_B(format));
227342542f5fSchristos	}
227442542f5fSchristos
227542542f5fSchristos	tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
227642542f5fSchristos	tmpl.direct.red = (PIXMAN_FORMAT_G(format) +
227742542f5fSchristos			   PIXMAN_FORMAT_B(format));
227842542f5fSchristos
227942542f5fSchristos	tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
228042542f5fSchristos	tmpl.direct.green = PIXMAN_FORMAT_B(format);
228142542f5fSchristos
228242542f5fSchristos	tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
228342542f5fSchristos	tmpl.direct.blue = 0;
228442542f5fSchristos
228542542f5fSchristos	mask |= PictFormatRed | PictFormatRedMask;
228642542f5fSchristos	mask |= PictFormatGreen | PictFormatGreenMask;
228742542f5fSchristos	mask |= PictFormatBlue | PictFormatBlueMask;
228842542f5fSchristos	mask |= PictFormatAlpha | PictFormatAlphaMask;
228942542f5fSchristos	break;
229042542f5fSchristos
229142542f5fSchristos    case PIXMAN_TYPE_ABGR:
229242542f5fSchristos	tmpl.type = PictTypeDirect;
229342542f5fSchristos
229442542f5fSchristos	if (tmpl.direct.alphaMask) {
229542542f5fSchristos		tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
229642542f5fSchristos		tmpl.direct.alpha = (PIXMAN_FORMAT_B(format) +
229742542f5fSchristos				     PIXMAN_FORMAT_G(format) +
229842542f5fSchristos				     PIXMAN_FORMAT_R(format));
229942542f5fSchristos	}
230042542f5fSchristos
230142542f5fSchristos	tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
230242542f5fSchristos	tmpl.direct.blue = (PIXMAN_FORMAT_G(format) +
230342542f5fSchristos			    PIXMAN_FORMAT_R(format));
230442542f5fSchristos
230542542f5fSchristos	tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
230642542f5fSchristos	tmpl.direct.green = PIXMAN_FORMAT_R(format);
230742542f5fSchristos
230842542f5fSchristos	tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
230942542f5fSchristos	tmpl.direct.red = 0;
231042542f5fSchristos
231142542f5fSchristos	mask |= PictFormatRed | PictFormatRedMask;
231242542f5fSchristos	mask |= PictFormatGreen | PictFormatGreenMask;
231342542f5fSchristos	mask |= PictFormatBlue | PictFormatBlueMask;
231442542f5fSchristos	mask |= PictFormatAlpha | PictFormatAlphaMask;
231542542f5fSchristos	break;
231642542f5fSchristos
231742542f5fSchristos    case PIXMAN_TYPE_BGRA:
231842542f5fSchristos	tmpl.type = PictTypeDirect;
231942542f5fSchristos
232042542f5fSchristos	tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
232142542f5fSchristos	tmpl.direct.blue = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format));
232242542f5fSchristos
232342542f5fSchristos	tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
232442542f5fSchristos	tmpl.direct.green = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) -
232542542f5fSchristos			     PIXMAN_FORMAT_G(format));
232642542f5fSchristos
232742542f5fSchristos	tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
232842542f5fSchristos	tmpl.direct.red = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) -
232942542f5fSchristos			   PIXMAN_FORMAT_G(format) - PIXMAN_FORMAT_R(format));
233042542f5fSchristos
233142542f5fSchristos	if (tmpl.direct.alphaMask) {
233242542f5fSchristos		tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
233342542f5fSchristos		tmpl.direct.alpha = 0;
233442542f5fSchristos	}
233542542f5fSchristos
233642542f5fSchristos	mask |= PictFormatRed | PictFormatRedMask;
233742542f5fSchristos	mask |= PictFormatGreen | PictFormatGreenMask;
233842542f5fSchristos	mask |= PictFormatBlue | PictFormatBlueMask;
233942542f5fSchristos	mask |= PictFormatAlpha | PictFormatAlphaMask;
234042542f5fSchristos	break;
234142542f5fSchristos
234242542f5fSchristos    case PIXMAN_TYPE_A:
234342542f5fSchristos	tmpl.type = PictTypeDirect;
234442542f5fSchristos
234542542f5fSchristos	tmpl.direct.alpha = 0;
234642542f5fSchristos	tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
234742542f5fSchristos
234842542f5fSchristos	mask |= PictFormatAlpha | PictFormatAlphaMask;
234942542f5fSchristos	break;
235042542f5fSchristos
235142542f5fSchristos    case PIXMAN_TYPE_COLOR:
235242542f5fSchristos    case PIXMAN_TYPE_GRAY:
235342542f5fSchristos	/* XXX Find matching visual/colormap */
235442542f5fSchristos	tmpl.type = PictTypeIndexed;
235542542f5fSchristos	//tmpl.colormap = screen->visuals[PIXMAN_FORMAT_VIS(format)].vid;
235642542f5fSchristos	//mask |= PictFormatColormap;
235742542f5fSchristos	return NULL;
235842542f5fSchristos    }
235942542f5fSchristos#undef MASK
236042542f5fSchristos
236142542f5fSchristos    return XRenderFindFormat(dpy, mask, &tmpl, 0);
236242542f5fSchristos}
236342542f5fSchristos
236442542f5fSchristosstatic int display_init_render(struct display *display, int depth, XRenderPictFormat **use_render)
236542542f5fSchristos{
236642542f5fSchristos	Display *dpy = display->dpy;
236742542f5fSchristos	int major, minor;
236842542f5fSchristos
236942542f5fSchristos	DBG(X11, ("%s is depth %d, want %d\n", DisplayString(dpy), display->depth, depth));
237042542f5fSchristos
237142542f5fSchristos	*use_render = 0;
237242542f5fSchristos	if (depth == display->depth && !bad_visual(display->visual, depth))
237342542f5fSchristos		return 0;
237442542f5fSchristos
237542542f5fSchristos	if (display->root_format == 0) {
237642542f5fSchristos		if (!XRenderQueryVersion(dpy, &major, &minor)) {
237742542f5fSchristos			fprintf(stderr, "Render extension not supported by %s\n", DisplayString(dpy));
237842542f5fSchristos			return -EINVAL;
237942542f5fSchristos		}
238042542f5fSchristos
238142542f5fSchristos		display->root_format = XRenderFindVisualFormat(dpy, display->visual);
238242542f5fSchristos		display->rgb16_format = find_xrender_format(dpy, PIXMAN_r5g6b5);
238342542f5fSchristos		display->rgb24_format = XRenderFindStandardFormat(dpy, PictStandardRGB24);
238442542f5fSchristos
238542542f5fSchristos		DBG(X11, ("%s: root format=%lx, rgb16 format=%lx, rgb24 format=%lx\n",
238642542f5fSchristos		     DisplayString(dpy),
238742542f5fSchristos		     (long)display->root_format,
238842542f5fSchristos		     (long)display->rgb16_format,
238942542f5fSchristos		     (long)display->rgb24_format));
239042542f5fSchristos	}
239142542f5fSchristos
239242542f5fSchristos	switch (depth) {
239342542f5fSchristos	case 16: *use_render = display->rgb16_format; break;
239442542f5fSchristos	case 24: *use_render = display->rgb24_format; break;
239542542f5fSchristos	}
239642542f5fSchristos	if (*use_render == 0)
239742542f5fSchristos		return -ENOENT;
239842542f5fSchristos
239942542f5fSchristos	return 0;
240042542f5fSchristos}
240142542f5fSchristos
240242542f5fSchristosstatic int clone_init_depth(struct clone *clone)
240342542f5fSchristos{
240442542f5fSchristos	int ret, depth;
240542542f5fSchristos
240642542f5fSchristos	DBG(X11,("%s-%s wants depth %d\n",
240742542f5fSchristos	     DisplayString(clone->dst.dpy), clone->dst.name, clone->depth));
240842542f5fSchristos
240942542f5fSchristos	ret = -1;
241042542f5fSchristos	for (depth = clone->depth; depth <= 24; depth += 8) {
241142542f5fSchristos		ret = display_init_render(clone->src.display, depth, &clone->src.use_render);
241242542f5fSchristos		if (ret)
241342542f5fSchristos			continue;
241442542f5fSchristos
241542542f5fSchristos		ret = display_init_render(clone->dst.display, depth, &clone->dst.use_render);
241642542f5fSchristos		if (ret)
241742542f5fSchristos			continue;
241842542f5fSchristos
241942542f5fSchristos		break;
242042542f5fSchristos	}
242142542f5fSchristos	if (ret)
242242542f5fSchristos		return ret;
242342542f5fSchristos
2424fe8aea9eSmrg	clone->depth = depth;
2425fe8aea9eSmrg
242642542f5fSchristos	DBG(X11, ("%s-%s using depth %d, requires xrender for src? %d, for dst? %d\n",
242742542f5fSchristos	     DisplayString(clone->dst.dpy), clone->dst.name,
242842542f5fSchristos	     clone->depth,
242942542f5fSchristos	     clone->src.use_render != NULL,
243042542f5fSchristos	     clone->dst.use_render != NULL));
243142542f5fSchristos
243242542f5fSchristos	if (!clone->dst.use_render &&
243342542f5fSchristos	    clone->src.display->dri3_active &&
243442542f5fSchristos	    clone->dst.display->dri3_active)
243542542f5fSchristos		dri3_create_fence(clone->src.dpy, clone->src.window, &clone->dri3);
243642542f5fSchristos
243742542f5fSchristos	return 0;
243842542f5fSchristos}
243942542f5fSchristos
244042542f5fSchristos#if defined(USE_XINERAMA)
244142542f5fSchristosstatic int xinerama_active(struct display *display)
244242542f5fSchristos{
244342542f5fSchristos	int active = 0;
244442542f5fSchristos	if (XineramaQueryExtension(display->dpy, &display->xinerama_event, &display->xinerama_error))
244542542f5fSchristos		active = XineramaIsActive(display->dpy);
244642542f5fSchristos	return active;
244742542f5fSchristos}
244842542f5fSchristos#else
244942542f5fSchristos#define xinerama_active(d) 0
245042542f5fSchristos#endif
245142542f5fSchristos
245242542f5fSchristosstatic int add_display(struct context *ctx, Display *dpy)
245342542f5fSchristos{
245442542f5fSchristos	struct display *display;
245542542f5fSchristos	int first_display = ctx->ndisplay == 0;
245642542f5fSchristos
245742542f5fSchristos	if (is_power_of_2(ctx->ndisplay)) {
245842542f5fSchristos		struct display *new_display;
245942542f5fSchristos
246042542f5fSchristos		new_display = realloc(ctx->display, 2*ctx->ndisplay*sizeof(struct display));
246142542f5fSchristos		if (new_display == NULL)
246242542f5fSchristos			return -ENOMEM;
246342542f5fSchristos
246442542f5fSchristos		if (new_display != ctx->display) {
246542542f5fSchristos			int n;
246642542f5fSchristos
246742542f5fSchristos			for (n = 0; n < ctx->nclone; n++) {
246842542f5fSchristos				struct clone *clone = &ctx->clones[n];
246942542f5fSchristos				clone->src.display = new_display + (clone->src.display - ctx->display);
247042542f5fSchristos				clone->dst.display = new_display + (clone->dst.display - ctx->display);
247142542f5fSchristos			}
247242542f5fSchristos		}
247342542f5fSchristos
247442542f5fSchristos		ctx->display = new_display;
247542542f5fSchristos	}
247642542f5fSchristos
247742542f5fSchristos	display = memset(&ctx->display[ctx->ndisplay++], 0, sizeof(struct display));
247842542f5fSchristos
247942542f5fSchristos	display->dpy = dpy;
248042542f5fSchristos	display->ctx = ctx;
248142542f5fSchristos
248242542f5fSchristos	display->root = DefaultRootWindow(dpy);
248342542f5fSchristos	display->depth = DefaultDepth(dpy, DefaultScreen(dpy));
248442542f5fSchristos	display->visual = DefaultVisual(dpy, DefaultScreen(dpy));
248542542f5fSchristos
2486fe8aea9eSmrg	XSelectInput(dpy, display->root, ExposureMask);
2487fe8aea9eSmrg
248842542f5fSchristos	display->has_shm = can_use_shm(dpy, display->root,
248942542f5fSchristos				       &display->shm_event,
249042542f5fSchristos				       &display->shm_opcode,
249142542f5fSchristos				       &display->has_shm_pixmap);
249242542f5fSchristos	DBG(X11, ("%s: has_shm?=%d, event=%d, opcode=%d, has_pixmap?=%d\n",
249342542f5fSchristos	     DisplayString(dpy),
249442542f5fSchristos	     display->has_shm,
249542542f5fSchristos	     display->shm_event,
249642542f5fSchristos	     display->shm_opcode,
249742542f5fSchristos	     display->has_shm_pixmap));
249842542f5fSchristos
2499fe8aea9eSmrg	screensaver_save(display);
2500fe8aea9eSmrg
250142542f5fSchristos	display->rr_active = XRRQueryExtension(dpy, &display->rr_event, &display->rr_error);
250242542f5fSchristos	DBG(X11, ("%s: randr_active?=%d, event=%d, error=%d\n",
250342542f5fSchristos	     DisplayString(dpy),
250442542f5fSchristos	     display->rr_active,
250542542f5fSchristos	     display->rr_event,
250642542f5fSchristos	     display->rr_error));
250742542f5fSchristos
250842542f5fSchristos	display->xinerama_active = xinerama_active(display);
250942542f5fSchristos	DBG(X11, ("%s: xinerama_active?=%d, event=%d, error=%d\n",
251042542f5fSchristos	     DisplayString(dpy),
251142542f5fSchristos	     display->xinerama_active,
251242542f5fSchristos	     display->xinerama_event,
251342542f5fSchristos	     display->xinerama_error));
251442542f5fSchristos
251542542f5fSchristos	display->dri3_active = dri3_exists(dpy);
251642542f5fSchristos	DBG(X11, ("%s: dri3_active?=%d\n",
251742542f5fSchristos	     DisplayString(dpy),
251842542f5fSchristos	     display->dri3_active));
251942542f5fSchristos
252042542f5fSchristos	/* first display (source) is slightly special */
252142542f5fSchristos	if (!first_display) {
252242542f5fSchristos		display->invisible_cursor = display_load_invisible_cursor(display);
252342542f5fSchristos		display_cursor_move(display, 0, 0, 0);
252442542f5fSchristos	}
252542542f5fSchristos
252642542f5fSchristos	return ConnectionNumber(dpy);
252742542f5fSchristos}
252842542f5fSchristos
252942542f5fSchristosstatic int display_open(struct context *ctx, const char *name)
253042542f5fSchristos{
253142542f5fSchristos	Display *dpy;
253242542f5fSchristos	int n;
253342542f5fSchristos
253442542f5fSchristos	DBG(X11, ("%s(%s)\n", __func__, name));
253542542f5fSchristos
253642542f5fSchristos	dpy = XOpenDisplay(name);
253742542f5fSchristos	if (dpy == NULL)
253842542f5fSchristos		return -ECONNREFUSED;
253942542f5fSchristos
254042542f5fSchristos	/* Prevent cloning the same display twice */
254142542f5fSchristos	for (n = 0; n < ctx->ndisplay; n++) {
254242542f5fSchristos		if (strcmp(DisplayString(dpy), DisplayString(ctx->display[n].dpy)) == 0) {
254342542f5fSchristos			DBG(X11, ("%s %s is already connected\n", __func__, name));
254442542f5fSchristos			XCloseDisplay(dpy);
254542542f5fSchristos			return -EBUSY;
254642542f5fSchristos		}
254742542f5fSchristos	}
254842542f5fSchristos
254942542f5fSchristos	return add_display(ctx, dpy);
255042542f5fSchristos}
255142542f5fSchristos
255242542f5fSchristosstatic int bumblebee_open(struct context *ctx)
255342542f5fSchristos{
255442542f5fSchristos	char buf[256];
255542542f5fSchristos	struct sockaddr_un addr;
255642542f5fSchristos	int fd, len;
255742542f5fSchristos
255842542f5fSchristos	fd = socket(PF_UNIX, SOCK_STREAM, 0);
255942542f5fSchristos	if (fd < 0) {
256042542f5fSchristos		DBG(X11, ("%s unable to create a socket: %d\n", __func__, errno));
256142542f5fSchristos		return -ECONNREFUSED;
256242542f5fSchristos	}
256342542f5fSchristos
256442542f5fSchristos	addr.sun_family = AF_UNIX;
256542542f5fSchristos	snprintf(addr.sun_path, sizeof(addr.sun_path), "%s",
256642542f5fSchristos		 optarg && *optarg ? optarg : "/var/run/bumblebee.socket");
256742542f5fSchristos	if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
256842542f5fSchristos		DBG(X11, ("%s unable to create a socket: %d\n", __func__, errno));
256942542f5fSchristos		goto err;
257042542f5fSchristos	}
257142542f5fSchristos
257242542f5fSchristos	/* Ask bumblebee to start the second server */
257342542f5fSchristos	buf[0] = 'C';
257442542f5fSchristos	if (send(fd, &buf, 1, 0) != 1 || (len = recv(fd, &buf, 255, 0)) <= 0) {
257542542f5fSchristos		DBG(X11, ("%s startup send/recv failed: %d\n", __func__, errno));
257642542f5fSchristos		goto err;
257742542f5fSchristos	}
257842542f5fSchristos	buf[len] = '\0';
257942542f5fSchristos
258042542f5fSchristos	/* Query the display name */
258142542f5fSchristos	strcpy(buf, "Q VirtualDisplay");
258242542f5fSchristos	if (send(fd, buf, 17, 0) != 17 || (len = recv(fd, buf, 255, 0)) <= 0) {
258342542f5fSchristos		DBG(X11, ("%s query send/recv failed: %d\n", __func__, errno));
258442542f5fSchristos		goto err;
258542542f5fSchristos	}
258642542f5fSchristos	buf[len] = '\0';
258742542f5fSchristos
258842542f5fSchristos	DBG(X11, ("%s query result '%s'\n", __func__, buf));
258942542f5fSchristos
259042542f5fSchristos	if (strncmp(buf, "Value: ", 7))
259142542f5fSchristos		goto err;
259242542f5fSchristos
259342542f5fSchristos	len = 7;
259442542f5fSchristos	while (buf[len] != '\n' && buf[len] != '\0')
259542542f5fSchristos		len++;
259642542f5fSchristos	buf[len] = '\0';
259742542f5fSchristos
259842542f5fSchristos	/* XXX We must keep the control socket open whilst we want to keep
259942542f5fSchristos	 * the display around.
260042542f5fSchristos	 *
260142542f5fSchristos	 * So what we need to do is listen for new bumblee Xservers and
260242542f5fSchristos	 * bind only for their duration.
260342542f5fSchristos	 */
260442542f5fSchristos
260542542f5fSchristos	return display_open(ctx, buf+7);
260642542f5fSchristos
260742542f5fSchristoserr:
260842542f5fSchristos	close(fd);
260942542f5fSchristos	return -ECONNREFUSED;
261042542f5fSchristos}
261142542f5fSchristos
261242542f5fSchristosstatic int display_init_damage(struct display *display)
261342542f5fSchristos{
261442542f5fSchristos	DBG(X11, ("%s(%s)\n", __func__, DisplayString(display->dpy)));
261542542f5fSchristos
261642542f5fSchristos	if (!XDamageQueryExtension(display->dpy, &display->damage_event, &display->damage_error) ||
261742542f5fSchristos	    !XFixesQueryExtension(display->dpy, &display->xfixes_event, &display->xfixes_error)) {
261842542f5fSchristos		fprintf(stderr, "Damage/Fixes extension not supported by %s\n", DisplayString(display->dpy));
261942542f5fSchristos		return EINVAL;
262042542f5fSchristos	}
262142542f5fSchristos
262242542f5fSchristos	display->damage = XDamageCreate(display->dpy, display->root, XDamageReportBoundingBox);
262342542f5fSchristos	if (display->damage == 0)
262442542f5fSchristos		return EACCES;
262542542f5fSchristos
262642542f5fSchristos	return 0;
262742542f5fSchristos}
262842542f5fSchristos
262942542f5fSchristosstatic void display_reset_damage(struct display *display)
263042542f5fSchristos{
263142542f5fSchristos	Damage damage;
263242542f5fSchristos
263342542f5fSchristos	damage = XDamageCreate(display->dpy, display->root, XDamageReportBoundingBox);
263442542f5fSchristos	if (damage) {
263542542f5fSchristos		XDamageDestroy(display->dpy, display->damage);
263642542f5fSchristos		display->damage = damage;
263742542f5fSchristos		XFlush(display->dpy);
263842542f5fSchristos		display->flush = 0;
263942542f5fSchristos	}
264042542f5fSchristos}
264142542f5fSchristos
264242542f5fSchristosstatic void display_init_randr_hpd(struct display *display)
264342542f5fSchristos{
264442542f5fSchristos	int major, minor;
264542542f5fSchristos
264642542f5fSchristos	DBG(X11,("%s(%s)\n", __func__, DisplayString(display->dpy)));
264742542f5fSchristos
264842542f5fSchristos	if (!XRRQueryVersion(display->dpy, &major, &minor))
264942542f5fSchristos		return;
265042542f5fSchristos
265142542f5fSchristos	DBG(X11, ("%s - randr version %d.%d\n", DisplayString(display->dpy), major, minor));
265242542f5fSchristos	if (major > 1 || (major == 1 && minor >= 2))
265342542f5fSchristos		XRRSelectInput(display->dpy, display->root, RROutputChangeNotifyMask);
265442542f5fSchristos}
265542542f5fSchristos
265642542f5fSchristosstatic void rebuild_clones(struct context *ctx, struct clone *new_clones)
265742542f5fSchristos{
265842542f5fSchristos	int n, m;
265942542f5fSchristos
266042542f5fSchristos	for (n = 1; n < ctx->ndisplay; n++) {
266142542f5fSchristos		struct display *d = &ctx->display[n];
266242542f5fSchristos
266342542f5fSchristos		d->clone = NULL;
266442542f5fSchristos		for (m = 0; m < ctx->nclone; m++) {
266542542f5fSchristos			struct clone *c = &new_clones[m];
266642542f5fSchristos
266742542f5fSchristos			if (c->dst.display != d)
266842542f5fSchristos				continue;
266942542f5fSchristos
267042542f5fSchristos			c->next = d->clone;
267142542f5fSchristos			d->clone = c;
267242542f5fSchristos		}
267342542f5fSchristos	}
267442542f5fSchristos
267542542f5fSchristos	ctx->clones = new_clones;
267642542f5fSchristos}
267742542f5fSchristos
267842542f5fSchristosstatic struct clone *add_clone(struct context *ctx)
267942542f5fSchristos{
268042542f5fSchristos	if (is_power_of_2(ctx->nclone)) {
268142542f5fSchristos		struct clone *new_clones;
268242542f5fSchristos
268342542f5fSchristos		new_clones = realloc(ctx->clones, 2*ctx->nclone*sizeof(struct clone));
268442542f5fSchristos		if (new_clones == NULL)
268542542f5fSchristos			return NULL;
268642542f5fSchristos
268742542f5fSchristos		if (new_clones != ctx->clones)
268842542f5fSchristos			rebuild_clones(ctx, new_clones);
268942542f5fSchristos	}
269042542f5fSchristos
269142542f5fSchristos	return memset(&ctx->clones[ctx->nclone++], 0, sizeof(struct clone));
269242542f5fSchristos}
269342542f5fSchristos
269442542f5fSchristosstatic struct display *last_display(struct context *ctx)
269542542f5fSchristos{
269642542f5fSchristos	return &ctx->display[ctx->ndisplay-1];
269742542f5fSchristos}
269842542f5fSchristos
269942542f5fSchristosstatic void reverse_clone_list(struct display *display)
270042542f5fSchristos{
270142542f5fSchristos	struct clone *list = NULL;
270242542f5fSchristos
270342542f5fSchristos	while (display->clone) {
270442542f5fSchristos		struct clone *clone = display->clone;
270542542f5fSchristos		display->clone = clone->next;
270642542f5fSchristos		clone->next = list;
270742542f5fSchristos		list = clone;
270842542f5fSchristos	}
270942542f5fSchristos
271042542f5fSchristos	display->clone = list;
271142542f5fSchristos}
271242542f5fSchristos
271342542f5fSchristosstatic int last_display_add_clones__randr(struct context *ctx)
271442542f5fSchristos{
271542542f5fSchristos	struct display *display = last_display(ctx);
271642542f5fSchristos	XRRScreenResources *res;
271742542f5fSchristos	char buf[80];
271842542f5fSchristos	int i, ret;
271942542f5fSchristos
272042542f5fSchristos	DBG(X11, ("%s(%s)\n", __func__, DisplayString(display->dpy)));
272142542f5fSchristos
272242542f5fSchristos	display_init_randr_hpd(display);
272342542f5fSchristos
272442542f5fSchristos	/* Force a probe of outputs on initial connection */
272542542f5fSchristos	res = XRRGetScreenResources(display->dpy, display->root);
272642542f5fSchristos	if (res == NULL)
272742542f5fSchristos		return -ENOMEM;
272842542f5fSchristos
272942542f5fSchristos	DBG(X11, ("%s - noutputs=%d\n", DisplayString(display->dpy), res->noutput));
273042542f5fSchristos	for (i = 0; i < res->noutput; i++) {
273142542f5fSchristos		XRROutputInfo *o = XRRGetOutputInfo(display->dpy, res, res->outputs[i]);
273242542f5fSchristos		struct clone *clone = add_clone(ctx);
273342542f5fSchristos		RROutput id;
273442542f5fSchristos
273542542f5fSchristos		if (clone == NULL)
273642542f5fSchristos			return -ENOMEM;
273742542f5fSchristos
273842542f5fSchristos		clone->depth = 24;
273942542f5fSchristos		clone->next = display->clone;
274042542f5fSchristos		display->clone = clone;
274142542f5fSchristos
274242542f5fSchristos		id = claim_virtual(ctx->display, buf, ctx->nclone);
274342542f5fSchristos		if (id == 0) {
274442542f5fSchristos			fprintf(stderr, "Failed to find available VirtualHead \"%s\" for \"%s\" on display \"%s\"\n",
274542542f5fSchristos				buf, o->name, DisplayString(display->dpy));
274642542f5fSchristos			return -ENOSPC;
274742542f5fSchristos		}
274842542f5fSchristos
274942542f5fSchristos		ret = clone_output_init(clone, &clone->src, ctx->display, buf, id);
275042542f5fSchristos		if (ret) {
275142542f5fSchristos			fprintf(stderr, "Failed to add output \"%s\" on display \"%s\"\n",
275242542f5fSchristos				buf, DisplayString(ctx->display->dpy));
275342542f5fSchristos			return ret;
275442542f5fSchristos		}
275542542f5fSchristos
275642542f5fSchristos		ret = clone_output_init(clone, &clone->dst, display, o->name, res->outputs[i]);
275742542f5fSchristos		if (ret) {
275842542f5fSchristos			fprintf(stderr, "Failed to add output \"%s\" on display \"%s\"\n",
275942542f5fSchristos				o->name, DisplayString(display->dpy));
276042542f5fSchristos			return ret;
276142542f5fSchristos		}
276242542f5fSchristos
276342542f5fSchristos		ret = clone_init_depth(clone);
276442542f5fSchristos		if (ret) {
276542542f5fSchristos			fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n",
276642542f5fSchristos				DisplayString(display->dpy));
276742542f5fSchristos			return ret;
276842542f5fSchristos		}
276942542f5fSchristos
2770fe8aea9eSmrg		clone->dst.x = 0;
2771fe8aea9eSmrg		clone->dst.y = 0;
2772fe8aea9eSmrg		clone->dst.width = display->width;
2773fe8aea9eSmrg		clone->dst.height = display->height;
2774fe8aea9eSmrg
277542542f5fSchristos		ret = clone_update_modes__randr(clone);
277642542f5fSchristos		if (ret) {
277742542f5fSchristos			fprintf(stderr, "Failed to clone output \"%s\" from display \"%s\"\n",
277842542f5fSchristos				o->name, DisplayString(display->dpy));
277942542f5fSchristos			return ret;
278042542f5fSchristos		}
278142542f5fSchristos
278242542f5fSchristos
278342542f5fSchristos		if (o->crtc) {
278442542f5fSchristos			DBG(X11, ("%s - disabling active output\n", DisplayString(display->dpy)));
278542542f5fSchristos			disable_crtc(display->dpy, res, o->crtc);
278642542f5fSchristos		}
278742542f5fSchristos
278842542f5fSchristos		XRRFreeOutputInfo(o);
278942542f5fSchristos	}
279042542f5fSchristos	XRRFreeScreenResources(res);
279142542f5fSchristos
279242542f5fSchristos	reverse_clone_list(display);
279342542f5fSchristos	return 0;
279442542f5fSchristos}
279542542f5fSchristos
279642542f5fSchristos#if defined(USE_XINERAMA)
279742542f5fSchristosstatic int last_display_add_clones__xinerama(struct context *ctx)
279842542f5fSchristos{
279942542f5fSchristos	struct display *display = last_display(ctx);
280042542f5fSchristos	Display *dpy = display->dpy;
280142542f5fSchristos	XineramaScreenInfo *xi;
280242542f5fSchristos	char buf[80];
280342542f5fSchristos	int n, count, ret;
280442542f5fSchristos
280542542f5fSchristos	DBG(X11, ("%s(%s)\n", __func__, DisplayString(display->dpy)));
280642542f5fSchristos
280742542f5fSchristos	count = 0;
280842542f5fSchristos	xi = XineramaQueryScreens(dpy, &count);
280942542f5fSchristos	for (n = 0; n < count; n++) {
281042542f5fSchristos		struct clone *clone = add_clone(ctx);
281142542f5fSchristos		RROutput id;
281242542f5fSchristos
281342542f5fSchristos		if (clone == NULL)
281442542f5fSchristos			return -ENOMEM;
281542542f5fSchristos
281642542f5fSchristos		if (xi[n].width == 0 || xi[n].height == 0)
281742542f5fSchristos			continue;
281842542f5fSchristos
281942542f5fSchristos		clone->depth = 24;
282042542f5fSchristos		clone->next = display->clone;
282142542f5fSchristos		display->clone = clone;
282242542f5fSchristos
282342542f5fSchristos		id = claim_virtual(ctx->display, buf, ctx->nclone);
282442542f5fSchristos		if (id == 0) {
282542542f5fSchristos			fprintf(stderr, "Failed to find available VirtualHead \"%s\" for Xinerama screen %d on display \"%s\"\n",
282642542f5fSchristos				buf, n, DisplayString(dpy));
282742542f5fSchristos		}
282842542f5fSchristos		ret = clone_output_init(clone, &clone->src, ctx->display, buf, id);
282942542f5fSchristos		if (ret) {
283042542f5fSchristos			fprintf(stderr, "Failed to add Xinerama screen %d on display \"%s\"\n",
283142542f5fSchristos				n, DisplayString(ctx->display->dpy));
283242542f5fSchristos			return ret;
283342542f5fSchristos		}
283442542f5fSchristos
283542542f5fSchristos		sprintf(buf, "XINERAMA%d", n);
283642542f5fSchristos		ret = clone_output_init(clone, &clone->dst, display, buf, 0);
283742542f5fSchristos		if (ret) {
283842542f5fSchristos			fprintf(stderr, "Failed to add Xinerama screen %d on display \"%s\"\n",
283942542f5fSchristos				n, DisplayString(dpy));
284042542f5fSchristos			return ret;
284142542f5fSchristos		}
284242542f5fSchristos
284342542f5fSchristos		ret = clone_init_depth(clone);
284442542f5fSchristos		if (ret) {
284542542f5fSchristos			fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n",
284642542f5fSchristos				DisplayString(display->dpy));
284742542f5fSchristos			return ret;
284842542f5fSchristos		}
284942542f5fSchristos
285042542f5fSchristos		/* Replace the modes on the local VIRTUAL output with the remote Screen */
2851fe8aea9eSmrg		clone->dst.width = xi[n].width;
2852fe8aea9eSmrg		clone->dst.height = xi[n].height;
285342542f5fSchristos		clone->dst.x = xi[n].x_org;
285442542f5fSchristos		clone->dst.y = xi[n].y_org;
285542542f5fSchristos		clone->dst.rr_crtc = -1;
285642542f5fSchristos		ret = clone_update_modes__fixed(clone);
285742542f5fSchristos		if (ret) {
285842542f5fSchristos			fprintf(stderr, "Failed to clone Xinerama screen %d from display \"%s\"\n",
285942542f5fSchristos				n, DisplayString(display->dpy));
286042542f5fSchristos			return ret;
286142542f5fSchristos		}
286242542f5fSchristos
286342542f5fSchristos		clone->active = ctx->active;
286442542f5fSchristos		ctx->active = clone;
286542542f5fSchristos	}
286642542f5fSchristos	XFree(xi);
286742542f5fSchristos
286842542f5fSchristos	reverse_clone_list(display);
286942542f5fSchristos	return 0;
287042542f5fSchristos}
287142542f5fSchristos#else
287242542f5fSchristos#define last_display_add_clones__xinerama(ctx) -1
287342542f5fSchristos#endif
287442542f5fSchristos
287542542f5fSchristosstatic int last_display_add_clones__display(struct context *ctx)
287642542f5fSchristos{
287742542f5fSchristos	struct display *display = last_display(ctx);
287842542f5fSchristos	Display *dpy = display->dpy;
287942542f5fSchristos	struct clone *clone;
288042542f5fSchristos	Screen *scr;
2881fe8aea9eSmrg	int count, s;
288242542f5fSchristos	char buf[80];
288342542f5fSchristos	int ret;
288442542f5fSchristos	RROutput id;
288542542f5fSchristos
2886fe8aea9eSmrg	count = ScreenCount(dpy);
2887fe8aea9eSmrg	DBG(X11, ("%s(%s) - %d screens\n", __func__, DisplayString(dpy), count));
2888fe8aea9eSmrg	for (s = 0; s < count; s++) {
2889fe8aea9eSmrg		clone = add_clone(ctx);
2890fe8aea9eSmrg		if (clone == NULL)
2891fe8aea9eSmrg			return -ENOMEM;
289242542f5fSchristos
2893fe8aea9eSmrg		clone->depth = 24;
2894fe8aea9eSmrg		clone->next = display->clone;
2895fe8aea9eSmrg		display->clone = clone;
289642542f5fSchristos
2897fe8aea9eSmrg		id = claim_virtual(ctx->display, buf, ctx->nclone);
2898fe8aea9eSmrg		if (id == 0) {
2899fe8aea9eSmrg			fprintf(stderr, "Failed to find available VirtualHead \"%s\" for on display \"%s\"\n",
2900fe8aea9eSmrg				buf, DisplayString(dpy));
2901fe8aea9eSmrg		}
2902fe8aea9eSmrg		ret = clone_output_init(clone, &clone->src, ctx->display, buf, id);
2903fe8aea9eSmrg		if (ret) {
2904fe8aea9eSmrg			fprintf(stderr, "Failed to add display \"%s\"\n",
2905fe8aea9eSmrg				DisplayString(ctx->display->dpy));
2906fe8aea9eSmrg			return ret;
2907fe8aea9eSmrg		}
290842542f5fSchristos
2909fe8aea9eSmrg		sprintf(buf, "SCREEN%d", s);
2910fe8aea9eSmrg		ret = clone_output_init(clone, &clone->dst, display, buf, 0);
2911fe8aea9eSmrg		if (ret) {
2912fe8aea9eSmrg			fprintf(stderr, "Failed to add display \"%s\"\n",
2913fe8aea9eSmrg				DisplayString(dpy));
2914fe8aea9eSmrg			return ret;
2915fe8aea9eSmrg		}
291642542f5fSchristos
2917fe8aea9eSmrg		ret = clone_init_depth(clone);
2918fe8aea9eSmrg		if (ret) {
2919fe8aea9eSmrg			fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n",
2920fe8aea9eSmrg				DisplayString(dpy));
2921fe8aea9eSmrg			return ret;
2922fe8aea9eSmrg		}
292342542f5fSchristos
2924fe8aea9eSmrg		/* Replace the modes on the local VIRTUAL output with the remote Screen */
2925fe8aea9eSmrg		scr = ScreenOfDisplay(dpy, s);
2926fe8aea9eSmrg		clone->dst.width = scr->width;
2927fe8aea9eSmrg		clone->dst.height = scr->height;
2928fe8aea9eSmrg		clone->dst.x = 0;
2929fe8aea9eSmrg		clone->dst.y = 0;
2930fe8aea9eSmrg		clone->dst.rr_crtc = -1;
2931fe8aea9eSmrg		ret = clone_update_modes__fixed(clone);
2932fe8aea9eSmrg		if (ret) {
2933fe8aea9eSmrg			fprintf(stderr, "Failed to clone display \"%s\"\n",
2934fe8aea9eSmrg				DisplayString(dpy));
2935fe8aea9eSmrg			return ret;
2936fe8aea9eSmrg		}
293742542f5fSchristos
2938fe8aea9eSmrg		clone->active = ctx->active;
2939fe8aea9eSmrg		ctx->active = clone;
294042542f5fSchristos	}
294142542f5fSchristos
294242542f5fSchristos	return 0;
294342542f5fSchristos}
294442542f5fSchristos
294542542f5fSchristosstatic int last_display_add_clones(struct context *ctx)
294642542f5fSchristos{
294742542f5fSchristos	struct display *display = last_display(ctx);
294842542f5fSchristos
294942542f5fSchristos	display->width = DisplayWidth(display->dpy, DefaultScreen(display->dpy));
295042542f5fSchristos	display->height = DisplayHeight(display->dpy, DefaultScreen(display->dpy));
295142542f5fSchristos	DBG(X11, ("%s - initial size %dx%d\n", DisplayString(display->dpy), display->width, display->height));
295242542f5fSchristos
295342542f5fSchristos	if (display->rr_active)
295442542f5fSchristos		return last_display_add_clones__randr(ctx);
295542542f5fSchristos
295642542f5fSchristos	if (display->xinerama_active)
295742542f5fSchristos		return last_display_add_clones__xinerama(ctx);
295842542f5fSchristos
295942542f5fSchristos	return last_display_add_clones__display(ctx);
296042542f5fSchristos}
296142542f5fSchristos
296242542f5fSchristosstatic int last_display_clone(struct context *ctx, int fd)
296342542f5fSchristos{
296442542f5fSchristos	fd = add_fd(ctx, fd);
296542542f5fSchristos	if (fd < 0)
296642542f5fSchristos		return fd;
296742542f5fSchristos
296842542f5fSchristos	fd = last_display_add_clones(ctx);
296942542f5fSchristos	if (fd)
297042542f5fSchristos		return fd;
297142542f5fSchristos
297242542f5fSchristos	return 0;
297342542f5fSchristos}
297442542f5fSchristos
297542542f5fSchristosstatic int first_display_has_singleton(struct context *ctx)
297642542f5fSchristos{
297742542f5fSchristos	struct display *display = ctx->display;
297842542f5fSchristos	unsigned long nitems, bytes;
297942542f5fSchristos	unsigned char *prop;
298042542f5fSchristos	int format;
298142542f5fSchristos	Atom type;
298242542f5fSchristos
298342542f5fSchristos	ctx->singleton = XInternAtom(display->dpy, "intel-virtual-output-singleton", False);
298442542f5fSchristos
298542542f5fSchristos	XGetWindowProperty(display->dpy, display->root, ctx->singleton,
298642542f5fSchristos			   0, 0, 0, AnyPropertyType, &type, &format, &nitems, &bytes, &prop);
298742542f5fSchristos	DBG(X11, ("%s: singleton registered? %d\n", DisplayString(display->dpy), type != None));
298842542f5fSchristos	return type != None;
298942542f5fSchristos}
299042542f5fSchristos
299142542f5fSchristosstatic int first_display_wait_for_ack(struct context *ctx, int timeout, int id)
299242542f5fSchristos{
299342542f5fSchristos	struct display *display = ctx->display;
299442542f5fSchristos	struct pollfd pfd;
299542542f5fSchristos	char expect[6]; /* "1234R\0" */
299642542f5fSchristos
299742542f5fSchristos	sprintf(expect, "%04xR", id);
299842542f5fSchristos	DBG(X11, ("%s: wait for act '%c%c%c%c%c'\n",
299942542f5fSchristos	     DisplayString(display->dpy),
300042542f5fSchristos	     expect[0], expect[1], expect[2], expect[3], expect[4]));
300142542f5fSchristos
300242542f5fSchristos	XFlush(display->dpy);
300342542f5fSchristos
300442542f5fSchristos	pfd.fd = ConnectionNumber(display->dpy);
300542542f5fSchristos	pfd.events = POLLIN;
300642542f5fSchristos	do {
300742542f5fSchristos		if (poll(&pfd, 1, timeout) <= 0)
300842542f5fSchristos			return -ETIME;
300942542f5fSchristos
301042542f5fSchristos		while (XPending(display->dpy)) {
301142542f5fSchristos			XEvent e;
301242542f5fSchristos			XClientMessageEvent *cme;
301342542f5fSchristos
301442542f5fSchristos			XNextEvent(display->dpy, &e);
301542542f5fSchristos			DBG(X11, ("%s: reading event type %d\n", DisplayString(display->dpy), e.type));
301642542f5fSchristos
301742542f5fSchristos			if (e.type != ClientMessage)
301842542f5fSchristos				continue;
301942542f5fSchristos
302042542f5fSchristos			cme = (XClientMessageEvent *)&e;
302142542f5fSchristos			if (cme->message_type != ctx->singleton)
302242542f5fSchristos				continue;
302342542f5fSchristos			if (cme->format != 8)
302442542f5fSchristos				continue;
302542542f5fSchristos
302642542f5fSchristos			DBG(X11, ("%s: client message '%c%c%c%c%c'\n",
302742542f5fSchristos			     DisplayString(display->dpy),
302842542f5fSchristos			     cme->data.b[0],
302942542f5fSchristos			     cme->data.b[1],
303042542f5fSchristos			     cme->data.b[2],
303142542f5fSchristos			     cme->data.b[3],
303242542f5fSchristos			     cme->data.b[4]));
303342542f5fSchristos			if (memcmp(cme->data.b, expect, 5))
303442542f5fSchristos				continue;
303542542f5fSchristos
303642542f5fSchristos			return -atoi(cme->data.b + 5);
303742542f5fSchristos		}
303842542f5fSchristos	} while (1);
303942542f5fSchristos}
304042542f5fSchristos
304142542f5fSchristos#if defined(__GNUC__) && (__GNUC__ > 3)
304242542f5fSchristos__attribute__((format(gnu_printf, 3, 4)))
304342542f5fSchristos#endif
304442542f5fSchristosstatic int first_display_send_command(struct context *ctx, int timeout,
304542542f5fSchristos				      const char *format,
304642542f5fSchristos				      ...)
304742542f5fSchristos{
304842542f5fSchristos	struct display *display = ctx->display;
304942542f5fSchristos	char buf[1024], *b;
305042542f5fSchristos	int len, id;
305142542f5fSchristos	va_list va;
305242542f5fSchristos
305342542f5fSchristos	id = rand() & 0xffff;
305442542f5fSchristos	sprintf(buf, "%04x", id);
305542542f5fSchristos	va_start(va, format);
305642542f5fSchristos	len = vsnprintf(buf+4, sizeof(buf)-4, format, va)+5;
305742542f5fSchristos	va_end(va);
305842542f5fSchristos	assert(len < sizeof(buf));
305942542f5fSchristos
306042542f5fSchristos	DBG(X11, ("%s: send command '%s'\n", DisplayString(display->dpy), buf));
306142542f5fSchristos
306242542f5fSchristos	b = buf;
306342542f5fSchristos	while (len) {
306442542f5fSchristos		XClientMessageEvent msg;
306542542f5fSchristos		int n = len;
306642542f5fSchristos		if (n > sizeof(msg.data.b))
306742542f5fSchristos			n = sizeof(msg.data.b);
306842542f5fSchristos		len -= n;
306942542f5fSchristos
307042542f5fSchristos		msg.type = ClientMessage;
307142542f5fSchristos		msg.serial = 0;
307242542f5fSchristos		msg.message_type = ctx->singleton;
307342542f5fSchristos		msg.format = 8;
307442542f5fSchristos		memcpy(msg.data.b, b, n);
307542542f5fSchristos		b += n;
307642542f5fSchristos
307742542f5fSchristos		XSendEvent(display->dpy, display->root, False, PropertyChangeMask, (XEvent *)&msg);
307842542f5fSchristos	}
307942542f5fSchristos
308042542f5fSchristos	return first_display_wait_for_ack(ctx, timeout, id);
308142542f5fSchristos}
308242542f5fSchristos
308342542f5fSchristosstatic void first_display_reply(struct context *ctx, int result)
308442542f5fSchristos{
308542542f5fSchristos	struct display *display = ctx->display;
308642542f5fSchristos	XClientMessageEvent msg;
308742542f5fSchristos
308842542f5fSchristos	sprintf(msg.data.b, "%c%c%c%cR%d",
308942542f5fSchristos	     ctx->command[0],
309042542f5fSchristos	     ctx->command[1],
309142542f5fSchristos	     ctx->command[2],
309242542f5fSchristos	     ctx->command[3],
309342542f5fSchristos	     -result);
309442542f5fSchristos
309542542f5fSchristos	DBG(X11, ("%s: send reply '%s'\n", DisplayString(display->dpy), msg.data.b));
309642542f5fSchristos
309742542f5fSchristos	msg.type = ClientMessage;
309842542f5fSchristos	msg.serial = 0;
309942542f5fSchristos	msg.message_type = ctx->singleton;
310042542f5fSchristos	msg.format = 8;
310142542f5fSchristos
310242542f5fSchristos	XSendEvent(display->dpy, display->root, False, PropertyChangeMask, (XEvent *)&msg);
310342542f5fSchristos	XFlush(display->dpy);
310442542f5fSchristos}
310542542f5fSchristos
310642542f5fSchristosstatic void first_display_handle_command(struct context *ctx,
310742542f5fSchristos					 const char *msg)
310842542f5fSchristos{
310942542f5fSchristos	int len;
311042542f5fSchristos
311142542f5fSchristos	DBG(X11, ("client message!\n"));
311242542f5fSchristos
311342542f5fSchristos	for (len = 0; len < 20 && msg[len]; len++)
311442542f5fSchristos		;
311542542f5fSchristos
311642542f5fSchristos	if (ctx->command_continuation + len > sizeof(ctx->command)) {
311742542f5fSchristos		ctx->command_continuation = 0;
311842542f5fSchristos		return;
311942542f5fSchristos	}
312042542f5fSchristos
312142542f5fSchristos	memcpy(ctx->command + ctx->command_continuation, msg, len);
312242542f5fSchristos	ctx->command_continuation += len;
312342542f5fSchristos
312442542f5fSchristos	if (len < 20) {
312542542f5fSchristos		ctx->command[ctx->command_continuation] = 0;
312642542f5fSchristos		DBG(X11, ("client command complete! '%s'\n", ctx->command));
312742542f5fSchristos		switch (ctx->command[4]) {
312842542f5fSchristos		case 'B':
312942542f5fSchristos			first_display_reply(ctx, last_display_clone(ctx, bumblebee_open(ctx)));
313042542f5fSchristos			break;
313142542f5fSchristos		case 'C':
313242542f5fSchristos			first_display_reply(ctx, last_display_clone(ctx, display_open(ctx, ctx->command + 5)));
313342542f5fSchristos			break;
313442542f5fSchristos		case 'P':
313542542f5fSchristos			first_display_reply(ctx, 0);
313642542f5fSchristos			break;
313742542f5fSchristos		case 'R':
313842542f5fSchristos			break;
313942542f5fSchristos		}
314042542f5fSchristos		ctx->command_continuation = 0;
314142542f5fSchristos		return;
314242542f5fSchristos	}
314342542f5fSchristos}
314442542f5fSchristos
314542542f5fSchristosstatic int first_display_register_as_singleton(struct context *ctx)
314642542f5fSchristos{
314742542f5fSchristos	struct display *display = ctx->display;
314842542f5fSchristos	struct pollfd pfd;
314942542f5fSchristos
315042542f5fSchristos	XChangeProperty(display->dpy, display->root, ctx->singleton,
315142542f5fSchristos			XA_STRING, 8, PropModeReplace, (unsigned char *)".", 1);
315242542f5fSchristos	XFlush(display->dpy);
315342542f5fSchristos
315442542f5fSchristos	/* And eat the notify (presuming that it is ours!) */
315542542f5fSchristos
315642542f5fSchristos	pfd.fd = ConnectionNumber(display->dpy);
315742542f5fSchristos	pfd.events = POLLIN;
315842542f5fSchristos	do {
315942542f5fSchristos		if (poll(&pfd, 1, 1000) <= 0) {
316042542f5fSchristos			fprintf(stderr, "Failed to register as singleton\n");
316142542f5fSchristos			return EBUSY;
316242542f5fSchristos		}
316342542f5fSchristos
316442542f5fSchristos		while (XPending(display->dpy)) {
316542542f5fSchristos			XEvent e;
316642542f5fSchristos
316742542f5fSchristos			XNextEvent(display->dpy, &e);
316842542f5fSchristos			DBG(X11, ("%s: reading event type %d\n", DisplayString(display->dpy), e.type));
316942542f5fSchristos
317042542f5fSchristos			if (e.type == PropertyNotify &&
317142542f5fSchristos			    ((XPropertyEvent *)&e)->atom == ctx->singleton)
317242542f5fSchristos				return 0;
317342542f5fSchristos		}
317442542f5fSchristos	} while (1);
317542542f5fSchristos}
317642542f5fSchristos
317742542f5fSchristosstatic void display_flush_send(struct display *display)
317842542f5fSchristos{
317942542f5fSchristos	XShmCompletionEvent e;
318042542f5fSchristos
318142542f5fSchristos	if (!display->send)
318242542f5fSchristos		return;
318342542f5fSchristos
318442542f5fSchristos	DBG(X11, ("%s flushing send (serial now %ld) (has shm send? %d)\n",
318542542f5fSchristos	     DisplayString(display->dpy),
318642542f5fSchristos	     (long)NextRequest(display->dpy),
318742542f5fSchristos	     display->shm_event));
318842542f5fSchristos
318942542f5fSchristos	display->send = 0;
319042542f5fSchristos
319142542f5fSchristos	if (display->shm_event == 0) {
319242542f5fSchristos		XSync(display->dpy, False);
319342542f5fSchristos		display->flush = 0;
319442542f5fSchristos		return;
319542542f5fSchristos	}
319642542f5fSchristos
319742542f5fSchristos	memset(&e, 0, sizeof(e));
319842542f5fSchristos	e.type = display->shm_event;
319942542f5fSchristos	e.send_event = 1;
320042542f5fSchristos	e.drawable = display->root;
320142542f5fSchristos	e.major_code = display->shm_opcode;
320242542f5fSchristos	e.minor_code = X_ShmPutImage;
320342542f5fSchristos
320442542f5fSchristos	XSendEvent(display->dpy, display->root, False, 0, (XEvent *)&e);
320542542f5fSchristos	display_mark_flush(display);
320642542f5fSchristos}
320742542f5fSchristos
320842542f5fSchristosstatic void display_sync(struct display *display)
320942542f5fSchristos{
321042542f5fSchristos	if (display->skip_clone == 0)
321142542f5fSchristos		return;
321242542f5fSchristos
321342542f5fSchristos	if (display->skip_frame++ < 2)
321442542f5fSchristos		return;
321542542f5fSchristos
321642542f5fSchristos	DBG(X11, ("%s forcing sync\n", DisplayString(display->dpy)));
321742542f5fSchristos	XSync(display->dpy, False);
321842542f5fSchristos
321942542f5fSchristos	display->flush = 0;
322042542f5fSchristos	display->send = 0;
322142542f5fSchristos
322242542f5fSchristos	/* Event tracking proven unreliable, disable */
322342542f5fSchristos	display->shm_event = 0;
322442542f5fSchristos}
322542542f5fSchristos
322642542f5fSchristosstatic void display_flush(struct display *display)
322742542f5fSchristos{
322842542f5fSchristos	display_flush_cursor(display);
322942542f5fSchristos	display_flush_send(display);
323042542f5fSchristos
323142542f5fSchristos	display_sync(display);
323242542f5fSchristos
323342542f5fSchristos	if (!display->flush)
323442542f5fSchristos		return;
323542542f5fSchristos
323642542f5fSchristos	DBG(X11, ("%s(%s)\n", __func__, DisplayString(display->dpy)));
323742542f5fSchristos
323842542f5fSchristos	XFlush(display->dpy);
323942542f5fSchristos	display->flush = 0;
324042542f5fSchristos}
324142542f5fSchristos
324242542f5fSchristosstatic int first_display_first_sibling(struct context *ctx)
324342542f5fSchristos{
324442542f5fSchristos	const char *str, *colon;
324542542f5fSchristos	int dpy, scr, len;
324642542f5fSchristos
324742542f5fSchristos	str = DisplayString(ctx->display->dpy);
324842542f5fSchristos	colon = strrchr(str, ':');
324942542f5fSchristos	if (colon == NULL)
325042542f5fSchristos		return -1;
325142542f5fSchristos
325242542f5fSchristos	if (sscanf(colon + 1, "%d.%d", &dpy, &scr) == 1)
325342542f5fSchristos		scr = 0;
325442542f5fSchristos
325542542f5fSchristos	len = (colon - str) + 1;
325642542f5fSchristos	memcpy(ctx->command, str, len);
325742542f5fSchristos	len += sprintf(ctx->command + len, "%d.", dpy);
325842542f5fSchristos	ctx->command_continuation = len;
325942542f5fSchristos
326042542f5fSchristos	return scr + 1;
326142542f5fSchristos}
326242542f5fSchristos
326342542f5fSchristosstatic int first_display_sibling(struct context *ctx, int i)
326442542f5fSchristos{
326542542f5fSchristos	if (i < 0)
326642542f5fSchristos		return 0;
326742542f5fSchristos
326842542f5fSchristos	sprintf(ctx->command + ctx->command_continuation, "%d", i);
326942542f5fSchristos	return 1;
327042542f5fSchristos}
327142542f5fSchristos
327242542f5fSchristos#define first_display_for_each_sibling(CTX, i) \
327342542f5fSchristos	for (i = first_display_first_sibling(CTX); first_display_sibling(CTX, i); i++)
327442542f5fSchristos
327542542f5fSchristosstatic void display_cleanup(struct display *display)
327642542f5fSchristos{
327742542f5fSchristos	Display *dpy = display->dpy;
327842542f5fSchristos	XRRScreenResources *res;
327942542f5fSchristos	int n;
328042542f5fSchristos
328142542f5fSchristos	XGrabServer(dpy);
328242542f5fSchristos
328342542f5fSchristos	res = _XRRGetScreenResourcesCurrent(dpy, display->root);
328442542f5fSchristos	if (res != NULL) {
328542542f5fSchristos		for (n = 0; n < res->ncrtc; n++)
328642542f5fSchristos			disable_crtc(display->dpy, res, res->crtcs[n]);
328742542f5fSchristos
328842542f5fSchristos		XRRFreeScreenResources(res);
328942542f5fSchristos	}
329042542f5fSchristos
329142542f5fSchristos	XUngrabServer(dpy);
329242542f5fSchristos}
329342542f5fSchristos
329442542f5fSchristosstatic void context_cleanup(struct context *ctx)
329542542f5fSchristos{
329642542f5fSchristos	Display *dpy = ctx->display->dpy;
329742542f5fSchristos	XRRScreenResources *res;
329842542f5fSchristos	int i, j;
329942542f5fSchristos
330042542f5fSchristos	for (i = 1; i < ctx->ndisplay; i++)
330142542f5fSchristos		display_cleanup(&ctx->display[i]);
330242542f5fSchristos
330313496ba1Ssnj	if (dpy == NULL)
330413496ba1Ssnj		return;
330513496ba1Ssnj
330642542f5fSchristos	res = _XRRGetScreenResourcesCurrent(dpy, ctx->display->root);
330742542f5fSchristos	if (res == NULL)
330842542f5fSchristos		return;
330942542f5fSchristos
331042542f5fSchristos	XGrabServer(dpy);
331142542f5fSchristos
331242542f5fSchristos	for (i = 0; i < ctx->nclone; i++) {
331342542f5fSchristos		struct clone *clone = &ctx->clones[i];
331442542f5fSchristos		XRROutputInfo *output;
331542542f5fSchristos
331642542f5fSchristos		assert(clone->src.display == ctx->display);
331742542f5fSchristos
331842542f5fSchristos		output = XRRGetOutputInfo(dpy, res, clone->src.rr_output);
331942542f5fSchristos		if (output == NULL)
332042542f5fSchristos			continue;
332142542f5fSchristos
332242542f5fSchristos		disable_crtc(dpy, res, output->crtc);
332342542f5fSchristos		for (j = 0; j < output->nmode; j++)
332442542f5fSchristos			XRRDeleteOutputMode(dpy, clone->src.rr_output, output->modes[j]);
332542542f5fSchristos
332642542f5fSchristos		XRRFreeOutputInfo(output);
332742542f5fSchristos	}
332842542f5fSchristos
332942542f5fSchristos	for (i = 0; i < res->nmode; i++) {
333042542f5fSchristos		if (strncmp(res->modes[i].name, "VIRTUAL", 7) == 0) {
333142542f5fSchristos			XRRDestroyMode(dpy, res->modes[i].id);
333242542f5fSchristos			continue;
333342542f5fSchristos		}
333442542f5fSchristos
333542542f5fSchristos		if (strcmp(res->modes[i].name, "ClaimVirtualHead") == 0) {
333642542f5fSchristos			XRRDestroyMode(dpy, res->modes[i].id);
333742542f5fSchristos			continue;
333842542f5fSchristos		}
333942542f5fSchristos	}
334042542f5fSchristos	XRRFreeScreenResources(res);
334142542f5fSchristos
334242542f5fSchristos	/* And hide them again */
334342542f5fSchristos	res = XRRGetScreenResources(dpy, ctx->display->root);
334442542f5fSchristos	if (res != NULL)
334542542f5fSchristos		XRRFreeScreenResources(res);
334642542f5fSchristos
334742542f5fSchristos	XUngrabServer(dpy);
334842542f5fSchristos
334942542f5fSchristos	if (ctx->singleton)
335042542f5fSchristos		XDeleteProperty(dpy, ctx->display->root, ctx->singleton);
335142542f5fSchristos	XCloseDisplay(dpy);
335242542f5fSchristos}
335342542f5fSchristos
3354fe8aea9eSmrgstatic void update_cursor_image(struct context *ctx)
3355fe8aea9eSmrg{
3356fe8aea9eSmrg	XFixesCursorImage *cur;
3357fe8aea9eSmrg	int i;
3358fe8aea9eSmrg
3359fe8aea9eSmrg	DBG(CURSOR, ("%s cursor changed\n",
3360fe8aea9eSmrg		     DisplayString(ctx->display->dpy)));
3361fe8aea9eSmrg
3362fe8aea9eSmrg	cur = XFixesGetCursorImage(ctx->display->dpy);
3363fe8aea9eSmrg	if (cur == NULL)
3364fe8aea9eSmrg		return;
3365fe8aea9eSmrg
3366fe8aea9eSmrg	display_load_visible_cursor(&ctx->display[0], cur);
3367fe8aea9eSmrg	for (i = 1; i < ctx->ndisplay; i++) {
3368fe8aea9eSmrg		struct display *display = &ctx->display[i];
3369fe8aea9eSmrg
3370fe8aea9eSmrg		DBG(CURSOR, ("%s marking cursor changed\n", DisplayString(display->dpy)));
3371fe8aea9eSmrg		display->cursor_moved++;
3372fe8aea9eSmrg		if (display->cursor != display->invisible_cursor) {
3373fe8aea9eSmrg			display->cursor_visible++;
3374fe8aea9eSmrg			context_enable_timer(display->ctx);
3375fe8aea9eSmrg		}
3376fe8aea9eSmrg	}
3377fe8aea9eSmrg
3378fe8aea9eSmrg	XFree(cur);
3379fe8aea9eSmrg}
3380fe8aea9eSmrg
338142542f5fSchristosstatic int done;
338242542f5fSchristos
338342542f5fSchristosstatic void signal_handler(int sig)
338442542f5fSchristos{
338542542f5fSchristos	done = sig;
338642542f5fSchristos}
338742542f5fSchristos
338842542f5fSchristosint main(int argc, char **argv)
338942542f5fSchristos{
339042542f5fSchristos	struct context ctx;
339142542f5fSchristos	const char *src_name = NULL;
339242542f5fSchristos	uint64_t count;
339342542f5fSchristos	int daemonize = 1, bumblebee = 0, siblings = 0, singleton = 1;
339442542f5fSchristos	int i, ret, open, fail;
3395fe8aea9eSmrg	int idle;
339642542f5fSchristos
339742542f5fSchristos	signal(SIGPIPE, SIG_IGN);
339842542f5fSchristos
339942542f5fSchristos	while ((i = getopt(argc, argv, "abd:fhSvV:")) != -1) {
340042542f5fSchristos		switch (i) {
340142542f5fSchristos		case 'd':
340242542f5fSchristos			src_name = optarg;
340342542f5fSchristos			break;
340442542f5fSchristos		case 'f':
340542542f5fSchristos			daemonize = 0;
340642542f5fSchristos			break;
340742542f5fSchristos		case 'b':
340842542f5fSchristos			bumblebee = 1;
340942542f5fSchristos			break;
341042542f5fSchristos		case 's':
341142542f5fSchristos			siblings = 1;
341242542f5fSchristos			break;
341342542f5fSchristos		case 'S':
341442542f5fSchristos			singleton = 0;
341542542f5fSchristos			break;
341642542f5fSchristos		case 'v':
341742542f5fSchristos			verbose = ~0;
341842542f5fSchristos			daemonize = 0;
341942542f5fSchristos			break;
342042542f5fSchristos		case 'V':
342142542f5fSchristos			verbose = strtol(optarg, NULL, 0);
342242542f5fSchristos			daemonize = 0;
342342542f5fSchristos			break;
342442542f5fSchristos		case 'h':
342542542f5fSchristos		default:
342642542f5fSchristos			usage(argv[0]);
342742542f5fSchristos			exit(0);
342842542f5fSchristos		}
342942542f5fSchristos	}
343042542f5fSchristos
343113496ba1Ssnj	if (verbose)
343213496ba1Ssnj		printf("intel-virtual-output: version %d.%d.%d\n",
343313496ba1Ssnj		       PACKAGE_VERSION_MAJOR,
343413496ba1Ssnj		       PACKAGE_VERSION_MINOR,
343513496ba1Ssnj		       PACKAGE_VERSION_PATCHLEVEL);
343613496ba1Ssnj
343742542f5fSchristos	ret = context_init(&ctx);
343842542f5fSchristos	if (ret)
343942542f5fSchristos		return -ret;
344042542f5fSchristos
344142542f5fSchristos	XSetErrorHandler(_check_error_handler);
3442fe8aea9eSmrg	XSetIOErrorHandler(_io_error_handler);
344342542f5fSchristos
344442542f5fSchristos	ret = add_fd(&ctx, display_open(&ctx, src_name));
344542542f5fSchristos	if (ret) {
344642542f5fSchristos		fprintf(stderr, "Unable to connect to \"%s\".\n", src_name ?: getenv("DISPLAY") ?:
344742542f5fSchristos			"<unspecified>, set either the DISPLAY environment variable or pass -d <display name> on the commandline");
344842542f5fSchristos		ret = -ret;
344942542f5fSchristos		goto out;
345042542f5fSchristos	}
345142542f5fSchristos
3452fe8aea9eSmrg	ret = check_virtual(ctx.display);
3453fe8aea9eSmrg	if (ret) {
3454fe8aea9eSmrg		fprintf(stderr, "No VIRTUAL outputs on \"%s\".\n",
3455fe8aea9eSmrg			DisplayString(ctx.display->dpy));
3456fe8aea9eSmrg		goto out;
3457fe8aea9eSmrg	}
3458fe8aea9eSmrg
345942542f5fSchristos	if (singleton) {
346042542f5fSchristos		XSelectInput(ctx.display->dpy, ctx.display->root, PropertyChangeMask);
346142542f5fSchristos		if (first_display_has_singleton(&ctx)) {
346242542f5fSchristos			DBG(X11, ("%s: pinging singleton\n", DisplayString(ctx.display->dpy)));
346342542f5fSchristos			ret = first_display_send_command(&ctx, 2000, "P");
346442542f5fSchristos			if (ret) {
346542542f5fSchristos				if (ret != -ETIME) {
346642542f5fSchristos					ret = -ret;
346742542f5fSchristos					goto out;
346842542f5fSchristos				}
346942542f5fSchristos				DBG(X11, ("No reply from singleton; assuming control\n"));
347042542f5fSchristos			} else {
347142542f5fSchristos				DBG(X11, ("%s: singleton active, sending open commands\n", DisplayString(ctx.display->dpy)));
347242542f5fSchristos
347342542f5fSchristos				open = fail = 0;
347442542f5fSchristos				for (i = optind; i < argc; i++) {
347542542f5fSchristos					ret = first_display_send_command(&ctx, 5000, "C%s", argv[i]);
347642542f5fSchristos					if (ret && ret != -EBUSY) {
347742542f5fSchristos						fprintf(stderr, "Unable to connect to \"%s\".\n", argv[i]);
347842542f5fSchristos						fail++;
347942542f5fSchristos					} else
348042542f5fSchristos						open++;
348142542f5fSchristos				}
348242542f5fSchristos				if (siblings || (optind == argc && !bumblebee)) {
348342542f5fSchristos					first_display_for_each_sibling(&ctx, i) {
348442542f5fSchristos						ret = first_display_send_command(&ctx, 5000, "C%s", ctx.command);
348542542f5fSchristos						if (ret && ret != -EBUSY)
348642542f5fSchristos							break;
348742542f5fSchristos						else
348842542f5fSchristos							open++;
348942542f5fSchristos					}
349042542f5fSchristos				}
349142542f5fSchristos				if (bumblebee || (optind == argc && !siblings)) {
349242542f5fSchristos					ret = first_display_send_command(&ctx, 5000, "B");
349342542f5fSchristos					if (ret && ret != -EBUSY) {
349442542f5fSchristos						if (bumblebee)
349542542f5fSchristos							fprintf(stderr, "Unable to connect to bumblebee.\n");
349642542f5fSchristos						fail++;
349742542f5fSchristos					} else
349842542f5fSchristos						open++;
349942542f5fSchristos				}
350042542f5fSchristos				ret = open || !fail ? 0 : ECONNREFUSED;
350142542f5fSchristos				goto out;
350242542f5fSchristos			}
350342542f5fSchristos		}
350442542f5fSchristos		ret = first_display_register_as_singleton(&ctx);
350542542f5fSchristos		if (ret)
350642542f5fSchristos			goto out;
350742542f5fSchristos	}
350842542f5fSchristos
350942542f5fSchristos	ret = display_init_damage(ctx.display);
351042542f5fSchristos	if (ret)
351142542f5fSchristos		goto out;
351242542f5fSchristos
3513fe8aea9eSmrg	if (ctx.display->saver_active)
3514fe8aea9eSmrg		XScreenSaverSelectInput(ctx.display->dpy,
3515fe8aea9eSmrg					ctx.display->root,
3516fe8aea9eSmrg					ScreenSaverNotifyMask);
3517fe8aea9eSmrg
351842542f5fSchristos	if ((ctx.display->rr_event | ctx.display->rr_error) == 0) {
351942542f5fSchristos		fprintf(stderr, "RandR extension not supported by %s\n", DisplayString(ctx.display->dpy));
352042542f5fSchristos		ret = EINVAL;
352142542f5fSchristos		goto out;
352242542f5fSchristos	}
352342542f5fSchristos	XRRSelectInput(ctx.display->dpy, ctx.display->root, RRScreenChangeNotifyMask);
352442542f5fSchristos	XFixesSelectCursorInput(ctx.display->dpy, ctx.display->root, XFixesDisplayCursorNotifyMask);
352542542f5fSchristos
352642542f5fSchristos	ret = add_fd(&ctx, record_mouse(&ctx));
352742542f5fSchristos	if (ret) {
352842542f5fSchristos		fprintf(stderr, "XTEST extension not supported by display \"%s\"\n", DisplayString(ctx.display->dpy));
352942542f5fSchristos		ret = -ret;
353042542f5fSchristos		goto out;
353142542f5fSchristos	}
353242542f5fSchristos
353342542f5fSchristos	open = fail = 0;
353442542f5fSchristos	for (i = optind; i < argc; i++) {
353542542f5fSchristos		ret = last_display_clone(&ctx, display_open(&ctx, argv[i]));
353642542f5fSchristos		if (ret && ret != -EBUSY) {
353742542f5fSchristos			fprintf(stderr, "Unable to connect to \"%s\".\n", argv[i]);
353842542f5fSchristos			fail++;
353942542f5fSchristos		} else
354042542f5fSchristos			open++;
354142542f5fSchristos	}
354242542f5fSchristos	if (siblings || (optind == argc && !bumblebee)) {
354342542f5fSchristos		first_display_for_each_sibling(&ctx, i) {
354442542f5fSchristos			ret = last_display_clone(&ctx, display_open(&ctx, ctx.command));
354542542f5fSchristos			if (ret && ret != -EBUSY)
354642542f5fSchristos				break;
354742542f5fSchristos			else
354842542f5fSchristos				open++;
354942542f5fSchristos		}
355042542f5fSchristos	}
355142542f5fSchristos	if (bumblebee || (optind == argc && !siblings)) {
355242542f5fSchristos		ret = last_display_clone(&ctx, bumblebee_open(&ctx));
355342542f5fSchristos		if (ret && ret != -EBUSY) {
355442542f5fSchristos			if (bumblebee)
355542542f5fSchristos				fprintf(stderr, "Unable to connect to bumblebee.\n");
355642542f5fSchristos			fail++;
355742542f5fSchristos		} else
355842542f5fSchristos			open++;
355942542f5fSchristos	}
356042542f5fSchristos	if (open == 0) {
356142542f5fSchristos		ret = fail ? ECONNREFUSED : 0;
356242542f5fSchristos		goto out;
356342542f5fSchristos	}
356442542f5fSchristos
356542542f5fSchristos	if (daemonize && daemon(0, 0)) {
356642542f5fSchristos		ret = EINVAL;
356742542f5fSchristos		goto out;
356842542f5fSchristos	}
356942542f5fSchristos
357042542f5fSchristos	signal(SIGHUP, signal_handler);
357142542f5fSchristos	signal(SIGINT, signal_handler);
357242542f5fSchristos	signal(SIGTERM, signal_handler);
357342542f5fSchristos
357442542f5fSchristos	ctx.command_continuation = 0;
3575fe8aea9eSmrg	update_cursor_image(&ctx);
3576fe8aea9eSmrg
3577fe8aea9eSmrg	idle = 0;
357842542f5fSchristos	while (!done) {
357942542f5fSchristos		XEvent e;
358042542f5fSchristos		int reconfigure = 0;
358142542f5fSchristos		int rr_update = 0;
358242542f5fSchristos
3583fe8aea9eSmrg		if (idle) {
3584fe8aea9eSmrg			DBG(POLL, ("polling - enable timer? %d, nfd=%d, ndisplay=%d\n", ctx.timer_active, ctx.nfd, ctx.ndisplay));
3585fe8aea9eSmrg			ret = poll(ctx.pfd + !ctx.timer_active, ctx.nfd - !ctx.timer_active, -1);
3586fe8aea9eSmrg			if (ret <= 0)
3587fe8aea9eSmrg				break;
3588fe8aea9eSmrg
3589fe8aea9eSmrg			DBG(POLL, ("poll reports %d fd awake\n", ret));
3590fe8aea9eSmrg		}
3591fe8aea9eSmrg		idle = 1;
359242542f5fSchristos
359342542f5fSchristos		/* pfd[0] is the timer, pfd[1] is the local display, pfd[2] is the mouse, pfd[3+] are the remotes */
359442542f5fSchristos
359542542f5fSchristos		if (ctx.pfd[1].revents || XPending(ctx.display[0].dpy)) {
359642542f5fSchristos			DBG(POLL,("%s woken up\n", DisplayString(ctx.display[0].dpy)));
3597fe8aea9eSmrg			ctx.pfd[1].revents = 0;
3598fe8aea9eSmrg			idle = 0;
3599fe8aea9eSmrg
360042542f5fSchristos			do {
360142542f5fSchristos				XNextEvent(ctx.display->dpy, &e);
360242542f5fSchristos
3603fe8aea9eSmrg				DBG(POLL, ("%s received event %d\n", DisplayString(ctx.display[0].dpy), e.type));
3604fe8aea9eSmrg
3605fe8aea9eSmrg				if (e.type == ctx.display->saver_event + ScreenSaverNotify) {
3606fe8aea9eSmrg					const XScreenSaverNotifyEvent *se = (const XScreenSaverNotifyEvent *)&e;
3607fe8aea9eSmrg					DBG(SCREEN,
3608fe8aea9eSmrg					    ("%s screen saver: state=%d, kind=%d, forced=%d\n",
3609fe8aea9eSmrg					     DisplayString(ctx.display->dpy),
3610fe8aea9eSmrg					     se->state, se->kind, se->forced));
3611fe8aea9eSmrg					for (i = 1; i < ctx.ndisplay; i++) {
3612fe8aea9eSmrg						struct display *display = &ctx.display[i];
3613fe8aea9eSmrg
3614fe8aea9eSmrg						if (!display->active)
3615fe8aea9eSmrg							continue;
3616fe8aea9eSmrg
3617fe8aea9eSmrg						DBG(SCREEN,
3618fe8aea9eSmrg						    ("%s %s screen saver\n",
3619fe8aea9eSmrg						     DisplayString(display->dpy),
3620fe8aea9eSmrg						     se->state == ScreenSaverOn ? "activating" : "resetting\n"));
3621fe8aea9eSmrg
3622fe8aea9eSmrg						if (se->state == ScreenSaverOn)
3623fe8aea9eSmrg							XActivateScreenSaver(display->dpy);
3624fe8aea9eSmrg						else
3625fe8aea9eSmrg							XResetScreenSaver(display->dpy);
3626fe8aea9eSmrg						XFlush(display->dpy);
3627fe8aea9eSmrg					}
3628fe8aea9eSmrg				} else if (e.type == ctx.display->damage_event + XDamageNotify) {
362942542f5fSchristos					const XDamageNotifyEvent *de = (const XDamageNotifyEvent *)&e;
363042542f5fSchristos					struct clone *clone;
363142542f5fSchristos
363242542f5fSchristos					DBG(DAMAGE, ("%s damaged: (%d, %d)x(%d, %d)\n",
363342542f5fSchristos					     DisplayString(ctx.display->dpy),
363442542f5fSchristos					     de->area.x, de->area.y, de->area.width, de->area.height));
363542542f5fSchristos
363642542f5fSchristos					for (clone = ctx.active; clone; clone = clone->active)
363742542f5fSchristos						clone_damage(clone, &de->area);
363842542f5fSchristos
363942542f5fSchristos					if (ctx.active)
364042542f5fSchristos						context_enable_timer(&ctx);
364142542f5fSchristos				} else if (e.type == ctx.display->xfixes_event + XFixesCursorNotify) {
3642fe8aea9eSmrg					update_cursor_image(&ctx);
364342542f5fSchristos				} else if (e.type == ctx.display->rr_event + RRScreenChangeNotify) {
364442542f5fSchristos					DBG(XRR, ("%s screen changed (reconfigure pending? %d)\n",
364542542f5fSchristos					     DisplayString(ctx.display->dpy), reconfigure));
364642542f5fSchristos					reconfigure = 1;
364742542f5fSchristos				} else if (e.type == PropertyNotify) {
364842542f5fSchristos					XPropertyEvent *pe = (XPropertyEvent *)&e;
364942542f5fSchristos					if (pe->atom == ctx.singleton) {
365042542f5fSchristos						DBG(X11, ("lost control of singleton\n"));
365142542f5fSchristos						return 0;
365242542f5fSchristos					}
365342542f5fSchristos				} else if (e.type == ClientMessage) {
365442542f5fSchristos					XClientMessageEvent *cme;
365542542f5fSchristos
365642542f5fSchristos					DBG(X11, ("%s client message\n",
365742542f5fSchristos					     DisplayString(ctx.display->dpy)));
365842542f5fSchristos
365942542f5fSchristos					cme = (XClientMessageEvent *)&e;
366042542f5fSchristos					if (cme->message_type != ctx.singleton)
366142542f5fSchristos						continue;
366242542f5fSchristos					if (cme->format != 8)
366342542f5fSchristos						continue;
366442542f5fSchristos
366542542f5fSchristos					first_display_handle_command(&ctx, cme->data.b);
366642542f5fSchristos				} else {
366742542f5fSchristos					DBG(X11, ("unknown event %d\n", e.type));
366842542f5fSchristos				}
366942542f5fSchristos			} while (XEventsQueued(ctx.display->dpy, QueuedAfterReading));
367042542f5fSchristos		}
367142542f5fSchristos
367242542f5fSchristos		for (i = 1; i < ctx.ndisplay; i++) {
367342542f5fSchristos			if (ctx.pfd[i+2].revents == 0 && !XPending(ctx.display[i].dpy))
367442542f5fSchristos				continue;
367542542f5fSchristos
3676fe8aea9eSmrg			ctx.pfd[i+2].revents = 0;
3677fe8aea9eSmrg			idle = 0;
3678fe8aea9eSmrg
367942542f5fSchristos			DBG(POLL, ("%s woken up\n", DisplayString(ctx.display[i].dpy)));
368042542f5fSchristos			do {
368142542f5fSchristos				XNextEvent(ctx.display[i].dpy, &e);
368242542f5fSchristos
368342542f5fSchristos				DBG(POLL, ("%s received event %d\n", DisplayString(ctx.display[i].dpy), e.type));
3684fe8aea9eSmrg				if (e.type == Expose) {
3685fe8aea9eSmrg					const XExposeEvent *xe = (XExposeEvent *)&e;
3686fe8aea9eSmrg					struct clone *clone;
3687fe8aea9eSmrg					int damaged = 0;
3688fe8aea9eSmrg
3689fe8aea9eSmrg					DBG(DAMAGE, ("%s exposed: (%d, %d)x(%d, %d)\n",
3690fe8aea9eSmrg					     DisplayString(ctx.display[i].dpy),
3691fe8aea9eSmrg					     xe->x, xe->y, xe->width, xe->height));
3692fe8aea9eSmrg
3693fe8aea9eSmrg					for (clone = ctx.active; clone; clone = clone->active) {
3694fe8aea9eSmrg						XRectangle r;
3695fe8aea9eSmrg
3696fe8aea9eSmrg						if (clone->dst.display != &ctx.display[i])
3697fe8aea9eSmrg							continue;
3698fe8aea9eSmrg
3699fe8aea9eSmrg						r.x = clone->src.x + xe->x;
3700fe8aea9eSmrg						r.y = clone->src.y + xe->y;
3701fe8aea9eSmrg						r.width  = xe->width;
3702fe8aea9eSmrg						r.height = xe->height;
3703fe8aea9eSmrg						clone_damage(clone, &r);
3704fe8aea9eSmrg						damaged++;
3705fe8aea9eSmrg					}
3706fe8aea9eSmrg
3707fe8aea9eSmrg					if (damaged)
3708fe8aea9eSmrg						context_enable_timer(&ctx);
3709fe8aea9eSmrg				} else if (ctx.display[i].rr_active && e.type == ctx.display[i].rr_event + RRNotify) {
3710fe8aea9eSmrg					const XRRNotifyEvent *re = (XRRNotifyEvent *)&e;
371142542f5fSchristos
371242542f5fSchristos					DBG(XRR, ("%s received RRNotify, type %d\n", DisplayString(ctx.display[i].dpy), re->subtype));
371342542f5fSchristos					if (re->subtype == RRNotify_OutputChange) {
371442542f5fSchristos						XRROutputPropertyNotifyEvent *ro = (XRROutputPropertyNotifyEvent *)re;
371542542f5fSchristos						struct clone *clone;
371642542f5fSchristos
371742542f5fSchristos						DBG(XRR, ("%s RRNotify_OutputChange, timestamp %ld\n", DisplayString(ctx.display[i].dpy), ro->timestamp));
371842542f5fSchristos						for (clone = ctx.display[i].clone; clone; clone = clone->next) {
371942542f5fSchristos							if (clone->dst.rr_output == ro->output)
372042542f5fSchristos								rr_update = clone->rr_update = 1;
372142542f5fSchristos						}
372242542f5fSchristos					}
372342542f5fSchristos				}
372442542f5fSchristos			} while (XEventsQueued(ctx.display[i].dpy, QueuedAfterReading));
372542542f5fSchristos		}
372642542f5fSchristos
372742542f5fSchristos		if (rr_update) {
372842542f5fSchristos			for (i = 0; i < ctx.nclone; i++)
372942542f5fSchristos				clone_update(&ctx.clones[i]);
373042542f5fSchristos		}
373142542f5fSchristos
373242542f5fSchristos		if (reconfigure && context_update(&ctx))
373342542f5fSchristos			display_reset_damage(ctx.display);
373442542f5fSchristos
373542542f5fSchristos		while (XPending(ctx.record)) /* discard all implicit events */
373642542f5fSchristos			XNextEvent(ctx.record, &e);
373742542f5fSchristos
373842542f5fSchristos		if (ctx.timer_active && read(ctx.timer, &count, sizeof(count)) > 0) {
373942542f5fSchristos			struct clone *clone;
374042542f5fSchristos
374142542f5fSchristos			DBG(TIMER, ("%s timer expired (count=%ld)\n", DisplayString(ctx.display->dpy), (long)count));
374242542f5fSchristos			ret = 0;
374342542f5fSchristos
374442542f5fSchristos			if (ctx.active) {
374542542f5fSchristos				DBG(DAMAGE, ("%s clearing damage\n", DisplayString(ctx.display->dpy)));
374642542f5fSchristos				XDamageSubtract(ctx.display->dpy, ctx.display->damage, None, None);
374742542f5fSchristos				ctx.display->flush = 1;
374842542f5fSchristos			}
374942542f5fSchristos
375042542f5fSchristos			for (clone = ctx.active; clone; clone = clone->active)
375142542f5fSchristos				ret |= clone_paint(clone);
375242542f5fSchristos
375342542f5fSchristos			for (i = 0; i < ctx.ndisplay; i++)
375442542f5fSchristos				display_flush(&ctx.display[i]);
375542542f5fSchristos
375642542f5fSchristos			DBG(TIMER, ("%s timer still active? %d\n", DisplayString(ctx.display->dpy), ret != 0));
375742542f5fSchristos			ctx.timer_active = ret != 0;
3758fe8aea9eSmrg			idle = 0;
375942542f5fSchristos		}
376042542f5fSchristos	}
376142542f5fSchristos
376242542f5fSchristos	ret = 0;
376342542f5fSchristosout:
376442542f5fSchristos	context_cleanup(&ctx);
376542542f5fSchristos	return ret;
376642542f5fSchristos}
3767