1 #include "CtrlCore.h"
2 
3 #ifdef GUI_WIN
4 
5 namespace Upp {
6 
7 #define LLOG(x)    //   DLOG(x)
8 #define LOGTIMING 0
9 
10 #ifdef _DEBUG
11 #define LOGMESSAGES 0
12 #endif
13 
14 #define ELOGW(x)   // RLOG(GetSysTime() << ": " << x) // Only activate in MT!
15 #define ELOG(x)    // RLOG(GetSysTime() << ": " << x)
16 
17 template<>
GetHashValue(const HWND & h)18 hash_t GetHashValue(const HWND& h)
19 {
20 	return (hash_t)(intptr_t)h;
21 }
22 
GetMsg(MSG & msg)23 bool Ctrl::GetMsg(MSG& msg)
24 {
25 	if(!PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) return false;
26 	return IsWindowUnicode(msg.hwnd) ? PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)
27 	                                 : PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
28 }
29 
30 static bool sFinished;
31 
IsExiting()32 bool IsExiting()
33 {
34 	return sFinished;
35 }
36 
sDumpWindow(HWND hwnd,LPARAM lParam)37 static BOOL CALLBACK sDumpWindow(HWND hwnd, LPARAM lParam) {
38 	String dump;
39 	dump << (IsWindowEnabled(hwnd) ? "ena" : "dis") << ' '
40 	     << (IsWindowVisible(hwnd) ? "vis" : "hid") << ' '
41 	     << Sprintf("owner=0x%x ", GetWindow(hwnd, GW_OWNER));
42 	Ctrl *ctrl = Ctrl::CtrlFromHWND(hwnd);
43 	if(ctrl) {
44 #ifdef _DEBUG
45 		dump << "Ctrl: " << UPP::Name(ctrl);
46 #endif
47 	}
48 	else if(!lParam)
49 		return TRUE;
50 	else
51 	{
52 #ifdef PLATFORM_WINCE
53 		wchar clsname[256], title[1024];
54 #else
55 		char clsname[256], title[1024];
56 #endif
57 		::GetClassName(hwnd, clsname, __countof(clsname));
58 		::GetWindowText(hwnd, title, __countof(title));
59 		dump << "HWND: " << Sprintf("0x%x", hwnd) << ", class = "
60 		     << clsname << ", title = " << title;
61 	}
62 	LLOG(dump);
63 	return TRUE;
64 }
65 
DumpWindowOrder(bool aliens)66 void DumpWindowOrder(bool aliens) {
67 #ifndef PLATFORM_WINCE
68 	LLOG("DumpWindowOrder" << LOG_BEGIN);
69 	EnumChildWindows(NULL, &sDumpWindow, (LPARAM)(aliens ? 1 : 0));
70 	LLOG(LOG_END << "//DumpWindowOrder");
71 #endif
72 }
73 
74 #ifndef PLATFORM_WINCE
GetMousePos()75 Point GetMousePos() {
76 	Point p;
77 	return ::GetCursorPos(p) ? p : Null;
78 	::GetCursorPos(p);
79 	return p;
80 }
81 #endif
82 
83 HCURSOR   Ctrl::hCursor;
84 HINSTANCE Ctrl::hInstance;
85 #ifndef flagDLL
86 #ifndef PLATFORM_WINCE
87 HANDLE    Ctrl::OverwatchThread;
88 HWND      Ctrl::OverwatchHWND;
89 
90 Win32Event Ctrl::OverwatchEndSession;
91 Win32Event Ctrl::ExitLoopEvent;
92 #endif
93 #endif
94 
95 bool Ctrl::endsession;
96 
EndSession()97 void Ctrl::EndSession()
98 {
99 	GuiLock __;
100 	EndSessionLoopNo = EventLoopNo;
101 	endsession = true;
102 }
103 
104 template <class U, class V>
AutoCast(U & a,V b)105 void AutoCast(U& a, V b)
106 {
107 	a = (U)b;
108 }
109 
110 #ifndef flagDLL
111 #ifndef PLATFORM_WINCE
OverwatchWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)112 LRESULT CALLBACK Ctrl::OverwatchWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
113 {
114 	if(msg == WM_USER) {
115 		ELOGW("WM_USER");
116 		PostQuitMessage(0);
117 	}
118 	if(msg == WM_QUERYENDSESSION) {
119 		static BOOL (WINAPI *ShutdownBlockReasonCreate)(HWND hWnd, LPCWSTR pwszReason);
120 		static BOOL (WINAPI *ShutdownBlockReasonDestroy)(HWND hWnd);
121 		ONCELOCK {
122 			if(HMODULE hDLL = LoadLibrary ("user32")) {
123 				AutoCast(ShutdownBlockReasonCreate, GetProcAddress(hDLL, "ShutdownBlockReasonCreate"));
124 				AutoCast(ShutdownBlockReasonDestroy, GetProcAddress(hDLL, "ShutdownBlockReasonDestroy"));
125 			}
126 		}
127 		if(ShutdownBlockReasonCreate)
128 			ShutdownBlockReasonCreate(hwnd, ~WString(t_("waiting for user response")));
129 		EndSession();
130 		ELOGW("WM_QUERYENDSESSION 1");
131 		OverwatchEndSession.Wait();
132 		if(ShutdownBlockReasonDestroy)
133 			ShutdownBlockReasonDestroy(hwnd);
134 		ELOGW("WM_QUERYENDSESSION 2");
135 		return TRUE;
136 	}
137 	if(msg == WM_ENDSESSION) {
138 		EndSession();
139 		ELOGW("WM_ENDSESSION 1");
140 		ExitLoopEvent.Set();
141 		ELOGW("WM_ENDSESSION 2");
142 	}
143 	return DefWindowProc(hwnd, msg, wParam, lParam);
144 }
145 
Win32OverwatchThread(LPVOID)146 DWORD WINAPI Ctrl::Win32OverwatchThread(LPVOID)
147 {
148     WNDCLASS  wc;
149     Zero(wc);
150 	wc.style         = CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW;
151 	wc.lpfnWndProc   = (WNDPROC)OverwatchWndProc;
152 	wc.hInstance     = hInstance;
153 	wc.hCursor       = NULL;
154 	wc.hbrBackground = NULL;
155 	wc.lpszClassName = "UPP-OVERWATCH";
156 	RegisterClass(&wc);
157 
158 	OverwatchHWND = CreateWindowEx(0, "UPP-OVERWATCH", "", WS_OVERLAPPEDWINDOW,
159 	                               -1000, -1000, 50, 50, NULL, NULL, hInstance, NULL);
160 
161 	ELOGW("OverWatch 1");
162 	ExitLoopEvent.Set();
163 	ELOGW("OverWatch 2");
164 	MSG Msg;
165 	while(GetMessage(&Msg, NULL, 0, 0) > 0) {
166         TranslateMessage(&Msg);
167 		if(IsWindowUnicode(Msg.hwnd))
168 			DispatchMessageW(&Msg);
169 		else
170 			DispatchMessage(&Msg);
171     }
172 	ELOGW("OverWatch 3");
173 	return 0;
174 }
175 #endif
176 #endif
177 
178 HWND utilityHWND = 0;
179 
180 extern VectorMap<int, ClipData>& sClipMap();
181 
182 INITBLOCK
183 {
184 	sClipMap();
185 }
186 
187 EXITBLOCK
188 {
189 	if(utilityHWND) DestroyWindow(utilityHWND);
190 }
191 
UtilityProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)192 LRESULT CALLBACK Ctrl::UtilityProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
193 {
194 	sClipMap();
195 	switch(message) {
196 	case WM_TIMER:
197 		TimerProc(msecs());
198 		AnimateCaret();
199 		break;
200 	case WM_RENDERFORMAT:
201 		RenderFormat((dword)wParam);
202 		return 0;
203 	case WM_DESTROYCLIPBOARD:
204 		DestroyClipboard();
205 		return 0;
206 	}
207 	return ::DefWindowProc(hWnd, message, wParam, lParam);
208 }
209 
210 #ifdef PLATFORM_WINCE
211 #define L_(x)  L##x
212 #else
213 #define L_(x)  x
214 #endif
215 
216 static DWORD sMainThreadId;
217 
WakeUpGuiThread()218 void WakeUpGuiThread()
219 {
220 	::PostThreadMessage(sMainThreadId, WM_NULL, 0, 0);
221 }
222 
223 void AvoidPaintingCheck__();
224 
Win32PanicMessageBox(const char * title,const char * text)225 static void Win32PanicMessageBox(const char *title, const char *text)
226 {
227 	AvoidPaintingCheck__();
228 #ifdef PLATFORM_WINCE
229 	static wchar wtext[256], wtitle[256];
230 	ToUnicode(wtext, text, strlen(text), CHARSET_DEFAULT);
231 	ToUnicode(wtitle, title, strlen(title), CHARSET_DEFAULT);
232 	MessageBox(::GetActiveWindow(), wtext, wtitle, MB_ICONSTOP | MB_OK | MB_APPLMODAL);
233 #else
234 	MessageBox(::GetActiveWindow(), text, title, MB_ICONSTOP | MB_OK | MB_APPLMODAL);
235 #endif
236 }
237 
InstallPanicBox()238 void Ctrl::InstallPanicBox()
239 {
240 	InstallPanicMessageBox(&Win32PanicMessageBox);
241 }
242 
InitWin32(HINSTANCE hInstance)243 void Ctrl::InitWin32(HINSTANCE hInstance)
244 {
245 	GuiLock __;
246 	LLOG("InitWin32");
247 
248 	InstallPanicMessageBox(&Win32PanicMessageBox);
249 //	RLOGBLOCK("Ctrl::InitWin32");
250 	sMainThreadId = GetCurrentThreadId();
251 #define ILOG(x) // RLOG(x)
252 	Ctrl::hInstance = hInstance;
253 	ILOG("RegisterClassW");
254 #ifndef PLATFORM_WINCE
255 	if(IsWinNT())
256 #endif
257 	{
258 		WNDCLASSW  wc;
259 		Zero(wc);
260 		wc.style         = CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW;
261 		wc.lpfnWndProc   = (WNDPROC)Ctrl::WndProc;
262 		wc.hInstance     = hInstance;
263 		wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
264 		wc.hbrBackground = IsWinVista() ? (HBRUSH)(COLOR_WINDOW+1) : (HBRUSH)NULL;
265 		wc.lpszClassName = L"UPP-CLASS-W";
266 		RegisterClassW(&wc);
267 		wc.style         = 0x20000|CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW;
268 		wc.lpszClassName = L"UPP-CLASS-DS-W";
269 		RegisterClassW(&wc);
270 		wc.style         = CS_SAVEBITS|CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW;
271 		wc.lpszClassName = L"UPP-CLASS-SB-W";
272 		RegisterClassW(&wc);
273 		wc.style         = 0x20000|CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW|CS_SAVEBITS;
274 		wc.lpszClassName = L"UPP-CLASS-SB-DS-W";
275 		RegisterClassW(&wc);
276 	}
277 
278 	ILOG("RegisterClassA");
279 	WNDCLASS  wc;
280 	Zero(wc);
281 	wc.style         = CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW;
282 	wc.lpfnWndProc   = (WNDPROC)Ctrl::WndProc;
283 	wc.hInstance     = hInstance;
284 	wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
285 	wc.hbrBackground = IsWinVista() ? (HBRUSH)(COLOR_WINDOW+1) : (HBRUSH)NULL;
286 	wc.lpszClassName = L_("UPP-CLASS-A");
287 	RegisterClass(&wc);
288 	if(IsWinXP()) {
289 		wc.style         = 0x20000|CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW;
290 		wc.lpszClassName = L_("UPP-CLASS-DS-A");
291 		RegisterClass(&wc);
292 	}
293 	wc.style         = CS_SAVEBITS|CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW;
294 	wc.lpszClassName = L_("UPP-CLASS-SB-A");
295 	RegisterClass(&wc);
296 	if(IsWinXP()) {
297 		wc.style         = 0x20000|CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW|CS_SAVEBITS;
298 		wc.lpszClassName = L_("UPP-CLASS-SB-DS-A");
299 		RegisterClass(&wc);
300 	}
301 	wc.style         = 0;
302 	wc.lpszClassName = L_("UPP-TIMER");
303 	wc.hCursor       = NULL;
304 	wc.lpfnWndProc   = &Ctrl::UtilityProc;
305 	RegisterClass(&wc);
306 
307 	ILOG("InitTimer");
308 	InitTimer();
309 	ILOG("SetTimer");
310 	utilityHWND = CreateWindow(L_("UPP-TIMER"), L_(""), WS_OVERLAPPED,
311 		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
312 		NULL, NULL, hInstance, NULL);
313 	SetTimer(utilityHWND, 1, 10, NULL);
314 	ILOG("Windows");
315 	Windows(); //?? TRC: what's the use of this?
316 
317 	ReSkin();
318 
319 	OleInitialize(NULL);
320 
321 /* TRC 05/11/14: moved to GuiSleep to avoid thread creation in OCX DllMain
322 	DWORD dummy;
323 	OverwatchThread = CreateThread(NULL, 0x100000, Win32OverwatchThread, NULL, 0, &dummy);
324 	ExitLoopEvent().Wait();
325 */
326 
327 // TRC 05/11/18: pSetLayeredWindowAttributes moved to GLOBAL_VAR (see below) to make OCX initialization simpler
328 
329 	Csizeinit();
330 #undef ILOG
331 
332 	if(IsWin7())
333 		GlobalBackPaint();
334 }
335 
336 typedef DWORD (WINAPI *PSLWA)(HWND, DWORD, BYTE, DWORD);
337 
SetLayeredWindowAttributes()338 static PSLWA SetLayeredWindowAttributes()
339 {
340 	static PSLWA pSet;
341 #ifndef PLATFORM_WINCE
342 	static bool inited = false;
343 	if(!inited) {
344 		inited = true;
345 		if(HMODULE hDLL = LoadLibrary ("user32"))
346 			pSet = (PSLWA) GetProcAddress(hDLL, "SetLayeredWindowAttributes");
347 	}
348 #endif
349 	return pSet;
350 }
351 
IsAlphaSupported()352 bool Ctrl::IsAlphaSupported()
353 {
354 	return SetLayeredWindowAttributes();
355 }
356 
IsCompositedGui()357 bool Ctrl::IsCompositedGui()
358 {
359 	return false;
360 }
361 
ExitWin32()362 void Ctrl::ExitWin32()
363 {
364 	RenderAllFormats();
365 
366 	TopWindow::ShutdownWindows();
367 	CloseTopCtrls();
368 
369 	OleUninitialize();
370 
371 	sFinished = true;
372 
373 	for(int i = 0; i < hotkey.GetCount(); i++)
374 		if(hotkey[i])
375 			UnregisterHotKey(NULL, i);
376 
377 	for(int i = 0; i < Windows().GetCount(); i++) {
378 		HWND hwnd = Windows().GetKey(i);
379 		if(hwnd)
380 			::DestroyWindow(hwnd);
381 	}
382 	MSG msg;
383 	while(GetMsg(msg))
384 		if(msg.message != WM_QUIT)
385 			::PostQuitMessage(0);
386 #ifndef flagDLL
387 #ifndef PLATFORM_WINCE
388 	ELOG("ExitWin32 1");
389 	OverwatchEndSession.Set();
390 	ELOG("ExitWin32 2");
391 	PostMessage(OverwatchHWND, WM_USER, 0, 0);
392 	ELOG("ExitWin32 3");
393 	LLOG("Waiting for overwatch thread to finish...");
394 	WaitForSingleObject(OverwatchThread, INFINITE);
395 	ELOG("ExitWin32 4");
396 	LLOG("...overwatch thread finished");
397 #endif
398 #endif
399 }
400 
SetTimerGranularity(int ms)401 void Ctrl::SetTimerGranularity(int ms)
402 {
403 	if(ms > 0)
404 		SetTimer(utilityHWND, 1, ms, NULL);
405 	else
406 		KillTimer(utilityHWND, 1);
407 }
408 
Windows()409 VectorMap< HWND, Ptr<Ctrl> >& Ctrl::Windows()
410 {
411 	static VectorMap< HWND, Ptr<Ctrl> > map;
412 	return map;
413 }
414 
GetTopCtrls()415 Vector<Ctrl *> Ctrl::GetTopCtrls()
416 {
417 	Vector<Ctrl *> v;
418 	VectorMap< HWND, Ptr<Ctrl> >& w = Windows();
419 	for(int i = 0; i < w.GetCount(); i++)
420 		if(w.GetKey(i) && w[i] && !w[i]->parent)
421 			v.Add(w[i]);
422 	return v;
423 }
424 
SetMouseCursor(const Image & image)425 void  Ctrl::SetMouseCursor(const Image& image)
426 {
427 	GuiLock __;
428 #ifndef PLATFORM_WINCE
429 	static Image img;
430 	if(image.GetSerialId() != img.GetSerialId()) {
431 		img = image;
432 		HCURSOR hc = SystemDraw::IconWin32(img, true);
433 		SetCursor(hc);
434 		if(hCursor)
435 			DestroyCursor(hCursor);
436 		hCursor = hc;
437 	}
438 #endif
439 }
440 
CtrlFromHWND(HWND hwnd)441 Ctrl *Ctrl::CtrlFromHWND(HWND hwnd)
442 {
443 	GuiLock __;
444 	return hwnd ? Windows().Get(hwnd, NULL) : NULL;
445 }
446 
GetOwnerHWND() const447 HWND Ctrl::GetOwnerHWND() const
448 {
449 	GuiLock __;
450 	HWND hwnd = GetHWND();
451 	if(!hwnd) return NULL;
452 	return GetWindow(hwnd, GW_OWNER);
453 }
454 
GetOwner()455 Ctrl *Ctrl::GetOwner()
456 {
457 	GuiLock __;
458 	HWND hwnd = GetOwnerHWND();
459 	return hwnd ? CtrlFromHWND(hwnd) : NULL;
460 }
461 
GetActiveCtrl()462 Ctrl *Ctrl::GetActiveCtrl()
463 {
464 	GuiLock __;
465 	if(focusCtrl)
466 		return focusCtrl->GetTopCtrl();
467 	HWND actwnd = ::GetActiveWindow();
468 	Vector<Ctrl *> top = GetTopCtrls();
469 	for(int i = 0; i < top.GetCount(); i++)
470 		if(top[i]->IsActiveX() && top[i]->GetHWND()) {
471 			LLOG("-> top[" << i << "] = " << FormatIntHex(top[i]->GetHWND()));
472 			for(HWND hwnd = top[i]->GetHWND(); hwnd; hwnd = ::GetParent(hwnd))
473 				if(hwnd == actwnd) {
474 					LLOG("-> match for " <<UPP::Name(top[i]));
475 					return top[i];
476 				}
477 		}
478 	LLOG("//Ctrl::GetActiveCtrl -> not found (NULL)");
479 	return NULL;
480 }
481 
482 UDropTarget *NewUDropTarget(Ctrl *);
483 
484 String WindowStyleAsString(dword style, dword exstyle);
485 
Create(HWND parent,DWORD style,DWORD exstyle,bool savebits,int show,bool dropshadow)486 void Ctrl::Create(HWND parent, DWORD style, DWORD exstyle, bool savebits, int show, bool dropshadow)
487 {
488 	GuiLock __;
489 	ASSERT_(IsMainThread(), "Window creation can only happen in the main thread");
490 	LLOG("Ctrl::Create(parent = " << (void *)parent << ") in " <<UPP::Name(this) << LOG_BEGIN);
491 	ASSERT(!IsChild() && !IsOpen());
492 	Rect r = GetRect();
493 	AdjustWindowRectEx(r, style, FALSE, exstyle);
494 	isopen = true;
495 	top = new Top;
496 	ASSERT(!parent || IsWindow(parent));
497 	style &= ~WS_VISIBLE;
498 	if(!IsWinXP())
499 		dropshadow = false;
500 	if(IsWinNT() && (!parent || IsWindowUnicode(parent)))
501 		top->hwnd = CreateWindowExW(exstyle,
502 		                            savebits ? dropshadow ? L"UPP-CLASS-SB-DS-W" : L"UPP-CLASS-SB-W"
503 		                                     : dropshadow ? L"UPP-CLASS-DS-W" : L"UPP-CLASS-W",
504 		                            L"", style, 0, 0, 0, 0,
505 		                            parent, NULL, hInstance, this);
506 	else
507 		top->hwnd = CreateWindowEx(exstyle,
508 		                           savebits ? dropshadow ? "UPP-CLASS-SB-DS-A" : "UPP-CLASS-SB-A"
509 		                                    : dropshadow ? "UPP-CLASS-DS-A" : "UPP-CLASS-A",
510 		                           "", style, 0, 0, 0, 0,
511 		                           parent, NULL, hInstance, this);
512 
513 	inloop = false;
514 
515 	ASSERT(top->hwnd);
516 	::MoveWindow(top->hwnd, r.left, r.top, r.Width(), r.Height(), false); // To avoid "black corners" artifact effect
517 	::ShowWindow(top->hwnd, visible ? show : SW_HIDE);
518 //	::UpdateWindow(hwnd);
519 	StateH(OPEN);
520 	LLOG(LOG_END << "//Ctrl::Create in " <<UPP::Name(this));
521 	RegisterDragDrop(top->hwnd, (LPDROPTARGET) (top->dndtgt = NewUDropTarget(this)));
522 	CancelMode();
523 	RefreshLayoutDeep();
524 }
525 
526 void ReleaseUDropTarget(UDropTarget *dt);
527 
WndFree()528 void Ctrl::WndFree()
529 {
530 	GuiLock __;
531 	if(!top) return;
532 	RevokeDragDrop(GetHWND());
533 	ReleaseUDropTarget(top->dndtgt);
534 	isopen = false;
535 	if(!top) return;
536 	HWND owner = GetWindow(top->hwnd, GW_OWNER);// CXL 31.10.2003 z DoRemove
537 	bool focus = ::GetFocus() == top->hwnd;
538 	LLOG("Ctrl::WndDestroy owner " << (void *)owner
539 	     << " focus " << focus
540 	     << " ::GetFocus() " << (void *)::GetFocus());
541 	if(owner && focus) {
542 		LLOG("Ctrl::WndFree->SetFocus " << UPP::Name(Ctrl::CtrlFromHWND(owner)));
543 		Ctrl *o = GetOwner();
544 		if(o && !o->IsEnabled()) // owner needs to be enabled, otherwise SetFocus bounces back
545 			o->Enable();
546 		::SetFocus(owner);
547 	}
548 	LLOG(LOG_END << "//Ctrl::WndFree() in " <<UPP::Name(this));
549 	delete top;
550 	top = NULL;
551 }
552 
WndDestroy()553 void Ctrl::WndDestroy()
554 {
555 	GuiLock __;
556 	if(top && top->hwnd) {
557 		HWND hwnd = top->hwnd;
558 		WndFree();
559 		::DestroyWindow(hwnd);
560 	}
561 }
562 
DoMouse(int e,Point p,int zd)563 Image Ctrl::DoMouse(int e, Point p, int zd)
564 {
565 //	LLOG("Ctrl::DoMouse(" << p << ", " << e << ")");
566 	GuiLock __;
567 	eventCtrl = this;
568 	Image img = DispatchMouse(e, p, zd);
569 	SyncCaret();
570 	return img;
571 }
572 
573 #ifdef _DEBUG
574 
575 bool Ctrl::LogMessages;
576 
577 #define x_MSG(x)       { x, #x },
578 
579 struct WinMsg {
580 	int         ID;
581 	const char *name;
582 }
583 sWinMsg[] = {
584 #include "Win32Msg.i"
585 	{0, NULL}
586 };
587 
588 #endif
589 
NcCreate(HWND hwnd)590 void Ctrl::NcCreate(HWND hwnd)
591 {
592 	GuiLock __;
593 	if(!parent)
594 		top->hwnd = hwnd;
595 }
596 
NcDestroy()597 void Ctrl::NcDestroy()
598 {
599 	GuiLock __;
600 	if(!parent)
601 		WndFree();
602 }
603 
PreprocessMessage(MSG & msg)604 bool Ctrl::PreprocessMessage(MSG& msg)
605 {
606 	return false;
607 }
608 
WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)609 LRESULT CALLBACK Ctrl::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
610 {
611 	GuiLock __;
612 	if(sFinished)
613 		return DefWindowProc(hWnd, message, wParam, lParam);
614 #ifdef PLATFORM_WINCE
615 	if(message == WM_CREATE)
616 #else
617 	if(message == WM_NCCREATE)
618 #endif
619 	{
620 		Ctrl *w = (Ctrl *)((LPCREATESTRUCT) lParam)->lpCreateParams;
621 		if(w) {
622 			w->NcCreate(hWnd);
623 			int i = Windows().Find(NULL);
624 			if(i >= 0) {
625 				Windows().SetKey(i, hWnd);
626 				Windows()[i] = w;
627 			}
628 			else
629 				Windows().Add(hWnd) = w;
630 		}
631 	}
632 	Ctrl *w = Windows().Get(hWnd, NULL);
633 #ifdef PLATFORM_WINCE
634 	if(message == WM_DESTROY)
635 #else
636 	if(message == WM_NCDESTROY)
637 #endif
638 	{
639 		if(w) w->NcDestroy();
640 		int i = Windows().Find(hWnd);
641 		if(i >= 0)
642 			Windows().SetKey(i, NULL);
643 	}
644 #if LOGMESSAGES
645 	bool logblk = false;
646 	if(message != WM_SETCURSOR && message != WM_CTLCOLORBTN && message != WM_TIMER &&
647 #ifndef PLATFORM_WINCE
648 	   message != WM_NCHITTEST  &&  message != WM_ENTERIDLE &&
649 #endif
650 	   message != WM_CTLCOLORDLG && message != WM_CTLCOLOREDIT && message != WM_CTLCOLORLISTBOX &&
651 	   message != WM_CTLCOLORMSGBOX && message != WM_CTLCOLORSCROLLBAR &&
652 	   message != WM_CTLCOLORSTATIC && message != WM_CANCELMODE &&
653 	   message != 0x0118)
654 		for(WinMsg *m = sWinMsg; m->ID; m++)
655 			if(m->ID == message) {
656 				RLOG(m->name << ' ' << UPP::Name(w) <<
657 					Sprintf(", wParam = %d (0x%x), lParam = %d (0x%x)",
658 					       wParam, wParam, lParam, lParam));
659 				VppLog() << LOG_BEGIN;
660 				logblk = true;
661 				break;
662 			}
663 #endif
664 	LRESULT l = 0;
665 	if(w && (w->GetHWND() || w->isdhctrl)) {
666 #if defined(_DEBUG) && LOGTIMING
667 			int ticks = msecs();
668 			String wname = w->Name();
669 #endif
670 			Ptr<Ctrl> pw = w;
671 			l = w->WindowProc(message, wParam, lParam);
672 			if(pw)
673 				pw->SyncMoves();
674 #if defined(_DEBUG) && LOGTIMING
675 			String msgname;
676 			for(WinMsg *m = sWinMsg; m->ID; m++)
677 				if(m->ID == message) {
678 					msgname = m->name;
679 					break;
680 				}
681 			if(IsNull(msgname))
682 				msgname = NFormat("0x%04x", (int)message);
683 			LLOG(NFormat("T+%d %s 0x%08x 0x%08x -> %s", msecs(ticks), msgname, (int)wParam, (int)lParam, wname));
684 #endif
685 	}
686 	else
687 		l = DefWindowProc(hWnd, message, wParam, lParam);
688 #if LOGMESSAGES
689 	if(logblk)
690 		VppLog() << LOG_END;
691 #endif
692 	return l;
693 }
694 
PassWindowsKey(int wParam)695 bool PassWindowsKey(int wParam)
696 {
697 	return wParam >= VK_NUMPAD0 && wParam <= VK_NUMPAD9
698 	||     wParam == VK_INSERT || wParam == VK_DELETE
699 	||     wParam == VK_HOME || wParam == VK_END
700 	||     wParam == VK_PRIOR || wParam == VK_NEXT
701 	||     wParam == VK_UP || wParam == VK_DOWN
702 	||     wParam == VK_LEFT || wParam == VK_RIGHT
703 	||     wParam == VK_CLEAR || wParam == VK_SPACE
704 	||     wParam >= 0x90; // OEM keys
705 }
706 
707 Vector<Event<> > Ctrl::hotkey;
708 
RegisterSystemHotKey(dword key,Function<void ()> cb)709 int Ctrl::RegisterSystemHotKey(dword key, Function<void ()> cb)
710 {
711 	ASSERT(key >= K_DELTA);
712 	int q = hotkey.GetCount();
713 	for(int i = 0; i < hotkey.GetCount(); i++)
714 		if(!hotkey[i]) {
715 			q = i;
716 			break;
717 		}
718 	hotkey.At(q) = Event<> () << cb;
719 	dword mod = 0;
720 	if(key & K_ALT)
721 		mod |= MOD_ALT;
722 	if(key & K_SHIFT)
723 		mod |= MOD_SHIFT;
724 	if(key & K_CTRL)
725 		mod |= MOD_CONTROL;
726 
727 	return RegisterHotKey(NULL, q, mod, key & 0xffff) ? q : -1;
728 }
729 
UnregisterSystemHotKey(int id)730 void Ctrl::UnregisterSystemHotKey(int id)
731 {
732 	if(id >= 0 && id < hotkey.GetCount()) {
733 		UnregisterHotKey(NULL, id);
734 		hotkey[id].Clear();
735 	}
736 }
737 
sProcessMSG(MSG & msg)738 void Ctrl::sProcessMSG(MSG& msg)
739 {
740 	if (msg.message == WM_HOTKEY) {
741 		if((int)msg.wParam >= 0 && (int)msg.wParam < Ctrl::hotkey.GetCount())
742 			Ctrl::hotkey[(int)msg.wParam]();
743 		return;
744 	}
745 
746 	if(!DHCtrl::PreprocessMessageAll(msg))
747 		if(msg.message != WM_SYSKEYDOWN && msg.message != WM_SYSKEYUP
748 		|| PassWindowsKey((dword)msg.wParam) || msg.wParam == VK_MENU) //17.11 Mirek - fix to get windows menu invoked on Alt+Space
749 			TranslateMessage(&msg); // 04/09/07: TRC fix to make barcode reader going better
750 
751 #if 0
752 	DDUMP(msg.hwnd);
753 		for(WinMsg *m = sWinMsg; m->ID; m++)
754 			if(m->ID == msg.message) {
755 				RLOG(m->name << ' ' <<
756 					Sprintf(", wParam = %d (0x%x), lParam = %d (0x%x)",
757 					        msg.wParam, msg.wParam, msg.lParam, msg.lParam));
758 				break;
759 			}
760 
761 	char cls[200];
762 	GetClassName(msg.hwnd, cls, 200);
763 	DDUMP(cls);
764 #endif
765 
766 	if(IsWindowUnicode(msg.hwnd))
767 		DispatchMessageW(&msg);
768 	else
769 		DispatchMessage(&msg);
770 }
771 
IsWaitingEvent()772 bool Ctrl::IsWaitingEvent()
773 {
774 	ASSERT_(IsMainThread(), "IsWaitingEvent can only run in the main thread");
775 	MSG msg;
776 	return PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
777 }
778 
ProcessEvent(bool * quit)779 bool Ctrl::ProcessEvent(bool *quit)
780 {
781 	ASSERT_(IsMainThread(), "ProcessEvent can only run in the main thread");
782 	if(!GetMouseLeft() && !GetMouseRight() && !GetMouseMiddle())
783 		ReleaseCtrlCapture();
784 	MSG msg;
785 	if(GetMsg(msg)) {
786 		if(msg.message == WM_QUIT && quit)
787 			*quit = true;
788 //		LLOG(GetSysTime() << " % " << (unsigned)msecs() % 10000 << ": sProcessMSG " << FormatIntHex(msg.message));
789 		sProcessMSG(msg);
790 //		LLOG(GetSysTime() << " % " << (unsigned)msecs() % 10000 << ": //sProcessMSG " << FormatIntHex(msg.message));
791 		DefferedFocusSync();
792 		SyncCaret();
793 		return true;
794 	}
795 	return false;
796 }
797 
SysEndLoop()798 void Ctrl::SysEndLoop()
799 {
800 }
801 
ProcessEvents(bool * quit)802 bool Ctrl::ProcessEvents(bool *quit)
803 {
804 	ASSERT_(IsMainThread(), "ProcessEvents can only run in the main thread");
805 	if(ProcessEvent(quit)) {
806 		while(ProcessEvent(quit) && (!LoopCtrl || LoopCtrl->InLoop())); // LoopCtrl-MF 071008
807 		SweepMkImageCache();
808 		return true;
809 	}
810 	SweepMkImageCache();
811 	return false;
812 }
813 
EventLoop(Ctrl * ctrl)814 void Ctrl::EventLoop(Ctrl *ctrl)
815 {
816 	GuiLock __;
817 	ASSERT_(IsMainThread(), "EventLoop can only run in the main thread");
818 	ASSERT(LoopLevel == 0 || ctrl);
819 	LoopLevel++;
820 	LLOG("Entering event loop at level " << LoopLevel << LOG_BEGIN);
821 	Ptr<Ctrl> ploop;
822 	if(ctrl) {
823 		ploop = LoopCtrl;
824 		LoopCtrl = ctrl;
825 		ctrl->inloop = true;
826 	}
827 
828 	bool quit = false;
829 	int64 loopno = ++EventLoopNo;
830 	ProcessEvents(&quit);
831 	while(loopno > EndSessionLoopNo && !quit && (ctrl ? ctrl->IsOpen() && ctrl->InLoop() : GetTopCtrls().GetCount()))
832 	{
833 //		LLOG(GetSysTime() << " % " << (unsigned)msecs() % 10000 << ": EventLoop / GuiSleep");
834 		SyncCaret();
835 		GuiSleep(1000);
836 //		LLOG(GetSysTime() << " % " << (unsigned)msecs() % 10000 << ": EventLoop / ProcessEvents");
837 		ProcessEvents(&quit);
838 //		LLOG(GetSysTime() << " % " << (unsigned)msecs() % 10000 << ": EventLoop / after ProcessEvents");
839 	}
840 
841 	if(ctrl)
842 		LoopCtrl = ploop;
843 	LoopLevel--;
844 	LLOG(LOG_END << "Leaving event loop ");
845 }
846 
GuiSleep(int ms)847 void Ctrl::GuiSleep(int ms)
848 {
849 	GuiLock __;
850 	ASSERT_(IsMainThread(), "Only the main thread can perform GuiSleep");
851 	ELOG("GuiSleep");
852 	int level = LeaveGuiMutexAll();
853 #if !defined(flagDLL) && !defined(PLATFORM_WINCE)
854 	if(!OverwatchThread) {
855 		DWORD dummy;
856 		OverwatchThread = CreateThread(NULL, 0x100000, Win32OverwatchThread, NULL, 0, &dummy);
857 		ELOG("ExitLoopEventWait 1");
858 		ExitLoopEvent.Wait();
859 	}
860 	HANDLE h[1];
861 	*h = ExitLoopEvent.GetHandle();
862 	ELOG("ExitLoopEventWait 2 " << (void *)*h);
863 	MsgWaitForMultipleObjects(1, h, FALSE, ms, QS_ALLINPUT);
864 #else
865 	MsgWaitForMultipleObjects(0, NULL, FALSE, ms, QS_ALLINPUT);
866 #endif
867 	EnterGuiMutex(level);
868 }
869 
870 #if 0
871 void Ctrl::WndDestroyCaret()
872 {
873 	DLOG("Ctrl::WndDestroyCaret()");
874 	::DestroyCaret();
875 }
876 
877 void Ctrl::WndCreateCaret(const Rect& cr)
878 {
879 	GuiLock __;
880 	DLOG("Ctrl::WndCreateCaret(" << cr << ") in " << UPP::Name(this));
881 	HWND hwnd = GetHWND();
882 	if(!hwnd) return;
883 	Rect r;
884 	::GetClientRect(hwnd, r);
885 	Point p = r.TopLeft();
886 	::ClientToScreen(hwnd, p);
887 	::CreateCaret(hwnd, NULL, cr.Width(), cr.Height());
888 	::SetCaretPos(cr.left - p.x, cr.top - p.y);
889 	::ShowCaret(hwnd);
890 }
891 #else
892 
893 int  Ctrl::WndCaretTime;
894 bool Ctrl::WndCaretVisible;
895 
AnimateCaret()896 void  Ctrl::AnimateCaret()
897 {
898 	GuiLock __;
899 	bool v = !(((msecs() - WndCaretTime) / GetCaretBlinkTime()) & 1);
900 	if(v != WndCaretVisible) {
901 		WndCaretVisible = v;
902 		RefreshCaret();
903 	}
904 }
905 
PaintCaret(SystemDraw & w)906 void Ctrl::PaintCaret(SystemDraw& w)
907 {
908 	GuiLock __;
909 	LLOG("PaintCaret " << Name() << ", caretCtrl: " << caretCtrl << ", WndCaretVisible: " << WndCaretVisible);
910 	if(this == caretCtrl && WndCaretVisible)
911 		w.DrawRect(caretx, carety, caretcx, caretcy, InvertColor);
912 }
913 
SetCaret(int x,int y,int cx,int cy)914 void Ctrl::SetCaret(int x, int y, int cx, int cy)
915 {
916 	GuiLock __;
917 	LLOG("SetCaret " << Name() << " " << RectC(x, y, cx, cy));
918 	if(this == caretCtrl)
919 		RefreshCaret();
920 	caretx = x;
921 	carety = y;
922 	caretcx = cx;
923 	caretcy = cy;
924 	if(this == caretCtrl) {
925 		WndCaretTime = msecs();
926 		RefreshCaret();
927 		AnimateCaret();
928 	}
929 }
930 
SyncCaret()931 void Ctrl::SyncCaret() {
932 	GuiLock __;
933 	LLOG("SyncCaret");
934 	if(focusCtrl != caretCtrl) {
935 		LLOG("SyncCaret DO " << Upp::Name(caretCtrl) << " -> " << Upp::Name(focusCtrl));
936 		RefreshCaret();
937 		caretCtrl = focusCtrl;
938 		RefreshCaret();
939 	}
940 }
941 #endif
942 
943 
GetWndScreenRect() const944 Rect Ctrl::GetWndScreenRect() const
945 {
946 	GuiLock __;
947 	HWND hwnd = GetHWND();
948 	if(!hwnd) return Null;
949 	Rect r;
950 	::GetWindowRect(hwnd, r);
951 	return r;
952 }
953 
WndShow(bool b)954 void Ctrl::WndShow(bool b)
955 {
956 	GuiLock __;
957 	HWND hwnd = GetHWND();
958 	if(hwnd)
959 		::ShowWindow(hwnd, b ? SW_SHOW : SW_HIDE);
960 }
961 
WndUpdate()962 void Ctrl::WndUpdate()
963 {
964 	GuiLock __;
965 	HWND hwnd = GetHWND();
966 	if(hwnd) ::UpdateWindow(hwnd);
967 }
968 
IsWndOpen() const969 bool Ctrl::IsWndOpen() const {
970 	GuiLock __;
971 	return GetHWND();
972 }
973 
SetAlpha(byte alpha)974 void Ctrl::SetAlpha(byte alpha)
975 {
976 	GuiLock __;
977 	HWND hwnd = GetHWND();
978 	if(!IsAlphaSupported() || parent || !top || !hwnd)
979 		return;
980 	if(alpha == 255) {
981 		SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) & ~0x80000);
982 		return;
983 	}
984 	SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | 0x80000);
985     SetLayeredWindowAttributes() (hwnd, 0, alpha, 2);
986 }
987 
988 #define DLLFILENAME "User32.dll"
989 #define DLIMODULE   MultiMon
990 #define DLIHEADER   <CtrlCore/MultiMon.dli>
991 #include <Core/dli.h>
992 
MonitorRectForHWND(HWND hwnd)993 Rect MonitorRectForHWND(HWND hwnd)
994 {
995 	if(hwnd && MultiMon())
996 		if(HMONITOR monitor = MultiMon().MonitorFromWindow(hwnd, 2/*MONITOR_DEFAULTTONEAREST*/)) {
997 			MONITORINFO moninfo;
998 			Zero(moninfo);
999 			moninfo.cbSize = sizeof(moninfo);
1000 			MultiMon().GetMonitorInfo(monitor, &moninfo);
1001 			return Rect(moninfo.rcWork);
1002 		}
1003 	return Ctrl::GetPrimaryWorkArea();
1004 }
1005 
GetWorkArea() const1006 Rect Ctrl::GetWorkArea() const
1007 {
1008 // return MonitorRectForHWND(GetHWND());
1009 // mst:2008-12-08, hack for better multimonitor support.
1010 	GuiLock __;
1011 	const Ctrl *topctl = GetTopCtrl();
1012 	HWND hwnd = topctl->GetHWND();
1013 	if(!hwnd && !((topctl = topctl->GetOwnerCtrl()) && (hwnd = topctl->GetHWND())))
1014 		hwnd = ::GetFocus();
1015 	return MonitorRectForHWND(hwnd);
1016 }
1017 
sMonEnumProc(HMONITOR monitor,HDC hdc,LPRECT lprcMonitor,LPARAM data)1018 static BOOL CALLBACK sMonEnumProc(HMONITOR monitor, HDC hdc, LPRECT lprcMonitor, LPARAM data)
1019 {
1020 	MONITORINFO moninfo;
1021 	Zero(moninfo);
1022 	moninfo.cbSize = sizeof(moninfo);
1023 	MultiMon().GetMonitorInfo(monitor, &moninfo);
1024 	((Array<Rect> *)data)->Add(Rect(moninfo.rcWork));
1025 	return TRUE;
1026 }
1027 
GetWorkArea(Array<Rect> & rc)1028 void Ctrl::GetWorkArea(Array<Rect>& rc)
1029 {
1030 	GuiLock __;
1031 	MultiMon().EnumDisplayMonitors(NULL, NULL, &sMonEnumProc, (LPARAM)&rc);
1032 }
1033 
GetVirtualWorkArea()1034 Rect Ctrl::GetVirtualWorkArea()
1035 {
1036 	Rect out = GetPrimaryWorkArea();
1037 	Array<Rect> rc;
1038 	GetWorkArea(rc);
1039 	for(int i = 0; i < rc.GetCount(); i++)
1040 		out |= rc[i];
1041 	return out;
1042 }
1043 
GetVirtualScreenArea()1044 Rect Ctrl::GetVirtualScreenArea()
1045 {
1046 	GuiLock __;
1047 	return RectC(GetSystemMetrics(SM_XVIRTUALSCREEN),
1048 		GetSystemMetrics(SM_YVIRTUALSCREEN),
1049 		GetSystemMetrics(SM_CXVIRTUALSCREEN),
1050 		GetSystemMetrics(SM_CYVIRTUALSCREEN));
1051 }
1052 
GetPrimaryWorkArea()1053 Rect Ctrl::GetPrimaryWorkArea()
1054 {
1055 	Rect r;
1056 	SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
1057 	LLOG("Ctrl::GetWorkArea -> " << r);
1058 	return r;
1059 }
1060 
GetPrimaryScreenArea()1061 Rect Ctrl::GetPrimaryScreenArea()
1062 {
1063 	return Size(GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
1064 }
1065 
GetKbdDelay()1066 int Ctrl::GetKbdDelay()
1067 {
1068 	GuiLock __;
1069 	int a;
1070 	SystemParametersInfo(SPI_GETKEYBOARDDELAY, 0, &a, 0);
1071 	return 250 + a * 750 / 4;
1072 }
1073 
GetKbdSpeed()1074 int Ctrl::GetKbdSpeed()
1075 {
1076 	GuiLock __;
1077 	int a;
1078 	SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &a, 0);
1079 	return 1000 / (a + 2);
1080 }
1081 
SetWndForeground()1082 void Ctrl::SetWndForeground()
1083 {
1084 	GuiLock __;
1085 	LLOG("Ctrl::SetWndForeground() in " << UPP::Name(this));
1086 	HWND hwnd = GetHWND();
1087 	if(hwnd)
1088 		::SetForegroundWindow(hwnd);
1089 }
1090 
IsWndForeground() const1091 bool Ctrl::IsWndForeground() const
1092 {
1093 	GuiLock __;
1094 	HWND hwnd = GetHWND();
1095 	if(!hwnd)
1096 		return false;
1097 	HWND fore = ::GetForegroundWindow();
1098 	LLOG("Ctrl::IsWndForeground(): hwnd = " << (void *)hwnd
1099 	     << ", fore = " << (void *)fore << " - " << UPP::Name(CtrlFromHWND(fore)));
1100 	if(IsActiveX()) {
1101 		while(hwnd && hwnd != fore && !!::GetParent(hwnd))
1102 			hwnd = ::GetParent(hwnd);
1103 	}
1104 	return hwnd == fore;
1105 }
1106 
WndEnable(bool b)1107 void Ctrl::WndEnable(bool b)
1108 {
1109 	GuiLock __;
1110 	LLOG("Ctrl::WndEnable(" << b << ") in " << UPP::Name(this) << ", focusCtrlWnd = " << UPP::Name(~focusCtrlWnd) << ", raw = " << (void *)::GetFocus());
1111 	if(b)
1112 		ReleaseCapture();
1113 	LLOG("//Ctrl::WndEnable(" << b << ") -> false " <<UPP::Name(this) << ", focusCtrlWnd = " <<UPP::Name(~focusCtrlWnd) << ", raw = " << (void *)::GetFocus());
1114 }
1115 
SetWndFocus()1116 bool Ctrl::SetWndFocus()
1117 {
1118 	GuiLock __;
1119 	LLOG("Ctrl::SetWndFocus() in " << UPP::Name(this));
1120 	HWND hwnd = GetHWND();
1121 	if(hwnd) {
1122 		LLOG("Ctrl::SetWndFocus() -> ::SetFocus(" << (void *)hwnd << ")");
1123 //		::SetActiveWindow(hwnd);
1124 		::SetFocus(hwnd);
1125 		return true;
1126 	}
1127 	LLOG("//Ctrl::SetWndFocus() in " <<UPP::Name(this) << ", active window = " << (void *)::GetActiveWindow());
1128 	return false;
1129 }
1130 
HasWndFocus() const1131 bool Ctrl::HasWndFocus() const
1132 {
1133 	GuiLock __;
1134 	HWND hwnd = GetHWND();
1135 	return hwnd && ::GetFocus() == hwnd;
1136 }
1137 
SetWndCapture()1138 bool Ctrl::SetWndCapture()
1139 {
1140 	GuiLock __;
1141 	LLOG("Ctrl::SetWndCapture() in " << UPP::Name(this));
1142 	ASSERT(IsMainThread());
1143 	HWND hwnd = GetHWND();
1144 	if(hwnd) {
1145 		::SetCapture(hwnd);
1146 		LLOG("SetCapture succeeded");
1147 		return true;
1148 	}
1149 	return false;
1150 }
1151 
ReleaseWndCapture()1152 bool Ctrl::ReleaseWndCapture()
1153 {
1154 	GuiLock __;
1155 	LLOG("Ctrl::ReleaseWndCapture() in " << UPP::Name(this));
1156 	ASSERT(IsMainThread());
1157 	HWND hwnd = GetHWND();
1158 	if(hwnd && HasWndCapture())
1159 	{
1160 		::ReleaseCapture();
1161 		LLOG("ReleaseCapture succeeded");
1162 		return true;
1163 	}
1164 	return false;
1165 }
1166 
HasWndCapture() const1167 bool Ctrl::HasWndCapture() const
1168 {
1169 	GuiLock __;
1170 	HWND hwnd = GetHWND();
1171 	return hwnd && hwnd == ::GetCapture();
1172 }
1173 
WndInvalidateRect(const Rect & r)1174 void Ctrl::WndInvalidateRect(const Rect& r)
1175 {
1176 	GuiLock __;
1177 	LLOG("WndInvalidateRect " << UPP::Name(this));
1178 	HWND hwnd = GetHWND();
1179 	if(hwnd)
1180 		::InvalidateRect(hwnd, r, false);
1181 }
1182 
WndSetPos(const Rect & rect)1183 void Ctrl::WndSetPos(const Rect& rect)
1184 {
1185 	GuiLock __;
1186 	LLOG("WndSetPos " << UPP::Name(this) << " " << rect);
1187 	HWND hwnd = GetHWND();
1188 	if(hwnd) {
1189 		Rect r = rect;
1190 		AdjustWindowRectEx(r, ::GetWindowLong(hwnd, GWL_STYLE), FALSE,
1191 		                   ::GetWindowLong(hwnd, GWL_EXSTYLE));
1192 		SetWindowPos(hwnd, NULL, r.left, r.top, r.Width(), r.Height(),
1193 		             SWP_NOACTIVATE|SWP_NOZORDER);
1194 		if(HasFocusDeep()) {
1195 			caretCtrl = NULL;
1196 			SyncCaret();
1197 		}
1198 	}
1199 	fullrefresh = false;
1200 }
1201 
WndUpdate(const Rect & r)1202 void Ctrl::WndUpdate(const Rect& r)
1203 {
1204 	GuiLock __;
1205 	LLOG("WndUpdate " << UPP::Name(this));
1206 	Ctrl *top = GetTopCtrl();
1207 	if(top->IsOpen()) {
1208 		HWND hwnd = top->GetHWND();
1209 		HDC hdc = GetDC(hwnd);
1210 		HRGN hrgn = CreateRectRgn(0, 0, 0, 0);
1211 		if(GetUpdateRgn(hwnd, hrgn, FALSE) != NULLREGION) {
1212 			SelectClipRgn(hdc, hrgn);
1213 			SystemDraw draw(hdc);
1214 			bool hcr = focusCtrl && focusCtrl->GetTopCtrl() == top &&
1215 			           caretRect.Intersects(r + top->GetRect().TopLeft());
1216 			if(hcr) ::HideCaret(hwnd);
1217 			draw.Clip(r);
1218 			top->UpdateArea(draw, r);
1219 			ValidateRect(hwnd, r);
1220 			SelectClipRgn(hdc, NULL);
1221 			if(hcr) ::ShowCaret(hwnd);
1222 		}
1223 		ReleaseDC(hwnd, hdc);
1224 		DeleteObject(hrgn);
1225 	}
1226 }
1227 
WndScrollView(const Rect & r,int dx,int dy)1228 void  Ctrl::WndScrollView(const Rect& r, int dx, int dy)
1229 {
1230 	GuiLock __;
1231 	LLOG("WndScrollView " << UPP::Name(this));
1232 	if(caretCtrl && caretCtrl->GetTopCtrl() == this) {
1233 #if WINCARET
1234 		WndDestroyCaret();
1235 #else
1236 		RefreshCaret();
1237 #endif
1238 		caretRect.Clear();
1239 	}
1240 #ifdef PLATFORM_WINCE
1241 	::ScrollWindowEx(GetHWND(), dx, dy, r, r, NULL, NULL, 0);
1242 #else
1243 	::ScrollWindow(GetHWND(), dx, dy, r, r);
1244 #endif
1245 	SyncCaret();
1246 }
1247 
PopUpHWND(HWND owner,bool savebits,bool activate,bool dropshadow,bool topmost)1248 void Ctrl::PopUpHWND(HWND owner, bool savebits, bool activate, bool dropshadow, bool topmost)
1249 {
1250 	LLOG("PopUpHWND " << UPP::Name(this) << ", owner: " << owner << ", activate: " << activate);
1251 	popup = false;
1252 	Create(owner, WS_POPUP, topmost ? WS_EX_TOPMOST : 0, savebits,
1253 	       owner || !activate ? SW_SHOWNOACTIVATE : SW_SHOW,
1254 	       dropshadow);
1255 	HWND hwnd = GetHWND();
1256 	if(hwnd) popup = true;
1257 	if(activate) SetFocus();
1258 }
1259 
PopUp(Ctrl * owner,bool savebits,bool activate,bool dropshadow,bool topmost)1260 void Ctrl::PopUp(Ctrl *owner, bool savebits, bool activate, bool dropshadow, bool topmost)
1261 {
1262 	popup = false;
1263 	Ctrl *q = owner ? owner->GetTopCtrl() : GetActiveCtrl();
1264 	PopUpHWND(q ? q->GetHWND() : NULL, savebits, activate, dropshadow, topmost);
1265 	if(top) top->owner = owner;
1266 }
1267 
GetScreenClient(HWND hwnd)1268 Rect Ctrl::GetScreenClient(HWND hwnd)
1269 {
1270 	Rect r;
1271 	::GetClientRect(hwnd, r);
1272 	Point tl = r.TopLeft();
1273 	Point br = r.BottomRight();
1274 	::ClientToScreen(hwnd, tl);
1275 	::ClientToScreen(hwnd, br);
1276 	LLOG("Ctrl::GetScreenClient: hwnd = " << FormatPtr(hwnd) << ", client = " << r
1277 	     << ", screen(tl) = " << tl << ", screen(br) = " << br);
1278 	return Rect(tl, br);
1279 }
1280 
GetDefaultWindowRect()1281 Rect Ctrl::GetDefaultWindowRect() {
1282 	HWND hwnd = ::CreateWindow("UPP-CLASS-A", "", WS_OVERLAPPED,
1283 		                       CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1284 							   NULL, NULL, NULL, NULL);
1285 	Rect sr;
1286 	if(hwnd) {
1287 		::ShowWindow(hwnd, SW_HIDE);
1288 		sr = GetScreenClient(hwnd);
1289 		::DestroyWindow(hwnd);
1290 	}
1291 	else
1292 		sr = RectC(20, 20, 500, 350);
1293 	return sr;
1294 }
1295 
TopFrameDraw(Ctrl * ctrl,const Rect & r)1296 TopFrameDraw::TopFrameDraw(Ctrl *ctrl, const Rect& r)
1297 {
1298 	EnterGuiMutex();
1299 	Ctrl *top = ctrl->GetTopCtrl();
1300 	hwnd = top->GetHWND();
1301 	ASSERT(hwnd);
1302 	Attach(GetDC(hwnd));
1303 	Clipoff(r);
1304 }
1305 
~TopFrameDraw()1306 TopFrameDraw::~TopFrameDraw()
1307 {
1308 	End();
1309 	HDC hdc = Detach();
1310 	if(hwnd && hdc)
1311 		ReleaseDC(hwnd, hdc);
1312 	LeaveGuiMutex();
1313 }
1314 
SplitCmdLine__(const char * cmd)1315 Vector<WString> SplitCmdLine__(const char *cmd)
1316 {
1317 	Vector<WString> out;
1318 	while(*cmd)
1319 		if((byte)*cmd <= ' ')
1320 			cmd++;
1321 		else if(*cmd == '\"') {
1322 			WString quoted;
1323 			while(*++cmd && (*cmd != '\"' || *++cmd == '\"'))
1324 				quoted.Cat(FromSystemCharset(String(cmd, 1)).ToWString());
1325 			out.Add(quoted);
1326 		}
1327 		else {
1328 			const char *begin = cmd;
1329 			while((byte)*cmd > ' ')
1330 				cmd++;
1331 			out.Add(String(begin, cmd).ToWString());
1332 		}
1333 	return out;
1334 }
1335 
1336 }
1337 
1338 #endif
1339