1 引言
在 MiniGUI 0.3.xx 的开发中,我们引入了图形和输入抽象层(Graphics and Input Abstract Layer,GAL 和 IAL)的概念。抽象层的概念类似 Linux 内核虚拟文件系统的概念。它定义了一组不依赖于任何特殊硬件的抽象接口,所有顶层的图形操作和输入处理都建立在抽象接口之上。而用于实现这一抽象接口的底 层代码称为“图形引擎”或“输入引擎”,类似操作系统中的驱动程序。这实际是一种面向对象的程序结构。利用 GAL 和 IAL,MiniGUI 可以在许多已有的图形函数库上运行,比如 SVGALib 和 LibGGI。并且可以非常方便地将 MiniGUI 移植到其他 POSIX 系统上,只需要根据我们的抽象层接口实现新的图形引擎即可。比如,在基于 Linux 的系统上,我们可以在 Linux FrameBuffer 驱动程序的基础上建立通用的 MiniGUI 图形引擎。实际上,包含在 MiniGUI 1.0.00 版本中的私有图形引擎(Native Engine)就是建立在 FrameBuffer 之上的图形引擎。一般而言,基于 Linux 的嵌入式系统均会提供 FrameBuffer 支持,这样私有图形引擎可以运行在一般的 PC 上,也可以运行在特定的嵌入式系统上。
相比图形来讲,将 MiniGUI 的底层输入与上层相隔显得更为重要。在基于 Linux 的嵌入式系统中,图形引擎可以通过 FrameBuffer 而获得,而输入设备的处理却没有统一的接口。在 PC 上,我们通常使用键盘和鼠标,而在嵌入式系统上,可能只有触摸屏和为数不多的几个键。在这种情况下,提供一个抽象的输入层,就显得格外重要。
本文将介绍 MiniGUI 的 GAL 和 IAL 接口,并介绍私有图形引擎和特定嵌入式系统下的输入引擎实现。
2 MiniGUI 的 GAL 和 IAL 定义
GAL 和 IAL 的结构是类似的,我们以 GAL 为例说明 MiniGUI GAL 和 IAL 抽象层的结构。
2.1 GAL 和图形引擎
参见图 1。系统维护一个已注册图形引擎数组,保存每个图形引擎数据结构的指针。系统利用一个指针保存当前使用的图形引擎。一般而言,系统中至少有两个图形引擎, 一个是“哑”图形引擎,不进行任何实际的图形输出;一个是实际要使用的图形引擎,比如 LibGGI 或者 SVGALib,或者 Native Engine。每个图形引擎的数据结构定义了该图形引擎的一些信息,比如标识符、属性等,更重要的是,它实现了 GAL 所定义的各个接口,包括初始化和终止、图形上下文管理、画点处理函数、画线处理函数、矩形框填充函数、调色板函数等等。
如果在某个实际项目中所使用的图形硬件比较特殊,现有的图形引擎均不支持。这时,我们就可以安照 GAL 所定义的接口实现自己的图形引擎,并指定 MiniGUI 使用这种私有的图形引擎即可。这种软件技术实际就是面向对象多态性的具体体现。
利用 GAL 和 IAL,大大提高了 MiniGUI 的可移植性,并且使得程序的开发和调试变得更加容易。我们可以在 X Window 上开发和调试自己的 MiniGUI 程序,通过重新编译就可以让 MiniGUI 应用程序运行在特殊的嵌入式硬件平台上。
在代码实现上,MiniGUI 通过 GFX 数据结构来表示图形引擎,见清单 1。
清单 1 MiniGUI 中的图形引擎结构(src/include/gal.h) |
系统启动之后,将根据配置寻找特定的图形引擎作为当前的图形引擎,并且对全局变量 cur_gfx 赋值。之后,当 MiniGUI 需要在屏幕上进行绘制之后,调用当前图形引擎的相应功能函数。比如,在画水平线时如下调用:
(*cur_gfx->drawhline) (gc, x, y, w, pixel); |
为方便程序书写,我们还定义了如下 C 语言宏:
167 #define PHYSICALGC (cur_gfx->phygc) |
这样,上述画线函数可以如下书写:
GAL_DrawVLine (gc, x, y, w, pixel); |
显然,只要在系统初始化时能够根据设定对 cur_gfx 进行适当的赋值,MiniGUI 就能够在相应的图形引擎之上进行绘制。
对底层图形引擎的调用,主要集中在 MiniGUI 的 GDI 函数中。比如,要绘制一条直线,MiniGUI 的 LineTo 函数定义如清单 2 所示:
清单 2 LineTo 函数(src/gdi/draw-lite.c) |
在 MiniGUI 的所有绘图函数中,要依次做如下几件事:
在上面的四个步骤当中,第 3 步和第 4 步实际可以放到底层引擎当中,从而能够大大提高 MiniGUI 的绘图效率。不过,这种性能上的提高,对块输出,比如填充矩形、输出位图来讲,并不是非常明显。在将来的底层图形引擎当中,我们将针对上述两点,进行较大 的优化以提高图形输出效率。
2.2 IAL 和输入引擎
如前所属,MiniGUI IAL 结构和 GAL 结构类似。在代码实现上,MiniGUI 通过 INPUT数据结构来表示输入引擎,见清单 3。
清单 3 MiniGUI 中的输入引擎结构(src/include/ial.h) |
系统启动之后,将根据配置寻找特定的输入引擎作为当前的输入引擎,并且对全局变量 cur_input 赋值。
(*cur_gfx->drawhline) (gc, x, y, w, pixel); |
为方便程序书写,我们还定义了如下 C 语言宏:
69 #define IAL_InitInput (*cur_input->init_input) |
在 src/kernel/event.c 中,我们如下调用底层的输入引擎,从而将输入引擎的数据转换为 MiniGUI 上层能够理解的消息(以 MiniGUI-Lite 为例),见清单 4:
清单 4 MiniGUI 对底层输入事件的处理 |
从这段代码中可以看出,对定点设备来讲,比如鼠标或者触摸屏,MiniGUI 能够自动识别移动信息,也能够自动识别用户的单击和双击事件。这样,底层引擎只需提供位置信息和当前的按键状态信息就可以了。对类似键盘的东西, MiniGUI 也能够自动进行重复处理。当一个按键按下一段时间之后,MiniGUI 将连续发送该按键的消息给上层处理。对特定的嵌入式系统来讲,可以将某些按键映射为 PC 的某些键盘键,上层只需处理这些键盘键消息的按下和释放即可。这样,嵌入式系统上的某些键的功能就可以在 PC 上进行模拟了。
(待续)
资源
关于作者
魏永明([email protected]),男,27 岁,工学硕士,现任蓝点软件(深圳)有限公司北京研发中心技术主管。国内最有影响的自由软件项目之一-- MiniGUI 的创始人以及主要开发人员。著有《Linux 实用教程》与《学用 Linux 与 Windows NT》,并主持翻译了《Red Hat Linux 奥秘》、《Linux 编程宝典》 等大量优秀的 Linux 技术著作。是清华大学 AKA Linux 编程技术系列讲座的主讲人。