xref: /reactos/sdk/lib/scrnsave/scrnsave.c (revision 5bc045c0)
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