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