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