diff options
| author | 2018-04-25 18:07:30 -0400 | |
|---|---|---|
| committer | 2018-04-25 18:07:30 -0400 | |
| commit | 9b1b081cfdb1c0fb6457278775e0823f8bc10f62 (patch) | |
| tree | ce8840148d8445055ba9e4f12263b2208f234c16 /src/lib/platform/MSWindowsScreenSaver.cpp | |
Import Upstream version 2.0.0+dfsgupstream/2.0.0+dfsg
Diffstat (limited to 'src/lib/platform/MSWindowsScreenSaver.cpp')
| -rw-r--r-- | src/lib/platform/MSWindowsScreenSaver.cpp | 359 |
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; +} |
