window.c 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105
  1. /*
  2. * File : window.c
  3. * This file is part of RTGUI in 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-04 Bernard first version
  13. */
  14. #include <rtgui/dc.h>
  15. #include <rtgui/color.h>
  16. #include <rtgui/image.h>
  17. #include <rtgui/rtgui_system.h>
  18. #include <rtgui/rtgui_server.h>
  19. #include <rtgui/rtgui_app.h>
  20. #include <rtgui/widgets/window.h>
  21. //#include <rtgui/widgets/button.h>
  22. #include <rtgui/widgets/title.h>
  23. static rt_bool_t _rtgui_win_deal_close(struct rtgui_win *win,
  24. struct rtgui_event *event,
  25. rt_bool_t force_close);
  26. static void _rtgui_win_constructor(rtgui_win_t *win)
  27. {
  28. /* set toplevel to self */
  29. RTGUI_WIDGET(win)->toplevel = win;
  30. /* init win property */
  31. win->drawing = 0;
  32. RTGUI_WIDGET(win)->flag |= RTGUI_WIDGET_FLAG_FOCUSABLE;
  33. win->parent_window = RT_NULL;
  34. win->app = rtgui_app_self();
  35. /* init window attribute */
  36. win->on_activate = RT_NULL;
  37. win->on_deactivate = RT_NULL;
  38. win->on_close = RT_NULL;
  39. win->on_key = RT_NULL;
  40. win->title = RT_NULL;
  41. win->_title_wgt = RT_NULL;
  42. win->modal_code = RTGUI_MODAL_OK;
  43. /* initialize last mouse event handled widget */
  44. win->last_mevent_widget = RT_NULL;
  45. win->focused_widget = RT_NULL;
  46. /* set window hide */
  47. RTGUI_WIDGET_HIDE(win);
  48. /* set window style */
  49. win->style = RTGUI_WIN_STYLE_DEFAULT;
  50. win->flag = RTGUI_WIN_FLAG_INIT;
  51. rtgui_object_set_event_handler(RTGUI_OBJECT(win), rtgui_win_event_handler);
  52. /* init user data */
  53. win->user_data = 0;
  54. win->_do_show = rtgui_win_do_show;
  55. }
  56. static void _rtgui_win_destructor(rtgui_win_t *win)
  57. {
  58. struct rtgui_event_win_destroy edestroy;
  59. if (win->flag & RTGUI_WIN_FLAG_CONNECTED)
  60. {
  61. /* destroy in server */
  62. RTGUI_EVENT_WIN_DESTROY_INIT(&edestroy);
  63. edestroy.wid = win;
  64. if (rtgui_server_post_event_sync(RTGUI_EVENT(&edestroy),
  65. sizeof(struct rtgui_event_win_destroy)) != RT_EOK)
  66. {
  67. /* destroy in server failed */
  68. return;
  69. }
  70. }
  71. /* release field */
  72. if (win->_title_wgt)
  73. {
  74. rtgui_widget_destroy(RTGUI_WIDGET(win->_title_wgt));
  75. win->_title_wgt = RT_NULL;
  76. }
  77. if (win->title != RT_NULL)
  78. {
  79. rt_free(win->title);
  80. win->title = RT_NULL;
  81. }
  82. rtgui_region_fini(&win->outer_clip);
  83. /* release external clip info */
  84. win->drawing = 0;
  85. }
  86. static rt_bool_t _rtgui_win_create_in_server(struct rtgui_win *win)
  87. {
  88. if (!(win->flag & RTGUI_WIN_FLAG_CONNECTED))
  89. {
  90. struct rtgui_event_win_create ecreate;
  91. RTGUI_EVENT_WIN_CREATE_INIT(&ecreate);
  92. /* send win create event to server */
  93. ecreate.parent_window = win->parent_window;
  94. ecreate.wid = win;
  95. ecreate.parent.user = win->style;
  96. if (rtgui_server_post_event_sync(RTGUI_EVENT(&ecreate),
  97. sizeof(struct rtgui_event_win_create)
  98. ) != RT_EOK)
  99. {
  100. rt_kprintf("create win: %s failed\n", win->title);
  101. return RT_FALSE;
  102. }
  103. win->flag |= RTGUI_WIN_FLAG_CONNECTED;
  104. }
  105. return RT_TRUE;
  106. }
  107. DEFINE_CLASS_TYPE(win, "win",
  108. RTGUI_PARENT_TYPE(container),
  109. _rtgui_win_constructor,
  110. _rtgui_win_destructor,
  111. sizeof(struct rtgui_win));
  112. int rtgui_win_init(struct rtgui_win *win, struct rtgui_win *parent_window,
  113. const char *title,
  114. rtgui_rect_t *rect,
  115. rt_uint16_t style)
  116. {
  117. if (win == RT_NULL) return -1;
  118. /* set parent window */
  119. win->parent_window = parent_window;
  120. /* set title, rect and style */
  121. if (title != RT_NULL)
  122. win->title = rt_strdup(title);
  123. else
  124. win->title = RT_NULL;
  125. rtgui_widget_set_rect(RTGUI_WIDGET(win), rect);
  126. win->style = style;
  127. if (!((style & RTGUI_WIN_STYLE_NO_TITLE) && (style & RTGUI_WIN_STYLE_NO_BORDER)))
  128. {
  129. struct rtgui_rect trect = *rect;
  130. win->_title_wgt = rtgui_wintitle_create(win);
  131. if (!win->_title_wgt)
  132. goto __on_err;
  133. if (!(style & RTGUI_WIN_STYLE_NO_BORDER))
  134. {
  135. rtgui_rect_inflate(&trect, WINTITLE_BORDER_SIZE);
  136. }
  137. if (!(style & RTGUI_WIN_STYLE_NO_TITLE))
  138. {
  139. trect.y1 -= WINTITLE_HEIGHT;
  140. }
  141. rtgui_widget_set_rect(RTGUI_WIDGET(win->_title_wgt), &trect);
  142. /* Update the clip of the wintitle manually. */
  143. rtgui_region_subtract_rect(&(RTGUI_WIDGET(win->_title_wgt)->clip),
  144. &(RTGUI_WIDGET(win->_title_wgt)->clip),
  145. &(RTGUI_WIDGET(win)->extent));
  146. /* The window title is always un-hidden for simplicity. */
  147. rtgui_widget_show(RTGUI_WIDGET(win->_title_wgt));
  148. rtgui_region_init_with_extents(&win->outer_clip, &trect);
  149. win->outer_extent = trect;
  150. }
  151. else
  152. {
  153. rtgui_region_init_with_extents(&win->outer_clip, rect);
  154. win->outer_extent = *rect;
  155. }
  156. if (_rtgui_win_create_in_server(win) == RT_FALSE)
  157. {
  158. goto __on_err;
  159. }
  160. win->app->window_cnt++;
  161. return 0;
  162. __on_err:
  163. return -1;
  164. }
  165. RTM_EXPORT(rtgui_win_init);
  166. int rtgui_win_fini(struct rtgui_win* win)
  167. {
  168. /* close the window first if it's not. */
  169. if (!(win->flag & RTGUI_WIN_FLAG_CLOSED))
  170. {
  171. struct rtgui_event_win_close eclose;
  172. RTGUI_EVENT_WIN_CLOSE_INIT(&eclose);
  173. eclose.wid = win;
  174. if (win->style & RTGUI_WIN_STYLE_DESTROY_ON_CLOSE)
  175. {
  176. _rtgui_win_deal_close(win,
  177. (struct rtgui_event *)&eclose,
  178. RT_TRUE);
  179. return 0;
  180. }
  181. else
  182. _rtgui_win_deal_close(win,
  183. (struct rtgui_event *)&eclose,
  184. RT_TRUE);
  185. }
  186. if (win->flag & RTGUI_WIN_FLAG_MODAL)
  187. {
  188. /* set the RTGUI_WIN_STYLE_DESTROY_ON_CLOSE flag so the window will be
  189. * destroyed after the event_loop */
  190. win->style |= RTGUI_WIN_STYLE_DESTROY_ON_CLOSE;
  191. rtgui_win_end_modal(win, RTGUI_MODAL_CANCEL);
  192. }
  193. return 0;
  194. }
  195. RTM_EXPORT(rtgui_win_fini);
  196. rtgui_win_t *rtgui_win_create(struct rtgui_win *parent_window,
  197. const char *title,
  198. rtgui_rect_t *rect,
  199. rt_uint16_t style)
  200. {
  201. struct rtgui_win *win;
  202. /* allocate win memory */
  203. win = RTGUI_WIN(rtgui_widget_create(RTGUI_WIN_TYPE));
  204. if (win == RT_NULL)
  205. return RT_NULL;
  206. if (rtgui_win_init(win, parent_window, title, rect, style) != 0)
  207. {
  208. rtgui_widget_destroy(RTGUI_WIDGET(win));
  209. return RT_NULL;
  210. }
  211. return win;
  212. }
  213. RTM_EXPORT(rtgui_win_create);
  214. rtgui_win_t *rtgui_mainwin_create(struct rtgui_win *parent_window, const char *title, rt_uint16_t style)
  215. {
  216. struct rtgui_rect rect;
  217. /* get rect of main window */
  218. rtgui_get_mainwin_rect(&rect);
  219. return rtgui_win_create(parent_window, title, &rect, style);
  220. }
  221. RTM_EXPORT(rtgui_mainwin_create);
  222. static rt_bool_t _rtgui_win_deal_close(struct rtgui_win *win,
  223. struct rtgui_event *event,
  224. rt_bool_t force_close)
  225. {
  226. if (win->on_close != RT_NULL)
  227. {
  228. if ((win->on_close(RTGUI_OBJECT(win), event) == RT_FALSE) && !force_close)
  229. return RT_FALSE;
  230. }
  231. rtgui_win_hide(win);
  232. win->flag |= RTGUI_WIN_FLAG_CLOSED;
  233. if (win->flag & RTGUI_WIN_FLAG_MODAL)
  234. {
  235. /* rtgui_win_end_modal cleared the RTGUI_WIN_FLAG_MODAL in win->flag so
  236. * we have to record it. */
  237. rtgui_win_end_modal(win, RTGUI_MODAL_CANCEL);
  238. }
  239. win->app->window_cnt--;
  240. if (win->app->window_cnt == 0 && !(win->app->state_flag & RTGUI_APP_FLAG_KEEP))
  241. {
  242. rtgui_app_exit(rtgui_app_self(), 0);
  243. }
  244. if (win->style & RTGUI_WIN_STYLE_DESTROY_ON_CLOSE)
  245. {
  246. rtgui_win_destroy(win);
  247. }
  248. return RT_TRUE;
  249. }
  250. void rtgui_win_destroy(struct rtgui_win *win)
  251. {
  252. /* close the window first if it's not. */
  253. if (!(win->flag & RTGUI_WIN_FLAG_CLOSED))
  254. {
  255. struct rtgui_event_win_close eclose;
  256. RTGUI_EVENT_WIN_CLOSE_INIT(&eclose);
  257. eclose.wid = win;
  258. if (win->style & RTGUI_WIN_STYLE_DESTROY_ON_CLOSE)
  259. {
  260. _rtgui_win_deal_close(win,
  261. (struct rtgui_event *)&eclose,
  262. RT_TRUE);
  263. return;
  264. }
  265. else
  266. _rtgui_win_deal_close(win,
  267. (struct rtgui_event *)&eclose,
  268. RT_TRUE);
  269. }
  270. if (win->flag & RTGUI_WIN_FLAG_MODAL)
  271. {
  272. /* set the RTGUI_WIN_STYLE_DESTROY_ON_CLOSE flag so the window will be
  273. * destroyed after the event_loop */
  274. win->style |= RTGUI_WIN_STYLE_DESTROY_ON_CLOSE;
  275. rtgui_win_end_modal(win, RTGUI_MODAL_CANCEL);
  276. }
  277. else
  278. {
  279. rtgui_widget_destroy(RTGUI_WIDGET(win));
  280. }
  281. }
  282. RTM_EXPORT(rtgui_win_destroy);
  283. /* send a close event to myself to get a consistent behavior */
  284. rt_bool_t rtgui_win_close(struct rtgui_win *win)
  285. {
  286. struct rtgui_event_win_close eclose;
  287. RTGUI_EVENT_WIN_CLOSE_INIT(&eclose);
  288. eclose.wid = win;
  289. return _rtgui_win_deal_close(win,
  290. (struct rtgui_event *)&eclose,
  291. RT_FALSE);
  292. }
  293. RTM_EXPORT(rtgui_win_close);
  294. rt_base_t rtgui_win_enter_modal(struct rtgui_win *win)
  295. {
  296. rt_base_t exit_code = -1;
  297. struct rtgui_event_win_modal_enter emodal;
  298. RTGUI_EVENT_WIN_MODAL_ENTER_INIT(&emodal);
  299. emodal.wid = win;
  300. if (rtgui_server_post_event_sync((struct rtgui_event *)&emodal,
  301. sizeof(emodal)) != RT_EOK)
  302. return exit_code;
  303. win->flag |= RTGUI_WIN_FLAG_MODAL;
  304. exit_code = rtgui_app_run(win->app);
  305. win->flag &= ~RTGUI_WIN_FLAG_MODAL;
  306. rtgui_win_hide(win);
  307. return exit_code;
  308. }
  309. RTM_EXPORT(rtgui_win_enter_modal);
  310. rt_base_t rtgui_win_do_show(struct rtgui_win *win)
  311. {
  312. rt_base_t exit_code = -1;
  313. struct rtgui_app *app;
  314. struct rtgui_event_win_show eshow;
  315. RTGUI_EVENT_WIN_SHOW_INIT(&eshow);
  316. eshow.wid = win;
  317. if (win == RT_NULL)
  318. return exit_code;
  319. win->flag &= ~RTGUI_WIN_FLAG_CLOSED;
  320. win->flag &= ~RTGUI_WIN_FLAG_CB_PRESSED;
  321. /* if it does not register into server, create it in server */
  322. if (!(win->flag & RTGUI_WIN_FLAG_CONNECTED))
  323. {
  324. if (_rtgui_win_create_in_server(win) == RT_FALSE)
  325. return exit_code;
  326. }
  327. /* set window unhidden before notify the server */
  328. rtgui_widget_show(RTGUI_WIDGET(win));
  329. if (rtgui_server_post_event_sync(RTGUI_EVENT(&eshow),
  330. sizeof(struct rtgui_event_win_show)) != RT_EOK)
  331. {
  332. /* It could not be shown if a parent window is hidden. */
  333. rtgui_widget_hide(RTGUI_WIDGET(win));
  334. return exit_code;
  335. }
  336. if (win->focused_widget == RT_NULL)
  337. rtgui_widget_focus(RTGUI_WIDGET(win));
  338. app = win->app;
  339. RT_ASSERT(app != RT_NULL);
  340. /* set main window */
  341. if (app->main_object == RT_NULL)
  342. rtgui_app_set_main_win(app, win);
  343. if (win->flag & RTGUI_WIN_FLAG_MODAL)
  344. {
  345. exit_code = rtgui_win_enter_modal(win);
  346. }
  347. return exit_code;
  348. }
  349. RTM_EXPORT(rtgui_win_do_show);
  350. rt_base_t rtgui_win_show(struct rtgui_win *win, rt_bool_t is_modal)
  351. {
  352. RTGUI_WIDGET_UNHIDE(win);
  353. if (is_modal)
  354. win->flag |= RTGUI_WIN_FLAG_MODAL;
  355. if (win->_do_show)
  356. return win->_do_show(win);
  357. return rtgui_win_do_show(win);
  358. }
  359. RTM_EXPORT(rtgui_win_show);
  360. void rtgui_win_end_modal(struct rtgui_win *win, rtgui_modal_code_t modal_code)
  361. {
  362. if (win == RT_NULL || !(win->flag & RTGUI_WIN_FLAG_MODAL))
  363. return;
  364. rtgui_app_exit(win->app, modal_code);
  365. /* remove modal mode */
  366. win->flag &= ~RTGUI_WIN_FLAG_MODAL;
  367. }
  368. RTM_EXPORT(rtgui_win_end_modal);
  369. void rtgui_win_hide(struct rtgui_win *win)
  370. {
  371. RT_ASSERT(win != RT_NULL);
  372. if (!RTGUI_WIDGET_IS_HIDE(win) &&
  373. win->flag & RTGUI_WIN_FLAG_CONNECTED)
  374. {
  375. /* send hidden message to server */
  376. struct rtgui_event_win_hide ehide;
  377. RTGUI_EVENT_WIN_HIDE_INIT(&ehide);
  378. ehide.wid = win;
  379. if (rtgui_server_post_event_sync(RTGUI_EVENT(&ehide),
  380. sizeof(struct rtgui_event_win_hide)) != RT_EOK)
  381. {
  382. rt_kprintf("hide win: %s failed\n", win->title);
  383. return;
  384. }
  385. rtgui_widget_hide(RTGUI_WIDGET(win));
  386. win->flag &= ~RTGUI_WIN_FLAG_ACTIVATE;
  387. }
  388. }
  389. RTM_EXPORT(rtgui_win_hide);
  390. rt_err_t rtgui_win_activate(struct rtgui_win *win)
  391. {
  392. struct rtgui_event_win_activate eact;
  393. RTGUI_EVENT_WIN_ACTIVATE_INIT(&eact);
  394. eact.wid = win;
  395. return rtgui_server_post_event_sync(RTGUI_EVENT(&eact),
  396. sizeof(eact));
  397. }
  398. RTM_EXPORT(rtgui_win_activate);
  399. rt_bool_t rtgui_win_is_activated(struct rtgui_win *win)
  400. {
  401. RT_ASSERT(win != RT_NULL);
  402. if (win->flag & RTGUI_WIN_FLAG_ACTIVATE) return RT_TRUE;
  403. return RT_FALSE;
  404. }
  405. RTM_EXPORT(rtgui_win_is_activated);
  406. void rtgui_win_move(struct rtgui_win *win, int x, int y)
  407. {
  408. struct rtgui_widget *wgt;
  409. struct rtgui_event_win_move emove;
  410. int dx, dy;
  411. RTGUI_EVENT_WIN_MOVE_INIT(&emove);
  412. if (win == RT_NULL)
  413. return;
  414. if (win->_title_wgt)
  415. {
  416. wgt = RTGUI_WIDGET(win->_title_wgt);
  417. dx = x - wgt->extent.x1;
  418. dy = y - wgt->extent.y1;
  419. rtgui_widget_move_to_logic(wgt, dx, dy);
  420. wgt = RTGUI_WIDGET(win);
  421. rtgui_widget_move_to_logic(wgt, dx, dy);
  422. }
  423. else
  424. {
  425. wgt = RTGUI_WIDGET(win);
  426. dx = x - wgt->extent.x1;
  427. dy = y - wgt->extent.y1;
  428. rtgui_widget_move_to_logic(wgt, dx, dy);
  429. }
  430. rtgui_rect_moveto(&win->outer_extent, dx, dy);
  431. if (win->flag & RTGUI_WIN_FLAG_CONNECTED)
  432. {
  433. rtgui_widget_hide(RTGUI_WIDGET(win));
  434. emove.wid = win;
  435. emove.x = x;
  436. emove.y = y;
  437. if (rtgui_server_post_event_sync(RTGUI_EVENT(&emove),
  438. sizeof(struct rtgui_event_win_move)) != RT_EOK)
  439. {
  440. return;
  441. }
  442. }
  443. rtgui_widget_show(RTGUI_WIDGET(win));
  444. return;
  445. }
  446. RTM_EXPORT(rtgui_win_move);
  447. static rt_bool_t rtgui_win_ondraw(struct rtgui_win *win)
  448. {
  449. struct rtgui_dc *dc;
  450. struct rtgui_rect rect;
  451. struct rtgui_event_paint event;
  452. /* begin drawing */
  453. dc = rtgui_dc_begin_drawing(RTGUI_WIDGET(win));
  454. if (dc == RT_NULL)
  455. return RT_FALSE;
  456. /* get window rect */
  457. rtgui_widget_get_rect(RTGUI_WIDGET(win), &rect);
  458. /* fill area */
  459. rtgui_dc_fill_rect(dc, &rect);
  460. rtgui_widget_onpaint(RTGUI_OBJECT(win), RT_NULL);
  461. /* paint each widget */
  462. RTGUI_EVENT_PAINT_INIT(&event);
  463. event.wid = RT_NULL;
  464. rtgui_container_dispatch_event(RTGUI_CONTAINER(win),
  465. (rtgui_event_t *)&event);
  466. rtgui_dc_end_drawing(dc);
  467. return RT_FALSE;
  468. }
  469. void rtgui_win_update_clip(struct rtgui_win *win)
  470. {
  471. struct rtgui_container *cnt;
  472. struct rtgui_list_node *node;
  473. if (win == RT_NULL)
  474. return;
  475. if (win->flag & RTGUI_WIN_FLAG_CLOSED)
  476. return;
  477. if (win->_title_wgt)
  478. {
  479. /* Reset the inner clip of title. */
  480. RTGUI_WIDGET(win->_title_wgt)->extent = win->outer_extent;
  481. rtgui_region_copy(&RTGUI_WIDGET(win->_title_wgt)->clip, &win->outer_clip);
  482. rtgui_region_subtract_rect(&RTGUI_WIDGET(win->_title_wgt)->clip,
  483. &RTGUI_WIDGET(win->_title_wgt)->clip,
  484. &RTGUI_WIDGET(win)->extent);
  485. /* Reset the inner clip of window. */
  486. rtgui_region_intersect_rect(&RTGUI_WIDGET(win)->clip,
  487. &win->outer_clip,
  488. &RTGUI_WIDGET(win)->extent);
  489. }
  490. else
  491. {
  492. RTGUI_WIDGET(win)->extent = win->outer_extent;
  493. rtgui_region_copy(&RTGUI_WIDGET(win)->clip, &win->outer_clip);
  494. }
  495. /* update the clip info of each child */
  496. cnt = RTGUI_CONTAINER(win);
  497. rtgui_list_foreach(node, &(cnt->children))
  498. {
  499. rtgui_widget_t *child = rtgui_list_entry(node, rtgui_widget_t, sibling);
  500. rtgui_widget_update_clip(child);
  501. }
  502. }
  503. RTM_EXPORT(rtgui_win_update_clip);
  504. static rt_bool_t _win_handle_mouse_btn(struct rtgui_win *win, struct rtgui_event *eve)
  505. {
  506. /* check whether has widget which handled mouse event before.
  507. *
  508. * Note #1: that the widget should have already received mouse down
  509. * event and we should only feed the mouse up event to it here.
  510. *
  511. * Note #2: the widget is responsible to clean up
  512. * last_mevent_widget on mouse up event(but not overwrite other
  513. * widgets). If not, it will receive two mouse up events.
  514. */
  515. if (((struct rtgui_event_mouse *)eve)->button & RTGUI_MOUSE_BUTTON_UP
  516. && win->last_mevent_widget != RT_NULL)
  517. {
  518. if (RTGUI_OBJECT(win->last_mevent_widget)->event_handler(
  519. RTGUI_OBJECT(win->last_mevent_widget),
  520. eve) == RT_TRUE)
  521. {
  522. /* clean last mouse event handled widget */
  523. win->last_mevent_widget = RT_NULL;
  524. return RT_TRUE;
  525. }
  526. }
  527. /** if a widget will destroy the window in the event_handler(or in
  528. * on_* callbacks), it should return RT_TRUE. Otherwise, it will
  529. * crash the application.
  530. *
  531. * TODO: add it in the doc
  532. */
  533. return rtgui_container_dispatch_mouse_event(RTGUI_CONTAINER(win),
  534. (struct rtgui_event_mouse *)eve);
  535. }
  536. rt_bool_t rtgui_win_event_handler(struct rtgui_object *object, struct rtgui_event *event)
  537. {
  538. struct rtgui_win *win;
  539. RT_ASSERT(object != RT_NULL);
  540. RT_ASSERT(event != RT_NULL);
  541. win = RTGUI_WIN(object);
  542. switch (event->type)
  543. {
  544. case RTGUI_EVENT_WIN_SHOW:
  545. rtgui_win_do_show(win);
  546. break;
  547. case RTGUI_EVENT_WIN_HIDE:
  548. rtgui_win_hide(win);
  549. break;
  550. case RTGUI_EVENT_WIN_CLOSE:
  551. _rtgui_win_deal_close(win, event, RT_FALSE);
  552. /* don't broadcast WIN_CLOSE event to others */
  553. return RT_TRUE;
  554. case RTGUI_EVENT_WIN_MOVE:
  555. {
  556. struct rtgui_event_win_move *emove = (struct rtgui_event_win_move *)event;
  557. /* move window */
  558. rtgui_win_move(win, emove->x, emove->y);
  559. }
  560. break;
  561. case RTGUI_EVENT_WIN_ACTIVATE:
  562. if (win->flag & RTGUI_WIN_FLAG_UNDER_MODAL ||
  563. RTGUI_WIDGET_IS_HIDE(win))
  564. {
  565. /* activate a hide window */
  566. return RT_TRUE;
  567. }
  568. win->flag |= RTGUI_WIN_FLAG_ACTIVATE;
  569. /* There are many cases where the paint event will follow this activate
  570. * event and just repaint the title is not a big deal. So just repaint
  571. * the title if there is one. If you want to update the content of the
  572. * window, do it in the on_activate callback.*/
  573. if (win->_title_wgt)
  574. rtgui_widget_update(RTGUI_WIDGET(win->_title_wgt));
  575. if (win->on_activate != RT_NULL)
  576. {
  577. win->on_activate(RTGUI_OBJECT(object), event);
  578. }
  579. break;
  580. case RTGUI_EVENT_WIN_DEACTIVATE:
  581. win->flag &= ~RTGUI_WIN_FLAG_ACTIVATE;
  582. /* No paint event follow the deactive event. So we have to update
  583. * the title manually to reflect the change. */
  584. if (win->_title_wgt)
  585. rtgui_widget_update(RTGUI_WIDGET(win->_title_wgt));
  586. if (win->on_deactivate != RT_NULL)
  587. win->on_deactivate(RTGUI_OBJECT(object), event);
  588. break;
  589. case RTGUI_EVENT_CLIP_INFO:
  590. /* update win clip */
  591. rtgui_win_update_clip(win);
  592. break;
  593. case RTGUI_EVENT_PAINT:
  594. if (win->_title_wgt)
  595. rtgui_widget_update(RTGUI_WIDGET(win->_title_wgt));
  596. rtgui_win_ondraw(win);
  597. break;
  598. #ifdef RTGUI_USING_VFRAMEBUFFER
  599. case RTGUI_EVENT_VPAINT_REQ:
  600. {
  601. struct rtgui_event_vpaint_req *req = (struct rtgui_event_vpaint_req *)event;
  602. struct rtgui_dc *dc;
  603. /* get drawing dc */
  604. dc = rtgui_win_get_drawing(win);
  605. req->sender->buffer = dc;
  606. rt_completion_done(req->sender->cmp);
  607. break;
  608. }
  609. #endif
  610. case RTGUI_EVENT_MOUSE_BUTTON: {
  611. struct rtgui_event_mouse *emouse = (struct rtgui_event_mouse*)event;
  612. if (rtgui_rect_contains_point(&RTGUI_WIDGET(win)->extent,
  613. emouse->x, emouse->y) == RT_EOK)
  614. return _win_handle_mouse_btn(win, event);
  615. if (win->_title_wgt)
  616. {
  617. struct rtgui_object *tobj = RTGUI_OBJECT(win->_title_wgt);
  618. return tobj->event_handler(tobj, event);
  619. }
  620. }
  621. break;
  622. case RTGUI_EVENT_MOUSE_MOTION:
  623. return rtgui_container_dispatch_mouse_event(RTGUI_CONTAINER(win),
  624. (struct rtgui_event_mouse *)event);
  625. case RTGUI_EVENT_KBD:
  626. /* we should dispatch key event firstly */
  627. if (!(win->flag & RTGUI_WIN_FLAG_HANDLE_KEY))
  628. {
  629. struct rtgui_widget *widget;
  630. rt_bool_t res = RT_FALSE;
  631. /* we should dispatch the key event just once. Once entered the
  632. * dispatch mode, we should swtich to key handling mode. */
  633. win->flag |= RTGUI_WIN_FLAG_HANDLE_KEY;
  634. /* dispatch the key event */
  635. for (widget = win->focused_widget;
  636. widget && !res;
  637. widget = widget->parent)
  638. {
  639. if (RTGUI_OBJECT(widget)->event_handler != RT_NULL)
  640. res = RTGUI_OBJECT(widget)->event_handler(
  641. RTGUI_OBJECT(widget), event);
  642. }
  643. win->flag &= ~RTGUI_WIN_FLAG_HANDLE_KEY;
  644. return res;
  645. }
  646. else
  647. {
  648. /* in key handling mode(it may reach here in
  649. * win->focused_widget->event_handler call) */
  650. if (win->on_key != RT_NULL)
  651. return win->on_key(RTGUI_OBJECT(win), event);
  652. }
  653. break;
  654. case RTGUI_EVENT_COMMAND:
  655. if (rtgui_container_dispatch_event(RTGUI_CONTAINER(object), event) != RT_TRUE)
  656. {
  657. }
  658. else return RT_TRUE;
  659. break;
  660. default:
  661. return rtgui_container_event_handler(object, event);
  662. }
  663. return RT_FALSE;
  664. }
  665. RTM_EXPORT(rtgui_win_event_handler);
  666. void rtgui_win_set_rect(rtgui_win_t *win, rtgui_rect_t *rect)
  667. {
  668. struct rtgui_event_win_resize event;
  669. if (win == RT_NULL || rect == RT_NULL) return;
  670. RTGUI_WIDGET(win)->extent = *rect;
  671. if (win->flag & RTGUI_WIN_FLAG_CONNECTED)
  672. {
  673. /* set window resize event to server */
  674. RTGUI_EVENT_WIN_RESIZE_INIT(&event);
  675. event.wid = win;
  676. event.rect = *rect;
  677. rtgui_server_post_event(&(event.parent), sizeof(struct rtgui_event_win_resize));
  678. }
  679. }
  680. RTM_EXPORT(rtgui_win_set_rect);
  681. void rtgui_win_set_onactivate(rtgui_win_t *win, rtgui_event_handler_ptr handler)
  682. {
  683. if (win != RT_NULL)
  684. {
  685. win->on_activate = handler;
  686. }
  687. }
  688. RTM_EXPORT(rtgui_win_set_onactivate);
  689. void rtgui_win_set_ondeactivate(rtgui_win_t *win, rtgui_event_handler_ptr handler)
  690. {
  691. if (win != RT_NULL)
  692. {
  693. win->on_deactivate = handler;
  694. }
  695. }
  696. RTM_EXPORT(rtgui_win_set_ondeactivate);
  697. void rtgui_win_set_onclose(rtgui_win_t *win, rtgui_event_handler_ptr handler)
  698. {
  699. if (win != RT_NULL)
  700. {
  701. win->on_close = handler;
  702. }
  703. }
  704. RTM_EXPORT(rtgui_win_set_onclose);
  705. void rtgui_win_set_onkey(rtgui_win_t *win, rtgui_event_handler_ptr handler)
  706. {
  707. if (win != RT_NULL)
  708. {
  709. win->on_key = handler;
  710. }
  711. }
  712. RTM_EXPORT(rtgui_win_set_onkey);
  713. void rtgui_win_set_title(rtgui_win_t *win, const char *title)
  714. {
  715. /* send title to server */
  716. if (win->flag & RTGUI_WIN_FLAG_CONNECTED)
  717. {
  718. }
  719. /* modify in local side */
  720. if (win->title != RT_NULL)
  721. {
  722. rtgui_free(win->title);
  723. win->title = RT_NULL;
  724. }
  725. if (title != RT_NULL)
  726. {
  727. win->title = rt_strdup(title);
  728. }
  729. }
  730. RTM_EXPORT(rtgui_win_set_title);
  731. char *rtgui_win_get_title(rtgui_win_t *win)
  732. {
  733. RT_ASSERT(win != RT_NULL);
  734. return win->title;
  735. }
  736. RTM_EXPORT(rtgui_win_get_title);
  737. #ifdef RTGUI_USING_VFRAMEBUFFER
  738. #include <rtgui/driver.h>
  739. struct rtgui_dc *rtgui_win_get_drawing(rtgui_win_t * win)
  740. {
  741. struct rtgui_dc *dc;
  742. struct rtgui_rect rect;
  743. if (rtgui_app_self() == RT_NULL)
  744. return RT_NULL;
  745. if (win == RT_NULL || !(win->flag & RTGUI_WIN_FLAG_CONNECTED))
  746. return RT_NULL;
  747. if (win->app == rtgui_app_self())
  748. {
  749. /* under the same application context */
  750. rtgui_region_t region;
  751. rtgui_region_t clip_region;
  752. rtgui_region_init(&clip_region);
  753. rtgui_region_copy(&clip_region, &win->outer_clip);
  754. rtgui_graphic_driver_vmode_enter();
  755. rtgui_graphic_driver_get_rect(RT_NULL, &rect);
  756. region.data = RT_NULL;
  757. region.extents.x1 = rect.x1;
  758. region.extents.y1 = rect.y1;
  759. region.extents.x2 = rect.x2;
  760. region.extents.y2 = rect.y2;
  761. /* remove clip */
  762. rtgui_region_reset(&win->outer_clip,
  763. &RTGUI_WIDGET(win)->extent);
  764. rtgui_region_intersect(&win->outer_clip,
  765. &win->outer_clip,
  766. &region);
  767. rtgui_win_update_clip(win);
  768. /* use virtual framebuffer */
  769. rtgui_widget_update(RTGUI_WIDGET(win));
  770. /* get the extent of widget */
  771. rtgui_widget_get_extent(RTGUI_WIDGET(win), &rect);
  772. dc = rtgui_graphic_driver_get_rect_buffer(RT_NULL, &rect);
  773. rtgui_graphic_driver_vmode_exit();
  774. /* restore the clip information of window */
  775. rtgui_region_reset(&RTGUI_WIDGET(win)->clip,
  776. &RTGUI_WIDGET(win)->extent);
  777. rtgui_region_intersect(&(RTGUI_WIDGET(win)->clip),
  778. &(RTGUI_WIDGET(win)->clip),
  779. &clip_region);
  780. rtgui_region_fini(&region);
  781. rtgui_region_fini(&clip_region);
  782. rtgui_win_update_clip(win);
  783. }
  784. else
  785. {
  786. /* send vpaint_req to the window and wait for response */
  787. struct rtgui_event_vpaint_req req;
  788. struct rt_completion cmp;
  789. int freeze;
  790. /* make sure the screen is not locked. */
  791. freeze = rtgui_screen_lock_freeze();
  792. RTGUI_EVENT_VPAINT_REQ_INIT(&req, win, &cmp);
  793. rtgui_send(win->app, &(req.parent), sizeof(struct rtgui_event_vpaint_req));
  794. rt_completion_wait(req.cmp, RT_WAITING_FOREVER);
  795. /* wait for vpaint_ack event */
  796. dc = req.buffer;
  797. rtgui_screen_lock_thaw(freeze);
  798. }
  799. return dc;
  800. }
  801. RTM_EXPORT(rtgui_win_get_drawing);
  802. #endif
  803. static const rt_uint8_t close_byte[14] = {
  804. 0x06, 0x18, 0x03, 0x30, 0x01, 0xE0, 0x00,
  805. 0xC0, 0x01, 0xE0, 0x03, 0x30, 0x06, 0x18
  806. };
  807. /* window drawing */
  808. void rtgui_theme_draw_win(struct rtgui_wintitle *wint)
  809. {
  810. struct rtgui_dc *dc;
  811. struct rtgui_win *win;
  812. rtgui_rect_t rect;
  813. if (!wint)
  814. return;
  815. win = RTGUI_WIDGET(wint)->toplevel;
  816. RT_ASSERT(win);
  817. if (win->_title_wgt == RT_NULL)
  818. return;
  819. /* begin drawing */
  820. dc = rtgui_dc_begin_drawing(RTGUI_WIDGET(win->_title_wgt));
  821. if (dc == RT_NULL)
  822. return;
  823. /* get rect */
  824. rtgui_widget_get_rect(RTGUI_WIDGET(win->_title_wgt), &rect);
  825. /* draw border */
  826. if (!(win->style & RTGUI_WIN_STYLE_NO_BORDER))
  827. {
  828. rect.x2 -= 1;
  829. rect.y2 -= 1;
  830. RTGUI_WIDGET_FOREGROUND(win->_title_wgt) = RTGUI_RGB(212, 208, 200);
  831. rtgui_dc_draw_hline(dc, rect.x1, rect.x2, rect.y1);
  832. rtgui_dc_draw_vline(dc, rect.x1, rect.y1, rect.y2);
  833. RTGUI_WIDGET_FOREGROUND(win->_title_wgt) = white;
  834. rtgui_dc_draw_hline(dc, rect.x1 + 1, rect.x2 - 1, rect.y1 + 1);
  835. rtgui_dc_draw_vline(dc, rect.x1 + 1, rect.y1 + 1, rect.y2 - 1);
  836. RTGUI_WIDGET_FOREGROUND(win->_title_wgt) = RTGUI_RGB(128, 128, 128);
  837. rtgui_dc_draw_hline(dc, rect.x1 + 1, rect.x2 - 1, rect.y2 - 1);
  838. rtgui_dc_draw_vline(dc, rect.x2 - 1, rect.y1 + 1, rect.y2);
  839. RTGUI_WIDGET_FOREGROUND(win->_title_wgt) = RTGUI_RGB(64, 64, 64);
  840. rtgui_dc_draw_hline(dc, rect.x1, rect.x2, rect.y2);
  841. rtgui_dc_draw_vline(dc, rect.x2, rect.y1, rect.y2 + 1);
  842. /* shrink border */
  843. rtgui_rect_inflate(&rect, -WINTITLE_BORDER_SIZE);
  844. }
  845. /* draw title */
  846. if (!(win->style & RTGUI_WIN_STYLE_NO_TITLE))
  847. {
  848. rt_uint16_t index;
  849. rt_uint16_t r, g, b, delta;
  850. #define RGB_FACTOR 4
  851. if (win->flag & RTGUI_WIN_FLAG_ACTIVATE)
  852. {
  853. r = 10 << RGB_FACTOR;
  854. g = 36 << RGB_FACTOR;
  855. b = 106 << RGB_FACTOR;
  856. delta = (150 << RGB_FACTOR) / (rect.x2 - rect.x1);
  857. }
  858. else
  859. {
  860. r = 128 << RGB_FACTOR;
  861. g = 128 << RGB_FACTOR;
  862. b = 128 << RGB_FACTOR;
  863. delta = (64 << RGB_FACTOR) / (rect.x2 - rect.x1);
  864. }
  865. for (index = rect.x1; index < rect.x2 + 1; index ++)
  866. {
  867. RTGUI_WIDGET_FOREGROUND(win->_title_wgt) = RTGUI_RGB((r>>RGB_FACTOR),
  868. (g>>RGB_FACTOR),
  869. (b>>RGB_FACTOR));
  870. rtgui_dc_draw_vline(dc, index, rect.y1, rect.y2);
  871. r += delta;
  872. g += delta;
  873. b += delta;
  874. }
  875. #undef RGB_FACTOR
  876. if (win->flag & RTGUI_WIN_FLAG_ACTIVATE)
  877. {
  878. RTGUI_WIDGET_FOREGROUND(win->_title_wgt) = white;
  879. }
  880. else
  881. {
  882. RTGUI_WIDGET_FOREGROUND(win->_title_wgt) = RTGUI_RGB(212, 208, 200);
  883. }
  884. rect.x1 += 4;
  885. rect.y1 += 2;
  886. rect.y2 = rect.y1 + WINTITLE_CB_HEIGHT;
  887. rtgui_dc_draw_text(dc, win->title, &rect);
  888. if (win->style & RTGUI_WIN_STYLE_CLOSEBOX)
  889. {
  890. /* get close button rect */
  891. rtgui_rect_t box_rect = {0, 0, WINTITLE_CB_WIDTH, WINTITLE_CB_HEIGHT};
  892. rtgui_rect_moveto_align(&rect, &box_rect, RTGUI_ALIGN_CENTER_VERTICAL | RTGUI_ALIGN_RIGHT);
  893. box_rect.x1 -= 3;
  894. box_rect.x2 -= 3;
  895. rtgui_dc_fill_rect(dc, &box_rect);
  896. /* draw close box */
  897. if (win->flag & RTGUI_WIN_FLAG_CB_PRESSED)
  898. {
  899. rtgui_dc_draw_border(dc, &box_rect, RTGUI_BORDER_SUNKEN);
  900. RTGUI_WIDGET_FOREGROUND(win->_title_wgt) = red;
  901. rtgui_dc_draw_word(dc, box_rect.x1, box_rect.y1 + 6, 7, close_byte);
  902. }
  903. else
  904. {
  905. rtgui_dc_draw_border(dc, &box_rect, RTGUI_BORDER_RAISE);
  906. RTGUI_WIDGET_FOREGROUND(win->_title_wgt) = black;
  907. rtgui_dc_draw_word(dc, box_rect.x1 - 1, box_rect.y1 + 5, 7, close_byte);
  908. }
  909. }
  910. }
  911. rtgui_dc_end_drawing(dc);
  912. }