00001
00002 #include "screensaver-x11.h"
00003
00004
00005 #include <QDateTime>
00006 #include <QTimer>
00007 #include <QX11Info>
00008
00009
00010 #include "mythlogging.h"
00011 #include "mythdb.h"
00012
00013
00014 #include "mythsystem.h"
00015 #include "mythxdisplay.h"
00016
00017
00018 #include <X11/Xlib.h>
00019
00020 extern "C" {
00021 #include <X11/extensions/dpms.h>
00022 }
00023
00024 #define LOC QString("ScreenSaverX11Private: ")
00025
00026 class ScreenSaverX11Private
00027 {
00028 friend class ScreenSaverX11;
00029
00030 public:
00031 ScreenSaverX11Private(ScreenSaverX11 *outer) :
00032 m_dpmsaware(false), m_dpmsdeactivated(false),
00033 m_xscreensaverRunning(false),
00034 m_dpmsenabled(false),
00035 m_timeoutInterval(-1), m_resetTimer(NULL),
00036 m_display(NULL)
00037 {
00038 const uint flags = kMSDontBlockInputDevs | kMSDontDisableDrawing |
00039 kMSProcessEvents;
00040 m_xscreensaverRunning =
00041 myth_system("xscreensaver-command -version >&- 2>&-",
00042 flags) == 0;
00043
00044 if (IsScreenSaverRunning())
00045 {
00046 m_resetTimer = new QTimer(outer);
00047 m_resetTimer->setSingleShot(false);
00048 QObject::connect(m_resetTimer, SIGNAL(timeout()),
00049 outer, SLOT(resetSlot()));
00050 if (m_xscreensaverRunning)
00051 LOG(VB_GENERAL, LOG_INFO, LOC + "XScreenSaver support enabled");
00052 }
00053
00054 m_display = OpenMythXDisplay();
00055 if (m_display)
00056 {
00057 int dummy0, dummy1;
00058 m_dpmsaware = DPMSQueryExtension(m_display->GetDisplay(),
00059 &dummy0, &dummy1);
00060 }
00061 else
00062 {
00063 LOG(VB_GENERAL, LOG_ERR, LOC +
00064 "Failed to open connection to X11 server");
00065 }
00066
00067 if (m_dpmsaware)
00068 {
00069 CARD16 power_level;
00070
00071
00072
00073
00074
00075
00076
00077 DPMSInfo(m_display->GetDisplay(), &power_level, &m_dpmsenabled);
00078
00079 if (m_dpmsenabled)
00080 LOG(VB_GENERAL, LOG_INFO, LOC + "DPMS is active.");
00081 else
00082 LOG(VB_GENERAL, LOG_INFO, LOC + "DPMS is disabled.");
00083 }
00084 else
00085 {
00086 LOG(VB_GENERAL, LOG_INFO, LOC + "DPMS is not supported.");
00087 }
00088 }
00089
00090 ~ScreenSaverX11Private()
00091 {
00092
00093 delete m_display;
00094 }
00095
00096 bool IsScreenSaverRunning(void) const
00097 {
00098 return m_xscreensaverRunning;
00099 }
00100
00101 bool IsDPMSEnabled(void) const { return m_dpmsenabled; }
00102
00103 void StopTimer(void)
00104 {
00105 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "StopTimer");
00106 if (m_resetTimer)
00107 m_resetTimer->stop();
00108 }
00109
00110 void StartTimer(void)
00111 {
00112 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "StartTimer");
00113 if (m_resetTimer)
00114 m_resetTimer->start(m_timeoutInterval);
00115 }
00116
00117 void ResetTimer(void)
00118 {
00119 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "ResetTimer -- begin");
00120
00121 StopTimer();
00122
00123 if (m_timeoutInterval == -1)
00124 {
00125 m_timeoutInterval = GetMythDB()->GetNumSettingOnHost(
00126 "xscreensaverInterval", GetMythDB()->GetHostName(), 50) * 1000;
00127 }
00128
00129 if (m_timeoutInterval > 0)
00130 StartTimer();
00131
00132 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "ResetTimer -- end");
00133 }
00134
00135
00136 bool DeactivatedDPMS(void) const
00137 {
00138 return m_dpmsdeactivated;
00139 }
00140
00141 void DisableDPMS(void)
00142 {
00143 if (IsDPMSEnabled() && m_display)
00144 {
00145 m_dpmsdeactivated = true;
00146 Status status = DPMSDisable(m_display->GetDisplay());
00147 m_display->Sync();
00148 LOG(VB_GENERAL, LOG_INFO, LOC +
00149 QString("DPMS Deactivated %1").arg(status));
00150 }
00151 }
00152
00153 void RestoreDPMS(void)
00154 {
00155 if (m_dpmsdeactivated && m_display)
00156 {
00157 m_dpmsdeactivated = false;
00158 Status status = DPMSEnable(m_display->GetDisplay());
00159 m_display->Sync();
00160 LOG(VB_GENERAL, LOG_INFO, LOC +
00161 QString("DPMS Reactivated %1").arg(status));
00162 }
00163 }
00164
00165 void SaveScreenSaver(void)
00166 {
00167 if (!m_state.saved && m_display)
00168 {
00169 XGetScreenSaver(m_display->GetDisplay(), &m_state.timeout,
00170 &m_state.interval, &m_state.preferblank,
00171 &m_state.allowexposure);
00172 m_state.saved = true;
00173 }
00174 }
00175
00176 void RestoreScreenSaver(void)
00177 {
00178 if (m_state.saved && m_display)
00179 {
00180 XSetScreenSaver(m_display->GetDisplay(), m_state.timeout,
00181 m_state.interval, m_state.preferblank,
00182 m_state.allowexposure);
00183 m_display->Sync();
00184 m_state.saved = false;
00185 }
00186 }
00187
00188 void ResetScreenSaver(void)
00189 {
00190 if (!IsScreenSaverRunning())
00191 return;
00192
00193 QDateTime current_time = QDateTime::currentDateTime();
00194 if ((!m_last_deactivated.isValid()) ||
00195 (m_last_deactivated.secsTo(current_time) > 30))
00196 {
00197 if (m_xscreensaverRunning)
00198 {
00199 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00200 "Calling xscreensaver-command -deactivate");
00201 myth_system("xscreensaver-command -deactivate >&- 2>&- &",
00202 kMSDontBlockInputDevs |
00203 kMSDontDisableDrawing |
00204 kMSRunBackground);
00205 }
00206 m_last_deactivated = current_time;
00207 }
00208 }
00209
00210 private:
00211 class ScreenSaverState
00212 {
00213 public:
00214 ScreenSaverState() :
00215 saved(false), timeout(-1), interval(-1),
00216 preferblank(-1), allowexposure(-1) {}
00217 bool saved;
00218 int timeout;
00219 int interval;
00220 int preferblank;
00221 int allowexposure;
00222 };
00223
00224 private:
00225 bool m_dpmsaware;
00226 bool m_dpmsdeactivated;
00227 bool m_xscreensaverRunning;
00228 BOOL m_dpmsenabled;
00229
00230 int m_timeoutInterval;
00231 QTimer *m_resetTimer;
00232
00233 QDateTime m_last_deactivated;
00234
00235 ScreenSaverState m_state;
00236 MythXDisplay *m_display;
00237 };
00238
00239 ScreenSaverX11::ScreenSaverX11() :
00240 d(new ScreenSaverX11Private(this))
00241 {
00242 }
00243
00244 ScreenSaverX11::~ScreenSaverX11()
00245 {
00246
00247 if (d->DeactivatedDPMS())
00248 Restore();
00249
00250 delete d;
00251 }
00252
00253 void ScreenSaverX11::Disable(void)
00254 {
00255 d->SaveScreenSaver();
00256
00257 if (d->m_display)
00258 {
00259 XResetScreenSaver(d->m_display->GetDisplay());
00260 XSetScreenSaver(d->m_display->GetDisplay(), 0, 0, 0, 0);
00261 d->m_display->Sync();
00262 }
00263
00264 d->DisableDPMS();
00265
00266 if (d->IsScreenSaverRunning())
00267 d->ResetTimer();
00268 }
00269
00270 void ScreenSaverX11::Restore(void)
00271 {
00272 d->RestoreScreenSaver();
00273 d->RestoreDPMS();
00274
00275
00276 if (d->m_display)
00277 {
00278 XResetScreenSaver(d->m_display->GetDisplay());
00279 d->m_display->Sync();
00280 }
00281
00282 if (d->IsScreenSaverRunning())
00283 d->StopTimer();
00284 }
00285
00286 void ScreenSaverX11::Reset(void)
00287 {
00288 bool need_xsync = false;
00289 Display *dsp = NULL;
00290 if (d->m_display)
00291 dsp = d->m_display->GetDisplay();
00292
00293 if (dsp)
00294 {
00295 XResetScreenSaver(dsp);
00296 need_xsync = true;
00297 }
00298
00299 if (d->IsScreenSaverRunning())
00300 resetSlot();
00301
00302 if (Asleep() && dsp)
00303 {
00304 DPMSForceLevel(dsp, DPMSModeOn);
00305 need_xsync = true;
00306 }
00307
00308 if (need_xsync && d->m_display)
00309 d->m_display->Sync();
00310 }
00311
00312 bool ScreenSaverX11::Asleep(void)
00313 {
00314 if (!d->IsDPMSEnabled())
00315 return false;
00316
00317 if (d->DeactivatedDPMS())
00318 return false;
00319
00320 BOOL on;
00321 CARD16 power_level = DPMSModeOn;
00322
00323 if (d->m_display)
00324 DPMSInfo(d->m_display->GetDisplay(), &power_level, &on);
00325
00326 return (power_level != DPMSModeOn);
00327 }
00328
00329 void ScreenSaverX11::resetSlot(void)
00330 {
00331 d->ResetScreenSaver();
00332 }