282 lines
8.0 KiB
C
282 lines
8.0 KiB
C
/*
|
|
* Copyright © 2006 Keith Packard
|
|
*
|
|
* 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 the copyright holders not be used in advertising or
|
|
* publicity pertaining to distribution of the software without specific,
|
|
* written prior permission. The copyright holders make no representations
|
|
* about the suitability of this software for any purpose. It is provided "as
|
|
* is" without express or implied warranty.
|
|
*
|
|
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
* EVENT SHALL THE COPYRIGHT HOLDERS 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.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <limits.h>
|
|
#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"
|
|
|
|
/*
|
|
* this is cheating on the knowledge that the two requests are identical
|
|
* but for the request number.
|
|
*/
|
|
static XRRScreenResources *
|
|
doGetScreenResources (Display *dpy, Window window, int poll)
|
|
{
|
|
XExtDisplayInfo *info = XRRFindDisplay(dpy);
|
|
xRRGetScreenResourcesReply rep;
|
|
xRRGetScreenResourcesReq *req;
|
|
_XAsyncHandler async;
|
|
_XRRVersionState async_state;
|
|
int nbytes, nbytesRead, rbytes;
|
|
int i;
|
|
xRRQueryVersionReq *vreq;
|
|
XRRScreenResources *xrsr;
|
|
char *names;
|
|
char *wire_names, *wire_name;
|
|
Bool getting_version = False;
|
|
XRandRInfo *xrri;
|
|
|
|
RRCheckExtension (dpy, info, NULL);
|
|
|
|
LockDisplay (dpy);
|
|
xrri = (XRandRInfo *) info->data;
|
|
|
|
if (xrri->major_version == -1)
|
|
{
|
|
/* hide a version query in the request */
|
|
GetReq (RRQueryVersion, vreq);
|
|
vreq->reqType = info->codes->major_opcode;
|
|
vreq->randrReqType = X_RRQueryVersion;
|
|
vreq->majorVersion = RANDR_MAJOR;
|
|
vreq->minorVersion = RANDR_MINOR;
|
|
|
|
async_state.version_seq = dpy->request;
|
|
async_state.error = False;
|
|
async.next = dpy->async_handlers;
|
|
async.handler = _XRRVersionHandler;
|
|
async.data = (XPointer) &async_state;
|
|
dpy->async_handlers = &async;
|
|
|
|
getting_version = True;
|
|
}
|
|
|
|
GetReq (RRGetScreenResources, req);
|
|
req->reqType = info->codes->major_opcode;
|
|
req->randrReqType = poll ? X_RRGetScreenResources
|
|
: X_RRGetScreenResourcesCurrent;
|
|
req->window = window;
|
|
|
|
if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))
|
|
{
|
|
if (getting_version)
|
|
DeqAsyncHandler (dpy, &async);
|
|
UnlockDisplay (dpy);
|
|
SyncHandle ();
|
|
return NULL;
|
|
}
|
|
if (getting_version)
|
|
{
|
|
DeqAsyncHandler (dpy, &async);
|
|
if (async_state.error)
|
|
{
|
|
UnlockDisplay (dpy);
|
|
SyncHandle();
|
|
LockDisplay (dpy);
|
|
}
|
|
xrri->major_version = async_state.major_version;
|
|
xrri->minor_version = async_state.minor_version;
|
|
xrri->has_rates = _XRRHasRates (xrri->minor_version, xrri->major_version);
|
|
}
|
|
|
|
if (rep.length < INT_MAX >> 2) {
|
|
nbytes = (long) rep.length << 2;
|
|
|
|
nbytesRead = (long) (rep.nCrtcs * 4 +
|
|
rep.nOutputs * 4 +
|
|
rep.nModes * SIZEOF (xRRModeInfo) +
|
|
((rep.nbytesNames + 3) & ~3));
|
|
|
|
/*
|
|
* first we must compute how much space to allocate for
|
|
* randr library's use; we'll allocate the structures in a single
|
|
* allocation, on cleanlyness grounds.
|
|
*/
|
|
|
|
rbytes = (sizeof (XRRScreenResources) +
|
|
rep.nCrtcs * sizeof (RRCrtc) +
|
|
rep.nOutputs * sizeof (RROutput) +
|
|
rep.nModes * sizeof (XRRModeInfo) +
|
|
rep.nbytesNames + rep.nModes); /* '\0' terminate names */
|
|
|
|
xrsr = (XRRScreenResources *) Xmalloc(rbytes);
|
|
wire_names = (char *) Xmalloc (rep.nbytesNames);
|
|
} else {
|
|
nbytes = 0;
|
|
nbytesRead = 0;
|
|
rbytes = 0;
|
|
xrsr = NULL;
|
|
wire_names = NULL;
|
|
}
|
|
|
|
if (xrsr == NULL || wire_names == NULL) {
|
|
Xfree (xrsr);
|
|
Xfree (wire_names);
|
|
_XEatDataWords (dpy, rep.length);
|
|
UnlockDisplay (dpy);
|
|
SyncHandle ();
|
|
return NULL;
|
|
}
|
|
|
|
xrsr->timestamp = rep.timestamp;
|
|
xrsr->configTimestamp = rep.configTimestamp;
|
|
xrsr->ncrtc = rep.nCrtcs;
|
|
xrsr->crtcs = (RRCrtc *) (xrsr + 1);
|
|
xrsr->noutput = rep.nOutputs;
|
|
xrsr->outputs = (RROutput *) (xrsr->crtcs + rep.nCrtcs);
|
|
xrsr->nmode = rep.nModes;
|
|
xrsr->modes = (XRRModeInfo *) (xrsr->outputs + rep.nOutputs);
|
|
names = (char *) (xrsr->modes + rep.nModes);
|
|
|
|
_XRead32 (dpy, (long *) xrsr->crtcs, rep.nCrtcs << 2);
|
|
_XRead32 (dpy, (long *) xrsr->outputs, rep.nOutputs << 2);
|
|
|
|
for (i = 0; i < rep.nModes; i++) {
|
|
xRRModeInfo modeInfo;
|
|
|
|
_XReadPad (dpy, (char *) &modeInfo, SIZEOF (xRRModeInfo));
|
|
xrsr->modes[i].id = modeInfo.id;
|
|
xrsr->modes[i].width = modeInfo.width;
|
|
xrsr->modes[i].height = modeInfo.height;
|
|
xrsr->modes[i].dotClock = modeInfo.dotClock;
|
|
xrsr->modes[i].hSyncStart = modeInfo.hSyncStart;
|
|
xrsr->modes[i].hSyncEnd = modeInfo.hSyncEnd;
|
|
xrsr->modes[i].hTotal = modeInfo.hTotal;
|
|
xrsr->modes[i].hSkew = modeInfo.hSkew;
|
|
xrsr->modes[i].vSyncStart = modeInfo.vSyncStart;
|
|
xrsr->modes[i].vSyncEnd = modeInfo.vSyncEnd;
|
|
xrsr->modes[i].vTotal = modeInfo.vTotal;
|
|
xrsr->modes[i].nameLength = modeInfo.nameLength;
|
|
xrsr->modes[i].modeFlags = modeInfo.modeFlags;
|
|
}
|
|
|
|
/*
|
|
* Read names and '\0' pad each one
|
|
*/
|
|
_XReadPad (dpy, wire_names, rep.nbytesNames);
|
|
wire_name = wire_names;
|
|
for (i = 0; i < rep.nModes; i++) {
|
|
xrsr->modes[i].name = names;
|
|
if (xrsr->modes[i].nameLength > rep.nbytesNames) {
|
|
Xfree (xrsr);
|
|
Xfree (wire_names);
|
|
UnlockDisplay (dpy);
|
|
SyncHandle ();
|
|
return NULL;
|
|
}
|
|
rep.nbytesNames -= xrsr->modes[i].nameLength;
|
|
memcpy (names, wire_name, xrsr->modes[i].nameLength);
|
|
names[xrsr->modes[i].nameLength] = '\0';
|
|
names += xrsr->modes[i].nameLength + 1;
|
|
wire_name += xrsr->modes[i].nameLength;
|
|
}
|
|
Xfree (wire_names);
|
|
|
|
/*
|
|
* Skip any extra data
|
|
*/
|
|
if (nbytes > nbytesRead)
|
|
_XEatData (dpy, (unsigned long) (nbytes - nbytesRead));
|
|
|
|
UnlockDisplay (dpy);
|
|
SyncHandle();
|
|
return (XRRScreenResources *) xrsr;
|
|
}
|
|
|
|
XRRScreenResources *
|
|
XRRGetScreenResources(Display *dpy, Window window)
|
|
{
|
|
return doGetScreenResources(dpy, window, 1);
|
|
}
|
|
|
|
XRRScreenResources *
|
|
XRRGetScreenResourcesCurrent(Display *dpy, Window window)
|
|
{
|
|
return doGetScreenResources(dpy, window, 0);
|
|
}
|
|
|
|
void
|
|
XRRFreeScreenResources (XRRScreenResources *resources)
|
|
{
|
|
Xfree (resources);
|
|
}
|
|
|
|
Status
|
|
XRRGetScreenSizeRange (Display *dpy, Window window,
|
|
int *minWidth, int *minHeight,
|
|
int *maxWidth, int *maxHeight)
|
|
{
|
|
XExtDisplayInfo *info = XRRFindDisplay(dpy);
|
|
xRRGetScreenSizeRangeReq *req;
|
|
xRRGetScreenSizeRangeReply rep;
|
|
|
|
RRCheckExtension (dpy, info, 0);
|
|
LockDisplay (dpy);
|
|
GetReq (RRGetScreenSizeRange, req);
|
|
req->reqType = info->codes->major_opcode;
|
|
req->randrReqType = X_RRGetScreenSizeRange;
|
|
req->window = window;
|
|
if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))
|
|
{
|
|
UnlockDisplay (dpy);
|
|
SyncHandle ();
|
|
return False;
|
|
}
|
|
UnlockDisplay (dpy);
|
|
SyncHandle ();
|
|
*minWidth = rep.minWidth;
|
|
*minHeight = rep.minHeight;
|
|
*maxWidth = rep.maxWidth;
|
|
*maxHeight = rep.maxHeight;
|
|
return True;
|
|
}
|
|
|
|
void
|
|
XRRSetScreenSize (Display *dpy, Window window,
|
|
int width, int height,
|
|
int mmWidth, int mmHeight)
|
|
{
|
|
XExtDisplayInfo *info = XRRFindDisplay(dpy);
|
|
xRRSetScreenSizeReq *req;
|
|
|
|
RRSimpleCheckExtension (dpy, info);
|
|
LockDisplay (dpy);
|
|
GetReq (RRSetScreenSize, req);
|
|
req->reqType = info->codes->major_opcode;
|
|
req->randrReqType = X_RRSetScreenSize;
|
|
req->window = window;
|
|
req->width = width;
|
|
req->height = height;
|
|
req->widthInMillimeters = mmWidth;
|
|
req->heightInMillimeters = mmHeight;
|
|
UnlockDisplay (dpy);
|
|
SyncHandle ();
|
|
}
|