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
ISSPACE(TCHAR c)39 static int ISSPACE(TCHAR c)
40 {
41 return (c == ' ' || c == '\t');
42 }
43
44 #define ISNUM(c) ((c) >= '0' && (c) <= '9')
45
_toulptr(const TCHAR * s)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
SysScreenSaverProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)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
DefScreenSaverProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)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
RegisterScreenSaverClass(void)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
LaunchConfig(HWND hParent)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
LaunchScreenSaver(HWND hParent)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
_tWinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPTSTR CmdLine,int nCmdShow)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