From: Alexander Volkov <a.vol...@rusbitech.ru> It was introduced in DPMS 1.2 (xorgproto). This allows applications to respond to changes of power level of a monitor, e.g. an application may stop rendering and related calculations when the monitor is off.
Related bug: https://bugs.freedesktop.org/57120 Signed-off-by: Alexander Volkov <a.vol...@rusbitech.ru> --- Xext/dpms.c | 212 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 207 insertions(+), 5 deletions(-) diff --git a/Xext/dpms.c b/Xext/dpms.c index e43a37974..3ac8b5795 100644 --- a/Xext/dpms.c +++ b/Xext/dpms.c @@ -50,6 +50,173 @@ CARD32 DPMSSuspendTime = -1; CARD32 DPMSOffTime = -1; Bool DPMSEnabled; +static int DPMSEventBase = 0; +static RESTYPE ClientType, DPMSEventType; /* resource types for event masks */ +static XID eventResource; + +typedef struct _DPMSEvent *DPMSEventPtr; +typedef struct _DPMSEvent { + DPMSEventPtr next; + ClientPtr client; + XID clientResource; + unsigned int mask; +} DPMSEventRec; + + /*ARGSUSED*/ static int +DPMSFreeClient(void *data, XID id) +{ + DPMSEventPtr pEvent; + DPMSEventPtr *pHead, pCur, pPrev; + + pEvent = (DPMSEventPtr) data; + dixLookupResourceByType((void *) &pHead, eventResource, DPMSEventType, + NullClient, DixUnknownAccess); + if (pHead) { + pPrev = 0; + for (pCur = *pHead; pCur && pCur != pEvent; pCur = pCur->next) + pPrev = pCur; + if (pCur) { + if (pPrev) + pPrev->next = pEvent->next; + else + *pHead = pEvent->next; + } + } + free((void *) pEvent); + return 1; +} + + /*ARGSUSED*/ static int +DPMSFreeEvents(void *data, XID id) +{ + DPMSEventPtr *pHead, pCur, pNext; + + pHead = (DPMSEventPtr *) data; + for (pCur = *pHead; pCur; pCur = pNext) { + pNext = pCur->next; + FreeResource(pCur->clientResource, ClientType); + free((void *) pCur); + } + free((void *) pHead); + return 1; +} + +static void +SDPMSInfoNotifyEvent(xDPMSInfoNotifyEvent * from, + xDPMSInfoNotifyEvent * to) +{ + to->type = from->type; + cpswaps(from->sequenceNumber, to->sequenceNumber); + cpswapl(from->timestamp, to->timestamp); + cpswaps(from->power_level, to->power_level); + to->state = from->state; +} + +static int +ProcDPMSSelectInput(register ClientPtr client) +{ + REQUEST(xDPMSSelectInputReq); + DPMSEventPtr pEvent, pNewEvent, *pHead; + XID clientResource; + int i; + + REQUEST_SIZE_MATCH(xDPMSSelectInputReq); + i = dixLookupResourceByType((void **)&pHead, eventResource, DPMSEventType, + client, + DixWriteAccess); + if (stuff->eventMask != 0) { + if (i == Success && pHead) { + /* check for existing entry. */ + for (pEvent = *pHead; pEvent; pEvent = pEvent->next) { + if (pEvent->client == client) { + pEvent->mask = stuff->eventMask; + return Success; + } + } + } + + /* build the entry */ + pNewEvent = (DPMSEventPtr)malloc(sizeof(DPMSEventRec)); + if (!pNewEvent) + return BadAlloc; + pNewEvent->next = 0; + pNewEvent->client = client; + pNewEvent->mask = stuff->eventMask; + /* + * add a resource that will be deleted when + * the client goes away + */ + clientResource = FakeClientID(client->index); + pNewEvent->clientResource = clientResource; + if (!AddResource(clientResource, ClientType, (void *)pNewEvent)) + return BadAlloc; + /* + * create a resource to contain a pointer to the list + * of clients selecting input. This must be indirect as + * the list may be arbitrarily rearranged which cannot be + * done through the resource database. + */ + if (i != Success || !pHead) { + pHead = (DPMSEventPtr *)malloc(sizeof(DPMSEventPtr)); + if (!pHead || + !AddResource(eventResource, DPMSEventType, (void *)pHead)) { + FreeResource(clientResource, RT_NONE); + return BadAlloc; + } + *pHead = 0; + } + pNewEvent->next = *pHead; + *pHead = pNewEvent; + } + else if (stuff->eventMask == 0) { + /* delete the interest */ + if (i == Success && pHead) { + pNewEvent = 0; + for (pEvent = *pHead; pEvent; pEvent = pEvent->next) { + if (pEvent->client == client) + break; + pNewEvent = pEvent; + } + if (pEvent) { + FreeResource(pEvent->clientResource, ClientType); + if (pNewEvent) + pNewEvent->next = pEvent->next; + else + *pHead = pEvent->next; + free(pEvent); + } + } + } + else { + client->errorValue = stuff->eventMask; + return BadValue; + } + return Success; +} + +static void +SendDPMSInfoNotify(void) +{ + DPMSEventPtr *pHead, pEvent; + xDPMSInfoNotifyEvent se; + int i; + + i = dixLookupResourceByType((void **)&pHead, eventResource, DPMSEventType, + serverClient, + DixReadAccess); + if (i != Success || !pHead) + return; + for (pEvent = *pHead; pEvent; pEvent = pEvent->next) { + if ((pEvent->mask & DPMSInfoNotifyMask) == 0) + continue; + se.type = DPMSEventBase + DPMSInfoNotify; + se.timestamp = currentTime.milliseconds; + se.power_level = DPMSPowerLevel; + se.state = DPMSEnabled; + WriteEventsToClient(pEvent->client, 1, (xEvent *)&se); + } +} + Bool DPMSSupported(void) { @@ -86,6 +253,7 @@ int DPMSSet(ClientPtr client, int level) { int rc, i; + int old_level = DPMSPowerLevel; DPMSPowerLevel = level; @@ -109,6 +277,9 @@ DPMSSet(ClientPtr client, int level) if (screenInfo.gpuscreens[i]->DPMS != NULL) screenInfo.gpuscreens[i]->DPMS(screenInfo.gpuscreens[i], level); + if (DPMSPowerLevel != old_level) + SendDPMSInfoNotify(); + return Success; } @@ -212,8 +383,10 @@ ProcDPMSEnable(ClientPtr client) REQUEST_SIZE_MATCH(xDPMSEnableReq); DPMSEnabled = TRUE; - if (!was_enabled) + if (!was_enabled) { SetScreenSaverTimer(); + SendDPMSInfoNotify(); + } return Success; } @@ -221,6 +394,8 @@ ProcDPMSEnable(ClientPtr client) static int ProcDPMSDisable(ClientPtr client) { + Bool was_enabled = DPMSEnabled; + /* REQUEST(xDPMSDisableReq); */ REQUEST_SIZE_MATCH(xDPMSDisableReq); @@ -228,6 +403,8 @@ ProcDPMSDisable(ClientPtr client) DPMSSet(client, DPMSModeOn); DPMSEnabled = FALSE; + if (was_enabled) + SendDPMSInfoNotify(); return Success; } @@ -298,6 +475,8 @@ ProcDPMSDispatch(ClientPtr client) return ProcDPMSForceLevel(client); case X_DPMSInfo: return ProcDPMSInfo(client); + case X_DPMSSelectInput: + return ProcDPMSSelectInput(client); default: return BadRequest; } @@ -397,6 +576,18 @@ SProcDPMSInfo(ClientPtr client) return ProcDPMSInfo(client); } +static int _X_COLD +SProcDPMSSelectInput(ClientPtr client) +{ + REQUEST(xDPMSSelectInputReq); + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xDPMSSelectInputReq); + swapl(&stuff->eventMask); + return ProcDPMSSelectInput(client); +} + + + static int _X_COLD SProcDPMSDispatch(ClientPtr client) { @@ -418,6 +609,8 @@ SProcDPMSDispatch(ClientPtr client) return SProcDPMSForceLevel(client); case X_DPMSInfo: return SProcDPMSInfo(client); + case X_DPMSSelectInput: + return SProcDPMSSelectInput(client); default: return BadRequest; } @@ -432,6 +625,8 @@ DPMSCloseDownExtension(ExtensionEntry *e) void DPMSExtensionInit(void) { + ExtensionEntry *extEntry; + #define CONDITIONALLY_SET_DPMS_TIMEOUT(_timeout_value_) \ if (_timeout_value_ == -1) { /* not yet set from config */ \ _timeout_value_ = ScreenSaverTime; \ @@ -444,8 +639,15 @@ DPMSExtensionInit(void) DPMSPowerLevel = DPMSModeOn; DPMSEnabled = DPMSSupported(); - if (DPMSEnabled) - AddExtension(DPMSExtensionName, 0, 0, - ProcDPMSDispatch, SProcDPMSDispatch, - DPMSCloseDownExtension, StandardMinorOpcode); + ClientType = CreateNewResourceType(DPMSFreeClient, "DPMSClient"); + DPMSEventType = CreateNewResourceType(DPMSFreeEvents, "DPMSEvent"); + eventResource = FakeClientID(0); + + if (DPMSEnabled && ClientType && DPMSEventType && + (extEntry = AddExtension(DPMSExtensionName, DPMSNumberEvents, 0, + ProcDPMSDispatch, SProcDPMSDispatch, + DPMSCloseDownExtension, StandardMinorOpcode))) { + DPMSEventBase = extEntry->eventBase; + EventSwapVector[DPMSEventBase] = (EventSwapPtr) SDPMSInfoNotifyEvent; + } } -- 2.17.0 _______________________________________________ xorg-devel@lists.x.org: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: https://lists.x.org/mailman/listinfo/xorg-devel