Changeset 2752 for trunk/synergy/lib/platform/CPMScreenSaver.cpp
- Timestamp:
- Jul 29, 2006, 6:43:07 AM (19 years ago)
- File:
-
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/synergy/lib/platform/CPMScreenSaver.cpp
r2751 r2752 2 2 * synergy -- mouse and keyboard sharing utility 3 3 * Copyright (C) 2002 Chris Schoeneman 4 * Copyright (C) 2006 Knut St. Osmundsen 4 5 * 5 6 * This package is free software; you can redistribute it and/or … … 13 14 */ 14 15 15 #include "CMSWindowsScreenSaver.h" 16 #include "CMSWindowsScreen.h" 17 #include "CThread.h" 18 #include "CLog.h" 19 #include "TMethodJob.h" 20 #include "CArch.h" 21 #include "CArchMiscWindows.h" 22 #include <malloc.h> 23 #include <tchar.h> 24 25 #if !defined(SPI_GETSCREENSAVERRUNNING) 26 #define SPI_GETSCREENSAVERRUNNING 114 27 #endif 28 29 static const TCHAR* g_isSecureNT = "ScreenSaverIsSecure"; 30 static const TCHAR* g_isSecure9x = "ScreenSaveUsePassword"; 31 static const TCHAR* const g_pathScreenSaverIsSecure[] = { 32 "Control Panel", 33 "Desktop", 34 NULL 35 }; 16 #include "CPMScreenSaver.h" 36 17 37 18 // 38 // C MSWindowsScreenSaver19 // CPMScreenSaver 39 20 // 40 21 41 CMSWindowsScreenSaver::CMSWindowsScreenSaver() : 42 m_wasSecure(false), 43 m_wasSecureAnInt(false), 44 m_process(NULL), 45 m_watch(NULL), 46 m_threadID(0), 47 m_active(false) 22 CPMScreenSaver::CPMScreenSaver() 48 23 { 49 // detect OS50 m_is95Family = false;51 m_is95 = false;52 m_isNT = false;53 OSVERSIONINFO info;54 info.dwOSVersionInfoSize = sizeof(info);55 if (GetVersionEx(&info)) {56 m_is95Family = (info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);57 if (info.dwPlatformId == VER_PLATFORM_WIN32_NT &&58 info.dwMajorVersion <= 4) {59 m_isNT = true;60 }61 else if (info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS &&62 info.dwMajorVersion == 4 &&63 info.dwMinorVersion == 0) {64 m_is95 = true;65 }66 }67 68 // check if screen saver is enabled69 SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0);70 24 } 71 25 72 C MSWindowsScreenSaver::~CMSWindowsScreenSaver()26 CPMScreenSaver::~CPMScreenSaver() 73 27 { 74 unwatchProcess(); 28 } 29 30 void 31 CPMScreenSaver::enable() 32 { 33 } 34 35 void 36 CPMScreenSaver::disable() 37 { 38 } 39 40 void 41 CPMScreenSaver::activate() 42 { 43 } 44 45 void 46 CPMScreenSaver::deactivate() 47 { 75 48 } 76 49 77 50 bool 78 C MSWindowsScreenSaver::checkStarted(UINT msg, WPARAM wParam, LPARAM lParam)51 CPMScreenSaver::isActive() const 79 52 { 80 // if already started then say it didn't just start 81 if (m_active) { 82 return false; 83 } 84 85 // screen saver may have started. look for it and get 86 // the process. if we can't find it then assume it 87 // didn't really start. we wait a moment before 88 // looking to give the screen saver a chance to start. 89 // this shouldn't be a problem since we only get here 90 // if the screen saver wants to kick in, meaning that 91 // the system is idle or the user deliberately started 92 // the screen saver. 93 Sleep(250); 94 95 // set parameters common to all screen saver handling 96 m_threadID = GetCurrentThreadId(); 97 m_msg = msg; 98 m_wParam = wParam; 99 m_lParam = lParam; 100 101 // we handle the screen saver differently for the windows 102 // 95 and nt families. 103 if (m_is95Family) { 104 // on windows 95 we wait for the screen saver process 105 // to terminate. get the process. 106 DWORD processID = findScreenSaver(); 107 HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, processID); 108 if (process == NULL) { 109 // didn't start 110 LOG((CLOG_DEBUG2 "can't open screen saver process")); 111 return false; 112 } 113 114 // watch for the process to exit 115 watchProcess(process); 116 } 117 else { 118 // on the windows nt family we wait for the desktop to 119 // change until it's neither the Screen-Saver desktop 120 // nor a desktop we can't open (the login desktop). 121 // since windows will send the request-to-start-screen- 122 // saver message even when the screen saver is disabled 123 // we first check that the screen saver is indeed active 124 // before watching for it to stop. 125 if (!isActive()) { 126 LOG((CLOG_DEBUG2 "can't open screen saver desktop")); 127 return false; 128 } 129 130 watchDesktop(); 131 } 132 133 return true; 53 return false; 134 54 } 135 55 136 void137 CMSWindowsScreenSaver::enable()138 {139 SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, m_wasEnabled, 0, 0);140 141 // restore password protection142 if (m_wasSecure) {143 setSecure(true, m_wasSecureAnInt);144 }145 146 // restore display power down147 CArchMiscWindows::removeBusyState(CArchMiscWindows::kDISPLAY);148 }149 150 void151 CMSWindowsScreenSaver::disable()152 {153 SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0);154 SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, 0, 0);155 156 // disable password protected screensaver157 m_wasSecure = isSecure(&m_wasSecureAnInt);158 if (m_wasSecure) {159 setSecure(false, m_wasSecureAnInt);160 }161 162 // disable display power down163 CArchMiscWindows::addBusyState(CArchMiscWindows::kDISPLAY);164 }165 166 void167 CMSWindowsScreenSaver::activate()168 {169 // don't activate if already active170 if (!isActive()) {171 // activate172 HWND hwnd = GetForegroundWindow();173 if (hwnd != NULL) {174 PostMessage(hwnd, WM_SYSCOMMAND, SC_SCREENSAVE, 0);175 }176 else {177 // no foreground window. pretend we got the event instead.178 DefWindowProc(NULL, WM_SYSCOMMAND, SC_SCREENSAVE, 0);179 }180 181 // restore power save when screen saver activates182 CArchMiscWindows::removeBusyState(CArchMiscWindows::kDISPLAY);183 }184 }185 186 void187 CMSWindowsScreenSaver::deactivate()188 {189 bool killed = false;190 if (!m_is95Family) {191 // NT runs screen saver in another desktop192 HDESK desktop = OpenDesktop("Screen-saver", 0, FALSE,193 DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS);194 if (desktop != NULL) {195 EnumDesktopWindows(desktop,196 &CMSWindowsScreenSaver::killScreenSaverFunc,197 reinterpret_cast<LPARAM>(&killed));198 CloseDesktop(desktop);199 }200 }201 202 // if above failed or wasn't tried, try the windows 95 way203 if (!killed) {204 // find screen saver window and close it205 HWND hwnd = FindWindow("WindowsScreenSaverClass", NULL);206 if (hwnd == NULL) {207 // win2k may use a different class208 hwnd = FindWindow("Default Screen Saver", NULL);209 }210 if (hwnd != NULL) {211 PostMessage(hwnd, WM_CLOSE, 0, 0);212 }213 }214 215 // force timer to restart216 SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0);217 SystemParametersInfo(SPI_SETSCREENSAVEACTIVE,218 !m_wasEnabled, 0, SPIF_SENDWININICHANGE);219 SystemParametersInfo(SPI_SETSCREENSAVEACTIVE,220 m_wasEnabled, 0, SPIF_SENDWININICHANGE);221 222 // disable display power down223 CArchMiscWindows::removeBusyState(CArchMiscWindows::kDISPLAY);224 }225 226 bool227 CMSWindowsScreenSaver::isActive() const228 {229 if (m_is95) {230 return (FindWindow("WindowsScreenSaverClass", NULL) != NULL);231 }232 else if (m_isNT) {233 // screen saver runs on a separate desktop234 HDESK desktop = OpenDesktop("Screen-saver", 0, FALSE, MAXIMUM_ALLOWED);235 if (desktop == NULL && GetLastError() != ERROR_ACCESS_DENIED) {236 // desktop doesn't exist so screen saver is not running237 return false;238 }239 240 // desktop exists. this should indicate that the screen saver241 // is running but an OS bug can cause a valid handle to be242 // returned even if the screen saver isn't running (Q230117).243 // we'll try to enumerate the windows on the desktop and, if244 // there are any, we assume the screen saver is running. (note245 // that if we don't have permission to enumerate then we'll246 // assume that the screen saver is not running.) that'd be247 // easy enough except there's another OS bug (Q198590) that can248 // cause EnumDesktopWindows() to enumerate the windows of249 // another desktop if the requested desktop has no windows. to250 // work around that we have to verify that the enumerated251 // windows are, in fact, on the expected desktop.252 CFindScreenSaverInfo info;253 info.m_desktop = desktop;254 info.m_window = NULL;255 EnumDesktopWindows(desktop,256 &CMSWindowsScreenSaver::findScreenSaverFunc,257 reinterpret_cast<LPARAM>(&info));258 259 // done with desktop260 CloseDesktop(desktop);261 262 // screen saver is running if a window was found263 return (info.m_window != NULL);264 }265 else {266 BOOL running;267 SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &running, 0);268 return (running != FALSE);269 }270 }271 272 BOOL CALLBACK273 CMSWindowsScreenSaver::findScreenSaverFunc(HWND hwnd, LPARAM arg)274 {275 CFindScreenSaverInfo* info = reinterpret_cast<CFindScreenSaverInfo*>(arg);276 277 if (info->m_desktop != NULL) {278 DWORD threadID = GetWindowThreadProcessId(hwnd, NULL);279 HDESK desktop = GetThreadDesktop(threadID);280 if (desktop != NULL && desktop != info->m_desktop) {281 // stop enumerating -- wrong desktop282 return FALSE;283 }284 }285 286 // found a window287 info->m_window = hwnd;288 289 // don't need to enumerate further290 return FALSE;291 }292 293 BOOL CALLBACK294 CMSWindowsScreenSaver::killScreenSaverFunc(HWND hwnd, LPARAM arg)295 {296 if (IsWindowVisible(hwnd)) {297 HINSTANCE instance = (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE);298 if (instance != CMSWindowsScreen::getInstance()) {299 PostMessage(hwnd, WM_CLOSE, 0, 0);300 *reinterpret_cast<bool*>(arg) = true;301 }302 }303 return TRUE;304 }305 306 DWORD307 CMSWindowsScreenSaver::findScreenSaver()308 {309 // try windows 95 way310 HWND hwnd = FindWindow("WindowsScreenSaverClass", NULL);311 312 // get process ID of process that owns the window, if found313 if (hwnd != NULL) {314 DWORD processID;315 GetWindowThreadProcessId(hwnd, &processID);316 return processID;317 }318 319 // not found320 return 0;321 }322 323 void324 CMSWindowsScreenSaver::watchDesktop()325 {326 // stop watching previous process/desktop327 unwatchProcess();328 329 // watch desktop in another thread330 LOG((CLOG_DEBUG "watching screen saver desktop"));331 m_active = true;332 m_watch = new CThread(new TMethodJob<CMSWindowsScreenSaver>(this,333 &CMSWindowsScreenSaver::watchDesktopThread));334 }335 336 void337 CMSWindowsScreenSaver::watchProcess(HANDLE process)338 {339 // stop watching previous process/desktop340 unwatchProcess();341 342 // watch new process in another thread343 if (process != NULL) {344 LOG((CLOG_DEBUG "watching screen saver process"));345 m_process = process;346 m_active = true;347 m_watch = new CThread(new TMethodJob<CMSWindowsScreenSaver>(this,348 &CMSWindowsScreenSaver::watchProcessThread));349 }350 }351 352 void353 CMSWindowsScreenSaver::unwatchProcess()354 {355 if (m_watch != NULL) {356 LOG((CLOG_DEBUG "stopped watching screen saver process/desktop"));357 m_watch->cancel();358 m_watch->wait();359 delete m_watch;360 m_watch = NULL;361 m_active = false;362 }363 if (m_process != NULL) {364 CloseHandle(m_process);365 m_process = NULL;366 }367 }368 369 void370 CMSWindowsScreenSaver::watchDesktopThread(void*)371 {372 DWORD reserved = 0;373 TCHAR* name = NULL;374 375 for (;;) {376 // wait a bit377 ARCH->sleep(0.2);378 379 if (m_isNT) {380 // get current desktop381 HDESK desk = OpenInputDesktop(0, FALSE, GENERIC_READ);382 if (desk == NULL) {383 // can't open desktop so keep waiting384 continue;385 }386 387 // get current desktop name length388 DWORD size;389 GetUserObjectInformation(desk, UOI_NAME, NULL, 0, &size);390 391 // allocate more space for the name, if necessary392 if (size > reserved) {393 reserved = size;394 name = (TCHAR*)alloca(reserved + sizeof(TCHAR));395 }396 397 // get current desktop name398 GetUserObjectInformation(desk, UOI_NAME, name, size, &size);399 CloseDesktop(desk);400 401 // compare name to screen saver desktop name402 if (_tcsicmp(name, TEXT("Screen-saver")) == 0) {403 // still the screen saver desktop so keep waiting404 continue;405 }406 }407 else {408 // 2000/XP have a sane way to detect a runnin screensaver.409 BOOL running;410 SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &running, 0);411 if (running) {412 continue;413 }414 }415 416 // send screen saver deactivation message417 m_active = false;418 PostThreadMessage(m_threadID, m_msg, m_wParam, m_lParam);419 return;420 }421 }422 423 void424 CMSWindowsScreenSaver::watchProcessThread(void*)425 {426 for (;;) {427 CThread::testCancel();428 if (WaitForSingleObject(m_process, 50) == WAIT_OBJECT_0) {429 // process terminated430 LOG((CLOG_DEBUG "screen saver died"));431 432 // send screen saver deactivation message433 m_active = false;434 PostThreadMessage(m_threadID, m_msg, m_wParam, m_lParam);435 return;436 }437 }438 }439 440 void441 CMSWindowsScreenSaver::setSecure(bool secure, bool saveSecureAsInt)442 {443 HKEY hkey =444 CArchMiscWindows::addKey(HKEY_CURRENT_USER, g_pathScreenSaverIsSecure);445 if (hkey == NULL) {446 return;447 }448 449 const TCHAR* isSecure = m_is95Family ? g_isSecure9x : g_isSecureNT;450 if (saveSecureAsInt) {451 CArchMiscWindows::setValue(hkey, isSecure, secure ? 1 : 0);452 }453 else {454 CArchMiscWindows::setValue(hkey, isSecure, secure ? "1" : "0");455 }456 457 CArchMiscWindows::closeKey(hkey);458 }459 460 bool461 CMSWindowsScreenSaver::isSecure(bool* wasSecureFlagAnInt) const462 {463 // get the password protection setting key464 HKEY hkey =465 CArchMiscWindows::openKey(HKEY_CURRENT_USER, g_pathScreenSaverIsSecure);466 if (hkey == NULL) {467 return false;468 }469 470 // get the value. the value may be an int or a string, depending471 // on the version of windows.472 bool result;473 const TCHAR* isSecure = m_is95Family ? g_isSecure9x : g_isSecureNT;474 switch (CArchMiscWindows::typeOfValue(hkey, isSecure)) {475 default:476 result = false;477 break;478 479 case CArchMiscWindows::kUINT: {480 DWORD value =481 CArchMiscWindows::readValueInt(hkey, isSecure);482 *wasSecureFlagAnInt = true;483 result = (value != 0);484 break;485 }486 487 case CArchMiscWindows::kSTRING: {488 std::string value =489 CArchMiscWindows::readValueString(hkey, isSecure);490 *wasSecureFlagAnInt = false;491 result = (value != "0");492 break;493 }494 }495 496 CArchMiscWindows::closeKey(hkey);497 return result;498 }
Note:
See TracChangeset
for help on using the changeset viewer.