1/* 2 * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina. 3 * 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining 7 * a copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation on the rights to use, copy, modify, merge, 10 * publish, distribute, sublicense, and/or sell copies of the Software, 11 * and to permit persons to whom the Software is furnished to do so, 12 * subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial 16 * portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS 22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 * SOFTWARE. 26 */ 27 28/* 29 * Author: 30 * Rickard E. (Rik) Faith <faith@redhat.com> 31 * 32 */ 33 34/** \file 35 * Provides DPMS support and unifies all DPMS and other screen-saver 36 * support in one file. If -dpms is given on the command line, or the 37 * Xdmx server is not compiled with DPMS support, then the DPMS extension 38 * does not work for clients, but DPMS on the backends is still disables 39 * (and restored at Xdmx server shutdown time). 40 */ 41 42#ifdef HAVE_DMX_CONFIG_H 43#include <dmx-config.h> 44#endif 45 46#include "dmx.h" 47#include "dmxdpms.h" 48#include "dmxlog.h" 49#include "dmxsync.h" 50#ifdef DPMSExtension 51#include "dpmsproc.h" 52#endif 53#include "windowstr.h" /* For screenIsSaved */ 54#include <X11/extensions/dpms.h> 55 56static unsigned long dpmsGeneration = 0; 57static Bool dpmsSupported = TRUE; 58 59static void _dmxDPMSInit(DMXScreenInfo *dmxScreen) 60{ 61 int event_base, error_base; 62 int major, minor; 63 CARD16 level, standby, suspend, off; 64 BOOL state; 65 const char *monitor; 66 67 if (dpmsGeneration != serverGeneration) { 68 dpmsSupported = TRUE; /* On unless a backend doesn't support it */ 69 dpmsGeneration = serverGeneration; 70 } 71 72#ifdef DPMSExtension 73 if (DPMSDisabledSwitch) dpmsSupported = FALSE; /* -dpms turns off */ 74#endif 75 76 dmxScreen->dpmsCapable = 0; 77 78 if (!dmxScreen->beDisplay) { 79 dmxLogOutput(dmxScreen, 80 "Cannot determine if DPMS supported (detached screen)\n"); 81 dpmsSupported = FALSE; 82 return; 83 } 84 85 if (!DPMSQueryExtension(dmxScreen->beDisplay, 86 &event_base, &error_base)) { 87 dmxLogOutput(dmxScreen, "DPMS not supported\n"); 88 dpmsSupported = FALSE; 89 return; 90 } 91 if (!DPMSGetVersion(dmxScreen->beDisplay, &major, &minor)) { 92 dmxLogOutput(dmxScreen, "DPMS not supported\n"); 93 dpmsSupported = FALSE; 94 return; 95 } 96 if (!DPMSCapable(dmxScreen->beDisplay)) { 97 dmxLogOutput(dmxScreen, "DPMS %d.%d (not DPMS capable)\n", 98 major, minor); 99 dpmsSupported = FALSE; 100 return; 101 } 102 103 DPMSInfo(dmxScreen->beDisplay, &level, &state); 104 DPMSGetTimeouts(dmxScreen->beDisplay, &standby, &suspend, &off); 105 DPMSSetTimeouts(dmxScreen->beDisplay, 0, 0, 0); 106 DPMSEnable(dmxScreen->beDisplay); 107 DPMSForceLevel(dmxScreen->beDisplay, DPMSModeOn); 108 dmxScreen->dpmsCapable = 1; 109 dmxScreen->dpmsEnabled = !!state; 110 dmxScreen->dpmsStandby = standby; 111 dmxScreen->dpmsSuspend = suspend; 112 dmxScreen->dpmsOff = off; 113 114 switch (level) { 115 case DPMSModeOn: monitor = "on"; break; 116 case DPMSModeStandby: monitor = "standby"; break; 117 case DPMSModeSuspend: monitor = "suspend"; break; 118 case DPMSModeOff: monitor = "off"; break; 119 default: monitor = "unknown"; break; 120 } 121 122 dmxLogOutput(dmxScreen, 123 "DPMS %d.%d (%s, %s, %d %d %d)\n", 124 major, minor, monitor, state ? "enabled" : "disabled", 125 standby, suspend, off); 126} 127 128/** Initialize DPMS support. We save the current settings and turn off 129 * DPMS. The settings are restored in #dmxDPMSTerm. */ 130void dmxDPMSInit(DMXScreenInfo *dmxScreen) 131{ 132 int interval, preferBlanking, allowExposures; 133 134 /* Turn off DPMS */ 135 _dmxDPMSInit(dmxScreen); 136 137 if (!dmxScreen->beDisplay) 138 return; 139 140 /* Turn off screen saver */ 141 XGetScreenSaver(dmxScreen->beDisplay, &dmxScreen->savedTimeout, &interval, 142 &preferBlanking, &allowExposures); 143 XSetScreenSaver(dmxScreen->beDisplay, 0, interval, 144 preferBlanking, allowExposures); 145 XResetScreenSaver(dmxScreen->beDisplay); 146 dmxSync(dmxScreen, FALSE); 147} 148 149/** Terminate DPMS support on \a dmxScreen. We restore the settings 150 * saved in #dmxDPMSInit. */ 151void dmxDPMSTerm(DMXScreenInfo *dmxScreen) 152{ 153 int timeout, interval, preferBlanking, allowExposures; 154 155 if (!dmxScreen->beDisplay) 156 return; 157 158 XGetScreenSaver(dmxScreen->beDisplay, &timeout, &interval, 159 &preferBlanking, &allowExposures); 160 XSetScreenSaver(dmxScreen->beDisplay, dmxScreen->savedTimeout, interval, 161 preferBlanking, allowExposures); 162 if (dmxScreen->dpmsCapable) { 163 /* Restore saved state */ 164 DPMSForceLevel(dmxScreen->beDisplay, DPMSModeOn); 165 DPMSSetTimeouts(dmxScreen->beDisplay, dmxScreen->dpmsStandby, 166 dmxScreen->dpmsSuspend, dmxScreen->dpmsOff); 167 if (dmxScreen->dpmsEnabled) DPMSEnable(dmxScreen->beDisplay); 168 else DPMSDisable(dmxScreen->beDisplay); 169 } 170 dmxSync(dmxScreen, FALSE); 171} 172 173/** Called when activity is detected so that DPMS power-saving mode can 174 * be deactivated. */ 175void dmxDPMSWakeup(void) 176{ 177 if (screenIsSaved == SCREEN_SAVER_ON) 178 dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset); 179#ifdef DPMSExtension 180 if (DPMSPowerLevel) DPMSSet(serverClient, 0); 181#endif 182} 183 184#ifdef DPMSExtension 185/** This is called on each server generation. It should determine if 186 * DPMS is supported on all of the backends and, if so, return TRUE. */ 187Bool DPMSSupported(void) 188{ 189 return dpmsSupported; 190} 191 192/** This is used by clients (e.g., xset) to set the DPMS level. */ 193int DPMSSet(ClientPtr client, int level) 194{ 195 int i; 196 197 if (!dpmsSupported) return Success; 198 199 if (level < 0) level = DPMSModeOn; 200 if (level > 3) level = DPMSModeOff; 201 202 DPMSPowerLevel = level; 203 204 for (i = 0; i < dmxNumScreens; i++) { 205 DMXScreenInfo *dmxScreen = &dmxScreens[i]; 206 if (dmxScreen->beDisplay) { 207 DPMSForceLevel(dmxScreen->beDisplay, level); 208 dmxSync(dmxScreen, FALSE); 209 } 210 } 211 return Success; 212} 213#endif 214