760 lines
22 KiB
C
760 lines
22 KiB
C
/*
|
|
* Copyright © 2000 Compaq Computer Corporation
|
|
* Copyright © 2002 Hewlett-Packard Company
|
|
* Copyright © 2006 Intel Corporation
|
|
* Copyright © 2017 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.
|
|
*
|
|
* Author: Jim Gettys, Hewlett-Packard Company, Inc.
|
|
* Keith Packard, Intel Corporation
|
|
*/
|
|
|
|
#ifdef HAVE_DIX_CONFIG_H
|
|
#include <dix-config.h>
|
|
#endif
|
|
|
|
#include "randrstr.h"
|
|
#include "extinit.h"
|
|
|
|
/* From render.h */
|
|
#ifndef SubPixelUnknown
|
|
#define SubPixelUnknown 0
|
|
#endif
|
|
|
|
#define RR_VALIDATE
|
|
static int RRNScreens;
|
|
|
|
#define wrap(priv,real,mem,func) {\
|
|
priv->mem = real->mem; \
|
|
real->mem = func; \
|
|
}
|
|
|
|
#define unwrap(priv,real,mem) {\
|
|
real->mem = priv->mem; \
|
|
}
|
|
|
|
static int ProcRRDispatch(ClientPtr pClient);
|
|
static int SProcRRDispatch(ClientPtr pClient);
|
|
|
|
int RREventBase;
|
|
int RRErrorBase;
|
|
RESTYPE RRClientType, RREventType; /* resource types for event masks */
|
|
DevPrivateKeyRec RRClientPrivateKeyRec;
|
|
|
|
DevPrivateKeyRec rrPrivKeyRec;
|
|
|
|
static void
|
|
RRClientCallback(CallbackListPtr *list, void *closure, void *data)
|
|
{
|
|
NewClientInfoRec *clientinfo = (NewClientInfoRec *) data;
|
|
ClientPtr pClient = clientinfo->client;
|
|
|
|
rrClientPriv(pClient);
|
|
RRTimesPtr pTimes = (RRTimesPtr) (pRRClient + 1);
|
|
int i;
|
|
|
|
pRRClient->major_version = 0;
|
|
pRRClient->minor_version = 0;
|
|
for (i = 0; i < screenInfo.numScreens; i++) {
|
|
ScreenPtr pScreen = screenInfo.screens[i];
|
|
|
|
rrScrPriv(pScreen);
|
|
|
|
if (pScrPriv) {
|
|
pTimes[i].setTime = pScrPriv->lastSetTime;
|
|
pTimes[i].configTime = pScrPriv->lastConfigTime;
|
|
}
|
|
}
|
|
}
|
|
|
|
static Bool
|
|
RRCloseScreen(ScreenPtr pScreen)
|
|
{
|
|
rrScrPriv(pScreen);
|
|
int j;
|
|
RRLeasePtr lease, next;
|
|
|
|
unwrap(pScrPriv, pScreen, CloseScreen);
|
|
|
|
xorg_list_for_each_entry_safe(lease, next, &pScrPriv->leases, list)
|
|
RRTerminateLease(lease);
|
|
for (j = pScrPriv->numCrtcs - 1; j >= 0; j--)
|
|
RRCrtcDestroy(pScrPriv->crtcs[j]);
|
|
for (j = pScrPriv->numOutputs - 1; j >= 0; j--)
|
|
RROutputDestroy(pScrPriv->outputs[j]);
|
|
|
|
if (pScrPriv->provider)
|
|
RRProviderDestroy(pScrPriv->provider);
|
|
|
|
RRMonitorClose(pScreen);
|
|
|
|
free(pScrPriv->crtcs);
|
|
free(pScrPriv->outputs);
|
|
free(pScrPriv);
|
|
RRNScreens -= 1; /* ok, one fewer screen with RandR running */
|
|
return (*pScreen->CloseScreen) (pScreen);
|
|
}
|
|
|
|
static void
|
|
SRRScreenChangeNotifyEvent(xRRScreenChangeNotifyEvent * from,
|
|
xRRScreenChangeNotifyEvent * to)
|
|
{
|
|
to->type = from->type;
|
|
to->rotation = from->rotation;
|
|
cpswaps(from->sequenceNumber, to->sequenceNumber);
|
|
cpswapl(from->timestamp, to->timestamp);
|
|
cpswapl(from->configTimestamp, to->configTimestamp);
|
|
cpswapl(from->root, to->root);
|
|
cpswapl(from->window, to->window);
|
|
cpswaps(from->sizeID, to->sizeID);
|
|
cpswaps(from->subpixelOrder, to->subpixelOrder);
|
|
cpswaps(from->widthInPixels, to->widthInPixels);
|
|
cpswaps(from->heightInPixels, to->heightInPixels);
|
|
cpswaps(from->widthInMillimeters, to->widthInMillimeters);
|
|
cpswaps(from->heightInMillimeters, to->heightInMillimeters);
|
|
}
|
|
|
|
static void
|
|
SRRCrtcChangeNotifyEvent(xRRCrtcChangeNotifyEvent * from,
|
|
xRRCrtcChangeNotifyEvent * to)
|
|
{
|
|
to->type = from->type;
|
|
to->subCode = from->subCode;
|
|
cpswaps(from->sequenceNumber, to->sequenceNumber);
|
|
cpswapl(from->timestamp, to->timestamp);
|
|
cpswapl(from->window, to->window);
|
|
cpswapl(from->crtc, to->crtc);
|
|
cpswapl(from->mode, to->mode);
|
|
cpswaps(from->rotation, to->rotation);
|
|
/* pad1 */
|
|
cpswaps(from->x, to->x);
|
|
cpswaps(from->y, to->y);
|
|
cpswaps(from->width, to->width);
|
|
cpswaps(from->height, to->height);
|
|
}
|
|
|
|
static void
|
|
SRROutputChangeNotifyEvent(xRROutputChangeNotifyEvent * from,
|
|
xRROutputChangeNotifyEvent * to)
|
|
{
|
|
to->type = from->type;
|
|
to->subCode = from->subCode;
|
|
cpswaps(from->sequenceNumber, to->sequenceNumber);
|
|
cpswapl(from->timestamp, to->timestamp);
|
|
cpswapl(from->configTimestamp, to->configTimestamp);
|
|
cpswapl(from->window, to->window);
|
|
cpswapl(from->output, to->output);
|
|
cpswapl(from->crtc, to->crtc);
|
|
cpswapl(from->mode, to->mode);
|
|
cpswaps(from->rotation, to->rotation);
|
|
to->connection = from->connection;
|
|
to->subpixelOrder = from->subpixelOrder;
|
|
}
|
|
|
|
static void
|
|
SRROutputPropertyNotifyEvent(xRROutputPropertyNotifyEvent * from,
|
|
xRROutputPropertyNotifyEvent * to)
|
|
{
|
|
to->type = from->type;
|
|
to->subCode = from->subCode;
|
|
cpswaps(from->sequenceNumber, to->sequenceNumber);
|
|
cpswapl(from->window, to->window);
|
|
cpswapl(from->output, to->output);
|
|
cpswapl(from->atom, to->atom);
|
|
cpswapl(from->timestamp, to->timestamp);
|
|
to->state = from->state;
|
|
/* pad1 */
|
|
/* pad2 */
|
|
/* pad3 */
|
|
/* pad4 */
|
|
}
|
|
|
|
static void
|
|
SRRProviderChangeNotifyEvent(xRRProviderChangeNotifyEvent * from,
|
|
xRRProviderChangeNotifyEvent * to)
|
|
{
|
|
to->type = from->type;
|
|
to->subCode = from->subCode;
|
|
cpswaps(from->sequenceNumber, to->sequenceNumber);
|
|
cpswapl(from->timestamp, to->timestamp);
|
|
cpswapl(from->window, to->window);
|
|
cpswapl(from->provider, to->provider);
|
|
}
|
|
|
|
static void
|
|
SRRProviderPropertyNotifyEvent(xRRProviderPropertyNotifyEvent * from,
|
|
xRRProviderPropertyNotifyEvent * to)
|
|
{
|
|
to->type = from->type;
|
|
to->subCode = from->subCode;
|
|
cpswaps(from->sequenceNumber, to->sequenceNumber);
|
|
cpswapl(from->window, to->window);
|
|
cpswapl(from->provider, to->provider);
|
|
cpswapl(from->atom, to->atom);
|
|
cpswapl(from->timestamp, to->timestamp);
|
|
to->state = from->state;
|
|
/* pad1 */
|
|
/* pad2 */
|
|
/* pad3 */
|
|
/* pad4 */
|
|
}
|
|
|
|
static void _X_COLD
|
|
SRRResourceChangeNotifyEvent(xRRResourceChangeNotifyEvent * from,
|
|
xRRResourceChangeNotifyEvent * to)
|
|
{
|
|
to->type = from->type;
|
|
to->subCode = from->subCode;
|
|
cpswaps(from->sequenceNumber, to->sequenceNumber);
|
|
cpswapl(from->timestamp, to->timestamp);
|
|
cpswapl(from->window, to->window);
|
|
}
|
|
|
|
static void _X_COLD
|
|
SRRLeaseNotifyEvent(xRRLeaseNotifyEvent * from,
|
|
xRRLeaseNotifyEvent * to)
|
|
{
|
|
to->type = from->type;
|
|
to->subCode = from->subCode;
|
|
cpswaps(from->sequenceNumber, to->sequenceNumber);
|
|
cpswapl(from->timestamp, to->timestamp);
|
|
cpswapl(from->window, to->window);
|
|
cpswapl(from->lease, to->lease);
|
|
to->created = from->created;
|
|
}
|
|
|
|
static void _X_COLD
|
|
SRRNotifyEvent(xEvent *from, xEvent *to)
|
|
{
|
|
switch (from->u.u.detail) {
|
|
case RRNotify_CrtcChange:
|
|
SRRCrtcChangeNotifyEvent((xRRCrtcChangeNotifyEvent *) from,
|
|
(xRRCrtcChangeNotifyEvent *) to);
|
|
break;
|
|
case RRNotify_OutputChange:
|
|
SRROutputChangeNotifyEvent((xRROutputChangeNotifyEvent *) from,
|
|
(xRROutputChangeNotifyEvent *) to);
|
|
break;
|
|
case RRNotify_OutputProperty:
|
|
SRROutputPropertyNotifyEvent((xRROutputPropertyNotifyEvent *) from,
|
|
(xRROutputPropertyNotifyEvent *) to);
|
|
break;
|
|
case RRNotify_ProviderChange:
|
|
SRRProviderChangeNotifyEvent((xRRProviderChangeNotifyEvent *) from,
|
|
(xRRProviderChangeNotifyEvent *) to);
|
|
break;
|
|
case RRNotify_ProviderProperty:
|
|
SRRProviderPropertyNotifyEvent((xRRProviderPropertyNotifyEvent *) from,
|
|
(xRRProviderPropertyNotifyEvent *) to);
|
|
break;
|
|
case RRNotify_ResourceChange:
|
|
SRRResourceChangeNotifyEvent((xRRResourceChangeNotifyEvent *) from,
|
|
(xRRResourceChangeNotifyEvent *) to);
|
|
break;
|
|
case RRNotify_Lease:
|
|
SRRLeaseNotifyEvent((xRRLeaseNotifyEvent *) from,
|
|
(xRRLeaseNotifyEvent *) to);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int RRGeneration;
|
|
|
|
Bool
|
|
RRInit(void)
|
|
{
|
|
if (RRGeneration != serverGeneration) {
|
|
if (!RRModeInit())
|
|
return FALSE;
|
|
if (!RRCrtcInit())
|
|
return FALSE;
|
|
if (!RROutputInit())
|
|
return FALSE;
|
|
if (!RRProviderInit())
|
|
return FALSE;
|
|
if (!RRLeaseInit())
|
|
return FALSE;
|
|
RRGeneration = serverGeneration;
|
|
}
|
|
if (!dixRegisterPrivateKey(&rrPrivKeyRec, PRIVATE_SCREEN, 0))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
Bool
|
|
RRScreenInit(ScreenPtr pScreen)
|
|
{
|
|
rrScrPrivPtr pScrPriv;
|
|
|
|
if (!RRInit())
|
|
return FALSE;
|
|
|
|
pScrPriv = (rrScrPrivPtr) calloc(1, sizeof(rrScrPrivRec));
|
|
if (!pScrPriv)
|
|
return FALSE;
|
|
|
|
SetRRScreen(pScreen, pScrPriv);
|
|
|
|
/*
|
|
* Calling function best set these function vectors
|
|
*/
|
|
pScrPriv->rrGetInfo = 0;
|
|
pScrPriv->maxWidth = pScrPriv->minWidth = pScreen->width;
|
|
pScrPriv->maxHeight = pScrPriv->minHeight = pScreen->height;
|
|
|
|
pScrPriv->width = pScreen->width;
|
|
pScrPriv->height = pScreen->height;
|
|
pScrPriv->mmWidth = pScreen->mmWidth;
|
|
pScrPriv->mmHeight = pScreen->mmHeight;
|
|
#if RANDR_12_INTERFACE
|
|
pScrPriv->rrScreenSetSize = NULL;
|
|
pScrPriv->rrCrtcSet = NULL;
|
|
pScrPriv->rrCrtcSetGamma = NULL;
|
|
#endif
|
|
#if RANDR_10_INTERFACE
|
|
pScrPriv->rrSetConfig = 0;
|
|
pScrPriv->rotations = RR_Rotate_0;
|
|
pScrPriv->reqWidth = pScreen->width;
|
|
pScrPriv->reqHeight = pScreen->height;
|
|
pScrPriv->nSizes = 0;
|
|
pScrPriv->pSizes = NULL;
|
|
pScrPriv->rotation = RR_Rotate_0;
|
|
pScrPriv->rate = 0;
|
|
pScrPriv->size = 0;
|
|
#endif
|
|
|
|
/*
|
|
* This value doesn't really matter -- any client must call
|
|
* GetScreenInfo before reading it which will automatically update
|
|
* the time
|
|
*/
|
|
pScrPriv->lastSetTime = currentTime;
|
|
pScrPriv->lastConfigTime = currentTime;
|
|
|
|
wrap(pScrPriv, pScreen, CloseScreen, RRCloseScreen);
|
|
|
|
pScreen->ConstrainCursorHarder = RRConstrainCursorHarder;
|
|
pScreen->ReplaceScanoutPixmap = RRReplaceScanoutPixmap;
|
|
pScrPriv->numOutputs = 0;
|
|
pScrPriv->outputs = NULL;
|
|
pScrPriv->numCrtcs = 0;
|
|
pScrPriv->crtcs = NULL;
|
|
|
|
xorg_list_init(&pScrPriv->leases);
|
|
|
|
RRMonitorInit(pScreen);
|
|
|
|
RRNScreens += 1; /* keep count of screens that implement randr */
|
|
return TRUE;
|
|
}
|
|
|
|
/*ARGSUSED*/ static int
|
|
RRFreeClient(void *data, XID id)
|
|
{
|
|
RREventPtr pRREvent;
|
|
WindowPtr pWin;
|
|
RREventPtr *pHead, pCur, pPrev;
|
|
|
|
pRREvent = (RREventPtr) data;
|
|
pWin = pRREvent->window;
|
|
dixLookupResourceByType((void **) &pHead, pWin->drawable.id,
|
|
RREventType, serverClient, DixDestroyAccess);
|
|
if (pHead) {
|
|
pPrev = 0;
|
|
for (pCur = *pHead; pCur && pCur != pRREvent; pCur = pCur->next)
|
|
pPrev = pCur;
|
|
if (pCur) {
|
|
if (pPrev)
|
|
pPrev->next = pRREvent->next;
|
|
else
|
|
*pHead = pRREvent->next;
|
|
}
|
|
}
|
|
free((void *) pRREvent);
|
|
return 1;
|
|
}
|
|
|
|
/*ARGSUSED*/ static int
|
|
RRFreeEvents(void *data, XID id)
|
|
{
|
|
RREventPtr *pHead, pCur, pNext;
|
|
|
|
pHead = (RREventPtr *) data;
|
|
for (pCur = *pHead; pCur; pCur = pNext) {
|
|
pNext = pCur->next;
|
|
FreeResource(pCur->clientResource, RRClientType);
|
|
free((void *) pCur);
|
|
}
|
|
free((void *) pHead);
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
RRExtensionInit(void)
|
|
{
|
|
ExtensionEntry *extEntry;
|
|
|
|
if (RRNScreens == 0)
|
|
return;
|
|
|
|
if (!dixRegisterPrivateKey(&RRClientPrivateKeyRec, PRIVATE_CLIENT,
|
|
sizeof(RRClientRec) +
|
|
screenInfo.numScreens * sizeof(RRTimesRec)))
|
|
return;
|
|
if (!AddCallback(&ClientStateCallback, RRClientCallback, 0))
|
|
return;
|
|
|
|
RRClientType = CreateNewResourceType(RRFreeClient, "RandRClient");
|
|
if (!RRClientType)
|
|
return;
|
|
RREventType = CreateNewResourceType(RRFreeEvents, "RandREvent");
|
|
if (!RREventType)
|
|
return;
|
|
extEntry = AddExtension(RANDR_NAME, RRNumberEvents, RRNumberErrors,
|
|
ProcRRDispatch, SProcRRDispatch,
|
|
NULL, StandardMinorOpcode);
|
|
if (!extEntry)
|
|
return;
|
|
RRErrorBase = extEntry->errorBase;
|
|
RREventBase = extEntry->eventBase;
|
|
EventSwapVector[RREventBase + RRScreenChangeNotify] = (EventSwapPtr)
|
|
SRRScreenChangeNotifyEvent;
|
|
EventSwapVector[RREventBase + RRNotify] = (EventSwapPtr)
|
|
SRRNotifyEvent;
|
|
|
|
RRModeInitErrorValue();
|
|
RRCrtcInitErrorValue();
|
|
RROutputInitErrorValue();
|
|
RRProviderInitErrorValue();
|
|
#ifdef PANORAMIX
|
|
RRXineramaExtensionInit();
|
|
#endif
|
|
}
|
|
|
|
void
|
|
RRResourcesChanged(ScreenPtr pScreen)
|
|
{
|
|
rrScrPriv(pScreen);
|
|
pScrPriv->resourcesChanged = TRUE;
|
|
|
|
RRSetChanged(pScreen);
|
|
}
|
|
|
|
static void
|
|
RRDeliverResourceEvent(ClientPtr client, WindowPtr pWin)
|
|
{
|
|
ScreenPtr pScreen = pWin->drawable.pScreen;
|
|
|
|
rrScrPriv(pScreen);
|
|
|
|
xRRResourceChangeNotifyEvent re = {
|
|
.type = RRNotify + RREventBase,
|
|
.subCode = RRNotify_ResourceChange,
|
|
.timestamp = pScrPriv->lastSetTime.milliseconds,
|
|
.window = pWin->drawable.id
|
|
};
|
|
|
|
WriteEventsToClient(client, 1, (xEvent *) &re);
|
|
}
|
|
|
|
static int
|
|
TellChanged(WindowPtr pWin, void *value)
|
|
{
|
|
RREventPtr *pHead, pRREvent;
|
|
ClientPtr client;
|
|
ScreenPtr pScreen = pWin->drawable.pScreen;
|
|
ScreenPtr iter;
|
|
rrScrPrivPtr pSecondaryScrPriv;
|
|
|
|
rrScrPriv(pScreen);
|
|
int i;
|
|
|
|
dixLookupResourceByType((void **) &pHead, pWin->drawable.id,
|
|
RREventType, serverClient, DixReadAccess);
|
|
if (!pHead)
|
|
return WT_WALKCHILDREN;
|
|
|
|
for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next) {
|
|
client = pRREvent->client;
|
|
if (client == serverClient || client->clientGone)
|
|
continue;
|
|
|
|
if (pRREvent->mask & RRScreenChangeNotifyMask)
|
|
RRDeliverScreenEvent(client, pWin, pScreen);
|
|
|
|
if (pRREvent->mask & RRCrtcChangeNotifyMask) {
|
|
for (i = 0; i < pScrPriv->numCrtcs; i++) {
|
|
RRCrtcPtr crtc = pScrPriv->crtcs[i];
|
|
|
|
if (crtc->changed)
|
|
RRDeliverCrtcEvent(client, pWin, crtc);
|
|
}
|
|
|
|
xorg_list_for_each_entry(iter, &pScreen->secondary_list, secondary_head) {
|
|
if (!iter->is_output_secondary)
|
|
continue;
|
|
|
|
pSecondaryScrPriv = rrGetScrPriv(iter);
|
|
for (i = 0; i < pSecondaryScrPriv->numCrtcs; i++) {
|
|
RRCrtcPtr crtc = pSecondaryScrPriv->crtcs[i];
|
|
|
|
if (crtc->changed)
|
|
RRDeliverCrtcEvent(client, pWin, crtc);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pRREvent->mask & RROutputChangeNotifyMask) {
|
|
for (i = 0; i < pScrPriv->numOutputs; i++) {
|
|
RROutputPtr output = pScrPriv->outputs[i];
|
|
|
|
if (output->changed)
|
|
RRDeliverOutputEvent(client, pWin, output);
|
|
}
|
|
|
|
xorg_list_for_each_entry(iter, &pScreen->secondary_list, secondary_head) {
|
|
if (!iter->is_output_secondary)
|
|
continue;
|
|
|
|
pSecondaryScrPriv = rrGetScrPriv(iter);
|
|
for (i = 0; i < pSecondaryScrPriv->numOutputs; i++) {
|
|
RROutputPtr output = pSecondaryScrPriv->outputs[i];
|
|
|
|
if (output->changed)
|
|
RRDeliverOutputEvent(client, pWin, output);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pRREvent->mask & RRProviderChangeNotifyMask) {
|
|
xorg_list_for_each_entry(iter, &pScreen->secondary_list, secondary_head) {
|
|
pSecondaryScrPriv = rrGetScrPriv(iter);
|
|
if (pSecondaryScrPriv->provider->changed)
|
|
RRDeliverProviderEvent(client, pWin, pSecondaryScrPriv->provider);
|
|
}
|
|
}
|
|
|
|
if (pRREvent->mask & RRResourceChangeNotifyMask) {
|
|
if (pScrPriv->resourcesChanged) {
|
|
RRDeliverResourceEvent(client, pWin);
|
|
}
|
|
}
|
|
|
|
if (pRREvent->mask & RRLeaseNotifyMask) {
|
|
if (pScrPriv->leasesChanged) {
|
|
RRDeliverLeaseEvent(client, pWin);
|
|
}
|
|
}
|
|
}
|
|
return WT_WALKCHILDREN;
|
|
}
|
|
|
|
void
|
|
RRSetChanged(ScreenPtr pScreen)
|
|
{
|
|
/* set changed bits on the primary screen only */
|
|
ScreenPtr primary;
|
|
rrScrPriv(pScreen);
|
|
rrScrPrivPtr primarysp;
|
|
|
|
if (pScreen->isGPU) {
|
|
primary = pScreen->current_primary;
|
|
if (!primary)
|
|
return;
|
|
primarysp = rrGetScrPriv(primary);
|
|
}
|
|
else {
|
|
primary = pScreen;
|
|
primarysp = pScrPriv;
|
|
}
|
|
|
|
primarysp->changed = TRUE;
|
|
}
|
|
|
|
/*
|
|
* Something changed; send events and adjust pointer position
|
|
*/
|
|
void
|
|
RRTellChanged(ScreenPtr pScreen)
|
|
{
|
|
ScreenPtr primary;
|
|
rrScrPriv(pScreen);
|
|
rrScrPrivPtr primarysp;
|
|
int i;
|
|
ScreenPtr iter;
|
|
rrScrPrivPtr pSecondaryScrPriv;
|
|
|
|
if (pScreen->isGPU) {
|
|
primary = pScreen->current_primary;
|
|
if (!primary)
|
|
return;
|
|
primarysp = rrGetScrPriv(primary);
|
|
}
|
|
else {
|
|
primary = pScreen;
|
|
primarysp = pScrPriv;
|
|
}
|
|
|
|
/* If there's no root window yet, can't send events */
|
|
if (!primary->root)
|
|
return;
|
|
|
|
xorg_list_for_each_entry(iter, &primary->secondary_list, secondary_head) {
|
|
pSecondaryScrPriv = rrGetScrPriv(iter);
|
|
|
|
if (!iter->is_output_secondary)
|
|
continue;
|
|
|
|
if (CompareTimeStamps(primarysp->lastSetTime,
|
|
pSecondaryScrPriv->lastSetTime) == EARLIER) {
|
|
primarysp->lastSetTime = pSecondaryScrPriv->lastSetTime;
|
|
}
|
|
}
|
|
|
|
if (primarysp->changed) {
|
|
UpdateCurrentTimeIf();
|
|
if (primarysp->configChanged) {
|
|
primarysp->lastConfigTime = currentTime;
|
|
primarysp->configChanged = FALSE;
|
|
}
|
|
pScrPriv->changed = FALSE;
|
|
primarysp->changed = FALSE;
|
|
|
|
WalkTree(primary, TellChanged, (void *) primary);
|
|
|
|
primarysp->resourcesChanged = FALSE;
|
|
|
|
for (i = 0; i < pScrPriv->numOutputs; i++)
|
|
pScrPriv->outputs[i]->changed = FALSE;
|
|
for (i = 0; i < pScrPriv->numCrtcs; i++)
|
|
pScrPriv->crtcs[i]->changed = FALSE;
|
|
|
|
xorg_list_for_each_entry(iter, &primary->secondary_list, secondary_head) {
|
|
pSecondaryScrPriv = rrGetScrPriv(iter);
|
|
pSecondaryScrPriv->provider->changed = FALSE;
|
|
if (iter->is_output_secondary) {
|
|
for (i = 0; i < pSecondaryScrPriv->numOutputs; i++)
|
|
pSecondaryScrPriv->outputs[i]->changed = FALSE;
|
|
for (i = 0; i < pSecondaryScrPriv->numCrtcs; i++)
|
|
pSecondaryScrPriv->crtcs[i]->changed = FALSE;
|
|
}
|
|
}
|
|
|
|
if (primarysp->layoutChanged) {
|
|
pScrPriv->layoutChanged = FALSE;
|
|
RRPointerScreenConfigured(primary);
|
|
RRSendConfigNotify(primary);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Return the first output which is connected to an active CRTC
|
|
* Used in emulating 1.0 behaviour
|
|
*/
|
|
RROutputPtr
|
|
RRFirstOutput(ScreenPtr pScreen)
|
|
{
|
|
rrScrPriv(pScreen);
|
|
RROutputPtr output;
|
|
int i, j;
|
|
|
|
if (!pScrPriv)
|
|
return NULL;
|
|
|
|
if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc)
|
|
return pScrPriv->primaryOutput;
|
|
|
|
for (i = 0; i < pScrPriv->numCrtcs; i++) {
|
|
RRCrtcPtr crtc = pScrPriv->crtcs[i];
|
|
|
|
for (j = 0; j < pScrPriv->numOutputs; j++) {
|
|
output = pScrPriv->outputs[j];
|
|
if (output->crtc == crtc)
|
|
return output;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
RRCrtcPtr
|
|
RRFirstEnabledCrtc(ScreenPtr pScreen)
|
|
{
|
|
rrScrPriv(pScreen);
|
|
RROutputPtr output;
|
|
int i, j;
|
|
|
|
if (!pScrPriv)
|
|
return NULL;
|
|
|
|
if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc &&
|
|
pScrPriv->primaryOutput->pScreen == pScreen)
|
|
return pScrPriv->primaryOutput->crtc;
|
|
|
|
for (i = 0; i < pScrPriv->numCrtcs; i++) {
|
|
RRCrtcPtr crtc = pScrPriv->crtcs[i];
|
|
|
|
for (j = 0; j < pScrPriv->numOutputs; j++) {
|
|
output = pScrPriv->outputs[j];
|
|
if (output->crtc == crtc && crtc->mode)
|
|
return crtc;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
CARD16
|
|
RRVerticalRefresh(xRRModeInfo * mode)
|
|
{
|
|
CARD32 refresh;
|
|
CARD32 dots = mode->hTotal * mode->vTotal;
|
|
|
|
if (!dots)
|
|
return 0;
|
|
refresh = (mode->dotClock + dots / 2) / dots;
|
|
if (refresh > 0xffff)
|
|
refresh = 0xffff;
|
|
return (CARD16) refresh;
|
|
}
|
|
|
|
static int
|
|
ProcRRDispatch(ClientPtr client)
|
|
{
|
|
REQUEST(xReq);
|
|
if (stuff->data >= RRNumberRequests || !ProcRandrVector[stuff->data])
|
|
return BadRequest;
|
|
UpdateCurrentTimeIf();
|
|
return (*ProcRandrVector[stuff->data]) (client);
|
|
}
|
|
|
|
static int _X_COLD
|
|
SProcRRDispatch(ClientPtr client)
|
|
{
|
|
REQUEST(xReq);
|
|
if (stuff->data >= RRNumberRequests || !SProcRandrVector[stuff->data])
|
|
return BadRequest;
|
|
UpdateCurrentTimeIf();
|
|
return (*SProcRandrVector[stuff->data]) (client);
|
|
}
|