/*
* $XFree86: xc/lib/Xrandr/Xrandr.c,v 1.13tsi Exp $
*
* Copyright © 2000 Compaq Computer Corporation, Inc.
* Copyright © 2002 Hewlett Packard Company, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Compaq or HP not be used in advertising
* or publicity pertaining to distribution of the software without specific,
* written prior permission. HP makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* HP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL COMPAQ
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Author: Jim Gettys, HP Labs, HP.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <X11/Xlib.h>
/* we need to be able to manipulate the Display structure on events */
#include <X11/Xlibint.h>
#include <X11/extensions/render.h>
#include <X11/extensions/Xrender.h>
#include "Xrandrint.h"
XExtensionInfo XRRExtensionInfo;
char XRRExtensionName[] = RANDR_NAME;
static Bool XRRWireToEvent(Display *dpy, XEvent *event, xEvent *wire);
static Status XRREventToWire(Display *dpy, XEvent *event, xEvent *wire);
static int
XRRCloseDisplay (Display *dpy, XExtCodes *codes);
static /* const */ XExtensionHooks rr_extension_hooks = {
NULL, /* create_gc */
NULL, /* copy_gc */
NULL, /* flush_gc */
NULL, /* free_gc */
NULL, /* create_font */
NULL, /* free_font */
XRRCloseDisplay, /* close_display */
XRRWireToEvent, /* wire_to_event */
XRREventToWire, /* event_to_wire */
NULL, /* error */
NULL, /* error_string */
};
static Bool XRRWireToEvent(Display *dpy, XEvent *event, xEvent *wire)
{
XExtDisplayInfo *info = XRRFindDisplay(dpy);
RRCheckExtension(dpy, info, False);
switch ((wire->u.u.type & 0x7F) - info->codes->first_event)
{
case RRScreenChangeNotify: {
XRRScreenChangeNotifyEvent *aevent= (XRRScreenChangeNotifyEvent *) event;
xRRScreenChangeNotifyEvent *awire = (xRRScreenChangeNotifyEvent *) wire;
aevent->type = awire->type & 0x7F;
aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
aevent->send_event = (awire->type & 0x80) != 0;
aevent->display = dpy;
aevent->window = awire->window;
aevent->root = awire->root;
aevent->timestamp = awire->timestamp;
aevent->config_timestamp = awire->configTimestamp;
aevent->size_index = awire->sizeID;
aevent->subpixel_order = awire->subpixelOrder;
aevent->rotation = awire->rotation;
aevent->width = awire->widthInPixels;
aevent->height = awire->heightInPixels;
aevent->mwidth = awire->widthInMillimeters;
aevent->mheight = awire->heightInMillimeters;
return True;
}
case RRNotify: {
XRRNotifyEvent *aevent = (XRRNotifyEvent *) event;
xRRCrtcChangeNotifyEvent *awire = (xRRCrtcChangeNotifyEvent *) wire;
aevent->type = awire->type & 0x7F;
aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
aevent->send_event = (awire->type & 0x80) != 0;
aevent->display = dpy;
aevent->window = awire->window;
aevent->subtype = awire->subCode;
switch (aevent->subtype) {
case RRNotify_OutputChange: {
XRROutputChangeNotifyEvent *aevent = (XRROutputChangeNotifyEvent *) event;
xRROutputChangeNotifyEvent *awire = (xRROutputChangeNotifyEvent *) wire;
aevent->output = awire->output;
aevent->crtc = awire->crtc;
aevent->mode = awire->mode;
aevent->rotation = awire->rotation;
aevent->connection = awire->connection;
aevent->subpixel_order = awire->subpixelOrder;
return True;
}
case RRNotify_CrtcChange: {
XRRCrtcChangeNotifyEvent *aevent = (XRRCrtcChangeNotifyEvent *) event;
xRRCrtcChangeNotifyEvent *awire = (xRRCrtcChangeNotifyEvent *) wire;
aevent->crtc = awire->crtc;
aevent->mode = awire->mode;
aevent->rotation = awire->rotation;
aevent->x = awire->x;
aevent->y = awire->y;
aevent->width = awire->width;
aevent->height = awire->height;
return True;
}
case RRNotify_OutputProperty: {
XRROutputPropertyNotifyEvent *aevent = (XRROutputPropertyNotifyEvent *) event;
xRROutputPropertyNotifyEvent *awire = (xRROutputPropertyNotifyEvent *) wire;
aevent->output = awire->output;
aevent->property = awire->atom;
aevent->timestamp = awire->timestamp;
aevent->state = awire->state;
return True;
}
break;
}
}
}
return False;
}
static Status XRREventToWire(Display *dpy, XEvent *event, xEvent *wire)
{
XExtDisplayInfo *info = XRRFindDisplay(dpy);
RRCheckExtension(dpy, info, False);
switch ((event->type & 0x7F) - info->codes->first_event)
{
case RRScreenChangeNotify: {
xRRScreenChangeNotifyEvent *awire = (xRRScreenChangeNotifyEvent *) wire;
XRRScreenChangeNotifyEvent *aevent = (XRRScreenChangeNotifyEvent *) event;
awire->type = aevent->type | (aevent->send_event ? 0x80 : 0);
awire->rotation = (CARD8) aevent->rotation;
awire->sequenceNumber = aevent->serial & 0xFFFF;
awire->timestamp = aevent->timestamp;
awire->configTimestamp = aevent->config_timestamp;
awire->root = aevent->root;
awire->window = aevent->window;
awire->sizeID = aevent->size_index;
awire->subpixelOrder = aevent->subpixel_order;
awire->widthInPixels = aevent->width;
awire->heightInPixels = aevent->height;
awire->widthInMillimeters = aevent->mwidth;
awire->heightInMillimeters = aevent->mheight;
return True;
}
case RRNotify: {
xRRCrtcChangeNotifyEvent *awire = (xRRCrtcChangeNotifyEvent *) wire;
XRRNotifyEvent *aevent = (XRRNotifyEvent *) event;
awire->type = aevent->type | (aevent->send_event ? 0x80 : 0);
awire->sequenceNumber = aevent->serial & 0xFFFF;
awire->window = aevent->window;
awire->subCode = aevent->subtype;
switch (aevent->subtype) {
case RRNotify_OutputChange: {
xRROutputChangeNotifyEvent *awire = (xRROutputChangeNotifyEvent *) wire;
XRROutputChangeNotifyEvent *aevent = (XRROutputChangeNotifyEvent *) event;
awire->output = aevent->output;
awire->crtc = aevent->crtc;
awire->mode = aevent->mode;
awire->rotation = aevent->rotation;
awire->connection = aevent->connection;
awire->subpixelOrder = aevent->subpixel_order;
return True;
}
case RRNotify_CrtcChange: {
xRRCrtcChangeNotifyEvent *awire = (xRRCrtcChangeNotifyEvent *) wire;
XRRCrtcChangeNotifyEvent *aevent = (XRRCrtcChangeNotifyEvent *) event;
awire->crtc = aevent->crtc;
awire->mode = aevent->mode;
awire->rotation = aevent->rotation;
awire->x = aevent->x;
awire->y = aevent->y;
awire->width = aevent->width;
awire->height = aevent->height;
return True;
}
case RRNotify_OutputProperty: {
xRROutputPropertyNotifyEvent *awire = (xRROutputPropertyNotifyEvent *) wire;
XRROutputPropertyNotifyEvent *aevent = (XRROutputPropertyNotifyEvent *) event;
awire->output = aevent->output;
awire->atom = aevent->property;
awire->timestamp = aevent->timestamp;
awire->state = aevent->state;
return True;
}
}
}
}
return False;
}
XExtDisplayInfo *
XRRFindDisplay (Display *dpy)
{
XExtDisplayInfo *dpyinfo;
XRandRInfo *xrri;
int i, numscreens;
dpyinfo = XextFindDisplay (&XRRExtensionInfo, dpy);
if (!dpyinfo) {
dpyinfo = XextAddDisplay (&XRRExtensionInfo, dpy,
XRRExtensionName,
&rr_extension_hooks,
RRNumberEvents, 0);
numscreens = ScreenCount(dpy);
xrri = Xmalloc (sizeof(XRandRInfo) +
sizeof(char *) * numscreens);
xrri->config = (XRRScreenConfiguration **)(xrri + 1);
for(i = 0; i < numscreens; i++)
xrri->config[i] = NULL;
xrri->major_version = -1;
dpyinfo->data = (char *) xrri;
}
return dpyinfo;
}
static int
XRRCloseDisplay (Display *dpy, XExtCodes *codes)
{
int i;
XRRScreenConfiguration **configs;
XExtDisplayInfo *info = XRRFindDisplay (dpy);
XRandRInfo *xrri;
LockDisplay(dpy);
/*
* free cached data
*/
if (XextHasExtension(info)) {
xrri = (XRandRInfo *) info->data;
if (xrri) {
configs = xrri->config;
for (i = 0; i < ScreenCount(dpy); i++) {
if (configs[i] != NULL) XFree (configs[i]);
}
XFree (xrri);
}
}
UnlockDisplay(dpy);
return XextRemoveDisplay (&XRRExtensionInfo, dpy);
}
int XRRRootToScreen(Display *dpy, Window root)
{
int snum;
for (snum = 0; snum < ScreenCount(dpy); snum++) {
if (RootWindow(dpy, snum) == root) return snum;
}
return -1;
}
Bool XRRQueryExtension (Display *dpy, int *event_basep, int *error_basep)
{
XExtDisplayInfo *info = XRRFindDisplay (dpy);
if (XextHasExtension(info)) {
*event_basep = info->codes->first_event;
*error_basep = info->codes->first_error;
return True;
} else {
return False;
}
}
Bool
_XRRHasRates (int major, int minor)
{
return major > 1 || (major == 1 && minor >= 1);
}
Status XRRQueryVersion (Display *dpy,
int *major_versionp,
int *minor_versionp)
{
XExtDisplayInfo *info = XRRFindDisplay (dpy);
xRRQueryVersionReply rep;
xRRQueryVersionReq *req;
XRandRInfo *xrri;
RRCheckExtension (dpy, info, 0);
xrri = (XRandRInfo *) info->data;
/*
* only get the version information from the server if we don't have it already
*/
if (xrri->major_version == -1) {
LockDisplay (dpy);
GetReq (RRQueryVersion, req);
req->reqType = info->codes->major_opcode;
req->randrReqType = X_RRQueryVersion;
req->majorVersion = RANDR_MAJOR;
req->minorVersion = RANDR_MINOR;
if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
UnlockDisplay (dpy);
SyncHandle ();
return 0;
}
xrri->major_version = rep.majorVersion;
xrri->minor_version = rep.minorVersion;
xrri->has_rates = _XRRHasRates (xrri->major_version, xrri->minor_version);
UnlockDisplay (dpy);
SyncHandle ();
}
*major_versionp = xrri->major_version;
*minor_versionp = xrri->minor_version;
return 1;
}
Bool
_XRRVersionHandler (Display *dpy,
xReply *rep,
char *buf,
int len,
XPointer data)
{
xRRQueryVersionReply replbuf;
xRRQueryVersionReply *repl;
_XRRVersionState *state = (_XRRVersionState *) data;
if (dpy->last_request_read != state->version_seq)
return False;
if (rep->generic.type == X_Error)
{
state->error = True;
return False;
}
repl = (xRRQueryVersionReply *)
_XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
(SIZEOF(xRRQueryVersionReply) - SIZEOF(xReply)) >> 2,
True);
state->major_version = repl->majorVersion;
state->minor_version = repl->minorVersion;
return True;
}
/*
* in protocol version 0.1, routine added to allow selecting for new events.
*/
void XRRSelectInput (Display *dpy, Window window, int mask)
{
XExtDisplayInfo *info = XRRFindDisplay (dpy);
xRRSelectInputReq *req;
RRSimpleCheckExtension (dpy, info);
LockDisplay (dpy);
GetReq (RRSelectInput, req);
req->reqType = info->codes->major_opcode;
req->randrReqType = X_RRSelectInput;
req->window = window;
req->enable = 0;
if (mask) req->enable = mask;
UnlockDisplay (dpy);
SyncHandle ();
return;
}
int XRRUpdateConfiguration(XEvent *event)
{
XRRScreenChangeNotifyEvent *scevent;
XConfigureEvent *rcevent;
Display *dpy = event->xany.display;
XExtDisplayInfo *info;
XRandRInfo *xrri;
int snum;
/* first, see if it is a vanilla configure notify event */
if (event->type == ConfigureNotify) {
rcevent = (XConfigureEvent *) event;
snum = XRRRootToScreen(dpy, rcevent->window);
dpy->screens[snum].width = rcevent->width;
dpy->screens[snum].height = rcevent->height;
return 1;
}
info = XRRFindDisplay(dpy);
RRCheckExtension (dpy, info, 0);
switch (event->type - info->codes->first_event) {
case RRScreenChangeNotify:
scevent = (XRRScreenChangeNotifyEvent *) event;
snum = XRRRootToScreen(dpy,
((XRRScreenChangeNotifyEvent *) event)->root);
if (scevent->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
dpy->screens[snum].width = scevent->height;
dpy->screens[snum].height = scevent->width;
dpy->screens[snum].mwidth = scevent->mheight;
dpy->screens[snum].mheight = scevent->mwidth;
} else {
dpy->screens[snum].width = scevent->width;
dpy->screens[snum].height = scevent->height;
dpy->screens[snum].mwidth = scevent->mwidth;
dpy->screens[snum].mheight = scevent->mheight;
}
XRenderSetSubpixelOrder (dpy, snum, scevent->subpixel_order);
break;
default:
return 0;
}
xrri = (XRandRInfo *) info->data;
/*
* so the next time someone wants some data, it will be fetched;
* it might be better to force the round trip immediately, but
* I dislike pounding the server simultaneously when not necessary
*/
if (xrri->config[snum] != NULL) {
XFree (xrri->config[snum]);
xrri->config[snum] = NULL;
}
return 1;
}
|