Commit 35e276c2 authored by Alexander Volkov's avatar Alexander Volkov Committed by Alexander Volkov

dpms: Add support for DPMSInfoNotify event from 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/57120Signed-off-by: Alexander Volkov's avatarAlexander Volkov <a.volkov@rusbitech.ru>
parent 9bf33bab
Pipeline #146136 passed with stages
in 4 minutes and 55 seconds
......@@ -42,6 +42,7 @@ Equipment Corporation.
#include "extinit.h"
#include "scrnintstr.h"
#include "windowstr.h"
#include "protocol-versions.h"
CARD16 DPMSPowerLevel = 0;
Bool DPMSDisabledSwitch = FALSE;
......@@ -50,6 +51,178 @@ CARD32 DPMSSuspendTime = -1;
CARD32 DPMSOffTime = -1;
Bool DPMSEnabled;
static int DPMSReqCode = 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(xGenericEvent * from,
xGenericEvent * to)
{
*to = *from;
swaps(&to->sequenceNumber);
swapl(&to->length);
swaps(&to->evtype);
if (from->evtype == DPMSInfoNotify) {
xDPMSInfoNotifyEvent *c = (xDPMSInfoNotifyEvent *) to;
swapl(&c->timestamp);
swaps(&c->power_level);
}
}
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 == DPMSInfoNotifyMask) {
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
*/
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 = GenericEvent;
se.extension = DPMSReqCode;
se.length = (sizeof(xDPMSInfoNotifyEvent) - 32) >> 2;
se.evtype = DPMSInfoNotify;
se.timestamp = currentTime.milliseconds;
se.power_level = DPMSPowerLevel;
se.state = DPMSEnabled;
WriteEventsToClient(pEvent->client, 1, (xEvent *)&se);
}
}
Bool
DPMSSupported(void)
{
......@@ -86,6 +259,7 @@ int
DPMSSet(ClientPtr client, int level)
{
int rc, i;
int old_level = DPMSPowerLevel;
DPMSPowerLevel = level;
......@@ -109,6 +283,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;
}
......@@ -120,8 +297,8 @@ ProcDPMSGetVersion(ClientPtr client)
.type = X_Reply,
.sequenceNumber = client->sequence,
.length = 0,
.majorVersion = DPMSMajorVersion,
.minorVersion = DPMSMinorVersion
.majorVersion = SERVER_DPMS_MAJOR_VERSION,
.minorVersion = SERVER_DPMS_MINOR_VERSION
};
REQUEST_SIZE_MATCH(xDPMSGetVersionReq);
......@@ -212,8 +389,10 @@ ProcDPMSEnable(ClientPtr client)
REQUEST_SIZE_MATCH(xDPMSEnableReq);
DPMSEnabled = TRUE;
if (!was_enabled)
if (!was_enabled) {
SetScreenSaverTimer();
SendDPMSInfoNotify();
}
return Success;
}
......@@ -221,6 +400,8 @@ ProcDPMSEnable(ClientPtr client)
static int
ProcDPMSDisable(ClientPtr client)
{
Bool was_enabled = DPMSEnabled;
/* REQUEST(xDPMSDisableReq); */
REQUEST_SIZE_MATCH(xDPMSDisableReq);
......@@ -228,6 +409,8 @@ ProcDPMSDisable(ClientPtr client)
DPMSSet(client, DPMSModeOn);
DPMSEnabled = FALSE;
if (was_enabled)
SendDPMSInfoNotify();
return Success;
}
......@@ -298,6 +481,8 @@ ProcDPMSDispatch(ClientPtr client)
return ProcDPMSForceLevel(client);
case X_DPMSInfo:
return ProcDPMSInfo(client);
case X_DPMSSelectInput:
return ProcDPMSSelectInput(client);
default:
return BadRequest;
}
......@@ -397,6 +582,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 +615,8 @@ SProcDPMSDispatch(ClientPtr client)
return SProcDPMSForceLevel(client);
case X_DPMSInfo:
return SProcDPMSInfo(client);
case X_DPMSSelectInput:
return SProcDPMSSelectInput(client);
default:
return BadRequest;
}
......@@ -432,6 +631,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 +645,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, 0, 0,
ProcDPMSDispatch, SProcDPMSDispatch,
DPMSCloseDownExtension, StandardMinorOpcode))) {
DPMSReqCode = extEntry->base;
GERegisterExtension(DPMSReqCode, SDPMSInfoNotifyEvent);
}
}
......@@ -737,6 +737,7 @@ DMXPROTO="dmxproto >= 2.2.99.1"
VIDMODEPROTO="xf86vidmodeproto >= 2.2.99.1"
APPLEWMPROTO="applewmproto >= 1.4"
LIBXSHMFENCE="xshmfence >= 1.1"
DPMSPROTO="dpmsproto >= 1.2"
dnl Required modules
XPROTO="xproto >= 7.0.31"
......@@ -1318,6 +1319,8 @@ fi
AM_CONDITIONAL(DPMSExtension, [test "x$DPMSExtension" = xyes])
if test "x$DPMSExtension" = xyes; then
AC_DEFINE(DPMSExtension, 1, [Support DPMS extension])
REQUIRED_MODULES="$REQUIRED_MODULES $DPMSPROTO"
SDK_REQUIRED_MODULES="$SDK_REQUIRED_MODULES $DPMSPROTO"
fi
AC_DEFINE(RENDER, 1, [Support RENDER extension])
......
......@@ -46,6 +46,10 @@
#define SERVER_DAMAGE_MAJOR_VERSION 1
#define SERVER_DAMAGE_MINOR_VERSION 1
/* DPMS */
#define SERVER_DPMS_MAJOR_VERSION 1
#define SERVER_DPMS_MINOR_VERSION 2
/* DRI3 */
#define SERVER_DRI3_MAJOR_VERSION 1
#define SERVER_DRI3_MINOR_VERSION 2
......
......@@ -92,6 +92,7 @@ xf86bigfontproto_dep = dependency('xf86bigfontproto', version: '>= 1.2.0', requi
xf86vidmodeproto_dep = dependency('xf86vidmodeproto', version: '>= 2.2.99.1')
applewmproto_dep = dependency('applewmproto', version: '>= 1.4', required: false)
xshmfence_dep = dependency('xshmfence', version: '>= 1.1', required: false)
dpmsproto_dep = dependency('dpmsproto', version: '>= 1.2', required: get_option('dpms'))
pixman_dep = dependency('pixman-1')
libbsd_dep = dependency('libbsd', required: false)
......@@ -587,6 +588,7 @@ common_dep = [
xf86dgaproto_dep,
xf86vidmodeproto_dep,
applewmproto_dep,
dpmsproto_dep,
pixman_dep,
libbsd_dep,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment