diff --git a/uppsrc/Core/Callback.h b/uppsrc/Core/Callback.h index a39296683..6a6ebbe28 100644 --- a/uppsrc/Core/Callback.h +++ b/uppsrc/Core/Callback.h @@ -30,8 +30,8 @@ struct CallbackMethodActionArg : public CallbackAction { void Execute() { (object->*method)(arg); } - CallbackMethodActionArg(OBJECT_ *object, METHOD_ method, T arg) - : object(object), method(method), arg(arg) {} + CallbackMethodActionArg(OBJECT_ *object, METHOD_ method, T arg_) + : object(object), method(method) { arg = arg_; } }; template diff --git a/uppsrc/CtrlCore/CtrlCore.h b/uppsrc/CtrlCore/CtrlCore.h index 476827d21..7443895cf 100644 --- a/uppsrc/CtrlCore/CtrlCore.h +++ b/uppsrc/CtrlCore/CtrlCore.h @@ -577,9 +577,17 @@ private: void SetInfoPart(int i, const char *txt); String GetInfoPart(int i) const; + static Callback CtrlCall; + + static bool DoCall(); + static bool PeekMsg(MSG& msg); + + // System window interface... + void WndShow0(bool b); void WndShow(bool b); + void WndSetPos0(const Rect& rect); void WndSetPos(const Rect& rect); bool IsWndOpen() const; @@ -597,23 +605,31 @@ private: void ActivateWnd(); void ClickActivateWnd(); bool SetFocus0(bool activate); + void SetWndFocus0(bool *b); bool SetWndFocus(); bool HasWndFocus() const; static void WndDestroyCaret(); + void WndCreateCaret0(const Rect& cr); void WndCreateCaret(const Rect& cr); + void WndInvalidateRect0(const Rect& r); void WndInvalidateRect(const Rect& r); + void SetWndForeground0(); void SetWndForeground(); bool IsWndForeground() const; + void WndEnable0(bool *b); bool WndEnable(bool b); Rect GetWndUpdateRect() const; Rect GetWndScreenRect() const; + void WndScrollView0(const Rect& r, int dx, int dy); void WndScrollView(const Rect& r, int dx, int dy); + void WndUpdate0(); void WndUpdate(); + void WndUpdate0r(const Rect& r); void WndUpdate(const Rect& r); void WndFree(); @@ -631,6 +647,8 @@ private: static void Csizeinit(); static void (*skin)(); + static void ICall(Callback cb); + friend void CtrlSetDefaultSkin(void (*fn1)(), void (*fn2)()); friend class DHCtrl; friend class ViewDraw; @@ -674,6 +692,8 @@ protected: Image DoMouse(int e, Point p, int zd = 0); friend void sSetCursor(Ctrl *ctrl, const Image& m); + + typedef Ctrl CLASSNAME; public: virtual void NcCreate(HWND hwnd); @@ -1235,10 +1255,10 @@ public: void PostCallback(Callback cb, int id = 0); void KillPostCallback(Callback cb, int id); - static void Call(Callback cb); - enum { TIMEID_COUNT = 1 }; + static void Call(Callback cb); + static void SetTimerGranularity(int ms); static Ctrl *GetActiveCtrl(); diff --git a/uppsrc/CtrlCore/CtrlCore.upp b/uppsrc/CtrlCore/CtrlCore.upp index 6417ee15d..e2a96074d 100644 --- a/uppsrc/CtrlCore/CtrlCore.upp +++ b/uppsrc/CtrlCore/CtrlCore.upp @@ -50,6 +50,7 @@ file X11Keys.i, MKeys.h, Frame.cpp, + CtrlMt.cpp, Ctrl.cpp, CtrlChild.cpp, CtrlPos.cpp, diff --git a/uppsrc/CtrlCore/CtrlMt.cpp b/uppsrc/CtrlCore/CtrlMt.cpp new file mode 100644 index 000000000..94b4216e0 --- /dev/null +++ b/uppsrc/CtrlCore/CtrlMt.cpp @@ -0,0 +1,192 @@ +#include "CtrlCore.h" + +#define LLOG(x) // LOG(x) + +NAMESPACE_UPP + +#ifdef _MULTITHREADED + +static int NonMain; +static StaticMutex NonMainLock; + +void EnterGuiMutex() +{ + LLOG("Thread " << IsMainThread() << " trying to lock"); + bool nonmain = !IsMainThread(); + if(nonmain) + NonMainLock.Enter(); + EnterGMutex(); + if(nonmain) + NonMain++; + LLOG("Thread " << IsMainThread() << " LOCK"); +} + +void LeaveGuiMutex() +{ + LLOG("Thread " << IsMainThread() << " trying to unlock"); + bool nonmain = !IsMainThread(); + if(nonmain) + NonMain--; + LeaveGMutex(); + if(nonmain) + NonMainLock.Leave(); + LLOG("Thread " << IsMainThread() << " UNLOCK"); +} + +struct Ctrl::CallBox { + Semaphore sem; + Callback cb; +}; + +void Ctrl::PerformCall(Ctrl::CallBox *cbox) +{ + cbox->cb(); + LLOG("Sem release"); + cbox->sem.Release(); +} + +Callback Ctrl::CtrlCall; + +void WakeUpGuiThread(); + +bool Ctrl::DoCall() +{ + LLOG("DoCall"); + CtrlCall(); + CtrlCall.Clear(); + LLOG("--- DoCall, nonmain: " << NonMain); + return NonMain; +} + +void Ctrl::ICall(Callback cb) +{ + LLOG("Ctrl::Call " << IsMainThread() << ", nonmain: " << NonMain); + if(IsMainThread()) + cb(); + else { + CallBox cbox; + cbox.cb = cb; + CtrlCall = callback1(PerformCall, &cbox); + int level = LeaveGMutexAll(); + WakeUpGuiThread(); + LLOG("Waiting for semaphore"); + if(!Thread::IsShutdownThreads()) + cbox.sem.Wait(); + EnterGMutex(level); + } + LLOG("-- Ctrl::Call " << IsMainThread()); +} + +void Ctrl::Call(Callback cb) +{ + if(IsMainThread()) + cb(); + else { + CallBox cbox; + DLOG("EventLoop 1"); + cbox.cb = cb; + DLOG("EventLoop 2"); + UPP::PostCallback(callback1(PerformCall, &cbox)); + int n = NonMain; + int nn = n; + NonMain = 0; + for(int i = 0; i < n; i++) + NonMainLock.Leave(); + int level = LeaveGMutexAll(); + WakeUpGuiThread(); + if(!Thread::IsShutdownThreads()) + cbox.sem.Wait(); + for(int i = 0; i < n; i++) + NonMainLock.Enter(); + EnterGMutex(level); + NonMain = n; + } +} + +#else + +bool Ctrl::DoCall() +{ + return false; +} + +void Ctrl::ICall(Callback cb) +{ + cb(); +} + +void Ctrl::Call(Callback cb) +{ + cb(); +} +#endif + +void Ctrl::GuiSleep(int ms) +{ + Call(callback1(&Ctrl::GuiSleep0, ms)); +} + +void Ctrl::WndDestroy() +{ + ICall(callback(this, &Ctrl::WndDestroy0)); +} + +void Ctrl::WndCreateCaret(const Rect& cr) +{ + ICall(THISBACK1(WndCreateCaret0, cr)); +} + +void Ctrl::WndShow(bool b) +{ + ICall(THISBACK1(WndShow0, b)); +} + +void Ctrl::WndUpdate() +{ + ICall(THISBACK(WndUpdate0)); +} + +void Ctrl::SetWndForeground() +{ + ICall(THISBACK(SetWndForeground0)); +} + +bool Ctrl::WndEnable(bool b) +{ + ICall(THISBACK1(WndEnable0, &b)); + return b; +} + +bool Ctrl::SetWndFocus() +{ + bool b; + ICall(THISBACK1(SetWndFocus0, &b)); + return b; +} + +void Ctrl::WndInvalidateRect(const Rect& r) +{ + ICall(THISBACK1(WndInvalidateRect0, r)); +} + +void Ctrl::WndSetPos(const Rect& rect) +{ + ICall(THISBACK1(WndSetPos0, rect)); +} + +void Ctrl::WndUpdate(const Rect& r) +{ + ICall(THISBACK1(WndUpdate0r, r)); +} + +void Ctrl::WndScrollView(const Rect& r, int dx, int dy) +{ + ICall(THISBACK3(WndScrollView0, r, dx, dy)); +} + +void Ctrl::EventLoop(Ctrl *ctrl) +{ + Call(callback1(&Ctrl::EventLoop0, ctrl)); +} + +END_UPP_NAMESPACE diff --git a/uppsrc/CtrlCore/CtrlTimer.cpp b/uppsrc/CtrlCore/CtrlTimer.cpp index 00ab7b187..8cef33fad 100644 --- a/uppsrc/CtrlCore/CtrlTimer.cpp +++ b/uppsrc/CtrlCore/CtrlTimer.cpp @@ -176,54 +176,4 @@ int Ctrl::GetExitCode() const return exitcode; } -#ifdef _MULTITHREADED -struct Ctrl::CallBox { - Semaphore sem; - Callback cb; -}; - -void Ctrl::PerformCall(Ctrl::CallBox *cbox) -{ - cbox->cb(); - cbox->sem.Release(); -} - -void WakeUpGuiThread(); - -void Ctrl::Call(Callback cb) -{ - if(IsMainThread()) - cb(); - else { - CallBox cbox; - cbox.cb = cb; - UPP::PostCallback(callback1(Ctrl::PerformCall, &cbox)); - WakeUpGuiThread(); - int level = LeaveGuiMutexAll(); - cbox.sem.Wait(); - EnterGuiMutex(level); - } -} -#else -void Ctrl::Call(Callback cb) -{ - cb(); -} -#endif - -void Ctrl::EventLoop(Ctrl *ctrl) -{ - Call(callback1(&Ctrl::EventLoop0, ctrl)); -} - -void Ctrl::WndDestroy() -{ - Call(callback(this, &Ctrl::WndDestroy0)); -} - -void Ctrl::GuiSleep(int ms) -{ - Call(callback1(&Ctrl::GuiSleep0, ms)); -} - END_UPP_NAMESPACE diff --git a/uppsrc/CtrlCore/SystemDraw.h b/uppsrc/CtrlCore/SystemDraw.h index 47737e098..23069921a 100644 --- a/uppsrc/CtrlCore/SystemDraw.h +++ b/uppsrc/CtrlCore/SystemDraw.h @@ -10,12 +10,18 @@ NAMESPACE_UPP -typedef DrawLock GuiLock; +#ifdef _MULTITHREADED +void EnterGuiMutex(); +void LeaveGuiMutex(); +#else +inline void EnterGuiMutex() {} +inline void LeaveGuiMutex() {} +#endif -inline void EnterGuiMutex() { EnterGMutex(); } -inline void EnterGuiMutex(int n) { EnterGMutex(n); } -inline void LeaveGuiMutex() { LeaveGMutex(); } -inline int LeaveGuiMutexAll() { return LeaveGMutexAll(); } +struct GuiLock { + GuiLock() { EnterGuiMutex(); } + ~GuiLock() { LeaveGuiMutex(); } +}; bool ScreenInPaletteMode(); Size GetScreenSize(); diff --git a/uppsrc/CtrlCore/TopWin32.cpp b/uppsrc/CtrlCore/TopWin32.cpp index a08afd9e6..50b85d1c2 100644 --- a/uppsrc/CtrlCore/TopWin32.cpp +++ b/uppsrc/CtrlCore/TopWin32.cpp @@ -76,7 +76,7 @@ void TopWindow::DeleteIco0() void TopWindow::DeleteIco() { - Call(THISBACK(DeleteIco0)); + ICall(THISBACK(DeleteIco0)); } void TopWindow::SyncCaption0() diff --git a/uppsrc/CtrlCore/TopWindow.cpp b/uppsrc/CtrlCore/TopWindow.cpp index 575939c0d..88c7a41fe 100644 --- a/uppsrc/CtrlCore/TopWindow.cpp +++ b/uppsrc/CtrlCore/TopWindow.cpp @@ -66,12 +66,12 @@ bool TopWindow::IsShowEnabled() const void TopWindow::SyncCaption() { - Call(THISBACK(SyncCaption0)); + ICall(THISBACK(SyncCaption0)); } void TopWindow::SyncTitle() { - Call(THISBACK(SyncTitle0)); + ICall(THISBACK(SyncTitle0)); } void TopWindow::Close() diff --git a/uppsrc/CtrlCore/Win32DnD.cpp b/uppsrc/CtrlCore/Win32DnD.cpp index 5a94be7d2..29de8f535 100644 --- a/uppsrc/CtrlCore/Win32DnD.cpp +++ b/uppsrc/CtrlCore/Win32DnD.cpp @@ -501,11 +501,11 @@ int Ctrl::DoDragAndDrop(const char *fmts, const Image& sample, dword actions, if(actions & DND_MOVE) dsrc->move = actions & DND_EXACTIMAGE ? sample : MakeDragImage(CtrlCoreImg::DndMove(), CtrlCoreImg::DndMove98(), sample); sDnDSource = this; - int level = LeaveGuiMutexAll(); + int level = LeaveGMutexAll(); HRESULT r = DoDragDrop(obj, dsrc, (actions & DND_COPY ? DROPEFFECT_COPY : 0) | (actions & DND_MOVE ? DROPEFFECT_MOVE : 0), &result); - EnterGuiMutex(level); + EnterGMutex(level); DWORD re = obj->effect; obj->Release(); dsrc->Release(); diff --git a/uppsrc/CtrlCore/Win32Wnd.cpp b/uppsrc/CtrlCore/Win32Wnd.cpp index d5ae3accf..c8b376d13 100644 --- a/uppsrc/CtrlCore/Win32Wnd.cpp +++ b/uppsrc/CtrlCore/Win32Wnd.cpp @@ -19,7 +19,7 @@ unsigned GetHashValue(const HWND& h) return (unsigned)(intptr_t)h; } -static bool PeekMsg(MSG& msg) +bool Ctrl::PeekMsg(MSG& msg) { if(!PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) return false; return IsWindowUnicode(msg.hwnd) ? PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE) @@ -28,6 +28,11 @@ static bool PeekMsg(MSG& msg) static bool sFinished; +bool IsExiting() +{ + return sFinished; +} + static BOOL CALLBACK sDumpWindow(HWND hwnd, LPARAM lParam) { String dump; dump << (IsWindowEnabled(hwnd) ? "ena" : "dis") << ' ' @@ -427,7 +432,7 @@ void Ctrl::Create(HWND parent, DWORD style, DWORD exstyle, bool savebits, int sh cr.savebits = savebits; cr.show = show; cr.dropshadow = dropshadow; - Call(callback1(this, &Ctrl::Create0, &cr)); + ICall(callback1(this, &Ctrl::Create0, &cr)); } void Ctrl::Create0(Ctrl::CreateBox *cr) @@ -684,6 +689,8 @@ bool Ctrl::IsWaitingEvent() bool Ctrl::ProcessEvent(bool *quit) { + if(DoCall()) + return false; if(EndSession()) return false; if(!GetMouseLeft() && !GetMouseRight() && !GetMouseMiddle()) @@ -756,7 +763,7 @@ void Ctrl::GuiSleep0(int ms) if(EndSession()) return; ELOG("GuiSleep 2"); - int level = LeaveGuiMutexAll(); + int level = LeaveGMutexAll(); #if !defined(flagDLL) && !defined(PLATFORM_WINCE) if(!OverwatchThread) { DWORD dummy; @@ -771,7 +778,7 @@ void Ctrl::GuiSleep0(int ms) #else MsgWaitForMultipleObjects(0, NULL, FALSE, ms, QS_ALLINPUT); #endif - EnterGuiMutex(level); + EnterGMutex(level); } void Ctrl::WndDestroyCaret() @@ -780,7 +787,7 @@ void Ctrl::WndDestroyCaret() ::DestroyCaret(); } -void Ctrl::WndCreateCaret(const Rect& cr) +void Ctrl::WndCreateCaret0(const Rect& cr) { GuiLock __; LLOG("Ctrl::WndCreateCaret(" << cr << ") in " << UPP::Name(this)); @@ -815,7 +822,7 @@ Rect Ctrl::GetWndScreenRect() const return r; } -void Ctrl::WndShow(bool b) +void Ctrl::WndShow0(bool b) { GuiLock __; HWND hwnd = GetHWND(); @@ -823,7 +830,7 @@ void Ctrl::WndShow(bool b) ::ShowWindow(hwnd, b ? SW_SHOW : SW_HIDE); } -void Ctrl::WndUpdate() +void Ctrl::WndUpdate0() { GuiLock __; HWND hwnd = GetHWND(); @@ -961,7 +968,7 @@ int Ctrl::GetKbdSpeed() #endif } -void Ctrl::SetWndForeground() +void Ctrl::SetWndForeground0() { GuiLock __; LLOG("Ctrl::SetWndForeground() in " << UPP::Name(this)); @@ -986,33 +993,29 @@ bool Ctrl::IsWndForeground() const return hwnd == fore; } -bool Ctrl::WndEnable(bool b) +void Ctrl::WndEnable0(bool *b) { GuiLock __; LLOG("Ctrl::WndEnable(" << b << ") in " << UPP::Name(this) << ", focusCtrlWnd = " << UPP::Name(focusCtrlWnd) << ", raw = " << (void *)::GetFocus()); - HWND hwnd = GetHWND(); - if(!b) { + if(*b) ReleaseCapture(); - LLOG("//Ctrl::WndEnable(" << b << ") -> true " << UPP::Name(this) << ", focusCtrlWnd = " < false " < ::SetFocus(" << (void *)hwnd << ")"); // ::SetActiveWindow(hwnd); ::SetFocus(hwnd); - return true; + *b = true; + return; } LLOG("//Ctrl::SetWndFocus() in " <>>>>>> .r1505 Size sz = m.GetSize(); int rsz = size ? 48 : 16; if(sz.cx > rsz || sz.cy > rsz) diff --git a/uppsrc/CtrlLib/LabelBase.cpp b/uppsrc/CtrlLib/LabelBase.cpp index 8f56e968e..55ee6f6ce 100644 --- a/uppsrc/CtrlLib/LabelBase.cpp +++ b/uppsrc/CtrlLib/LabelBase.cpp @@ -450,9 +450,11 @@ void DisplayPopup::Paint(Draw& w) { Rect r = GetSize(); w.DrawRect(r, SColorPaper); - display->PaintBackground(w, r, value, ink, paper, style); - r.left += margin; - display->Paint(w, r, value, ink, paper, style); + if(display) { + display->PaintBackground(w, r, value, ink, paper, style); + r.left += margin; + display->Paint(w, r, value, ink, paper, style); + } } DisplayPopup::DisplayPopup() diff --git a/uppsrc/Draw/DrawLock.cpp b/uppsrc/Draw/DrawLock.cpp index b9342ab2b..8617031fc 100644 --- a/uppsrc/Draw/DrawLock.cpp +++ b/uppsrc/Draw/DrawLock.cpp @@ -1,5 +1,7 @@ #include "Draw.h" +#define LLOG(x) + NAMESPACE_UPP #ifdef _MULTITHREADED @@ -12,6 +14,7 @@ void EnterGMutex() { if(sGLockLevel++ == 0) sGLock.Enter(); + LLOG("EnterGMutex"); } void EnterGMutex(int n) @@ -21,6 +24,7 @@ void EnterGMutex(int n) sGLock.Enter(); sGLockLevel += n; } + LLOG("EnterGMutex " << n); } void LeaveGMutex() @@ -28,6 +32,7 @@ void LeaveGMutex() ASSERT(sGLockLevel > 0); if(--sGLockLevel == 0) sGLock.Leave(); + LLOG("LeaveGMutex"); } int LeaveGMutexAll() @@ -37,6 +42,7 @@ int LeaveGMutexAll() sGLock.Leave(); sGLockLevel = 0; } + LLOG("LeaveGMutex all"); return q; } diff --git a/uppsrc/Draw/Drawing.cpp b/uppsrc/Draw/Drawing.cpp index e88c95425..8a40e36fa 100644 --- a/uppsrc/Draw/Drawing.cpp +++ b/uppsrc/Draw/Drawing.cpp @@ -635,6 +635,7 @@ void DrawingDraw::Create(Size sz, bool dots_) { drawing.Create(); size = sz; dots = dots_; + val.Clear(); LLOG("DrawingDraw::Create, sz = " << sz << ", dots = " << dots << " -> clip = " << GetClip()); }