Added win32 support for power management.

This commit is contained in:
crs 2004-03-13 17:13:55 +00:00
parent a1c807ba67
commit a6e858a208
9 changed files with 401 additions and 60 deletions

View File

@ -13,17 +13,17 @@
#define IDR_TASKBAR 107 #define IDR_TASKBAR 107
#define IDD_TASKBAR_STATUS 108 #define IDD_TASKBAR_STATUS 108
#define IDC_TASKBAR_STATUS_STATUS 1000 #define IDC_TASKBAR_STATUS_STATUS 1000
#define IDC_TASKBAR_QUIT 40003 #define IDC_TASKBAR_QUIT 40001
#define IDC_TASKBAR_STATUS 40004 #define IDC_TASKBAR_STATUS 40002
#define IDC_TASKBAR_LOG 40005 #define IDC_TASKBAR_LOG 40003
// Next default values for new objects // Next default values for new objects
// //
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS #ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_RESOURCE_VALUE 109
#define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_COMMAND_VALUE 40004
#define _APS_NEXT_CONTROL_VALUE 1000 #define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101 #define _APS_NEXT_SYMED_VALUE 101
#endif #endif
#endif #endif

View File

@ -24,6 +24,7 @@
#include "CThread.h" #include "CThread.h"
#include "CEventQueue.h" #include "CEventQueue.h"
#include "CFunctionEventJob.h" #include "CFunctionEventJob.h"
#include "CFunctionJob.h"
#include "CLog.h" #include "CLog.h"
#include "CString.h" #include "CString.h"
#include "CStringUtil.h" #include "CStringUtil.h"
@ -54,7 +55,12 @@
#endif #endif
typedef int (*StartupFunc)(int, char**); typedef int (*StartupFunc)(int, char**);
static bool startClient();
static void parse(int argc, const char* const* argv); static void parse(int argc, const char* const* argv);
#if WINDOWS_LIKE
static void handleSystemSuspend(void*);
static void handleSystemResume(void*);
#endif
// //
// program arguments // program arguments
@ -97,7 +103,9 @@ CScreen*
createScreen() createScreen()
{ {
#if WINDOWS_LIKE #if WINDOWS_LIKE
return new CScreen(new CMSWindowsScreen(false)); return new CScreen(new CMSWindowsScreen(false,
new CFunctionJob(&handleSystemSuspend),
new CFunctionJob(&handleSystemResume)));
#elif UNIX_LIKE #elif UNIX_LIKE
return new CScreen(new CXWindowsScreen(false)); return new CScreen(new CXWindowsScreen(false));
#endif #endif
@ -124,6 +132,7 @@ static CClient* s_client = NULL;
static CScreen* s_clientScreen = NULL; static CScreen* s_clientScreen = NULL;
static CClientTaskBarReceiver* s_taskBarReceiver = NULL; static CClientTaskBarReceiver* s_taskBarReceiver = NULL;
static double s_retryTime = 0.0; static double s_retryTime = 0.0;
static bool s_suspened = false;
static static
void void
@ -181,6 +190,26 @@ handleScreenError(const CEvent&, void*)
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit)); 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 static
CScreen* CScreen*
openClientScreen() openClientScreen()
@ -211,11 +240,12 @@ handleClientRestart(const CEvent&, void* vtimer)
// discard old timer // discard old timer
CEventQueueTimer* timer = reinterpret_cast<CEventQueueTimer*>(vtimer); CEventQueueTimer* timer = reinterpret_cast<CEventQueueTimer*>(vtimer);
EVENTQUEUE->deleteTimer(timer); EVENTQUEUE->deleteTimer(timer);
EVENTQUEUE->removeHandler(CEvent::kTimer, NULL); EVENTQUEUE->removeHandler(CEvent::kTimer, timer);
// reconnect // reconnect
s_client->connect(); if (!s_suspened) {
updateStatus(); startClient();
}
} }
static static
@ -251,8 +281,10 @@ handleClientFailed(const CEvent& e, void*)
} }
else { else {
LOG((CLOG_WARN "failed to connect to server: %s", info->m_what)); LOG((CLOG_WARN "failed to connect to server: %s", info->m_what));
if (!s_suspened) {
scheduleClientRestart(nextRestartTimeout()); scheduleClientRestart(nextRestartTimeout());
} }
}
} }
static static
@ -263,7 +295,7 @@ handleClientDisconnected(const CEvent&, void*)
if (!ARG->m_restartable) { if (!ARG->m_restartable) {
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit)); EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
} }
else { else if (!s_suspened) {
s_client->connect(); s_client->connect();
} }
updateStatus(); updateStatus();
@ -308,11 +340,13 @@ startClient()
double retryTime; double retryTime;
CScreen* clientScreen = NULL; CScreen* clientScreen = NULL;
try { try {
if (s_clientScreen == NULL) {
clientScreen = openClientScreen(); clientScreen = openClientScreen();
s_client = openClient(ARG->m_name, s_client = openClient(ARG->m_name,
*ARG->m_serverAddress, clientScreen); *ARG->m_serverAddress, clientScreen);
s_clientScreen = clientScreen; s_clientScreen = clientScreen;
LOG((CLOG_NOTE "started client")); LOG((CLOG_NOTE "started client"));
}
s_client->connect(); s_client->connect();
updateStatus(); updateStatus();
return true; return true;

View File

@ -114,7 +114,7 @@ CScreen*
createScreen() createScreen()
{ {
#if WINDOWS_LIKE #if WINDOWS_LIKE
return new CScreen(new CMSWindowsScreen(true)); return new CScreen(new CMSWindowsScreen(true, NULL, NULL));
#elif UNIX_LIKE #elif UNIX_LIKE
return new CScreen(new CXWindowsScreen(true)); return new CScreen(new CXWindowsScreen(true));
#endif #endif

View File

@ -15,11 +15,24 @@
#include "CArchMiscWindows.h" #include "CArchMiscWindows.h"
#include "CArchDaemonWindows.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
// //
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 void
CArchMiscWindows::init() CArchMiscWindows::init()
@ -143,6 +156,29 @@ CArchMiscWindows::hasValue(HKEY key, const TCHAR* name)
(type == REG_DWORD || type == REG_SZ)); (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 void
CArchMiscWindows::setValue(HKEY key, CArchMiscWindows::setValue(HKEY key,
const TCHAR* name, const std::string& value) const TCHAR* name, const std::string& value)
@ -164,14 +200,25 @@ CArchMiscWindows::setValue(HKEY key, const TCHAR* name, DWORD value)
sizeof(DWORD)); 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<const BYTE*>(value.data()),
value.size());
}
std::string std::string
CArchMiscWindows::readValueString(HKEY key, const TCHAR* name) CArchMiscWindows::readBinaryOrString(HKEY key, const TCHAR* name, DWORD type)
{ {
// get the size of the string // get the size of the string
DWORD type; DWORD actualType;
DWORD size = 0; DWORD size = 0;
LONG result = RegQueryValueEx(key, name, 0, &type, NULL, &size); LONG result = RegQueryValueEx(key, name, 0, &actualType, NULL, &size);
if (result != ERROR_SUCCESS || type != REG_SZ) { if (result != ERROR_SUCCESS || actualType != type) {
return std::string(); return std::string();
} }
@ -179,19 +226,31 @@ CArchMiscWindows::readValueString(HKEY key, const TCHAR* name)
char* buffer = new char[size]; char* buffer = new char[size];
// read it // read it
result = RegQueryValueEx(key, name, 0, &type, result = RegQueryValueEx(key, name, 0, &actualType,
reinterpret_cast<BYTE*>(buffer), &size); reinterpret_cast<BYTE*>(buffer), &size);
if (result != ERROR_SUCCESS || type != REG_SZ) { if (result != ERROR_SUCCESS || actualType != type) {
delete[] buffer; delete[] buffer;
return std::string(); return std::string();
} }
// clean up and return value // clean up and return value
std::string value(buffer); std::string value(buffer, size);
delete[] buffer; delete[] buffer;
return value; 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 DWORD
CArchMiscWindows::readValueInt(HKEY key, const TCHAR* name) CArchMiscWindows::readValueInt(HKEY key, const TCHAR* name)
{ {
@ -229,3 +288,55 @@ CArchMiscWindows::processDialog(MSG* msg)
} }
return false; 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<STES_t>(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;
}

View File

@ -25,6 +25,19 @@
//! Miscellaneous win32 functions. //! Miscellaneous win32 functions.
class CArchMiscWindows { class CArchMiscWindows {
public: public:
enum EValueType {
kUNKNOWN,
kNO_VALUE,
kUINT,
kSTRING,
kBINARY
};
enum EBusyModes {
kIDLE = 0x0000,
kSYSTEM = 0x0001,
kDISPLAY = 0x0002
};
typedef int (*RunFunc)(void); typedef int (*RunFunc)(void);
//! Initialize //! Initialize
@ -78,6 +91,9 @@ public:
//! Test if a value exists //! Test if a value exists
static bool hasValue(HKEY key, const TCHAR* name); 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 //! Set a string value in the registry
static void setValue(HKEY key, const TCHAR* name, static void setValue(HKEY key, const TCHAR* name,
const std::string& value); const std::string& value);
@ -85,12 +101,22 @@ public:
//! Set a DWORD value in the registry //! Set a DWORD value in the registry
static void setValue(HKEY key, const TCHAR* name, DWORD value); 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 //! Read a string value from the registry
static std::string readValueString(HKEY, const TCHAR* name); static std::string readValueString(HKEY, const TCHAR* name);
//! Read a DWORD value from the registry //! Read a DWORD value from the registry
static DWORD readValueInt(HKEY, const TCHAR* name); 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 //! Add a dialog
static void addDialog(HWND); static void addDialog(HWND);
@ -104,10 +130,28 @@ public:
*/ */
static bool processDialog(MSG*); 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: private:
typedef std::set<HWND> CDialogs; typedef std::set<HWND> CDialogs;
typedef DWORD (WINAPI *STES_t)(DWORD);
static CDialogs* s_dialogs; static CDialogs* s_dialogs;
static DWORD s_busyState;
static STES_t s_stes;
}; };
#endif #endif

View File

@ -113,7 +113,8 @@
HINSTANCE CMSWindowsScreen::s_instance = NULL; HINSTANCE CMSWindowsScreen::s_instance = NULL;
CMSWindowsScreen* CMSWindowsScreen::s_screen = NULL; CMSWindowsScreen* CMSWindowsScreen::s_screen = NULL;
CMSWindowsScreen::CMSWindowsScreen(bool isPrimary) : CMSWindowsScreen::CMSWindowsScreen(bool isPrimary,
IJob* suspend, IJob* resume) :
m_isPrimary(isPrimary), m_isPrimary(isPrimary),
m_is95Family(CArchMiscWindows::isWindows95Family()), m_is95Family(CArchMiscWindows::isWindows95Family()),
m_isOnScreen(m_isPrimary), m_isOnScreen(m_isPrimary),
@ -137,16 +138,29 @@ CMSWindowsScreen::CMSWindowsScreen(bool isPrimary) :
m_activeDesk(NULL), m_activeDesk(NULL),
m_activeDeskName(), m_activeDeskName(),
m_hookLibrary(NULL), 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_keyState(NULL),
m_mutex(), m_mutex(),
m_deskReady(&m_mutex, false) m_deskReady(&m_mutex, false),
m_suspend(suspend),
m_resume(resume)
{ {
assert(s_instance != NULL); assert(s_instance != NULL);
assert(s_screen == NULL); assert(s_screen == NULL);
s_screen = this; s_screen = this;
try { try {
if (m_isPrimary) {
m_hookLibrary = openHookLibrary("synrgyhk"); m_hookLibrary = openHookLibrary("synrgyhk");
}
m_cursor = createBlankCursor(); m_cursor = createBlankCursor();
m_class = createWindowClass(); m_class = createWindowClass();
m_deskClass = createDeskWindowClass(m_isPrimary); m_deskClass = createDeskWindowClass(m_isPrimary);
@ -171,9 +185,6 @@ CMSWindowsScreen::CMSWindowsScreen(bool isPrimary) :
throw; throw;
} }
// install our clipboard snooper
m_nextClipboardWindow = SetClipboardViewer(m_window);
// install event handlers // install event handlers
EVENTQUEUE->adoptHandler(CEvent::kSystem, IEventQueue::getSystemTarget(), EVENTQUEUE->adoptHandler(CEvent::kSystem, IEventQueue::getSystemTarget(),
new TMethodEventJob<CMSWindowsScreen>(this, new TMethodEventJob<CMSWindowsScreen>(this,
@ -190,14 +201,14 @@ CMSWindowsScreen::~CMSWindowsScreen()
disable(); disable();
EVENTQUEUE->adoptBuffer(NULL); EVENTQUEUE->adoptBuffer(NULL);
EVENTQUEUE->removeHandler(CEvent::kSystem, IEventQueue::getSystemTarget()); EVENTQUEUE->removeHandler(CEvent::kSystem, IEventQueue::getSystemTarget());
removeDesks();
ChangeClipboardChain(m_window, m_nextClipboardWindow);
delete m_screensaver; delete m_screensaver;
destroyWindow(m_window); destroyWindow(m_window);
destroyClass(m_deskClass); destroyClass(m_deskClass);
destroyClass(m_class); destroyClass(m_class);
destroyCursor(m_cursor); destroyCursor(m_cursor);
closeHookLibrary(m_hookLibrary); closeHookLibrary(m_hookLibrary);
delete m_suspend;
delete m_resume;
s_screen = NULL; s_screen = NULL;
} }
@ -229,6 +240,9 @@ CMSWindowsScreen::enable()
{ {
assert(m_isOnScreen == m_isPrimary); assert(m_isOnScreen == m_isPrimary);
// install our clipboard snooper
m_nextClipboardWindow = SetClipboardViewer(m_window);
if (m_isPrimary) { if (m_isPrimary) {
// update shadow key state // update shadow key state
m_keyMapper.update(NULL); m_keyMapper.update(NULL);
@ -239,6 +253,12 @@ CMSWindowsScreen::enable()
// watch jump zones // watch jump zones
m_setMode(kHOOK_WATCH_JUMP_ZONE); 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 // set the active desk and (re)install the hooks
checkDesk(); checkDesk();
@ -263,10 +283,27 @@ CMSWindowsScreen::disable()
m_timer = NULL; m_timer = NULL;
} }
// disable hooks
if (m_isPrimary) { if (m_isPrimary) {
// disable hooks
m_setMode(kHOOK_DISABLE); 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 void
@ -973,6 +1010,25 @@ CMSWindowsScreen::onEvent(HWND, UINT msg,
case WM_DISPLAYCHANGE: case WM_DISPLAYCHANGE:
return onDisplayChange(); 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; return false;
@ -1316,10 +1372,16 @@ CMSWindowsScreen::onScreensaver(bool activated)
if (activated) { if (activated) {
if (m_screensaver->checkStarted(SYNERGY_MSG_SCREEN_SAVER, FALSE, 0)) { if (m_screensaver->checkStarted(SYNERGY_MSG_SCREEN_SAVER, FALSE, 0)) {
sendEvent(getScreensaverActivatedEvent()); sendEvent(getScreensaverActivatedEvent());
// enable display power down
CArchMiscWindows::removeBusyState(CArchMiscWindows::kDISPLAY);
} }
} }
else { else {
sendEvent(getScreensaverDeactivatedEvent()); sendEvent(getScreensaverDeactivatedEvent());
// disable display power down
CArchMiscWindows::addBusyState(CArchMiscWindows::kDISPLAY);
} }
return true; return true;
@ -1616,7 +1678,6 @@ LRESULT CALLBACK
CMSWindowsScreen::primaryDeskProc( CMSWindowsScreen::primaryDeskProc(
HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{ {
// FIXME
return DefWindowProc(hwnd, msg, wParam, lParam); return DefWindowProc(hwnd, msg, wParam, lParam);
} }
@ -1893,6 +1954,7 @@ CMSWindowsScreen::deskThread(void* vdesk)
} }
// clean up // clean up
deskEnter(desk);
if (desk->m_window != NULL) { if (desk->m_window != NULL) {
DestroyWindow(desk->m_window); DestroyWindow(desk->m_window);
} }
@ -1927,6 +1989,8 @@ CMSWindowsScreen::removeDesks()
delete desk; delete desk;
} }
m_desks.clear(); m_desks.clear();
m_activeDesk = NULL;
m_activeDeskName = "";
} }
void void
@ -1952,7 +2016,6 @@ CMSWindowsScreen::checkDesk()
// active becaue we'd most likely switch to the screensaver desktop // active becaue we'd most likely switch to the screensaver desktop
// which would have the side effect of forcing the screensaver to // which would have the side effect of forcing the screensaver to
// stop. // stop.
// FIXME -- really not switch if screensaver is active?
if (name != m_activeDeskName && !m_screensaver->isActive()) { if (name != m_activeDeskName && !m_screensaver->isActive()) {
// show cursor on previous desk // show cursor on previous desk
if (!m_isOnScreen) { 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 bool
CMSWindowsScreen::isDeskAccessible(const CDesk* desk) const CMSWindowsScreen::isDeskAccessible(const CDesk* desk) const
{ {

View File

@ -31,7 +31,7 @@ class CThread;
//! Implementation of IPlatformScreen for Microsoft Windows //! Implementation of IPlatformScreen for Microsoft Windows
class CMSWindowsScreen : public IPlatformScreen { class CMSWindowsScreen : public IPlatformScreen {
public: public:
CMSWindowsScreen(bool isPrimary); CMSWindowsScreen(bool isPrimary, IJob* suspend, IJob* resume);
virtual ~CMSWindowsScreen(); virtual ~CMSWindowsScreen();
//! @name manipulators //! @name manipulators
@ -112,7 +112,7 @@ private:
}; };
typedef std::map<CString, CDesk*> CDesks; typedef std::map<CString, CDesk*> CDesks;
// FIXME -- comment // initialization and shutdown operations
HINSTANCE openHookLibrary(const char* name); HINSTANCE openHookLibrary(const char* name);
void closeHookLibrary(HINSTANCE hookLibrary) const; void closeHookLibrary(HINSTANCE hookLibrary) const;
HCURSOR createBlankCursor() const; HCURSOR createBlankCursor() const;
@ -122,8 +122,12 @@ private:
void destroyClass(ATOM windowClass) const; void destroyClass(ATOM windowClass) const;
HWND createWindow(ATOM windowClass, const char* name) const; HWND createWindow(ATOM windowClass, const char* name) const;
void destroyWindow(HWND) const; void destroyWindow(HWND) const;
// convenience function to send events
void sendEvent(CEvent::Type type, void* = NULL); void sendEvent(CEvent::Type type, void* = NULL);
void sendClipboardEvent(CEvent::Type type, ClipboardID id); void sendClipboardEvent(CEvent::Type type, ClipboardID id);
// system event handler (does DispatchMessage)
void handleSystemEvent(const CEvent& event, void*); void handleSystemEvent(const CEvent& event, void*);
// handle message before it gets dispatched. returns true iff // handle message before it gets dispatched. returns true iff
@ -148,7 +152,6 @@ private:
bool onDisplayChange(); bool onDisplayChange();
bool onClipboardChange(); bool onClipboardChange();
// XXX
// warp cursor without discarding queued events // warp cursor without discarding queued events
void warpCursorNoFlush(SInt32 x, SInt32 y); void warpCursorNoFlush(SInt32 x, SInt32 y);
@ -157,7 +160,6 @@ private:
// test if event should be ignored // test if event should be ignored
bool ignore() const; bool ignore() const;
// XXX
// update screen size cache // update screen size cache
void updateScreenShape(); void updateScreenShape();
@ -278,6 +280,10 @@ private:
// map of button state // map of button state
BYTE m_buttons[1 + kButtonExtra0 + 1]; BYTE m_buttons[1 + kButtonExtra0 + 1];
// suspend/resume callbacks
IJob* m_suspend;
IJob* m_resume;
static CMSWindowsScreen* s_screen; static CMSWindowsScreen* s_screen;
}; };

View File

@ -13,10 +13,12 @@
*/ */
#include "CMSWindowsScreenSaver.h" #include "CMSWindowsScreenSaver.h"
#include "CMSWindowsScreen.h"
#include "CThread.h" #include "CThread.h"
#include "CLog.h" #include "CLog.h"
#include "TMethodJob.h" #include "TMethodJob.h"
#include "CArch.h" #include "CArch.h"
#include "CArchMiscWindows.h"
#include <malloc.h> #include <malloc.h>
#include <tchar.h> #include <tchar.h>
@ -24,11 +26,21 @@
#define SPI_GETSCREENSAVERRUNNING 114 #define SPI_GETSCREENSAVERRUNNING 114
#endif #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::CMSWindowsScreenSaver() : CMSWindowsScreenSaver::CMSWindowsScreenSaver() :
m_wasSecure(false),
m_wasSecureAnInt(false),
m_process(NULL), m_process(NULL),
m_threadID(0), m_threadID(0),
m_watch(NULL) m_watch(NULL)
@ -119,6 +131,14 @@ void
CMSWindowsScreenSaver::enable() CMSWindowsScreenSaver::enable()
{ {
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, m_wasEnabled, 0, 0); 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 void
@ -126,6 +146,15 @@ CMSWindowsScreenSaver::disable()
{ {
SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0); SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0);
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, 0, 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 void
@ -141,6 +170,9 @@ CMSWindowsScreenSaver::activate()
// no foreground window. pretend we got the event instead. // no foreground window. pretend we got the event instead.
DefWindowProc(NULL, WM_SYSCOMMAND, SC_SCREENSAVE, 0); 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); !m_wasEnabled, 0, SPIF_SENDWININICHANGE);
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, SystemParametersInfo(SPI_SETSCREENSAVEACTIVE,
m_wasEnabled, 0, SPIF_SENDWININICHANGE); m_wasEnabled, 0, SPIF_SENDWININICHANGE);
// disable display power down
CArchMiscWindows::removeBusyState(CArchMiscWindows::kDISPLAY);
} }
bool bool
@ -252,9 +287,12 @@ BOOL CALLBACK
CMSWindowsScreenSaver::killScreenSaverFunc(HWND hwnd, LPARAM arg) CMSWindowsScreenSaver::killScreenSaverFunc(HWND hwnd, LPARAM arg)
{ {
if (IsWindowVisible(hwnd)) { if (IsWindowVisible(hwnd)) {
HINSTANCE instance = (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE);
if (instance != CMSWindowsScreen::getInstance()) {
PostMessage(hwnd, WM_CLOSE, 0, 0); PostMessage(hwnd, WM_CLOSE, 0, 0);
*reinterpret_cast<bool*>(arg) = true; *reinterpret_cast<bool*>(arg) = true;
} }
}
return 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;
}

View File

@ -16,6 +16,7 @@
#define CMSWINDOWSSCREENSAVER_H #define CMSWINDOWSSCREENSAVER_H
#include "IScreenSaver.h" #include "IScreenSaver.h"
#include "CString.h"
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
@ -65,11 +66,16 @@ private:
void watchDesktopThread(void*); void watchDesktopThread(void*);
void watchProcessThread(void*); void watchProcessThread(void*);
void setSecure(bool secure, bool saveSecureAsInt);
bool isSecure(bool* wasSecureAnInt) const;
private: private:
bool m_is95Family; bool m_is95Family;
bool m_is95; bool m_is95;
bool m_isNT; bool m_isNT;
BOOL m_wasEnabled; BOOL m_wasEnabled;
bool m_wasSecure;
bool m_wasSecureAnInt;
HANDLE m_process; HANDLE m_process;
CThread* m_watch; CThread* m_watch;