diff options
Diffstat (limited to 'Src/Wasabi/api/wnd/wndclass/qpaintwnd.cpp')
-rw-r--r-- | Src/Wasabi/api/wnd/wndclass/qpaintwnd.cpp | 357 |
1 files changed, 357 insertions, 0 deletions
diff --git a/Src/Wasabi/api/wnd/wndclass/qpaintwnd.cpp b/Src/Wasabi/api/wnd/wndclass/qpaintwnd.cpp new file mode 100644 index 00000000..dfdccc18 --- /dev/null +++ b/Src/Wasabi/api/wnd/wndclass/qpaintwnd.cpp @@ -0,0 +1,357 @@ +#include <precomp.h> +#include "qpaintwnd.h" +#include <tataki/canvas/bltcanvas.h> +#include "../nu/threadpool/TimerHandle.hpp" + +#define TIMER_QUICKPAINT 0x650 + +// thread context, this is here so we can avoid the windows types in quickpaintwnd.h +class QuickPaintContext +{ +public: + QuickPaintContext(QuickPaintWnd *_wnd, int timeout) + { + killswitch = 0; + wnd = _wnd; + death = CreateEvent(NULL, FALSE, FALSE, NULL); + timer_ms = timeout; + WASABI_API_THREADPOOL->AddHandle(0, timer_handle, QPThreadPoolFunc, (void *)this, 0, 0/*api_threadpool::FLAG_LONG_EXECUTION*/); + timer_handle.Wait(timer_ms); + } + + ~QuickPaintContext() + { + CloseHandle(death); + timer_handle.Close(); + } + + void Kill() + { + InterlockedExchangePointer((volatile PVOID*)&wnd, 0); + killswitch=1; + WaitForSingleObject(death, INFINITE); + } + + QuickPaintWnd *wnd; + TimerHandle timer_handle; + HANDLE death; + volatile int killswitch; + int timer_ms; + static int QPThreadPoolFunc(HANDLE h, void *user_data, intptr_t t); +}; + +int QuickPaintContext::QPThreadPoolFunc(HANDLE h, void *user_data, intptr_t t) +{ + QuickPaintContext *context = (QuickPaintContext *)user_data; + + if (context->killswitch) + { + WASABI_API_THREADPOOL->RemoveHandle(0, h); + SetEvent(context->death); + } + else + { + DWORD start = GetTickCount(); + QuickPaintWnd *wnd = 0; + InterlockedExchangePointer((volatile PVOID*)&wnd, context->wnd); + if (wnd) + { + wnd->quickPaint(); + TimerHandle timer_handle(h); + DWORD end = GetTickCount(); + if (end-start > (DWORD)context->timer_ms) + timer_handle.Wait(1); + else + timer_handle.Wait(context->timer_ms - (end - start)); + } + } + + return 0; +} + + +// ----------------------------------------------------------------------- +QuickPaintWnd::QuickPaintWnd() +{ + invalidates_required = 0; + realtime = 1; + canvas_w = -1; + canvas_h = -1; + timerset = 0; + speed = 25; + enabled = 0; + render_canvas1 = NULL; + render_canvas2 = NULL; + paint_canvas = NULL; + thread_context = 0; + + while (1) + { + svc_skinFilter *obj = sfe.getNext(); + if (!obj) break; + filters.addItem(obj); + } + invalidated = 0; +} + +// ----------------------------------------------------------------------- +QuickPaintWnd::~QuickPaintWnd() +{ + foreach(filters) + sfe.release(filters.getfor()); + endfor; + + KillThread(); + + delete render_canvas1; + delete render_canvas2; +} + +// ----------------------------------------------------------------------- +void QuickPaintWnd::setRealtime(int rt) +{ + realtime = rt; +} + +// ----------------------------------------------------------------------- +int QuickPaintWnd::getRealtime() const +{ + return realtime; +} + +// ----------------------------------------------------------------------- +void QuickPaintWnd::setSpeed(int ms) +{ + speed = ms; + if (enabled && timerset) + { + if (thread_context) + thread_context->timer_ms = ms; + // let it change the timer value on the invalidate() timer + killTimer(TIMER_QUICKPAINT); + setTimer(TIMER_QUICKPAINT, getSpeed()); + } +} + +// ----------------------------------------------------------------------- +void QuickPaintWnd::startQuickPaint() +{ + enabled = 1; + if (!isInited()) return; + CreateRenderThread(); + timerset=1; +} + +// ----------------------------------------------------------------------- +void QuickPaintWnd::stopQuickPaint() +{ + enabled = 0; + if (!isInited()) return; + KillThread(); + timerset=0; +} + +// ----------------------------------------------------------------------- +int QuickPaintWnd::isQuickPainting() +{ + return enabled; +} + +// ----------------------------------------------------------------------- +int QuickPaintWnd::getSpeed() +{ + return speed; +} + +// ----------------------------------------------------------------------- +int QuickPaintWnd::onInit() +{ + QUICKPAINTWND_PARENT::onInit(); + if (enabled) + { + ASSERT(!thread_context); + CreateRenderThread(); + timerset = 1; + } + return 1; +} + +// ----------------------------------------------------------------------- +void QuickPaintWnd::timerCallback(int id) +{ + switch (id) + { + case TIMER_QUICKPAINT: + if (invalidates_required) + { + invalidated = 1; + + if (getRealtime() && isVisible() && !isMinimized()) + cascadeRepaint(); + else + invalidate(); + + InterlockedExchange(&invalidates_required, 0); + } + //quickPaint(); + break; + default: + QUICKPAINTWND_PARENT::timerCallback(id); + } +} + +void QuickPaintWnd::SetPaintingCanvas(BltCanvas *c) +{ + InterlockedExchangePointer((volatile PVOID*)&paint_canvas, c); +} + +BltCanvas *&QuickPaintWnd::GetDrawingConvas() +{ + if (paint_canvas == render_canvas2) + return render_canvas1; + else + return render_canvas2; +} + +// ----------------------------------------------------------------------- +int QuickPaintWnd::quickPaint() +{ + int repaint=0; + + int w, h; + getQuickPaintSize(&w, &h); + + if (wantEvenAlignment()) + { + if (w & 1) w++; + if (h & 1) h++; + } + + if (w == 0 && h == 0) return 0; + + BltCanvas *&render_canvas = GetDrawingConvas(); + int newone = 0; + + if (canvas_w != w || canvas_h != h) + { + delete render_canvas1; render_canvas1=0; + delete render_canvas2; render_canvas2=0; + } + + if (!render_canvas) + { + render_canvas = new BltCanvas(w, wantNegativeHeight() ? -h : h, getOsWindowHandle()); + canvas_w = w; + canvas_h = h; + newone = 1; + } + + repaint = onQuickPaint(render_canvas, canvas_w, canvas_h, newone); + + SetPaintingCanvas(render_canvas); + if (repaint) + InterlockedIncrement(&invalidates_required); + + return repaint; +} + +// ----------------------------------------------------------------------- +void QuickPaintWnd::getQuickPaintSize(int *w, int *h) +{ + RECT r; + getClientRect(&r); + if (w) *w = r.right - r.left; + if (h) *h = r.bottom - r.top; +} + +// ----------------------------------------------------------------------- +void QuickPaintWnd::getQuickPaintSource(RECT *r) +{ + ASSERT(r != NULL); + r->left = 0; + r->right = canvas_w; + r->top = 0; + r->bottom = canvas_h; +} + +// ----------------------------------------------------------------------- +void QuickPaintWnd::getQuickPaintDest(RECT *r) +{ + ASSERT(r != NULL); + getClientRect(r); +} + +// ----------------------------------------------------------------------- +void QuickPaintWnd::onSetVisible(int show) +{ + QUICKPAINTWND_PARENT::onSetVisible(show); + if (!show) + { + if (timerset) + { + KillThread(); + timerset = 0; + } + } + else + { + if (enabled && !timerset) + { + CreateRenderThread(); + + timerset = 1; + } + } +} + +// ----------------------------------------------------------------------- +int QuickPaintWnd::onPaint(Canvas *canvas) +{ + QUICKPAINTWND_PARENT::onPaint(canvas); + + if (!enabled) return 1; + + BltCanvas *render_canvas; + InterlockedExchangePointer((volatile PVOID*)&render_canvas, paint_canvas); + if (!render_canvas) return 1; + + RECT r; + getQuickPaintDest(&r); + RECT sr; + getQuickPaintSource(&sr); + + if (invalidated && wantFilters()) + { + foreach(filters) + filters.getfor()->filterBitmap((unsigned char *)render_canvas->getBits(), canvas_w, canvas_h, 32, NULL, getFiltersGroup()); + endfor; + invalidated = 0; + } + + render_canvas->/*getSkinBitmap()->*/stretchToRectAlpha(canvas, &sr, &r, getPaintingAlpha()); + InterlockedExchange(&invalidates_required, 0); + return 1; +} + +void QuickPaintWnd::KillThread() +{ + if (thread_context) + { + killTimer(TIMER_QUICKPAINT); + thread_context->Kill(); + delete thread_context; + thread_context = 0; + } +} + +void QuickPaintWnd::CreateRenderThread() +{ + int sp = getSpeed(); + if (!thread_context) + { + thread_context = new QuickPaintContext(this, sp); + } + else + thread_context->timer_ms = sp; + setTimer(TIMER_QUICKPAINT, sp); +}
\ No newline at end of file |