1 /* 2 * PROJECT: ReactOS Screen Saver Library 3 * LICENSE: GPL v2 or any later version 4 * FILE: lib/sdk/scrnsave/scrnsave.c 5 * PURPOSE: Library for writing screen savers, compatible with 6 * MS' scrnsave.lib without Win9x support. 7 * PROGRAMMERS: Anders Norlander <anorland@hem2.passagen.se> 8 * Colin Finck <mail@colinfinck.de> 9 */ 10 11 #include <stdarg.h> 12 #include <windef.h> 13 #include <winbase.h> 14 #include <wingdi.h> 15 #include <winuser.h> 16 #include <tchar.h> 17 #include <stdlib.h> 18 #include <scrnsave.h> 19 20 // Screen Saver window class 21 #define CLASS_SCRNSAVE TEXT("WindowsScreenSaverClass") 22 23 // Globals 24 HWND hMainWindow = NULL; 25 BOOL fChildPreview = FALSE; 26 HINSTANCE hMainInstance; 27 TCHAR szName[TITLEBARNAMELEN]; 28 TCHAR szAppName[APPNAMEBUFFERLEN]; 29 TCHAR szIniFile[MAXFILELEN]; 30 TCHAR szScreenSaver[22]; 31 TCHAR szHelpFile[MAXFILELEN]; 32 TCHAR szNoHelpMemory[BUFFLEN]; 33 UINT MyHelpMessage; 34 35 // Local house keeping 36 static POINT pt_orig; 37 static BOOL pt_init = FALSE; 38 39 static int ISSPACE(TCHAR c) 40 { 41 return (c == ' ' || c == '\t'); 42 } 43 44 #define ISNUM(c) ((c) >= '0' && (c) <= '9') 45 46 static ULONG_PTR _toulptr(const TCHAR *s) 47 { 48 ULONG_PTR res; 49 ULONG_PTR n; 50 const TCHAR *p; 51 52 for (p = s; *p; p++) 53 if (!ISNUM(*p)) 54 break; 55 56 p--; 57 res = 0; 58 59 for (n = 1; p >= s; p--, n *= 10) 60 res += (*p - '0') * n; 61 62 return res; 63 } 64 65 // This function takes care of *must* do tasks, like terminating screen saver 66 static LRESULT WINAPI SysScreenSaverProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 67 { 68 switch(uMsg) 69 { 70 case WM_DESTROY: 71 PostQuitMessage(0); 72 break; 73 74 case WM_SYSCOMMAND: 75 if (!fChildPreview) 76 { 77 switch (wParam) 78 { 79 case SC_CLOSE: // - Closing the screen saver, or... 80 case SC_NEXTWINDOW: // - Switching to 81 case SC_PREVWINDOW: // different windows, or... 82 case SC_SCREENSAVE: // - Starting another screen saver: 83 return FALSE; // Fail it! 84 } 85 } 86 break; 87 } 88 89 return ScreenSaverProc(hWnd, uMsg, wParam, lParam); 90 } 91 92 LRESULT WINAPI DefScreenSaverProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 93 { 94 // Don't do any special processing when in preview mode 95 if (fChildPreview) 96 return DefWindowProc(hWnd, uMsg, wParam, lParam); 97 98 switch (uMsg) 99 { 100 case WM_NCACTIVATE: 101 case WM_ACTIVATE: 102 case WM_ACTIVATEAPP: 103 if (!wParam) 104 { 105 // wParam is FALSE, so the screen saver is losing the focus. 106 PostMessage(hWnd, WM_CLOSE, 0, 0); 107 } 108 break; 109 110 case WM_MOUSEMOVE: 111 { 112 POINT pt; 113 GetCursorPos(&pt); 114 115 if (!pt_init) 116 { 117 pt_orig = pt; 118 pt_init = TRUE; 119 break; 120 } 121 122 if (abs(pt.x-pt_orig.x) > 10 || abs(pt.y-pt_orig.y) > 10) 123 PostMessage(hWnd, WM_CLOSE, 0, 0); 124 break; 125 } 126 127 case WM_LBUTTONDOWN: 128 case WM_MBUTTONDOWN: 129 case WM_RBUTTONDOWN: 130 case WM_XBUTTONDOWN: 131 case WM_KEYDOWN: 132 case WM_KEYUP: 133 case WM_SYSKEYDOWN: 134 // Send a WM_CLOSE to close the screen saver (allows 135 // the screen saver to perform clean-up tasks) 136 PostMessage(hWnd, WM_CLOSE, 0, 0); 137 break; 138 139 case WM_SETCURSOR: 140 SetCursor(NULL); 141 return TRUE; 142 } 143 144 return DefWindowProc(hWnd, uMsg, wParam, lParam); 145 } 146 147 // Registers the screen saver window class 148 static BOOL RegisterScreenSaverClass(void) 149 { 150 WNDCLASS cls; 151 152 cls.hCursor = NULL; 153 cls.hIcon = LoadIcon(hMainInstance, MAKEINTATOM(ID_APP)); 154 cls.lpszMenuName = NULL; 155 cls.lpszClassName = CLASS_SCRNSAVE; 156 cls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); 157 cls.hInstance = hMainInstance; 158 cls.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS | CS_SAVEBITS | CS_PARENTDC; 159 cls.lpfnWndProc = SysScreenSaverProc; 160 cls.cbWndExtra = 0; 161 cls.cbClsExtra = 0; 162 163 return (RegisterClass(&cls) != 0); 164 } 165 166 static int LaunchConfig(HWND hParent) 167 { 168 // Only show the dialog if the RegisterDialogClasses function succeeded. 169 // This is the same behaviour as MS' scrnsave.lib. 170 if (!RegisterDialogClasses(hMainInstance)) 171 return -1; 172 173 return DialogBox(hMainInstance, MAKEINTRESOURCE(DLG_SCRNSAVECONFIGURE), 174 hParent, (DLGPROC)ScreenSaverConfigureDialog); 175 } 176 177 static int LaunchScreenSaver(HWND hParent) 178 { 179 LPCTSTR lpWindowName; 180 UINT style, exstyle; 181 RECT rc; 182 MSG msg; 183 184 if (!RegisterScreenSaverClass()) 185 { 186 MessageBox(NULL, TEXT("RegisterClass() failed"), NULL, MB_ICONHAND); 187 return -1; 188 } 189 190 // A slightly different approach needs to be used when displaying in a preview window 191 if (hParent) 192 { 193 fChildPreview = TRUE; 194 lpWindowName = TEXT("Preview"); 195 196 style = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN; 197 exstyle = 0; 198 199 GetClientRect(hParent, &rc); 200 rc.left = 0; 201 rc.top = 0; 202 } 203 else 204 { 205 fChildPreview = FALSE; 206 lpWindowName = TEXT("Screen Saver"); 207 208 style = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; 209 exstyle = WS_EX_TOOLWINDOW | WS_EX_TOPMOST; 210 211 // Get the left & top side coordinates of the virtual screen 212 rc.left = GetSystemMetrics(SM_XVIRTUALSCREEN); 213 rc.top = GetSystemMetrics(SM_YVIRTUALSCREEN); 214 // Get the width and height of the virtual screen 215 rc.right = GetSystemMetrics(SM_CXVIRTUALSCREEN); 216 rc.bottom = GetSystemMetrics(SM_CYVIRTUALSCREEN); 217 } 218 219 // Create the main screen saver window 220 hMainWindow = CreateWindowEx(exstyle, CLASS_SCRNSAVE, lpWindowName, style, 221 rc.left, rc.top, rc.right, rc.bottom, 222 hParent, NULL, hMainInstance, NULL); 223 if (!hMainWindow) 224 return -1; 225 226 // Display window and start pumping messages 227 ShowWindow(hMainWindow, SW_SHOW); 228 if (!hParent) 229 SetCursor(NULL); 230 231 while (GetMessage(&msg, NULL, 0, 0)) 232 { 233 TranslateMessage(&msg); 234 DispatchMessage(&msg); 235 } 236 237 return msg.wParam; 238 } 239 240 // Screen Saver entry point 241 int APIENTRY _tWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPTSTR CmdLine, int nCmdShow) 242 { 243 LPTSTR p; 244 245 UNREFERENCED_PARAMETER(nCmdShow); 246 UNREFERENCED_PARAMETER(hPrevInst); 247 248 hMainInstance = hInst; 249 250 // Parse the arguments: 251 // -a <hwnd> (Change the password; only for Win9x, unused on WinNT) 252 // -s (Run the screensaver) 253 // -p <hwnd> (Preview) 254 // -c <hwnd> (Configure) 255 for (p = CmdLine; *p; p++) 256 { 257 switch (*p) 258 { 259 case 'S': 260 case 's': 261 // Start the screen saver 262 return LaunchScreenSaver(NULL); 263 264 case 'P': 265 case 'p': 266 { 267 HWND hParent; 268 269 while (ISSPACE(*++p)); 270 hParent = (HWND)_toulptr(p); 271 272 // Start the screen saver in preview mode 273 if (hParent && IsWindow(hParent)) 274 return LaunchScreenSaver(hParent); 275 else 276 return -1; 277 } 278 279 case 'C': 280 case 'c': 281 { 282 HWND hParent; 283 284 if (p[1] == ':') 285 hParent = (HWND)_toulptr(p + 2); 286 else 287 hParent = GetForegroundWindow(); 288 289 // Display the configuration dialog 290 if (hParent && IsWindow(hParent)) 291 return LaunchConfig(hParent); 292 else 293 return -1; 294 } 295 296 case '-': 297 case '/': 298 case ' ': 299 default: 300 break; 301 } 302 } 303 304 return LaunchConfig(NULL); 305 } 306