1b042e37fSmrg/*
2b042e37fSmrg * Copyright © 2000 Compaq Computer Corporation, Inc.
3b042e37fSmrg * Copyright © 2002 Hewlett Packard Company, Inc.
4b042e37fSmrg *
5b042e37fSmrg * Permission to use, copy, modify, distribute, and sell this software and its
6b042e37fSmrg * documentation for any purpose is hereby granted without fee, provided that
7b042e37fSmrg * the above copyright notice appear in all copies and that both that
8b042e37fSmrg * copyright notice and this permission notice appear in supporting
9b042e37fSmrg * documentation, and that the name of Compaq or HP not be used in advertising
10b042e37fSmrg * or publicity pertaining to distribution of the software without specific,
11b042e37fSmrg * written prior permission.  HP makes no representations about the
12b042e37fSmrg * suitability of this software for any purpose.  It is provided "as is"
13b042e37fSmrg * without express or implied warranty.
14b042e37fSmrg *
15b042e37fSmrg * HP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
16b042e37fSmrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL COMPAQ
17b042e37fSmrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18b042e37fSmrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
190597fb56Smrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20b042e37fSmrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21b042e37fSmrg *
22b042e37fSmrg * Author:  Jim Gettys, HP Labs, HP.
23b042e37fSmrg */
24b042e37fSmrg
25b042e37fSmrg#ifdef HAVE_CONFIG_H
26b042e37fSmrg#include <config.h>
27b042e37fSmrg#endif
28b042e37fSmrg
29b042e37fSmrg#include <stdio.h>
30b042e37fSmrg#include <X11/Xlib.h>
31b042e37fSmrg/* we need to be able to manipulate the Display structure on events */
32b042e37fSmrg#include <X11/Xlibint.h>
33b042e37fSmrg#include <X11/extensions/render.h>
34b042e37fSmrg#include <X11/extensions/Xrender.h>
35b042e37fSmrg#include "Xrandrint.h"
36b042e37fSmrg
378c4a8e55Smrgstatic XExtensionInfo XRRExtensionInfo;
388c4a8e55Smrg_X_HIDDEN char XRRExtensionName[] = RANDR_NAME;
39b042e37fSmrg
40b042e37fSmrgstatic Bool     XRRWireToEvent(Display *dpy, XEvent *event, xEvent *wire);
41b042e37fSmrgstatic Status   XRREventToWire(Display *dpy, XEvent *event, xEvent *wire);
42b042e37fSmrg
43b042e37fSmrgstatic int
44b042e37fSmrgXRRCloseDisplay (Display *dpy, XExtCodes *codes);
45b042e37fSmrg
46b042e37fSmrgstatic /* const */ XExtensionHooks rr_extension_hooks = {
47b042e37fSmrg    NULL,				/* create_gc */
48b042e37fSmrg    NULL,				/* copy_gc */
49b042e37fSmrg    NULL,				/* flush_gc */
50b042e37fSmrg    NULL,				/* free_gc */
51b042e37fSmrg    NULL,				/* create_font */
52b042e37fSmrg    NULL,				/* free_font */
53b042e37fSmrg    XRRCloseDisplay,			/* close_display */
54b042e37fSmrg    XRRWireToEvent,			/* wire_to_event */
55b042e37fSmrg    XRREventToWire,			/* event_to_wire */
56b042e37fSmrg    NULL,				/* error */
57b042e37fSmrg    NULL,				/* error_string */
58b042e37fSmrg};
59b042e37fSmrg
60b042e37fSmrgstatic Bool XRRWireToEvent(Display *dpy, XEvent *event, xEvent *wire)
61b042e37fSmrg{
62b042e37fSmrg    XExtDisplayInfo *info = XRRFindDisplay(dpy);
63b042e37fSmrg
64b042e37fSmrg    RRCheckExtension(dpy, info, False);
65b042e37fSmrg
66b042e37fSmrg    switch ((wire->u.u.type & 0x7F) - info->codes->first_event)
67b042e37fSmrg    {
68b042e37fSmrg      case RRScreenChangeNotify: {
69b042e37fSmrg	XRRScreenChangeNotifyEvent *aevent= (XRRScreenChangeNotifyEvent *) event;
70b042e37fSmrg	xRRScreenChangeNotifyEvent *awire = (xRRScreenChangeNotifyEvent *) wire;
71b042e37fSmrg	aevent->type = awire->type & 0x7F;
72b042e37fSmrg	aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
73b042e37fSmrg	aevent->send_event = (awire->type & 0x80) != 0;
74b042e37fSmrg	aevent->display = dpy;
75b042e37fSmrg	aevent->window = awire->window;
76b042e37fSmrg	aevent->root = awire->root;
77b042e37fSmrg	aevent->timestamp = awire->timestamp;
78b042e37fSmrg	aevent->config_timestamp = awire->configTimestamp;
79b042e37fSmrg	aevent->size_index = awire->sizeID;
80b042e37fSmrg	aevent->subpixel_order = awire->subpixelOrder;
81b042e37fSmrg	aevent->rotation = awire->rotation;
82b042e37fSmrg	aevent->width = awire->widthInPixels;
83b042e37fSmrg	aevent->height = awire->heightInPixels;
84b042e37fSmrg	aevent->mwidth = awire->widthInMillimeters;
85b042e37fSmrg	aevent->mheight = awire->heightInMillimeters;
86b042e37fSmrg	return True;
87b042e37fSmrg      }
88b042e37fSmrg      case RRNotify: {
898c4a8e55Smrg	switch (wire->u.u.detail) {
90b042e37fSmrg	case RRNotify_OutputChange: {
91b042e37fSmrg	    XRROutputChangeNotifyEvent *aevent = (XRROutputChangeNotifyEvent *) event;
92b042e37fSmrg	    xRROutputChangeNotifyEvent *awire = (xRROutputChangeNotifyEvent *) wire;
938c4a8e55Smrg	    aevent->type = awire->type & 0x7F;
948c4a8e55Smrg	    aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
958c4a8e55Smrg	    aevent->send_event = (awire->type & 0x80) != 0;
968c4a8e55Smrg	    aevent->display = dpy;
978c4a8e55Smrg	    aevent->window = awire->window;
988c4a8e55Smrg	    aevent->subtype = awire->subCode;
99b042e37fSmrg	    aevent->output = awire->output;
100b042e37fSmrg	    aevent->crtc = awire->crtc;
101b042e37fSmrg	    aevent->mode = awire->mode;
102b042e37fSmrg	    aevent->rotation = awire->rotation;
103b042e37fSmrg	    aevent->connection = awire->connection;
104b042e37fSmrg	    aevent->subpixel_order = awire->subpixelOrder;
105b042e37fSmrg	    return True;
106b042e37fSmrg	}
107b042e37fSmrg	case RRNotify_CrtcChange: {
108b042e37fSmrg	    XRRCrtcChangeNotifyEvent *aevent = (XRRCrtcChangeNotifyEvent *) event;
109b042e37fSmrg	    xRRCrtcChangeNotifyEvent *awire = (xRRCrtcChangeNotifyEvent *) wire;
1108c4a8e55Smrg	    aevent->type = awire->type & 0x7F;
1118c4a8e55Smrg	    aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
1128c4a8e55Smrg	    aevent->send_event = (awire->type & 0x80) != 0;
1138c4a8e55Smrg	    aevent->display = dpy;
1148c4a8e55Smrg	    aevent->window = awire->window;
1158c4a8e55Smrg	    aevent->subtype = awire->subCode;
116b042e37fSmrg	    aevent->crtc = awire->crtc;
117b042e37fSmrg	    aevent->mode = awire->mode;
118b042e37fSmrg	    aevent->rotation = awire->rotation;
119b042e37fSmrg	    aevent->x = awire->x;
120b042e37fSmrg	    aevent->y = awire->y;
121b042e37fSmrg	    aevent->width = awire->width;
122b042e37fSmrg	    aevent->height = awire->height;
123b042e37fSmrg	    return True;
124b042e37fSmrg	}
125b042e37fSmrg	case RRNotify_OutputProperty: {
126b042e37fSmrg	    XRROutputPropertyNotifyEvent *aevent = (XRROutputPropertyNotifyEvent *) event;
127b042e37fSmrg	    xRROutputPropertyNotifyEvent *awire = (xRROutputPropertyNotifyEvent *) wire;
1288c4a8e55Smrg	    aevent->type = awire->type & 0x7F;
1298c4a8e55Smrg	    aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
1308c4a8e55Smrg	    aevent->send_event = (awire->type & 0x80) != 0;
1318c4a8e55Smrg	    aevent->display = dpy;
1328c4a8e55Smrg	    aevent->window = awire->window;
1338c4a8e55Smrg	    aevent->subtype = awire->subCode;
134b042e37fSmrg	    aevent->output = awire->output;
135b042e37fSmrg	    aevent->property = awire->atom;
136b042e37fSmrg	    aevent->timestamp = awire->timestamp;
137b042e37fSmrg	    aevent->state = awire->state;
138b042e37fSmrg	    return True;
139b042e37fSmrg	}
1400597fb56Smrg	case RRNotify_ProviderChange: {
1410597fb56Smrg	    XRRProviderChangeNotifyEvent *aevent = (XRRProviderChangeNotifyEvent *) event;
1420597fb56Smrg	    xRRProviderChangeNotifyEvent *awire = (xRRProviderChangeNotifyEvent *) wire;
1430597fb56Smrg	    aevent->type = awire->type & 0x7F;
1440597fb56Smrg	    aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
1450597fb56Smrg	    aevent->send_event = (awire->type & 0x80) != 0;
1460597fb56Smrg	    aevent->display = dpy;
1470597fb56Smrg	    aevent->window = awire->window;
1480597fb56Smrg	    aevent->subtype = awire->subCode;
1490597fb56Smrg	    aevent->provider = awire->provider;
1500597fb56Smrg	    aevent->timestamp = awire->timestamp;
1510597fb56Smrg	    return True;
1520597fb56Smrg	}
1530597fb56Smrg	case RRNotify_ProviderProperty: {
1540597fb56Smrg	    XRRProviderPropertyNotifyEvent *aevent = (XRRProviderPropertyNotifyEvent *) event;
1550597fb56Smrg	    xRRProviderPropertyNotifyEvent *awire = (xRRProviderPropertyNotifyEvent *) wire;
1560597fb56Smrg	    aevent->type = awire->type & 0x7F;
1570597fb56Smrg	    aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
1580597fb56Smrg	    aevent->send_event = (awire->type & 0x80) != 0;
1590597fb56Smrg	    aevent->display = dpy;
1600597fb56Smrg	    aevent->window = awire->window;
1610597fb56Smrg	    aevent->subtype = awire->subCode;
1620597fb56Smrg	    aevent->provider = awire->provider;
1630597fb56Smrg	    aevent->property = awire->atom;
1640597fb56Smrg	    aevent->timestamp = awire->timestamp;
1650597fb56Smrg	    aevent->state = awire->state;
1660597fb56Smrg	    return True;
1670597fb56Smrg	}
1680597fb56Smrg	case RRNotify_ResourceChange: {
1690597fb56Smrg	    XRRResourceChangeNotifyEvent *aevent = (XRRResourceChangeNotifyEvent *) event;
1700597fb56Smrg	    xRRResourceChangeNotifyEvent *awire = (xRRResourceChangeNotifyEvent *) wire;
1710597fb56Smrg	    aevent->type = awire->type & 0x7F;
1720597fb56Smrg	    aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
1730597fb56Smrg	    aevent->send_event = (awire->type & 0x80) != 0;
1740597fb56Smrg	    aevent->display = dpy;
1750597fb56Smrg	    aevent->window = awire->window;
1760597fb56Smrg	    aevent->subtype = awire->subCode;
1770597fb56Smrg	    aevent->timestamp = awire->timestamp;
1780597fb56Smrg	    return True;
1790597fb56Smrg	}
180b042e37fSmrg	    break;
181b042e37fSmrg	}
182b042e37fSmrg      }
183b042e37fSmrg    }
184b042e37fSmrg
185b042e37fSmrg    return False;
186b042e37fSmrg}
187b042e37fSmrg
188b042e37fSmrgstatic Status XRREventToWire(Display *dpy, XEvent *event, xEvent *wire)
189b042e37fSmrg{
190b042e37fSmrg    XExtDisplayInfo *info = XRRFindDisplay(dpy);
191b042e37fSmrg
192b042e37fSmrg    RRCheckExtension(dpy, info, False);
193b042e37fSmrg
194b042e37fSmrg    switch ((event->type & 0x7F) - info->codes->first_event)
195b042e37fSmrg    {
196b042e37fSmrg      case RRScreenChangeNotify: {
197b042e37fSmrg	xRRScreenChangeNotifyEvent *awire = (xRRScreenChangeNotifyEvent *) wire;
198b042e37fSmrg	XRRScreenChangeNotifyEvent *aevent = (XRRScreenChangeNotifyEvent *) event;
199b042e37fSmrg	awire->type = aevent->type | (aevent->send_event ? 0x80 : 0);
200b042e37fSmrg	awire->rotation = (CARD8) aevent->rotation;
201b042e37fSmrg	awire->sequenceNumber = aevent->serial & 0xFFFF;
202b042e37fSmrg	awire->timestamp = aevent->timestamp;
203b042e37fSmrg	awire->configTimestamp = aevent->config_timestamp;
204b042e37fSmrg	awire->root = aevent->root;
205b042e37fSmrg	awire->window = aevent->window;
206b042e37fSmrg	awire->sizeID = aevent->size_index;
207b042e37fSmrg	awire->subpixelOrder = aevent->subpixel_order;
208b042e37fSmrg	awire->widthInPixels = aevent->width;
209b042e37fSmrg	awire->heightInPixels = aevent->height;
210b042e37fSmrg	awire->widthInMillimeters = aevent->mwidth;
211b042e37fSmrg	awire->heightInMillimeters = aevent->mheight;
212b042e37fSmrg	return True;
213b042e37fSmrg      }
214b042e37fSmrg      case RRNotify: {
215b042e37fSmrg	xRRCrtcChangeNotifyEvent *awire = (xRRCrtcChangeNotifyEvent *) wire;
216b042e37fSmrg	XRRNotifyEvent *aevent = (XRRNotifyEvent *) event;
217b042e37fSmrg	awire->type = aevent->type | (aevent->send_event ? 0x80 : 0);
218b042e37fSmrg	awire->sequenceNumber = aevent->serial & 0xFFFF;
219b042e37fSmrg	awire->subCode = aevent->subtype;
220b042e37fSmrg	switch (aevent->subtype) {
221b042e37fSmrg	case RRNotify_OutputChange: {
22267594505Smrg	    xRROutputChangeNotifyEvent *sawire = (xRROutputChangeNotifyEvent *) wire;
22367594505Smrg	    XRROutputChangeNotifyEvent *saevent = (XRROutputChangeNotifyEvent *) event;
22467594505Smrg	    sawire->window = saevent->window;
22567594505Smrg	    sawire->output = saevent->output;
22667594505Smrg	    sawire->crtc = saevent->crtc;
22767594505Smrg	    sawire->mode = saevent->mode;
22867594505Smrg	    sawire->rotation = saevent->rotation;
22967594505Smrg	    sawire->connection = saevent->connection;
23067594505Smrg	    sawire->subpixelOrder = saevent->subpixel_order;
231b042e37fSmrg	    return True;
232b042e37fSmrg	}
233b042e37fSmrg	case RRNotify_CrtcChange: {
23467594505Smrg	    xRRCrtcChangeNotifyEvent *sawire = (xRRCrtcChangeNotifyEvent *) wire;
23567594505Smrg	    XRRCrtcChangeNotifyEvent *saevent = (XRRCrtcChangeNotifyEvent *) event;
23667594505Smrg	    sawire->window = saevent->window;
23767594505Smrg	    sawire->crtc = saevent->crtc;
23867594505Smrg	    sawire->mode = saevent->mode;
23967594505Smrg	    sawire->rotation = saevent->rotation;
24067594505Smrg	    sawire->x = saevent->x;
24167594505Smrg	    sawire->y = saevent->y;
24267594505Smrg	    sawire->width = saevent->width;
24367594505Smrg	    sawire->height = saevent->height;
244b042e37fSmrg	    return True;
245b042e37fSmrg	}
246b042e37fSmrg	case RRNotify_OutputProperty: {
24767594505Smrg	    xRROutputPropertyNotifyEvent *sawire = (xRROutputPropertyNotifyEvent *) wire;
24867594505Smrg	    XRROutputPropertyNotifyEvent *saevent = (XRROutputPropertyNotifyEvent *) event;
24967594505Smrg	    sawire->window = saevent->window;
25067594505Smrg	    sawire->output = saevent->output;
25167594505Smrg	    sawire->atom = saevent->property;
25267594505Smrg	    sawire->timestamp = saevent->timestamp;
25367594505Smrg	    sawire->state = saevent->state;
254b042e37fSmrg	    return True;
255b042e37fSmrg	}
2560597fb56Smrg	case RRNotify_ProviderChange: {
25767594505Smrg	    xRRProviderChangeNotifyEvent *sawire = (xRRProviderChangeNotifyEvent *) wire;
25867594505Smrg	    XRRProviderChangeNotifyEvent *saevent = (XRRProviderChangeNotifyEvent *) event;
25967594505Smrg	    sawire->window = saevent->window;
26067594505Smrg	    sawire->provider = saevent->provider;
2610597fb56Smrg	    return True;
2620597fb56Smrg	}
2630597fb56Smrg	case RRNotify_ProviderProperty: {
26467594505Smrg	    xRRProviderPropertyNotifyEvent *sawire = (xRRProviderPropertyNotifyEvent *) wire;
26567594505Smrg	    XRRProviderPropertyNotifyEvent *saevent = (XRRProviderPropertyNotifyEvent *) event;
26667594505Smrg	    sawire->window = saevent->window;
26767594505Smrg	    sawire->provider = saevent->provider;
26867594505Smrg	    sawire->atom = saevent->property;
26967594505Smrg	    sawire->timestamp = saevent->timestamp;
27067594505Smrg	    sawire->state = saevent->state;
2710597fb56Smrg	    return True;
2720597fb56Smrg	}
2730597fb56Smrg	case RRNotify_ResourceChange: {
27467594505Smrg	    xRRResourceChangeNotifyEvent *sawire = (xRRResourceChangeNotifyEvent *) wire;
27567594505Smrg	    XRRResourceChangeNotifyEvent *saevent = (XRRResourceChangeNotifyEvent *) event;
27667594505Smrg	    sawire->window = saevent->window;
27767594505Smrg	    sawire->timestamp = saevent->timestamp;
2780597fb56Smrg	    return True;
2790597fb56Smrg	}
280b042e37fSmrg	}
281b042e37fSmrg      }
282b042e37fSmrg    }
283b042e37fSmrg    return False;
284b042e37fSmrg}
285b042e37fSmrg
2868c4a8e55Smrg_X_HIDDEN XExtDisplayInfo *
287b042e37fSmrgXRRFindDisplay (Display *dpy)
288b042e37fSmrg{
2898d0bc965Smrg    XExtDisplayInfo *dpyinfo = XextFindDisplay (&XRRExtensionInfo, dpy);
290b042e37fSmrg
291b042e37fSmrg    if (!dpyinfo) {
2928d0bc965Smrg	XRandRInfo *xrri;
2938d0bc965Smrg	int numscreens;
2948d0bc965Smrg
2950597fb56Smrg	dpyinfo = XextAddDisplay (&XRRExtensionInfo, dpy,
296b042e37fSmrg				  XRRExtensionName,
297b042e37fSmrg				  &rr_extension_hooks,
2988c4a8e55Smrg				  RRNumberEvents, NULL);
299b042e37fSmrg	numscreens = ScreenCount(dpy);
3000597fb56Smrg	xrri = Xmalloc (sizeof(XRandRInfo) +
301b042e37fSmrg				 sizeof(char *) * numscreens);
302b042e37fSmrg	xrri->config = (XRRScreenConfiguration **)(xrri + 1);
3038d0bc965Smrg	for (int i = 0; i < numscreens; i++)
304b042e37fSmrg	  xrri->config[i] = NULL;
305b042e37fSmrg	xrri->major_version = -1;
306b042e37fSmrg	dpyinfo->data = (char *) xrri;
307b042e37fSmrg    }
308b042e37fSmrg    return dpyinfo;
309b042e37fSmrg}
310b042e37fSmrg
311b042e37fSmrgstatic int
312b042e37fSmrgXRRCloseDisplay (Display *dpy, XExtCodes *codes)
313b042e37fSmrg{
314b042e37fSmrg    XExtDisplayInfo *info = XRRFindDisplay (dpy);
315b042e37fSmrg
316b042e37fSmrg    LockDisplay(dpy);
317b042e37fSmrg    /*
318b042e37fSmrg     * free cached data
319b042e37fSmrg     */
320b042e37fSmrg    if (XextHasExtension(info)) {
3218d0bc965Smrg	XRandRInfo *xrri = (XRandRInfo *) info->data;
322b042e37fSmrg	if (xrri) {
3238d0bc965Smrg	    XRRScreenConfiguration **configs = xrri->config;
324b042e37fSmrg
3258d0bc965Smrg	    for (int i = 0; i < ScreenCount(dpy); i++) {
326b042e37fSmrg		if (configs[i] != NULL) XFree (configs[i]);
327b042e37fSmrg	    }
328b042e37fSmrg	    XFree (xrri);
329b042e37fSmrg	}
330b042e37fSmrg    }
331b042e37fSmrg    UnlockDisplay(dpy);
332b042e37fSmrg    return XextRemoveDisplay (&XRRExtensionInfo, dpy);
333b042e37fSmrg}
334b042e37fSmrg
335b042e37fSmrgint XRRRootToScreen(Display *dpy, Window root)
336b042e37fSmrg{
3378d0bc965Smrg  for (int snum = 0; snum < ScreenCount(dpy); snum++) {
338b042e37fSmrg    if (RootWindow(dpy, snum) == root) return snum;
339b042e37fSmrg  }
340b042e37fSmrg  return -1;
341b042e37fSmrg}
342b042e37fSmrg
343b042e37fSmrg
3448c4a8e55SmrgBool XRRQueryExtension (Display *dpy,
3458c4a8e55Smrg			int *event_base_return,
3468c4a8e55Smrg			int *error_base_return)
347b042e37fSmrg{
348b042e37fSmrg  XExtDisplayInfo *info = XRRFindDisplay (dpy);
349b042e37fSmrg
350b042e37fSmrg    if (XextHasExtension(info)) {
3518c4a8e55Smrg	*event_base_return = info->codes->first_event;
3528c4a8e55Smrg	*error_base_return = info->codes->first_error;
353b042e37fSmrg	return True;
354b042e37fSmrg    } else {
355b042e37fSmrg	return False;
356b042e37fSmrg    }
357b042e37fSmrg}
358b042e37fSmrg
3598c4a8e55Smrg_X_HIDDEN Bool
360b042e37fSmrg_XRRHasRates (int major, int minor)
361b042e37fSmrg{
362b042e37fSmrg    return major > 1 || (major == 1 && minor >= 1);
363b042e37fSmrg}
364b042e37fSmrg
365b042e37fSmrgStatus XRRQueryVersion (Display *dpy,
366b042e37fSmrg			    int	    *major_versionp,
367b042e37fSmrg			    int	    *minor_versionp)
368b042e37fSmrg{
369b042e37fSmrg    XExtDisplayInfo *info = XRRFindDisplay (dpy);
370b042e37fSmrg    xRRQueryVersionReply rep;
371b042e37fSmrg    xRRQueryVersionReq  *req;
372b042e37fSmrg    XRandRInfo *xrri;
373b042e37fSmrg
374b042e37fSmrg    RRCheckExtension (dpy, info, 0);
375b042e37fSmrg
376b042e37fSmrg    xrri = (XRandRInfo *) info->data;
377b042e37fSmrg
3780597fb56Smrg    /*
379b042e37fSmrg     * only get the version information from the server if we don't have it already
380b042e37fSmrg     */
381b042e37fSmrg    if (xrri->major_version == -1) {
382b042e37fSmrg      LockDisplay (dpy);
383b042e37fSmrg      GetReq (RRQueryVersion, req);
384b042e37fSmrg      req->reqType = info->codes->major_opcode;
385b042e37fSmrg      req->randrReqType = X_RRQueryVersion;
386b042e37fSmrg      req->majorVersion = RANDR_MAJOR;
387b042e37fSmrg      req->minorVersion = RANDR_MINOR;
388b042e37fSmrg      if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
389b042e37fSmrg	UnlockDisplay (dpy);
390b042e37fSmrg	SyncHandle ();
391b042e37fSmrg	return 0;
392b042e37fSmrg      }
393b042e37fSmrg      xrri->major_version = rep.majorVersion;
394b042e37fSmrg      xrri->minor_version = rep.minorVersion;
395b042e37fSmrg      xrri->has_rates = _XRRHasRates (xrri->major_version, xrri->minor_version);
396b042e37fSmrg      UnlockDisplay (dpy);
397b042e37fSmrg      SyncHandle ();
398b042e37fSmrg    }
399b042e37fSmrg    *major_versionp = xrri->major_version;
400b042e37fSmrg    *minor_versionp = xrri->minor_version;
401b042e37fSmrg    return 1;
402b042e37fSmrg}
403b042e37fSmrg
4048c4a8e55Smrg_X_HIDDEN Bool
405b042e37fSmrg_XRRVersionHandler (Display	    *dpy,
406b042e37fSmrg			xReply	    *rep,
407b042e37fSmrg			char	    *buf,
408b042e37fSmrg			int	    len,
409b042e37fSmrg			XPointer    data)
410b042e37fSmrg{
411b042e37fSmrg    xRRQueryVersionReply	replbuf;
412b042e37fSmrg    xRRQueryVersionReply	*repl;
413b042e37fSmrg    _XRRVersionState	*state = (_XRRVersionState *) data;
414b042e37fSmrg
415b042e37fSmrg    if (dpy->last_request_read != state->version_seq)
416b042e37fSmrg	return False;
417b042e37fSmrg    if (rep->generic.type == X_Error)
418b042e37fSmrg    {
419b042e37fSmrg	state->error = True;
420b042e37fSmrg	return False;
421b042e37fSmrg    }
422b042e37fSmrg    repl = (xRRQueryVersionReply *)
423b042e37fSmrg	_XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
424b042e37fSmrg		     (SIZEOF(xRRQueryVersionReply) - SIZEOF(xReply)) >> 2,
425b042e37fSmrg			True);
426b042e37fSmrg    state->major_version = repl->majorVersion;
427b042e37fSmrg    state->minor_version = repl->minorVersion;
428b042e37fSmrg    return True;
429b042e37fSmrg}
430b042e37fSmrg
4310597fb56Smrg/*
432b042e37fSmrg * in protocol version 0.1, routine added to allow selecting for new events.
433b042e37fSmrg */
434b042e37fSmrg
435b042e37fSmrgvoid XRRSelectInput (Display *dpy, Window window, int mask)
436b042e37fSmrg{
437b042e37fSmrg    XExtDisplayInfo *info = XRRFindDisplay (dpy);
438b042e37fSmrg    xRRSelectInputReq  *req;
439b042e37fSmrg
440b042e37fSmrg    RRSimpleCheckExtension (dpy, info);
441b042e37fSmrg
442b042e37fSmrg    LockDisplay (dpy);
443b042e37fSmrg    GetReq (RRSelectInput, req);
444b042e37fSmrg    req->reqType = info->codes->major_opcode;
445b042e37fSmrg    req->randrReqType = X_RRSelectInput;
446b042e37fSmrg    req->window = window;
447b042e37fSmrg    req->enable = 0;
448b042e37fSmrg    if (mask) req->enable = mask;
449b042e37fSmrg    UnlockDisplay (dpy);
450b042e37fSmrg    SyncHandle ();
451b042e37fSmrg    return;
452b042e37fSmrg}
453b042e37fSmrg
454b042e37fSmrgint XRRUpdateConfiguration(XEvent *event)
455b042e37fSmrg{
456b042e37fSmrg    XRRScreenChangeNotifyEvent *scevent;
457b042e37fSmrg    XConfigureEvent *rcevent;
458b042e37fSmrg    Display *dpy = event->xany.display;
459b042e37fSmrg    XExtDisplayInfo *info;
460b042e37fSmrg    XRandRInfo *xrri;
461b042e37fSmrg    int snum;
462b042e37fSmrg
463b042e37fSmrg    /* first, see if it is a vanilla configure notify event */
464b042e37fSmrg    if (event->type == ConfigureNotify) {
465b042e37fSmrg	rcevent = (XConfigureEvent *) event;
466b042e37fSmrg	snum = XRRRootToScreen(dpy, rcevent->window);
4678c4a8e55Smrg	if (snum != -1) {
4688c4a8e55Smrg	    dpy->screens[snum].width   = rcevent->width;
4698c4a8e55Smrg	    dpy->screens[snum].height  = rcevent->height;
4708c4a8e55Smrg	    return 1;
4718c4a8e55Smrg	}
472b042e37fSmrg    }
473b042e37fSmrg
474b042e37fSmrg    info = XRRFindDisplay(dpy);
475b042e37fSmrg    RRCheckExtension (dpy, info, 0);
476b042e37fSmrg
477b042e37fSmrg    switch (event->type - info->codes->first_event) {
478b042e37fSmrg    case RRScreenChangeNotify:
479b042e37fSmrg	scevent = (XRRScreenChangeNotifyEvent *) event;
4800597fb56Smrg	snum = XRRRootToScreen(dpy,
481b042e37fSmrg			       ((XRRScreenChangeNotifyEvent *) event)->root);
482fc98c8e2Smrg	if (snum < 0)
483fc98c8e2Smrg	    return 0;
484fc98c8e2Smrg
485b042e37fSmrg	if (scevent->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
486b042e37fSmrg		dpy->screens[snum].width   = scevent->height;
487b042e37fSmrg		dpy->screens[snum].height  = scevent->width;
488b042e37fSmrg		dpy->screens[snum].mwidth  = scevent->mheight;
489b042e37fSmrg		dpy->screens[snum].mheight = scevent->mwidth;
490b042e37fSmrg	} else {
491b042e37fSmrg		dpy->screens[snum].width   = scevent->width;
492b042e37fSmrg		dpy->screens[snum].height  = scevent->height;
493b042e37fSmrg		dpy->screens[snum].mwidth  = scevent->mwidth;
494b042e37fSmrg		dpy->screens[snum].mheight = scevent->mheight;
495b042e37fSmrg	}
496b042e37fSmrg	XRenderSetSubpixelOrder (dpy, snum, scevent->subpixel_order);
497b042e37fSmrg	break;
498b042e37fSmrg    default:
499b042e37fSmrg	return 0;
500b042e37fSmrg    }
501b042e37fSmrg    xrri = (XRandRInfo *) info->data;
5020597fb56Smrg    /*
5030597fb56Smrg     * so the next time someone wants some data, it will be fetched;
5040597fb56Smrg     * it might be better to force the round trip immediately, but
505b042e37fSmrg     * I dislike pounding the server simultaneously when not necessary
506b042e37fSmrg     */
507b042e37fSmrg    if (xrri->config[snum] != NULL) {
508b042e37fSmrg	XFree (xrri->config[snum]);
509b042e37fSmrg	xrri->config[snum] = NULL;
510b042e37fSmrg    }
511b042e37fSmrg    return 1;
512b042e37fSmrg}
513