window.c 32 KB

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