dc_client.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. /*
  2. * File : dc_client.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2006 - 2009, RT-Thread Development Team
  5. *
  6. * The license and distribution terms for this file may be
  7. * found in the file LICENSE in this distribution or at
  8. * http://www.rt-thread.org/license/LICENSE
  9. *
  10. * Change Logs:
  11. * Date Author Notes
  12. * 2009-10-16 Bernard first version
  13. * 2010-08-09 Bernard rename hardware dc to client dc
  14. * 2010-09-13 Bernard fix rtgui_dc_client_blit_line issue, which found
  15. * by appele
  16. * 2010-09-14 Bernard fix vline and hline coordinate issue
  17. */
  18. #include <rtgui/dc.h>
  19. #include <rtgui/dc_hw.h>
  20. #include <rtgui/dc_client.h>
  21. #include <rtgui/driver.h>
  22. #include <rtgui/rtgui_system.h>
  23. #include <rtgui/rtgui_app.h>
  24. #include <rtgui/rtgui_server.h>
  25. #include <rtgui/widgets/container.h>
  26. #include <rtgui/widgets/window.h>
  27. #include <rtgui/widgets/title.h>
  28. static void rtgui_dc_client_draw_point(struct rtgui_dc *dc, int x, int y);
  29. static void rtgui_dc_client_draw_color_point(struct rtgui_dc *dc, int x, int y, rtgui_color_t color);
  30. static void rtgui_dc_client_draw_hline(struct rtgui_dc *dc, int x1, int x2, int y);
  31. static void rtgui_dc_client_draw_vline(struct rtgui_dc *dc, int x, int y1, int y2);
  32. static void rtgui_dc_client_fill_rect(struct rtgui_dc *dc, rtgui_rect_t *rect);
  33. static void rtgui_dc_client_blit_line(struct rtgui_dc *self, int x1, int x2, int y, rt_uint8_t *line_data);
  34. static void rtgui_dc_client_blit(struct rtgui_dc *dc, struct rtgui_point *dc_point, struct rtgui_dc *dest, rtgui_rect_t *rect);
  35. static void rtgui_dc_client_set_gc(struct rtgui_dc *dc, rtgui_gc_t *gc);
  36. static rtgui_gc_t *rtgui_dc_client_get_gc(struct rtgui_dc *dc);
  37. static rt_bool_t rtgui_dc_client_fini(struct rtgui_dc *dc);
  38. static rt_bool_t rtgui_dc_client_get_visible(struct rtgui_dc *dc);
  39. static void rtgui_dc_client_get_rect(struct rtgui_dc *dc, rtgui_rect_t *rect);
  40. #define hw_driver (rtgui_graphic_driver_get_default())
  41. #define dc_set_foreground(c) dc->gc.foreground = c
  42. #define dc_set_background(c) dc->gc.background = c
  43. #define _int_swap(x, y) do {x ^= y; y ^= x; x ^= y;} while (0)
  44. struct rtgui_dc *rtgui_dc_begin_drawing(rtgui_widget_t *owner)
  45. {
  46. struct rtgui_dc *dc;
  47. RT_ASSERT(owner != RT_NULL);
  48. rtgui_screen_lock(RT_WAITING_FOREVER);
  49. if ((rtgui_region_is_flat(&owner->clip) == RT_EOK) &&
  50. rtgui_rect_is_equal(&(owner->extent), &(owner->clip.extents)) == RT_EOK)
  51. dc = rtgui_dc_hw_create(owner);
  52. else
  53. dc = rtgui_dc_client_create(owner);
  54. if (dc == RT_NULL) rtgui_screen_unlock();
  55. return dc;
  56. }
  57. RTM_EXPORT(rtgui_dc_begin_drawing);
  58. void rtgui_dc_end_drawing(struct rtgui_dc *dc)
  59. {
  60. dc->engine->fini(dc);
  61. rtgui_screen_unlock();
  62. }
  63. RTM_EXPORT(rtgui_dc_end_drawing);
  64. const struct rtgui_dc_engine dc_client_engine =
  65. {
  66. rtgui_dc_client_draw_point,
  67. rtgui_dc_client_draw_color_point,
  68. rtgui_dc_client_draw_vline,
  69. rtgui_dc_client_draw_hline,
  70. rtgui_dc_client_fill_rect,
  71. rtgui_dc_client_blit_line,
  72. rtgui_dc_client_blit,
  73. rtgui_dc_client_set_gc,
  74. rtgui_dc_client_get_gc,
  75. rtgui_dc_client_get_visible,
  76. rtgui_dc_client_get_rect,
  77. rtgui_dc_client_fini,
  78. };
  79. void rtgui_dc_client_init(rtgui_widget_t *owner)
  80. {
  81. struct rtgui_dc *dc;
  82. RT_ASSERT(owner != RT_NULL);
  83. dc = RTGUI_WIDGET_DC(owner);
  84. dc->type = RTGUI_DC_CLIENT;
  85. dc->engine = &dc_client_engine;
  86. }
  87. extern struct rt_mutex cursor_mutex;
  88. extern void rtgui_mouse_show_cursor(void);
  89. extern void rtgui_mouse_hide_cursor(void);
  90. struct rtgui_dc *rtgui_dc_client_create(rtgui_widget_t *owner)
  91. {
  92. struct rtgui_dc *dc;
  93. rtgui_widget_t *widget;
  94. /* adjudge owner */
  95. if (owner == RT_NULL || owner->toplevel == RT_NULL) return RT_NULL;
  96. if (!RTGUI_IS_WIN(owner->toplevel)) return RT_NULL;
  97. dc = RTGUI_WIDGET_DC(owner);
  98. /* set init visible as true */
  99. RTGUI_WIDGET_DC_SET_VISIBLE(owner);
  100. /* check widget visible */
  101. widget = owner;
  102. while (widget != RT_NULL)
  103. {
  104. if (RTGUI_WIDGET_IS_HIDE(widget))
  105. {
  106. RTGUI_WIDGET_DC_SET_UNVISIBLE(owner);
  107. return RT_NULL;
  108. }
  109. widget = widget->parent;
  110. }
  111. if (RTGUI_IS_WINTITLE(owner->toplevel))
  112. {
  113. struct rtgui_win *top = RTGUI_WIN(owner->toplevel);
  114. top->drawing ++;
  115. if (top->drawing == 1)
  116. {
  117. #ifdef RTGUI_USING_MOUSE_CURSOR
  118. #ifdef _WIN32_NATIVE
  119. rt_mutex_take(&cursor_mutex, RT_WAITING_FOREVER);
  120. rt_kprintf("hide cursor\n");
  121. rtgui_mouse_hide_cursor();
  122. #else
  123. /* hide cursor */
  124. rtgui_mouse_hide_cursor();
  125. #endif
  126. #endif
  127. }
  128. }
  129. else if (RTGUI_IS_APP(owner->toplevel))
  130. {
  131. RT_ASSERT(0);
  132. }
  133. else if (RTGUI_IS_WIN(owner->toplevel))
  134. {
  135. struct rtgui_win *top = RTGUI_WIN(owner->toplevel);
  136. top->drawing ++;
  137. if (top->drawing == 1)
  138. {
  139. #ifdef _WIN32_NATIVE
  140. #ifdef RTGUI_USING_MOUSE_CURSOR
  141. rt_mutex_take(&cursor_mutex, RT_WAITING_FOREVER);
  142. rt_kprintf("hide cursor\n");
  143. rtgui_mouse_hide_cursor();
  144. #endif
  145. #else
  146. /* send draw begin to server */
  147. struct rtgui_event_update_begin eupdate;
  148. RTGUI_EVENT_UPDATE_BEGIN_INIT(&(eupdate));
  149. eupdate.rect = RTGUI_WIDGET(top)->extent;
  150. rtgui_server_post_event((struct rtgui_event *)&eupdate, sizeof(eupdate));
  151. #endif
  152. }
  153. }
  154. return dc;
  155. }
  156. static rt_bool_t rtgui_dc_client_fini(struct rtgui_dc *dc)
  157. {
  158. rtgui_widget_t *owner;
  159. if (dc == RT_NULL || dc->type != RTGUI_DC_CLIENT) return RT_FALSE;
  160. /* get owner */
  161. owner = RTGUI_CONTAINER_OF(dc, struct rtgui_widget, dc_type);
  162. if (RTGUI_IS_WINTITLE(owner->toplevel))
  163. {
  164. /* update title extent */
  165. struct rtgui_win *top = RTGUI_WIN(owner->toplevel);
  166. top->drawing --;
  167. if ((top->drawing == 0) && RTGUI_WIDGET_IS_DC_VISIBLE(owner))
  168. {
  169. #ifdef _WIN32_NATIVE
  170. #ifdef RTGUI_USING_MOUSE_CURSOR
  171. rt_mutex_release(&cursor_mutex);
  172. /* show cursor */
  173. rtgui_mouse_show_cursor();
  174. rt_kprintf("show cursor\n");
  175. #endif
  176. /* update screen */
  177. rtgui_graphic_driver_screen_update(hw_driver, &(owner->extent));
  178. #else
  179. #ifdef RTGUI_USING_MOUSE_CURSOR
  180. /* show cursor */
  181. rtgui_mouse_show_cursor();
  182. #endif
  183. /* update screen */
  184. rtgui_graphic_driver_screen_update(hw_driver, &(owner->extent));
  185. #endif
  186. }
  187. }
  188. else if (RTGUI_IS_APP(owner->toplevel) ||
  189. RTGUI_IS_WIN(owner->toplevel))
  190. {
  191. struct rtgui_win *top = RTGUI_WIN(owner->toplevel);
  192. top->drawing --;
  193. if ((top->drawing == 0) && RTGUI_WIDGET_IS_DC_VISIBLE(owner))
  194. {
  195. #ifdef _WIN32_NATIVE
  196. #ifdef RTGUI_USING_MOUSE_CURSOR
  197. rt_mutex_release(&cursor_mutex);
  198. /* show cursor */
  199. rtgui_mouse_show_cursor();
  200. rt_kprintf("show cursor\n");
  201. #endif
  202. /* update screen */
  203. rtgui_graphic_driver_screen_update(hw_driver, &(owner->extent));
  204. #else
  205. /* send to server to end drawing */
  206. struct rtgui_event_update_end eupdate;
  207. RTGUI_EVENT_UPDATE_END_INIT(&(eupdate));
  208. eupdate.rect = owner->extent;
  209. rtgui_server_post_event((struct rtgui_event *)&eupdate, sizeof(eupdate));
  210. #endif
  211. }
  212. }
  213. return RT_TRUE;
  214. }
  215. /*
  216. * draw a logic point on device
  217. */
  218. static void rtgui_dc_client_draw_point(struct rtgui_dc *self, int x, int y)
  219. {
  220. rtgui_rect_t rect;
  221. rtgui_widget_t *owner;
  222. if (self == RT_NULL) return;
  223. /* get owner */
  224. owner = RTGUI_CONTAINER_OF(self, struct rtgui_widget, dc_type);
  225. if (!RTGUI_WIDGET_IS_DC_VISIBLE(owner)) return;
  226. x = x + owner->extent.x1;
  227. y = y + owner->extent.y1;
  228. if (rtgui_region_contains_point(&(owner->clip), x, y, &rect) == RT_EOK)
  229. {
  230. /* draw this point */
  231. hw_driver->ops->set_pixel(&(owner->gc.foreground), x, y);
  232. }
  233. }
  234. static void rtgui_dc_client_draw_color_point(struct rtgui_dc *self, int x, int y, rtgui_color_t color)
  235. {
  236. rtgui_rect_t rect;
  237. rtgui_widget_t *owner;
  238. if (self == RT_NULL) return;
  239. /* get owner */
  240. owner = RTGUI_CONTAINER_OF(self, struct rtgui_widget, dc_type);
  241. if (!RTGUI_WIDGET_IS_DC_VISIBLE(owner)) return;
  242. x = x + owner->extent.x1;
  243. y = y + owner->extent.y1;
  244. if (rtgui_region_contains_point(&(owner->clip), x, y, &rect) == RT_EOK)
  245. {
  246. /* draw this point */
  247. hw_driver->ops->set_pixel(&color, x, y);
  248. }
  249. }
  250. /*
  251. * draw a logic vertical line on device
  252. */
  253. static void rtgui_dc_client_draw_vline(struct rtgui_dc *self, int x, int y1, int y2)
  254. {
  255. register rt_base_t index;
  256. rtgui_widget_t *owner;
  257. if (self == RT_NULL) return;
  258. /* get owner */
  259. owner = RTGUI_CONTAINER_OF(self, struct rtgui_widget, dc_type);
  260. if (!RTGUI_WIDGET_IS_DC_VISIBLE(owner)) return;
  261. x = x + owner->extent.x1;
  262. y1 = y1 + owner->extent.y1;
  263. y2 = y2 + owner->extent.y1;
  264. if (y1 > y2) _int_swap(y1, y2);
  265. if (owner->clip.data == RT_NULL)
  266. {
  267. rtgui_rect_t *prect;
  268. prect = &(owner->clip.extents);
  269. /* calculate vline intersect */
  270. if (prect->x1 > x || prect->x2 <= x) return;
  271. if (prect->y2 <= y1 || prect->y1 > y2) return;
  272. if (prect->y1 > y1) y1 = prect->y1;
  273. if (prect->y2 < y2) y2 = prect->y2;
  274. /* draw vline */
  275. hw_driver->ops->draw_vline(&(owner->gc.foreground), x, y1, y2);
  276. }
  277. else for (index = 0; index < rtgui_region_num_rects(&(owner->clip)); index ++)
  278. {
  279. rtgui_rect_t *prect;
  280. register rt_base_t draw_y1, draw_y2;
  281. prect = ((rtgui_rect_t *)(owner->clip.data + index + 1));
  282. draw_y1 = y1;
  283. draw_y2 = y2;
  284. /* calculate vline clip */
  285. if (prect->x1 > x || prect->x2 <= x) continue;
  286. if (prect->y2 <= y1 || prect->y1 > y2) continue;
  287. if (prect->y1 > y1) draw_y1 = prect->y1;
  288. if (prect->y2 < y2) draw_y2 = prect->y2;
  289. /* draw vline */
  290. hw_driver->ops->draw_vline(&(owner->gc.foreground), x, draw_y1, draw_y2);
  291. }
  292. }
  293. /*
  294. * draw a logic horizontal line on device
  295. */
  296. static void rtgui_dc_client_draw_hline(struct rtgui_dc *self, int x1, int x2, int y)
  297. {
  298. register rt_base_t index;
  299. rtgui_widget_t *owner;
  300. if (self == RT_NULL) return;
  301. /* get owner */
  302. owner = RTGUI_CONTAINER_OF(self, struct rtgui_widget, dc_type);
  303. if (!RTGUI_WIDGET_IS_DC_VISIBLE(owner)) return;
  304. /* convert logic to device */
  305. x1 = x1 + owner->extent.x1;
  306. x2 = x2 + owner->extent.x1;
  307. if (x1 > x2) _int_swap(x1, x2);
  308. y = y + owner->extent.y1;
  309. if (owner->clip.data == RT_NULL)
  310. {
  311. rtgui_rect_t *prect;
  312. prect = &(owner->clip.extents);
  313. /* calculate vline intersect */
  314. if (prect->y1 > y || prect->y2 <= y) return;
  315. if (prect->x2 <= x1 || prect->x1 > x2) return;
  316. if (prect->x1 > x1) x1 = prect->x1;
  317. if (prect->x2 < x2) x2 = prect->x2;
  318. /* draw hline */
  319. hw_driver->ops->draw_hline(&(owner->gc.foreground), x1, x2, y);
  320. }
  321. else for (index = 0; index < rtgui_region_num_rects(&(owner->clip)); index ++)
  322. {
  323. rtgui_rect_t *prect;
  324. register rt_base_t draw_x1, draw_x2;
  325. prect = ((rtgui_rect_t *)(owner->clip.data + index + 1));
  326. draw_x1 = x1;
  327. draw_x2 = x2;
  328. /* calculate hline clip */
  329. if (prect->y1 > y || prect->y2 <= y) continue;
  330. if (prect->x2 <= x1 || prect->x1 > x2) continue;
  331. if (prect->x1 > x1) draw_x1 = prect->x1;
  332. if (prect->x2 < x2) draw_x2 = prect->x2;
  333. /* draw hline */
  334. hw_driver->ops->draw_hline(&(owner->gc.foreground), draw_x1, draw_x2, y);
  335. }
  336. }
  337. static void rtgui_dc_client_fill_rect(struct rtgui_dc *self, struct rtgui_rect *rect)
  338. {
  339. rtgui_color_t foreground;
  340. register rt_base_t index;
  341. rtgui_widget_t *owner;
  342. if (self == RT_NULL) return;
  343. /* get owner */
  344. owner = RTGUI_CONTAINER_OF(self, struct rtgui_widget, dc_type);
  345. if (!RTGUI_WIDGET_IS_DC_VISIBLE(owner)) return;
  346. /* save foreground color */
  347. foreground = owner->gc.foreground;
  348. /* set background color as foreground color */
  349. owner->gc.foreground = owner->gc.background;
  350. /* fill rect */
  351. for (index = rect->y1; index < rect->y2; index ++)
  352. {
  353. rtgui_dc_client_draw_hline(self, rect->x1, rect->x2, index);
  354. }
  355. /* restore foreground color */
  356. owner->gc.foreground = foreground;
  357. }
  358. static void rtgui_dc_client_blit_line(struct rtgui_dc *self, int x1, int x2, int y, rt_uint8_t *line_data)
  359. {
  360. register rt_base_t index;
  361. rtgui_widget_t *owner;
  362. if (self == RT_NULL) return;
  363. /* get owner */
  364. owner = RTGUI_CONTAINER_OF(self, struct rtgui_widget, dc_type);
  365. if (!RTGUI_WIDGET_IS_DC_VISIBLE(owner)) return;
  366. /* convert logic to device */
  367. x1 = x1 + owner->extent.x1;
  368. x2 = x2 + owner->extent.x1;
  369. if (x1 > x2) _int_swap(x1, x2);
  370. y = y + owner->extent.y1;
  371. if (rtgui_region_is_flat(&(owner->clip)) == RT_EOK)
  372. {
  373. rtgui_rect_t *prect;
  374. int offset = 0;
  375. prect = &(owner->clip.extents);
  376. /* calculate vline intersect */
  377. if (prect->y1 > y || prect->y2 <= y) return;
  378. if (prect->x2 <= x1 || prect->x1 > x2) return;
  379. if (prect->x1 > x1) x1 = prect->x1;
  380. if (prect->x2 < x2) x2 = prect->x2;
  381. /* patch note:
  382. * We need to adjust the offset when update widget clip!
  383. * Of course at ordinary times for 0. General */
  384. offset = owner->clip.extents.x1 - owner->extent.x1;
  385. offset = offset * hw_driver->bits_per_pixel / 8;
  386. /* draw hline */
  387. hw_driver->ops->draw_raw_hline(line_data + offset, x1, x2, y);
  388. }
  389. else for (index = 0; index < rtgui_region_num_rects(&(owner->clip)); index ++)
  390. {
  391. rtgui_rect_t *prect;
  392. register rt_base_t draw_x1, draw_x2;
  393. prect = ((rtgui_rect_t *)(owner->clip.data + index + 1));
  394. draw_x1 = x1;
  395. draw_x2 = x2;
  396. /* calculate hline clip */
  397. if (prect->y1 > y || prect->y2 <= y) continue;
  398. if (prect->x2 <= x1 || prect->x1 > x2) continue;
  399. if (prect->x1 > x1) draw_x1 = prect->x1;
  400. if (prect->x2 < x2) draw_x2 = prect->x2;
  401. /* draw hline */
  402. hw_driver->ops->draw_raw_hline(line_data + (draw_x1 - x1) * hw_driver->bits_per_pixel / 8, draw_x1, draw_x2, y);
  403. }
  404. }
  405. static void rtgui_dc_client_blit(struct rtgui_dc *dc, struct rtgui_point *dc_point, struct rtgui_dc *dest, rtgui_rect_t *rect)
  406. {
  407. /* not blit in hardware dc */
  408. return ;
  409. }
  410. static void rtgui_dc_client_set_gc(struct rtgui_dc *self, rtgui_gc_t *gc)
  411. {
  412. rtgui_widget_t *owner;
  413. if (self == RT_NULL) return;
  414. /* get owner */
  415. owner = RTGUI_CONTAINER_OF(self, struct rtgui_widget, dc_type);
  416. owner->gc = *gc;
  417. }
  418. static rtgui_gc_t *rtgui_dc_client_get_gc(struct rtgui_dc *self)
  419. {
  420. rtgui_widget_t *owner;
  421. RT_ASSERT(self != RT_NULL);
  422. /* get owner */
  423. owner = RTGUI_CONTAINER_OF(self, struct rtgui_widget, dc_type);
  424. return &(owner->gc);
  425. }
  426. static rt_bool_t rtgui_dc_client_get_visible(struct rtgui_dc *self)
  427. {
  428. rtgui_widget_t *owner;
  429. if (self == RT_NULL) return RT_FALSE;
  430. /* get owner */
  431. owner = RTGUI_CONTAINER_OF(self, struct rtgui_widget, dc_type);
  432. if (!RTGUI_WIDGET_IS_DC_VISIBLE(owner)) return RT_FALSE;
  433. return RT_TRUE;
  434. }
  435. static void rtgui_dc_client_get_rect(struct rtgui_dc *self, rtgui_rect_t *rect)
  436. {
  437. rtgui_widget_t *owner;
  438. if (self == RT_NULL) return;
  439. /* get owner */
  440. owner = RTGUI_CONTAINER_OF(self, struct rtgui_widget, dc_type);
  441. rtgui_widget_get_rect(owner, rect);
  442. }