window.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  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. static void _rtgui_win_constructor(rtgui_win_t *win)
  23. {
  24. RTGUI_WIDGET(win)->flag |= RTGUI_WIDGET_FLAG_FOCUSABLE;
  25. win->parent_window = RT_NULL;
  26. /* init window attribute */
  27. win->on_activate = RT_NULL;
  28. win->on_deactivate = RT_NULL;
  29. win->on_close = RT_NULL;
  30. win->on_key = RT_NULL;
  31. win->title = RT_NULL;
  32. win->modal_code = RTGUI_MODAL_OK;
  33. /* initialize last mouse event handled widget */
  34. win->last_mevent_widget = RT_NULL;
  35. win->focused_widget = RT_NULL;
  36. /* set window hide */
  37. RTGUI_WIDGET_HIDE(RTGUI_WIDGET(win));
  38. /* set window style */
  39. win->style = RTGUI_WIN_STYLE_DEFAULT;
  40. win->flag = RTGUI_WIN_FLAG_INIT;
  41. rtgui_object_set_event_handler(RTGUI_OBJECT(win), rtgui_win_event_handler);
  42. /* init user data */
  43. win->user_data = 0;
  44. }
  45. static void _rtgui_win_destructor(rtgui_win_t* win)
  46. {
  47. struct rtgui_event_win_destroy edestroy;
  48. if (win->flag & RTGUI_WIN_FLAG_CONNECTED)
  49. {
  50. /* destroy in server */
  51. RTGUI_EVENT_WIN_DESTROY_INIT(&edestroy);
  52. edestroy.wid = win;
  53. if (rtgui_server_post_event_sync(RTGUI_EVENT(&edestroy),
  54. sizeof(struct rtgui_event_win_destroy)) != RT_EOK)
  55. {
  56. /* destroy in server failed */
  57. return;
  58. }
  59. }
  60. /* release field */
  61. rt_free(win->title);
  62. }
  63. static rt_bool_t _rtgui_win_create_in_server(struct rtgui_win *win)
  64. {
  65. if (!(win->flag & RTGUI_WIN_FLAG_CONNECTED))
  66. {
  67. struct rtgui_event_win_create ecreate;
  68. RTGUI_EVENT_WIN_CREATE_INIT(&ecreate);
  69. /* send win create event to server */
  70. ecreate.parent_window = win->parent_window;
  71. ecreate.wid = win;
  72. ecreate.parent.user = win->style;
  73. #ifndef RTGUI_USING_SMALL_SIZE
  74. ecreate.extent = RTGUI_WIDGET(win)->extent;
  75. rt_strncpy((char*)ecreate.title, (char*)win->title, RTGUI_NAME_MAX);
  76. #endif
  77. if (rtgui_server_post_event_sync(RTGUI_EVENT(&ecreate),
  78. sizeof(struct rtgui_event_win_create)
  79. ) != RT_EOK)
  80. {
  81. rt_kprintf("create win: %s failed\n", win->title);
  82. return RT_FALSE;
  83. }
  84. win->flag |= RTGUI_WIN_FLAG_CONNECTED;
  85. }
  86. return RT_TRUE;
  87. }
  88. DEFINE_CLASS_TYPE(win, "win",
  89. RTGUI_TOPLEVEL_TYPE,
  90. _rtgui_win_constructor,
  91. _rtgui_win_destructor,
  92. sizeof(struct rtgui_win));
  93. rtgui_win_t* rtgui_win_create(struct rtgui_win* parent_window,
  94. const char* title,
  95. rtgui_rect_t *rect,
  96. rt_uint16_t style)
  97. {
  98. struct rtgui_win* win;
  99. /* allocate win memory */
  100. win = RTGUI_WIN(rtgui_widget_create(RTGUI_WIN_TYPE));
  101. if (win == RT_NULL)
  102. return RT_NULL;
  103. /* set parent toplevel */
  104. win->parent_window = parent_window;
  105. /* set title, rect and style */
  106. if (title != RT_NULL)
  107. win->title = rt_strdup(title);
  108. else
  109. win->title = RT_NULL;
  110. rtgui_widget_set_rect(RTGUI_WIDGET(win), rect);
  111. win->style = style;
  112. if (_rtgui_win_create_in_server(win) == RT_FALSE)
  113. {
  114. goto __on_err;
  115. }
  116. return win;
  117. __on_err:
  118. rtgui_widget_destroy(RTGUI_WIDGET(win));
  119. return RT_NULL;
  120. }
  121. static rt_bool_t _rtgui_win_deal_close(struct rtgui_win *win,
  122. struct rtgui_event *event,
  123. rt_bool_t force_close)
  124. {
  125. if (win->on_close != RT_NULL)
  126. {
  127. if ((win->on_close(RTGUI_OBJECT(win), event) == RT_FALSE) && !force_close)
  128. return RT_FALSE;
  129. }
  130. rtgui_win_hiden(win);
  131. win->flag |= RTGUI_WIN_FLAG_CLOSED;
  132. if (win->flag & RTGUI_WIN_FLAG_MODAL)
  133. {
  134. rtgui_win_end_modal(win, RTGUI_MODAL_CANCEL);
  135. }
  136. else if (win->style & RTGUI_WIN_STYLE_DESTROY_ON_CLOSE)
  137. {
  138. rtgui_win_destroy(win);
  139. }
  140. return RT_TRUE;
  141. }
  142. void rtgui_win_destroy(struct rtgui_win* win)
  143. {
  144. /* close the window first if it's not. */
  145. if (!(win->flag & RTGUI_WIN_FLAG_CLOSED))
  146. {
  147. struct rtgui_event_win_close eclose;
  148. RTGUI_EVENT_WIN_CLOSE_INIT(&eclose);
  149. eclose.wid = win;
  150. if (win->style & RTGUI_WIN_STYLE_DESTROY_ON_CLOSE)
  151. {
  152. _rtgui_win_deal_close(win,
  153. (struct rtgui_event*)&eclose,
  154. RT_TRUE);
  155. return;
  156. }
  157. else
  158. _rtgui_win_deal_close(win,
  159. (struct rtgui_event*)&eclose,
  160. RT_TRUE);
  161. }
  162. if (win->flag & RTGUI_WIN_FLAG_MODAL)
  163. {
  164. /* set the RTGUI_WIN_STYLE_DESTROY_ON_CLOSE flag so the window will be
  165. * destroyed after the event_loop */
  166. win->style |= RTGUI_WIN_STYLE_DESTROY_ON_CLOSE;
  167. rtgui_win_end_modal(win, RTGUI_MODAL_CANCEL);
  168. }
  169. else
  170. {
  171. rtgui_widget_destroy(RTGUI_WIDGET(win));
  172. }
  173. }
  174. /* send a close event to myself to get a consistent behavior */
  175. rt_bool_t rtgui_win_close(struct rtgui_win* win)
  176. {
  177. struct rtgui_event_win_close eclose;
  178. RTGUI_EVENT_WIN_CLOSE_INIT(&eclose);
  179. eclose.wid = win;
  180. return _rtgui_win_deal_close(win,
  181. (struct rtgui_event*)&eclose,
  182. RT_FALSE);
  183. }
  184. rt_base_t rtgui_win_show(struct rtgui_win* win, rt_bool_t is_modal)
  185. {
  186. rt_base_t exit_code = -1;
  187. struct rtgui_app *app;
  188. struct rtgui_event_win_show eshow;
  189. app = rtgui_app_self();
  190. RTGUI_EVENT_WIN_SHOW_INIT(&eshow);
  191. eshow.wid = win;
  192. if (win == RT_NULL)
  193. return exit_code;
  194. /* if it does not register into server, create it in server */
  195. if (!(win->flag & RTGUI_WIN_FLAG_CONNECTED))
  196. {
  197. if (_rtgui_win_create_in_server(win) == RT_FALSE)
  198. return exit_code;
  199. }
  200. /* set window unhidden before notify the server */
  201. rtgui_widget_show(RTGUI_WIDGET(win));
  202. if (rtgui_server_post_event_sync(RTGUI_EVENT(&eshow),
  203. sizeof(struct rtgui_event_win_show)) != RT_EOK)
  204. {
  205. /* It could not be shown if a parent window is hidden. */
  206. rtgui_widget_hide(RTGUI_WIDGET(win));
  207. return exit_code;
  208. }
  209. if (win->focused_widget == RT_NULL)
  210. rtgui_widget_focus(RTGUI_WIDGET(win));
  211. /* set main window */
  212. if (app->main_object == RT_NULL)
  213. rtgui_app_set_main_win(win);
  214. if (is_modal == RT_TRUE)
  215. {
  216. struct rtgui_app *app;
  217. struct rtgui_event_win_modal_enter emodal;
  218. RTGUI_EVENT_WIN_MODAL_ENTER_INIT(&emodal);
  219. emodal.wid = win;
  220. app = rtgui_app_self();
  221. RT_ASSERT(app != RT_NULL);
  222. win->flag |= RTGUI_WIN_FLAG_MODAL;
  223. if (rtgui_server_post_event_sync((struct rtgui_event*)&emodal,
  224. sizeof(emodal)) != RT_EOK)
  225. return exit_code;
  226. app->modal_object = RTGUI_OBJECT(win);
  227. exit_code = rtgui_app_run(app);
  228. app->modal_object = RT_NULL;
  229. win->flag &= ~RTGUI_WIN_FLAG_MODAL;
  230. if (win->style & RTGUI_WIN_STYLE_DESTROY_ON_CLOSE)
  231. {
  232. rtgui_win_destroy(win);
  233. }
  234. }
  235. return exit_code;
  236. }
  237. void rtgui_win_end_modal(struct rtgui_win* win, rtgui_modal_code_t modal_code)
  238. {
  239. if (win == RT_NULL || !(win->flag & RTGUI_WIN_FLAG_MODAL))
  240. return;
  241. rtgui_app_exit(rtgui_app_self(), modal_code);
  242. /* remove modal mode */
  243. win->flag &= ~RTGUI_WIN_FLAG_MODAL;
  244. }
  245. void rtgui_win_hiden(struct rtgui_win* win)
  246. {
  247. RT_ASSERT(win != RT_NULL);
  248. if (!RTGUI_WIDGET_IS_HIDE(RTGUI_WIDGET(win)) &&
  249. win->flag & RTGUI_WIN_FLAG_CONNECTED)
  250. {
  251. /* send hidden message to server */
  252. struct rtgui_event_win_hide ehide;
  253. RTGUI_EVENT_WIN_HIDE_INIT(&ehide);
  254. ehide.wid = win;
  255. if (rtgui_server_post_event_sync(RTGUI_EVENT(&ehide),
  256. sizeof(struct rtgui_event_win_hide)) != RT_EOK)
  257. {
  258. rt_kprintf("hide win: %s failed\n", win->title);
  259. return;
  260. }
  261. rtgui_widget_hide(RTGUI_WIDGET(win));
  262. win->flag &= ~RTGUI_WIN_FLAG_ACTIVATE;
  263. }
  264. }
  265. rt_err_t rtgui_win_activate(struct rtgui_win *win)
  266. {
  267. struct rtgui_event_win_activate eact;
  268. RTGUI_EVENT_WIN_ACTIVATE_INIT(&eact);
  269. eact.wid = win;
  270. return rtgui_server_post_event_sync(RTGUI_EVENT(&eact),
  271. sizeof(eact));
  272. }
  273. rt_bool_t rtgui_win_is_activated(struct rtgui_win* win)
  274. {
  275. RT_ASSERT(win != RT_NULL);
  276. if (win->flag & RTGUI_WIN_FLAG_ACTIVATE) return RT_TRUE;
  277. return RT_FALSE;
  278. }
  279. void rtgui_win_move(struct rtgui_win* win, int x, int y)
  280. {
  281. struct rtgui_event_win_move emove;
  282. RTGUI_EVENT_WIN_MOVE_INIT(&emove);
  283. if (win == RT_NULL)
  284. return;
  285. /* move window to logic position */
  286. rtgui_widget_move_to_logic(RTGUI_WIDGET(win),
  287. x - RTGUI_WIDGET(win)->extent.x1,
  288. y - RTGUI_WIDGET(win)->extent.y1);
  289. if (win->flag & RTGUI_WIN_FLAG_CONNECTED)
  290. {
  291. /* set win hide firstly */
  292. rtgui_widget_hide(RTGUI_WIDGET(win));
  293. emove.wid = win;
  294. emove.x = x;
  295. emove.y = y;
  296. if (rtgui_server_post_event_sync(RTGUI_EVENT(&emove),
  297. sizeof(struct rtgui_event_win_move)) != RT_EOK)
  298. {
  299. return;
  300. }
  301. }
  302. /* set window visible */
  303. rtgui_widget_show(RTGUI_WIDGET(win));
  304. return;
  305. }
  306. static rt_bool_t rtgui_win_ondraw(struct rtgui_win* win)
  307. {
  308. struct rtgui_dc* dc;
  309. struct rtgui_rect rect;
  310. struct rtgui_event_paint event;
  311. /* begin drawing */
  312. dc = rtgui_dc_begin_drawing(RTGUI_WIDGET(win));
  313. if (dc == RT_NULL)
  314. return RT_FALSE;
  315. /* get window rect */
  316. rtgui_widget_get_rect(RTGUI_WIDGET(win), &rect);
  317. /* fill area */
  318. rtgui_dc_fill_rect(dc, &rect);
  319. /* paint each widget */
  320. RTGUI_EVENT_PAINT_INIT(&event);
  321. event.wid = RT_NULL;
  322. rtgui_container_dispatch_event(RTGUI_CONTAINER(win),
  323. (rtgui_event_t*)&event);
  324. rtgui_dc_end_drawing(dc);
  325. return RT_FALSE;
  326. }
  327. rt_bool_t rtgui_win_event_handler(struct rtgui_object* object, struct rtgui_event* event)
  328. {
  329. struct rtgui_win* win;
  330. RT_ASSERT(object != RT_NULL);
  331. RT_ASSERT(event != RT_NULL);
  332. win = RTGUI_WIN(object);
  333. switch (event->type)
  334. {
  335. case RTGUI_EVENT_WIN_SHOW:
  336. rtgui_win_show(win, RT_FALSE);
  337. break;
  338. case RTGUI_EVENT_WIN_HIDE:
  339. rtgui_win_hiden(win);
  340. break;
  341. case RTGUI_EVENT_WIN_CLOSE:
  342. _rtgui_win_deal_close(win, event, RT_FALSE);
  343. /* don't broadcast WIN_CLOSE event to others */
  344. return RT_TRUE;
  345. case RTGUI_EVENT_WIN_MOVE:
  346. {
  347. struct rtgui_event_win_move* emove = (struct rtgui_event_win_move*)event;
  348. /* move window */
  349. rtgui_win_move(win, emove->x, emove->y);
  350. }
  351. break;
  352. case RTGUI_EVENT_WIN_ACTIVATE:
  353. if (RTGUI_WIDGET_IS_HIDE(RTGUI_WIDGET(win)))
  354. {
  355. /* activate a hide window */
  356. return RT_TRUE;
  357. }
  358. win->flag |= RTGUI_WIN_FLAG_ACTIVATE;
  359. #ifndef RTGUI_USING_SMALL_SIZE
  360. if (RTGUI_WIDGET(object)->on_draw != RT_NULL)
  361. RTGUI_WIDGET(object)->on_draw(object, event);
  362. else
  363. #endif
  364. rtgui_widget_update(RTGUI_WIDGET(win));
  365. if (win->on_activate != RT_NULL)
  366. {
  367. win->on_activate(RTGUI_OBJECT(object), event);
  368. }
  369. break;
  370. case RTGUI_EVENT_WIN_DEACTIVATE:
  371. if (win->flag & RTGUI_WIN_FLAG_MODAL)
  372. {
  373. /* FIXME: make modal concept clear and easy. See the comment of
  374. * rtgui_topwin_modal_enter. */
  375. /* There are various reason that a modal window got deactivated:
  376. * 1, it has child windows and the user activate one of them.
  377. * 2, the application has more than one root window and the
  378. * user switched to one of the others.
  379. *
  380. * In any of the cases, we have nothing to do here.
  381. */
  382. }
  383. else
  384. {
  385. win->flag &= ~RTGUI_WIN_FLAG_ACTIVATE;
  386. #ifndef RTGUI_USING_SMALL_SIZE
  387. if (RTGUI_WIDGET(object)->on_draw != RT_NULL)
  388. RTGUI_WIDGET(object)->on_draw(object, event);
  389. else
  390. #endif
  391. rtgui_widget_update(RTGUI_WIDGET(win));
  392. if (win->on_deactivate != RT_NULL)
  393. {
  394. win->on_deactivate(RTGUI_OBJECT(object), event);
  395. }
  396. }
  397. break;
  398. case RTGUI_EVENT_PAINT:
  399. #ifndef RTGUI_USING_SMALL_SIZE
  400. if (RTGUI_WIDGET(object)->on_draw != RT_NULL)
  401. RTGUI_WIDGET(object)->on_draw(object, event);
  402. else
  403. #endif
  404. rtgui_win_ondraw(win);
  405. break;
  406. case RTGUI_EVENT_MOUSE_BUTTON:
  407. /* check whether has widget which handled mouse event before */
  408. if (win->last_mevent_widget != RT_NULL)
  409. {
  410. RTGUI_OBJECT(win->last_mevent_widget)->event_handler(
  411. RTGUI_OBJECT(win->last_mevent_widget),
  412. event);
  413. /* clean last mouse event handled widget */
  414. win->last_mevent_widget = RT_NULL;
  415. }
  416. else if (rtgui_container_dispatch_mouse_event(RTGUI_CONTAINER(win),
  417. (struct rtgui_event_mouse*)event) == RT_FALSE)
  418. {
  419. #ifndef RTGUI_USING_SMALL_SIZE
  420. if (RTGUI_WIDGET(object)->on_mouseclick != RT_NULL)
  421. {
  422. return RTGUI_WIDGET(object)->on_mouseclick(object, event);
  423. }
  424. #endif
  425. }
  426. break;
  427. case RTGUI_EVENT_MOUSE_MOTION:
  428. #if 0
  429. if (rtgui_widget_dispatch_mouse_event(widget,
  430. (struct rtgui_event_mouse*)event) == RT_FALSE)
  431. {
  432. #ifndef RTGUI_USING_SMALL_SIZE
  433. /* handle event in current widget */
  434. if (widget->on_mousemotion != RT_NULL)
  435. {
  436. return widget->on_mousemotion(widget, event);
  437. }
  438. #endif
  439. }
  440. else return RT_TRUE;
  441. #endif
  442. break;
  443. case RTGUI_EVENT_KBD:
  444. /* we should dispatch key event firstly */
  445. if (!(win->flag & RTGUI_WIN_FLAG_HANDLE_KEY))
  446. {
  447. struct rtgui_widget *widget;
  448. rt_bool_t res = RT_FALSE;
  449. /* we should dispatch the key event just once. Once entered the
  450. * dispatch mode, we should swtich to key handling mode. */
  451. win->flag |= RTGUI_WIN_FLAG_HANDLE_KEY;
  452. /* dispatch the key event */
  453. for (widget = win->focused_widget;
  454. widget && !res;
  455. widget = widget->parent)
  456. {
  457. if (RTGUI_OBJECT(widget)->event_handler != RT_NULL)
  458. res = RTGUI_OBJECT(widget)->event_handler(
  459. RTGUI_OBJECT(widget), event);
  460. }
  461. win->flag &= ~RTGUI_WIN_FLAG_HANDLE_KEY;
  462. return res;
  463. }
  464. else
  465. {
  466. /* in key handling mode(it may reach here in
  467. * win->focused_widget->event_handler call) */
  468. if (win->on_key != RT_NULL)
  469. return win->on_key(RTGUI_OBJECT(win), event);
  470. }
  471. break;
  472. default:
  473. /* call parent event handler */
  474. return rtgui_toplevel_event_handler(object, event);
  475. }
  476. return RT_FALSE;
  477. }
  478. void rtgui_win_set_rect(rtgui_win_t* win, rtgui_rect_t* rect)
  479. {
  480. struct rtgui_event_win_resize event;
  481. if (win == RT_NULL || rect == RT_NULL) return;
  482. RTGUI_WIDGET(win)->extent = *rect;
  483. if (win->flag & RTGUI_WIN_FLAG_CONNECTED)
  484. {
  485. /* set window resize event to server */
  486. RTGUI_EVENT_WIN_RESIZE_INIT(&event);
  487. event.wid = win;
  488. event.rect = *rect;
  489. rtgui_server_post_event(&(event.parent), sizeof(struct rtgui_event_win_resize));
  490. }
  491. }
  492. void rtgui_win_set_onactivate(rtgui_win_t* win, rtgui_event_handler_ptr handler)
  493. {
  494. if (win != RT_NULL)
  495. {
  496. win->on_activate = handler;
  497. }
  498. }
  499. void rtgui_win_set_ondeactivate(rtgui_win_t* win, rtgui_event_handler_ptr handler)
  500. {
  501. if (win != RT_NULL)
  502. {
  503. win->on_deactivate = handler;
  504. }
  505. }
  506. void rtgui_win_set_onclose(rtgui_win_t* win, rtgui_event_handler_ptr handler)
  507. {
  508. if (win != RT_NULL)
  509. {
  510. win->on_close = handler;
  511. }
  512. }
  513. void rtgui_win_set_onkey(rtgui_win_t* win, rtgui_event_handler_ptr handler)
  514. {
  515. if (win != RT_NULL)
  516. {
  517. win->on_key = handler;
  518. }
  519. }
  520. void rtgui_win_set_title(rtgui_win_t* win, const char *title)
  521. {
  522. /* send title to server */
  523. if (win->flag & RTGUI_WIN_FLAG_CONNECTED)
  524. {
  525. }
  526. /* modify in local side */
  527. if (win->title != RT_NULL)
  528. {
  529. rtgui_free(win->title);
  530. win->title = RT_NULL;
  531. }
  532. if (title != RT_NULL)
  533. {
  534. win->title = rt_strdup(title);
  535. }
  536. }
  537. char* rtgui_win_get_title(rtgui_win_t* win)
  538. {
  539. RT_ASSERT(win != RT_NULL);
  540. return win->title;
  541. }