Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / sdk / lib / scrnsave / scrnsave.c
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 }