Stroika Library 3.0d25
 
Loading...
Searching...
No Matches
Windows.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#include "Stroika/Frameworks/StroikaPreComp.h"
5
8#include "Stroika/Frameworks/Led/IdleManager.h"
9
10#include "Windows.h"
11
12using namespace Stroika::Foundation;
13
14CompileTimeFlagChecker_SOURCE (Stroika::Frameworks::Led::Platform, qSupportWindowsSDKCallbacks, qSupportWindowsSDKCallbacks);
15
16namespace Stroika::Frameworks::Led::Platform {
17
18 namespace Private {
19 IdleMangerLinkerSupport::IdleMangerLinkerSupport ()
20 {
21 }
22 }
23
24 /*
25 @CLASS: IdleManagerOSImpl_Win32
26 @BASES: @'IdleManager::IdleManagerOSImpl'
27 @ACCESS: public
28 @DESCRIPTION: <p>Implemenation detail of the idle-task management system. This can generally be ignored by Led users.
29 </p>
30 */
31 class IdleManagerOSImpl_Win32 : public IdleManager::IdleManagerOSImpl {
32 public:
33 IdleManagerOSImpl_Win32 ();
34 ~IdleManagerOSImpl_Win32 ();
35
36 public:
37 virtual void StartSpendTimeCalls () override;
38 virtual void TerminateSpendTimeCalls () override;
39 virtual Foundation::Time::DurationSeconds GetSuggestedFrequency () const override;
40 virtual void SetSuggestedFrequency (Foundation::Time::DurationSeconds suggestedFrequency) override;
41
42 protected:
43 nonvirtual void OnTimer_Msg (UINT_PTR nEventID, TIMERPROC* proc);
44
45 protected:
46 nonvirtual void CheckAndCreateIdleWnd ();
47
48 public:
49 static LRESULT CALLBACK StaticWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
50
51 private:
52 enum {
53 eTimerEventID = 34252
54 }; // Magic#
55 HWND fIdleWnd;
56 Foundation::Time::DurationSeconds fSuggestedFrequency;
57 UINT_PTR fTimerID;
58 };
59
60 namespace {
61 /*
62 * Code to automatically install and remove our idle manager.
63 */
64 struct IdleMangerSetter {
65 IdleMangerSetter ()
66 {
67 IdleManager::SetIdleManagerOSImpl (&fIdleManagerOSImpl);
68 }
69 ~IdleMangerSetter ()
70 {
71 IdleManager::SetIdleManagerOSImpl (NULL);
72 }
73 IdleManagerOSImpl_Win32 fIdleManagerOSImpl;
74 };
75 struct IdleMangerSetter sIdleMangerSetter;
76 }
77
78 /*
79 ********************************************************************************
80 ******************** FunnyMSPageUpDownAdjustSelectionHelper ********************
81 ********************************************************************************
82 */
83 FunnyMSPageUpDownAdjustSelectionHelper::FunnyMSPageUpDownAdjustSelectionHelper ()
84 : fRowNum (0)
85 {
86 }
87
88 void FunnyMSPageUpDownAdjustSelectionHelper::CaptureInfo (TextInteractor& ti)
89 {
90 size_t pinPoint = ti.GetSelectionStart ();
91 ptrdiff_t rowNum = ti.CalculateRowDeltaFromCharDeltaFromTopOfWindow (long (pinPoint) - long (ti.GetMarkerPositionOfStartOfWindow ()));
92 fRowNum = ::abs (rowNum);
93 }
94
95 void FunnyMSPageUpDownAdjustSelectionHelper::CompleteAdjustment (TextInteractor& ti)
96 {
97 // Finish the crazy caret adjustments!
98 size_t totalRowsInWindow = ti.GetTotalRowsInWindow (); // not can have changed from above due to scrolling
99 Assert (totalRowsInWindow >= 1);
100 fRowNum = min (fRowNum, totalRowsInWindow - 1);
101
102 size_t newRowStart = ti.CalculateCharDeltaFromRowDeltaFromTopOfWindow (fRowNum) + ti.GetMarkerPositionOfStartOfWindow ();
103 size_t newRowEnd = ti.GetEndOfRowContainingPosition (newRowStart);
104 Assert (newRowEnd >= newRowStart);
105
106 TextImager::GoalColumnRecomputerControlContext skipRecompute (ti, true);
107
108 size_t newSelStart = ti.GetRowRelativeCharAtLoc (TextImager::Tablet_Acquirer (&ti)->CvtFromTWIPSH (ti.GetSelectionGoalColumn ()), newRowStart);
109
110 newSelStart = min (newSelStart, newRowEnd); // pin to END of row
111
112 // Ha! Finally!
113 ti.SetSelection (newSelStart, newSelStart);
114 }
115
116 /*
117 ********************************************************************************
118 **************************** SimpleWin32WndProcHelper **************************
119 ********************************************************************************
120 */
121
122 /*
123 @METHOD: SimpleWin32WndProcHelper::Create
124 @DESCRIPTION: <p></p>
125 */
126 void SimpleWin32WndProcHelper::Create (DWORD dwExStyle, LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y,
127 int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance)
128 {
129 SDKString tmpClassName;
130 if (lpClassName == NULL) {
131 tmpClassName = Characters::CString::Format (_T("LED_SimpleWin32WndProcHelper-%d-%p"), ::GetCurrentProcessId (), &StaticWndProc);
132 lpClassName = tmpClassName.c_str ();
133 {
134 static bool sRegistered = false;
135 if (not sRegistered) {
136 WNDCLASSEX wcex;
137 memset (&wcex, 0, sizeof (wcex));
138 wcex.cbSize = sizeof (WNDCLASSEX);
139 wcex.lpfnWndProc = (WNDPROC)StaticWndProc;
140 wcex.lpszClassName = lpClassName;
141 ATOM regResult = ::RegisterClassEx (&wcex);
142 if (regResult == 0) {
143 DWORD laserErr = ::GetLastError ();
144 if (laserErr == ERROR_CLASS_ALREADY_EXISTS) {
145 // Shouldn't happen - but if it does - SB OK since StaticWndProc addr is the same!
146 }
147 else {
148 Assert (false); // could be a problem?
149 }
150 }
151 sRegistered = true;
152 }
153 }
154 }
155 [[maybe_unused]] HWND hWnd =
156 ::CreateWindowEx (dwExStyle, lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, this);
157 Assert (hWnd == GetValidatedHWND ()); // already pre-set on the WM_CREATE message...
158 }
159
160 LRESULT CALLBACK SimpleWin32WndProcHelper::StaticWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
161 {
162 if (message == WM_CREATE) {
163 LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
164 AssertNotNull (lpcs);
165 SimpleWin32WndProcHelper* pThis = reinterpret_cast<SimpleWin32WndProcHelper*> (lpcs->lpCreateParams);
166 Assert (pThis->GetHWND () == NULL); // cuz not set yet...
167 pThis->SetHWND (hWnd);
168 }
169
170 SimpleWin32WndProcHelper* pThis = reinterpret_cast<SimpleWin32WndProcHelper*> (::GetWindowLongPtr (hWnd, GWLP_USERDATA));
171
172 if (pThis == NULL) {
173 /*
174 * The only time I know of where this can happen is that these messages can be passed before the WM_CREATE.
175 * Seeing this assertion isn't necesarily a bug - but its a clue something wrong maybe going on.
176 */
177 Assert (message == WM_GETMINMAXINFO or message == WM_NCCREATE or message == WM_NCCALCSIZE);
178 return ::DefWindowProc (hWnd, message, wParam, lParam);
179 }
180
181 Assert (pThis != NULL);
182 Assert (pThis->GetHWND () == hWnd);
183 return pThis->WndProc (message, wParam, lParam);
184 }
185
186 /*
187 ********************************************************************************
188 **************************** IdleManagerOSImpl_Win32 ***************************
189 ********************************************************************************
190 */
191 IdleManagerOSImpl_Win32::IdleManagerOSImpl_Win32 ()
192 : fIdleWnd (NULL)
193 , fSuggestedFrequency (0)
194 , fTimerID (0)
195 {
196 }
197
198 IdleManagerOSImpl_Win32::~IdleManagerOSImpl_Win32 ()
199 {
200 if (fIdleWnd != NULL) {
201 ::DestroyWindow (fIdleWnd);
202 }
203 }
204
205 void IdleManagerOSImpl_Win32::StartSpendTimeCalls ()
206 {
207 CheckAndCreateIdleWnd ();
208 AssertNotNull (fIdleWnd);
209 // ignore if already started
210 if (fTimerID == 0) {
211 int timeout = static_cast<int> (fSuggestedFrequency.count () * 1000); // cvt specified frequency to milliseconds
212 Verify ((fTimerID = ::SetTimer (fIdleWnd, eTimerEventID, timeout, NULL)) != 0);
213 }
214 }
215
216 void IdleManagerOSImpl_Win32::TerminateSpendTimeCalls ()
217 {
218 if (fTimerID != 0) {
219 AssertNotNull (fIdleWnd);
220 Verify (::KillTimer (fIdleWnd, eTimerEventID));
221 fTimerID = 0;
222 }
223 }
224
225 Foundation::Time::DurationSeconds IdleManagerOSImpl_Win32::GetSuggestedFrequency () const
226 {
227 return fSuggestedFrequency;
228 }
229
230 void IdleManagerOSImpl_Win32::SetSuggestedFrequency (Foundation::Time::DurationSeconds suggestedFrequency)
231 {
232 if (fSuggestedFrequency != suggestedFrequency) {
233 fSuggestedFrequency = suggestedFrequency;
234 if (fTimerID != 0) {
235 TerminateSpendTimeCalls ();
236 StartSpendTimeCalls ();
237 }
238 }
239 }
240
241 LRESULT CALLBACK IdleManagerOSImpl_Win32::StaticWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
242 {
243 if (message == WM_CREATE) {
244 LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT> (lParam);
245 AssertNotNull (lpcs);
246 IdleManagerOSImpl_Win32* pThis = reinterpret_cast<IdleManagerOSImpl_Win32*> (lpcs->lpCreateParams);
247 ::SetWindowLongPtr (hWnd, GWLP_USERDATA, reinterpret_cast<DWORD_PTR> (pThis));
248 }
249
250 IdleManagerOSImpl_Win32* pThis = reinterpret_cast<IdleManagerOSImpl_Win32*> (::GetWindowLongPtr (hWnd, GWLP_USERDATA));
251
252 if (pThis == NULL) {
253 return ::DefWindowProc (hWnd, message, wParam, lParam);
254 }
255
256 Assert (pThis != NULL);
257 switch (message) {
258 case WM_TIMER:
259 pThis->OnTimer_Msg (wParam, reinterpret_cast<TIMERPROC*> (lParam));
260 return 0;
261 }
262 return ::DefWindowProc (hWnd, message, wParam, lParam);
263 }
264
265 void IdleManagerOSImpl_Win32::OnTimer_Msg (UINT_PTR /*nEventID*/, TIMERPROC* /*proc*/)
266 {
267 /*
268 * Check if any input or paint messages pending, and if so - ignore the timer message as
269 * this isn't really IDLE time.
270 */
271 MSG msg;
272 if (::PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE | PM_QS_INPUT | PM_QS_PAINT) == 0) {
273 CallSpendTime ();
274 }
275 }
276
277 void IdleManagerOSImpl_Win32::CheckAndCreateIdleWnd ()
278 {
279 if (fIdleWnd == NULL) {
280 // Because of SPR#1549 - make sure the className depends on the ADDRESS of StaticWndProc
281 SDKString className = Characters::CString::Format (Led_SDK_TCHAROF ("Led::IdleManagerOSImpl_Win32 (%p)"), &StaticWndProc);
282 static SDKString sRegisteredClassName;
283 if (sRegisteredClassName != className) {
284 WNDCLASSEX wcex;
285 memset (&wcex, 0, sizeof (wcex));
286 wcex.cbSize = sizeof (WNDCLASSEX);
287 wcex.lpfnWndProc = (WNDPROC)StaticWndProc;
288 wcex.lpszClassName = className.c_str ();
289 ATOM regResult = ::RegisterClassEx (&wcex);
290 if (regResult == 0) {
291 DWORD x = ::GetLastError ();
292 if (x == ERROR_CLASS_ALREADY_EXISTS) {
293 // ignore - probably multiple template instantiations, or something like that. SB OK. They are all identical.
294 }
295 else {
296 Assert (false); // could be a problem?
297 }
298 }
299 sRegisteredClassName = className;
300 }
301 fIdleWnd = ::CreateWindowEx (0, className.c_str (), _T(""), 0, 0, 0, 1, 1, NULL, NULL, NULL, this);
302 }
303 }
304}
#define AssertNotNull(p)
Definition Assertions.h:336
#define Verify(c)
Definition Assertions.h:422
#define CompileTimeFlagChecker_SOURCE(NS_PREFIX, NAME, VALUE)
chrono::duration< double > DurationSeconds
chrono::duration<double> - a time span (length of time) measured in seconds, but high precision.
Definition Realtime.h:57
basic_string< SDKChar > SDKString
Definition SDKString.h:38