aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/platform/MSWindowsScreenSaver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/platform/MSWindowsScreenSaver.cpp')
-rw-r--r--src/lib/platform/MSWindowsScreenSaver.cpp359
1 files changed, 359 insertions, 0 deletions
diff --git a/src/lib/platform/MSWindowsScreenSaver.cpp b/src/lib/platform/MSWindowsScreenSaver.cpp
new file mode 100644
index 0000000..f9c15fb
--- /dev/null
+++ b/src/lib/platform/MSWindowsScreenSaver.cpp
@@ -0,0 +1,359 @@
+/*
+ * barrier -- mouse and keyboard sharing utility
+ * Copyright (C) 2012-2016 Symless Ltd.
+ * Copyright (C) 2002 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "platform/MSWindowsScreenSaver.h"
+
+#include "platform/MSWindowsScreen.h"
+#include "mt/Thread.h"
+#include "arch/Arch.h"
+#include "arch/win32/ArchMiscWindows.h"
+#include "base/Log.h"
+#include "base/TMethodJob.h"
+
+#include <malloc.h>
+#include <tchar.h>
+
+#if !defined(SPI_GETSCREENSAVERRUNNING)
+#define SPI_GETSCREENSAVERRUNNING 114
+#endif
+
+static const TCHAR* g_isSecureNT = "ScreenSaverIsSecure";
+static const TCHAR* g_isSecure9x = "ScreenSaveUsePassword";
+static const TCHAR* const g_pathScreenSaverIsSecure[] = {
+ "Control Panel",
+ "Desktop",
+ NULL
+};
+
+//
+// MSWindowsScreenSaver
+//
+
+MSWindowsScreenSaver::MSWindowsScreenSaver() :
+ m_wasSecure(false),
+ m_wasSecureAnInt(false),
+ m_process(NULL),
+ m_watch(NULL),
+ m_threadID(0),
+ m_msg(0),
+ m_wParam(0),
+ m_lParam(0),
+ m_active(false)
+{
+ // check if screen saver is enabled
+ SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0);
+}
+
+MSWindowsScreenSaver::~MSWindowsScreenSaver()
+{
+ unwatchProcess();
+}
+
+bool
+MSWindowsScreenSaver::checkStarted(UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ // if already started then say it didn't just start
+ if (m_active) {
+ return false;
+ }
+
+ // screen saver may have started. look for it and get
+ // the process. if we can't find it then assume it
+ // didn't really start. we wait a moment before
+ // looking to give the screen saver a chance to start.
+ // this shouldn't be a problem since we only get here
+ // if the screen saver wants to kick in, meaning that
+ // the system is idle or the user deliberately started
+ // the screen saver.
+ Sleep(250);
+
+ // set parameters common to all screen saver handling
+ m_threadID = GetCurrentThreadId();
+ m_msg = msg;
+ m_wParam = wParam;
+ m_lParam = lParam;
+
+ // on the windows nt family we wait for the desktop to
+ // change until it's neither the Screen-Saver desktop
+ // nor a desktop we can't open (the login desktop).
+ // since windows will send the request-to-start-screen-
+ // saver message even when the screen saver is disabled
+ // we first check that the screen saver is indeed active
+ // before watching for it to stop.
+ if (!isActive()) {
+ LOG((CLOG_DEBUG2 "can't open screen saver desktop"));
+ return false;
+ }
+
+ watchDesktop();
+ return true;
+}
+
+void
+MSWindowsScreenSaver::enable()
+{
+ SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, m_wasEnabled, 0, 0);
+
+ // restore password protection
+ if (m_wasSecure) {
+ setSecure(true, m_wasSecureAnInt);
+ }
+
+ // restore display power down
+ ArchMiscWindows::removeBusyState(ArchMiscWindows::kDISPLAY);
+}
+
+void
+MSWindowsScreenSaver::disable()
+{
+ SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0);
+ SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, 0, 0);
+
+ // disable password protected screensaver
+ m_wasSecure = isSecure(&m_wasSecureAnInt);
+ if (m_wasSecure) {
+ setSecure(false, m_wasSecureAnInt);
+ }
+
+ // disable display power down
+ ArchMiscWindows::addBusyState(ArchMiscWindows::kDISPLAY);
+}
+
+void
+MSWindowsScreenSaver::activate()
+{
+ // don't activate if already active
+ if (!isActive()) {
+ // activate
+ HWND hwnd = GetForegroundWindow();
+ if (hwnd != NULL) {
+ PostMessage(hwnd, WM_SYSCOMMAND, SC_SCREENSAVE, 0);
+ }
+ else {
+ // no foreground window. pretend we got the event instead.
+ DefWindowProc(NULL, WM_SYSCOMMAND, SC_SCREENSAVE, 0);
+ }
+
+ // restore power save when screen saver activates
+ ArchMiscWindows::removeBusyState(ArchMiscWindows::kDISPLAY);
+ }
+}
+
+void
+MSWindowsScreenSaver::deactivate()
+{
+ bool killed = false;
+
+ // NT runs screen saver in another desktop
+ HDESK desktop = OpenDesktop("Screen-saver", 0, FALSE,
+ DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS);
+ if (desktop != NULL) {
+ EnumDesktopWindows(desktop,
+ &MSWindowsScreenSaver::killScreenSaverFunc,
+ reinterpret_cast<LPARAM>(&killed));
+ CloseDesktop(desktop);
+ }
+
+ // if above failed or wasn't tried, try the windows 95 way
+ if (!killed) {
+ // find screen saver window and close it
+ HWND hwnd = FindWindow("WindowsScreenSaverClass", NULL);
+ if (hwnd == NULL) {
+ // win2k may use a different class
+ hwnd = FindWindow("Default Screen Saver", NULL);
+ }
+ if (hwnd != NULL) {
+ PostMessage(hwnd, WM_CLOSE, 0, 0);
+ }
+ }
+
+ // force timer to restart
+ SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0);
+ SystemParametersInfo(SPI_SETSCREENSAVEACTIVE,
+ !m_wasEnabled, 0, SPIF_SENDWININICHANGE);
+ SystemParametersInfo(SPI_SETSCREENSAVEACTIVE,
+ m_wasEnabled, 0, SPIF_SENDWININICHANGE);
+
+ // disable display power down
+ ArchMiscWindows::removeBusyState(ArchMiscWindows::kDISPLAY);
+}
+
+bool
+MSWindowsScreenSaver::isActive() const
+{
+ BOOL running;
+ SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &running, 0);
+ return (running != FALSE);
+}
+
+BOOL CALLBACK
+MSWindowsScreenSaver::killScreenSaverFunc(HWND hwnd, LPARAM arg)
+{
+ if (IsWindowVisible(hwnd)) {
+ HINSTANCE instance = (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE);
+ if (instance != MSWindowsScreen::getWindowInstance()) {
+ PostMessage(hwnd, WM_CLOSE, 0, 0);
+ *reinterpret_cast<bool*>(arg) = true;
+ }
+ }
+ return TRUE;
+}
+
+void
+MSWindowsScreenSaver::watchDesktop()
+{
+ // stop watching previous process/desktop
+ unwatchProcess();
+
+ // watch desktop in another thread
+ LOG((CLOG_DEBUG "watching screen saver desktop"));
+ m_active = true;
+ m_watch = new Thread(new TMethodJob<MSWindowsScreenSaver>(this,
+ &MSWindowsScreenSaver::watchDesktopThread));
+}
+
+void
+MSWindowsScreenSaver::watchProcess(HANDLE process)
+{
+ // stop watching previous process/desktop
+ unwatchProcess();
+
+ // watch new process in another thread
+ if (process != NULL) {
+ LOG((CLOG_DEBUG "watching screen saver process"));
+ m_process = process;
+ m_active = true;
+ m_watch = new Thread(new TMethodJob<MSWindowsScreenSaver>(this,
+ &MSWindowsScreenSaver::watchProcessThread));
+ }
+}
+
+void
+MSWindowsScreenSaver::unwatchProcess()
+{
+ if (m_watch != NULL) {
+ LOG((CLOG_DEBUG "stopped watching screen saver process/desktop"));
+ m_watch->cancel();
+ m_watch->wait();
+ delete m_watch;
+ m_watch = NULL;
+ m_active = false;
+ }
+ if (m_process != NULL) {
+ CloseHandle(m_process);
+ m_process = NULL;
+ }
+}
+
+void
+MSWindowsScreenSaver::watchDesktopThread(void*)
+{
+ DWORD reserved = 0;
+ TCHAR* name = NULL;
+
+ for (;;) {
+ // wait a bit
+ ARCH->sleep(0.2);
+
+ BOOL running;
+ SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &running, 0);
+ if (running) {
+ continue;
+ }
+
+ // send screen saver deactivation message
+ m_active = false;
+ PostThreadMessage(m_threadID, m_msg, m_wParam, m_lParam);
+ return;
+ }
+}
+
+void
+MSWindowsScreenSaver::watchProcessThread(void*)
+{
+ for (;;) {
+ Thread::testCancel();
+ if (WaitForSingleObject(m_process, 50) == WAIT_OBJECT_0) {
+ // process terminated
+ LOG((CLOG_DEBUG "screen saver died"));
+
+ // send screen saver deactivation message
+ m_active = false;
+ PostThreadMessage(m_threadID, m_msg, m_wParam, m_lParam);
+ return;
+ }
+ }
+}
+
+void
+MSWindowsScreenSaver::setSecure(bool secure, bool saveSecureAsInt)
+{
+ HKEY hkey =
+ ArchMiscWindows::addKey(HKEY_CURRENT_USER, g_pathScreenSaverIsSecure);
+ if (hkey == NULL) {
+ return;
+ }
+
+ if (saveSecureAsInt) {
+ ArchMiscWindows::setValue(hkey, g_isSecureNT, secure ? 1 : 0);
+ }
+ else {
+ ArchMiscWindows::setValue(hkey, g_isSecureNT, secure ? "1" : "0");
+ }
+
+ ArchMiscWindows::closeKey(hkey);
+}
+
+bool
+MSWindowsScreenSaver::isSecure(bool* wasSecureFlagAnInt) const
+{
+ // get the password protection setting key
+ HKEY hkey =
+ ArchMiscWindows::openKey(HKEY_CURRENT_USER, g_pathScreenSaverIsSecure);
+ if (hkey == NULL) {
+ return false;
+ }
+
+ // get the value. the value may be an int or a string, depending
+ // on the version of windows.
+ bool result;
+ switch (ArchMiscWindows::typeOfValue(hkey, g_isSecureNT)) {
+ default:
+ result = false;
+ break;
+
+ case ArchMiscWindows::kUINT: {
+ DWORD value =
+ ArchMiscWindows::readValueInt(hkey, g_isSecureNT);
+ *wasSecureFlagAnInt = true;
+ result = (value != 0);
+ break;
+ }
+
+ case ArchMiscWindows::kSTRING: {
+ std::string value =
+ ArchMiscWindows::readValueString(hkey, g_isSecureNT);
+ *wasSecureFlagAnInt = false;
+ result = (value != "0");
+ break;
+ }
+ }
+
+ ArchMiscWindows::closeKey(hkey);
+ return result;
+}