1/*****************************************************************
2
3Copyright (c) 1996 Digital Equipment Corporation, Maynard, Massachusetts.
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
18BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
19WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
20IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of Digital Equipment Corporation
23shall not be used in advertising or otherwise to promote the sale, use or other
24dealings in this Software without prior written authorization from Digital
25Equipment Corporation.
26
27******************************************************************/
28
29#ifdef HAVE_DIX_CONFIG_H
30#include <dix-config.h>
31#endif
32
33#include <X11/X.h>
34#include <X11/Xproto.h>
35#include "misc.h"
36#include "os.h"
37#include "dixstruct.h"
38#include "extnsionst.h"
39#include "opaque.h"
40#include <X11/extensions/dpmsproto.h>
41#include "dpmsproc.h"
42#include "extinit.h"
43#include "scrnintstr.h"
44#include "windowstr.h"
45
46CARD16 DPMSPowerLevel = 0;
47Bool DPMSDisabledSwitch = FALSE;
48CARD32 DPMSStandbyTime = -1;
49CARD32 DPMSSuspendTime = -1;
50CARD32 DPMSOffTime = -1;
51Bool DPMSEnabled;
52
53Bool
54DPMSSupported(void)
55{
56    int i;
57
58    /* For each screen, check if DPMS is supported */
59    for (i = 0; i < screenInfo.numScreens; i++)
60        if (screenInfo.screens[i]->DPMS != NULL)
61            return TRUE;
62
63    for (i = 0; i < screenInfo.numGPUScreens; i++)
64        if (screenInfo.gpuscreens[i]->DPMS != NULL)
65            return TRUE;
66
67    return FALSE;
68}
69
70static Bool
71isUnblank(int mode)
72{
73    switch (mode) {
74    case SCREEN_SAVER_OFF:
75    case SCREEN_SAVER_FORCER:
76        return TRUE;
77    case SCREEN_SAVER_ON:
78    case SCREEN_SAVER_CYCLE:
79        return FALSE;
80    default:
81        return TRUE;
82    }
83}
84
85int
86DPMSSet(ClientPtr client, int level)
87{
88    int rc, i;
89
90    DPMSPowerLevel = level;
91
92    if (level != DPMSModeOn) {
93        if (isUnblank(screenIsSaved)) {
94            rc = dixSaveScreens(client, SCREEN_SAVER_FORCER, ScreenSaverActive);
95            if (rc != Success)
96                return rc;
97        }
98    } else if (!isUnblank(screenIsSaved)) {
99        rc = dixSaveScreens(client, SCREEN_SAVER_OFF, ScreenSaverReset);
100        if (rc != Success)
101            return rc;
102    }
103
104    for (i = 0; i < screenInfo.numScreens; i++)
105        if (screenInfo.screens[i]->DPMS != NULL)
106            screenInfo.screens[i]->DPMS(screenInfo.screens[i], level);
107
108    for (i = 0; i < screenInfo.numGPUScreens; i++)
109        if (screenInfo.gpuscreens[i]->DPMS != NULL)
110            screenInfo.gpuscreens[i]->DPMS(screenInfo.gpuscreens[i], level);
111
112    return Success;
113}
114
115static int
116ProcDPMSGetVersion(ClientPtr client)
117{
118    /* REQUEST(xDPMSGetVersionReq); */
119    xDPMSGetVersionReply rep = {
120        .type = X_Reply,
121        .sequenceNumber = client->sequence,
122        .length = 0,
123        .majorVersion = DPMSMajorVersion,
124        .minorVersion = DPMSMinorVersion
125    };
126
127    REQUEST_SIZE_MATCH(xDPMSGetVersionReq);
128
129    if (client->swapped) {
130        swaps(&rep.sequenceNumber);
131        swaps(&rep.majorVersion);
132        swaps(&rep.minorVersion);
133    }
134    WriteToClient(client, sizeof(xDPMSGetVersionReply), &rep);
135    return Success;
136}
137
138static int
139ProcDPMSCapable(ClientPtr client)
140{
141    /* REQUEST(xDPMSCapableReq); */
142    xDPMSCapableReply rep = {
143        .type = X_Reply,
144        .sequenceNumber = client->sequence,
145        .length = 0,
146        .capable = TRUE
147    };
148
149    REQUEST_SIZE_MATCH(xDPMSCapableReq);
150
151    if (client->swapped) {
152        swaps(&rep.sequenceNumber);
153    }
154    WriteToClient(client, sizeof(xDPMSCapableReply), &rep);
155    return Success;
156}
157
158static int
159ProcDPMSGetTimeouts(ClientPtr client)
160{
161    /* REQUEST(xDPMSGetTimeoutsReq); */
162    xDPMSGetTimeoutsReply rep = {
163        .type = X_Reply,
164        .sequenceNumber = client->sequence,
165        .length = 0,
166        .standby = DPMSStandbyTime / MILLI_PER_SECOND,
167        .suspend = DPMSSuspendTime / MILLI_PER_SECOND,
168        .off = DPMSOffTime / MILLI_PER_SECOND
169    };
170
171    REQUEST_SIZE_MATCH(xDPMSGetTimeoutsReq);
172
173    if (client->swapped) {
174        swaps(&rep.sequenceNumber);
175        swaps(&rep.standby);
176        swaps(&rep.suspend);
177        swaps(&rep.off);
178    }
179    WriteToClient(client, sizeof(xDPMSGetTimeoutsReply), &rep);
180    return Success;
181}
182
183static int
184ProcDPMSSetTimeouts(ClientPtr client)
185{
186    REQUEST(xDPMSSetTimeoutsReq);
187
188    REQUEST_SIZE_MATCH(xDPMSSetTimeoutsReq);
189
190    if ((stuff->off != 0) && (stuff->off < stuff->suspend)) {
191        client->errorValue = stuff->off;
192        return BadValue;
193    }
194    if ((stuff->suspend != 0) && (stuff->suspend < stuff->standby)) {
195        client->errorValue = stuff->suspend;
196        return BadValue;
197    }
198
199    DPMSStandbyTime = stuff->standby * MILLI_PER_SECOND;
200    DPMSSuspendTime = stuff->suspend * MILLI_PER_SECOND;
201    DPMSOffTime = stuff->off * MILLI_PER_SECOND;
202    SetScreenSaverTimer();
203
204    return Success;
205}
206
207static int
208ProcDPMSEnable(ClientPtr client)
209{
210    Bool was_enabled = DPMSEnabled;
211
212    REQUEST_SIZE_MATCH(xDPMSEnableReq);
213
214    DPMSEnabled = TRUE;
215    if (!was_enabled)
216        SetScreenSaverTimer();
217
218    return Success;
219}
220
221static int
222ProcDPMSDisable(ClientPtr client)
223{
224    /* REQUEST(xDPMSDisableReq); */
225
226    REQUEST_SIZE_MATCH(xDPMSDisableReq);
227
228    DPMSSet(client, DPMSModeOn);
229
230    DPMSEnabled = FALSE;
231
232    return Success;
233}
234
235static int
236ProcDPMSForceLevel(ClientPtr client)
237{
238    REQUEST(xDPMSForceLevelReq);
239
240    REQUEST_SIZE_MATCH(xDPMSForceLevelReq);
241
242    if (!DPMSEnabled)
243        return BadMatch;
244
245    if (stuff->level != DPMSModeOn &&
246        stuff->level != DPMSModeStandby &&
247        stuff->level != DPMSModeSuspend && stuff->level != DPMSModeOff) {
248        client->errorValue = stuff->level;
249        return BadValue;
250    }
251
252    DPMSSet(client, stuff->level);
253
254    return Success;
255}
256
257static int
258ProcDPMSInfo(ClientPtr client)
259{
260    /* REQUEST(xDPMSInfoReq); */
261    xDPMSInfoReply rep = {
262        .type = X_Reply,
263        .sequenceNumber = client->sequence,
264        .length = 0,
265        .power_level = DPMSPowerLevel,
266        .state = DPMSEnabled
267    };
268
269    REQUEST_SIZE_MATCH(xDPMSInfoReq);
270
271    if (client->swapped) {
272        swaps(&rep.sequenceNumber);
273        swaps(&rep.power_level);
274    }
275    WriteToClient(client, sizeof(xDPMSInfoReply), &rep);
276    return Success;
277}
278
279static int
280ProcDPMSDispatch(ClientPtr client)
281{
282    REQUEST(xReq);
283
284    switch (stuff->data) {
285    case X_DPMSGetVersion:
286        return ProcDPMSGetVersion(client);
287    case X_DPMSCapable:
288        return ProcDPMSCapable(client);
289    case X_DPMSGetTimeouts:
290        return ProcDPMSGetTimeouts(client);
291    case X_DPMSSetTimeouts:
292        return ProcDPMSSetTimeouts(client);
293    case X_DPMSEnable:
294        return ProcDPMSEnable(client);
295    case X_DPMSDisable:
296        return ProcDPMSDisable(client);
297    case X_DPMSForceLevel:
298        return ProcDPMSForceLevel(client);
299    case X_DPMSInfo:
300        return ProcDPMSInfo(client);
301    default:
302        return BadRequest;
303    }
304}
305
306static int _X_COLD
307SProcDPMSGetVersion(ClientPtr client)
308{
309    REQUEST(xDPMSGetVersionReq);
310
311    swaps(&stuff->length);
312    REQUEST_SIZE_MATCH(xDPMSGetVersionReq);
313    swaps(&stuff->majorVersion);
314    swaps(&stuff->minorVersion);
315    return ProcDPMSGetVersion(client);
316}
317
318static int _X_COLD
319SProcDPMSCapable(ClientPtr client)
320{
321    REQUEST(xDPMSCapableReq);
322
323    swaps(&stuff->length);
324    REQUEST_SIZE_MATCH(xDPMSCapableReq);
325
326    return ProcDPMSCapable(client);
327}
328
329static int _X_COLD
330SProcDPMSGetTimeouts(ClientPtr client)
331{
332    REQUEST(xDPMSGetTimeoutsReq);
333
334    swaps(&stuff->length);
335    REQUEST_SIZE_MATCH(xDPMSGetTimeoutsReq);
336
337    return ProcDPMSGetTimeouts(client);
338}
339
340static int _X_COLD
341SProcDPMSSetTimeouts(ClientPtr client)
342{
343    REQUEST(xDPMSSetTimeoutsReq);
344
345    swaps(&stuff->length);
346    REQUEST_SIZE_MATCH(xDPMSSetTimeoutsReq);
347
348    swaps(&stuff->standby);
349    swaps(&stuff->suspend);
350    swaps(&stuff->off);
351    return ProcDPMSSetTimeouts(client);
352}
353
354static int _X_COLD
355SProcDPMSEnable(ClientPtr client)
356{
357    REQUEST(xDPMSEnableReq);
358
359    swaps(&stuff->length);
360    REQUEST_SIZE_MATCH(xDPMSEnableReq);
361
362    return ProcDPMSEnable(client);
363}
364
365static int _X_COLD
366SProcDPMSDisable(ClientPtr client)
367{
368    REQUEST(xDPMSDisableReq);
369
370    swaps(&stuff->length);
371    REQUEST_SIZE_MATCH(xDPMSDisableReq);
372
373    return ProcDPMSDisable(client);
374}
375
376static int _X_COLD
377SProcDPMSForceLevel(ClientPtr client)
378{
379    REQUEST(xDPMSForceLevelReq);
380
381    swaps(&stuff->length);
382    REQUEST_SIZE_MATCH(xDPMSForceLevelReq);
383
384    swaps(&stuff->level);
385
386    return ProcDPMSForceLevel(client);
387}
388
389static int _X_COLD
390SProcDPMSInfo(ClientPtr client)
391{
392    REQUEST(xDPMSInfoReq);
393
394    swaps(&stuff->length);
395    REQUEST_SIZE_MATCH(xDPMSInfoReq);
396
397    return ProcDPMSInfo(client);
398}
399
400static int _X_COLD
401SProcDPMSDispatch(ClientPtr client)
402{
403    REQUEST(xReq);
404    switch (stuff->data) {
405    case X_DPMSGetVersion:
406        return SProcDPMSGetVersion(client);
407    case X_DPMSCapable:
408        return SProcDPMSCapable(client);
409    case X_DPMSGetTimeouts:
410        return SProcDPMSGetTimeouts(client);
411    case X_DPMSSetTimeouts:
412        return SProcDPMSSetTimeouts(client);
413    case X_DPMSEnable:
414        return SProcDPMSEnable(client);
415    case X_DPMSDisable:
416        return SProcDPMSDisable(client);
417    case X_DPMSForceLevel:
418        return SProcDPMSForceLevel(client);
419    case X_DPMSInfo:
420        return SProcDPMSInfo(client);
421    default:
422        return BadRequest;
423    }
424}
425
426static void
427DPMSCloseDownExtension(ExtensionEntry *e)
428{
429    DPMSSet(serverClient, DPMSModeOn);
430}
431
432void
433DPMSExtensionInit(void)
434{
435#define CONDITIONALLY_SET_DPMS_TIMEOUT(_timeout_value_)         \
436    if (_timeout_value_ == -1) { /* not yet set from config */  \
437        _timeout_value_ = ScreenSaverTime;                      \
438    }
439
440    CONDITIONALLY_SET_DPMS_TIMEOUT(DPMSStandbyTime)
441    CONDITIONALLY_SET_DPMS_TIMEOUT(DPMSSuspendTime)
442    CONDITIONALLY_SET_DPMS_TIMEOUT(DPMSOffTime)
443
444    DPMSPowerLevel = DPMSModeOn;
445    DPMSEnabled = DPMSSupported();
446
447    if (DPMSEnabled)
448        AddExtension(DPMSExtensionName, 0, 0,
449                     ProcDPMSDispatch, SProcDPMSDispatch,
450                     DPMSCloseDownExtension, StandardMinorOpcode);
451}
452