一、简介
RT-Thread/GUI是一个图形用户界面(Graphic User Interface),它专为RT-Thread操作系统而开发,并在一些地方采用了RT-Thread特有功能以和RT-Thread无缝的整合起来的。这个图形用户界面组件能够为Rt-Thread上的应用程序提供人机界面交互的功能,例如人机界面设备,设备信息显示,播放器界面等。
二、架构
RT-Thread/GUI采用传统的客户端/服务端(C/S)的结构,但和传统的客户端/服务端构架,把绘画操作放在服务端不同的是,绘画操作完全有客户端自行完成。服务端仅维护着客户端的位置信息。
服务器
在初始化线程中调用rtgui_system_server_init()进行rtgui服务器端的初始化
void rtgui_system_server_init()
{
rt_mutex_init(&_screen_lock, "screen", RT_IPC_FLAG_FIFO);
rtgui_system_image_init(); //初始化图像系统, 其中至少包含硬件DC的注册
rtgui_font_system_init(); //初始化字体系统
/* 从前面液晶的驱动程序得到整个屏幕的大小参数 存在全局变量_mainwin_rect */
rtgui_graphic_driver_get_rect(rtgui_graphic_driver_get_default(),&_mainwin_rect);
rtgui_topwin_init(); //主要是初始化一个双向链表_rtgui_topwin_list
rtgui_server_init();
rtgui_system_theme_init(); /* init theme */
}
rtgui_server_init()是整个函数最重要的部分,它创建并启动了rtgui服务器线程,下面是服务器线程入口:
static void rtgui_server_entry(void *parameter)
{
1 rtgui_server_application = rtgui_app_create(rtgui_server_tid,"rtgui");
2 rtgui_object_set_event_handler(RTGUI_OBJECT(rtgui_server_application),rtgui_server_event_handler);
3 rtgui_app_run(rtgui_server_application);
4 rtgui_app_destroy(rtgui_server_application);
5 rtgui_server_application = RT_NULL;
}
第1行首先创建一个app应用,rtgui_server_application指向的数据结构struct rtgui_app
struct rtgui_app
{
struct rtgui_object parent; //表示rtgui_app继承于rtgui_object
unsigned char *name; //app的名字
rt_thread_t tid; //需要绑定的线程,也即创建此app的线程
rt_thread_t server; //rtgui服务器端的线程
rt_mq_t mq; //此线程的消息队列指针
rt_uint8_t event_buffer[sizeof(union rtgui_event_generic)]; //事件缓冲区
};
第2行的作用是设置这个app的OBJECT级别的事件处理函数为rtgui_server_event_handler,在那里面,根据接收到的事件event类型和参数调用不同的函数进行处理。
第3行启动这个app,跟踪进去会发现该函数调用_rtgui_application_event_loop(app)启动这个app的事件循环,再跟踪进去会发现次函数在循环调用事件接收函数
{
result = rtgui_recv(event, sizeof(union rtgui_event_generic));
if(result == RT_EOK)
RTGUI_OBJECT(app)->handler(RTGUI_OBJECT(app), event);
}
跟踪进rtgui_recv会看到 r = rt_mq_recv(app->mq, event, event_size, RT_WAITING_FOREVER);
可见,线程会阻塞在这里,从消息队列中接收事件。
在接收到事件以后,调用rtgui_server_event_handler。
在app结束时,会执行第4-5行,销毁app所占用的内存资源。
RT-Thread/GUI服务端处理事件线程rtgui,主要分成几个模块:
1-GUI Server,服务端事件处理主线程。(上面已经说明了)
2-Panel,画板及画板之上的线程维护。
3-TopWin,顶层窗口信息维护。
4-Mouse,鼠标相关信息处理。
画板
注册画板可以通过如下函数接口:
void rtgui_panel_register(char* name, rtgui_rect_t* extent);
参数name,指示出要创建的画板名称。参数extent,指示出要创建画板的位置信息。
跟画板相关的事件包括:
RTGUI_EVENT_PANEL_ATTACH,这个事件由应用发送给服务端线程,以附着到画板上。
RTGUI_EVENT_PANEL_DETACH,应用线程从画板上脱离。
RTGUI_EVENT_PANEL_SHOW,应用线程请求显示于附着的画板上。
RTGUI_EVENT_PANEL_HIDE,隐藏当前画板上的线程。
RTGUI_EVENT_PANEL_INFO,当应用线程请求附着画板时,服务端返回相应的画板信息。
RTGUI_EVENT_PANEL_FULLSCREEN,应用线程请求画板进行全屏显示。
RTGUI_EVENT_PANEL_NORMAL,应用线程请求画板恢复到原始状态。
窗口
当应用线程需要创建窗口时,亦需要向GUI服务端请求创建,并把它的位置信息报给服务端。服务端在收到窗口创建请求后,需要把它的位置信息加入到topwin列表中,并根据它的情况决定是否添加表框、标题信息。
跟窗口相关的事件包括:
RTGUI_EVENT_WIN_CREATE,创建窗口事件。
RTGUI_EVENT_WIN_DESTROY,删除窗口事件。
RTGUI_EVENT_WIN_SHOW,显示窗口事件。
RTGUI_EVENT_WIN_HIDE,隐藏窗口事件。
RTGUI_EVENT_WIN_ACTIVATE,激活窗口事件。
RTGUI_EVENT_WIN_DEACTIVATE,去激活窗口事件。
RTGUI_EVENT_WIN_CLOSE,关闭窗口事件。
RTGUI_EVENT_WIN_MOVE,移动窗口事件。
RTGUI_EVENT_WIN_RESIZE,更改窗口的大小信息。
鼠标与键盘
鼠标与键盘的处理亦由GUI服务端处理,它们都转换成消息事件的方式进行处理。所以鼠标、键盘驱动最主要的方法就是:把相应的鼠标状态和键值转换成事件的形式发送给GUI服务端。发送给服务端的函数是:
void rtgui_server_post_event(struct rtgui_event* event, rt_size_t size);
相应的事件类型如下:
RTGUI_EVENT_MOUSE_MOTION,鼠标移到事件。
RTGUI_EVENT_MOUSE_BUTTON,鼠标按键事件。
RTGUI_EVENT_KBD,键盘事件
服务端的主要内容就是这些了,剩下的就该是客户端了。服务端主要是为客户端服务的,记录客户端的一些主要的信息。