qpaintwnd.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. #include <precomp.h>
  2. #include "qpaintwnd.h"
  3. #include <tataki/canvas/bltcanvas.h>
  4. #include "../nu/threadpool/TimerHandle.hpp"
  5. #define TIMER_QUICKPAINT 0x650
  6. // thread context, this is here so we can avoid the windows types in quickpaintwnd.h
  7. class QuickPaintContext
  8. {
  9. public:
  10. QuickPaintContext(QuickPaintWnd *_wnd, int timeout)
  11. {
  12. killswitch = 0;
  13. wnd = _wnd;
  14. death = CreateEvent(NULL, FALSE, FALSE, NULL);
  15. timer_ms = timeout;
  16. WASABI_API_THREADPOOL->AddHandle(0, timer_handle, QPThreadPoolFunc, (void *)this, 0, 0/*api_threadpool::FLAG_LONG_EXECUTION*/);
  17. timer_handle.Wait(timer_ms);
  18. }
  19. ~QuickPaintContext()
  20. {
  21. CloseHandle(death);
  22. timer_handle.Close();
  23. }
  24. void Kill()
  25. {
  26. InterlockedExchangePointer((volatile PVOID*)&wnd, 0);
  27. killswitch=1;
  28. WaitForSingleObject(death, INFINITE);
  29. }
  30. QuickPaintWnd *wnd;
  31. TimerHandle timer_handle;
  32. HANDLE death;
  33. volatile int killswitch;
  34. int timer_ms;
  35. static int QPThreadPoolFunc(HANDLE h, void *user_data, intptr_t t);
  36. };
  37. int QuickPaintContext::QPThreadPoolFunc(HANDLE h, void *user_data, intptr_t t)
  38. {
  39. QuickPaintContext *context = (QuickPaintContext *)user_data;
  40. if (context->killswitch)
  41. {
  42. WASABI_API_THREADPOOL->RemoveHandle(0, h);
  43. SetEvent(context->death);
  44. }
  45. else
  46. {
  47. DWORD start = GetTickCount();
  48. QuickPaintWnd *wnd = 0;
  49. InterlockedExchangePointer((volatile PVOID*)&wnd, context->wnd);
  50. if (wnd)
  51. {
  52. wnd->quickPaint();
  53. TimerHandle timer_handle(h);
  54. DWORD end = GetTickCount();
  55. if (end-start > (DWORD)context->timer_ms)
  56. timer_handle.Wait(1);
  57. else
  58. timer_handle.Wait(context->timer_ms - (end - start));
  59. }
  60. }
  61. return 0;
  62. }
  63. // -----------------------------------------------------------------------
  64. QuickPaintWnd::QuickPaintWnd()
  65. {
  66. invalidates_required = 0;
  67. realtime = 1;
  68. canvas_w = -1;
  69. canvas_h = -1;
  70. timerset = 0;
  71. speed = 25;
  72. enabled = 0;
  73. render_canvas1 = NULL;
  74. render_canvas2 = NULL;
  75. paint_canvas = NULL;
  76. thread_context = 0;
  77. while (1)
  78. {
  79. svc_skinFilter *obj = sfe.getNext();
  80. if (!obj) break;
  81. filters.addItem(obj);
  82. }
  83. invalidated = 0;
  84. }
  85. // -----------------------------------------------------------------------
  86. QuickPaintWnd::~QuickPaintWnd()
  87. {
  88. foreach(filters)
  89. sfe.release(filters.getfor());
  90. endfor;
  91. KillThread();
  92. delete render_canvas1;
  93. delete render_canvas2;
  94. }
  95. // -----------------------------------------------------------------------
  96. void QuickPaintWnd::setRealtime(int rt)
  97. {
  98. realtime = rt;
  99. }
  100. // -----------------------------------------------------------------------
  101. int QuickPaintWnd::getRealtime() const
  102. {
  103. return realtime;
  104. }
  105. // -----------------------------------------------------------------------
  106. void QuickPaintWnd::setSpeed(int ms)
  107. {
  108. speed = ms;
  109. if (enabled && timerset)
  110. {
  111. if (thread_context)
  112. thread_context->timer_ms = ms;
  113. // let it change the timer value on the invalidate() timer
  114. killTimer(TIMER_QUICKPAINT);
  115. setTimer(TIMER_QUICKPAINT, getSpeed());
  116. }
  117. }
  118. // -----------------------------------------------------------------------
  119. void QuickPaintWnd::startQuickPaint()
  120. {
  121. enabled = 1;
  122. if (!isInited()) return;
  123. CreateRenderThread();
  124. timerset=1;
  125. }
  126. // -----------------------------------------------------------------------
  127. void QuickPaintWnd::stopQuickPaint()
  128. {
  129. enabled = 0;
  130. if (!isInited()) return;
  131. KillThread();
  132. timerset=0;
  133. }
  134. // -----------------------------------------------------------------------
  135. int QuickPaintWnd::isQuickPainting()
  136. {
  137. return enabled;
  138. }
  139. // -----------------------------------------------------------------------
  140. int QuickPaintWnd::getSpeed()
  141. {
  142. return speed;
  143. }
  144. // -----------------------------------------------------------------------
  145. int QuickPaintWnd::onInit()
  146. {
  147. QUICKPAINTWND_PARENT::onInit();
  148. if (enabled)
  149. {
  150. ASSERT(!thread_context);
  151. CreateRenderThread();
  152. timerset = 1;
  153. }
  154. return 1;
  155. }
  156. // -----------------------------------------------------------------------
  157. void QuickPaintWnd::timerCallback(int id)
  158. {
  159. switch (id)
  160. {
  161. case TIMER_QUICKPAINT:
  162. if (invalidates_required)
  163. {
  164. invalidated = 1;
  165. if (getRealtime() && isVisible() && !isMinimized())
  166. cascadeRepaint();
  167. else
  168. invalidate();
  169. InterlockedExchange(&invalidates_required, 0);
  170. }
  171. //quickPaint();
  172. break;
  173. default:
  174. QUICKPAINTWND_PARENT::timerCallback(id);
  175. }
  176. }
  177. void QuickPaintWnd::SetPaintingCanvas(BltCanvas *c)
  178. {
  179. InterlockedExchangePointer((volatile PVOID*)&paint_canvas, c);
  180. }
  181. BltCanvas *&QuickPaintWnd::GetDrawingConvas()
  182. {
  183. if (paint_canvas == render_canvas2)
  184. return render_canvas1;
  185. else
  186. return render_canvas2;
  187. }
  188. // -----------------------------------------------------------------------
  189. int QuickPaintWnd::quickPaint()
  190. {
  191. int repaint=0;
  192. int w, h;
  193. getQuickPaintSize(&w, &h);
  194. if (wantEvenAlignment())
  195. {
  196. if (w & 1) w++;
  197. if (h & 1) h++;
  198. }
  199. if (w == 0 && h == 0) return 0;
  200. BltCanvas *&render_canvas = GetDrawingConvas();
  201. int newone = 0;
  202. if (canvas_w != w || canvas_h != h)
  203. {
  204. delete render_canvas1; render_canvas1=0;
  205. delete render_canvas2; render_canvas2=0;
  206. }
  207. if (!render_canvas)
  208. {
  209. render_canvas = new BltCanvas(w, wantNegativeHeight() ? -h : h, getOsWindowHandle());
  210. canvas_w = w;
  211. canvas_h = h;
  212. newone = 1;
  213. }
  214. repaint = onQuickPaint(render_canvas, canvas_w, canvas_h, newone);
  215. SetPaintingCanvas(render_canvas);
  216. if (repaint)
  217. InterlockedIncrement(&invalidates_required);
  218. return repaint;
  219. }
  220. // -----------------------------------------------------------------------
  221. void QuickPaintWnd::getQuickPaintSize(int *w, int *h)
  222. {
  223. RECT r;
  224. getClientRect(&r);
  225. if (w) *w = r.right - r.left;
  226. if (h) *h = r.bottom - r.top;
  227. }
  228. // -----------------------------------------------------------------------
  229. void QuickPaintWnd::getQuickPaintSource(RECT *r)
  230. {
  231. ASSERT(r != NULL);
  232. r->left = 0;
  233. r->right = canvas_w;
  234. r->top = 0;
  235. r->bottom = canvas_h;
  236. }
  237. // -----------------------------------------------------------------------
  238. void QuickPaintWnd::getQuickPaintDest(RECT *r)
  239. {
  240. ASSERT(r != NULL);
  241. getClientRect(r);
  242. }
  243. // -----------------------------------------------------------------------
  244. void QuickPaintWnd::onSetVisible(int show)
  245. {
  246. QUICKPAINTWND_PARENT::onSetVisible(show);
  247. if (!show)
  248. {
  249. if (timerset)
  250. {
  251. KillThread();
  252. timerset = 0;
  253. }
  254. }
  255. else
  256. {
  257. if (enabled && !timerset)
  258. {
  259. CreateRenderThread();
  260. timerset = 1;
  261. }
  262. }
  263. }
  264. // -----------------------------------------------------------------------
  265. int QuickPaintWnd::onPaint(Canvas *canvas)
  266. {
  267. QUICKPAINTWND_PARENT::onPaint(canvas);
  268. if (!enabled) return 1;
  269. BltCanvas *render_canvas;
  270. InterlockedExchangePointer((volatile PVOID*)&render_canvas, paint_canvas);
  271. if (!render_canvas) return 1;
  272. RECT r;
  273. getQuickPaintDest(&r);
  274. RECT sr;
  275. getQuickPaintSource(&sr);
  276. if (invalidated && wantFilters())
  277. {
  278. foreach(filters)
  279. filters.getfor()->filterBitmap((unsigned char *)render_canvas->getBits(), canvas_w, canvas_h, 32, NULL, getFiltersGroup());
  280. endfor;
  281. invalidated = 0;
  282. }
  283. render_canvas->/*getSkinBitmap()->*/stretchToRectAlpha(canvas, &sr, &r, getPaintingAlpha());
  284. InterlockedExchange(&invalidates_required, 0);
  285. return 1;
  286. }
  287. void QuickPaintWnd::KillThread()
  288. {
  289. if (thread_context)
  290. {
  291. killTimer(TIMER_QUICKPAINT);
  292. thread_context->Kill();
  293. delete thread_context;
  294. thread_context = 0;
  295. }
  296. }
  297. void QuickPaintWnd::CreateRenderThread()
  298. {
  299. int sp = getSpeed();
  300. if (!thread_context)
  301. {
  302. thread_context = new QuickPaintContext(this, sp);
  303. }
  304. else
  305. thread_context->timer_ms = sp;
  306. setTimer(TIMER_QUICKPAINT, sp);
  307. }