From a6e858a2081a8ba7cc49a96c94baf3c2d3fa27e7 Mon Sep 17 00:00:00 2001 From: crs Date: Sat, 13 Mar 2004 17:13:55 +0000 Subject: [PATCH] Added win32 support for power management. --- cmd/synergyc/resource.h | 12 +-- cmd/synergyc/synergyc.cpp | 54 +++++++++-- cmd/synergys/synergys.cpp | 2 +- lib/arch/CArchMiscWindows.cpp | 127 +++++++++++++++++++++++-- lib/arch/CArchMiscWindows.h | 44 +++++++++ lib/platform/CMSWindowsScreen.cpp | 103 ++++++++++++++------ lib/platform/CMSWindowsScreen.h | 14 ++- lib/platform/CMSWindowsScreenSaver.cpp | 99 ++++++++++++++++++- lib/platform/CMSWindowsScreenSaver.h | 6 ++ 9 files changed, 401 insertions(+), 60 deletions(-) diff --git a/cmd/synergyc/resource.h b/cmd/synergyc/resource.h index 37f085d6..1a5455a1 100644 --- a/cmd/synergyc/resource.h +++ b/cmd/synergyc/resource.h @@ -13,17 +13,17 @@ #define IDR_TASKBAR 107 #define IDD_TASKBAR_STATUS 108 #define IDC_TASKBAR_STATUS_STATUS 1000 -#define IDC_TASKBAR_QUIT 40003 -#define IDC_TASKBAR_STATUS 40004 -#define IDC_TASKBAR_LOG 40005 +#define IDC_TASKBAR_QUIT 40001 +#define IDC_TASKBAR_STATUS 40002 +#define IDC_TASKBAR_LOG 40003 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 102 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_RESOURCE_VALUE 109 +#define _APS_NEXT_COMMAND_VALUE 40004 +#define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/cmd/synergyc/synergyc.cpp b/cmd/synergyc/synergyc.cpp index 2f5b945b..9e7be5ab 100644 --- a/cmd/synergyc/synergyc.cpp +++ b/cmd/synergyc/synergyc.cpp @@ -24,6 +24,7 @@ #include "CThread.h" #include "CEventQueue.h" #include "CFunctionEventJob.h" +#include "CFunctionJob.h" #include "CLog.h" #include "CString.h" #include "CStringUtil.h" @@ -54,7 +55,12 @@ #endif typedef int (*StartupFunc)(int, char**); +static bool startClient(); static void parse(int argc, const char* const* argv); +#if WINDOWS_LIKE +static void handleSystemSuspend(void*); +static void handleSystemResume(void*); +#endif // // program arguments @@ -97,7 +103,9 @@ CScreen* createScreen() { #if WINDOWS_LIKE - return new CScreen(new CMSWindowsScreen(false)); + return new CScreen(new CMSWindowsScreen(false, + new CFunctionJob(&handleSystemSuspend), + new CFunctionJob(&handleSystemResume))); #elif UNIX_LIKE return new CScreen(new CXWindowsScreen(false)); #endif @@ -124,6 +132,7 @@ static CClient* s_client = NULL; static CScreen* s_clientScreen = NULL; static CClientTaskBarReceiver* s_taskBarReceiver = NULL; static double s_retryTime = 0.0; +static bool s_suspened = false; static void @@ -181,6 +190,26 @@ handleScreenError(const CEvent&, void*) EVENTQUEUE->addEvent(CEvent(CEvent::kQuit)); } +#if WINDOWS_LIKE +static +void +handleSystemSuspend(void*) +{ + LOG((CLOG_NOTE "system suspending")); + s_suspened = true; + s_client->disconnect(NULL); +} + +static +void +handleSystemResume(void*) +{ + LOG((CLOG_NOTE "system resuming")); + s_suspened = false; + startClient(); +} +#endif + static CScreen* openClientScreen() @@ -211,11 +240,12 @@ handleClientRestart(const CEvent&, void* vtimer) // discard old timer CEventQueueTimer* timer = reinterpret_cast(vtimer); EVENTQUEUE->deleteTimer(timer); - EVENTQUEUE->removeHandler(CEvent::kTimer, NULL); + EVENTQUEUE->removeHandler(CEvent::kTimer, timer); // reconnect - s_client->connect(); - updateStatus(); + if (!s_suspened) { + startClient(); + } } static @@ -251,7 +281,9 @@ handleClientFailed(const CEvent& e, void*) } else { LOG((CLOG_WARN "failed to connect to server: %s", info->m_what)); - scheduleClientRestart(nextRestartTimeout()); + if (!s_suspened) { + scheduleClientRestart(nextRestartTimeout()); + } } } @@ -263,7 +295,7 @@ handleClientDisconnected(const CEvent&, void*) if (!ARG->m_restartable) { EVENTQUEUE->addEvent(CEvent(CEvent::kQuit)); } - else { + else if (!s_suspened) { s_client->connect(); } updateStatus(); @@ -308,11 +340,13 @@ startClient() double retryTime; CScreen* clientScreen = NULL; try { - clientScreen = openClientScreen(); - s_client = openClient(ARG->m_name, + if (s_clientScreen == NULL) { + clientScreen = openClientScreen(); + s_client = openClient(ARG->m_name, *ARG->m_serverAddress, clientScreen); - s_clientScreen = clientScreen; - LOG((CLOG_NOTE "started client")); + s_clientScreen = clientScreen; + LOG((CLOG_NOTE "started client")); + } s_client->connect(); updateStatus(); return true; diff --git a/cmd/synergys/synergys.cpp b/cmd/synergys/synergys.cpp index c1370197..b1cdaed5 100644 --- a/cmd/synergys/synergys.cpp +++ b/cmd/synergys/synergys.cpp @@ -114,7 +114,7 @@ CScreen* createScreen() { #if WINDOWS_LIKE - return new CScreen(new CMSWindowsScreen(true)); + return new CScreen(new CMSWindowsScreen(true, NULL, NULL)); #elif UNIX_LIKE return new CScreen(new CXWindowsScreen(true)); #endif diff --git a/lib/arch/CArchMiscWindows.cpp b/lib/arch/CArchMiscWindows.cpp index d2b0842c..6f4e9ca2 100644 --- a/lib/arch/CArchMiscWindows.cpp +++ b/lib/arch/CArchMiscWindows.cpp @@ -15,11 +15,24 @@ #include "CArchMiscWindows.h" #include "CArchDaemonWindows.h" +#ifndef ES_SYSTEM_REQUIRED +#define ES_SYSTEM_REQUIRED ((DWORD)0x00000001) +#endif +#ifndef ES_DISPLAY_REQUIRED +#define ES_DISPLAY_REQUIRED ((DWORD)0x00000002) +#endif +#ifndef ES_CONTINUOUS +#define ES_CONTINUOUS ((DWORD)0x80000000) +#endif +typedef DWORD EXECUTION_STATE; + // // CArchMiscWindows // -CArchMiscWindows::CDialogs* CArchMiscWindows::s_dialogs = NULL; +CArchMiscWindows::CDialogs* CArchMiscWindows::s_dialogs = NULL; +DWORD CArchMiscWindows::s_busyState = 0; +CArchMiscWindows::STES_t CArchMiscWindows::s_stes = NULL; void CArchMiscWindows::init() @@ -143,6 +156,29 @@ CArchMiscWindows::hasValue(HKEY key, const TCHAR* name) (type == REG_DWORD || type == REG_SZ)); } +CArchMiscWindows::EValueType +CArchMiscWindows::typeOfValue(HKEY key, const TCHAR* name) +{ + DWORD type; + LONG result = RegQueryValueEx(key, name, 0, &type, NULL, NULL); + if (result != ERROR_SUCCESS) { + return kNO_VALUE; + } + switch (type) { + case REG_DWORD: + return kUINT; + + case REG_SZ: + return kSTRING; + + case REG_BINARY: + return kBINARY; + + default: + return kUNKNOWN; + } +} + void CArchMiscWindows::setValue(HKEY key, const TCHAR* name, const std::string& value) @@ -164,14 +200,25 @@ CArchMiscWindows::setValue(HKEY key, const TCHAR* name, DWORD value) sizeof(DWORD)); } +void +CArchMiscWindows::setValueBinary(HKEY key, + const TCHAR* name, const std::string& value) +{ + assert(key != NULL); + assert(name != NULL); + RegSetValueEx(key, name, 0, REG_BINARY, + reinterpret_cast(value.data()), + value.size()); +} + std::string -CArchMiscWindows::readValueString(HKEY key, const TCHAR* name) +CArchMiscWindows::readBinaryOrString(HKEY key, const TCHAR* name, DWORD type) { // get the size of the string - DWORD type; + DWORD actualType; DWORD size = 0; - LONG result = RegQueryValueEx(key, name, 0, &type, NULL, &size); - if (result != ERROR_SUCCESS || type != REG_SZ) { + LONG result = RegQueryValueEx(key, name, 0, &actualType, NULL, &size); + if (result != ERROR_SUCCESS || actualType != type) { return std::string(); } @@ -179,19 +226,31 @@ CArchMiscWindows::readValueString(HKEY key, const TCHAR* name) char* buffer = new char[size]; // read it - result = RegQueryValueEx(key, name, 0, &type, + result = RegQueryValueEx(key, name, 0, &actualType, reinterpret_cast(buffer), &size); - if (result != ERROR_SUCCESS || type != REG_SZ) { + if (result != ERROR_SUCCESS || actualType != type) { delete[] buffer; return std::string(); } // clean up and return value - std::string value(buffer); + std::string value(buffer, size); delete[] buffer; return value; } +std::string +CArchMiscWindows::readValueString(HKEY key, const TCHAR* name) +{ + return readBinaryOrString(key, name, REG_SZ); +} + +std::string +CArchMiscWindows::readValueBinary(HKEY key, const TCHAR* name) +{ + return readBinaryOrString(key, name, REG_BINARY); +} + DWORD CArchMiscWindows::readValueInt(HKEY key, const TCHAR* name) { @@ -229,3 +288,55 @@ CArchMiscWindows::processDialog(MSG* msg) } return false; } + +void +CArchMiscWindows::addBusyState(DWORD busyModes) +{ + s_busyState |= busyModes; + setThreadExecutionState(s_busyState); +} + +void +CArchMiscWindows::removeBusyState(DWORD busyModes) +{ + s_busyState &= ~busyModes; + setThreadExecutionState(s_busyState); +} + +void +CArchMiscWindows::setThreadExecutionState(DWORD busyModes) +{ + // look up function dynamically so we work on older systems + if (s_stes == NULL) { + HINSTANCE kernel = LoadLibrary("kernel32.dll"); + if (kernel != NULL) { + s_stes = reinterpret_cast(GetProcAddress(kernel, + "SetThreadExecutionState")); + } + if (s_stes == NULL) { + s_stes = &CArchMiscWindows::dummySetThreadExecutionState; + } + } + + // convert to STES form + EXECUTION_STATE state = 0; + if ((busyModes & kSYSTEM) != 0) { + state |= ES_SYSTEM_REQUIRED; + } + if ((busyModes & kDISPLAY) != 0) { + state |= ES_DISPLAY_REQUIRED; + } + if (state != 0) { + state |= ES_CONTINUOUS; + } + + // do it + s_stes(state); +} + +DWORD +CArchMiscWindows::dummySetThreadExecutionState(DWORD) +{ + // do nothing + return 0; +} diff --git a/lib/arch/CArchMiscWindows.h b/lib/arch/CArchMiscWindows.h index 749e52f5..e55b6dd2 100644 --- a/lib/arch/CArchMiscWindows.h +++ b/lib/arch/CArchMiscWindows.h @@ -25,6 +25,19 @@ //! Miscellaneous win32 functions. class CArchMiscWindows { public: + enum EValueType { + kUNKNOWN, + kNO_VALUE, + kUINT, + kSTRING, + kBINARY + }; + enum EBusyModes { + kIDLE = 0x0000, + kSYSTEM = 0x0001, + kDISPLAY = 0x0002 + }; + typedef int (*RunFunc)(void); //! Initialize @@ -78,6 +91,9 @@ public: //! Test if a value exists static bool hasValue(HKEY key, const TCHAR* name); + //! Get type of value + static EValueType typeOfValue(HKEY key, const TCHAR* name); + //! Set a string value in the registry static void setValue(HKEY key, const TCHAR* name, const std::string& value); @@ -85,12 +101,22 @@ public: //! Set a DWORD value in the registry static void setValue(HKEY key, const TCHAR* name, DWORD value); + //! Set a BINARY value in the registry + /*! + Sets the \p name value of \p key to \p value.data(). + */ + static void setValueBinary(HKEY key, const TCHAR* name, + const std::string& value); + //! Read a string value from the registry static std::string readValueString(HKEY, const TCHAR* name); //! Read a DWORD value from the registry static DWORD readValueInt(HKEY, const TCHAR* name); + //! Read a BINARY value from the registry + static std::string readValueBinary(HKEY, const TCHAR* name); + //! Add a dialog static void addDialog(HWND); @@ -104,10 +130,28 @@ public: */ static bool processDialog(MSG*); + //! Disable power saving + static void addBusyState(DWORD busyModes); + + //! Enable power saving + static void removeBusyState(DWORD busyModes); + +private: + //! Read a string value from the registry + static std::string readBinaryOrString(HKEY, const TCHAR* name, DWORD type); + + //! Set thread busy state + static void setThreadExecutionState(DWORD); + + static DWORD WINAPI dummySetThreadExecutionState(DWORD); + private: typedef std::set CDialogs; + typedef DWORD (WINAPI *STES_t)(DWORD); static CDialogs* s_dialogs; + static DWORD s_busyState; + static STES_t s_stes; }; #endif diff --git a/lib/platform/CMSWindowsScreen.cpp b/lib/platform/CMSWindowsScreen.cpp index ae15ffb8..4bc2aae7 100644 --- a/lib/platform/CMSWindowsScreen.cpp +++ b/lib/platform/CMSWindowsScreen.cpp @@ -113,7 +113,8 @@ HINSTANCE CMSWindowsScreen::s_instance = NULL; CMSWindowsScreen* CMSWindowsScreen::s_screen = NULL; -CMSWindowsScreen::CMSWindowsScreen(bool isPrimary) : +CMSWindowsScreen::CMSWindowsScreen(bool isPrimary, + IJob* suspend, IJob* resume) : m_isPrimary(isPrimary), m_is95Family(CArchMiscWindows::isWindows95Family()), m_isOnScreen(m_isPrimary), @@ -137,16 +138,29 @@ CMSWindowsScreen::CMSWindowsScreen(bool isPrimary) : m_activeDesk(NULL), m_activeDeskName(), m_hookLibrary(NULL), + m_init(NULL), + m_cleanup(NULL), + m_install(NULL), + m_uninstall(NULL), + m_setSides(NULL), + m_setZone(NULL), + m_setMode(NULL), + m_installScreensaver(NULL), + m_uninstallScreensaver(NULL), m_keyState(NULL), m_mutex(), - m_deskReady(&m_mutex, false) + m_deskReady(&m_mutex, false), + m_suspend(suspend), + m_resume(resume) { assert(s_instance != NULL); assert(s_screen == NULL); s_screen = this; try { - m_hookLibrary = openHookLibrary("synrgyhk"); + if (m_isPrimary) { + m_hookLibrary = openHookLibrary("synrgyhk"); + } m_cursor = createBlankCursor(); m_class = createWindowClass(); m_deskClass = createDeskWindowClass(m_isPrimary); @@ -171,9 +185,6 @@ CMSWindowsScreen::CMSWindowsScreen(bool isPrimary) : throw; } - // install our clipboard snooper - m_nextClipboardWindow = SetClipboardViewer(m_window); - // install event handlers EVENTQUEUE->adoptHandler(CEvent::kSystem, IEventQueue::getSystemTarget(), new TMethodEventJob(this, @@ -190,14 +201,14 @@ CMSWindowsScreen::~CMSWindowsScreen() disable(); EVENTQUEUE->adoptBuffer(NULL); EVENTQUEUE->removeHandler(CEvent::kSystem, IEventQueue::getSystemTarget()); - removeDesks(); - ChangeClipboardChain(m_window, m_nextClipboardWindow); delete m_screensaver; destroyWindow(m_window); destroyClass(m_deskClass); destroyClass(m_class); destroyCursor(m_cursor); closeHookLibrary(m_hookLibrary); + delete m_suspend; + delete m_resume; s_screen = NULL; } @@ -229,6 +240,9 @@ CMSWindowsScreen::enable() { assert(m_isOnScreen == m_isPrimary); + // install our clipboard snooper + m_nextClipboardWindow = SetClipboardViewer(m_window); + if (m_isPrimary) { // update shadow key state m_keyMapper.update(NULL); @@ -239,6 +253,12 @@ CMSWindowsScreen::enable() // watch jump zones m_setMode(kHOOK_WATCH_JUMP_ZONE); } + else { + // prevent the system from entering power saving modes. if + // it did we'd be forced to disconnect from the server and + // the server would not be able to wake us up. + CArchMiscWindows::addBusyState(CArchMiscWindows::kSYSTEM); + } // set the active desk and (re)install the hooks checkDesk(); @@ -263,10 +283,27 @@ CMSWindowsScreen::disable() m_timer = NULL; } - // disable hooks if (m_isPrimary) { + // disable hooks m_setMode(kHOOK_DISABLE); + + // enable special key sequences on win95 family + enableSpecialKeys(true); } + else { + // allow the system to enter power saving mode + CArchMiscWindows::removeBusyState(CArchMiscWindows::kSYSTEM | + CArchMiscWindows::kDISPLAY); + } + + // destroy desks + removeDesks(); + + // stop snooping the clipboard + ChangeClipboardChain(m_window, m_nextClipboardWindow); + m_nextClipboardWindow = NULL; + + m_isOnScreen = m_isPrimary; } void @@ -973,6 +1010,25 @@ CMSWindowsScreen::onEvent(HWND, UINT msg, case WM_DISPLAYCHANGE: return onDisplayChange(); + + case WM_POWERBROADCAST: + switch (wParam) { + case PBT_APMRESUMEAUTOMATIC: + case PBT_APMRESUMECRITICAL: + case PBT_APMRESUMESUSPEND: + if (m_resume != NULL) { + m_resume->run(); + } + break; + + case PBT_APMSUSPEND: + if (m_suspend != NULL) { + m_suspend->run(); + } + break; + } + *result = TRUE; + return true; } return false; @@ -1316,10 +1372,16 @@ CMSWindowsScreen::onScreensaver(bool activated) if (activated) { if (m_screensaver->checkStarted(SYNERGY_MSG_SCREEN_SAVER, FALSE, 0)) { sendEvent(getScreensaverActivatedEvent()); + + // enable display power down + CArchMiscWindows::removeBusyState(CArchMiscWindows::kDISPLAY); } } else { sendEvent(getScreensaverDeactivatedEvent()); + + // disable display power down + CArchMiscWindows::addBusyState(CArchMiscWindows::kDISPLAY); } return true; @@ -1616,7 +1678,6 @@ LRESULT CALLBACK CMSWindowsScreen::primaryDeskProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { - // FIXME return DefWindowProc(hwnd, msg, wParam, lParam); } @@ -1893,6 +1954,7 @@ CMSWindowsScreen::deskThread(void* vdesk) } // clean up + deskEnter(desk); if (desk->m_window != NULL) { DestroyWindow(desk->m_window); } @@ -1927,6 +1989,8 @@ CMSWindowsScreen::removeDesks() delete desk; } m_desks.clear(); + m_activeDesk = NULL; + m_activeDeskName = ""; } void @@ -1952,7 +2016,6 @@ CMSWindowsScreen::checkDesk() // active becaue we'd most likely switch to the screensaver desktop // which would have the side effect of forcing the screensaver to // stop. - // FIXME -- really not switch if screensaver is active? if (name != m_activeDeskName && !m_screensaver->isActive()) { // show cursor on previous desk if (!m_isOnScreen) { @@ -1987,24 +2050,6 @@ CMSWindowsScreen::checkDesk() } } -// FIXME -- may want some of following when we switch desks. calling -// nextMark() for isPrimary may lead to loss of events. updateKeys() -// is to catch any key events lost between switching and detecting the -// switch. neither are strictly necessary. -/* - if (m_isPrimary) { - if (m_isOnScreen) { - // all messages prior to now are invalid - // FIXME -- is this necessary; couldn't we lose key releases? - nextMark(); - } - } - else { - // update key state - updateKeys(); - } -*/ - bool CMSWindowsScreen::isDeskAccessible(const CDesk* desk) const { diff --git a/lib/platform/CMSWindowsScreen.h b/lib/platform/CMSWindowsScreen.h index 15c8dfc9..5f10a45d 100644 --- a/lib/platform/CMSWindowsScreen.h +++ b/lib/platform/CMSWindowsScreen.h @@ -31,7 +31,7 @@ class CThread; //! Implementation of IPlatformScreen for Microsoft Windows class CMSWindowsScreen : public IPlatformScreen { public: - CMSWindowsScreen(bool isPrimary); + CMSWindowsScreen(bool isPrimary, IJob* suspend, IJob* resume); virtual ~CMSWindowsScreen(); //! @name manipulators @@ -112,7 +112,7 @@ private: }; typedef std::map CDesks; -// FIXME -- comment + // initialization and shutdown operations HINSTANCE openHookLibrary(const char* name); void closeHookLibrary(HINSTANCE hookLibrary) const; HCURSOR createBlankCursor() const; @@ -122,8 +122,12 @@ private: void destroyClass(ATOM windowClass) const; HWND createWindow(ATOM windowClass, const char* name) const; void destroyWindow(HWND) const; + + // convenience function to send events void sendEvent(CEvent::Type type, void* = NULL); void sendClipboardEvent(CEvent::Type type, ClipboardID id); + + // system event handler (does DispatchMessage) void handleSystemEvent(const CEvent& event, void*); // handle message before it gets dispatched. returns true iff @@ -148,7 +152,6 @@ private: bool onDisplayChange(); bool onClipboardChange(); -// XXX // warp cursor without discarding queued events void warpCursorNoFlush(SInt32 x, SInt32 y); @@ -157,7 +160,6 @@ private: // test if event should be ignored bool ignore() const; -// XXX // update screen size cache void updateScreenShape(); @@ -278,6 +280,10 @@ private: // map of button state BYTE m_buttons[1 + kButtonExtra0 + 1]; + // suspend/resume callbacks + IJob* m_suspend; + IJob* m_resume; + static CMSWindowsScreen* s_screen; }; diff --git a/lib/platform/CMSWindowsScreenSaver.cpp b/lib/platform/CMSWindowsScreenSaver.cpp index 14e0bac3..89090009 100644 --- a/lib/platform/CMSWindowsScreenSaver.cpp +++ b/lib/platform/CMSWindowsScreenSaver.cpp @@ -13,10 +13,12 @@ */ #include "CMSWindowsScreenSaver.h" +#include "CMSWindowsScreen.h" #include "CThread.h" #include "CLog.h" #include "TMethodJob.h" #include "CArch.h" +#include "CArchMiscWindows.h" #include #include @@ -24,11 +26,21 @@ #define SPI_GETSCREENSAVERRUNNING 114 #endif +static const TCHAR* g_isSecureNT = "ScreenSaverIsSecure"; +static const TCHAR* g_isSecure9x = "ScreenSaverUsePassword"; +static const TCHAR* const g_pathScreenSaverIsSecure[] = { + "Control Panel", + "Desktop", + NULL +}; + // // CMSWindowsScreenSaver // CMSWindowsScreenSaver::CMSWindowsScreenSaver() : + m_wasSecure(false), + m_wasSecureAnInt(false), m_process(NULL), m_threadID(0), m_watch(NULL) @@ -119,6 +131,14 @@ void CMSWindowsScreenSaver::enable() { SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, m_wasEnabled, 0, 0); + + // restore password protection + if (m_wasSecure) { + setSecure(true, m_wasSecureAnInt); + } + + // restore display power down + CArchMiscWindows::removeBusyState(CArchMiscWindows::kDISPLAY); } void @@ -126,6 +146,15 @@ CMSWindowsScreenSaver::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 + CArchMiscWindows::addBusyState(CArchMiscWindows::kDISPLAY); } void @@ -141,6 +170,9 @@ CMSWindowsScreenSaver::activate() // no foreground window. pretend we got the event instead. DefWindowProc(NULL, WM_SYSCOMMAND, SC_SCREENSAVE, 0); } + + // restore power save when screen saver activates + CArchMiscWindows::removeBusyState(CArchMiscWindows::kDISPLAY); } } @@ -179,6 +211,9 @@ CMSWindowsScreenSaver::deactivate() !m_wasEnabled, 0, SPIF_SENDWININICHANGE); SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, m_wasEnabled, 0, SPIF_SENDWININICHANGE); + + // disable display power down + CArchMiscWindows::removeBusyState(CArchMiscWindows::kDISPLAY); } bool @@ -252,8 +287,11 @@ BOOL CALLBACK CMSWindowsScreenSaver::killScreenSaverFunc(HWND hwnd, LPARAM arg) { if (IsWindowVisible(hwnd)) { - PostMessage(hwnd, WM_CLOSE, 0, 0); - *reinterpret_cast(arg) = true; + HINSTANCE instance = (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE); + if (instance != CMSWindowsScreen::getInstance()) { + PostMessage(hwnd, WM_CLOSE, 0, 0); + *reinterpret_cast(arg) = true; + } } return TRUE; } @@ -375,3 +413,60 @@ CMSWindowsScreenSaver::watchProcessThread(void*) } } } + +void +CMSWindowsScreenSaver::setSecure(bool secure, bool saveSecureAsInt) +{ + HKEY hkey = + CArchMiscWindows::openKey(HKEY_CURRENT_USER, g_pathScreenSaverIsSecure); + if (hkey == NULL) { + return; + } + + const TCHAR* isSecure = m_is95Family ? g_isSecure9x : g_isSecureNT; + if (saveSecureAsInt) { + CArchMiscWindows::setValue(hkey, isSecure, secure ? 1 : 0); + } + else { + CArchMiscWindows::setValue(hkey, isSecure, secure ? "1" : "0"); + } + + CArchMiscWindows::closeKey(hkey); +} + +bool +CMSWindowsScreenSaver::isSecure(bool* wasSecureFlagAnInt) const +{ + // get the password protection setting key + HKEY hkey = + CArchMiscWindows::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; + const TCHAR* isSecure = m_is95Family ? g_isSecure9x : g_isSecureNT; + switch (CArchMiscWindows::typeOfValue(hkey, isSecure)) { + default: + result = false; + + case CArchMiscWindows::kUINT: { + DWORD value = + CArchMiscWindows::readValueInt(hkey, isSecure); + *wasSecureFlagAnInt = true; + result = (value != 0); + } + + case CArchMiscWindows::kSTRING: { + std::string value = + CArchMiscWindows::readValueString(hkey, isSecure); + *wasSecureFlagAnInt = false; + result = (value != "0"); + } + } + + CArchMiscWindows::closeKey(hkey); + return result; +} diff --git a/lib/platform/CMSWindowsScreenSaver.h b/lib/platform/CMSWindowsScreenSaver.h index b4c5feac..7cc7cdc9 100644 --- a/lib/platform/CMSWindowsScreenSaver.h +++ b/lib/platform/CMSWindowsScreenSaver.h @@ -16,6 +16,7 @@ #define CMSWINDOWSSCREENSAVER_H #include "IScreenSaver.h" +#include "CString.h" #define WIN32_LEAN_AND_MEAN #include @@ -65,11 +66,16 @@ private: void watchDesktopThread(void*); void watchProcessThread(void*); + void setSecure(bool secure, bool saveSecureAsInt); + bool isSecure(bool* wasSecureAnInt) const; + private: bool m_is95Family; bool m_is95; bool m_isNT; BOOL m_wasEnabled; + bool m_wasSecure; + bool m_wasSecureAnInt; HANDLE m_process; CThread* m_watch;