Merge from amd64-branch:
[reactos.git] / rosapps / applications / screensavers / starfield / screensaver.c
1 /*
2 * Copyright 2003 J Brown
3 * Copyright 2006 Eric Kohl
4 * Copyright 2007 Marc Piulachs (marc.piulachs@codexchange.net)
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 */
20
21 #include <windows.h>
22 #include <tchar.h>
23 #include "resource.h"
24
25 #define RANDOM( min, max ) ((rand() % (int)(((max)+1) - (min))) + (min))
26
27 #define MAX_LOADSTRING 100
28 #define MAX_STARS 1000
29
30 #define APPNAME _T("Starfield")
31 #define APP_TIMER 1
32 #define APP_TIMER_INTERVAL 20
33
34 #define MAX_STARS 1000
35
36 // Details of each individual star
37 typedef struct star
38 {
39 int m_nXPos, m_nYPos, m_nZPos;
40 int m_nOldX, m_nOldY;
41 } STAR;
42
43 HINSTANCE hInstance;
44 BOOL fullscreen = FALSE;
45
46 STAR *stars;
47
48 int m_nTotStars;
49 int m_nCenterX, m_nCenterY;
50
51 void DrawStarField (HDC pDC)
52 {
53 int nX, nY;
54 int i;
55 for (i = 0; i < m_nTotStars; i++)
56 {
57 // Clear last position of this star
58 SetPixel (
59 pDC,
60 stars[i].m_nOldX,
61 stars[i].m_nOldY,
62 RGB (0, 0, 0));
63
64 nX = (int)((((long)stars[i].m_nXPos << 7) / (long)stars[i].m_nZPos) + m_nCenterX);
65 nY = (int)((((long)stars[i].m_nYPos << 7) / (long)stars[i].m_nZPos) + m_nCenterY);
66
67 // Draw star
68 SetPixel (
69 pDC,
70 nX,
71 nY,
72 RGB (255, 255, 255));
73
74 // Remember current position for clearing later
75 stars[i].m_nOldX = nX;
76 stars[i].m_nOldY = nY;
77 }
78 }
79
80 BOOL SetUpStars (int nNumStars)
81 {
82 int i;
83 if (nNumStars > MAX_STARS)
84 {
85 MessageBox (0,
86 _T("Too many stars! Aborting!"),
87 _T("Error"),
88 MB_OK | MB_ICONWARNING);
89 return FALSE;
90 }
91
92 if (stars)
93 free (stars);
94
95 m_nTotStars = nNumStars;
96
97 stars = (STAR*)malloc(nNumStars * sizeof(STAR));
98
99 if (!stars)
100 {
101 MessageBox (0,
102 _T("Unable to allocate memory! Aborting!"),
103 _T("Error"),
104 MB_OK | MB_ICONWARNING);
105 return FALSE;
106 }
107
108 for (i = 0; i < m_nTotStars; i++)
109 {
110 do
111 {
112 stars[i].m_nXPos = RANDOM (-320, 320);
113 stars[i].m_nYPos = RANDOM (-200, 200);
114 stars[i].m_nZPos = i+1;
115 stars[i].m_nOldX = -1;
116 stars[i].m_nOldY = -1;
117 } while ((stars[i].m_nXPos == 0) || (stars[i].m_nYPos == 0));
118 }
119
120 return TRUE;
121 }
122
123 void MoveStarField (int nXofs, int nYofs, int nZofs)
124 {
125 int i;
126 for (i = 0; i < m_nTotStars; i++)
127 {
128 stars[i].m_nXPos += nXofs;
129 stars[i].m_nYPos += nYofs;
130 stars[i].m_nZPos += nZofs;
131
132 if (stars[i].m_nZPos > m_nTotStars)
133 stars[i].m_nZPos -= m_nTotStars;
134 if (stars[i].m_nZPos < 1)
135 stars[i].m_nZPos += m_nTotStars;
136 }
137 }
138
139 void SetDimensions (int nWidth, int nHeight)
140 {
141 m_nCenterX = nWidth / 2;
142 m_nCenterY = nHeight / 2;
143 }
144
145 LRESULT WINAPI WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
146 {
147 static POINT ptLast;
148 static POINT ptCursor;
149 static BOOL fFirstTime = TRUE;
150 static HDC pDC;
151
152 switch (msg)
153 {
154 case WM_CREATE :
155 {
156 SetTimer (
157 hwnd,
158 APP_TIMER,
159 APP_TIMER_INTERVAL,
160 NULL);
161 }
162 break;
163 case WM_PAINT :
164 {
165 PAINTSTRUCT PtStr;
166 HDC pDC = BeginPaint (hwnd, &PtStr);
167 DrawStarField (pDC);
168 EndPaint (hwnd, &PtStr);
169 return (0);
170 }
171 break;
172 case WM_TIMER :
173 {
174 if (wParam == APP_TIMER)
175 {
176 MoveStarField (0, 0, -3);
177 pDC = GetDC(hwnd);
178 DrawStarField (pDC);
179 ReleaseDC(hwnd, pDC);
180 }
181 }
182 break;
183 case WM_SIZE :
184 {
185 // Change the center point of the starfield
186 SetDimensions (
187 LOWORD(lParam),
188 HIWORD(lParam));
189 }
190 break;
191 case WM_DESTROY :
192 {
193 KillTimer (hwnd, APP_TIMER);
194 free(stars);
195 ShowCursor(TRUE);
196 PostQuitMessage (0);
197 return 0;
198 }
199 break;
200 // break out of screen-saver if any keyboard activity
201 case WM_NOTIFY:
202 case WM_SYSKEYDOWN:
203 {
204 PostMessage(hwnd, WM_CLOSE, 0, 0);
205 break;
206 }
207 // break out of screen-saver if any mouse activity
208 case WM_LBUTTONDOWN:
209 case WM_LBUTTONUP:
210 case WM_RBUTTONDOWN:
211 case WM_RBUTTONUP:
212 case WM_MBUTTONDOWN:
213 case WM_MBUTTONUP:
214 case WM_MOUSEMOVE:
215 {
216 // If we've got a parent then we must be a preview
217 if(GetParent(hwnd) != 0)
218 return 0;
219
220 if(fFirstTime)
221 {
222 GetCursorPos(&ptLast);
223 fFirstTime = FALSE;
224 }
225
226 GetCursorPos(&ptCursor);
227
228 // if the mouse has moved more than 3 pixels then exit
229 if( (abs(ptCursor.x - ptLast.x) >= 3) ||
230 (abs(ptCursor.y - ptLast.y) >= 3))
231 {
232 PostMessage(hwnd, WM_CLOSE, 0, 0);
233 }
234
235 ptLast = ptCursor;
236 return 0;
237 }
238 }
239
240 return DefWindowProc(hwnd, msg, wParam, lParam);
241 }
242
243
244 void InitSaver(HWND hwndParent)
245 {
246 WNDCLASS wc;
247 ZeroMemory(&wc, sizeof(wc));
248 wc.style = CS_HREDRAW | CS_VREDRAW;
249 wc.lpfnWndProc = WndProc;
250 wc.lpszClassName = APPNAME;
251 wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
252 RegisterClass(&wc);
253
254 if (hwndParent != 0)
255 {
256 RECT rect;
257 GetClientRect(hwndParent, &rect);
258 CreateWindow(APPNAME, APPNAME,
259 WS_VISIBLE | WS_CHILD,
260 0, 0,
261 rect.right,
262 rect.bottom,
263 hwndParent, 0,
264 hInstance, NULL);
265 fullscreen = FALSE;
266 }
267 else
268 {
269 HWND hwnd;
270 hwnd = CreateWindowEx(WS_EX_TOPMOST,
271 APPNAME,
272 APPNAME,
273 WS_VISIBLE | WS_POPUP,
274 0, 0,
275 GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
276 HWND_DESKTOP, 0,
277 hInstance, NULL);
278
279 SetWindowPos(hwnd,
280 0, 0, 0, 0, 0,
281 SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_SHOWWINDOW);
282
283 ShowCursor(FALSE);
284 fullscreen = TRUE;
285 }
286
287 SetUpStars(250);
288 }
289
290 //
291 // Look for any options Windows has passed to us:
292 //
293 // -a <hwnd> (set password)
294 // -s (screensave)
295 // -p <hwnd> (preview)
296 // -c <hwnd> (configure)
297 //
298 VOID ParseCommandLine(LPWSTR szCmdLine, UCHAR *chOption, HWND *hwndParent)
299 {
300 UCHAR ch = *szCmdLine++;
301
302 if(ch == '-' || ch == '/')
303 ch = *szCmdLine++;
304
305 if(ch >= 'A' && ch <= 'Z')
306 ch += 'a' - 'A'; //convert to lower case
307
308 *chOption = ch;
309 ch = *szCmdLine++;
310
311 if(ch == ':')
312 ch = *szCmdLine++;
313
314 while(ch == ' ' || ch == '\t')
315 ch = *szCmdLine++;
316
317 if(isdigit(ch))
318 {
319 unsigned int i = _wtoi(szCmdLine - 1);
320 *hwndParent = (HWND)i;
321 }
322 else
323 *hwndParent = NULL;
324 }
325
326 void Configure(void)
327 {
328 TCHAR szTitle[256];
329 TCHAR szText[256];
330
331 LoadString(hInstance,
332 IDS_TITLE,
333 szTitle,
334 256);
335
336 LoadString(hInstance,
337 IDS_TEXT,
338 szText,
339 256);
340
341 MessageBox(0,
342 szText,
343 szTitle,
344 MB_OK | MB_ICONWARNING);
345 }
346
347 int CALLBACK wWinMain (HINSTANCE hInst,
348 HINSTANCE hPrev,
349 LPWSTR lpCmdLine,
350 int iCmdShow)
351 {
352 HWND hwndParent;
353 UINT nPreviousState;
354 UCHAR chOption;
355 MSG Message;
356
357 hInstance = hInst;
358
359 ParseCommandLine(lpCmdLine, &chOption, &hwndParent);
360
361 SystemParametersInfo(SPI_SETSCREENSAVERRUNNING, TRUE, &nPreviousState, 0);
362
363 switch (chOption)
364 {
365 case 's':
366 InitSaver(0);
367 break;
368
369 case 'p':
370 InitSaver(hwndParent);
371 break;
372
373 case 'c':
374 default:
375 Configure();
376 return 0;
377 }
378
379 while (GetMessage(&Message, 0, 0, 0))
380 DispatchMessage(&Message);
381
382 SystemParametersInfo(SPI_SETSCREENSAVERRUNNING, FALSE, &nPreviousState, 0);
383
384 return Message.wParam;
385 }