topwin.c 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174
  1. /*
  2. * File : topwin.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-16 Bernard first version
  23. * 2012-02-25 Grissiom rewrite topwin implementation
  24. */
  25. #include "topwin.h"
  26. #include "mouse.h"
  27. #include <rtservice.h>
  28. #include <rtgui/event.h>
  29. #include <rtgui/image.h>
  30. //#include <rtgui/rtgui_theme.h>
  31. #include <rtgui/rtgui_system.h>
  32. #include <rtgui/rtgui_app.h>
  33. #include <rtgui/widgets/window.h>
  34. #include <rtgui/widgets/container.h>
  35. /*
  36. * windows tree in the server side.
  37. *
  38. * This list is divided into two parts. The first part is the shown list, in
  39. * which all the windows have the WINTITLE_SHOWN flag set. Second part is the
  40. * hidden items, in which all the windows don't have WINTITLE_SHOWN flag.
  41. *
  42. * The active window is the one that would receive kbd events. It should always
  43. * be in the first tree. The order of this list is the order of the windows.
  44. * Top window can always clip the window beneath it when the two
  45. * overlapping. Child window can always clip it's parent. Slibing windows can
  46. * clip each other with the same rule as this list. Each child list is the same
  47. * as _rtgui_topwin_list. This forms the hierarchy tree structure of all
  48. * windows.
  49. *
  50. * Thus, the left most leaf of the tree is the top most window and the right
  51. * most root node is the bottom window. The hidden part have no specific
  52. * order.
  53. */
  54. #define get_topwin_from_list(list_entry) (rt_list_entry((list_entry), struct rtgui_topwin, list))
  55. /* the direction can only be next or prev. If you want to iterate the list in
  56. * normal order, use next. If you want to iterate the list with reverse order,
  57. * use prev.*/
  58. #define rt_list_foreach(node, list, direction) \
  59. for ((node) = (list)->direction; (node) != list; (node) = (node)->direction)
  60. #define IS_ROOT_WIN(topwin) ((topwin)->parent == RT_NULL)
  61. static rt_list_t _rtgui_topwin_list = RT_LIST_OBJECT_INIT(_rtgui_topwin_list);
  62. static struct rt_semaphore _rtgui_topwin_lock;
  63. static void rtgui_topwin_update_clip(void);
  64. static void rtgui_topwin_redraw(struct rtgui_rect *rect);
  65. static void _rtgui_topwin_activate_next(enum rtgui_topwin_flag);
  66. void rtgui_topwin_init(void)
  67. {
  68. /* initialize semaphore */
  69. rt_sem_init(&_rtgui_topwin_lock, "wintree", 1, RT_IPC_FLAG_FIFO);
  70. }
  71. static struct rtgui_topwin *rtgui_topwin_search_in_list(struct rtgui_win *window,
  72. struct rt_list_node *list)
  73. {
  74. /* TODO: use a cache to speed up the search. */
  75. struct rt_list_node *node;
  76. struct rtgui_topwin *topwin;
  77. /* the action is tend to operate on the top most window. So we search in a
  78. * depth first order.
  79. */
  80. rt_list_foreach(node, list, next)
  81. {
  82. topwin = rt_list_entry(node, struct rtgui_topwin, list);
  83. /* is this node? */
  84. if (topwin->wid == window)
  85. {
  86. return topwin;
  87. }
  88. topwin = rtgui_topwin_search_in_list(window, &topwin->child_list);
  89. if (topwin != RT_NULL)
  90. return topwin;
  91. }
  92. return RT_NULL;
  93. }
  94. /* add a window to window list[hide] */
  95. rt_err_t rtgui_topwin_add(struct rtgui_event_win_create *event)
  96. {
  97. struct rtgui_topwin *topwin;
  98. topwin = rtgui_malloc(sizeof(struct rtgui_topwin));
  99. if (topwin == RT_NULL)
  100. return -RT_ERROR;
  101. topwin->wid = event->wid;
  102. if (event->wid->_title_wgt)
  103. topwin->extent = RTGUI_WIDGET(event->wid->_title_wgt)->extent;
  104. else
  105. topwin->extent = RTGUI_WIDGET(event->wid)->extent;
  106. topwin->app = event->parent.sender;
  107. if (event->parent_window == RT_NULL)
  108. {
  109. topwin->parent = RT_NULL;
  110. rt_list_insert_before(&_rtgui_topwin_list, &topwin->list);
  111. }
  112. else
  113. {
  114. topwin->parent = rtgui_topwin_search_in_list(event->parent_window, &_rtgui_topwin_list);
  115. if (topwin->parent == RT_NULL)
  116. {
  117. /* parent does not exist. Orphan window? */
  118. rtgui_free(topwin);
  119. return -RT_ERROR;
  120. }
  121. rt_list_insert_before(&topwin->parent->child_list, &topwin->list);
  122. }
  123. rt_list_init(&topwin->child_list);
  124. topwin->flag = WINTITLE_INIT;
  125. if (event->parent.user & RTGUI_WIN_STYLE_NO_FOCUS)
  126. topwin->flag |= WINTITLE_NOFOCUS;
  127. if (event->parent.user & RTGUI_WIN_STYLE_ONTOP)
  128. topwin->flag |= WINTITLE_ONTOP;
  129. if (event->parent.user & RTGUI_WIN_STYLE_ONBTM)
  130. topwin->flag |= WINTITLE_ONBTM;
  131. topwin->title = RT_NULL;
  132. rtgui_list_init(&topwin->monitor_list);
  133. return RT_EOK;
  134. }
  135. static struct rtgui_topwin *_rtgui_topwin_get_root_win(struct rtgui_topwin *topwin)
  136. {
  137. struct rtgui_topwin *topparent;
  138. RT_ASSERT(topwin != RT_NULL);
  139. topparent = topwin;
  140. while (topparent && !IS_ROOT_WIN(topparent))
  141. topparent = topparent->parent;
  142. return topparent;
  143. }
  144. static struct rtgui_topwin *_rtgui_topwin_get_topmost_child_shown(struct rtgui_topwin *topwin)
  145. {
  146. RT_ASSERT(topwin != RT_NULL);
  147. while (!(rt_list_isempty(&topwin->child_list)) &&
  148. get_topwin_from_list(topwin->child_list.next)->flag & WINTITLE_SHOWN)
  149. {
  150. topwin = get_topwin_from_list(topwin->child_list.next);
  151. }
  152. return topwin;
  153. }
  154. static rt_bool_t _rtgui_topwin_in_layer(struct rtgui_topwin *topwin, enum rtgui_topwin_flag flag)
  155. {
  156. return (topwin->flag & (WINTITLE_ONTOP | WINTITLE_ONBTM))
  157. == (flag & (WINTITLE_ONTOP | WINTITLE_ONBTM));
  158. }
  159. /* find the topmost window shown in the layer set by flag. The flag has many
  160. * other infomations but we only use the ONTOP/ONBTM */
  161. struct rtgui_topwin *rtgui_topwin_get_topmost_window_shown(enum rtgui_topwin_flag flag)
  162. {
  163. struct rt_list_node *node;
  164. rt_list_foreach(node, &_rtgui_topwin_list, next)
  165. {
  166. struct rtgui_topwin *topwin = get_topwin_from_list(node);
  167. /* reach the hidden region no window shown in current layer */
  168. if (!(topwin->flag & WINTITLE_SHOWN))
  169. return RT_NULL;
  170. if (_rtgui_topwin_in_layer(topwin, flag))
  171. return _rtgui_topwin_get_topmost_child_shown(topwin);
  172. }
  173. /* no window in current layer is shown */
  174. return RT_NULL;
  175. }
  176. struct rtgui_topwin *rtgui_topwin_get_topmost_window_shown_all(void)
  177. {
  178. struct rtgui_topwin *top;
  179. top = rtgui_topwin_get_topmost_window_shown(WINTITLE_ONTOP);
  180. /* 0 is normal layer */
  181. if (top == RT_NULL)
  182. top = rtgui_topwin_get_topmost_window_shown(WINTITLE_INIT);
  183. if (top == RT_NULL)
  184. top = rtgui_topwin_get_topmost_window_shown(WINTITLE_ONBTM);
  185. return top;
  186. }
  187. struct rtgui_win* rtgui_win_get_topmost_shown(void)
  188. {
  189. struct rtgui_topwin *top;
  190. top = rtgui_topwin_get_topmost_window_shown_all();
  191. if (!top)
  192. return RT_NULL;
  193. return top->wid;
  194. }
  195. static struct rtgui_topwin* _rtgui_topwin_get_next_shown(struct rtgui_topwin *top)
  196. {
  197. /* move to next sibling tree */
  198. if (top->parent == RT_NULL)
  199. {
  200. if (top->list.next != &_rtgui_topwin_list &&
  201. get_topwin_from_list(top->list.next)->flag & WINTITLE_SHOWN)
  202. top = _rtgui_topwin_get_topmost_child_shown(get_topwin_from_list(top->list.next));
  203. else
  204. return RT_NULL;
  205. }
  206. /* move to next slibing topwin */
  207. else if (top->list.next != &top->parent->child_list &&
  208. get_topwin_from_list(top->list.next)->flag & WINTITLE_SHOWN)
  209. {
  210. top = _rtgui_topwin_get_topmost_child_shown(get_topwin_from_list(top->list.next));
  211. }
  212. /* level up */
  213. else
  214. {
  215. top = top->parent;
  216. }
  217. return top;
  218. }
  219. struct rtgui_win* rtgui_win_get_next_shown(void)
  220. {
  221. struct rtgui_topwin *top;
  222. top = rtgui_topwin_get_topmost_window_shown_all();
  223. if (!top)
  224. return RT_NULL;
  225. top = _rtgui_topwin_get_next_shown(top);
  226. if (!top)
  227. return RT_NULL;
  228. return top->wid;
  229. }
  230. /* a hidden parent will hide it's children. Top level window can be shown at
  231. * any time. */
  232. static rt_bool_t _rtgui_topwin_could_show(struct rtgui_topwin *topwin)
  233. {
  234. struct rtgui_topwin *parent;
  235. RT_ASSERT(topwin != RT_NULL);
  236. for (parent = topwin->parent; parent != RT_NULL; parent = parent->parent)
  237. {
  238. if (!(parent->flag & WINTITLE_SHOWN))
  239. return RT_FALSE;
  240. }
  241. return RT_TRUE;
  242. }
  243. static void _rtgui_topwin_union_region_tree(struct rtgui_topwin *topwin,
  244. struct rtgui_region *region)
  245. {
  246. struct rt_list_node *node;
  247. RT_ASSERT(topwin != RT_NULL);
  248. rt_list_foreach(node, &topwin->child_list, next)
  249. _rtgui_topwin_union_region_tree(get_topwin_from_list(node), region);
  250. rtgui_region_union_rect(region, region, &topwin->extent);
  251. }
  252. /* The return value of this function is the next node in tree.
  253. *
  254. * As we freed the node in this function, it would be a null reference error of
  255. * the caller iterate the tree normally.
  256. */
  257. static struct rt_list_node *_rtgui_topwin_free_tree(struct rtgui_topwin *topwin)
  258. {
  259. struct rt_list_node *node, *next_node;
  260. RT_ASSERT(topwin != RT_NULL);
  261. node = topwin->child_list.next;
  262. while (node != &topwin->child_list)
  263. node = _rtgui_topwin_free_tree(get_topwin_from_list(node));
  264. next_node = topwin->list.next;
  265. rt_list_remove(&topwin->list);
  266. /* free the monitor rect list, topwin node and title */
  267. while (topwin->monitor_list.next != RT_NULL)
  268. {
  269. struct rtgui_mouse_monitor *monitor = rtgui_list_entry(topwin->monitor_list.next,
  270. struct rtgui_mouse_monitor, list);
  271. topwin->monitor_list.next = topwin->monitor_list.next->next;
  272. rtgui_free(monitor);
  273. }
  274. rtgui_free(topwin);
  275. return next_node;
  276. }
  277. rt_err_t rtgui_topwin_remove(struct rtgui_win *wid)
  278. {
  279. struct rtgui_topwin *topwin, *old_focus;
  280. struct rtgui_region region;
  281. /* find the topwin node */
  282. topwin = rtgui_topwin_search_in_list(wid, &_rtgui_topwin_list);
  283. if (topwin == RT_NULL) return -RT_ERROR;
  284. rtgui_region_init(&region);
  285. old_focus = rtgui_topwin_get_focus();
  286. /* remove the root from _rtgui_topwin_list will remove the whole tree from
  287. * _rtgui_topwin_list. */
  288. rt_list_remove(&topwin->list);
  289. if (old_focus == topwin)
  290. {
  291. _rtgui_topwin_activate_next(topwin->flag);
  292. }
  293. if (topwin->flag & WINTITLE_SHOWN)
  294. {
  295. rtgui_topwin_update_clip();
  296. /* redraw the old rect */
  297. _rtgui_topwin_union_region_tree(topwin, &region);
  298. rtgui_topwin_redraw(rtgui_region_extents(&region));
  299. }
  300. rtgui_region_fini(&region);
  301. _rtgui_topwin_free_tree(topwin);
  302. return RT_EOK;
  303. }
  304. /* neither deactivate the old focus nor change _rtgui_topwin_list.
  305. * Suitable to be called when the first item is the window to be activated
  306. * already. */
  307. static void _rtgui_topwin_only_activate(struct rtgui_topwin *topwin)
  308. {
  309. struct rtgui_event_win event;
  310. RT_ASSERT(topwin != RT_NULL);
  311. if (topwin->flag & WINTITLE_NOFOCUS)
  312. return;
  313. /* activate the raised window */
  314. RTGUI_EVENT_WIN_ACTIVATE_INIT(&event);
  315. topwin->flag |= WINTITLE_ACTIVATE;
  316. event.wid = topwin->wid;
  317. rtgui_send(topwin->app, &(event.parent), sizeof(struct rtgui_event_win));
  318. }
  319. /* activate next window in the same layer as flag. The flag has many other
  320. * infomations but we only use the ONTOP/ONBTM */
  321. static void _rtgui_topwin_activate_next(enum rtgui_topwin_flag flag)
  322. {
  323. struct rtgui_topwin *topwin;
  324. topwin = rtgui_topwin_get_topmost_window_shown(flag);
  325. if (topwin == RT_NULL)
  326. return;
  327. _rtgui_topwin_only_activate(topwin);
  328. }
  329. /* this function does not update the clip(to avoid doubel clipping). So if the
  330. * tree has changed, make sure it has already updated outside. */
  331. static void _rtgui_topwin_deactivate(struct rtgui_topwin *topwin)
  332. {
  333. struct rtgui_event_win event;
  334. RT_ASSERT(topwin != RT_NULL);
  335. RT_ASSERT(topwin->app != RT_NULL);
  336. RTGUI_EVENT_WIN_DEACTIVATE_INIT(&event);
  337. event.wid = topwin->wid;
  338. rtgui_send(topwin->app,
  339. &event.parent, sizeof(struct rtgui_event_win));
  340. topwin->flag &= ~WINTITLE_ACTIVATE;
  341. }
  342. /* Return 1 on the tree is truely moved. If the tree is already in position,
  343. * return 0. */
  344. static int _rtgui_topwin_move_whole_tree2top(struct rtgui_topwin *topwin)
  345. {
  346. struct rtgui_topwin *topparent;
  347. RT_ASSERT(topwin != RT_NULL);
  348. /* move the whole tree */
  349. topparent = _rtgui_topwin_get_root_win(topwin);
  350. RT_ASSERT(topparent != RT_NULL);
  351. /* add node to show list */
  352. if (topwin->flag & WINTITLE_ONTOP)
  353. {
  354. if (get_topwin_from_list(_rtgui_topwin_list.next) == topwin)
  355. return 0;
  356. rt_list_remove(&topparent->list);
  357. rt_list_insert_after(&_rtgui_topwin_list, &(topparent->list));
  358. }
  359. else if (topwin->flag & WINTITLE_ONBTM)
  360. {
  361. /* botton layer window, before the fisrt bottom window or hidden window. */
  362. struct rt_list_node *node;
  363. struct rtgui_topwin *ntopwin = RT_NULL;
  364. rt_list_foreach(node, &_rtgui_topwin_list, next)
  365. {
  366. ntopwin = get_topwin_from_list(node);
  367. if ((ntopwin->flag & WINTITLE_ONBTM)
  368. || !(ntopwin->flag & WINTITLE_SHOWN))
  369. break;
  370. }
  371. if (get_topwin_from_list(node) == topparent)
  372. return 0;
  373. rt_list_remove(&topparent->list);
  374. rt_list_insert_before(node, &(topparent->list));
  375. }
  376. else
  377. {
  378. /* normal layer window, before the fisrt shown normal layer window. */
  379. struct rtgui_topwin *ntopwin = RT_NULL;
  380. struct rt_list_node *node;
  381. rt_list_foreach(node, &_rtgui_topwin_list, next)
  382. {
  383. ntopwin = get_topwin_from_list(node);
  384. if (!((ntopwin->flag & WINTITLE_ONTOP)
  385. && (ntopwin->flag & WINTITLE_SHOWN)))
  386. break;
  387. }
  388. if (get_topwin_from_list(node) == topparent)
  389. return 0;
  390. rt_list_remove(&topparent->list);
  391. rt_list_insert_before(node, &(topparent->list));
  392. }
  393. return 1;
  394. }
  395. static void _rtgui_topwin_raise_in_sibling(struct rtgui_topwin *topwin)
  396. {
  397. struct rt_list_node *win_level;
  398. RT_ASSERT(topwin != RT_NULL);
  399. if (topwin->parent == RT_NULL)
  400. win_level = &_rtgui_topwin_list;
  401. else
  402. win_level = &topwin->parent->child_list;
  403. rt_list_remove(&topwin->list);
  404. rt_list_insert_after(win_level, &topwin->list);
  405. }
  406. /* it will do 2 things. One is moving the whole tree(the root of the tree) to
  407. * the front and the other is moving topwin to the front of it's siblings. */
  408. static int _rtgui_topwin_raise_tree_from_root(struct rtgui_topwin *topwin)
  409. {
  410. int moved;
  411. RT_ASSERT(topwin != RT_NULL);
  412. moved = _rtgui_topwin_move_whole_tree2top(topwin);
  413. /* root win is aleady moved by _rtgui_topwin_move_whole_tree2top */
  414. if (!IS_ROOT_WIN(topwin))
  415. _rtgui_topwin_raise_in_sibling(topwin);
  416. return moved;
  417. }
  418. /* activate a win means:
  419. * - deactivate the old focus win if any
  420. * - raise the window to the front of it's siblings
  421. * - activate a win
  422. */
  423. rt_err_t rtgui_topwin_activate(struct rtgui_event_win_activate *event)
  424. {
  425. struct rtgui_topwin *topwin;
  426. RT_ASSERT(event);
  427. topwin = rtgui_topwin_search_in_list(event->wid, &_rtgui_topwin_list);
  428. if (topwin == RT_NULL)
  429. return -RT_ERROR;
  430. return rtgui_topwin_activate_topwin(topwin);
  431. }
  432. static void _rtgui_topwin_draw_tree(struct rtgui_topwin *topwin, struct rtgui_event_paint *epaint)
  433. {
  434. struct rt_list_node *node;
  435. rt_list_foreach(node, &topwin->child_list, next)
  436. {
  437. if (!(get_topwin_from_list(node)->flag & WINTITLE_SHOWN))
  438. break;
  439. _rtgui_topwin_draw_tree(get_topwin_from_list(node), epaint);
  440. }
  441. epaint->wid = topwin->wid;
  442. rtgui_send(topwin->app, &(epaint->parent), sizeof(*epaint));
  443. }
  444. rt_err_t rtgui_topwin_activate_topwin(struct rtgui_topwin *topwin)
  445. {
  446. int tpmoved;
  447. struct rtgui_topwin *old_focus_topwin;
  448. struct rtgui_event_paint epaint;
  449. RT_ASSERT(topwin != RT_NULL);
  450. RTGUI_EVENT_PAINT_INIT(&epaint);
  451. if (!(topwin->flag & WINTITLE_SHOWN))
  452. return -RT_ERROR;
  453. if (topwin->flag & WINTITLE_NOFOCUS)
  454. {
  455. /* just raise and show, no other effects. Active window is the one
  456. * which will receive kbd events. So a no-focus window can only be
  457. * "raised" but not "activated".
  458. */
  459. tpmoved = _rtgui_topwin_raise_tree_from_root(topwin);
  460. rtgui_topwin_update_clip();
  461. if (tpmoved)
  462. _rtgui_topwin_draw_tree(_rtgui_topwin_get_root_win(topwin),
  463. &epaint);
  464. else
  465. _rtgui_topwin_draw_tree(topwin, &epaint);
  466. return RT_EOK;
  467. }
  468. if (topwin->flag & WINTITLE_ACTIVATE)
  469. return RT_EOK;
  470. old_focus_topwin = rtgui_topwin_get_focus();
  471. /* if topwin has the focus, it should have WINTITLE_ACTIVATE set and
  472. * returned above. */
  473. RT_ASSERT(old_focus_topwin != topwin);
  474. tpmoved = _rtgui_topwin_raise_tree_from_root(topwin);
  475. /* clip before active the window, so we could get right boarder region. */
  476. rtgui_topwin_update_clip();
  477. if (old_focus_topwin != RT_NULL)
  478. {
  479. /* deactivate the old focus window firstly, otherwise it will make the new
  480. * window invisible. */
  481. _rtgui_topwin_deactivate(old_focus_topwin);
  482. }
  483. _rtgui_topwin_only_activate(topwin);
  484. if (tpmoved)
  485. _rtgui_topwin_draw_tree(_rtgui_topwin_get_root_win(topwin),
  486. &epaint);
  487. else
  488. _rtgui_topwin_draw_tree(topwin, &epaint);
  489. return RT_EOK;
  490. }
  491. /* map func to the topwin tree in preorder.
  492. *
  493. * Remember that we are in a embedded system so write the @param func memory
  494. * efficiently.
  495. */
  496. rt_inline void _rtgui_topwin_preorder_map(struct rtgui_topwin *topwin, void (*func)(struct rtgui_topwin *))
  497. {
  498. struct rt_list_node *child;
  499. RT_ASSERT(topwin != RT_NULL);
  500. RT_ASSERT(func != RT_NULL);
  501. func(topwin);
  502. rt_list_foreach(child, &topwin->child_list, next)
  503. _rtgui_topwin_preorder_map(get_topwin_from_list(child), func);
  504. }
  505. rt_inline void _rtgui_topwin_mark_hidden(struct rtgui_topwin *topwin)
  506. {
  507. topwin->flag &= ~WINTITLE_SHOWN;
  508. RTGUI_WIDGET_HIDE(topwin->wid);
  509. }
  510. rt_inline void _rtgui_topwin_mark_shown(struct rtgui_topwin *topwin)
  511. {
  512. if (topwin->flag & WINTITLE_SHOWN)
  513. return;
  514. topwin->flag |= WINTITLE_SHOWN;
  515. if (RTGUI_WIDGET_IS_HIDE(topwin->wid))
  516. {
  517. rtgui_widget_show(RTGUI_WIDGET(topwin->wid));
  518. }
  519. }
  520. rt_err_t rtgui_topwin_show(struct rtgui_event_win *event)
  521. {
  522. struct rtgui_topwin *topwin;
  523. struct rtgui_win *wid = event->wid;
  524. topwin = rtgui_topwin_search_in_list(wid, &_rtgui_topwin_list);
  525. /* no such a window recorded */
  526. if (topwin == RT_NULL)
  527. return -RT_ERROR;
  528. /* child windows could only be shown iif the parent is shown */
  529. if (!_rtgui_topwin_could_show(topwin))
  530. {
  531. return -RT_ERROR;
  532. }
  533. _rtgui_topwin_preorder_map(topwin, _rtgui_topwin_mark_shown);
  534. rtgui_topwin_activate_topwin(topwin);
  535. return RT_EOK;
  536. }
  537. static void _rtgui_topwin_clear_modal_tree(struct rtgui_topwin *topwin)
  538. {
  539. struct rt_list_node *node;
  540. RT_ASSERT(topwin != RT_NULL);
  541. RT_ASSERT(topwin->parent != RT_NULL);
  542. while (!IS_ROOT_WIN(topwin))
  543. {
  544. rt_list_foreach(node, &topwin->parent->child_list, next)
  545. {
  546. get_topwin_from_list(node)->flag &= ~WINTITLE_MODALED;
  547. get_topwin_from_list(node)->wid->flag &= ~RTGUI_WIN_FLAG_UNDER_MODAL;
  548. if (get_topwin_from_list(node)->flag & WINTITLE_MODALING)
  549. {
  550. goto _out;
  551. }
  552. }
  553. topwin = topwin->parent;
  554. }
  555. _out:
  556. /* clear the modal flag of the root window */
  557. topwin->flag &= ~WINTITLE_MODALED;
  558. topwin->wid->flag &= ~RTGUI_WIN_FLAG_UNDER_MODAL;
  559. }
  560. /* hide a window */
  561. rt_err_t rtgui_topwin_hide(struct rtgui_event_win *event)
  562. {
  563. struct rtgui_topwin *topwin;
  564. struct rtgui_topwin *old_focus_topwin;
  565. struct rtgui_win *wid;
  566. struct rt_list_node *containing_list;
  567. if (!event)
  568. return -RT_ERROR;
  569. wid = event->wid;
  570. /* find in show list */
  571. topwin = rtgui_topwin_search_in_list(wid, &_rtgui_topwin_list);
  572. if (topwin == RT_NULL)
  573. {
  574. return -RT_ERROR;
  575. }
  576. if (!(topwin->flag & WINTITLE_SHOWN))
  577. {
  578. return RT_EOK;
  579. }
  580. old_focus_topwin = rtgui_topwin_get_focus();
  581. _rtgui_topwin_preorder_map(topwin, _rtgui_topwin_mark_hidden);
  582. if (topwin->parent == RT_NULL)
  583. containing_list = &_rtgui_topwin_list;
  584. else
  585. containing_list = &topwin->parent->child_list;
  586. rt_list_remove(&topwin->list);
  587. rt_list_insert_before(containing_list, &topwin->list);
  588. /* update clip info */
  589. rtgui_topwin_update_clip();
  590. if (topwin->flag & WINTITLE_MODALING)
  591. {
  592. topwin->flag &= ~WINTITLE_MODALING;
  593. _rtgui_topwin_clear_modal_tree(topwin);
  594. }
  595. if (old_focus_topwin == topwin)
  596. {
  597. _rtgui_topwin_activate_next(topwin->flag);
  598. }
  599. topwin->flag &= ~WINTITLE_ACTIVATE;
  600. /* redraw the old rect */
  601. rtgui_topwin_redraw(&(topwin->extent));
  602. return RT_EOK;
  603. }
  604. /* move top window */
  605. rt_err_t rtgui_topwin_move(struct rtgui_event_win_move *event)
  606. {
  607. struct rtgui_topwin *topwin;
  608. int dx, dy;
  609. rtgui_rect_t old_rect; /* the old topwin coverage area */
  610. struct rtgui_list_node *node;
  611. /* find in show list */
  612. topwin = rtgui_topwin_search_in_list(event->wid, &_rtgui_topwin_list);
  613. if (topwin == RT_NULL ||
  614. !(topwin->flag & WINTITLE_SHOWN))
  615. {
  616. return -RT_ERROR;
  617. }
  618. /* get the delta move x, y */
  619. dx = event->x - topwin->extent.x1;
  620. dy = event->y - topwin->extent.y1;
  621. old_rect = topwin->extent;
  622. /* move window rect */
  623. rtgui_rect_move(&(topwin->extent), dx, dy);
  624. /* move the monitor rect list */
  625. rtgui_list_foreach(node, &(topwin->monitor_list))
  626. {
  627. struct rtgui_mouse_monitor *monitor = rtgui_list_entry(node,
  628. struct rtgui_mouse_monitor,
  629. list);
  630. rtgui_rect_move(&(monitor->rect), dx, dy);
  631. }
  632. /* update windows clip info */
  633. rtgui_topwin_update_clip();
  634. /* update old window coverage area */
  635. rtgui_topwin_redraw(&old_rect);
  636. if (rtgui_rect_is_intersect(&old_rect, &(topwin->extent)) != RT_EOK)
  637. {
  638. /*
  639. * the old rect is not intersect with moved rect,
  640. * re-paint window
  641. */
  642. struct rtgui_event_paint epaint;
  643. RTGUI_EVENT_PAINT_INIT(&epaint);
  644. epaint.wid = topwin->wid;
  645. rtgui_send(topwin->app, &(epaint.parent), sizeof(epaint));
  646. }
  647. return RT_EOK;
  648. }
  649. /*
  650. * resize a top win
  651. * Note: currently, only support resize hidden window
  652. */
  653. void rtgui_topwin_resize(struct rtgui_win *wid, rtgui_rect_t *rect)
  654. {
  655. struct rtgui_topwin *topwin;
  656. struct rtgui_region region;
  657. /* find in show list */
  658. topwin = rtgui_topwin_search_in_list(wid, &_rtgui_topwin_list);
  659. if (topwin == RT_NULL ||
  660. !(topwin->flag & WINTITLE_SHOWN))
  661. return;
  662. /* record the old rect */
  663. rtgui_region_init_with_extents(&region, &topwin->extent);
  664. /* union the new rect so this is the region we should redraw */
  665. rtgui_region_union_rect(&region, &region, rect);
  666. topwin->extent = *rect;
  667. /* update windows clip info */
  668. rtgui_topwin_update_clip();
  669. /* update old window coverage area */
  670. rtgui_topwin_redraw(rtgui_region_extents(&region));
  671. rtgui_region_fini(&region);
  672. }
  673. static struct rtgui_topwin *_rtgui_topwin_get_focus_from_list(struct rt_list_node *list)
  674. {
  675. struct rt_list_node *node;
  676. RT_ASSERT(list != RT_NULL);
  677. rt_list_foreach(node, list, next)
  678. {
  679. struct rtgui_topwin *child = get_topwin_from_list(node);
  680. if (child->flag & WINTITLE_ACTIVATE)
  681. return child;
  682. child = _rtgui_topwin_get_focus_from_list(&child->child_list);
  683. if (child != RT_NULL)
  684. return child;
  685. }
  686. return RT_NULL;
  687. }
  688. struct rtgui_topwin *rtgui_topwin_get_focus(void)
  689. {
  690. return _rtgui_topwin_get_focus_from_list(&_rtgui_topwin_list);
  691. }
  692. static struct rtgui_topwin *_rtgui_topwin_get_wnd_from_tree(struct rt_list_node *list,
  693. int x, int y,
  694. rt_bool_t exclude_modaled)
  695. {
  696. struct rt_list_node *node;
  697. struct rtgui_topwin *topwin, *target;
  698. RT_ASSERT(list != RT_NULL);
  699. rt_list_foreach(node, list, next)
  700. {
  701. topwin = get_topwin_from_list(node);
  702. if (!(topwin->flag & WINTITLE_SHOWN))
  703. break;
  704. /* if higher window have this point, return it */
  705. target = _rtgui_topwin_get_wnd_from_tree(&topwin->child_list, x, y, exclude_modaled);
  706. if (target != RT_NULL)
  707. return target;
  708. if (exclude_modaled && (topwin->flag & WINTITLE_MODALED))
  709. break;
  710. if (rtgui_rect_contains_point(&(topwin->extent), x, y) == RT_EOK)
  711. {
  712. return topwin;
  713. }
  714. }
  715. return RT_NULL;
  716. }
  717. struct rtgui_topwin *rtgui_topwin_get_wnd(int x, int y)
  718. {
  719. return _rtgui_topwin_get_wnd_from_tree(&_rtgui_topwin_list, x, y, RT_FALSE);
  720. }
  721. struct rtgui_topwin *rtgui_topwin_get_wnd_no_modaled(int x, int y)
  722. {
  723. return _rtgui_topwin_get_wnd_from_tree(&_rtgui_topwin_list, x, y, RT_TRUE);
  724. }
  725. /* clip region from topwin, and the windows beneath it. */
  726. rt_inline void _rtgui_topwin_clip_to_region(struct rtgui_topwin *topwin,
  727. struct rtgui_region *region)
  728. {
  729. RT_ASSERT(region != RT_NULL);
  730. RT_ASSERT(topwin != RT_NULL);
  731. rtgui_region_reset(&topwin->wid->outer_clip, &topwin->wid->outer_extent);
  732. rtgui_region_intersect(&topwin->wid->outer_clip, &topwin->wid->outer_clip, region);
  733. }
  734. static void rtgui_topwin_update_clip(void)
  735. {
  736. struct rtgui_topwin *top;
  737. struct rtgui_event_clip_info eclip;
  738. /* Note that the region is a "female die", that means it's the region you
  739. * can paint to, not the region covered by others.
  740. */
  741. struct rtgui_region region_available;
  742. if (rt_list_isempty(&_rtgui_topwin_list) ||
  743. !(get_topwin_from_list(_rtgui_topwin_list.next)->flag & WINTITLE_SHOWN))
  744. return;
  745. RTGUI_EVENT_CLIP_INFO_INIT(&eclip);
  746. rtgui_region_init_rect(&region_available, 0, 0,
  747. rtgui_graphic_driver_get_default()->width,
  748. rtgui_graphic_driver_get_default()->height);
  749. /* from top to bottom. */
  750. top = rtgui_topwin_get_topmost_window_shown(WINTITLE_ONTOP);
  751. /* 0 is normal layer */
  752. if (top == RT_NULL)
  753. top = rtgui_topwin_get_topmost_window_shown(WINTITLE_INIT);
  754. if (top == RT_NULL)
  755. top = rtgui_topwin_get_topmost_window_shown(WINTITLE_ONBTM);
  756. while (top != RT_NULL)
  757. {
  758. /* clip the topwin */
  759. _rtgui_topwin_clip_to_region(top, &region_available);
  760. /* update available region */
  761. rtgui_region_subtract_rect(&region_available, &region_available, &top->extent);
  762. /* send clip event to destination window */
  763. eclip.wid = top->wid;
  764. rtgui_send(top->app, &(eclip.parent), sizeof(struct rtgui_event_clip_info));
  765. top = _rtgui_topwin_get_next_shown(top);
  766. }
  767. rtgui_region_fini(&region_available);
  768. }
  769. static void _rtgui_topwin_redraw_tree(struct rt_list_node *list,
  770. struct rtgui_rect *rect,
  771. struct rtgui_event_paint *epaint)
  772. {
  773. struct rt_list_node *node;
  774. RT_ASSERT(list != RT_NULL);
  775. RT_ASSERT(rect != RT_NULL);
  776. RT_ASSERT(epaint != RT_NULL);
  777. /* skip the hidden windows */
  778. rt_list_foreach(node, list, prev)
  779. {
  780. if (get_topwin_from_list(node)->flag & WINTITLE_SHOWN)
  781. break;
  782. }
  783. for (; node != list; node = node->prev)
  784. {
  785. struct rtgui_topwin *topwin;
  786. topwin = get_topwin_from_list(node);
  787. //FIXME: intersect with clip?
  788. if (rtgui_rect_is_intersect(rect, &(topwin->extent)) == RT_EOK)
  789. {
  790. epaint->wid = topwin->wid;
  791. rtgui_send(topwin->app, &(epaint->parent), sizeof(*epaint));
  792. }
  793. _rtgui_topwin_redraw_tree(&topwin->child_list, rect, epaint);
  794. }
  795. }
  796. static void rtgui_topwin_redraw(struct rtgui_rect *rect)
  797. {
  798. struct rtgui_event_paint epaint;
  799. RTGUI_EVENT_PAINT_INIT(&epaint);
  800. epaint.wid = RT_NULL;
  801. _rtgui_topwin_redraw_tree(&_rtgui_topwin_list, rect, &epaint);
  802. }
  803. /* a window enter modal mode will modal all the sibling window and parent
  804. * window all along to the root window. If a root window modals, there is
  805. * nothing to do here.*/
  806. rt_err_t rtgui_topwin_modal_enter(struct rtgui_event_win_modal_enter *event)
  807. {
  808. struct rtgui_topwin *topwin, *parent_top;
  809. struct rt_list_node *node;
  810. topwin = rtgui_topwin_search_in_list(event->wid, &_rtgui_topwin_list);
  811. if (topwin == RT_NULL)
  812. return -RT_ERROR;
  813. if (IS_ROOT_WIN(topwin))
  814. return RT_EOK;
  815. parent_top = topwin->parent;
  816. /* modal window should be on top already */
  817. RT_ASSERT(get_topwin_from_list(parent_top->child_list.next) == topwin);
  818. do
  819. {
  820. rt_list_foreach(node, &parent_top->child_list, next)
  821. {
  822. get_topwin_from_list(node)->flag |= WINTITLE_MODALED;
  823. get_topwin_from_list(node)->wid->flag |= RTGUI_WIN_FLAG_UNDER_MODAL;
  824. }
  825. parent_top->flag |= WINTITLE_MODALED;
  826. parent_top->wid->flag |= RTGUI_WIN_FLAG_UNDER_MODAL;
  827. parent_top = parent_top->parent;
  828. } while (parent_top);
  829. topwin->flag &= ~WINTITLE_MODALED;
  830. topwin->wid->flag &= ~RTGUI_WIN_FLAG_UNDER_MODAL;
  831. topwin->flag |= WINTITLE_MODALING;
  832. return RT_EOK;
  833. }
  834. void rtgui_topwin_append_monitor_rect(struct rtgui_win *wid, rtgui_rect_t *rect)
  835. {
  836. struct rtgui_topwin *win;
  837. /* parameters check */
  838. if (wid == RT_NULL || rect == RT_NULL) return;
  839. /* find topwin */
  840. win = rtgui_topwin_search_in_list(wid, &_rtgui_topwin_list);
  841. if (win == RT_NULL)
  842. return;
  843. /* append rect to top window monitor rect list */
  844. rtgui_mouse_monitor_append(&(win->monitor_list), rect);
  845. }
  846. void rtgui_topwin_remove_monitor_rect(struct rtgui_win *wid, rtgui_rect_t *rect)
  847. {
  848. struct rtgui_topwin *win;
  849. /* parameters check */
  850. if (wid == RT_NULL || rect == RT_NULL)
  851. return;
  852. /* find topwin */
  853. win = rtgui_topwin_search_in_list(wid, &_rtgui_topwin_list);
  854. if (win == RT_NULL)
  855. return;
  856. /* remove rect from top window monitor rect list */
  857. rtgui_mouse_monitor_remove(&(win->monitor_list), rect);
  858. }
  859. static struct rtgui_object* _get_obj_in_topwin(struct rtgui_topwin *topwin,
  860. struct rtgui_app *app,
  861. rt_uint32_t id)
  862. {
  863. struct rtgui_object *object;
  864. struct rt_list_node *node;
  865. object = RTGUI_OBJECT(topwin->wid);
  866. if (object->id == id)
  867. return object;
  868. object = rtgui_container_get_object(RTGUI_CONTAINER(object), id);
  869. if (object)
  870. return object;
  871. rt_list_foreach(node, &topwin->child_list, next)
  872. {
  873. struct rtgui_topwin *topwin;
  874. topwin = get_topwin_from_list(node);
  875. if (topwin->app != app)
  876. continue;
  877. object = _get_obj_in_topwin(topwin, app, id);
  878. if (object)
  879. return object;
  880. }
  881. return RT_NULL;
  882. }
  883. struct rtgui_object* rtgui_get_object(struct rtgui_app *app, rt_uint32_t id)
  884. {
  885. struct rtgui_object *object;
  886. struct rt_list_node *node;
  887. object = RTGUI_OBJECT(app);
  888. if (object->id == id)
  889. return object;
  890. rt_list_foreach(node, &_rtgui_topwin_list, next)
  891. {
  892. struct rtgui_topwin *topwin;
  893. topwin = get_topwin_from_list(node);
  894. if (topwin->app != app)
  895. continue;
  896. object = _get_obj_in_topwin(topwin, app, id);
  897. if (object)
  898. return object;
  899. }
  900. return RT_NULL;
  901. }
  902. RTM_EXPORT(rtgui_get_object);
  903. struct rtgui_object* rtgui_get_self_object(rt_uint32_t id)
  904. {
  905. return rtgui_get_object(rtgui_app_self(), id);
  906. }
  907. RTM_EXPORT(rtgui_get_self_object);
  908. static void _rtgui_topwin_dump(struct rtgui_topwin *topwin)
  909. {
  910. rt_kprintf("0x%p:%s,0x%x,%c%c",
  911. topwin, topwin->wid->title, topwin->flag,
  912. topwin->flag & WINTITLE_SHOWN ? 'S' : 'H',
  913. topwin->flag & WINTITLE_MODALED ? 'm' :
  914. topwin->flag & WINTITLE_MODALING ? 'M' : ' ');
  915. }
  916. static void _rtgui_topwin_dump_tree(struct rtgui_topwin *topwin)
  917. {
  918. struct rt_list_node *node;
  919. _rtgui_topwin_dump(topwin);
  920. rt_kprintf("(");
  921. rt_list_foreach(node, &topwin->child_list, next)
  922. {
  923. _rtgui_topwin_dump_tree(get_topwin_from_list(node));
  924. }
  925. rt_kprintf(")");
  926. }
  927. void rtgui_topwin_dump_tree(void)
  928. {
  929. struct rt_list_node *node;
  930. rt_list_foreach(node, &_rtgui_topwin_list, next)
  931. {
  932. _rtgui_topwin_dump_tree(get_topwin_from_list(node));
  933. rt_kprintf("\n");
  934. }
  935. }
  936. #ifdef RT_USING_FINSH
  937. #include <finsh.h>
  938. void dump_tree()
  939. {
  940. rtgui_topwin_dump_tree();
  941. }
  942. FINSH_FUNCTION_EXPORT(dump_tree, dump rtgui topwin tree)
  943. #endif