dc_client.c 14 KB

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