Merge from amd64-branch:
[reactos.git] / reactos / lib / sdk / 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 MS' scrnsave.lib
6 * PROGRAMMERS: Anders Norlander <anorland@hem2.passagen.se>
7 * Colin Finck <mail@colinfinck.de>
8 */
9
10 #include <windows.h>
11 #include <tchar.h>
12 #include <scrnsave.h>
13
14 // Screen Saver window class
15 #define CLASS_SCRNSAVE TEXT("WindowsScreenSaverClass")
16
17 // Globals
18 HWND hMainWindow = NULL;
19 BOOL fChildPreview = FALSE;
20 HINSTANCE hMainInstance;
21 TCHAR szName[TITLEBARNAMELEN];
22 TCHAR szAppName[APPNAMEBUFFERLEN];
23 TCHAR szIniFile[MAXFILELEN];
24 TCHAR szScreenSaver[22];
25 TCHAR szHelpFile[MAXFILELEN];
26 TCHAR szNoHelpMemory[BUFFLEN];
27 UINT MyHelpMessage;
28
29 // Local house keeping
30 static POINT pt_orig;
31
32 static int ISSPACE(TCHAR c)
33 {
34 return (c == ' ' || c == '\t');
35 }
36
37 #define ISNUM(c) ((c) >= '0' && c <= '9')
38
39 static ULONG_PTR _toulptr(const TCHAR *s)
40 {
41 ULONG_PTR res;
42 ULONG_PTR n;
43 const TCHAR *p;
44
45 for (p = s; *p; p++)
46 if (!ISNUM(*p))
47 break;
48
49 p--;
50 res = 0;
51
52 for (n = 1; p >= s; p--, n *= 10)
53 res += (*p - '0') * n;
54
55 return res;
56 }
57
58 // This function takes care of *must* do tasks, like terminating screen saver
59 static LRESULT WINAPI SysScreenSaverProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
60 {
61 switch(uMsg)
62 {
63 case WM_CREATE:
64 // Mouse is not supposed to move from this position
65 GetCursorPos(&pt_orig);
66 break;
67
68 case WM_DESTROY:
69 PostQuitMessage(0);
70 break;
71
72 case WM_SYSCOMMAND:
73 if (!fChildPreview)
74 {
75 switch (wParam)
76 {
77 case SC_CLOSE:
78 case SC_SCREENSAVE:
79 return FALSE;
80 }
81 }
82 break;
83 }
84
85 return ScreenSaverProc(hWnd, uMsg, wParam, lParam);
86 }
87
88 LRESULT WINAPI DefScreenSaverProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
89 {
90 // Don't do any special processing when in preview mode
91 if (fChildPreview)
92 return DefWindowProc(hWnd, uMsg, wParam, lParam);
93
94 switch (uMsg)
95 {
96 case WM_NCACTIVATE:
97 case WM_ACTIVATE:
98 case WM_ACTIVATEAPP:
99 if (!wParam)
100 {
101 // wParam is FALSE, so the screensaver is losing the focus.
102 PostMessage(hWnd, WM_CLOSE, 0, 0);
103 }
104 break;
105
106 case WM_MOUSEMOVE:
107 {
108 POINT pt;
109 GetCursorPos(&pt);
110 if (pt.x == pt_orig.x && pt.y == pt_orig.y)
111 break;
112
113 // Fall through
114 }
115
116 case WM_LBUTTONDOWN:
117 case WM_RBUTTONDOWN:
118 case WM_MBUTTONDOWN:
119 case WM_KEYDOWN:
120 case WM_KEYUP:
121 // Send a WM_CLOSE to close the screen saver (allows the screensaver author to do clean-up tasks)
122 PostMessage(hWnd, WM_CLOSE, 0, 0);
123 break;
124
125 case WM_SETCURSOR:
126 SetCursor(NULL);
127 return TRUE;
128 }
129
130 return DefWindowProc(hWnd, uMsg, wParam, lParam);
131 }
132
133 // Registers the screen saver window class
134 static BOOL RegisterScreenSaverClass(void)
135 {
136 WNDCLASS cls = {0,};
137
138 cls.hIcon = LoadIcon(hMainInstance, MAKEINTATOM(ID_APP));
139 cls.lpszClassName = CLASS_SCRNSAVE;
140 cls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
141 cls.hInstance = hMainInstance;
142 cls.style = CS_VREDRAW | CS_HREDRAW | CS_SAVEBITS | CS_PARENTDC;
143 cls.lpfnWndProc = (WNDPROC)SysScreenSaverProc;
144
145 return RegisterClass(&cls) != 0;
146 }
147
148 static void LaunchConfig(void)
149 {
150 // Only show the dialog if the RegisterDialogClasses function succeeded.
151 // This is the same behaviour as MS' scrnsave.lib.
152 if( RegisterDialogClasses(hMainInstance) )
153 DialogBox(hMainInstance, MAKEINTRESOURCE(DLG_SCRNSAVECONFIGURE), GetForegroundWindow(), (DLGPROC) ScreenSaverConfigureDialog);
154 }
155
156 static int LaunchScreenSaver(HWND hParent)
157 {
158 UINT style;
159 RECT rc;
160 MSG msg;
161
162 if (!RegisterScreenSaverClass())
163 {
164 MessageBox(NULL, TEXT("RegisterClass() failed"), NULL, MB_ICONHAND);
165 return 1;
166 }
167
168 // A slightly different approach needs to be used when displaying in a preview window
169 if (hParent)
170 {
171 style = WS_CHILD;
172 GetClientRect(hParent, &rc);
173 }
174 else
175 {
176 style = WS_POPUP;
177 rc.right = GetSystemMetrics(SM_CXSCREEN);
178 rc.bottom = GetSystemMetrics(SM_CYSCREEN);
179 style |= WS_VISIBLE;
180 }
181
182 // Create the main screen saver window
183 hMainWindow = CreateWindowEx(hParent ? 0 : WS_EX_TOPMOST, CLASS_SCRNSAVE,
184 TEXT("SCREENSAVER"), style,
185 0, 0, rc.right, rc.bottom, hParent, NULL,
186 hMainInstance, NULL);
187
188 if(!hMainWindow)
189 return 1;
190
191 // Display window and start pumping messages
192 ShowWindow(hMainWindow, SW_SHOW);
193 if (!hParent)
194 SetCursor(NULL);
195
196 while (GetMessage(&msg, NULL, 0, 0))
197 DispatchMessage(&msg);
198
199 return msg.wParam;
200 }
201
202 // Screen Saver entry point
203 int APIENTRY _tWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPTSTR CmdLine, int nCmdShow)
204 {
205 LPTSTR p;
206
207 hMainInstance = hInst;
208
209 // Parse the arguments
210 for (p = CmdLine; *p; p++)
211 {
212 switch (*p)
213 {
214 case 'S':
215 case 's':
216 // Start the screen saver
217 return LaunchScreenSaver(NULL);
218
219 case 'P':
220 case 'p':
221 {
222 // Start the screen saver in preview mode
223 HWND hParent;
224 fChildPreview = TRUE;
225
226 while (ISSPACE(*++p));
227 hParent = (HWND) _toulptr(p);
228
229 if (hParent && IsWindow(hParent))
230 return LaunchScreenSaver(hParent);
231 }
232 return 0;
233
234 case 'C':
235 case 'c':
236 // Display the configuration dialog
237 LaunchConfig();
238 return 0;
239
240 case '-':
241 case '/':
242 case ' ':
243 default:
244 break;
245 }
246 }
247
248 LaunchConfig();
249
250 return 0;
251 }