diff options
| author | [email protected] <[email protected]> | 2012-04-18 15:06:12 +0000 |
|---|---|---|
| committer | [email protected] <[email protected]> | 2012-04-18 15:06:12 +0000 |
| commit | db0646020812efc16ff0beebe35f9049dcc2bfed (patch) | |
| tree | 5e949e9ba679a07b0198745853e900a016a3834e /components/rtgui/server | |
| parent | 06d45f0c42f2aa3678d509403fcf9cd82be106e6 (diff) | |
merge new RTGUI in to trunk
The full log is at https://github.com/RTGUI/RTGUI/commits/merge_1 and it's difficult to merge the new tree commit by commit. I also converted all the file into unix eol so there are many fake diff. Big changes are noted in rtgui/doc/road_map.txt and rtgui/doc/attention.txt. Keep an eye on them if you want to migrate your old code.
Note that the work is still in progress and the bsp is not prepared in trunk so far.
git-svn-id: https://rt-thread.googlecode.com/svn/trunk@2092 bbd45198-f89e-11dd-88c7-29a3b14d5316
Diffstat (limited to 'components/rtgui/server')
| -rw-r--r-- | components/rtgui/server/mouse.c | 2 | ||||
| -rw-r--r-- | components/rtgui/server/panel.c | 315 | ||||
| -rw-r--r-- | components/rtgui/server/panel.h | 72 | ||||
| -rw-r--r-- | components/rtgui/server/rtgui_application.c | 673 | ||||
| -rw-r--r-- | components/rtgui/server/server.c | 601 | ||||
| -rw-r--r-- | components/rtgui/server/topwin.c | 1255 | ||||
| -rw-r--r-- | components/rtgui/server/topwin.h | 22 |
7 files changed, 1596 insertions, 1344 deletions
diff --git a/components/rtgui/server/mouse.c b/components/rtgui/server/mouse.c index 8d851f0f85..c7a05aac4b 100644 --- a/components/rtgui/server/mouse.c +++ b/components/rtgui/server/mouse.c @@ -432,7 +432,7 @@ static void rtgui_winrect_show() rt_uint16_t x, y; rtgui_color_t c; rtgui_rect_t screen_rect, win_rect, win_rect_inner; - void (*set_pixel) (rtgui_color_t *c, rt_base_t x, rt_base_t y); + void (*set_pixel) (rtgui_color_t *c, int x, int y); c = black; set_pixel = rtgui_graphic_driver_get_default()->ops->set_pixel; diff --git a/components/rtgui/server/panel.c b/components/rtgui/server/panel.c deleted file mode 100644 index f9cd93a578..0000000000 --- a/components/rtgui/server/panel.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * File : panel.c - * This file is part of RTGUI in RT-Thread RTOS - * COPYRIGHT (C) 2006 - 2009, RT-Thread Development Team - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rt-thread.org/license/LICENSE - * - * Change Logs: - * Date Author Notes - * 2009-10-04 Bernard first version - */ - -#include "panel.h" -#include "mouse.h" - -#include <rtgui/rtgui_system.h> - -/* the global parameter */ -struct rtgui_list_node _rtgui_panel_list = {RT_NULL}; - -void rtgui_panel_register(char* name, rtgui_rect_t* extent) -{ - register rt_base_t temp; - struct rtgui_panel* panel; - - panel = rtgui_panel_find(name); - if (panel != RT_NULL ) - { - /* there are already a same named panel exist. */ - return; - } - - panel = rtgui_malloc(sizeof(struct rtgui_panel)); - if (panel == RT_NULL) - { - /* can't alloc memory */ - return; - } - - /* copy name */ - for (temp = 0; temp < RTGUI_NAME_MAX; temp ++) - { - panel->name[temp] = name[temp]; - } - - /* copy extent */ - panel->extent = *extent; - - panel->wm_thread = RT_NULL; - panel->is_focusable = RT_TRUE; - - /* init list */ - rtgui_list_init(&(panel->sibling)); - rtgui_list_init(&(panel->thread_list)); - - /* add panel to panel list */ - rtgui_list_insert(&_rtgui_panel_list, &(panel->sibling)); -} - -void rtgui_panel_deregister(char* name) -{ - struct rtgui_panel* panel; - - panel = rtgui_panel_find(name); - if (panel != RT_NULL) - { - rtgui_list_remove(&_rtgui_panel_list, &(panel->sibling)); - - /* free pane node */ - rtgui_free(panel); - } -} - -/* set default focused panel, please use it after registered panel */ -void rtgui_panel_set_default_focused(char* name) -{ - extern struct rtgui_panel* rtgui_server_focus_panel; - struct rtgui_panel* panel; - - panel = rtgui_panel_find(name); - if (panel != RT_NULL) - { - rtgui_server_focus_panel = panel; - } -} - -void rtgui_panel_set_nofocused(char* name) -{ - extern struct rtgui_panel* rtgui_server_focus_panel; - struct rtgui_panel* panel; - - panel = rtgui_panel_find(name); - if (panel != RT_NULL) - { - panel->is_focusable = RT_FALSE; - } -} - -struct rtgui_panel* rtgui_panel_find(char* name) -{ - struct rtgui_list_node* node; - struct rtgui_panel* panel; - - rtgui_list_foreach(node, &_rtgui_panel_list) - { - panel = rtgui_list_entry(node, struct rtgui_panel, sibling); - - if (rt_strncmp(panel->name, name, RTGUI_NAME_MAX) == 0) - { - return panel; - } - } - - return RT_NULL; -} - -struct rtgui_panel* rtgui_panel_thread_add(char* name, rt_thread_t tid) -{ - struct rtgui_panel* panel; - - panel = rtgui_panel_find(name); - if (panel != RT_NULL ) - { - struct rtgui_panel_thread* thread; - - /* allocate panel thread node */ - thread = rtgui_malloc(sizeof(struct rtgui_panel_thread)); - if (thread == RT_NULL) - { - return RT_NULL; - } - - /* construct panel thread node */ - thread->tid = tid; - - /* init list */ - rtgui_list_init(&(thread->list)); - rtgui_list_init(&(thread->monitor_list)); - - /* append thread to the list */ - rtgui_list_append(&(panel->thread_list), &(thread->list)); - } - - return panel; -} - -void rtgui_panel_thread_remove(rtgui_panel_t* panel, rt_thread_t tid) -{ - if (panel != RT_NULL ) - { - struct rtgui_list_node* node; - struct rtgui_panel_thread* thread; - - rtgui_list_foreach(node, &(panel->thread_list)) - { - thread = rtgui_list_entry(node, struct rtgui_panel_thread, list); - if (thread->tid == tid) - { - /* remove node from list */ - rtgui_list_remove(&(panel->thread_list), &(thread->list)); - - /* free the panel thread node */ - rtgui_free(thread); - return; - } - } - } -} - -rt_thread_t rtgui_panel_get_active_thread(rtgui_panel_t* panel) -{ - if (panel != RT_NULL) - { - if (panel->thread_list.next != RT_NULL) - { - struct rtgui_panel_thread* thread; - thread = rtgui_list_entry(panel->thread_list.next, struct rtgui_panel_thread, list); - - return thread->tid; - } - } - - return RT_NULL; -} - -void rtgui_panel_set_active_thread(rtgui_panel_t* panel, rt_thread_t tid) -{ - /* get old active thread */ - rt_thread_t prev_actived = rtgui_panel_get_active_thread(panel); - if (prev_actived != tid) - { - /* de-active old active workbench */ - struct rtgui_event_panel_hide ehide; - RTGUI_EVENT_PANEL_HIDE_INIT(&ehide); - - ehide.panel = panel; - ehide.workbench = RT_NULL; - rtgui_thread_send_urgent(prev_actived, &(ehide.parent), sizeof (ehide)); - } - - if (panel != RT_NULL ) - { - struct rtgui_list_node* node; - struct rtgui_panel_thread* thread; - - rtgui_list_foreach(node, &(panel->thread_list)) - { - thread = rtgui_list_entry(node, struct rtgui_panel_thread, list); - if (thread->tid == tid) - { - /* remove node from list */ - rtgui_list_remove(&(panel->thread_list), &(thread->list)); - - /* insert node to the header */ - rtgui_list_insert(&(panel->thread_list), &(thread->list)); - return; - } - } - } -} - -/* deactivate current activated thread -- move it to the end of list */ -void rtgui_panel_deactive_thread(rtgui_panel_t* panel) -{ - RT_ASSERT(panel == RT_NULL); - - if (panel->thread_list.next != RT_NULL) - { - struct rtgui_panel_thread* thread; - thread = rtgui_list_entry(panel->thread_list.next, struct rtgui_panel_thread, list); - - /* remove it */ - panel->thread_list.next = thread->list.next; - - /* append to the tail of thread list */ - rtgui_list_append(&(panel->thread_list), &(thread->list)); - } -} - -/** - * get the panel which contains a point(x, y) - */ -rtgui_panel_t* rtgui_panel_get_contain(int x, int y) -{ - struct rtgui_list_node* node; - struct rtgui_panel* panel; - - rtgui_list_foreach(node, &(_rtgui_panel_list)) - { - panel = rtgui_list_entry(node, struct rtgui_panel, sibling); - if (rtgui_rect_contains_point(&(panel->extent), x, y) == RT_EOK) - { - return panel; - } - } - - return RT_NULL; -} - -/** - * append a rect to panel mouse monitor rect list - */ -void rtgui_panel_append_monitor_rect(rtgui_panel_t* panel, rt_thread_t tid, rtgui_rect_t* rect) -{ - if (panel != RT_NULL ) - { - struct rtgui_list_node* node; - struct rtgui_panel_thread* thread; - - rtgui_list_foreach(node, &(panel->thread_list)) - { - thread = rtgui_list_entry(node, struct rtgui_panel_thread, list); - if (thread->tid == tid) - { - /* add the monitor rect to list */ - rtgui_mouse_monitor_append(&(thread->monitor_list), rect); - return; - } - } - } -} - -/** - * remove a rect from panel mouse monitor rect list - */ -void rtgui_panel_remove_monitor_rect(rtgui_panel_t* panel, rt_thread_t tid, rtgui_rect_t* rect) -{ - if (panel != RT_NULL ) - { - struct rtgui_list_node* node; - struct rtgui_panel_thread* thread; - - rtgui_list_foreach(node, &(panel->thread_list)) - { - thread = rtgui_list_entry(node, struct rtgui_panel_thread, list); - if (thread->tid == tid) - { - /* remove the monitor rect from list */ - rtgui_mouse_monitor_remove(&(thread->monitor_list), rect); - return; - } - } - } -} - -void rtgui_panel_set_wm(rtgui_panel_t* panel, rt_thread_t wm) -{ - RT_ASSERT(wm != RT_NULL); - RT_ASSERT(panel != RT_NULL); - - panel->wm_thread = wm; -} - diff --git a/components/rtgui/server/panel.h b/components/rtgui/server/panel.h deleted file mode 100644 index 559ddc4307..0000000000 --- a/components/rtgui/server/panel.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * File : panel.h - * This file is part of RTGUI in RT-Thread RTOS - * COPYRIGHT (C) 2006 - 2009, RT-Thread Development Team - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rt-thread.org/license/LICENSE - * - * Change Logs: - * Date Author Notes - * 2009-10-04 Bernard first version - */ - -#ifndef __RT_PANEL_H__ -#define __RT_PANEL_H__ - -#include <rtgui/rtgui.h> -#include <rtgui/list.h> -#include <rtgui/region.h> - -struct rtgui_panel_thread -{ - /* thread id */ - rt_thread_t tid; - - /* the list of thread */ - rtgui_list_t list; - - /* monitor rect list */ - rtgui_list_t monitor_list; -}; -typedef struct rtgui_panel_thread rtgui_panel_thread_list_t; - -struct rtgui_panel -{ - char name[RTGUI_NAME_MAX]; - - /* the extent of panel */ - rtgui_rect_t extent; - - /* the list of panel */ - rtgui_list_t sibling; - - /* the thread list in this panel */ - rtgui_list_t thread_list; - - /* the workbench manager thread */ - rt_thread_t wm_thread; - - /* is focusable */ - rt_bool_t is_focusable; -}; - -/* find panel by name */ -struct rtgui_panel* rtgui_panel_find(char* name); - -/* add or remove application thread from specified panel */ -rtgui_panel_t* rtgui_panel_thread_add(char* name, rt_thread_t tid); -void rtgui_panel_thread_remove(rtgui_panel_t* panel, rt_thread_t tid); - -rt_thread_t rtgui_panel_get_active_thread(rtgui_panel_t* panel); -void rtgui_panel_set_active_thread(rtgui_panel_t* panel, rt_thread_t tid); - -rtgui_panel_t* rtgui_panel_get_contain(int x, int y); -void rtgui_panel_set_wm(rtgui_panel_t* panel, rt_thread_t wm); - -void rtgui_panel_append_monitor_rect(rtgui_panel_t* panel, rt_thread_t tid, rtgui_rect_t* rect); -void rtgui_panel_remove_monitor_rect(rtgui_panel_t* panel, rt_thread_t tid, rtgui_rect_t* rect); - -#endif - diff --git a/components/rtgui/server/rtgui_application.c b/components/rtgui/server/rtgui_application.c new file mode 100644 index 0000000000..97de7bd17a --- /dev/null +++ b/components/rtgui/server/rtgui_application.c @@ -0,0 +1,673 @@ +/* + * File : rtgui_application.c + * This file is part of RTGUI in RT-Thread RTOS + * COPYRIGHT (C) 2012, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2012-01-13 Grissiom first version(just a prototype of application API) + */ + +#include <rtgui/rtgui_system.h> +#include <rtgui/rtgui_application.h> +#include <rtgui/widgets/window.h> + +#ifdef _WIN32 +#define RTGUI_EVENT_DEBUG +#endif + +#ifdef RTGUI_EVENT_DEBUG +const char *event_string[] = +{ + /* window event */ + "WIN_CREATE", /* create a window */ + "WIN_DESTROY", /* destroy a window */ + "WIN_SHOW", /* show a window */ + "WIN_HIDE", /* hide a window */ + "WIN_ACTIVATE", /* activate a window */ + "WIN_DEACTIVATE", /* deactivate a window */ + "WIN_CLOSE", /* close a window */ + "WIN_MOVE", /* move a window */ + "WIN_RESIZE", /* resize a window */ + "WIN_MODAL_ENTER", /* a window modals */ + + "SET_WM", /* set window manager */ + + "UPDATE_BEGIN", /* begin of update rect */ + "UPDATE_END", /* end of update rect */ + "MONITOR_ADD", /* add a monitor rect */ + "MONITOR_REMOVE", /* remove a monitor rect*/ + "PAINT", /* paint on screen */ + "TIMER", /* timer */ + + /* clip rect information */ + "CLIP_INFO", /* clip rect info */ + + /* mouse and keyboard event */ + "MOUSE_MOTION", /* mouse motion */ + "MOUSE_BUTTON", /* mouse button info */ + "KBD", /* keyboard info */ + + /* user command event */ + "COMMAND", /* user command */ + + /* request's status event */ + "STATUS", /* request result */ + "SCROLLED", /* scroll bar scrolled */ + "RESIZE", /* widget resize */ +}; + +#define DBG_MSG(x) rt_kprintf x + +static void rtgui_event_dump(rt_thread_t tid, rtgui_event_t* event) +{ + char* sender = "(unknown)"; + + if ((event->type == RTGUI_EVENT_TIMER) || + (event->type == RTGUI_EVENT_UPDATE_BEGIN) || + (event->type == RTGUI_EVENT_MOUSE_MOTION) || + (event->type == RTGUI_EVENT_UPDATE_END)) + { + /* don't dump timer event */ + return ; + } + + if (event->sender != RT_NULL) + sender = event->sender->name; + + rt_kprintf("%s -- %s --> %s ", sender, event_string[event->type], tid->name); + switch (event->type) + { + case RTGUI_EVENT_PAINT: + { + struct rtgui_event_paint *paint = (struct rtgui_event_paint *)event; + + if(paint->wid != RT_NULL) + rt_kprintf("win: %s", paint->wid->title); + } + break; + + case RTGUI_EVENT_KBD: + { + struct rtgui_event_kbd *ekbd = (struct rtgui_event_kbd*) event; + if (ekbd->wid != RT_NULL) + rt_kprintf("win: %s", ekbd->wid->title); + if (RTGUI_KBD_IS_UP(ekbd)) rt_kprintf(", up"); + else rt_kprintf(", down"); + } + break; + + case RTGUI_EVENT_CLIP_INFO: + { + struct rtgui_event_clip_info *info = (struct rtgui_event_clip_info *)event; + + if(info->wid != RT_NULL) + rt_kprintf("win: %s", info->wid->title); + } + break; + + case RTGUI_EVENT_WIN_CREATE: + { + struct rtgui_event_win_create *create = (struct rtgui_event_win_create*)event; + + rt_kprintf(" win: %s at (x1:%d, y1:%d, x2:%d, y2:%d), addr: %p", +#ifdef RTGUI_USING_SMALL_SIZE + create->wid->title, + RTGUI_WIDGET(create->wid)->extent.x1, + RTGUI_WIDGET(create->wid)->extent.y1, + RTGUI_WIDGET(create->wid)->extent.x2, + RTGUI_WIDGET(create->wid)->extent.y2, +#else + create->title, + create->extent.x1, + create->extent.y1, + create->extent.x2, + create->extent.y2, +#endif + create->wid + ); + } + break; + + case RTGUI_EVENT_UPDATE_END: + { + struct rtgui_event_update_end* update_end = (struct rtgui_event_update_end*)event; + rt_kprintf("(x:%d, y1:%d, x2:%d, y2:%d)", update_end->rect.x1, + update_end->rect.y1, + update_end->rect.x2, + update_end->rect.y2); + } + break; + + case RTGUI_EVENT_WIN_ACTIVATE: + case RTGUI_EVENT_WIN_DEACTIVATE: + case RTGUI_EVENT_WIN_SHOW: + case RTGUI_EVENT_WIN_MODAL_ENTER: + { + struct rtgui_event_win *win = (struct rtgui_event_win *)event; + + if(win->wid != RT_NULL) + rt_kprintf("win: %s", win->wid->title); + } + break; + + case RTGUI_EVENT_WIN_MOVE: + { + struct rtgui_event_win_move *win = (struct rtgui_event_win_move *)event; + + if(win->wid != RT_NULL) + { + rt_kprintf("win: %s", win->wid->title); + rt_kprintf(" to (x:%d, y:%d)", win->x, win->y); + } + } + break; + + case RTGUI_EVENT_WIN_RESIZE: + { + struct rtgui_event_win_resize* win = (struct rtgui_event_win_resize *)event; + + if (win->wid != RT_NULL) + { + rt_kprintf("win: %s, rect(x1:%d, y1:%d, x2:%d, y2:%d)", win->wid->title, + RTGUI_WIDGET(win->wid)->extent.x1, + RTGUI_WIDGET(win->wid)->extent.y1, + RTGUI_WIDGET(win->wid)->extent.x2, + RTGUI_WIDGET(win->wid)->extent.y2); + } + } + break; + + case RTGUI_EVENT_MOUSE_BUTTON: + case RTGUI_EVENT_MOUSE_MOTION: + { + struct rtgui_event_mouse *mouse = (struct rtgui_event_mouse*)event; + + if (mouse->button & RTGUI_MOUSE_BUTTON_LEFT) rt_kprintf("left "); + else rt_kprintf("right "); + + if (mouse->button & RTGUI_MOUSE_BUTTON_DOWN) rt_kprintf("down "); + else rt_kprintf("up "); + + if (mouse->wid != RT_NULL) + rt_kprintf("win: %s at (%d, %d)", mouse->wid->title, + mouse->x, mouse->y); + else + rt_kprintf("(%d, %d)", mouse->x, mouse->y); + } + break; + + case RTGUI_EVENT_MONITOR_ADD: + { + struct rtgui_event_monitor *monitor = (struct rtgui_event_monitor*)event; + if (monitor->wid != RT_NULL) + { + rt_kprintf("win: %s, the rect is:(%d, %d) - (%d, %d)", monitor->wid->title, + monitor->rect.x1, monitor->rect.y1, + monitor->rect.x2, monitor->rect.y2); + } + } + break; + } + + rt_kprintf("\n"); +} +#else +#define DBG_MSG(x) +#define rtgui_event_dump(tid, event) +#endif + +rt_bool_t rtgui_application_event_handler(struct rtgui_object* obj, rtgui_event_t* event); + +static void _rtgui_application_constructor(struct rtgui_application *app) +{ + /* set event handler */ + rtgui_object_set_event_handler(RTGUI_OBJECT(app), + rtgui_application_event_handler); + + app->name = RT_NULL; + /* set EXITED so we can destroy an application that just created */ + app->state_flag = RTGUI_APPLICATION_FLAG_EXITED; + app->ref_count = 0; + app->exit_code = 0; + app->tid = RT_NULL; + app->server = RT_NULL; + app->mq = RT_NULL; + app->modal_object = RT_NULL; + app->on_idle = RT_NULL; +} + +static void _rtgui_application_destructor(struct rtgui_application *app) +{ + RT_ASSERT(app != RT_NULL); + + rt_free(app->name); + app->name = RT_NULL; +} + +DEFINE_CLASS_TYPE(application, "application", + RTGUI_OBJECT_TYPE, + _rtgui_application_constructor, + _rtgui_application_destructor, + sizeof(struct rtgui_application)); + +struct rtgui_application* rtgui_application_create( + rt_thread_t tid, + const char *myname) +{ + struct rtgui_application *app; + + RT_ASSERT(tid != RT_NULL); + RT_ASSERT(myname != RT_NULL); + + /* create application */ + app = RTGUI_APPLICATION(rtgui_object_create(RTGUI_APPLICATION_TYPE)); + if (app == RT_NULL) + return RT_NULL; + + DBG_MSG(("register a rtgui application(%s) on thread %s\n", myname, tid->name)); + + app->tid = tid; + /* set user thread */ + tid->user_data = (rt_uint32_t)app; + + app->mq = rt_mq_create("rtgui", sizeof(union rtgui_event_generic), 32, RT_IPC_FLAG_FIFO); + if (app->mq == RT_NULL) + { + rt_kprintf("mq err\n"); + goto __mq_err; + } + + /* set application title */ + app->name = (unsigned char*)rt_strdup((char*)myname); + if (app->name != RT_NULL) + return app; + +__mq_err: + rtgui_object_destroy(RTGUI_OBJECT(app)); + tid->user_data = 0; + return RT_NULL; +} + +#define _rtgui_application_check(app) \ +do { \ + RT_ASSERT(app != RT_NULL); \ + RT_ASSERT(app->tid != RT_NULL); \ + RT_ASSERT(app->tid->user_data != 0); \ + RT_ASSERT(app->mq != RT_NULL); \ +} while (0) + +void rtgui_application_destroy(struct rtgui_application *app) +{ + _rtgui_application_check(app); + + if (!(app->state_flag & RTGUI_APPLICATION_FLAG_EXITED)) + { + rt_kprintf("cannot destroy a running application: %s.\n", + app->name); + return; + } + + app->tid->user_data = 0; + rt_mq_delete(app->mq); + rtgui_object_destroy(RTGUI_OBJECT(app)); +} + +struct rtgui_application* rtgui_application_self(void) +{ + struct rtgui_application *app; + rt_thread_t self; + + /* get current thread */ + self = rt_thread_self(); + app = (struct rtgui_application*)(self->user_data); + + return app; +} + +void rtgui_application_set_onidle(rtgui_idle_func onidle) +{ + struct rtgui_application *app; + + app = rtgui_application_self(); + if (app != RT_NULL) + app->on_idle = onidle; +} + +rtgui_idle_func rtgui_application_get_onidle(void) +{ + struct rtgui_application *app; + + app = rtgui_application_self(); + if (app != RT_NULL) + return app->on_idle; + else + return RT_NULL; +} + +extern rt_thread_t rt_thread_find(char* name); +rt_thread_t rtgui_application_get_server(void) +{ + return rt_thread_find("rtgui"); +} + +rt_err_t rtgui_application_send(rt_thread_t tid, rtgui_event_t* event, rt_size_t event_size) +{ + rt_err_t result; + struct rtgui_application *app; + + RT_ASSERT(tid != RT_NULL); + RT_ASSERT(event != RT_NULL); + RT_ASSERT(event_size != 0); + + rtgui_event_dump(tid, event); + + /* find struct rtgui_application */ + app = (struct rtgui_application*) (tid->user_data); + if (app == RT_NULL) + return -RT_ERROR; + + result = rt_mq_send(app->mq, event, event_size); + if (result != RT_EOK) + { + if (event->type != RTGUI_EVENT_TIMER) + rt_kprintf("send event to %s failed\n", app->tid->name); + } + + return result; +} + +rt_err_t rtgui_application_send_urgent(rt_thread_t tid, rtgui_event_t* event, rt_size_t event_size) +{ + rt_err_t result; + struct rtgui_application *app; + + RT_ASSERT(tid != RT_NULL); + RT_ASSERT(event != RT_NULL); + RT_ASSERT(event_size != 0); + + rtgui_event_dump(tid, event); + + /* find rtgui_application */ + app = (struct rtgui_application*) (tid->user_data); + if (app == RT_NULL) + return -RT_ERROR; + + result = rt_mq_urgent(app->mq, event, event_size); + if (result != RT_EOK) + rt_kprintf("send ergent event failed\n"); + + return result; +} + +rt_err_t rtgui_application_send_sync(rt_thread_t tid, rtgui_event_t* event, rt_size_t event_size) +{ + rt_err_t r; + struct rtgui_application *app; + rt_int32_t ack_buffer, ack_status; + struct rt_mailbox ack_mb; + + RT_ASSERT(tid != RT_NULL); + RT_ASSERT(event != RT_NULL); + RT_ASSERT(event_size != 0); + + rtgui_event_dump(tid, event); + + /* init ack mailbox */ + r = rt_mb_init(&ack_mb, "ack", &ack_buffer, 1, 0); + if (r!= RT_EOK) + goto __return; + + app = (struct rtgui_application*) (tid->user_data); + if (app == RT_NULL) + { + r = -RT_ERROR; + goto __return; + } + + event->ack = &ack_mb; + r = rt_mq_send(app->mq, event, event_size); + if (r != RT_EOK) + { + rt_kprintf("send sync event failed\n"); + goto __return; + } + + r = rt_mb_recv(&ack_mb, (rt_uint32_t*)&ack_status, RT_WAITING_FOREVER); + if (r!= RT_EOK) + goto __return; + + if (ack_status != RTGUI_STATUS_OK) + r = -RT_ERROR; + else + r = RT_EOK; + +__return: + /* fini ack mailbox */ + rt_mb_detach(&ack_mb); + return r; +} + +rt_err_t rtgui_application_ack(rtgui_event_t* event, rt_int32_t status) +{ + RT_ASSERT(event != RT_NULL); + RT_ASSERT(event->ack != RT_NULL); + + rt_mb_send(event->ack, status); + + return RT_EOK; +} + +rt_err_t rtgui_application_recv(rtgui_event_t* event, rt_size_t event_size) +{ + struct rtgui_application* app; + rt_err_t r; + + RT_ASSERT(event != RT_NULL); + RT_ASSERT(event_size != 0); + + app = (struct rtgui_application*) (rt_thread_self()->user_data); + if (app == RT_NULL) + return -RT_ERROR; + + r = rt_mq_recv(app->mq, event, event_size, RT_WAITING_FOREVER); + + return r; +} + +rt_err_t rtgui_application_recv_nosuspend(rtgui_event_t* event, rt_size_t event_size) +{ + struct rtgui_application *app; + rt_err_t r; + + RT_ASSERT(event != RT_NULL); + RT_ASSERT(event != 0); + + app = (struct rtgui_application*) (rt_thread_self()->user_data); + if (app == RT_NULL) + return -RT_ERROR; + + r = rt_mq_recv(app->mq, event, event_size, 0); + + return r; +} + +rt_err_t rtgui_application_recv_filter(rt_uint32_t type, rtgui_event_t* event, rt_size_t event_size) +{ + struct rtgui_application *app; + + RT_ASSERT(event != RT_NULL); + RT_ASSERT(event_size != 0); + + app = (struct rtgui_application*) (rt_thread_self()->user_data); + if (app == RT_NULL) + return -RT_ERROR; + + while (rt_mq_recv(app->mq, event, event_size, RT_WAITING_FOREVER) == RT_EOK) + { + if (event->type == type) + { + return RT_EOK; + } + else + { + if (RTGUI_OBJECT(app)->event_handler != RT_NULL) + { + RTGUI_OBJECT(app)->event_handler(RTGUI_OBJECT(app), event); + } + } + } + + return -RT_ERROR; +} + +rt_inline rt_bool_t _rtgui_application_dest_handle( + struct rtgui_application *app, + struct rtgui_event *event) +{ + struct rtgui_event_win* wevent = (struct rtgui_event_win*)event; + + struct rtgui_object* dest_object = RTGUI_OBJECT(wevent->wid); + + if (dest_object != RT_NULL) + { + if (dest_object->event_handler != RT_NULL) + return dest_object->event_handler(RTGUI_OBJECT(dest_object), event); + else + return RT_FALSE; + } + else + { + rt_kprintf("RTGUI ERROR:server sent a event(%d) without wid\n", event->type); + return RT_FALSE; + } +} + +rt_bool_t rtgui_application_event_handler(struct rtgui_object* object, rtgui_event_t* event) +{ + struct rtgui_application* app; + + RT_ASSERT(object != RT_NULL); + RT_ASSERT(event != RT_NULL); + + app = RTGUI_APPLICATION(object); + + switch (event->type) + { + case RTGUI_EVENT_PAINT: + case RTGUI_EVENT_CLIP_INFO: + case RTGUI_EVENT_WIN_ACTIVATE: + case RTGUI_EVENT_WIN_DEACTIVATE: + case RTGUI_EVENT_WIN_CLOSE: + case RTGUI_EVENT_WIN_MOVE: + case RTGUI_EVENT_KBD: + _rtgui_application_dest_handle(app, event); + break; + + case RTGUI_EVENT_MOUSE_BUTTON: + case RTGUI_EVENT_MOUSE_MOTION: + { + struct rtgui_event_win* wevent = (struct rtgui_event_win*)event; + struct rtgui_object* dest_object = RTGUI_OBJECT(wevent->wid); + + // FIXME: let application determine the dest_wiget but not in sever + // so we can combine this handler with above one + if (app->modal_object != RT_NULL && + dest_object != app->modal_object) + { +// rt_kprintf("discard event %s that is not sent to modal object\n", +// event_string[event->type]); + } + else + { + _rtgui_application_dest_handle(app, event); + } + } + break; + + case RTGUI_EVENT_TIMER: + { + struct rtgui_timer* timer; + struct rtgui_event_timer* etimer = (struct rtgui_event_timer*) event; + + timer = etimer->timer; + if (timer->timeout != RT_NULL) + { + /* call timeout function */ + timer->timeout(timer, timer->user_data); + } + } + break; + + case RTGUI_EVENT_COMMAND: + { + struct rtgui_event_command *ecmd = (struct rtgui_event_command*)event; + + if (ecmd->wid != RT_NULL) + return _rtgui_application_dest_handle(app, event); + } + + default: + return rtgui_object_event_handler(object, event); + } + + return RT_TRUE; +} + +rt_inline void _rtgui_application_event_loop(struct rtgui_application *app) +{ + rt_err_t result; + rt_uint16_t current_ref; + struct rtgui_event *event; + + _rtgui_application_check(app); + + /* point to event buffer */ + event = (struct rtgui_event*)app->event_buffer; + + current_ref = ++app->ref_count; + + while (current_ref <= app->ref_count) + { + RT_ASSERT(current_ref == app->ref_count); + + if (app->on_idle != RT_NULL) + { + result = rtgui_application_recv_nosuspend(event, sizeof(union rtgui_event_generic)); + if (result == RT_EOK) + RTGUI_OBJECT(app)->event_handler(RTGUI_OBJECT(app), event); + else if (result == -RT_ETIMEOUT) + app->on_idle(RTGUI_OBJECT(app), RT_NULL); + } + else + { + result = rtgui_application_recv(event, sizeof(union rtgui_event_generic)); + if (result == RT_EOK) + RTGUI_OBJECT(app)->event_handler(RTGUI_OBJECT(app), event); + } + } +} + +rt_base_t rtgui_application_run(struct rtgui_application *app) +{ + _rtgui_application_check(app); + + app->state_flag &= ~RTGUI_APPLICATION_FLAG_EXITED; + + _rtgui_application_event_loop(app); + + if (app->ref_count == 0) + app->state_flag |= RTGUI_APPLICATION_FLAG_EXITED; + + return app->exit_code; +} + +void rtgui_application_exit(struct rtgui_application* app, rt_uint16_t code) +{ + --app->ref_count; + app->exit_code = code; +} diff --git a/components/rtgui/server/server.c b/components/rtgui/server/server.c index 5b90b64b1b..10ddfbf77a 100644 --- a/components/rtgui/server/server.c +++ b/components/rtgui/server/server.c @@ -15,176 +15,15 @@ #include <rtgui/rtgui.h> #include <rtgui/event.h> #include <rtgui/rtgui_system.h> +#include <rtgui/rtgui_object.h> +#include <rtgui/rtgui_application.h> #include <rtgui/driver.h> #include "mouse.h" -#include "panel.h" #include "topwin.h" static struct rt_thread *rtgui_server_tid; -static struct rt_messagequeue *rtgui_server_mq; - -extern struct rtgui_topwin* rtgui_server_focus_topwin; -struct rtgui_panel* rtgui_server_focus_panel = RT_NULL; - -void rtgui_server_create_application(struct rtgui_event_panel_attach* event) -{ - struct rtgui_panel* panel = rtgui_panel_find(event->panel_name); - - if (panel != RT_NULL) - { - struct rtgui_event_panel_info ep; - RTGUI_EVENT_PANEL_INFO_INIT(&ep); - - if (panel->wm_thread != RT_NULL) - { - /* notify to workbench */ - rtgui_thread_send(panel->wm_thread, &(event->parent), sizeof(struct rtgui_event_panel_attach)); - } - - /* send the responses - ok */ - rtgui_thread_ack(RTGUI_EVENT(event), RTGUI_STATUS_OK); - - /* send the panel info */ - ep.panel = panel; - ep.extent = panel->extent; - rtgui_thread_send(event->parent.sender, (struct rtgui_event*)&ep, sizeof(ep)); - - rtgui_panel_thread_add(event->panel_name, event->parent.sender); - } - else - { - /* send the responses - failure */ - rtgui_thread_ack(RTGUI_EVENT(event), RTGUI_STATUS_NRC); - } -} - -void rtgui_server_destroy_application(struct rtgui_event_panel_detach* event) -{ - struct rtgui_panel* panel = event->panel; - - if (panel != RT_NULL) - { - if (panel->wm_thread != RT_NULL) - { - /* notify to workbench */ - rtgui_thread_send(panel->wm_thread, &(event->parent), sizeof(struct rtgui_event_panel_detach)); - } - - /* send the responses */ - rtgui_thread_ack(RTGUI_EVENT(event), RTGUI_STATUS_OK); - - rtgui_panel_thread_remove(panel, event->parent.sender); - - { - /* get next thread and active it */ - rt_thread_t tid = rtgui_panel_get_active_thread(panel); - if (tid != RT_NULL) - { - /* let this thread repaint */ - struct rtgui_event_paint epaint; - RTGUI_EVENT_PAINT_INIT(&epaint); - epaint.wid = RT_NULL; - rtgui_thread_send(tid, (struct rtgui_event*)&epaint, sizeof(epaint)); - } - } - } - else - { - /* send the responses - failure */ - rtgui_thread_ack(RTGUI_EVENT(event), RTGUI_STATUS_NRC); - } -} - -void rtgui_server_thread_panel_show(struct rtgui_event_panel_show* event) -{ - struct rtgui_panel* panel = event->panel; - - if (panel != RT_NULL) - { - struct rtgui_event_paint epaint; - - /* send the responses */ - rtgui_thread_ack(RTGUI_EVENT(event), RTGUI_STATUS_OK); - - if (panel->wm_thread != RT_NULL) - { - /* notify to workbench */ - rtgui_thread_send(panel->wm_thread, &(event->parent), sizeof(struct rtgui_event_panel_show)); - } - - rtgui_panel_set_active_thread(panel, event->parent.sender); - - /* send all topwin clip info */ - rtgui_topwin_update_clip_to_panel(panel); - - /* send paint event */ - RTGUI_EVENT_PAINT_INIT(&epaint); - epaint.wid = RT_NULL; - rtgui_thread_send(event->parent.sender, (struct rtgui_event*)&epaint, - sizeof(epaint)); - } - else - { - /* send failed */ - rtgui_thread_ack(RTGUI_EVENT(event), RTGUI_STATUS_ERROR); - } -} - -void rtgui_server_thread_panel_hide(struct rtgui_event_panel_hide* event) -{ - struct rtgui_panel* panel = event->panel; - - if (panel != RT_NULL) - { - rt_thread_t tid; - - /* send the responses */ - rtgui_thread_ack(RTGUI_EVENT(event), RTGUI_STATUS_OK); - - if (panel->thread_list.next != RT_NULL) - { - struct rtgui_panel_thread* thread; - thread = rtgui_list_entry(panel->thread_list.next, struct rtgui_panel_thread, list); - - /* remove it */ - panel->thread_list.next = thread->list.next; - - /* append to the tail of thread list */ - rtgui_list_append(&(panel->thread_list), &(thread->list)); - } - - /* send all topwin clip info */ - rtgui_topwin_update_clip_to_panel(panel); - - /* get new active thread */ - tid = rtgui_panel_get_active_thread(panel); - if (tid != RT_NULL) - { - struct rtgui_event_paint epaint; - - /* send paint event */ - RTGUI_EVENT_PAINT_INIT(&epaint); - epaint.wid = RT_NULL; - rtgui_thread_send(tid, (struct rtgui_event*)&epaint, sizeof(epaint)); - } - } - else - { - /* send failed */ - rtgui_thread_ack(RTGUI_EVENT(event), RTGUI_STATUS_ERROR); - } -} - -void rtgui_server_handle_set_wm(struct rtgui_event_set_wm *event) -{ - struct rtgui_panel* panel = rtgui_panel_find(event->panel_name); - - if (panel != RT_NULL) - { - rtgui_panel_set_wm(panel, event->parent.sender); - } -} +static struct rtgui_application *rtgui_server_application; void rtgui_server_handle_update(struct rtgui_event_update_end* event) { @@ -199,36 +38,19 @@ void rtgui_server_handle_update(struct rtgui_event_update_end* event) void rtgui_server_handle_monitor_add(struct rtgui_event_monitor* event) { - if (event->panel != RT_NULL) - { - /* append monitor rect to panel list */ - rtgui_panel_append_monitor_rect(event->panel, event->parent.sender, &(event->rect)); - } - else - { - /* add monitor rect to top window list */ - rtgui_topwin_append_monitor_rect(event->wid, &(event->rect)); - } + /* add monitor rect to top window list */ + rtgui_topwin_append_monitor_rect(event->wid, &(event->rect)); } void rtgui_server_handle_monitor_remove(struct rtgui_event_monitor* event) { - if (event->panel != RT_NULL) - { - /* add monitor rect to panel list */ - rtgui_panel_remove_monitor_rect(event->panel, event->parent.sender, &(event->rect)); - } - else - { - /* add monitor rect to top window list */ - rtgui_topwin_remove_monitor_rect(event->wid, &(event->rect)); - } + /* add monitor rect to top window list */ + rtgui_topwin_remove_monitor_rect(event->wid, &(event->rect)); } void rtgui_server_handle_mouse_btn(struct rtgui_event_mouse* event) { struct rtgui_topwin* wnd; - struct rtgui_panel* panel; /* re-init to server thread */ RTGUI_EVENT_MOUSE_BUTTON_INIT(event); @@ -263,7 +85,7 @@ void rtgui_server_handle_mouse_btn(struct rtgui_event_mouse* event) } /* send to client thread */ - rtgui_thread_send(topwin->tid, &(ewin.parent), sizeof(ewin)); + rtgui_application_send(topwin->tid, &(ewin.parent), sizeof(ewin)); return; } @@ -271,16 +93,15 @@ void rtgui_server_handle_mouse_btn(struct rtgui_event_mouse* event) #endif /* get the wnd which contains the mouse */ - wnd = rtgui_topwin_get_wnd(event->x, event->y); + wnd = rtgui_topwin_get_wnd_no_modaled(event->x, event->y); if (wnd != RT_NULL) { event->wid = wnd->wid; - if (rtgui_server_focus_topwin != wnd) + if (rtgui_topwin_get_focus() != wnd) { /* raise this window */ rtgui_topwin_activate_win(wnd); - rtgui_server_focus_panel = RT_NULL; } if (wnd->title != RT_NULL && @@ -291,137 +112,39 @@ void rtgui_server_handle_mouse_btn(struct rtgui_event_mouse* event) else { /* send mouse event to thread */ - rtgui_thread_send(wnd->tid, (struct rtgui_event*)event, sizeof(struct rtgui_event_mouse)); + rtgui_application_send(wnd->tid, (struct rtgui_event*)event, sizeof(struct rtgui_event_mouse)); } return ; } - - /* get the panel which contains the mouse */ - panel = rtgui_panel_get_contain(event->x, event->y); - if ((panel != RT_NULL) && (panel->is_focusable == RT_TRUE)) - { - /* deactivate old window */ - if (rtgui_server_focus_topwin != RT_NULL) - { - rtgui_topwin_deactivate_win(rtgui_server_focus_topwin); - } - - rtgui_server_focus_panel = panel; - rtgui_server_focus_topwin = RT_NULL; - - /* set destination window to null */ - event->wid = RT_NULL; - - /* send mouse event to thread */ - if (rtgui_panel_get_active_thread(panel) != RT_NULL) - { - rtgui_thread_send(rtgui_panel_get_active_thread(panel), - (struct rtgui_event*)event, - sizeof(struct rtgui_event_mouse)); - } - } } -static struct rtgui_panel* last_monitor_panel = RT_NULL; static struct rtgui_topwin* last_monitor_topwin = RT_NULL; void rtgui_server_handle_mouse_motion(struct rtgui_event_mouse* event) { /* the topwin contains current mouse */ struct rtgui_topwin* win = RT_NULL; - struct rtgui_panel* panel = RT_NULL; /* re-init mouse event */ RTGUI_EVENT_MOUSE_MOTION_INIT(event); - /* find the panel or topwin which monitor the mouse motion */ - win = rtgui_topwin_get_wnd(event->x, event->y); - if (win == RT_NULL) - { - /* try to find monitor on the panel */ - panel = rtgui_panel_get_contain(event->x, event->y); - - if (panel != RT_NULL) - { - struct rtgui_panel_thread* thread; - - /* get active panel thread */ - if (panel->thread_list.next != RT_NULL) - { - thread = rtgui_list_entry(panel->thread_list.next, struct rtgui_panel_thread, list); - if (!rtgui_mouse_monitor_contains_point(&(thread->monitor_list), - event->x, event->y) == RT_TRUE) - { - /* no monitor in this panel */ - panel = RT_NULL; - } - } - } - } - else if (win->monitor_list.next != RT_NULL) + win = rtgui_topwin_get_wnd_no_modaled(event->x, event->y); + if (win != RT_NULL && win->monitor_list.next != RT_NULL) { + // FIXME: /* check whether the monitor exist */ - if (rtgui_mouse_monitor_contains_point(&(win->monitor_list), event->x, event->y) != RT_TRUE) + if (rtgui_mouse_monitor_contains_point(&(win->monitor_list), + event->x, event->y) != RT_TRUE) { win = RT_NULL; - - /* try to find monitor on the panel */ - panel = rtgui_panel_get_contain(event->x, event->y); - if (panel != RT_NULL) - { - struct rtgui_panel_thread* thread; - - /* get active panel thread */ - if (panel->thread_list.next != RT_NULL) - { - thread = rtgui_list_entry(panel->thread_list.next, struct rtgui_panel_thread, list); - if (!rtgui_mouse_monitor_contains_point(&(thread->monitor_list), - event->x, event->y) == RT_TRUE) - { - /* no monitor in this panel */ - panel = RT_NULL; - } - } - } } } - else - { - win = RT_NULL; - } - - /* check old panel or window */ - if (last_monitor_panel != RT_NULL) - { - rt_thread_t tid = rtgui_panel_get_active_thread(last_monitor_panel); - /* send mouse motion event */ - if (tid != RT_NULL) - { - event->wid = RT_NULL; - rtgui_thread_send(tid, &(event->parent), sizeof(struct rtgui_event_mouse)); - } - } - else if (last_monitor_topwin != RT_NULL) + if (last_monitor_topwin != RT_NULL) { event->wid = last_monitor_topwin->wid; - /* send mouse motion event */ - rtgui_thread_send(last_monitor_topwin->tid, &(event->parent), sizeof(struct rtgui_event_mouse)); - } - - if (last_monitor_panel != panel) - { - last_monitor_panel = panel; - if (last_monitor_panel != RT_NULL) - { - rt_thread_t tid = rtgui_panel_get_active_thread(last_monitor_panel); - event->wid = RT_NULL; - - /* send mouse motion event */ - if (tid != RT_NULL) - rtgui_thread_send(tid, &(event->parent), sizeof(struct rtgui_event_mouse)); - } + rtgui_application_send(last_monitor_topwin->tid, &(event->parent), sizeof(struct rtgui_event_mouse)); } if (last_monitor_topwin != win) @@ -432,7 +155,7 @@ void rtgui_server_handle_mouse_motion(struct rtgui_event_mouse* event) event->wid = last_monitor_topwin->wid; /* send mouse motion event */ - rtgui_thread_send(last_monitor_topwin->tid, &(event->parent), sizeof(struct rtgui_event_mouse)); + rtgui_application_send(last_monitor_topwin->tid, &(event->parent), sizeof(struct rtgui_event_mouse)); } } @@ -443,203 +166,191 @@ void rtgui_server_handle_mouse_motion(struct rtgui_event_mouse* event) void rtgui_server_handle_kbd(struct rtgui_event_kbd* event) { struct rtgui_topwin* wnd; - struct rtgui_panel* panel; /* re-init to server thread */ RTGUI_EVENT_KBD_INIT(event); /* todo: handle input method and global shortcut */ - /* send to focus window or focus panel */ - wnd = rtgui_server_focus_topwin; - if (wnd != RT_NULL && wnd->flag & WINTITLE_ACTIVATE) + wnd = rtgui_topwin_get_focus(); + if (wnd != RT_NULL) { + RT_ASSERT(wnd->flag & WINTITLE_ACTIVATE) + /* send to focus window */ event->wid = wnd->wid; /* send keyboard event to thread */ - rtgui_thread_send(wnd->tid, (struct rtgui_event*)event, sizeof(struct rtgui_event_kbd)); + rtgui_application_send(wnd->tid, (struct rtgui_event*)event, sizeof(struct rtgui_event_kbd)); return; } - - panel = rtgui_server_focus_panel; - if (panel != RT_NULL) - { - rt_thread_t tid; - - /* get active thread in this panel */ - tid = rtgui_panel_get_active_thread(panel); - if (tid != RT_NULL) - { - /* send to focus panel */ - event->wid = RT_NULL; - - /* send keyboard event to thread */ - rtgui_thread_send(tid, (struct rtgui_event*)event, sizeof(struct rtgui_event_kbd)); - } - } } -#ifdef __WIN32__ +#ifdef _WIN32 #include <windows.h> #endif -/** - * rtgui server thread's entry - */ -static void rtgui_server_entry(void* parameter) +static rt_bool_t rtgui_server_event_handler(struct rtgui_object *object, + struct rtgui_event *event) { -#ifdef __WIN32__ - /* set the server thread to highest */ - HANDLE hCurrentThread = GetCurrentThread(); - SetThreadPriority(hCurrentThread, THREAD_PRIORITY_HIGHEST); -#endif + RT_ASSERT(object != RT_NULL); + RT_ASSERT(event != RT_NULL); -#ifdef RTGUI_USING_SMALL_SIZE - /* create rtgui server msgq */ - rtgui_server_mq = rt_mq_create("rtgui", - 32, 16, RT_IPC_FLAG_FIFO); -#else - /* create rtgui server msgq */ - rtgui_server_mq = rt_mq_create("rtgui", - 256, 8, RT_IPC_FLAG_FIFO); -#endif - /* register rtgui server thread */ - rtgui_thread_register(rtgui_server_tid, rtgui_server_mq); + /* dispatch event */ + switch (event->type) + { + /* window event */ + case RTGUI_EVENT_WIN_CREATE: + if (rtgui_topwin_add((struct rtgui_event_win_create*)event) == RT_EOK) + rtgui_application_ack(event, RTGUI_STATUS_OK); + else + rtgui_application_ack(event, RTGUI_STATUS_ERROR); + break; - /* init mouse and show */ - rtgui_mouse_init(); -#ifdef RTGUI_USING_MOUSE_CURSOR - rtgui_mouse_show_cursor(); -#endif + case RTGUI_EVENT_WIN_DESTROY: + if (last_monitor_topwin != RT_NULL && + last_monitor_topwin->wid == ((struct rtgui_event_win*)event)->wid) + last_monitor_topwin = RT_NULL; + if (rtgui_topwin_remove(((struct rtgui_event_win*)event)->wid) == RT_EOK) + rtgui_application_ack(event, RTGUI_STATUS_OK); + else + rtgui_application_ack(event, RTGUI_STATUS_ERROR); + break; - while (1) - { - /* the buffer uses to receive event */ -#ifdef RTGUI_USING_SMALL_SIZE - char event_buf[64]; -#else - char event_buf[256]; -#endif - struct rtgui_event* event = (struct rtgui_event*)&(event_buf[0]); + case RTGUI_EVENT_WIN_SHOW: + if (rtgui_topwin_show((struct rtgui_event_win*)event) == RT_EOK) + rtgui_application_ack(event, RTGUI_STATUS_OK); + else + rtgui_application_ack(event, RTGUI_STATUS_ERROR); + break; - if (rtgui_thread_recv(event, sizeof(event_buf)) == RT_EOK) - { - /* dispatch event */ - switch (event->type) - { - /* panel event */ - case RTGUI_EVENT_PANEL_ATTACH: - /* register an application in panel */ - rtgui_server_create_application((struct rtgui_event_panel_attach*)event); - break; + case RTGUI_EVENT_WIN_HIDE: + if (rtgui_topwin_hide((struct rtgui_event_win*)event) == RT_EOK) + rtgui_application_ack(event, RTGUI_STATUS_OK); + else + rtgui_application_ack(event, RTGUI_STATUS_ERROR); + break; - case RTGUI_EVENT_PANEL_DETACH: - /* unregister an application */ - rtgui_server_destroy_application((struct rtgui_event_panel_detach*)event); - break; + case RTGUI_EVENT_WIN_MOVE: + if (rtgui_topwin_move((struct rtgui_event_win_move*)event) == RT_EOK) + rtgui_application_ack(event, RTGUI_STATUS_OK); + else + rtgui_application_ack(event, RTGUI_STATUS_ERROR); + break; - case RTGUI_EVENT_PANEL_SHOW: - /* handle raise an application */ - rtgui_server_thread_panel_show((struct rtgui_event_panel_show*)event); - break; + case RTGUI_EVENT_WIN_MODAL_ENTER: + if (rtgui_topwin_modal_enter((struct rtgui_event_win_modal_enter*)event) == RT_EOK) + rtgui_application_ack(event, RTGUI_STATUS_OK); + else + rtgui_application_ack(event, RTGUI_STATUS_ERROR); + break; - case RTGUI_EVENT_PANEL_HIDE: - /* handle hide an application */ - rtgui_server_thread_panel_hide((struct rtgui_event_panel_hide*)event); - break; + case RTGUI_EVENT_WIN_RESIZE: + rtgui_topwin_resize(((struct rtgui_event_win_resize*)event)->wid, + &(((struct rtgui_event_win_resize*)event)->rect)); + break; - case RTGUI_EVENT_SET_WM: - /* handle set workbench manager event */ - rtgui_server_handle_set_wm((struct rtgui_event_set_wm*)event); - break; + /* other event */ + case RTGUI_EVENT_UPDATE_BEGIN: +#ifdef RTGUI_USING_MOUSE_CURSOR + /* hide cursor */ + rtgui_mouse_hide_cursor(); +#endif + break; - /* window event */ - case RTGUI_EVENT_WIN_CREATE: - rtgui_thread_ack(event, RTGUI_STATUS_OK); - rtgui_topwin_add((struct rtgui_event_win_create*)event); - break; + case RTGUI_EVENT_UPDATE_END: + /* handle screen update */ + rtgui_server_handle_update((struct rtgui_event_update_end*)event); +#ifdef RTGUI_USING_MOUSE_CURSOR + /* show cursor */ + rtgui_mouse_show_cursor(); +#endif + break; - case RTGUI_EVENT_WIN_DESTROY: - if (rtgui_topwin_remove(((struct rtgui_event_win*)event)->wid) == RT_EOK) - rtgui_thread_ack(event, RTGUI_STATUS_OK); - else - rtgui_thread_ack(event, RTGUI_STATUS_ERROR); - break; + case RTGUI_EVENT_MONITOR_ADD: + /* handle mouse monitor */ + rtgui_server_handle_monitor_add((struct rtgui_event_monitor*)event); + break; - case RTGUI_EVENT_WIN_SHOW: - rtgui_topwin_show((struct rtgui_event_win*)event); - break; + /* mouse and keyboard event */ + case RTGUI_EVENT_MOUSE_MOTION: + /* handle mouse motion event */ + rtgui_server_handle_mouse_motion((struct rtgui_event_mouse*)event); + break; - case RTGUI_EVENT_WIN_HIDE: - rtgui_topwin_hide((struct rtgui_event_win*)event); - break; + case RTGUI_EVENT_MOUSE_BUTTON: + /* handle mouse button */ + rtgui_server_handle_mouse_btn((struct rtgui_event_mouse*)event); + break; - case RTGUI_EVENT_WIN_MOVE: - rtgui_topwin_move((struct rtgui_event_win_move*)event); - break; + case RTGUI_EVENT_KBD: + /* handle keyboard event */ + rtgui_server_handle_kbd((struct rtgui_event_kbd*)event); + break; - case RTGUI_EVENT_WIN_RESIZE: - rtgui_topwin_resize(((struct rtgui_event_win_resize*)event)->wid, - &(((struct rtgui_event_win_resize*)event)->rect)); - break; + case RTGUI_EVENT_COMMAND: + break; + } - /* other event */ - case RTGUI_EVENT_UPDATE_BEGIN: -#ifdef RTGUI_USING_MOUSE_CURSOR - /* hide cursor */ - rtgui_mouse_hide_cursor(); -#endif - break; + return RT_TRUE; +} - case RTGUI_EVENT_UPDATE_END: - /* handle screen update */ - rtgui_server_handle_update((struct rtgui_event_update_end*)event); -#ifdef RTGUI_USING_MOUSE_CURSOR - /* show cursor */ - rtgui_mouse_show_cursor(); +/** + * rtgui server thread's entry + */ +static void rtgui_server_entry(void* parameter) +{ +#ifdef _WIN32 + /* set the server thread to highest */ + HANDLE hCurrentThread = GetCurrentThread(); + SetThreadPriority(hCurrentThread, THREAD_PRIORITY_HIGHEST); #endif - break; - case RTGUI_EVENT_MONITOR_ADD: - /* handle mouse monitor */ - rtgui_server_handle_monitor_add((struct rtgui_event_monitor*)event); - break; - - /* mouse and keyboard event */ - case RTGUI_EVENT_MOUSE_MOTION: - /* handle mouse motion event */ - rtgui_server_handle_mouse_motion((struct rtgui_event_mouse*)event); - break; - - case RTGUI_EVENT_MOUSE_BUTTON: - /* handle mouse button */ - rtgui_server_handle_mouse_btn((struct rtgui_event_mouse*)event); - break; + /* register rtgui server thread */ + rtgui_server_application = rtgui_application_create(rtgui_server_tid, + "rtgui"); + if (rtgui_server_application == RT_NULL) + return; - case RTGUI_EVENT_KBD: - /* handle keyboard event */ - rtgui_server_handle_kbd((struct rtgui_event_kbd*)event); - break; + rtgui_object_set_event_handler(RTGUI_OBJECT(rtgui_server_application), + rtgui_server_event_handler); + /* init mouse and show */ + rtgui_mouse_init(); +#ifdef RTGUI_USING_MOUSE_CURSOR + rtgui_mouse_show_cursor(); +#endif - case RTGUI_EVENT_COMMAND: - break; - } - } - } + rtgui_application_run(rtgui_server_application); - /* unregister in rtgui thread */ - // rtgui_thread_deregister(rt_thread_self()); + rtgui_application_destroy(rtgui_server_application); + rtgui_server_application = RT_NULL; } void rtgui_server_post_event(struct rtgui_event* event, rt_size_t size) { - rt_mq_send(rtgui_server_mq, event, size); + if (rtgui_server_tid != RT_NULL) + rtgui_application_send(rtgui_server_tid, event, size); + else + rt_kprintf("post when server is not running\n"); +} + +rt_err_t rtgui_server_post_event_sync(struct rtgui_event* event, rt_size_t size) +{ + if (rtgui_server_tid != RT_NULL) + return rtgui_application_send_sync(rtgui_server_tid, event, size); + else + { + rt_kprintf("post when server is not running\n"); + return -RT_ENOSYS; + } } -void rtgui_server_init() +void rtgui_server_init(void) { + if (rtgui_server_tid != RT_NULL) + return; + rtgui_server_tid = rt_thread_create("rtgui", rtgui_server_entry, RT_NULL, RTGUI_SVR_THREAD_STACK_SIZE, diff --git a/components/rtgui/server/topwin.c b/components/rtgui/server/topwin.c index 498f8987a8..14c9432b18 100644 --- a/components/rtgui/server/topwin.c +++ b/components/rtgui/server/topwin.c @@ -11,51 +11,82 @@ * Date Author Notes * 2009-10-16 Bernard first version */ -#include "panel.h" #include "topwin.h" #include "mouse.h" +#include <rtgui/dlist.h> #include <rtgui/event.h> #include <rtgui/image.h> #include <rtgui/rtgui_theme.h> #include <rtgui/rtgui_system.h> +#include <rtgui/rtgui_application.h> #include <rtgui/widgets/window.h> -struct rtgui_topwin* rtgui_server_focus_topwin = RT_NULL; +/* This list is divided into two parts. The first part is the shown list, in + * which all the windows have the WINTITLE_SHOWN flag set. Second part is the + * hidden list, in which all the windows don't have WINTITLE_SHOWN flag. + * + * The active window is the one that would receive kbd events. It should always + * in the first tree. The order of this list is the order of the windows. + * Thus, the first item is the top most window and the last item is the bottom + * window. Top window can always clip the window beneath it when the two + * overlapping. Child window can always clip it's parent. Slibing windows can + * clip each other with the same rule as this list. Thus, each child list is + * the same as _rtgui_topwin_list. This forms the hierarchy tree structure of + * all windows. + * + * The hidden list have no specific order. + */ +static struct rtgui_dlist_node _rtgui_topwin_list; +#define get_topwin_from_list(list_entry) \ + (rtgui_dlist_entry((list_entry), struct rtgui_topwin, list)) + +#ifdef RTGUI_USING_DESKTOP_WINDOW +static struct rtgui_topwin *the_desktop_topwin; + +#define IS_ROOT_WIN(topwin) ((topwin)->parent == the_desktop_topwin) +#else +#define IS_ROOT_WIN(topwin) ((topwin)->parent == RT_NULL) +#endif -static struct rtgui_list_node _rtgui_topwin_show_list; -static struct rtgui_list_node _rtgui_topwin_hide_list; static struct rt_semaphore _rtgui_topwin_lock; static void rtgui_topwin_update_clip(void); static void rtgui_topwin_redraw(struct rtgui_rect* rect); +static void _rtgui_topwin_activate_next(void); -void rtgui_topwin_init() +void rtgui_topwin_init(void) { /* init window list */ - rtgui_list_init(&_rtgui_topwin_show_list); - rtgui_list_init(&_rtgui_topwin_hide_list); + rtgui_dlist_init(&_rtgui_topwin_list); - rt_sem_init(&_rtgui_topwin_lock, + rt_sem_init(&_rtgui_topwin_lock, "topwin", 1, RT_IPC_FLAG_FIFO); } -static struct rtgui_topwin* -rtgui_topwin_search_in_list(struct rtgui_win* wid, struct rtgui_list_node* list) +static struct rtgui_topwin* rtgui_topwin_search_in_list(struct rtgui_win* window, + struct rtgui_dlist_node* list) { - struct rtgui_list_node* node; + /* TODO: use a cache to speed up the search. */ + struct rtgui_dlist_node* node; struct rtgui_topwin* topwin; - /* search in list */ - rtgui_list_foreach(node, list) + /* the action is tend to operate on the top most window. So we search in a + * depth first order. + */ + rtgui_dlist_foreach(node, list, next) { - topwin = rtgui_list_entry(node, struct rtgui_topwin, list); + topwin = rtgui_dlist_entry(node, struct rtgui_topwin, list); /* is this node? */ - if (topwin->wid == wid) + if (topwin->wid == window) { return topwin; } + + topwin = rtgui_topwin_search_in_list(window, &topwin->child_list); + if (topwin != RT_NULL) + return topwin; } return RT_NULL; @@ -67,17 +98,42 @@ rt_err_t rtgui_topwin_add(struct rtgui_event_win_create* event) struct rtgui_topwin* topwin; topwin = rtgui_malloc(sizeof(struct rtgui_topwin)); - if (topwin == RT_NULL) return -RT_ERROR; + if (topwin == RT_NULL) + return -RT_ERROR; - topwin->wid = event->wid; + topwin->wid = event->wid; #ifdef RTGUI_USING_SMALL_SIZE - topwin->extent = RTGUI_WIDGET(event->wid)->extent; + topwin->extent = RTGUI_WIDGET(event->wid)->extent; #else - topwin->extent = event->extent; + topwin->extent = event->extent; #endif - topwin->tid = event->parent.sender; + topwin->tid = event->parent.sender; - topwin->flag = 0; + if (event->parent_window == RT_NULL) + { + topwin->parent = RT_NULL; + rtgui_dlist_insert_before(&_rtgui_topwin_list, &topwin->list); +#ifdef RTGUI_USING_DESKTOP_WINDOW + RT_ASSERT(the_desktop_topwin == RT_NULL); + RT_ASSERT(event->parent.user & RTGUI_WIN_STYLE_DESKTOP); + the_desktop_topwin = topwin; +#endif + } + else + { + topwin->parent = rtgui_topwin_search_in_list(event->parent_window, &_rtgui_topwin_list); + if (topwin->parent == RT_NULL) + { + /* parent does not exist. Orphan window? */ + rtgui_free(topwin); + return -RT_ERROR; + } + rtgui_dlist_insert_before(&topwin->parent->child_list, &topwin->list); + } + + rtgui_dlist_init(&topwin->child_list); + + topwin->flag = 0; if (event->parent.user & RTGUI_WIN_STYLE_NO_TITLE) topwin->flag |= WINTITLE_NO; if (event->parent.user & RTGUI_WIN_STYLE_CLOSEBOX) topwin->flag |= WINTITLE_CLOSEBOX; if (!(event->parent.user & RTGUI_WIN_STYLE_NO_BORDER)) topwin->flag |= WINTITLE_BORDER; @@ -105,541 +161,660 @@ rt_err_t rtgui_topwin_add(struct rtgui_event_win_create* event) rtgui_widget_set_rect(RTGUI_WIDGET(topwin->title), &rect); /* update clip info */ - rtgui_toplevel_update_clip(RTGUI_TOPLEVEL(topwin->title)); rtgui_region_subtract_rect(&(RTGUI_WIDGET(topwin->title)->clip), &(RTGUI_WIDGET(topwin->title)->clip), &(topwin->extent)); } - else topwin->title = RT_NULL; + else + topwin->title = RT_NULL; - rtgui_list_init(&topwin->list); rtgui_list_init(&topwin->monitor_list); - /* add topwin node to the hidden window list */ - rtgui_list_insert(&(_rtgui_topwin_hide_list), &(topwin->list)); - return RT_EOK; } -rt_err_t rtgui_topwin_remove(struct rtgui_win* wid) +static struct rtgui_topwin* _rtgui_topwin_get_root_win(struct rtgui_topwin *topwin) { - struct rtgui_topwin* topwin; + struct rtgui_topwin *topparent; - /* find the topwin node */ - topwin = rtgui_topwin_search_in_list(wid, &_rtgui_topwin_show_list); + RT_ASSERT(topwin != RT_NULL); + + topparent = topwin; + while (topparent && !IS_ROOT_WIN(topparent)) + topparent = topparent->parent; + return topparent; +} - if (topwin) +static struct rtgui_topwin* _rtgui_topwin_get_topmost_child_shown(struct rtgui_topwin *topwin) +{ + RT_ASSERT(topwin != RT_NULL); + + while (!(rtgui_dlist_isempty(&topwin->child_list)) && + get_topwin_from_list(topwin->child_list.next)->flag & WINTITLE_SHOWN) + topwin = get_topwin_from_list(topwin->child_list.next); + return topwin; +} + +static struct rtgui_topwin* _rtgui_topwin_get_topmost_window_shown(void) +{ + if (!(get_topwin_from_list(_rtgui_topwin_list.next)->flag & WINTITLE_SHOWN)) + return RT_NULL; + else + return _rtgui_topwin_get_topmost_child_shown(get_topwin_from_list(_rtgui_topwin_list.next)); +} + +/* a hidden parent will hide it's children. Top level window can be shown at + * any time. */ +static rt_bool_t _rtgui_topwin_could_show(struct rtgui_topwin *topwin) +{ + struct rtgui_topwin *parent; + + RT_ASSERT(topwin != RT_NULL); + + for (parent = topwin->parent; parent != RT_NULL; parent = parent->parent) { - /* remove node from list */ - rtgui_list_remove(&_rtgui_topwin_show_list, &(topwin->list)); + if (!(parent->flag & WINTITLE_SHOWN)) + return RT_FALSE; + } + return RT_TRUE; +} - rtgui_topwin_update_clip(); +static void _rtgui_topwin_union_region_tree(struct rtgui_topwin *topwin, + struct rtgui_region *region) +{ + struct rtgui_dlist_node *node; - /* redraw the old rect */ - rtgui_topwin_redraw(&(topwin->extent)); + RT_ASSERT(topwin != RT_NULL); - if (rtgui_server_focus_topwin == topwin) - { - /* activate the next window */ - if (_rtgui_topwin_show_list.next != RT_NULL) - { - struct rtgui_event_win wevent; - struct rtgui_topwin* wnd; + rtgui_dlist_foreach(node, &topwin->child_list, next) + _rtgui_topwin_union_region_tree(get_topwin_from_list(node), region); - /* get the topwin */ - wnd = rtgui_list_entry(_rtgui_topwin_show_list.next, - struct rtgui_topwin, list); + if (topwin->title != RT_NULL) + rtgui_region_union_rect(region, region, &RTGUI_WIDGET(topwin->title)->extent); + else + rtgui_region_union_rect(region, region, &topwin->extent); +} - /* activate the window */ - RTGUI_EVENT_WIN_ACTIVATE_INIT(&wevent); - wevent.wid = wnd->wid; - rtgui_thread_send(wnd->tid, &(wevent.parent), sizeof(struct rtgui_event_win)); +/* The return value of this function is the next node in tree. + * + * As we freed the node in this function, it would be a null reference error of + * the caller iterate the tree normally. + */ +static struct rtgui_dlist_node* _rtgui_topwin_free_tree(struct rtgui_topwin *topwin) +{ + struct rtgui_dlist_node *node, *next_node; - /* set new focus topwin */ - rtgui_server_focus_topwin = wnd; - } - else - { - /* there is no shown window right now */ - rtgui_server_focus_topwin = RT_NULL; - } - } + RT_ASSERT(topwin != RT_NULL); - /* free the monitor rect list, topwin node and title */ - while (topwin->monitor_list.next != RT_NULL) - { - struct rtgui_mouse_monitor* monitor = rtgui_list_entry(topwin->monitor_list.next, + node = topwin->child_list.next; + while (node != &topwin->child_list) + node = _rtgui_topwin_free_tree(get_topwin_from_list(node)); + + next_node = topwin->list.next; + rtgui_dlist_remove(&topwin->list); + + /* free the monitor rect list, topwin node and title */ + while (topwin->monitor_list.next != RT_NULL) + { + struct rtgui_mouse_monitor* monitor = rtgui_list_entry(topwin->monitor_list.next, struct rtgui_mouse_monitor, list); - topwin->monitor_list.next = topwin->monitor_list.next->next; - rtgui_free(monitor); - } + topwin->monitor_list.next = topwin->monitor_list.next->next; + rtgui_free(monitor); + } - /* destroy win title */ - rtgui_wintitle_destroy(topwin->title); - topwin->title = RT_NULL; + /* destroy win title */ + rtgui_wintitle_destroy(topwin->title); + topwin->title = RT_NULL; - rtgui_free(topwin); + rtgui_free(topwin); + return next_node; +} - return RT_EOK; - } +rt_err_t rtgui_topwin_remove(struct rtgui_win* wid) +{ + struct rtgui_topwin *topwin, *old_focus; + struct rtgui_region region; - topwin = rtgui_topwin_search_in_list(wid, &_rtgui_topwin_hide_list); - if (topwin) - { - /* remove node from list */ - rtgui_list_remove(&_rtgui_topwin_hide_list, &(topwin->list)); + /* find the topwin node */ + topwin = rtgui_topwin_search_in_list(wid, &_rtgui_topwin_list); - /* free the topwin node and title */ - rtgui_wintitle_destroy(topwin->title); - topwin->title = RT_NULL; + if (topwin == RT_NULL) + return -RT_ERROR; - rtgui_free(topwin); + rtgui_region_init(®ion); - return RT_EOK; + old_focus = rtgui_topwin_get_focus(); + + // TODO: if the window is hidden, there is no need to update the window + // region + _rtgui_topwin_union_region_tree(topwin, ®ion); + if (topwin->flag & WINTITLE_SHOWN) + rtgui_topwin_update_clip(); + + if (old_focus == topwin) + { + _rtgui_topwin_activate_next(); } - return -RT_ERROR; + /* redraw the old rect */ + rtgui_topwin_redraw(rtgui_region_extents(®ion)); + + /* remove the root from _rtgui_topwin_list will remove the whole tree from + * _rtgui_topwin_list. */ + rtgui_dlist_remove(&topwin->list); + + _rtgui_topwin_free_tree(topwin); + + return RT_EOK; } -/* activate a win - * - deactivate the old focus win - * - activate a win - * - set the focus win to activate win - * - draw win title - */ -void rtgui_topwin_activate_win(struct rtgui_topwin* win) +/* neither deactivate the old focus nor change _rtgui_topwin_list. + * Suitable to be called when the first item is the window to be activated + * already. */ +static void _rtgui_topwin_only_activate(struct rtgui_topwin *topwin) { struct rtgui_event_win event; + RT_ASSERT(topwin != RT_NULL); + + if (topwin->flag & WINTITLE_NOFOCUS) + return; + /* activate the raised window */ RTGUI_EVENT_WIN_ACTIVATE_INIT(&event); - event.wid = win->wid; - rtgui_thread_send(win->tid, &(event.parent), sizeof(struct rtgui_event_win)); + + topwin->flag |= WINTITLE_ACTIVATE; + + event.wid = topwin->wid; + rtgui_application_send(topwin->tid, &(event.parent), sizeof(struct rtgui_event_win)); /* redraw title */ - if (win->title != RT_NULL) + if (topwin->title != RT_NULL) { - win->flag |= WINTITLE_ACTIVATE; - rtgui_theme_draw_win(win); + rtgui_theme_draw_win(topwin); } +} - if ((rtgui_server_focus_topwin != RT_NULL) && (rtgui_server_focus_topwin != win)) - { - /* deactivate the old focus win */ - RTGUI_EVENT_WIN_DEACTIVATE_INIT(&event); - event.wid = rtgui_server_focus_topwin->wid; - rtgui_thread_send(rtgui_server_focus_topwin->tid, - &event.parent, sizeof(struct rtgui_event_win)); +static void _rtgui_topwin_activate_next(void) +{ + struct rtgui_topwin *topwin; - /* redraw title */ - if (rtgui_server_focus_topwin->title != RT_NULL) - { - rtgui_server_focus_topwin->flag &= ~WINTITLE_ACTIVATE; - rtgui_theme_draw_win(rtgui_server_focus_topwin); - } - } + topwin = _rtgui_topwin_get_topmost_window_shown(); + if (topwin == RT_NULL) + return; - rtgui_server_focus_topwin = win; + _rtgui_topwin_only_activate(topwin); } -/* - * deactivate a win - * - deactivate the win - * - redraw win title - * - set rtgui_server_focus_topwin - */ -void rtgui_topwin_deactivate_win(struct rtgui_topwin* win) +/* this function does not update the clip(to avoid doubel clipping). So if the + * tree has changed, make sure it has already updated outside. */ +static void _rtgui_topwin_deactivate(struct rtgui_topwin *topwin) { - /* deactivate win */ struct rtgui_event_win event; + + RT_ASSERT(topwin != RT_NULL); + RT_ASSERT(topwin->tid != RT_NULL); + RTGUI_EVENT_WIN_DEACTIVATE_INIT(&event); - event.wid = win->wid; - rtgui_thread_send(win->tid, - &event.parent, sizeof(struct rtgui_event_win)); + event.wid = topwin->wid; + rtgui_application_send(topwin->tid, + &event.parent, sizeof(struct rtgui_event_win)); - win->flag &= ~WINTITLE_ACTIVATE; - rtgui_theme_draw_win(win); + topwin->flag &= ~WINTITLE_ACTIVATE; - if (rtgui_server_focus_topwin == win) + /* redraw title */ + if (topwin->title != RT_NULL) { - rtgui_server_focus_topwin = RT_NULL; + rtgui_theme_draw_win(topwin); } } -/* raise window to front */ -void rtgui_topwin_raise(struct rtgui_win* wid, rt_thread_t sender) +static void _rtgui_topwin_move_whole_tree2top(struct rtgui_topwin *topwin) { - struct rtgui_topwin* topwin; - struct rtgui_list_node* node; - struct rtgui_event_clip_info eclip; + struct rtgui_topwin *topparent; - RTGUI_EVENT_CLIP_INFO_INIT(&eclip); - eclip.wid = RT_NULL; + RT_ASSERT(topwin != RT_NULL); - /* the window is already placed in front */ - if (&(topwin->list) == _rtgui_topwin_show_list.next) +#ifdef RTGUI_USING_DESKTOP_WINDOW + /* handle desktop window separately, avoid calling + * _rtgui_topwin_get_root_win */ + if (topwin == the_desktop_topwin) { - rtgui_server_focus_topwin = RT_NULL; - rtgui_topwin_activate_win(topwin); - return ; + rtgui_dlist_remove(&the_desktop_topwin->list); + rtgui_dlist_insert_after(&_rtgui_topwin_list, &the_desktop_topwin->list); + return; } +#endif - // rt_sem_take(&_rtgui_topwin_lock, RT_WAITING_FOREVER); - /* find the topwin node */ - for (node = _rtgui_topwin_show_list.next; node->next != RT_NULL; node = node->next) - { - topwin = rtgui_list_entry(node->next, struct rtgui_topwin, list); - if (topwin->wid == wid) - { - /* found target */ - - struct rtgui_list_node* n; - n = node->next; - /* remove node */ - node->next = node->next->next; - /* insert node to the header */ - n->next = _rtgui_topwin_show_list.next; - _rtgui_topwin_show_list.next = n; + /* move the whole tree */ + topparent = _rtgui_topwin_get_root_win(topwin); + RT_ASSERT(topparent != RT_NULL); - /* send clip update to each upper window */ - for (n = _rtgui_topwin_show_list.next; n != node->next; n = n->next) - { - struct rtgui_topwin* wnd = rtgui_list_entry(n, struct rtgui_topwin, list); - eclip.wid = wnd->wid; + /* remove node from hidden list */ + rtgui_dlist_remove(&topparent->list); + /* add node to show list */ +#ifdef RTGUI_USING_DESKTOP_WINDOW + rtgui_dlist_insert_after(&the_desktop_topwin->child_list, &(topparent->list)); +#else + rtgui_dlist_insert_after(&_rtgui_topwin_list, &(topparent->list)); +#endif +} - /* send to destination window */ - rtgui_thread_send(wnd->tid, &(eclip.parent), sizeof(struct rtgui_event_clip_info)); +static void _rtgui_topwin_raise_topwin_in_tree(struct rtgui_topwin *topwin) +{ + struct rtgui_dlist_node *win_level; - /* reset clip info in title */ - if (wnd->title != RT_NULL) - { - rtgui_toplevel_update_clip(RTGUI_TOPLEVEL(wnd->title)); - rtgui_region_subtract_rect(&(RTGUI_WIDGET(wnd->title)->clip), - &(RTGUI_WIDGET(wnd->title)->clip), - &(wnd->extent)); - } - } + RT_ASSERT(topwin != RT_NULL); - /* active window */ - rtgui_topwin_activate_win(topwin); - break; - } - } - // rt_sem_release(&_rtgui_topwin_lock); + _rtgui_topwin_move_whole_tree2top(topwin); + if (topwin->parent == RT_NULL) + win_level = &_rtgui_topwin_list; + else + win_level = &topwin->parent->child_list; + rtgui_dlist_remove(&topwin->list); + rtgui_dlist_insert_after(win_level, &topwin->list); } -/* show a window */ -void rtgui_topwin_show(struct rtgui_event_win* event) +/* activate a win means: + * - deactivate the old focus win if any + * - raise the window to the front of it's siblings + * - activate a win + */ +void rtgui_topwin_activate_win(struct rtgui_topwin* topwin) { - struct rtgui_topwin* topwin; - struct rtgui_win* wid = event->wid; - rt_thread_t sender = RTGUI_EVENT(event)->sender; + struct rtgui_topwin *old_focus_topwin; - /* find in hide list */ - topwin = rtgui_topwin_search_in_list(wid, &_rtgui_topwin_hide_list); + RT_ASSERT(topwin != RT_NULL); - /* find it */ - if (topwin != RT_NULL) + if (topwin->flag & WINTITLE_NOFOCUS) { - /* remove node from hidden list */ - rtgui_list_remove(&_rtgui_topwin_hide_list, &(topwin->list)); - - /* add node to show list */ - rtgui_list_insert(&_rtgui_topwin_show_list, &(topwin->list)); - - /* show window title */ - if (topwin->title != RT_NULL) - { - RTGUI_WIDGET_UNHIDE(RTGUI_WIDGET(topwin->title)); - } + /* just raise it, not affect others. */ + _rtgui_topwin_raise_topwin_in_tree(topwin); /* update clip info */ rtgui_topwin_update_clip(); + return; + } - rtgui_thread_ack(RTGUI_EVENT(event), RTGUI_STATUS_OK); + old_focus_topwin = rtgui_topwin_get_focus(); - /* activate this window */ - rtgui_topwin_activate_win(topwin); - } - else - { - /* the wnd is located in show list, raise wnd to front */ - topwin = rtgui_topwin_search_in_list(wid, &_rtgui_topwin_show_list); - if (topwin != RT_NULL) - { - if (_rtgui_topwin_show_list.next != &(topwin->list)) - { - rtgui_thread_ack(RTGUI_EVENT(event), RTGUI_STATUS_OK); + if (old_focus_topwin == topwin) + return; - /* not the front window, raise it */ - rtgui_topwin_raise(wid, sender); - } - else - { - /* just raise it */ - rtgui_topwin_raise(wid, sender); - } - } - else - { - /* there is no wnd in wnd list */ - rtgui_thread_ack(RTGUI_EVENT(event), RTGUI_STATUS_ERROR); - } + _rtgui_topwin_raise_topwin_in_tree(topwin); + /* update clip info */ + rtgui_topwin_update_clip(); + + if (old_focus_topwin != RT_NULL) + { + /* deactivate the old focus window firstly, otherwise it will make the new + * window invisible. */ + _rtgui_topwin_deactivate(old_focus_topwin); } + + _rtgui_topwin_only_activate(topwin); } -/* send clip info to panel */ -#ifdef RTGUI_USING_SMALL_SIZE -void rtgui_topwin_update_clip_to_panel(struct rtgui_panel* panel) +/* map func to the topwin tree in preorder. + * + * Remember that we are in a embedded system so write the @param func memory + * efficiently. + */ +rt_inline void _rtgui_topwin_preorder_map(struct rtgui_topwin *topwin, void (*func)(struct rtgui_topwin*)) { - rt_uint32_t count; - rt_thread_t tid; - struct rtgui_list_node* node; - struct rtgui_event_clip_info eclip; + struct rtgui_dlist_node *child; - /* get topwin count */ - count = 0; - node = _rtgui_topwin_show_list.next; - while (node != RT_NULL) - { - count ++; - node = node->next; - } + RT_ASSERT(topwin != RT_NULL); + RT_ASSERT(func != RT_NULL); - /* send clip info event to panel */ - RTGUI_EVENT_CLIP_INFO_INIT(&eclip); - eclip.num_rect = count; eclip.wid = RT_NULL; + func(topwin); - /* send to the activated thread of panel */ - tid = rtgui_panel_get_active_thread(panel); - rtgui_thread_send(tid, &eclip.parent, sizeof(struct rtgui_event_clip_info)); + rtgui_dlist_foreach(child, &topwin->child_list, next) + _rtgui_topwin_preorder_map(get_topwin_from_list(child), func); } -#else -void rtgui_topwin_update_clip_to_panel(struct rtgui_panel* panel) -{ - rt_uint32_t count; - rt_thread_t tid; - struct rtgui_list_node* node; - struct rtgui_event_clip_info* eclip; - /* get topwin count */ - count = 0; - node = _rtgui_topwin_show_list.next; - while (node != RT_NULL) +rt_inline void _rtgui_topwin_mark_hidden(struct rtgui_topwin *topwin) +{ + topwin->flag &= ~WINTITLE_SHOWN; + if (topwin->title != RT_NULL) { - count ++; - node = node->next; + RTGUI_WIDGET_HIDE(RTGUI_WIDGET(topwin->title)); } + RTGUI_WIDGET_HIDE(RTGUI_WIDGET(topwin->wid)); +} - eclip = (struct rtgui_event_clip_info*)rtgui_malloc(sizeof(struct rtgui_event_clip_info) - + (count + 1)* sizeof(struct rtgui_rect)); - if (eclip == RT_NULL) +rt_inline void _rtgui_topwin_mark_shown(struct rtgui_topwin *topwin) +{ + topwin->flag |= WINTITLE_SHOWN; + if (topwin->title != RT_NULL) { - /* no memory */ - return ; + RTGUI_WIDGET_UNHIDE(RTGUI_WIDGET(topwin->title)); } + RTGUI_WIDGET_UNHIDE(RTGUI_WIDGET(topwin->wid)); +} - /* reset clip info to top window */ - RTGUI_EVENT_CLIP_INFO_INIT(eclip); - eclip->num_rect = count; eclip->wid = RT_NULL; +static void _rtgui_topwin_draw_tree(struct rtgui_topwin *topwin, struct rtgui_event_paint *epaint) +{ + struct rtgui_dlist_node *node; - count = 0; - for (node = _rtgui_topwin_show_list.next; node != RT_NULL; node = node->next) + if (topwin->title != RT_NULL) { - struct rtgui_topwin* wnd; - struct rtgui_rect* rect; + rtgui_theme_draw_win(topwin); + } - wnd = rtgui_list_entry(node, struct rtgui_topwin, list); + epaint->wid = topwin->wid; + rtgui_application_send(topwin->tid, &(epaint->parent), sizeof(struct rtgui_event_paint)); - rect = RTGUI_EVENT_GET_RECT(eclip, count++); - *rect = (wnd->title != RT_NULL)? RTGUI_WIDGET(wnd->title)->extent : wnd->extent; + rtgui_dlist_foreach(node, &topwin->child_list, prev) + { + _rtgui_topwin_draw_tree(get_topwin_from_list(node), epaint); } +} + +/* show the window tree. @param epaint can be initialized outside and reduce stack + * usage. */ +static void _rtgui_topwin_show_tree(struct rtgui_topwin *topwin, struct rtgui_event_paint *epaint) +{ + RT_ASSERT(topwin != RT_NULL); + RT_ASSERT(epaint != RT_NULL); - /* send to the activated thread of panel */ - tid = rtgui_panel_get_active_thread(panel); - rtgui_thread_send(tid, (struct rtgui_event*)eclip, sizeof(struct rtgui_event_clip_info) - + count* sizeof(struct rtgui_rect)); + _rtgui_topwin_raise_topwin_in_tree(topwin); + /* we have to mark the _all_ tree before update_clip because update_clip + * will stop as hidden windows */ + _rtgui_topwin_preorder_map(topwin, _rtgui_topwin_mark_shown); - /* release clip info event */ - rtgui_free(eclip); + // TODO: if all the window is shown already, there is no need to + // update_clip. But since we use peorder_map, it seems it's a bit difficult + // to tell whether @param topwin and it's children are all shown. + rtgui_topwin_update_clip(); + + _rtgui_topwin_draw_tree(topwin, epaint); } -#endif -/* hide a window */ -void rtgui_topwin_hide(struct rtgui_event_win* event) +/** show a window + * + * If any parent window in the hierarchy tree is hidden, this window won't be + * shown. If this window could be shown, all the child windows will be shown as + * well. The topmost child will be active. + * + * Top level window(parent == RT_NULL) can always be shown. + */ +rt_err_t rtgui_topwin_show(struct rtgui_event_win* event) { - struct rtgui_topwin* topwin; + struct rtgui_topwin *topwin, *old_focus; struct rtgui_win* wid = event->wid; + struct rtgui_event_paint epaint; - /* find in show list */ - topwin = rtgui_topwin_search_in_list(wid, &_rtgui_topwin_show_list); + RTGUI_EVENT_PAINT_INIT(&epaint); + + /* find in hide list */ + topwin = rtgui_topwin_search_in_list(wid, &_rtgui_topwin_list); + if (topwin == RT_NULL || + !_rtgui_topwin_could_show(topwin)) + return -RT_ERROR; + + old_focus = rtgui_topwin_get_focus(); + + _rtgui_topwin_show_tree(topwin, &epaint); - /* found it */ - if (topwin) + /* we don't want double clipping(bare rtgui_topwin_activate_win will clip), + * so we have to do deactivate/activate manually. */ + if (old_focus == RT_NULL) + _rtgui_topwin_only_activate(topwin); + else if (old_focus != topwin) { - /* remove node from show list */ - rtgui_list_remove(&_rtgui_topwin_show_list, &(topwin->list)); + _rtgui_topwin_deactivate(old_focus); + _rtgui_topwin_only_activate(topwin); + } - /* add node to hidden list */ - rtgui_list_insert(&_rtgui_topwin_hide_list, &(topwin->list)); + return RT_EOK; +} - /* show window title */ - if (topwin->title != RT_NULL) - { - RTGUI_WIDGET_HIDE(RTGUI_WIDGET(topwin->title)); - } +static void _rtgui_topwin_clear_modal_tree(struct rtgui_topwin *topwin) +{ + struct rtgui_dlist_node *node; - /* update clip info */ - rtgui_topwin_update_clip(); + RT_ASSERT(topwin != RT_NULL); + RT_ASSERT(topwin->parent != RT_NULL); - /* redraw the old rect */ - rtgui_topwin_redraw(&(topwin->extent)); + while (!IS_ROOT_WIN(topwin)) + { + rtgui_dlist_foreach(node, &topwin->parent->child_list, next) + get_topwin_from_list(node)->flag &= ~WINTITLE_MODALED; + topwin = topwin->parent; + } + /* clear the modal flag of the root window */ + topwin->flag &= ~WINTITLE_MODALED; +} - if (rtgui_server_focus_topwin == topwin) - { - /* activate the next window */ - if (_rtgui_topwin_show_list.next != RT_NULL) - { - /* get the topwin */ - topwin = rtgui_list_entry(_rtgui_topwin_show_list.next, - struct rtgui_topwin, list); +/* hide a window */ +rt_err_t rtgui_topwin_hide(struct rtgui_event_win* event) +{ + struct rtgui_topwin *topwin; + struct rtgui_topwin *old_focus_topwin = rtgui_topwin_get_focus(); + struct rtgui_win *wid = event->wid; + struct rtgui_dlist_node *containing_list; - rtgui_server_focus_topwin = RT_NULL; - rtgui_topwin_activate_win(topwin); - } - else - { - /* there is no shown window right now */ - rtgui_server_focus_topwin = RT_NULL; - } - } + /* find in show list */ + topwin = rtgui_topwin_search_in_list(wid, &_rtgui_topwin_list); + if (topwin == RT_NULL) + { + return -RT_ERROR; + } + if (!(topwin->flag & WINTITLE_SHOWN)) + { + return RT_EOK; } + + old_focus_topwin = rtgui_topwin_get_focus(); + + _rtgui_topwin_preorder_map(topwin, _rtgui_topwin_mark_hidden); + + if (topwin->parent == RT_NULL) + containing_list = &_rtgui_topwin_list; else + containing_list = &topwin->parent->child_list; + + rtgui_dlist_remove(&topwin->list); + rtgui_dlist_insert_before(containing_list, &topwin->list); + + /* update clip info */ + rtgui_topwin_update_clip(); + + /* redraw the old rect */ + rtgui_topwin_redraw(&(topwin->extent)); + + if (topwin->flag & WINTITLE_MODALING) { - rtgui_thread_ack(RTGUI_EVENT(event), RTGUI_STATUS_ERROR); - return; + _rtgui_topwin_clear_modal_tree(topwin); + topwin->flag &= ~WINTITLE_MODALING; + } + + if (old_focus_topwin == topwin) + { + _rtgui_topwin_activate_next(); } - rtgui_thread_ack(RTGUI_EVENT(event), RTGUI_STATUS_OK); + return RT_EOK; } /* move top window */ -void rtgui_topwin_move(struct rtgui_event_win_move* event) +rt_err_t rtgui_topwin_move(struct rtgui_event_win_move* event) { struct rtgui_topwin* topwin; + int dx, dy; + rtgui_rect_t old_rect; /* the old topwin coverage area */ + struct rtgui_list_node* node; /* find in show list */ - topwin = rtgui_topwin_search_in_list(event->wid, &_rtgui_topwin_show_list); - if (topwin != RT_NULL) + topwin = rtgui_topwin_search_in_list(event->wid, &_rtgui_topwin_list); + if (topwin == RT_NULL || + !(topwin->flag & WINTITLE_SHOWN)) { - int dx, dy; - rtgui_rect_t rect; /* the old topwin coverage area */ - struct rtgui_list_node* node; - - /* send status ok */ - rtgui_thread_ack(RTGUI_EVENT(event), RTGUI_STATUS_OK); + return -RT_ERROR; + } - /* get the delta move x, y */ - dx = event->x - topwin->extent.x1; - dy = event->y - topwin->extent.y1; + /* get the delta move x, y */ + dx = event->x - topwin->extent.x1; + dy = event->y - topwin->extent.y1; - rect = topwin->extent; - /* move window rect */ - rtgui_rect_moveto(&(topwin->extent), dx, dy); + old_rect = topwin->extent; + /* move window rect */ + rtgui_rect_moveto(&(topwin->extent), dx, dy); - /* move window title */ - if (topwin->title != RT_NULL) - { - rect = RTGUI_WIDGET(topwin->title)->extent; - rtgui_widget_move_to_logic(RTGUI_WIDGET(topwin->title), dx, dy); - } + /* move window title */ + if (topwin->title != RT_NULL) + { + old_rect = RTGUI_WIDGET(topwin->title)->extent; + rtgui_widget_move_to_logic(RTGUI_WIDGET(topwin->title), dx, dy); + } - /* move the monitor rect list */ - rtgui_list_foreach(node, &(topwin->monitor_list)) - { - struct rtgui_mouse_monitor* monitor = rtgui_list_entry(node, + /* move the monitor rect list */ + rtgui_list_foreach(node, &(topwin->monitor_list)) + { + struct rtgui_mouse_monitor* monitor = rtgui_list_entry(node, struct rtgui_mouse_monitor, list); - rtgui_rect_moveto(&(monitor->rect), dx, dy); - } + rtgui_rect_moveto(&(monitor->rect), dx, dy); + } - /* update windows clip info */ - rtgui_topwin_update_clip(); + /* update windows clip info */ + rtgui_topwin_update_clip(); - /* update top window title */ - if (topwin->title != RT_NULL) rtgui_theme_draw_win(topwin); - if (rtgui_rect_is_intersect(&rect, &(topwin->extent)) != RT_EOK) - { - /* - * the old rect is not intersect with moved rect, - * re-paint window - */ - struct rtgui_event_paint epaint; - RTGUI_EVENT_PAINT_INIT(&epaint); - epaint.wid = topwin->wid; - rtgui_thread_send(topwin->tid, &(epaint.parent), sizeof(epaint)); - } + /* update old window coverage area */ + rtgui_topwin_redraw(&old_rect); - /* update old window coverage area */ - rtgui_topwin_redraw(&rect); - } - else + /* update top window title */ + if (topwin->title != RT_NULL) + rtgui_theme_draw_win(topwin); + if (rtgui_rect_is_intersect(&old_rect, &(topwin->extent)) != RT_EOK) { - rtgui_thread_ack(RTGUI_EVENT(event), RTGUI_STATUS_ERROR); + /* + * the old rect is not intersect with moved rect, + * re-paint window + */ + struct rtgui_event_paint epaint; + RTGUI_EVENT_PAINT_INIT(&epaint); + epaint.wid = topwin->wid; + rtgui_application_send(topwin->tid, &(epaint.parent), sizeof(epaint)); } + + return RT_EOK; } /* * resize a top win * Note: currently, only support resize hidden window */ -void rtgui_topwin_resize(struct rtgui_win* wid, rtgui_rect_t* r) +void rtgui_topwin_resize(struct rtgui_win* wid, rtgui_rect_t* rect) { struct rtgui_topwin* topwin; + struct rtgui_region region; /* find in show list */ - topwin = rtgui_topwin_search_in_list(wid, &_rtgui_topwin_hide_list); - if (topwin) + topwin = rtgui_topwin_search_in_list(wid, &_rtgui_topwin_list); + if (topwin == RT_NULL || + !(topwin->flag & WINTITLE_SHOWN)) + return; + + /* record the old rect */ + rtgui_region_init_with_extents(®ion, &topwin->extent); + /* union the new rect so this is the region we should redraw */ + rtgui_region_union_rect(®ion, ®ion, rect); + + topwin->extent = *rect; + + if (topwin->title != RT_NULL) { - topwin->extent = *r; + /* get win extent */ + rtgui_rect_t rect = topwin->extent; - if (topwin->title != RT_NULL) + /* add border rect */ + if (topwin->flag & WINTITLE_BORDER) { - /* get win extent */ - rtgui_rect_t rect = topwin->extent; + rtgui_rect_inflate(&rect, WINTITLE_BORDER_SIZE); + } - /* add border rect */ - if (topwin->flag & WINTITLE_BORDER) - { - rtgui_rect_inflate(&rect, WINTITLE_BORDER_SIZE); - } + /* add title rect */ + if (!(topwin->flag & WINTITLE_NO)) + rect.y1 -= WINTITLE_HEIGHT; - /* add title rect */ - if (!(topwin->flag & WINTITLE_NO)) rect.y1 -= WINTITLE_HEIGHT; + RTGUI_WIDGET(topwin->title)->extent = rect; + } - RTGUI_WIDGET(topwin->title)->extent = rect; + /* update windows clip info */ + rtgui_topwin_update_clip(); - /* update title & border clip info */ - rtgui_toplevel_update_clip(RTGUI_TOPLEVEL(topwin->title)); - rtgui_region_subtract_rect(&(RTGUI_WIDGET(topwin->title)->clip), - &(RTGUI_WIDGET(topwin->title)->clip), - &(topwin->extent)); - } + /* update old window coverage area */ + rtgui_topwin_redraw(rtgui_region_extents(®ion)); +} + +static struct rtgui_topwin* _rtgui_topwin_get_focus_from_list(struct rtgui_dlist_node *list) +{ + struct rtgui_dlist_node *node; + + RT_ASSERT(list != RT_NULL); + + rtgui_dlist_foreach(node, list, next) + { + struct rtgui_topwin *child = get_topwin_from_list(node); + if (child->flag & WINTITLE_ACTIVATE) + return child; + + child = _rtgui_topwin_get_focus_from_list(&child->child_list); + if (child != RT_NULL) + return child; } + + return RT_NULL; } -struct rtgui_topwin* rtgui_topwin_get_wnd(int x, int y) +struct rtgui_topwin* rtgui_topwin_get_focus(void) { - struct rtgui_list_node* node; - struct rtgui_topwin* topwin; +#if 1 + // debug code + struct rtgui_topwin *topwin = _rtgui_topwin_get_focus_from_list(&_rtgui_topwin_list); - /* search in list */ - rtgui_list_foreach(node, &(_rtgui_topwin_show_list)) + if (topwin != RT_NULL) +#ifdef RTGUI_USING_DESKTOP_WINDOW + RT_ASSERT(topwin == the_desktop_topwin ||\ + get_topwin_from_list(the_desktop_topwin->child_list.next) == + _rtgui_topwin_get_root_win(topwin)); +#else + RT_ASSERT(get_topwin_from_list(_rtgui_topwin_list.next) == + _rtgui_topwin_get_root_win(topwin)); +#endif + + return topwin; +#else + return _rtgui_topwin_get_focus_from_list(&_rtgui_topwin_list); +#endif +} + +static struct rtgui_topwin* _rtgui_topwin_get_wnd_from_tree(struct rtgui_dlist_node *list, + int x, int y, + rt_bool_t exclude_modaled) +{ + struct rtgui_dlist_node *node; + struct rtgui_topwin *topwin, *target; + + RT_ASSERT(list != RT_NULL); + + rtgui_dlist_foreach(node, list, next) { - topwin = rtgui_list_entry(node, struct rtgui_topwin, list); + topwin = get_topwin_from_list(node); + if (!(topwin->flag & WINTITLE_SHOWN)) + break; + + /* if higher window have this point, return it */ + target = _rtgui_topwin_get_wnd_from_tree(&topwin->child_list, x, y, exclude_modaled); + if (target != RT_NULL) + return target; + + if (exclude_modaled && (topwin->flag & WINTITLE_MODALED)) + break; - /* is this window? */ if ((topwin->title != RT_NULL) && rtgui_rect_contains_point(&(RTGUI_WIDGET(topwin->title)->extent), x, y) == RT_EOK) { @@ -654,105 +829,186 @@ struct rtgui_topwin* rtgui_topwin_get_wnd(int x, int y) return RT_NULL; } -extern struct rtgui_list_node _rtgui_panel_list; -static void rtgui_topwin_update_clip() +struct rtgui_topwin* rtgui_topwin_get_wnd(int x, int y) +{ + return _rtgui_topwin_get_wnd_from_tree(&_rtgui_topwin_list, x, y, RT_FALSE); +} + +struct rtgui_topwin* rtgui_topwin_get_wnd_no_modaled(int x, int y) +{ + return _rtgui_topwin_get_wnd_from_tree(&_rtgui_topwin_list, x, y, RT_TRUE); +} + +/* clip region from topwin, and the windows beneath it. */ +rt_inline void _rtgui_topwin_clip_to_region(struct rtgui_region *region, + struct rtgui_topwin *topwin) +{ + RT_ASSERT(region != RT_NULL); + RT_ASSERT(topwin != RT_NULL); + + if (topwin->title != RT_NULL) + { + rtgui_region_reset(&(RTGUI_WIDGET(topwin->title)->clip), + &(RTGUI_WIDGET(topwin->title)->extent)); + rtgui_region_intersect(&(RTGUI_WIDGET(topwin->title)->clip), + &(RTGUI_WIDGET(topwin->title)->clip), + region); + rtgui_region_subtract_rect(&(RTGUI_WIDGET(topwin->title)->clip), + &(RTGUI_WIDGET(topwin->title)->clip), + &topwin->extent); + } + + rtgui_region_reset(&RTGUI_WIDGET(topwin->wid)->clip, + &RTGUI_WIDGET(topwin->wid)->extent); + rtgui_region_intersect(&RTGUI_WIDGET(topwin->wid)->clip, + &RTGUI_WIDGET(topwin->wid)->clip, + region); +} + +static void rtgui_topwin_update_clip(void) { - rt_int32_t count = 0; + struct rtgui_topwin *top; struct rtgui_event_clip_info eclip; - struct rtgui_list_node* node = _rtgui_topwin_show_list.next; + /* Note that the region is a "female die", that means it's the region you + * can paint to, not the region covered by others. + */ + struct rtgui_region region_available; + + if (rtgui_dlist_isempty(&_rtgui_topwin_list) || + !(get_topwin_from_list(_rtgui_topwin_list.next)->flag & WINTITLE_SHOWN)) + return; RTGUI_EVENT_CLIP_INFO_INIT(&eclip); - rtgui_list_foreach(node, &_rtgui_topwin_show_list) - { - struct rtgui_topwin* wnd; - wnd = rtgui_list_entry(node, struct rtgui_topwin, list); + rtgui_region_init_rect(®ion_available, 0, 0, + rtgui_graphic_driver_get_default()->width, + rtgui_graphic_driver_get_default()->height); + + /* from top to bottom. */ + top = _rtgui_topwin_get_topmost_window_shown(); - eclip.num_rect = count; - eclip.wid = wnd->wid; + while (top != RT_NULL) + { + /* clip the topwin */ + _rtgui_topwin_clip_to_region(®ion_available, top); +#if 0 + /* debug window clipping */ + rt_kprintf("clip %s ", top->wid->title); + rtgui_region_dump(®ion_available); + rt_kprintf("\n"); +#endif - count ++; + /* update available region */ + if (top->title != RT_NULL) + rtgui_region_subtract_rect(®ion_available, ®ion_available, &RTGUI_WIDGET(top->title)->extent); + else + rtgui_region_subtract_rect(®ion_available, ®ion_available, &top->extent); - /* send to destination window */ - rtgui_thread_send(wnd->tid, &(eclip.parent), sizeof(struct rtgui_event_clip_info)); + /* send clip event to destination window */ + eclip.wid = top->wid; + rtgui_application_send(top->tid, &(eclip.parent), sizeof(struct rtgui_event_clip_info)); - /* update clip in win title */ - if (wnd->title != RT_NULL) - { - /* reset clip info */ - rtgui_toplevel_update_clip(RTGUI_TOPLEVEL(wnd->title)); - rtgui_region_subtract_rect(&(RTGUI_WIDGET(wnd->title)->clip), - &(RTGUI_WIDGET(wnd->title)->clip), - &(wnd->extent)); - } + /* move to next sibling tree */ + if (top->parent == RT_NULL) + if (top->list.next != &_rtgui_topwin_list && + get_topwin_from_list(top->list.next)->flag & WINTITLE_SHOWN) + top = _rtgui_topwin_get_topmost_child_shown(get_topwin_from_list(top->list.next)); + else + break; + else if (top->list.next != &top->parent->child_list && + get_topwin_from_list(top->list.next)->flag & WINTITLE_SHOWN) + top = _rtgui_topwin_get_topmost_child_shown(get_topwin_from_list(top->list.next)); + /* level up */ + else + top = top->parent; } +} + +static void _rtgui_topwin_redraw_tree(struct rtgui_dlist_node *list, + struct rtgui_rect* rect, + struct rtgui_event_paint *epaint) +{ + struct rtgui_dlist_node *node; - /* send clip info to each panel */ - eclip.wid = RT_NULL; - eclip.num_rect = count; + RT_ASSERT(list != RT_NULL); + RT_ASSERT(rect != RT_NULL); + RT_ASSERT(epaint != RT_NULL); - rtgui_list_foreach(node, &(_rtgui_panel_list)) + /* skip the hidden windows */ + rtgui_dlist_foreach(node, list, prev) { - struct rtgui_panel* panel; - struct rtgui_list_node* panel_node; + if (get_topwin_from_list(node)->flag & WINTITLE_SHOWN) + break; + } - panel = rtgui_list_entry(node, struct rtgui_panel, sibling); + for (; node != list; node = node->prev) + { + struct rtgui_topwin *topwin; - rtgui_list_foreach(panel_node, &(panel->thread_list)) + topwin = get_topwin_from_list(node); + + //FIXME: intersect with clip? + if (rtgui_rect_is_intersect(rect, &(topwin->extent)) == RT_EOK) { - struct rtgui_panel_thread* thread; - thread = rtgui_list_entry(panel_node, struct rtgui_panel_thread, list); + epaint->wid = topwin->wid; + rtgui_application_send(topwin->tid, &(epaint->parent), sizeof(*epaint)); - /* send clip info to panel */ - rtgui_thread_send(thread->tid, &(eclip.parent), sizeof(struct rtgui_event_clip_info)); + /* draw title */ + if (topwin->title != RT_NULL) + { + rtgui_theme_draw_win(topwin); + } } + + _rtgui_topwin_redraw_tree(&topwin->child_list, rect, epaint); } } static void rtgui_topwin_redraw(struct rtgui_rect* rect) { - struct rtgui_list_node* node; struct rtgui_event_paint epaint; RTGUI_EVENT_PAINT_INIT(&epaint); epaint.wid = RT_NULL; - rtgui_list_foreach(node, &_rtgui_topwin_show_list) - { - struct rtgui_topwin* wnd = rtgui_list_entry(node, struct rtgui_topwin, list); + _rtgui_topwin_redraw_tree(&_rtgui_topwin_list, rect, &epaint); +} - if (rtgui_rect_is_intersect(rect, &(wnd->extent)) == RT_EOK) - { - /* draw window */ - epaint.wid = wnd->wid; - rtgui_thread_send(wnd->tid, &(epaint.parent), sizeof(epaint)); +/* a window enter modal mode will modal all the sibling window and parent + * window all along to the root window(which parent is RT_NULL or the desktop + * window if there is). If a root window modals, there is nothing to do here.*/ +rt_err_t rtgui_topwin_modal_enter(struct rtgui_event_win_modal_enter* event) +{ + struct rtgui_topwin *topwin, *parent_top; + struct rtgui_dlist_node *node; - /* draw title */ - if (wnd->title != RT_NULL) - { - rtgui_theme_draw_win(wnd); - } - } - } + topwin = rtgui_topwin_search_in_list(event->wid, &_rtgui_topwin_list); - /* redraw the panel */ - rtgui_list_foreach(node, &(_rtgui_panel_list)) - { - struct rtgui_panel* panel; - panel = rtgui_list_entry(node, struct rtgui_panel, sibling); + if (topwin == RT_NULL) + return -RT_ERROR; - if (rtgui_rect_is_intersect(rect, &(panel->extent)) == RT_EOK) - { - rt_thread_t tid; + if (IS_ROOT_WIN(topwin)) + return RT_EOK; - tid = rtgui_panel_get_active_thread(panel); - if (tid != RT_NULL) - { - /* draw panel */ - epaint.wid = RT_NULL; - rtgui_thread_send(tid, &(epaint.parent), sizeof(epaint)); - } - } + parent_top = topwin->parent; + + /* modal window should be on top already */ + RT_ASSERT(get_topwin_from_list(parent_top->child_list.next) == topwin); + + while (!IS_ROOT_WIN(parent_top)) + { + rtgui_dlist_foreach(node, &parent_top->child_list, next) + get_topwin_from_list(node)->flag |= WINTITLE_MODALED; + parent_top->flag |= WINTITLE_MODALED; + + parent_top = parent_top->parent; } + /* mark root window as modaled */ + parent_top->flag |= WINTITLE_MODALED; + + topwin->flag &= ~WINTITLE_MODALED; + topwin->flag |= WINTITLE_MODALING; + + return RT_EOK; } void rtgui_topwin_title_onmouse(struct rtgui_topwin* win, struct rtgui_event_mouse* event) @@ -763,7 +1019,7 @@ void rtgui_topwin_title_onmouse(struct rtgui_topwin* win, struct rtgui_event_mou if (rtgui_rect_contains_point(&win->extent, event->x, event->y) == RT_EOK) { /* send mouse event to thread */ - rtgui_thread_send(win->tid, &(event->parent), sizeof(struct rtgui_event_mouse)); + rtgui_application_send(win->tid, &(event->parent), sizeof(struct rtgui_event_mouse)); return; } @@ -790,7 +1046,7 @@ void rtgui_topwin_title_onmouse(struct rtgui_topwin* win, struct rtgui_event_mou } #endif } - else if (event->button & RTGUI_MOUSE_BUTTON_UP) + else if (win->flag & WINTITLE_CB_PRESSED && event->button & RTGUI_MOUSE_BUTTON_UP) { if (rtgui_rect_contains_point(&rect, event->x, event->y) == RT_EOK) { @@ -802,7 +1058,7 @@ void rtgui_topwin_title_onmouse(struct rtgui_topwin* win, struct rtgui_event_mou /* send close event to window */ RTGUI_EVENT_WIN_CLOSE_INIT(&event); event.wid = win->wid; - rtgui_thread_send(win->tid, &(event.parent), sizeof(struct rtgui_event_win)); + rtgui_application_send(win->tid, &(event.parent), sizeof(struct rtgui_event_win)); } } } @@ -816,11 +1072,9 @@ void rtgui_topwin_append_monitor_rect(struct rtgui_win* wid, rtgui_rect_t* rect) if (wid == RT_NULL || rect == RT_NULL) return; /* find topwin */ - win = rtgui_topwin_search_in_list(wid, &_rtgui_topwin_show_list); + win = rtgui_topwin_search_in_list(wid, &_rtgui_topwin_list); if (win == RT_NULL) - win = rtgui_topwin_search_in_list(wid, &_rtgui_topwin_hide_list); - - if (win == RT_NULL) return; + return; /* append rect to top window monitor rect list */ rtgui_mouse_monitor_append(&(win->monitor_list), rect); @@ -831,51 +1085,54 @@ void rtgui_topwin_remove_monitor_rect(struct rtgui_win* wid, rtgui_rect_t* rect) struct rtgui_topwin* win; /* parameters check */ - if (wid == RT_NULL || rect == RT_NULL) return; + if (wid == RT_NULL || rect == RT_NULL) + return; /* find topwin */ - win = rtgui_topwin_search_in_list(wid, &_rtgui_topwin_show_list); + win = rtgui_topwin_search_in_list(wid, &_rtgui_topwin_list); if (win == RT_NULL) - win = rtgui_topwin_search_in_list(wid, &_rtgui_topwin_hide_list); - - if (win == RT_NULL) return; + return; /* remove rect from top window monitor rect list */ rtgui_mouse_monitor_remove(&(win->monitor_list), rect); } -/** - * do clip for topwin list - * widget, the clip widget to be done clip - */ -void rtgui_topwin_do_clip(rtgui_widget_t* widget) +static void _rtgui_topwin_dump(struct rtgui_topwin *topwin) { - rtgui_widget_t* wid; - struct rtgui_rect* rect; - struct rtgui_topwin* topwin; - struct rtgui_list_node* node; + rt_kprintf("0x%p:%s,0x%x", topwin, topwin->wid->title, topwin->flag); +} + +static void _rtgui_topwin_dump_tree(struct rtgui_topwin *topwin) +{ + struct rtgui_dlist_node *node; - /* get toplevel wid */ - wid = widget->toplevel; + _rtgui_topwin_dump(topwin); - rt_sem_take(&_rtgui_topwin_lock, RT_WAITING_FOREVER); - /* get all of topwin rect list */ - rtgui_list_foreach(node, &_rtgui_topwin_show_list) + rt_kprintf("("); + rtgui_dlist_foreach(node, &topwin->child_list, next) { - topwin = rtgui_list_entry(node, struct rtgui_topwin, list); - - if (topwin->wid == (rtgui_win_t*)(wid) || - RTGUI_WIDGET(topwin->title) == widget) break; /* it's self window, break */ + _rtgui_topwin_dump_tree(get_topwin_from_list(node)); + } + rt_kprintf(")"); +} - /* get extent */ - if (topwin->title != RT_NULL) - rect = &(RTGUI_WIDGET(topwin->title)->extent); - else - rect = &(topwin->extent); +void rtgui_topwin_dump_tree(void) +{ + struct rtgui_dlist_node *node; - /* subtract the topwin rect */ - rtgui_region_subtract_rect(&(widget->clip), &(widget->clip), rect); +#ifdef RTGUI_USING_DESKTOP_WINDOW + _rtgui_topwin_dump(the_desktop_topwin); + rt_kprintf("\n"); + rtgui_dlist_foreach(node, &the_desktop_topwin->child_list, next) + { + _rtgui_topwin_dump_tree(get_topwin_from_list(node)); + rt_kprintf("\n"); } - rt_sem_release(&_rtgui_topwin_lock); +#else + rtgui_dlist_foreach(node, &_rtgui_topwin_list, next) + { + _rtgui_topwin_dump_tree(get_topwin_from_list(node)); + rt_kprintf("\n"); + } +#endif } - diff --git a/components/rtgui/server/topwin.h b/components/rtgui/server/topwin.h index 8ec5a5c6cc..bc9db9d284 100644 --- a/components/rtgui/server/topwin.h +++ b/components/rtgui/server/topwin.h @@ -15,7 +15,6 @@ #define __RTGUI_TOPWIN_H__ #include <rtgui/rtgui.h> -#include <rtgui/list.h> #include <rtgui/region.h> #include <rtgui/event.h> #include <rtgui/widgets/title.h> @@ -25,25 +24,24 @@ rt_err_t rtgui_topwin_add(struct rtgui_event_win_create* event); rt_err_t rtgui_topwin_remove(struct rtgui_win* wid); -/* raise window to front */ -void rtgui_topwin_raise(struct rtgui_win* wid, rt_thread_t sender); -/* update clip info to a panel */ -void rtgui_topwin_update_clip_to_panel(struct rtgui_panel* panel); +void rtgui_topwin_activate_win(struct rtgui_topwin* win); /* show a window */ -void rtgui_topwin_show(struct rtgui_event_win* event); +rt_err_t rtgui_topwin_show(struct rtgui_event_win* event); /* hide a window */ -void rtgui_topwin_hide(struct rtgui_event_win* event); +rt_err_t rtgui_topwin_hide(struct rtgui_event_win* event); /* move a window */ -void rtgui_topwin_move(struct rtgui_event_win_move* event); +rt_err_t rtgui_topwin_move(struct rtgui_event_win_move* event); /* resize a window */ void rtgui_topwin_resize(struct rtgui_win* wid, rtgui_rect_t* r); +/* a window is entering modal mode */ +rt_err_t rtgui_topwin_modal_enter(struct rtgui_event_win_modal_enter* event); /* get window at (x, y) */ struct rtgui_topwin* rtgui_topwin_get_wnd(int x, int y); +struct rtgui_topwin* rtgui_topwin_get_wnd_no_modaled(int x, int y); -void rtgui_topwin_activate_win(struct rtgui_topwin* win); -void rtgui_topwin_deactivate_win(struct rtgui_topwin* win); +//void rtgui_topwin_deactivate_win(struct rtgui_topwin* win); /* window title */ void rtgui_topwin_title_ondraw(struct rtgui_topwin* win); @@ -53,7 +51,7 @@ void rtgui_topwin_title_onmouse(struct rtgui_topwin* win, struct rtgui_event_mou void rtgui_topwin_append_monitor_rect(struct rtgui_win* wid, rtgui_rect_t* rect); void rtgui_topwin_remove_monitor_rect(struct rtgui_win* wid, rtgui_rect_t* rect); -void rtgui_topwin_do_clip(rtgui_widget_t* widget); - +/* get the topwin that is currently focused */ +struct rtgui_topwin* rtgui_topwin_get_focus(void); #endif |
