window.c 15 KB

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