2 * Copyright (C) 2009-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
22 #include "DPMSSupport.h"
23 #include "utils/log.h"
24 #include "windowing/WindowingFactory.h"
25 #include "utils/SystemInfo.h"
29 #include "guilib/GraphicContext.h"
32 //////// Generic, non-platform-specific code
34 static const char* const MODE_NAMES[DPMSSupport::NUM_MODES] =
35 { "STANDBY", "SUSPEND", "OFF" };
37 bool DPMSSupport::CheckValidMode(PowerSavingMode mode)
39 if (mode < 0 || mode > NUM_MODES)
41 CLog::Log(LOGERROR, "Invalid power-saving mode %d", mode);
47 const char* DPMSSupport::GetModeName(PowerSavingMode mode)
49 if (!CheckValidMode(mode)) return NULL;
50 return MODE_NAMES[mode];
53 DPMSSupport::DPMSSupport()
55 PlatformSpecificInit();
57 if (!m_supportedModes.empty())
59 std::string modes_message;
60 for (size_t i = 0; i < m_supportedModes.size(); i++)
62 assert(CheckValidMode(m_supportedModes[i]));
64 modes_message += MODE_NAMES[m_supportedModes[i]];
66 CLog::Log(LOGDEBUG, "DPMS: supported power-saving modes:%s",
67 modes_message.c_str());
71 bool DPMSSupport::IsModeSupported(PowerSavingMode mode) const
73 if (!CheckValidMode(mode)) return false;
74 for (size_t i = 0; i < m_supportedModes.size(); i++)
76 if (m_supportedModes[i] == mode) return true;
81 bool DPMSSupport::EnablePowerSaving(PowerSavingMode mode)
83 if (!CheckValidMode(mode)) return false;
84 if (!IsModeSupported(mode))
86 CLog::Log(LOGERROR, "DPMS: power-saving mode %s is not supported",
91 if (!PlatformSpecificEnablePowerSaving(mode)) return false;
93 CLog::Log(LOGINFO, "DPMS: enabled power-saving mode %s",
98 bool DPMSSupport::DisablePowerSaving()
100 if (!PlatformSpecificDisablePowerSaving()) return false;
101 CLog::Log(LOGINFO, "DPMS: disabled power-saving");
105 ///////// Platform-specific support
110 // Here's a sad story: our Windows-inspired BOOL type from linux/PlatformDefs.h
111 // is incompatible with the BOOL in X11's Xmd.h (int vs. unsigned char).
112 // This is not a good idea for a X11 app and it should
113 // probably be fixed. Meanwhile, we can work around it rather cleanly with
114 // the preprocessor (which is partly to blame for this needless conflict
115 // anyway). BOOL is not used in the DPMS APIs that we need. Try not to use
116 // BOOL in the remaining X11-specific code in this file, since X might
117 // someday use a #define instead of a typedef.
118 // Addendum: INT64 apparently hhas the same problem on x86_64. Oh well.
119 // Once again, INT64 is not used in the APIs we need, so we can #ifdef it away.
120 #define BOOL __X11_SPECIFIC_BOOL
121 #define INT64 __X11_SPECIFIC_INT64
122 #include <X11/Xlib.h>
123 #include <X11/extensions/dpms.h>
127 // Mapping of PowerSavingMode to X11's mode constants.
128 static const CARD16 X_DPMS_MODES[] =
129 { DPMSModeStandby, DPMSModeSuspend, DPMSModeOff };
131 void DPMSSupport::PlatformSpecificInit()
133 Display* dpy = g_Windowing.GetDisplay();
134 if (dpy == NULL) return;
136 int event_base, error_base; // we ignore these
137 if (!DPMSQueryExtension(dpy, &event_base, &error_base)) {
138 CLog::Log(LOGINFO, "DPMS: X11 extension not present, power-saving"
139 " will not be available");
143 if (!DPMSCapable(dpy)) {
144 CLog::Log(LOGINFO, "DPMS: display does not support power-saving");
148 m_supportedModes.push_back(SUSPEND); // best compromise
149 m_supportedModes.push_back(OFF); // next best
150 m_supportedModes.push_back(STANDBY); // rather lame, < 80% power according to
154 bool DPMSSupport::PlatformSpecificEnablePowerSaving(PowerSavingMode mode)
156 Display* dpy = g_Windowing.GetDisplay();
157 if (dpy == NULL) return false;
159 // This is not needed on my ATI Radeon, but the docs say that DPMSForceLevel
160 // after a DPMSDisable (from SDL) should not normally work.
162 DPMSForceLevel(dpy, X_DPMS_MODES[mode]);
163 // There shouldn't be any errors if we called DPMSEnable; if they do happen,
164 // they're asynchronous and messy to detect.
169 bool DPMSSupport::PlatformSpecificDisablePowerSaving()
171 Display* dpy = g_Windowing.GetDisplay();
172 if (dpy == NULL) return false;
174 DPMSForceLevel(dpy, DPMSModeOn);
177 // On my ATI, the full-screen window stays blank after waking up from
178 // DPMS, presumably due to being OpenGL. There is something magical about
179 // window expose events (involving the window manager) that solves this
181 XUnmapWindow(dpy, g_Windowing.GetWindow());
183 XMapWindow(dpy, g_Windowing.GetWindow());
189 ///// Add other platforms here.
190 #elif defined(TARGET_WINDOWS)
191 void DPMSSupport::PlatformSpecificInit()
193 // Assume we support DPMS. Is there a way to test it?
194 m_supportedModes.push_back(OFF);
195 m_supportedModes.push_back(STANDBY);
198 bool DPMSSupport::PlatformSpecificEnablePowerSaving(PowerSavingMode mode)
200 if(!g_graphicsContext.IsFullScreenRoot())
202 CLog::Log(LOGDEBUG, "DPMS: not in fullscreen, power saving disabled");
209 return SendMessage(g_Windowing.GetHwnd(), WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM) 2) == 0;
211 // Set display to low power
212 return SendMessage(g_Windowing.GetHwnd(), WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM) 1) == 0;
218 bool DPMSSupport::PlatformSpecificDisablePowerSaving()
221 return SendMessage(g_Windowing.GetHwnd(), WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM) -1) == 0;
224 #elif defined(TARGET_DARWIN_OSX)
225 #include <IOKit/IOKitLib.h>
226 #include <CoreFoundation/CFNumber.h>
228 void DPMSSupport::PlatformSpecificInit()
230 m_supportedModes.push_back(OFF);
231 m_supportedModes.push_back(STANDBY);
234 bool DPMSSupport::PlatformSpecificEnablePowerSaving(PowerSavingMode mode)
237 // http://lists.apple.com/archives/Cocoa-dev/2007/Nov/msg00267.html
238 // This is an unsupported system call that might kernel panic on PPC boxes
239 // The reported OSX-PPC panic is unverified so we are going to enable this until
240 // we find out which OSX-PPC boxes have problems, then add detect/disable for those boxes.
241 io_registry_entry_t r = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/IOResources/IODisplayWrangler");
248 status = (IORegistryEntrySetCFProperty(r, CFSTR("IORequestIdle"), kCFBooleanTrue) == 0);
251 // Set display to low power
252 status = (IORegistryEntrySetCFProperty(r, CFSTR("IORequestIdle"), kCFBooleanTrue) == 0);
261 bool DPMSSupport::PlatformSpecificDisablePowerSaving()
263 // http://lists.apple.com/archives/Cocoa-dev/2007/Nov/msg00267.html
264 // This is an unsupported system call that might kernel panic on PPC boxes
265 // The reported OSX-PPC panic is unverified so we are going to enable this until
266 // we find out which OSX-PPC boxes have problems, then add detect/disable for those boxes.
267 io_registry_entry_t r = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/IOResources/IODisplayWrangler");
271 return (IORegistryEntrySetCFProperty(r, CFSTR("IORequestIdle"), kCFBooleanFalse) == 0);
275 // Not implemented on this platform
276 void DPMSSupport::PlatformSpecificInit()
278 CLog::Log(LOGINFO, "DPMS: not supported on this platform");
281 bool DPMSSupport::PlatformSpecificEnablePowerSaving(PowerSavingMode mode)
286 bool DPMSSupport::PlatformSpecificDisablePowerSaving()
291 #endif // platform ifdefs