ultimatepp/uppsrc/CtrlCore/CtrlMt.cpp
cxl bd87a04fda Draw, CtrlCore: Major refactor of Draw
git-svn-id: svn://ultimatepp.org/upp/trunk@5545 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2012-11-11 12:33:47 +00:00

234 lines
4 KiB
C++

#include "CtrlCore.h"
#define LLOG(x) // if(!IsMainThread()) DLOG((int)GetCurrentThreadId() << " " << x)
NAMESPACE_UPP
#ifdef _MULTITHREADED
static StaticMutex sGLock;
static thread__ int sGLockLevel = 0;
void EnterGMutex()
{
if(sGLockLevel++ == 0)
sGLock.Enter();
LLOG("EnterGMutex");
}
void EnterGMutex(int n)
{
if(n > 0) {
if(sGLockLevel == 0)
sGLock.Enter();
sGLockLevel += n;
}
LLOG("EnterGMutex " << n);
}
void LeaveGMutex()
{
ASSERT(sGLockLevel > 0);
if(--sGLockLevel == 0)
sGLock.Leave();
LLOG("LeaveGMutex");
}
int LeaveGMutexAll()
{
int q = sGLockLevel;
if(q) {
sGLock.Leave();
sGLockLevel = 0;
}
LLOG("LeaveGMutex all");
return q;
}
static int NonMain;
static StaticMutex NonMainLock;
void EnterGuiMutex()
{
LLOG("Thread " << IsMainThread() << " trying to lock" << ", nonmain: " << NonMain);
bool nonmain = !IsMainThread();
if(nonmain)
NonMainLock.Enter();
EnterGMutex();
if(nonmain)
NonMain++;
LLOG("Thread " << IsMainThread() << " LOCK" << ", nonmain: " << NonMain);
}
void LeaveGuiMutex()
{
LLOG("Thread " << IsMainThread() << " trying to unlock" << ", nonmain: " << NonMain);
bool nonmain = !IsMainThread();
if(nonmain)
NonMain--;
LeaveGMutex();
if(nonmain)
NonMainLock.Leave();
LLOG("Thread " << IsMainThread() << " UNLOCK" << ", nonmain: " << NonMain);
}
struct Ctrl::CallBox {
Semaphore sem;
Callback cb;
};
void Ctrl::PerformCall(Ctrl::CallBox *cbox)
{
cbox->cb();
LLOG("Sem release");
cbox->sem.Release();
}
Callback Ctrl::CtrlCall;
static Mutex CtrlCallMutex;
void WakeUpGuiThread();
bool Ctrl::DoCall()
{
LLOG("DoCall");
GuiLock __;
{
Mutex::Lock __(CtrlCallMutex);
CtrlCall();
CtrlCall.Clear();
}
LLOG("--- DoCall, nonmain: " << NonMain);
return NonMain;
}
void Ctrl::ICall(Callback cb)
{
LLOG("Ctrl::Call " << IsMainThread() << ", nonmain: " << NonMain);
if(IsMainThread())
cb();
else {
GuiLock __;
CallBox cbox;
cbox.cb = cb;
{
Mutex::Lock __(CtrlCallMutex);
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 {
GuiLock __;
CallBox cbox;
cbox.cb = cb;
UPP::PostCallback(callback1(PerformCall, &cbox));
int n = NonMain;
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::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