window.c 15 KB

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