Xrandr.c revision b042e37f
1b042e37fSmrg/*
2b042e37fSmrg * $XFree86: xc/lib/Xrandr/Xrandr.c,v 1.13tsi Exp $
3b042e37fSmrg *
4b042e37fSmrg * Copyright © 2000 Compaq Computer Corporation, Inc.
5b042e37fSmrg * Copyright © 2002 Hewlett Packard Company, Inc.
6b042e37fSmrg *
7b042e37fSmrg * Permission to use, copy, modify, distribute, and sell this software and its
8b042e37fSmrg * documentation for any purpose is hereby granted without fee, provided that
9b042e37fSmrg * the above copyright notice appear in all copies and that both that
10b042e37fSmrg * copyright notice and this permission notice appear in supporting
11b042e37fSmrg * documentation, and that the name of Compaq or HP not be used in advertising
12b042e37fSmrg * or publicity pertaining to distribution of the software without specific,
13b042e37fSmrg * written prior permission.  HP makes no representations about the
14b042e37fSmrg * suitability of this software for any purpose.  It is provided "as is"
15b042e37fSmrg * without express or implied warranty.
16b042e37fSmrg *
17b042e37fSmrg * HP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
18b042e37fSmrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL COMPAQ
19b042e37fSmrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20b042e37fSmrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21b042e37fSmrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22b042e37fSmrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23b042e37fSmrg *
24b042e37fSmrg * Author:  Jim Gettys, HP Labs, HP.
25b042e37fSmrg */
26b042e37fSmrg
27b042e37fSmrg#ifdef HAVE_CONFIG_H
28b042e37fSmrg#include <config.h>
29b042e37fSmrg#endif
30b042e37fSmrg
31b042e37fSmrg#include <stdio.h>
32b042e37fSmrg#include <X11/Xlib.h>
33b042e37fSmrg/* we need to be able to manipulate the Display structure on events */
34b042e37fSmrg#include <X11/Xlibint.h>
35b042e37fSmrg#include <X11/extensions/render.h>
36b042e37fSmrg#include <X11/extensions/Xrender.h>
37b042e37fSmrg#include "Xrandrint.h"
38b042e37fSmrg
39b042e37fSmrgXExtensionInfo XRRExtensionInfo;
40b042e37fSmrgchar XRRExtensionName[] = RANDR_NAME;
41b042e37fSmrg
42b042e37fSmrgstatic Bool     XRRWireToEvent(Display *dpy, XEvent *event, xEvent *wire);
43b042e37fSmrgstatic Status   XRREventToWire(Display *dpy, XEvent *event, xEvent *wire);
44b042e37fSmrg
45b042e37fSmrgstatic int
46b042e37fSmrgXRRCloseDisplay (Display *dpy, XExtCodes *codes);
47b042e37fSmrg
48b042e37fSmrgstatic /* const */ XExtensionHooks rr_extension_hooks = {
49b042e37fSmrg    NULL,				/* create_gc */
50b042e37fSmrg    NULL,				/* copy_gc */
51b042e37fSmrg    NULL,				/* flush_gc */
52b042e37fSmrg    NULL,				/* free_gc */
53b042e37fSmrg    NULL,				/* create_font */
54b042e37fSmrg    NULL,				/* free_font */
55b042e37fSmrg    XRRCloseDisplay,			/* close_display */
56b042e37fSmrg    XRRWireToEvent,			/* wire_to_event */
57b042e37fSmrg    XRREventToWire,			/* event_to_wire */
58b042e37fSmrg    NULL,				/* error */
59b042e37fSmrg    NULL,				/* error_string */
60b042e37fSmrg};
61b042e37fSmrg
62b042e37fSmrgstatic Bool XRRWireToEvent(Display *dpy, XEvent *event, xEvent *wire)
63b042e37fSmrg{
64b042e37fSmrg    XExtDisplayInfo *info = XRRFindDisplay(dpy);
65b042e37fSmrg
66b042e37fSmrg    RRCheckExtension(dpy, info, False);
67b042e37fSmrg
68b042e37fSmrg    switch ((wire->u.u.type & 0x7F) - info->codes->first_event)
69b042e37fSmrg    {
70b042e37fSmrg      case RRScreenChangeNotify: {
71b042e37fSmrg	XRRScreenChangeNotifyEvent *aevent= (XRRScreenChangeNotifyEvent *) event;
72b042e37fSmrg	xRRScreenChangeNotifyEvent *awire = (xRRScreenChangeNotifyEvent *) wire;
73b042e37fSmrg	aevent->type = awire->type & 0x7F;
74b042e37fSmrg	aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
75b042e37fSmrg	aevent->send_event = (awire->type & 0x80) != 0;
76b042e37fSmrg	aevent->display = dpy;
77b042e37fSmrg	aevent->window = awire->window;
78b042e37fSmrg	aevent->root = awire->root;
79b042e37fSmrg	aevent->timestamp = awire->timestamp;
80b042e37fSmrg	aevent->config_timestamp = awire->configTimestamp;
81b042e37fSmrg	aevent->size_index = awire->sizeID;
82b042e37fSmrg	aevent->subpixel_order = awire->subpixelOrder;
83b042e37fSmrg	aevent->rotation = awire->rotation;
84b042e37fSmrg	aevent->width = awire->widthInPixels;
85b042e37fSmrg	aevent->height = awire->heightInPixels;
86b042e37fSmrg	aevent->mwidth = awire->widthInMillimeters;
87b042e37fSmrg	aevent->mheight = awire->heightInMillimeters;
88b042e37fSmrg	return True;
89b042e37fSmrg      }
90b042e37fSmrg      case RRNotify: {
91b042e37fSmrg	XRRNotifyEvent *aevent = (XRRNotifyEvent *) event;
92b042e37fSmrg	xRRCrtcChangeNotifyEvent *awire = (xRRCrtcChangeNotifyEvent *) wire;
93b042e37fSmrg	aevent->type = awire->type & 0x7F;
94b042e37fSmrg	aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
95b042e37fSmrg	aevent->send_event = (awire->type & 0x80) != 0;
96b042e37fSmrg	aevent->display = dpy;
97b042e37fSmrg	aevent->window = awire->window;
98b042e37fSmrg	aevent->subtype = awire->subCode;
99b042e37fSmrg	switch (aevent->subtype) {
100b042e37fSmrg	case RRNotify_OutputChange: {
101b042e37fSmrg	    XRROutputChangeNotifyEvent *aevent = (XRROutputChangeNotifyEvent *) event;
102b042e37fSmrg	    xRROutputChangeNotifyEvent *awire = (xRROutputChangeNotifyEvent *) wire;
103b042e37fSmrg	    aevent->output = awire->output;
104b042e37fSmrg	    aevent->crtc = awire->crtc;
105b042e37fSmrg	    aevent->mode = awire->mode;
106b042e37fSmrg	    aevent->rotation = awire->rotation;
107b042e37fSmrg	    aevent->connection = awire->connection;
108b042e37fSmrg	    aevent->subpixel_order = awire->subpixelOrder;
109b042e37fSmrg	    return True;
110b042e37fSmrg	}
111b042e37fSmrg	case RRNotify_CrtcChange: {
112b042e37fSmrg	    XRRCrtcChangeNotifyEvent *aevent = (XRRCrtcChangeNotifyEvent *) event;
113b042e37fSmrg	    xRRCrtcChangeNotifyEvent *awire = (xRRCrtcChangeNotifyEvent *) wire;
114b042e37fSmrg	    aevent->crtc = awire->crtc;
115b042e37fSmrg	    aevent->mode = awire->mode;
116b042e37fSmrg	    aevent->rotation = awire->rotation;
117b042e37fSmrg	    aevent->x = awire->x;
118b042e37fSmrg	    aevent->y = awire->y;
119b042e37fSmrg	    aevent->width = awire->width;
120b042e37fSmrg	    aevent->height = awire->height;
121b042e37fSmrg	    return True;
122b042e37fSmrg	}
123b042e37fSmrg	case RRNotify_OutputProperty: {
124b042e37fSmrg	    XRROutputPropertyNotifyEvent *aevent = (XRROutputPropertyNotifyEvent *) event;
125b042e37fSmrg	    xRROutputPropertyNotifyEvent *awire = (xRROutputPropertyNotifyEvent *) wire;
126b042e37fSmrg	    aevent->output = awire->output;
127b042e37fSmrg	    aevent->property = awire->atom;
128b042e37fSmrg	    aevent->timestamp = awire->timestamp;
129b042e37fSmrg	    aevent->state = awire->state;
130b042e37fSmrg	    return True;
131b042e37fSmrg	}
132b042e37fSmrg
133b042e37fSmrg	    break;
134b042e37fSmrg	}
135b042e37fSmrg      }
136b042e37fSmrg    }
137b042e37fSmrg
138b042e37fSmrg    return False;
139b042e37fSmrg}
140b042e37fSmrg
141b042e37fSmrgstatic Status XRREventToWire(Display *dpy, XEvent *event, xEvent *wire)
142b042e37fSmrg{
143b042e37fSmrg    XExtDisplayInfo *info = XRRFindDisplay(dpy);
144b042e37fSmrg
145b042e37fSmrg    RRCheckExtension(dpy, info, False);
146b042e37fSmrg
147b042e37fSmrg    switch ((event->type & 0x7F) - info->codes->first_event)
148b042e37fSmrg    {
149b042e37fSmrg      case RRScreenChangeNotify: {
150b042e37fSmrg	xRRScreenChangeNotifyEvent *awire = (xRRScreenChangeNotifyEvent *) wire;
151b042e37fSmrg	XRRScreenChangeNotifyEvent *aevent = (XRRScreenChangeNotifyEvent *) event;
152b042e37fSmrg	awire->type = aevent->type | (aevent->send_event ? 0x80 : 0);
153b042e37fSmrg	awire->rotation = (CARD8) aevent->rotation;
154b042e37fSmrg	awire->sequenceNumber = aevent->serial & 0xFFFF;
155b042e37fSmrg	awire->timestamp = aevent->timestamp;
156b042e37fSmrg	awire->configTimestamp = aevent->config_timestamp;
157b042e37fSmrg	awire->root = aevent->root;
158b042e37fSmrg	awire->window = aevent->window;
159b042e37fSmrg	awire->sizeID = aevent->size_index;
160b042e37fSmrg	awire->subpixelOrder = aevent->subpixel_order;
161b042e37fSmrg	awire->widthInPixels = aevent->width;
162b042e37fSmrg	awire->heightInPixels = aevent->height;
163b042e37fSmrg	awire->widthInMillimeters = aevent->mwidth;
164b042e37fSmrg	awire->heightInMillimeters = aevent->mheight;
165b042e37fSmrg	return True;
166b042e37fSmrg      }
167b042e37fSmrg      case RRNotify: {
168b042e37fSmrg	xRRCrtcChangeNotifyEvent *awire = (xRRCrtcChangeNotifyEvent *) wire;
169b042e37fSmrg	XRRNotifyEvent *aevent = (XRRNotifyEvent *) event;
170b042e37fSmrg	awire->type = aevent->type | (aevent->send_event ? 0x80 : 0);
171b042e37fSmrg	awire->sequenceNumber = aevent->serial & 0xFFFF;
172b042e37fSmrg	awire->window = aevent->window;
173b042e37fSmrg	awire->subCode = aevent->subtype;
174b042e37fSmrg	switch (aevent->subtype) {
175b042e37fSmrg	case RRNotify_OutputChange: {
176b042e37fSmrg	    xRROutputChangeNotifyEvent *awire = (xRROutputChangeNotifyEvent *) wire;
177b042e37fSmrg	    XRROutputChangeNotifyEvent *aevent = (XRROutputChangeNotifyEvent *) event;
178b042e37fSmrg	    awire->output = aevent->output;
179b042e37fSmrg	    awire->crtc = aevent->crtc;
180b042e37fSmrg	    awire->mode = aevent->mode;
181b042e37fSmrg	    awire->rotation = aevent->rotation;
182b042e37fSmrg	    awire->connection = aevent->connection;
183b042e37fSmrg	    awire->subpixelOrder = aevent->subpixel_order;
184b042e37fSmrg	    return True;
185b042e37fSmrg	}
186b042e37fSmrg	case RRNotify_CrtcChange: {
187b042e37fSmrg	    xRRCrtcChangeNotifyEvent *awire = (xRRCrtcChangeNotifyEvent *) wire;
188b042e37fSmrg	    XRRCrtcChangeNotifyEvent *aevent = (XRRCrtcChangeNotifyEvent *) event;
189b042e37fSmrg	    awire->crtc = aevent->crtc;
190b042e37fSmrg	    awire->mode = aevent->mode;
191b042e37fSmrg	    awire->rotation = aevent->rotation;
192b042e37fSmrg	    awire->x = aevent->x;
193b042e37fSmrg	    awire->y = aevent->y;
194b042e37fSmrg	    awire->width = aevent->width;
195b042e37fSmrg	    awire->height = aevent->height;
196b042e37fSmrg	    return True;
197b042e37fSmrg	}
198b042e37fSmrg	case RRNotify_OutputProperty: {
199b042e37fSmrg	    xRROutputPropertyNotifyEvent *awire = (xRROutputPropertyNotifyEvent *) wire;
200b042e37fSmrg	    XRROutputPropertyNotifyEvent *aevent = (XRROutputPropertyNotifyEvent *) event;
201b042e37fSmrg	    awire->output = aevent->output;
202b042e37fSmrg	    awire->atom = aevent->property;
203b042e37fSmrg	    awire->timestamp = aevent->timestamp;
204b042e37fSmrg	    awire->state = aevent->state;
205b042e37fSmrg	    return True;
206b042e37fSmrg	}
207b042e37fSmrg	}
208b042e37fSmrg      }
209b042e37fSmrg    }
210b042e37fSmrg    return False;
211b042e37fSmrg}
212b042e37fSmrg
213b042e37fSmrgXExtDisplayInfo *
214b042e37fSmrgXRRFindDisplay (Display *dpy)
215b042e37fSmrg{
216b042e37fSmrg    XExtDisplayInfo *dpyinfo;
217b042e37fSmrg    XRandRInfo *xrri;
218b042e37fSmrg    int i, numscreens;
219b042e37fSmrg
220b042e37fSmrg    dpyinfo = XextFindDisplay (&XRRExtensionInfo, dpy);
221b042e37fSmrg    if (!dpyinfo) {
222b042e37fSmrg	dpyinfo = XextAddDisplay (&XRRExtensionInfo, dpy,
223b042e37fSmrg				  XRRExtensionName,
224b042e37fSmrg				  &rr_extension_hooks,
225b042e37fSmrg				  RRNumberEvents, 0);
226b042e37fSmrg	numscreens = ScreenCount(dpy);
227b042e37fSmrg	xrri = Xmalloc (sizeof(XRandRInfo) +
228b042e37fSmrg				 sizeof(char *) * numscreens);
229b042e37fSmrg	xrri->config = (XRRScreenConfiguration **)(xrri + 1);
230b042e37fSmrg	for(i = 0; i < numscreens; i++)
231b042e37fSmrg	  xrri->config[i] = NULL;
232b042e37fSmrg	xrri->major_version = -1;
233b042e37fSmrg	dpyinfo->data = (char *) xrri;
234b042e37fSmrg    }
235b042e37fSmrg    return dpyinfo;
236b042e37fSmrg}
237b042e37fSmrg
238b042e37fSmrgstatic int
239b042e37fSmrgXRRCloseDisplay (Display *dpy, XExtCodes *codes)
240b042e37fSmrg{
241b042e37fSmrg    int i;
242b042e37fSmrg    XRRScreenConfiguration **configs;
243b042e37fSmrg    XExtDisplayInfo *info = XRRFindDisplay (dpy);
244b042e37fSmrg    XRandRInfo *xrri;
245b042e37fSmrg
246b042e37fSmrg    LockDisplay(dpy);
247b042e37fSmrg    /*
248b042e37fSmrg     * free cached data
249b042e37fSmrg     */
250b042e37fSmrg    if (XextHasExtension(info)) {
251b042e37fSmrg	xrri = (XRandRInfo *) info->data;
252b042e37fSmrg	if (xrri) {
253b042e37fSmrg	    configs = xrri->config;
254b042e37fSmrg
255b042e37fSmrg	    for (i = 0; i < ScreenCount(dpy); i++) {
256b042e37fSmrg		if (configs[i] != NULL) XFree (configs[i]);
257b042e37fSmrg	    }
258b042e37fSmrg	    XFree (xrri);
259b042e37fSmrg	}
260b042e37fSmrg    }
261b042e37fSmrg    UnlockDisplay(dpy);
262b042e37fSmrg    return XextRemoveDisplay (&XRRExtensionInfo, dpy);
263b042e37fSmrg}
264b042e37fSmrg
265b042e37fSmrgint XRRRootToScreen(Display *dpy, Window root)
266b042e37fSmrg{
267b042e37fSmrg  int snum;
268b042e37fSmrg  for (snum = 0; snum < ScreenCount(dpy); snum++) {
269b042e37fSmrg    if (RootWindow(dpy, snum) == root) return snum;
270b042e37fSmrg  }
271b042e37fSmrg  return -1;
272b042e37fSmrg}
273b042e37fSmrg
274b042e37fSmrg
275b042e37fSmrgBool XRRQueryExtension (Display *dpy, int *event_basep, int *error_basep)
276b042e37fSmrg{
277b042e37fSmrg  XExtDisplayInfo *info = XRRFindDisplay (dpy);
278b042e37fSmrg
279b042e37fSmrg    if (XextHasExtension(info)) {
280b042e37fSmrg	*event_basep = info->codes->first_event;
281b042e37fSmrg	*error_basep = info->codes->first_error;
282b042e37fSmrg	return True;
283b042e37fSmrg    } else {
284b042e37fSmrg	return False;
285b042e37fSmrg    }
286b042e37fSmrg}
287b042e37fSmrg
288b042e37fSmrgBool
289b042e37fSmrg_XRRHasRates (int major, int minor)
290b042e37fSmrg{
291b042e37fSmrg    return major > 1 || (major == 1 && minor >= 1);
292b042e37fSmrg}
293b042e37fSmrg
294b042e37fSmrgStatus XRRQueryVersion (Display *dpy,
295b042e37fSmrg			    int	    *major_versionp,
296b042e37fSmrg			    int	    *minor_versionp)
297b042e37fSmrg{
298b042e37fSmrg    XExtDisplayInfo *info = XRRFindDisplay (dpy);
299b042e37fSmrg    xRRQueryVersionReply rep;
300b042e37fSmrg    xRRQueryVersionReq  *req;
301b042e37fSmrg    XRandRInfo *xrri;
302b042e37fSmrg
303b042e37fSmrg    RRCheckExtension (dpy, info, 0);
304b042e37fSmrg
305b042e37fSmrg    xrri = (XRandRInfo *) info->data;
306b042e37fSmrg
307b042e37fSmrg    /*
308b042e37fSmrg     * only get the version information from the server if we don't have it already
309b042e37fSmrg     */
310b042e37fSmrg    if (xrri->major_version == -1) {
311b042e37fSmrg      LockDisplay (dpy);
312b042e37fSmrg      GetReq (RRQueryVersion, req);
313b042e37fSmrg      req->reqType = info->codes->major_opcode;
314b042e37fSmrg      req->randrReqType = X_RRQueryVersion;
315b042e37fSmrg      req->majorVersion = RANDR_MAJOR;
316b042e37fSmrg      req->minorVersion = RANDR_MINOR;
317b042e37fSmrg      if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
318b042e37fSmrg	UnlockDisplay (dpy);
319b042e37fSmrg	SyncHandle ();
320b042e37fSmrg	return 0;
321b042e37fSmrg      }
322b042e37fSmrg      xrri->major_version = rep.majorVersion;
323b042e37fSmrg      xrri->minor_version = rep.minorVersion;
324b042e37fSmrg      xrri->has_rates = _XRRHasRates (xrri->major_version, xrri->minor_version);
325b042e37fSmrg      UnlockDisplay (dpy);
326b042e37fSmrg      SyncHandle ();
327b042e37fSmrg    }
328b042e37fSmrg    *major_versionp = xrri->major_version;
329b042e37fSmrg    *minor_versionp = xrri->minor_version;
330b042e37fSmrg    return 1;
331b042e37fSmrg}
332b042e37fSmrg
333b042e37fSmrgBool
334b042e37fSmrg_XRRVersionHandler (Display	    *dpy,
335b042e37fSmrg			xReply	    *rep,
336b042e37fSmrg			char	    *buf,
337b042e37fSmrg			int	    len,
338b042e37fSmrg			XPointer    data)
339b042e37fSmrg{
340b042e37fSmrg    xRRQueryVersionReply	replbuf;
341b042e37fSmrg    xRRQueryVersionReply	*repl;
342b042e37fSmrg    _XRRVersionState	*state = (_XRRVersionState *) data;
343b042e37fSmrg
344b042e37fSmrg    if (dpy->last_request_read != state->version_seq)
345b042e37fSmrg	return False;
346b042e37fSmrg    if (rep->generic.type == X_Error)
347b042e37fSmrg    {
348b042e37fSmrg	state->error = True;
349b042e37fSmrg	return False;
350b042e37fSmrg    }
351b042e37fSmrg    repl = (xRRQueryVersionReply *)
352b042e37fSmrg	_XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
353b042e37fSmrg		     (SIZEOF(xRRQueryVersionReply) - SIZEOF(xReply)) >> 2,
354b042e37fSmrg			True);
355b042e37fSmrg    state->major_version = repl->majorVersion;
356b042e37fSmrg    state->minor_version = repl->minorVersion;
357b042e37fSmrg    return True;
358b042e37fSmrg}
359b042e37fSmrg
360b042e37fSmrg/*
361b042e37fSmrg * in protocol version 0.1, routine added to allow selecting for new events.
362b042e37fSmrg */
363b042e37fSmrg
364b042e37fSmrgvoid XRRSelectInput (Display *dpy, Window window, int mask)
365b042e37fSmrg{
366b042e37fSmrg    XExtDisplayInfo *info = XRRFindDisplay (dpy);
367b042e37fSmrg    xRRSelectInputReq  *req;
368b042e37fSmrg
369b042e37fSmrg    RRSimpleCheckExtension (dpy, info);
370b042e37fSmrg
371b042e37fSmrg    LockDisplay (dpy);
372b042e37fSmrg    GetReq (RRSelectInput, req);
373b042e37fSmrg    req->reqType = info->codes->major_opcode;
374b042e37fSmrg    req->randrReqType = X_RRSelectInput;
375b042e37fSmrg    req->window = window;
376b042e37fSmrg    req->enable = 0;
377b042e37fSmrg    if (mask) req->enable = mask;
378b042e37fSmrg    UnlockDisplay (dpy);
379b042e37fSmrg    SyncHandle ();
380b042e37fSmrg    return;
381b042e37fSmrg}
382b042e37fSmrg
383b042e37fSmrgint XRRUpdateConfiguration(XEvent *event)
384b042e37fSmrg{
385b042e37fSmrg    XRRScreenChangeNotifyEvent *scevent;
386b042e37fSmrg    XConfigureEvent *rcevent;
387b042e37fSmrg    Display *dpy = event->xany.display;
388b042e37fSmrg    XExtDisplayInfo *info;
389b042e37fSmrg    XRandRInfo *xrri;
390b042e37fSmrg    int snum;
391b042e37fSmrg
392b042e37fSmrg    /* first, see if it is a vanilla configure notify event */
393b042e37fSmrg    if (event->type == ConfigureNotify) {
394b042e37fSmrg	rcevent = (XConfigureEvent *) event;
395b042e37fSmrg	snum = XRRRootToScreen(dpy, rcevent->window);
396b042e37fSmrg	dpy->screens[snum].width   = rcevent->width;
397b042e37fSmrg	dpy->screens[snum].height  = rcevent->height;
398b042e37fSmrg	return 1;
399b042e37fSmrg    }
400b042e37fSmrg
401b042e37fSmrg    info = XRRFindDisplay(dpy);
402b042e37fSmrg    RRCheckExtension (dpy, info, 0);
403b042e37fSmrg
404b042e37fSmrg    switch (event->type - info->codes->first_event) {
405b042e37fSmrg    case RRScreenChangeNotify:
406b042e37fSmrg	scevent = (XRRScreenChangeNotifyEvent *) event;
407b042e37fSmrg	snum = XRRRootToScreen(dpy,
408b042e37fSmrg			       ((XRRScreenChangeNotifyEvent *) event)->root);
409b042e37fSmrg	if (scevent->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
410b042e37fSmrg		dpy->screens[snum].width   = scevent->height;
411b042e37fSmrg		dpy->screens[snum].height  = scevent->width;
412b042e37fSmrg		dpy->screens[snum].mwidth  = scevent->mheight;
413b042e37fSmrg		dpy->screens[snum].mheight = scevent->mwidth;
414b042e37fSmrg	} else {
415b042e37fSmrg		dpy->screens[snum].width   = scevent->width;
416b042e37fSmrg		dpy->screens[snum].height  = scevent->height;
417b042e37fSmrg		dpy->screens[snum].mwidth  = scevent->mwidth;
418b042e37fSmrg		dpy->screens[snum].mheight = scevent->mheight;
419b042e37fSmrg	}
420b042e37fSmrg	XRenderSetSubpixelOrder (dpy, snum, scevent->subpixel_order);
421b042e37fSmrg	break;
422b042e37fSmrg    default:
423b042e37fSmrg	return 0;
424b042e37fSmrg    }
425b042e37fSmrg    xrri = (XRandRInfo *) info->data;
426b042e37fSmrg    /*
427b042e37fSmrg     * so the next time someone wants some data, it will be fetched;
428b042e37fSmrg     * it might be better to force the round trip immediately, but
429b042e37fSmrg     * I dislike pounding the server simultaneously when not necessary
430b042e37fSmrg     */
431b042e37fSmrg    if (xrri->config[snum] != NULL) {
432b042e37fSmrg	XFree (xrri->config[snum]);
433b042e37fSmrg	xrri->config[snum] = NULL;
434b042e37fSmrg    }
435b042e37fSmrg    return 1;
436b042e37fSmrg}
437