[PATCH xserver] dpms: Add support for DPMSInfoNotify event
Alexander Volkov
avolkov at astralinux.ru
Tue Oct 2 13:10:37 UTC 2018
From: Alexander Volkov <a.volkov at 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.volkov at 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
More information about the xorg-devel
mailing list