-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapp.cpccScreenSaveLibWin_OsInterface.cpp
381 lines (303 loc) · 12.2 KB
/
app.cpccScreenSaveLibWin_OsInterface.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
/* *****************************************
* File: app.cpccScreenSaveLibWin_OsInterface.cpp
* Purpose: Portable (cross-platform), light-weight, screensaver helper class
* *****************************************
* Library: Cross Platform C++ Classes (cpcc)
* Copyright: 2014 StarMessage software.
* License: Free for opensource projects.
* Commercial license exists for closed source projects.
* Web: http://www.StarMessageSoftware.com/cpcclibrary
* Download: https://github.com/starmessage/cpcc
* https://code.google.com/p/cpcc/
* email: sales -at- starmessage.info
* *****************************************
*/
//////////////////////////////////////////
//
// engine configuration
//
#define USE_WM_PAINT 1
#define FramesPerSec 25
//
//////////////////////////////////////////
#include "io.cpccLog.h"
#define _WINSOCKAPI_ // stops windows.h including winsock.h
#pragma warning( push )
#pragma warning( disable : 4005 )
#include <windows.h>
#pragma warning( pop )
#include <ScrnSave.h>
#include <commctrl.h>
#include "app.cpccScreenSaverInterface.h"
#include "app.cpccApp.h"
#include "core.cpccOS.h"
#include "core.cpccTryAndCatch.h"
#include "core.cpccStringUtil.h"
/* Handling Screen Savers
http://msdn.microsoft.com/en-us/library/cc144066%28v=vs.85%29.aspx
*/
/* command line arguments:
ScreenSaver - Show the Settings dialog box.
ScreenSaver /c - Show the Settings dialog box, modal to the foreground window.
ScreenSaver /c <HWND> - Show the Settings dialog box, as child to the HWND window.
ScreenSaver /p <HWND> - Preview Screen Saver as child of window <HWND>.
ScreenSaver /s - Run the Screen Saver.
ScreenSaver /sm - emulate multi-monitor
Multiple monitors:
1) if you've only got a single monitor, you can still test multi-monitor support with "fake" monitors
by running your saver with argument
mysaver.scr /sm // test multi-monitor
2) Example of two monitors, where the main monitor A is 1920 x 1080
the 2nd monitor 1280x1024, is placed on the left of the main monitor
the OS passes a single window handle to cover the merged area of both monitors.
Window rect: TopLeft:-74,-1280 screen width:3200, height:1154
Monitor 0: Left 0, top 0, right 1920, bottom 1080
Monitor 1: Left -1280, top -74, right 0, bottom 950
These are cases where the top left is not at 0,0
*/
#pragma comment(lib, "comctl32.lib")
#ifdef UNICODE
#pragma comment(lib, "ScrnSavw.lib")
#else
#pragma comment(lib, "ScrnSave.lib")
// the windows SDK 6.0A (comes with vs2008) creates an error under XP: changewindowmessagefilter user32.dll
// SDK 7.0 is OK
#endif
// If using Dev-C++ in the pragma comment change 'scrnsave.lib' to 'libscrnsave.a'
/*
http://msdn.microsoft.com/en-us/library/windows/desktop/bb762098%28v=vs.85%29.aspx
The ScreenSaverProc function must be exported by including it in the EXPORTS statement in the application's module-definition (.def) file.
------------------------------
When exporting this function in the module definition (.def) file you must consider
that there are two of them: the ANSI and the Unicode version, so you must export
either ScreenSaverProcA or ScreenSaverProcW depending on whether you are #defining UNICODE or not.
Also, it is unclear why exporting is necessary: without exporting it works anyway.
------------------------------
This is how it is defined by microsoft:
#ifdef UNICODE
LRESULT WINAPI ScreenSaverProcW (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
# define ScreenSaverProc ScreenSaverProcW
#else
LRESULT WINAPI ScreenSaverProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
#endif
*/
LRESULT WINAPI ScreenSaverProc(HWND hwnd, UINT wMessage, WPARAM wParam, LPARAM lParam)
{ // http://www.cityintherain.com/howtoscr.html
static UINT_PTR uTimer=NULL; /* timer identifier */
static bool isDrawing=false;
static cpccScreenSaverInterface* screensaverPtr=NULL;
static HWND hWndDebugPreview = 0;
switch(wMessage)
{
case WM_CREATE: // Set a window timer for the screen saver window.
// Perform any other required initialization.
infoLog().add(_T("ScreenSaverProc() received WM_CREATE"));
/* to run the screensaver under the notepad's window:
UN-comment the line that assigns a value to hWndDebugPreview
open notepad, run the screensaver normally, open the log file and get the notepad's HWND
run:
myscreensaver.scr /p <HWND_number_from_log>
*/
#ifdef _DEBUG
hWndDebugPreview = cpccOS::getWindowHandleOfProgram(_T("Notepad"));
#endif
if (hWndDebugPreview)
infoLog().addf(_T("notepad window handle: %i"), hWndDebugPreview);
if (!screensaverPtr)
{
screensaverPtr = cpccScreenSaverFactory::createScreenSaver();
}
if (screensaverPtr)
{
static bool screensaverWindowInitialised = false;
// 2019-10-28: deleted as it was not needed by anyone
// screensaverPtr->m_framesPerSec = FramesPerSec;
if (!screensaverWindowInitialised)
{
int monitorID = 0;
cpccApp app;
cpcc_stringList args;
app.getArgcArgv(args);
if (args.size() > 1)
monitorID = (args[1] == _T("/p")) ? -1 : 0;
CPCC_TRY_AND_CATCH(screensaverPtr->initWithWindowHandle(hwnd, monitorID, 1), "exception caught: screensaverPtr->initWithWindowHandle()");
screensaverWindowInitialised = true;
}
}
// Last job: Set the timer
uTimer = SetTimer(hwnd, 1, 1000/FramesPerSec, NULL);
return 0;
case WM_ERASEBKGND:
{
logFunctionLife _tmpLog(_T("WM_ERASEBKGND"));
/*
// http://msdn.microsoft.com/en-us/library/cc144066%28v=vs.85%29.aspx#Using_the_Screen_Sav
// The WM_ERASEBKGND message is issued before the WM_TIMER message, allowing the screen saver to paint the background as appropriate.
hdc = GetDC(hwnd);
GetClientRect (hwnd, &rc);
FillRect (hdc, &rc, GetStockObject(BLACK_BRUSH));
ReleaseDC(hwnd,hdc);
break;
In the preview window, the WM_ERASEBKGND does not come when the screensaver is starting.
Only WM_CREATE is received.
In normal operation (desktop window) the WM_ERASEBKGND comes after the WM_CREATE
*/
// About WM_ERASEBKGND: wParam holds the HDC;
// erases the background in the case of password protected running
// when the user cancels the password entry dialog.
if (screensaverPtr)
screensaverPtr->backgroundWasInvalidatedByOS();
/*
// the typical erase background is:
{ RECT tmpRect;
GetClientRect(hwnd, &tmpRect);
FillRect((HDC) wParam, &tmpRect, (HBRUSH) GetStockObject(BLACK_BRUSH));
}
*/
//break;
return 1L; //An application should return nonzero (1L) if it erases the background
}
case WM_CLOSE: // An application can prompt the user for confirmation,
// prior to destroying a window, by processing the
// WM_CLOSE message and calling the DestroyWindow function
// only if the user confirms the choice.
// todo: na paei sto WM_DESTROY
infoLog().add(_T("ScreenSaverProc() received WM_CLOSE"));
if (uTimer)
KillTimer(hwnd, uTimer);
uTimer = NULL;
// wait for one extra tick so that any pending timer event is fired before the clean up of the screensaver classes
Sleep(1000 / FramesPerSec);
break;
case WM_PAINT:
//ns_cmiLog::cmiQLog().put() << "WM_PAINT";
#if (USE_WM_PAINT)
isDrawing = true;
// https://docs.microsoft.com/en-us/windows/win32/learnwin32/painting-the-window
PAINTSTRUCT ps;
BeginPaint(hwnd,&ps);
if (screensaverPtr)
{
screensaverPtr->drawOneFrame();
screensaverPtr->flushOneFrame();
}
EndPaint(hwnd,&ps);
isDrawing = false;
#endif
//ns_cmiLog::cmiQLog().put() << "WM_PAINT exiting";
break;
case WM_TIMER:
// if a tick from a different timer arrives, ignore it.
if (wParam!=uTimer)
return 1;
//infoLog().add("ScreenSaverProc() received WM_TIMER");
if (isDrawing)
return 0;
if (screensaverPtr)
{
static const float animatePeriod_inSec = 1.0f / FramesPerSec;
screensaverPtr->animateOneFrame(animatePeriod_inSec);
#if (USE_WM_PAINT)
// ask windows for a redraw
RECT tmpRect;
GetClientRect(hwnd, &tmpRect);
InvalidateRect(hwnd, &tmpRect, false);
#else
isDrawing = true;
screensaverPtr->drawOneFrame();
screensaverPtr->flushOneFrame();
isDrawing = false;
#endif
}
return 0l;
case WM_DESTROY:
// Destroy the timer(s) created when the application processed the WM_CREATE message.
// Perform any additional required cleanup.
infoLog().add(_T("ScreenSaverProc() received WM_DESTROY"));
if (screensaverPtr)
{
screensaverPtr->shutDown();
delete(screensaverPtr);
screensaverPtr=NULL;
}
// infoLog().add(cpccLogClosingStamp);
// PostQuitMessage(0);
// isos edo thelei break gia na kalestei i DefScreenSaverProc() na kanei to sosto cleanup
break; //return 0l;
case WM_MOUSEMOVE: // mouse trap for the first 3 seconds
//if (Snoozed) break; // this rule does not apply when snoozed.
// gia na mi kleinei o screensaver amesos apo tin arxi
//if (GlobalTime < 4 * 1000/ 60 ) return 0; // 60 is a proximation of RealTickTime
break;
/* case WM_ACTIVATEAPP: if( wParam ) break; */
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_SYSKEYDOWN:
case WM_KEYDOWN: // if the termination of the saver is because of KEYDOWN....
//if (!Snoozed) TimeoutCorrection.Stop();
break;
}
return DefScreenSaverProc(hwnd, wMessage, wParam, lParam);
}
BOOL WINAPI RegisterDialogClasses( HANDLE /* hInst */ )
{
return true;
}
BOOL WINAPI ScreenSaverConfigureDialog (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
/*
http://msdn.microsoft.com/en-us/library/bb762097%28v=vs.85%29.aspx
http://msdn.microsoft.com/en-us/library/cc144066%28v=vs.85%29.aspx
If the function successfully processes the message, it should return TRUE.
If not, it should return FALSE
The ScreenSaverConfigureDialog function must be exported by including it
in the EXPORTS statement in the application's module-definition (.def) file.
Prepei na yparxei ena dialog template me to parakato ID
(mesa sto resource.h)
#define DLG_SCRNSAVECONFIGURE 2003
*/
//static cpccScreenSaverInterface* screensaverPtr=NULL;
cpccScreenSaverInterface* screensaverPtr = NULL;
switch(message)
{
case WM_INITDIALOG:
infoLog().add(_T("ScreenSaverConfigureDialog received WM_INITDIALOG"));
/* In response to a WM_INITDIALOG message,
ScreenSaverConfigureDialog should return FALSE if it calls
the SetFocus function to set the keyboard focus to one of
the controls in the dialog box.
Otherwise, the function should return TRUE, in which case the
system sets the keyboard focus to the first control in the
dialog box that can be given the focus. */
//MessageBox(NULL,"WM_INITDIALOG",NULL,NULL);
/*
if (!screensaverPtr)
{
screensaverPtr = cpccScreenSaverFactory::createScreenSaver();
}
*/
screensaverPtr = cpccScreenSaverFactory::createScreenSaver();
if (screensaverPtr)
if (screensaverPtr->hasConfigureSheet())
screensaverPtr->showConfigureSheet(hDlg);
delete(screensaverPtr);
PostMessage(hDlg,WM_COMMAND, IDOK, NULL);
return TRUE;
case WM_DESTROY:
// Clean up window-specific data objects.
// infoLog().add(cpccLogClosingStamp);
return 0;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDOK:
EndDialog(hDlg, LOWORD(wParam) == IDOK);
return TRUE;
case IDCANCEL: // common ending for OK and CANCEL
EndDialog(hDlg, LOWORD(wParam) == IDOK);
return TRUE;
}
}
return TRUE;
}