适用于机顶盒的嵌入式窗口系统开发
2010-04-17刘畅
刘 畅
(中国电子科技集团公司第三研究所,北京 100015)
1 引言
作为一种面向最终用户的消费电子产品,用户界面的设计在机顶盒软件的开发中占有越来越重要的地位。界面软件的设计以用户为中心,其目的是让用户能够用最简单有效的方式完成交互操作,图形界面作为有效提高用户易用性的手段被广泛使用。图形用户界面的设计具有复杂度高、需求多变、可重用性差的特点,而在实际工程中具有开发周期长、稳定性低、模块化程度低等问题[1-3]。
导致产生上述问题的一个重要因素是:机顶盒软件基于嵌入式实时操作系统开发,而此类操作系统一般没有对图形用户界面的特殊支持,用户界面往往被简单划分为用户层软件的一部分,其实现与具体的界面设计方案耦合过强。解决此问题的有效方法是:定义一个适用于界面开发的中间层模块,为图形界面的开发提供必要支持[4]。图1为一个典型的采用此种设计模式的机顶盒系统结构。
与传统的机顶盒软件相比,其最显著的区别是新增了一个位于中间层的软件模块,为图形界面的开发提供必要的支持。而基于窗口系统的图形界面系统是目前应用最为广泛的技术。由于硬件机能的限制,机顶盒通常不能支持PC上常见的复杂图形系统。笔者介绍了一种适用于机顶盒的轻量级图形系统,该系统能够有效完成大多数界面设计的需求,同时保持很高的性能和灵活性。
图1 基于图形系统的机顶盒软件结构
2 窗口系统的整体结构
本设计中的窗口系统的基本功能包括标量及矢量图形绘制、屏幕区域管理、窗口管理和分发输入事件,提供常用界面控件以及应用编程接口。该系统采用层次化设计思想,每一层均可根据工程中的实际需要进行修改,而不会对系统的整体结构造成影响。该系统的结构模型如图 2所示[5]。
图2 窗口系统结构模型
在底层,驱动程序为访问图形设备和输入设备提供最基本的支持。在目前常见的机顶盒系统中,图形硬件通常包括二维图形加速器,而输入设备在多数情况下为遥控器和机顶盒控制面板。
在中间层,该系统实现了一个与硬件无关的绘图引擎,提供了常用的标量图绘制和少量的矢量图绘制功能,同时提供对屏幕缓冲区的管理和裁剪区域的支持。
在上层,窗口管理器提供了窗口系统的大部分核心功能,如窗口的创建和管理、窗口的重绘,以及对输入事件的分发等功能。
应用程序通过窗口管理器提供了编程接口与图形系统交互,为保证用户界面的一致性并提高开发效率,该系统同时包含常用的界面控件库,提供诸如按钮、列表等常用图形控件。基于该系统开发的应用完全与具体的硬件和操作系统隔离,可以很方便地移植到不同的机顶盒平台上。
3 绘图引擎
绘图引擎是整个图形系统的重要组成部分,主要功能包括[6]:1)管理屏幕缓冲区和显示内存。2)提供对窗口区域的管理和屏幕裁剪的支持。3)提供对矢量图、标量图以及矢量字库的支持。4)为上层模块提供与设备无关的编程接口。绘图引擎的结构如图3所示。
图3 与硬件无关的绘图引擎结构图
绘图引擎直接操纵下层硬件设备,并为上层模块提供与设备无关的编程接口,是整个图形系统跨平台性的保证。绘图引擎所提供的各项功能对窗口系统也是非常关键的。
3.1 屏幕缓冲区管理
当前主流机顶盒系统的显示设备无一例外地采用帧缓存设计,屏幕上显示的内容对应于显示内存中的一帧图像数据。机顶盒软件向帧缓存中写入数据,显示设备从同一个缓存中读取数据,进而更新屏幕上显示的图像内容。
管理屏幕缓冲区需要解决2个基本问题:确保写入缓存的数据符合当前显示设备的显示模式,以及保证帧缓存中数据的完整性,避免在机顶盒软件更新帧缓存时,屏幕图像产生抖动。
图形显示模式决定了帧缓存中的数据格式,即色深和内存排布方式。机顶盒软件必须采用设备要求的显示模式向缓存中写入图像数据,否则显示设备无法显示正确的图像信息。不同的硬件设备和图形模式下,写入帧缓存中的数据格式差异很大。为了避免这些差异对上层软件的影响,图形引擎通过一系列宏定义,为不同的显示模式生成正确的颜色数据,例如定义如下的宏来写入32位的像素数据:#define ARGB_8888(a,r,g,b),(a)<<24|(r)|(g)<<8|(b)<<16。
不同于桌面计算机系统,机顶盒系统的显示模式在出厂后是不可改变的,因此图形引擎通过条件编译,选择一种匹配当前系统颜色模式的数据格式作为通用的像素表示:#define ARGB ARGB_8888。上层模块只需统一使用ARGB宏定义颜色即可,无须考虑具体的硬件显示模式。
在保证数据格式正确的同时,机顶盒软件还会面临屏幕内容与帧缓存内容同步的问题。在软件绘制屏幕图像的过程中,往往会多次更新屏幕同一个像素的内容。例如,应用程序需要更改屏幕上显示的文字,通常的做法是先将屏幕上相应的区域用背景色完全填充,然后重新绘制新的文字内容。这样做比先计算不同的文字更改了哪些像素,然后只更新受影响的像素开销更低。然而其带来的影响是:尚未完全更新的图像(清空的背景)可能会短暂显示在屏幕上,从而造成图像闪烁。
为了保证帧缓存中图像的完整性,绘图引擎使用多缓冲技术。也就是在显存中分配多个缓冲区,任意时刻仅将其中的一帧作为当前显示帧。机顶盒软件在工作时只向非当前屏幕显示帧中写入将要显示的帧数据,当全部绘图操作完成后,再将当前的显示帧切换到已经绘制完成的帧缓存中去,这样避免了图像闪烁的发生。
使用多重缓冲势必会带来显存的开销,因此在机顶盒系统中,绘图引擎只使用2块帧缓存。帧缓存的管理对上层应用是透明的,绘图引擎对上层提供以下2个编程接口:BeginPaint和EndPaint,用来标识1次屏幕更新的开始和结束。帧缓存的切换在EndPaint调用时进行。
3.2 屏幕区域和裁剪
屏幕区域是指在屏幕上的一系列像素构成的集合。考虑到机顶盒系统的限制和实际工程的需要,绘图引擎仅支持矩形的屏幕区域。上层应用可以使用编程接口AllocateRegion和DestroyRegion来分配或销毁区域。
屏幕区域的主要使用者是上层的窗口管理器,因为屏幕区域对应一个窗口,因此最重要的功能是完成对绘图内容的裁剪。在任意时刻,绘图引擎仅支持一个活动区域作为当前的裁剪区域。任何绘图指令都只会影响该区域中的帧缓存内的数据,超出该区域的部分不会发生变化。上层模块可以通过SetClipRegion接口来设置当前的裁剪区域。
图形引擎中提供了对软件和硬件裁剪的支持,由于软件裁剪的速度较慢,而主流的机顶盒平台均已提供对硬件裁剪的支持,硬件裁剪是首选的实现方式。
3.3 绘图编程接口
在对帧缓存和裁剪支持的基础上,绘图引擎提供了一系列绘图接口供上层模块使用。考虑到在实际工程中,机顶盒上的界面软件往往仅使用标量绘图,因而绘图引擎提供的图形接口包括:
1)绘制线段。实际工程中通常不需要绘制除水平和垂直线段之外的任意角度线段。绘图引擎会对这2类特殊线段提供硬件加速支持。
2)绘制标量图。这是在机顶盒系统上最为常用的图形操作,包括对标量图形的显示、缩放,以及基于透明度的混合等,所有操作都提供硬件加速支持。
3)文字显示。绘图引擎提供对矢量和标量字库的支持。用于显示固定或任意大小的文字。
4 窗口管理器
基于绘图引擎提供的绘图能力,窗口管理器将屏幕划分为任意的矩形区域,每个区域作为一个窗口,提供给上层应用程序,是应用可编程的最基本屏幕单元。窗口管理器实现对窗口的管理,例如窗口的创建和销毁、窗口的布局等。窗口管理器作为整个图形系统的最上层,是上层应用访问图形系统的唯一入口,因此窗口管理器提供了绝大部分的应用编程接口,其结构如图4所示。
图4 窗口管理器结构图
在窗口管理器中,各种输入设备产生的事件通过消息队列分发到窗口系统的各个窗口中,窗口通过处理不同的消息来更新其在屏幕上的显示内容,从而完成与用户的交互。
4.1 消息队列和消息传递
窗口间的基本通信机制是窗口消息,每条消息由1个消息编号以及2个32位的参数构成。窗口消息存储在应用程序的消息队列中,每个使用窗口管理器的线程都有一个消息队列。在实际工程中,机顶盒系统往往采用基于微内核结构的实时操作系统,在这样的系统中,每个任务通常都已经有一个消息队列,因此窗口管理器会重用该任务的消息队列来传递窗口消息。
窗口系统中的消息分为3类:
1)输入设备消息。通常是遥控器或控制面板按键产生的消息,此类消息会被窗口管理器分发给当前具有输入焦点的窗口。在任意时刻,系统中最多只有一个窗口具有输入焦点,通常是一个编辑框窗口。
2)普通窗口消息。此类消息发送给某个特定的窗口,发送方在发送消息时,必须正确指定目的窗口的窗口句柄。
3)系统广播消息。当系统中的硬件设备产生特定事件,需要提示用户注意时,产生此类消息。这些消息不对应特定窗口。往往由应用程序决定如何处理。
应用程序通过调用GetMessage接口来获取队列中的窗口消息,该函数的调用会被阻塞,直到有新的窗口消息到达。当新的消息到达后,应用通过DispatchMessage接口将收到的消息分发给特定的窗口处理。
系统中的每个窗口都需要提供与其相关联的消息处理函数,窗口管理器在分发消息的过程中,通过调用相关窗口的消息处理函数来处理消息。窗口管理器同时提供了缺省的消息处理函数DefWindowProc(),用于统一处理常见的消息,例如改变窗口的位置和大小。窗口的消息处理函数应当将自身不处理的消息交给缺省消息处理函数处理。
当应用程序通过窗口管理器发送消息时,有2种方式可供选择:1)异步发送。消息被放置到消息队列中,当下一次调用GetMessage()时该消息被处理。采用此种发送方式时,消息的发送方不能确认接收方何时会处理该消息。2)同步发送。此时消息并不会被放置在消息队列中,窗口管理器直接调用目标窗口的消息处理函数。此时消息传递等同于函数调用,因此发送方能够确定接收方会立刻处理该消息。
此消息传递机制的存在使窗口管理器能够通过发送消息来管理和协调系统中所有窗口的功能,例如在创建和销毁窗口时发送特定消息,同时也能够通过缺省的消息处理函数保证各个窗口在基本交互行为上的一致性。
4.2 窗口树
图形用户界面中的界面元素自然形成一颗树,因此窗口系统中的窗口以树形结构存放在窗口管理器中。窗口树中重要的操作包括:窗口的创建和销毁、窗口的遮挡关系和窗口的显示和隐藏。
1)窗口的创建和销毁
创建和销毁窗口对应于窗口树上节点的插入和删除操作。窗口树的根节点由窗口管理器创建,应用程序创建新的窗口时应当指定该窗口的父窗口。如果父窗口为空,窗口管理器会将根节点作为其父节点。窗口管理器将新建的窗口节点的指针返回给上层应用作为窗口句柄,窗口句柄将被用于绝大多数窗口系统的编程接口中,用于快速定位窗口树中的特定节点。
2)窗口的遮挡关系
窗口之间的遮挡关系可以通过相应节点在树中的位置确定:高度相同的窗口节点之间,左邻居遮挡右邻居;高度不同的窗口节点之间,子节点遮挡父节点。窗口间默认的Z序在创建窗口时被确定,新创建的窗口遮挡已经创建的窗口。窗口管理器同时提供调整Z序的编程接口,用于调整同一高度的窗口节点之间的相互关系。
3)窗口的显示和隐藏
应用可以通过设置窗口的属性来显示或隐藏某个窗口,隐藏的窗口不会被销毁。窗口管理器在遍历窗口树时会检查相应的属性,如果窗口被隐藏,该节点及其所有子节点会被跳过,从而不会出现在屏幕上。
4.3 窗口布局和屏幕重绘
窗口的重绘过程等效于在该窗口树上的中序遍历,图5为简单窗口树实例。
桌面作为覆盖整个屏幕的窗口被最先绘制,由于顶层窗口2具有更高的Z序,因此系统首先绘制窗口1及其所有子窗口,然后绘制窗口2,进而完成对所有屏幕元素的重绘。
为了提高绘图效率,窗口管理器在重绘屏幕时采用2次遍历的方式。第1次遍历时,系统仅根据Z序计算各个窗口需要重绘区域的外接矩形,进而判断出哪些窗口由于完全被遮挡而不需重绘。第2次遍历时,完成实际的重绘过程。以图5为例,如果窗口2具有与窗口1同样的位置,则窗口1的重绘将被忽略,进而提高重绘过程的效率。
窗口管理器提供在窗口中绘图的编程接口,这些编程接口大多对应绘图引擎中的相应函数,窗口管理器在调用绘图引擎前完成的额外操作包括:
1)坐标变换。应用程序通过窗口管理器绘图时需要指定特定的窗口句柄作为绘图的目标,绘图时所有坐标均是窗口坐标,即以窗口左上角为原点的坐标。这样当窗口被移动时,所有绘图指令在窗口内仍然有效。在调用绘图引擎前,窗口管理器根据当前窗口的实际位置完成窗口坐标到屏幕坐标的转换,然后以屏幕坐标作为参数调用绘图引擎的相应接口。
2)设定裁剪区域。窗口自然映射到绘图引擎中的裁剪区域,为了保证任何绘图指令只影响某一个窗口内的内容,窗口管理器首先根据指令中的窗口句柄设置相应的裁剪区域,然后再进行实际的绘图操作。
4.4 常用界面控件库
采用上述窗口管理器,应用程序已经可以开发各类图形用户界面。本文的图形系统中,常用的界面元素被包含在窗口管理器中提供给应用程序使用。界面控件库是基于该系统窗口的实现,包括按钮、选单、列表、编辑输入框和分页显示控件等。应用程序通过创建某类控件窗口的实例来使用该控件库。
5 小结
通过笔者介绍的方法实现的嵌入式窗口系统,应用于广东南方银视网络传媒有限公司的各种类型机顶盒软件中。该软件可移植性高,操作灵活,逻辑清晰,性能稳定,上层开发简便,界面优美,受到用户的肯定和好评。
[1] 陈卉,刘卫忠,冯卓明.嵌入式平台下GUI工具的设计[J].电视技术,2007,31(2):29-31.
[2] 彭文,陈虹,罗惠琼.嵌入式窗口系统的研究与实现[J].计算机应用研究, 2002(9):104-107.
[3] 李升亮,徐剑峰,李峻林.嵌入式系统中的多窗口GUI系统的研究[J].计算机与数字工程, 2008(10):126-128.
[4] 陈雁飞,赵岳松,陈榕.基于构件技术的嵌入式GUI系统[J].计算机工程与设计, 2006, 27(4):561-564.
[5] 丁茂顺.用户接口技术与交互系统构造方法[M].北京:科学出版社,1992.
[6] 孙家广.计算机图形学[M].北京:清华大学出版社,1998.