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