/* * 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 #endif #include #include #include /* we need to be able to manipulate the Display structure on events */ #include #include #include #include "Xrandrint.h" XRRCrtcInfo * XRRGetCrtcInfo (Display *dpy, XRRScreenResources *resources, RRCrtc crtc) { XExtDisplayInfo *info = XRRFindDisplay(dpy); xRRGetCrtcInfoReply rep; xRRGetCrtcInfoReq *req; int nbytes, nbytesRead, rbytes; XRRCrtcInfo *xci; RRCheckExtension (dpy, info, NULL); LockDisplay (dpy); GetReq (RRGetCrtcInfo, req); req->reqType = info->codes->major_opcode; req->randrReqType = X_RRGetCrtcInfo; req->crtc = crtc; req->configTimestamp = resources->configTimestamp; if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) { UnlockDisplay (dpy); SyncHandle (); return NULL; } if (rep.length < INT_MAX >> 2) { nbytes = (long) rep.length << 2; nbytesRead = (long) (rep.nOutput * 4 + rep.nPossibleOutput * 4); /* * 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 (XRRCrtcInfo) + rep.nOutput * sizeof (RROutput) + rep.nPossibleOutput * sizeof (RROutput)); xci = (XRRCrtcInfo *) Xmalloc(rbytes); } else { nbytes = 0; nbytesRead = 0; rbytes = 0; xci = NULL; } if (xci == NULL) { _XEatDataWords (dpy, rep.length); UnlockDisplay (dpy); SyncHandle (); return NULL; } xci->timestamp = rep.timestamp; xci->x = rep.x; xci->y = rep.y; xci->width = rep.width; xci->height = rep.height; xci->mode = rep.mode; xci->rotation = rep.rotation; xci->noutput = rep.nOutput; xci->outputs = (RROutput *) (xci + 1); xci->rotations = rep.rotations; xci->npossible = rep.nPossibleOutput; xci->possible = (RROutput *) (xci->outputs + rep.nOutput); _XRead32 (dpy, (long *) xci->outputs, rep.nOutput << 2); _XRead32 (dpy, (long *) xci->possible, rep.nPossibleOutput << 2); /* * Skip any extra data */ if (nbytes > nbytesRead) _XEatData (dpy, (unsigned long) (nbytes - nbytesRead)); UnlockDisplay (dpy); SyncHandle (); return (XRRCrtcInfo *) xci; } void XRRFreeCrtcInfo (XRRCrtcInfo *crtcInfo) { Xfree (crtcInfo); } Status XRRSetCrtcConfig (Display *dpy, XRRScreenResources *resources, RRCrtc crtc, Time timestamp, int x, int y, RRMode mode, Rotation rotation, RROutput *outputs, int noutputs) { XExtDisplayInfo *info = XRRFindDisplay(dpy); xRRSetCrtcConfigReply rep; xRRSetCrtcConfigReq *req; RRCheckExtension (dpy, info, 0); LockDisplay(dpy); GetReq (RRSetCrtcConfig, req); req->reqType = info->codes->major_opcode; req->randrReqType = X_RRSetCrtcConfig; req->length += noutputs; req->crtc = crtc; req->timestamp = timestamp; req->configTimestamp = resources->configTimestamp; req->x = x; req->y = y; req->mode = mode; req->rotation = rotation; Data32 (dpy, outputs, noutputs << 2); if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) rep.status = RRSetConfigFailed; UnlockDisplay (dpy); SyncHandle (); return rep.status; } int XRRGetCrtcGammaSize (Display *dpy, RRCrtc crtc) { XExtDisplayInfo *info = XRRFindDisplay(dpy); xRRGetCrtcGammaSizeReply rep; xRRGetCrtcGammaSizeReq *req; RRCheckExtension (dpy, info, 0); LockDisplay(dpy); GetReq (RRGetCrtcGammaSize, req); req->reqType = info->codes->major_opcode; req->randrReqType = X_RRGetCrtcGammaSize; req->crtc = crtc; if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) rep.size = 0; UnlockDisplay (dpy); SyncHandle (); return rep.size; } XRRCrtcGamma * XRRGetCrtcGamma (Display *dpy, RRCrtc crtc) { XExtDisplayInfo *info = XRRFindDisplay(dpy); xRRGetCrtcGammaReply rep; xRRGetCrtcGammaReq *req; XRRCrtcGamma *crtc_gamma = NULL; long nbytes; long nbytesRead; RRCheckExtension (dpy, info, NULL); LockDisplay(dpy); GetReq (RRGetCrtcGamma, req); req->reqType = info->codes->major_opcode; req->randrReqType = X_RRGetCrtcGamma; req->crtc = crtc; if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) goto out; if (rep.length < INT_MAX >> 2) { nbytes = (long) rep.length << 2; /* three channels of CARD16 data */ nbytesRead = (rep.size * 2 * 3); crtc_gamma = XRRAllocGamma (rep.size); } else { nbytes = 0; nbytesRead = 0; crtc_gamma = NULL; } if (!crtc_gamma) { _XEatDataWords (dpy, rep.length); goto out; } _XRead16 (dpy, crtc_gamma->red, rep.size * 2); _XRead16 (dpy, crtc_gamma->green, rep.size * 2); _XRead16 (dpy, crtc_gamma->blue, rep.size * 2); if (nbytes > nbytesRead) _XEatData (dpy, (unsigned long) (nbytes - nbytesRead)); out: UnlockDisplay (dpy); SyncHandle (); return crtc_gamma; } XRRCrtcGamma * XRRAllocGamma (int size) { XRRCrtcGamma *crtc_gamma; crtc_gamma = Xmalloc (sizeof (XRRCrtcGamma) + sizeof (crtc_gamma->red[0]) * size * 3); if (!crtc_gamma) return NULL; crtc_gamma->size = size; crtc_gamma->red = (unsigned short *) (crtc_gamma + 1); crtc_gamma->green = crtc_gamma->red + size; crtc_gamma->blue = crtc_gamma->green + size; return crtc_gamma; } void XRRSetCrtcGamma (Display *dpy, RRCrtc crtc, XRRCrtcGamma *crtc_gamma) { XExtDisplayInfo *info = XRRFindDisplay(dpy); xRRSetCrtcGammaReq *req; RRSimpleCheckExtension (dpy, info); LockDisplay(dpy); GetReq (RRSetCrtcGamma, req); req->reqType = info->codes->major_opcode; req->randrReqType = X_RRSetCrtcGamma; req->crtc = crtc; req->size = crtc_gamma->size; req->length += (crtc_gamma->size * 2 * 3 + 3) >> 2; /* * Note this assumes the structure was allocated with XRRAllocGamma, * otherwise the channels might not be contiguous */ Data16 (dpy, crtc_gamma->red, crtc_gamma->size * 2 * 3); UnlockDisplay (dpy); SyncHandle (); } void XRRFreeGamma (XRRCrtcGamma *crtc_gamma) { Xfree (crtc_gamma); } /* Version 1.3 additions */ static void XTransform_from_xRenderTransform (XTransform *x, xRenderTransform *render) { x->matrix[0][0] = render->matrix11; x->matrix[0][1] = render->matrix12; x->matrix[0][2] = render->matrix13; x->matrix[1][0] = render->matrix21; x->matrix[1][1] = render->matrix22; x->matrix[1][2] = render->matrix23; x->matrix[2][0] = render->matrix31; x->matrix[2][1] = render->matrix32; x->matrix[2][2] = render->matrix33; } static void xRenderTransform_from_XTransform (xRenderTransform *render, XTransform *x) { render->matrix11 = x->matrix[0][0]; render->matrix12 = x->matrix[0][1]; render->matrix13 = x->matrix[0][2]; render->matrix21 = x->matrix[1][0]; render->matrix22 = x->matrix[1][1]; render->matrix23 = x->matrix[1][2]; render->matrix31 = x->matrix[2][0]; render->matrix32 = x->matrix[2][1]; render->matrix33 = x->matrix[2][2]; } void XRRSetCrtcTransform (Display *dpy, RRCrtc crtc, XTransform *transform, _Xconst char *filter, XFixed *params, int nparams) { XExtDisplayInfo *info = XRRFindDisplay(dpy); xRRSetCrtcTransformReq *req; int nbytes = strlen (filter); RRSimpleCheckExtension (dpy, info); LockDisplay(dpy); GetReq (RRSetCrtcTransform, req); req->reqType = info->codes->major_opcode; req->randrReqType = X_RRSetCrtcTransform; req->crtc = crtc; xRenderTransform_from_XTransform (&req->transform, transform); req->nbytesFilter = nbytes; req->length += ((nbytes + 3) >> 2) + nparams; Data (dpy, filter, nbytes); Data32 (dpy, params, nparams << 2); UnlockDisplay (dpy); SyncHandle (); } #define CrtcTransformExtra (SIZEOF(xRRGetCrtcTransformReply) - 32) static const xRenderTransform identity = { 0x10000, 0, 0, 0, 0x10000, 0, 0, 0, 0x10000, }; static Bool _XRRHasTransform (int major, int minor) { return major > 1 || (major == 1 && minor >= 3); } Status XRRGetCrtcTransform (Display *dpy, RRCrtc crtc, XRRCrtcTransformAttributes **attributes) { XExtDisplayInfo *info = XRRFindDisplay(dpy); xRRGetCrtcTransformReply rep; int major_version, minor_version; XRRCrtcTransformAttributes *attr; char *extra = NULL, *end = NULL, *e; *attributes = NULL; RRCheckExtension (dpy, info, False); if (!XRRQueryVersion (dpy, &major_version, &minor_version) || !_XRRHasTransform (major_version, minor_version)) { /* For pre-1.3 servers, just report identity matrices everywhere */ rep.pendingTransform = identity; rep.pendingNbytesFilter = 0; rep.pendingNparamsFilter = 0; rep.currentTransform = identity; rep.currentNbytesFilter = 0; rep.currentNparamsFilter = 0; } else { xRRGetCrtcTransformReq *req; LockDisplay (dpy); GetReq (RRGetCrtcTransform, req); req->reqType = info->codes->major_opcode; req->randrReqType = X_RRGetCrtcTransform; req->crtc = crtc; if (!_XReply (dpy, (xReply *) &rep, CrtcTransformExtra >> 2, xFalse)) { rep.pendingTransform = identity; rep.pendingNbytesFilter = 0; rep.pendingNparamsFilter = 0; rep.currentTransform = identity; rep.currentNbytesFilter = 0; rep.currentNparamsFilter = 0; } else { int extraBytes = rep.length * 4 - CrtcTransformExtra; if (rep.length < INT_MAX / 4 && rep.length * 4 >= CrtcTransformExtra) { extra = Xmalloc (extraBytes); end = extra + extraBytes; } else extra = NULL; if (!extra) { if (rep.length > (CrtcTransformExtra >> 2)) _XEatDataWords (dpy, rep.length - (CrtcTransformExtra >> 2)); else _XEatDataWords (dpy, rep.length); UnlockDisplay (dpy); SyncHandle (); return False; } _XRead (dpy, extra, extraBytes); } UnlockDisplay (dpy); SyncHandle (); } attr = Xmalloc (sizeof (XRRCrtcTransformAttributes) + rep.pendingNparamsFilter * sizeof (XFixed) + rep.currentNparamsFilter * sizeof (XFixed) + rep.pendingNbytesFilter + 1 + rep.currentNbytesFilter + 1); if (!attr) { XFree (extra); return False; } XTransform_from_xRenderTransform (&attr->pendingTransform, &rep.pendingTransform); XTransform_from_xRenderTransform (&attr->currentTransform, &rep.currentTransform); attr->pendingParams = (XFixed *) (attr + 1); attr->currentParams = attr->pendingParams + rep.pendingNparamsFilter; attr->pendingFilter = (char *) (attr->currentParams + rep.currentNparamsFilter); attr->currentFilter = attr->pendingFilter + rep.pendingNbytesFilter + 1; e = extra; if (e + rep.pendingNbytesFilter > end) { XFree (attr); XFree (extra); return False; } memcpy (attr->pendingFilter, e, rep.pendingNbytesFilter); attr->pendingFilter[rep.pendingNbytesFilter] = '\0'; e += (rep.pendingNbytesFilter + 3) & ~3; for (unsigned int p = 0; p < rep.pendingNparamsFilter; p++) { INT32 f; if (e + 4 > end) { XFree (attr); XFree (extra); return False; } memcpy (&f, e, 4); e += 4; attr->pendingParams[p] = (XFixed) f; } attr->pendingNparams = rep.pendingNparamsFilter; if (e + rep.currentNbytesFilter > end) { XFree (attr); XFree (extra); return False; } memcpy (attr->currentFilter, e, rep.currentNbytesFilter); attr->currentFilter[rep.currentNbytesFilter] = '\0'; e += (rep.currentNbytesFilter + 3) & ~3; for (unsigned int p = 0; p < rep.currentNparamsFilter; p++) { INT32 f; if (e + 4 > end) { XFree (attr); XFree (extra); return False; } memcpy (&f, e, 4); e += 4; attr->currentParams[p] = (XFixed) f; } attr->currentNparams = rep.currentNparamsFilter; if (extra) XFree (extra); *attributes = attr; return True; } XRRPanning * XRRGetPanning (Display *dpy, XRRScreenResources *resources, RRCrtc crtc) { XExtDisplayInfo *info = XRRFindDisplay(dpy); xRRGetPanningReply rep; xRRGetPanningReq *req; XRRPanning *xp; RRCheckExtension (dpy, info, NULL); LockDisplay (dpy); GetReq (RRGetPanning, req); req->reqType = info->codes->major_opcode; req->randrReqType = X_RRGetPanning; req->crtc = crtc; if (!_XReply (dpy, (xReply *) &rep, 1, xFalse)) { UnlockDisplay (dpy); SyncHandle (); return NULL; } if (! (xp = (XRRPanning *) Xmalloc(sizeof(XRRPanning))) ) { _XEatData (dpy, sizeof(XRRPanning)); UnlockDisplay (dpy); SyncHandle (); return NULL; } xp->timestamp = rep.timestamp; xp->left = rep.left; xp->top = rep.top; xp->width = rep.width; xp->height = rep.height; xp->track_left = rep.track_left; xp->track_top = rep.track_top; xp->track_width = rep.track_width; xp->track_height = rep.track_height; xp->border_left = rep.border_left; xp->border_top = rep.border_top; xp->border_right = rep.border_right; xp->border_bottom = rep.border_bottom; UnlockDisplay (dpy); SyncHandle (); return (XRRPanning *) xp; } void XRRFreePanning (XRRPanning *panning) { Xfree (panning); } Status XRRSetPanning (Display *dpy, XRRScreenResources *resources, RRCrtc crtc, XRRPanning *panning) { XExtDisplayInfo *info = XRRFindDisplay(dpy); xRRSetPanningReply rep; xRRSetPanningReq *req; RRCheckExtension (dpy, info, 0); LockDisplay(dpy); GetReq (RRSetPanning, req); req->reqType = info->codes->major_opcode; req->randrReqType = X_RRSetPanning; req->crtc = crtc; req->timestamp = panning->timestamp; req->left = panning->left; req->top = panning->top; req->width = panning->width; req->height = panning->height; req->track_left = panning->track_left; req->track_top = panning->track_top; req->track_width = panning->track_width; req->track_height = panning->track_height; req->border_left = panning->border_left; req->border_top = panning->border_top; req->border_right = panning->border_right; req->border_bottom = panning->border_bottom; if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) rep.status = RRSetConfigFailed; UnlockDisplay (dpy); SyncHandle (); return rep.status; }