window.c 31 KB

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