文档中心

8.窗口系统

01.窗口系统架构

窗口系统的整体结构图:

上图中只有屏幕(framebuffer)是真正占用内存空间的,如屏幕分辨率为 1280*720,32bit颜色,那么这个屏幕对应的 framebuffer所占用的内存大小为 1280*720*4=3.6MB。window(包括 root window,top window) 都只是表示屏幕上的一个矩形区域,没有分配颜色空间内存。

window是有层次关系的,这种层次结构可以以树状图表示。在树状图的最上层是根窗口(root window),这个根窗口由系统自动创建,大小和对应的framebuffer一样。其他窗口则由开发人员创建,相同父控件的窗口称为兄弟窗口。 窗口树的深度、兄弟窗口的个数没有任何限制。

每个窗口都有一个位置(x,y)和大小(w,h),位置是相对于父窗口左上角的坐标(y轴向下为正),当一个窗口移动时,那么它所有的子孙窗口在屏幕上也都会移动。除了根窗口,其他窗口的位置没有限制,可以为负数。窗口的大小只要大于 0,没有其他限制。

顶层窗口(top window)特指父窗口是根窗口的窗口。

02.窗口剪裁

一个窗口的显示区域由窗口剪裁来确定,窗口剪裁的原则如下

A、父子窗口剪裁:子窗口的显示区域不能超出父窗口;

B、兄弟窗口剪裁:兄弟窗口的显示区域有重叠时,上层窗口遮住下层窗口;

03.窗口的层次

一般情况下,一个 top窗口及其子孙窗口都是由一个客户进程创建的,一个进程也可以创建多个 top window。

不同的 top window可能属于不同的进程,并且进程看不到其他进程的窗口,所以由系统来统一管理 top window的层次。为了方便管理,系统设计了 top window的几种类型:

层次

类型

属性

说明

1

TW_WINDOW_DOCK

ABOVE

Dock类型,用于 top栏,系统提示框等

2

NORMAL

3

TW_WINDOW_NORMAL

TW_WINDOW_SPLASH

ABOVE

普通窗口

4

NORMAL

5

BELOW

6

TW_WINDOW_DESKTOP

 

桌面窗口,专用于桌面

窗口的类型是创建时确定的,不能修改。窗口的属性 above、normal和below是可以运行时动态调整的。由窗口的类型和属性决定了窗口的层次。上 层的窗口总是在下层窗口上面,无论谁先创建或先显示出来。即 DOCK类型的top window总是在 NORMAL类型的上面,NORMAL类型的总是在 DESKTOP 类型的上面。

属于相同层次的多个窗口之间,后创建的窗口在上面,也可以之后通过 API 来调整在同层次窗口的上下关系。

04.窗口的互斥
只针对 NORMAL类型(包括 SPLASH类型)的 top window,当一个 app显示它的第一个 NORMAL类型窗口时,会自动隐藏其他 app的 NORMAL类型窗口。即系统当前总是只能显示一个 app的 NORMAL类型窗口。 其他类型的窗口不受互斥规则影响。
05.弹出框管理规范

弹出框是指在任意 app的 NORMAL类型窗口界面或桌面上,可以随时出现的一种由后台服务程序弹出的界面窗口。弹出框不受普通窗口的互斥限制,也不 会互斥普通窗口。弹出框应该显示一段时间之后自动消失。
弹出框对应的窗口类型为 DOCK类型。根据系统的 UI设计需求,
弹出框规范如下:

弹出框分类

top窗口类型/属性

 

1 警示信息

TW_WINDOW_DOCK

ABOVE

警示信息和语音识别信

息在屏幕上弹窗的位置不重叠

2 语音识别信息

3 导航

TW_WINDOW_DOCK

NORMAL

 

4 电话

5 其他弹出信息

注:因为 1,2,3,4等弹出框内部显示的复杂性,所以有各自的后台服务程序自己负责弹出。其他弹出信息中,如果弹出内容比较简单(只有一个文本串),可以交给桌面代为弹出(通过远程方法把文本串发给桌面)。

06.前台进程和后台进程

前台显示 NORMAL(包括 SPLASH)类型的顶层窗口的 app是前台进程,因为普通窗口的互斥关系,所以前台进程只有一个,后台进程可以有多个。

当一个进程被创建时,它的第一个普通窗口显示出来时,该进程变为前台进 程,并且挤掉前一个前台进程,前台进程可以调用 TwShow()或 TwHide()来显 示或隐藏它的普通窗口。

后台进程调用 TwShow()显示普通窗口是无效的,不能显示出来。因为后台进程不能干扰前台进程的显示,只有通过下面的消息把自己变为前台进程才行。

(系统会记录后台进程的 TwShow()和 TwHide()操作,当它变成前台进程时才生效)

前台进程退出或它的所有普通窗口都隐藏时,自动把上一个前台进程变为当前的前台进程。

void msg_show_hide_client(void *msg, Tint pid, Tbool show)
{
    TTable temp=TTableCreate();
    TTableAddInt(temp, TStringID("process"), pid);
    TTableAddInt(temp, TStringID("show"), show); TMessageRemoteMethod(msg,"tdWM",
    TStringID("SHOW_HIDE_CLIENT"), temp, NULL, NULL);
    TTableDestroy(temp);
    return;
}

例如一个后台的进程,想把自己提到前台来,调用:

msg_show_hide_client(msg, getpid(), TRUE); //msg是自己的消息对象
07.回到桌面

回到桌面的操作导致当前的前台进程也到后台,即所有的进程都是后台进程,这样才露出桌面。

/*参数 msg是自己的消息对象*/
void msg_return_desktop(void *msg, Tint pid, Tbool show)
{
    TMessageRemoteMethod(msg,"PmServer",
    TStringID("PM_RET_HOME"), NULL, NULL, NULL);
    return;
}