# MiniGUI 技术白皮书

（Ver 1.0 For MiniGUI 1.0.xx）
魏永明，2001/2/23
版权所有。未经授权，不得随意复制发布

## 1 MiniGUI 简介

### 1.1 什么是 MiniGUI

MiniGUI（http://www.minigui.org）是由魏永明主持的一个自由软件项目（遵循 LGPL 条款发布），其目标是为基于 Linux 的实时嵌入式系统提供一个轻量级的图形用户界面支持系统。该项目自 1998 年底开始到现在，已历经 2 年多的开发过程，到目前为止，已经非常成熟和稳定。尤其在过去的一年当中，MiniGUI 发生了巨大的变化。

目前，MiniGUI 已经发展到了 1.0.00版。MiniGUI 从最初基于 SVGALib 和 PThread 的 0.2.xx 版本，到具有图形抽象层（GAL）和输入抽象层（IAL），以及高级字符集和字体支持的 0.3.xx 版本，到后来独具匠心的 MiniGUI-Lite 版本以及直接基于 Linux FrameBuffer 私有引擎的问世（0.9.xx 版本），直到今天的 MiniGUI 1.0.00 版本，其中凝聚了许多开发人员的心血。MiniGUI 的发展历程，是不断突破和创新的过程。

MiniGUI 最初定义了一些类似 Win32 窗口管理 API 的应用程序调用接口，但现在，MiniGUI 的 API 已经越来越远离 Win32 API，并形成了自己的特色。利用 MiniGUI，我们几乎可以完成任何其他窗口系统能够完成的工作。

有的人会问，有许多其他的窗口系统可以使用，我们为什么还要自己开发呢？大家都知道，Linux 上的标准窗口系统，即 X Window，非常庞大，占用资源非常多，因此，不适合于实时系统和嵌入式系统。因此，有必要开发一个小型的窗口支持系统，能够支持实时系统和嵌入式系统。当然，与 MiniGUI 目标相一致的系统现在也有些可从 INTERNET上获得，比如 NanoGUI（Microwindows），但 MiniGUI 还是有它自己的优势，并且在体系结构上有许多独特之处。

本技术白皮书即介绍 MiniGUI 在技术上的一些特色和创新。

### 1.2 实时嵌入式系统对 GUI 的要求

在常见的 PDA 等小型手持式设备上，由于硬件条件等的限制，我们看到的用户界面都非常简单，几乎看不到我们在 PC 机上司空见惯的华丽美观的 GUI 支持。但最近出现的 Palm 等手持式电脑或者在 Windows CE 等面向嵌入式系统的操作系统上，我们已经看到了完整的图形用户界面支持。随着手持式设备的硬件条件的提高，我们估计嵌入式系统对轻量级 GUI 的需求会越来越迫切。

近来的市场需求显示，越来越多的嵌入式系统，包括 PDA、机顶盒、DVD/VCD 播放机、WAP 手机等等系统均要求提供全功能的 Web 浏览器。这包括 HTML 4.0 的支持、JavaScript 的支持，甚至包括 Java 虚拟机的支持。而这一些均要求有一个高性能、高可靠的 GUI 的支持。

另外一个对轻量级 GUI 需求迫切的系统是工业实时控制系统。这些系统一般建立在标准 PC 平台上，硬件条件相对嵌入式系统要好，但对实时性的要求非常高，并且比起嵌入式系统来说，对 GUI 的要求也更高。这些系统一般不希望建立在庞大累赘的、非常消耗系统资源的操作系统和 GUI 之上，比如 Windows 或 X Window。目前许多这类系统都建立在 DOS 等系统上，并且采用比较简单的手法实现 GUI。但是，在出现 Linux 系统之后，尤其在 RT-Linux 系统出现之后，许多工业控制系统开始采用 RT-Linux 作为操作系统，但 GUI 仍然是一个问题。关键是 X Window 太过庞大和臃肿。这样，这些系统对轻型 GUI 的需求更加突出。

但是，我们必须清楚的是，嵌入式系统往往是一种定制设备，它们对 GUI 的需求也各不相同。举个简单的例子，有的系统只要求一些图形功能，而有些系统要求完备的 GUI 支持。因此，GUI 也必须是可定制的。

综上所述，GUI 在嵌入式系统或者实时系统中的地位将越来越重要，这些系统对 GUI 的基本要求包括：

1. 轻型、占用资源少。
2. 高性能。
3. 高可靠性。
4. 可配置。

### 1.3 为什么要使用 MiniGUI

如前所述，由于在实时嵌入式操作系统中，其硬件环境比较苛刻，因此要求运行其中的图形界面尽可能的精简，而传统的窗口系统尚不能满足实时嵌入式系统的需求。所以，在基于 Linux 的实时嵌入式系统上，构建一个能够充分满足嵌入式系统需求的图形用户界面支持系统就成了当务之急。实际上，国内外已有许多专门针对 Linux 的嵌入式 GUI 系统，MiniGUI 只是其中之一。然而，由于开发人员对实时嵌入式系统在理解上的不同，使得这些 GUI 系统在接口定义、体系结构、功能特性等方面存在着很大的差别。另外，这些 GUI 系统所使用的授权条款也各有不同。

那么，MiniGUI 和其他面向嵌入式系统的 GUI 有何不同？

#### 1.3.1 其他嵌入式 GUI 系统简介

##### 1 MicroWindows

Microwindows（http://microsoft.censoft.com）是一个开放源码的项目，目前由美国一家公司在主持开发。该项目的开发非常活跃，国内也有人参与了其中的开发，并编写了 GB2312 等字符集的支持。该项目的主要特色在于提供了比较完善的图形功能，包括一些高级的功能，比如 Alpha 混合，三维支持，TrueType 字体支持等。但作为一个窗口系统，该项目提供的窗口处理功能还需要进一步完善。值得一提的是，该项目的许多控件是从 MiniGUI 中移植过去的，扫雷游戏也是从 MiniGUI 中移植过去的。

该项目已经启动了一个开放源码的浏览器项目（称为ViewML，http://www.viewml.org），该浏览器在 KDE kfm 提供的 HTML 解释器的基础上开发，目前能够解释一些较为简单的 HTML 页面。

MicroWindows 是一个基于典型客户/服务器体系结构的 GUI 系统，基本分为三层。最底层是面向图形输出和键盘、鼠标或触摸屏的驱动程序；中间层提供底层硬件的抽象接口，并进行窗口管理；最高层分别提供兼容于 X Wiw 和 Windows CE（Win32 子集）的 API。

MicroWindows 采用 MPL 条款发布（该条款基本类似 LGPL 条款）。

##### 2 OpenGUI

OpenGUI（http://www.tutok.sk/fastgl/）在 Linux 系统上存在已经很长时间了。最初的名字叫 FastGL，只支持 256 的线性显存模式。但目前也支持其他显示模式，并且支持多种平台，比如 MS-DOS、QNX 和 Linux 等等，不过目前只支持 x86 硬件平台。OpenGUI 也分为三层。最低层是由汇编编写的快速图形引擎；中间层提供了图形绘制 API，包括线条、矩形、圆弧等，并且兼容于 Borland 的 BGI API。第三层用 C++ 编写，提供了完整的 GUI 对象集。

OpenGUI 采用 LGPL 条款发布。OpenGUI 比较适合于基于 x86 平台的实时系统，可移植性稍差。

##### 3 Qt/Embedded

QT/Embedded是著名的 QT 库开发商 TrollTech（http://www.trolltech.com/）发布的面向嵌入式系统的 QT 版本。这个版本的主要特点是稳定、可移植性较好，许多基于 QT 的 X Window 程序可以非常方便地移植到嵌入式版本。目前，该系统采用两种条款发布，其中包括 GPL 条款。不过，这种授权方式保留了 Trolltech 在将来向 QT/Embedded 用户收取费用的权力。另外，由于 QT 是 C++ 语言编写的，所以在效率、大小等方面有一些缺点。

表 1 综合对比了上述 GUI 系统，其中也包括 MiniGUI。

表 1 常见面向实时嵌入式系统的 GUI 之比较

| MiniGUI | MicroWindows | OpenGUI | QT/Embedded
API | Win32风格 | X、Win32 子集 | 私有 | QT（C++）
API 是否完备 | 是 | Win32支持尚不完备 | 是 | 是
函数库的典型大小 | 300K | 300K | 300K | 600K
可移植性 | 很好 | 很好 | 只支持 x86 平台 | 较好（但函数库本身的跨平台交叉编译很困难）
授权条款 | LGPL（免费使用） | MPL/LGPL | LGPL | QPL/GPL（限制使用它的应用程序也必须是 GPL 条款发布自由软件）
多进程支持 | 好 | NanoX 接口很好, Win32 接口很差. | 不好 | 好
健壮性 | 好 | 好 | 好 | 好
多语种支持 | 好 | 一般 | 一般 | 好
可配置和可定制性 | 好（提供了大量编译配置选项，可配置能力很强） | 一般 | 一般 | 一般
系统资源消耗 | 小（多线程和 MiniGUI-Lite 均是针对最小系统资源消耗设计） | 较大（基于 UNIX 套接字的传统客户/服务器体系，进程间的通讯频繁，系统资源消耗较大） | 最小（不支持多进程，资源消耗最小） | 最大（用C++实现，系统资源消耗最大）
效率 | 好 | 好 | 最好（底层用汇编编写） | 一般
使用是否广泛 | 已有基于 MiniGUI 的产品上市（HappyLinux 和 Linpus Linux的安装程序，清华大学 CNC 数控系统等）。今年中将有基于 MiniGUI 的嵌入式产品上市。 | 目前尚没有基于 MicroWindows 的嵌入式正式产品上市，但已有样机发布。 | 在实时控制领域使用广泛。 | 由于授权条款的限制，基本不会有基于 QT/Embedded 的商业嵌入式产品在近期出现。
操作系统支持 | Linux | Linux | DOS、 Linux、QNX | Linux

#### 1.3.2 MiniGUI 的优势

比较上述几个面向实时嵌入式系统的 GUI，我们认为目前比较成熟，同时得到最多开发人员认可的有 MiniGUI 和 MicroWindows 两个系统。这两个系统在许多方面互相借鉴，优势互补，但本质的区别在于体系结构上的不同。

MicroWindows 追求和 X 的兼容，所以，采用的传统的基于 UNIX 套接字的客户/服务器系统结构。在这种体系结构下，客户建立窗口、绘制等等都要通过套接字传递到服务器，由服务器完成实质工作。这样，系统非常依赖于 UNIX 套接字通讯。而大家都知道，UNIX 套接字的数据传递，要经过内核，然后再传递到另外一个程序。这样，大量的数据在客户/内核/服务器之间传递，从而增加了系统负荷，也占用了许多系统资源。这对许多嵌入式系统来说，是不可接受的。

MiniGUI 为了解决这个问题，首先采用了线程机制（类似Windows CE），所有的应用程序都运行在同一个地址空间，这样，大大提高了程序之间的通讯效率。但显然，这种基于线程的结构也导致了系统整体的脆弱――如果某个线程因为非法的数据访问而终止运行，则整个进程都将受到影响。不过，这种体系结构对实时控制系统等时间关键的系统来讲，还是非常适合的。

为了解决 MiniGUI 版本因为线程而引入的一些问题，同时也为了让 MiniGUI更加适合于嵌入式系统，我们决定开发一个 MiniGUI-Lite 版本。这个版本的开发目的是：

1. 保持与原先 MiniGUI 版本在源代码级 99% 以上的兼容。
2. 不再使用线程库。
3. 可以同时运行多个基于 MiniGUI-Lite 的应用程序，即多个进程，并且提供前后台进程的切换。

显然，要同时满足上述三个目的，如果采用传统的 C/S 结构对现有 MiniGUI 进行改造，应该不难实现。但前面提到的传统 C/S 结构的缺陷却无法避免。经过对 PDA 等嵌入式系统的分析，我们发现，某些 PDA 产品具有运行多个任务的能力，但同一时刻在屏幕上进行绘制的程序，一般不会超过两个。因此，只要确保将这两个进程的绘制相互隔离，就不需要采用复杂的 C/S 结构处理多个进程窗口之间的互相剪切。也就是说，在这种产品中，如果采用基于传统 C/S 结构的多窗口系统，实际是一种浪费。

有了上述认识，我们对 MiniGUI 版本进行了如下简化设计：

1. 每个进程维护自己的主窗口 Z 序，同一进程创建的主窗口之间互相剪切。也就是说，除这个进程只有一个线程，只有一个消息循环之外，它与原有的 MiniGUI 版本之间没有任何区别。每个进程在进行屏幕绘制时，不需要考虑其他进程。
2. 建立一个简单的客户/服务器体系，但确保最小化进程间的数据复制功能。因此，在服务器和客户之间传递的数据仅限于输入设备的输入数据，以及客户和服务器之间的某些请求和响应数据。
3. 有一个服务器进程（mginit），它负责初始化一些输入设备，并且通过 UNIX Domain 套接字将输入设备的消息发送到前台的 MiniGUI-Lite 客户进程。
4. 服务器和客户被分别限定在屏幕的某两个不相交矩形内进行绘制，同一时刻，只能有一个客户及服务器进行屏幕绘制。其他客户可继续运行，但屏幕输入被屏蔽。服务器可以利用 API 接口将某个客户切换到前台。同时，服务器和客户之间采用信号和 System V 信号量进行同步。
5. 服务器还采用 System V IPC 机制提供一些资源的共享，包括位图、图标、鼠标、字体等等，以便减少实际内存的消耗。

从传统 C/S 窗口系统的角度看，MiniGUI-Lite 的这种设计，无法实现类似 X 的完整多窗口支持，这的确是一个结构设计上的不足和缺陷。不过，这实际是 MiniGUI-Lite 不同于其他窗口系统的一个特征。因为处理每个进程之间的互相剪切问题，将导致客户和服务器之间的通讯量大大增加，但实际上在许多嵌入式系统当中这种处理是没有必要的。在类似 PDA 的嵌入式系统中，往往各个程序启动后，就独占屏幕进行绘制输出，其他程序根本就没有必要知道它现在的窗口被别的进程剪切了，因为它根本就没有机会输出到屏幕上。所以，在 MiniGUI-Lite 当中，当一个进程成为最顶层程序时，服务器会保证其输出正常，而当有新的程序成为最顶层程序时，服务器也会保证其他程序不能输出到屏幕上。但这些进程依然在正常执行着，不过，服务器只向最顶层的程序发送外部事件消息。

现在，你可以下载 MiniGUI 的最新源代码，根据你的需求，将其编译为线程版本或者 MiniGUI-Lite 版本，使得你的 GUI 系统占用系统资源最少，运行效率最高。

### 1.4 MiniGUI 的主要功能特色和创新

#### 1.4.1 主要功能特色

就现有的 MiniGUI 1.0.00 版本 来看，MiniGUI 的主要功能特色为：

- 遵循 LGPL 条款的纯自由软件。
- 提供了完备的多窗口机制。
- 多个单独线程中运行的多窗口。
- 单个线程中主窗口的附属。
- MiniGUI-Lite 版本可让程序以单独的进程形式执行，各进程能够实现完备的多窗口处理。
- 预定义的控件类（静态文本框、按钮、单行和多行编辑框、列表框、进度条、工具栏、拖动条、树型控件、月历控件等）。
- 对话框。
- 消息传递机制。
- GDI 函数和直接基于 Linux FrameBuffer 的 Native Graphics Engine。
- Windows 的资源文件支持，如位图、图标、光标等。
- 插入符。
- 定时器。
- 加速键。
- 多字符集和多字体支持，目前支持 ISO8859-1～ISO8859-15、GB2312、Big5、EUCKR、UJIS等字符集。
- 汉字输入法支持。
- GIF 和 JPG 支持。
- 其他（Beep, ETC/INI 文件操作等）。

#### 1.4.2 MiniGUI 的系统特点

MiniGUI 的系统特点包括如下几点：

- 小巧。包含全部功能的库文件大小为 300 K左右。
- 可配置。可根据项目需求进行定制配置和编译。
- 高稳定性和高性能。MiniGUI 已经在 HappyLinux 安装程序、Linpus Linux 安装程序、CNC 系统等关键应用程序中得到了实际的应用。
- 可移植性好。目前，MiniGUI 可以在 X Window 和 Linux 控制台上运行。许多公司现在已经将 MiniGUI 移植到不同的硬件平台上，包括基于 ARM 和 StrongARM 的嵌入式系统、基于 MIPS 的嵌入式系统等等。

#### 1.4.3 MiniGUI 的创新特性

在最近的 MiniGUI 开发中，从而实现了如下新的创新特性：

- 图形抽象层。图形抽象层对顶层 API 基本没有影响，但大大方便了 MiniGUI 应用程序的移植、调试等工作。目前包含两个图形引擎，SVGALib 和 LibGGI，利用 LibGGI 时，可在 X Window 上运行 MiniGUI 应用程序，并可非常方便地进行调试。与图形抽象层相关的还有输入事件的抽象层。
- 多字体和多字符集支持。这部分通过设备上下文（DC）的逻辑字体（LOGFONT）实现，不管是字体类型还是字符集，都可以非常方便地进行扩充。应用程序在启动时，可切换系统字符集，比如 GB 或 BIG5。利用 DrawText 等函数时，可通过指定字体而获得其他字符集支持。对于一个窗口来说，同时显示不同语种的文字是可能的。MiniGUI 的这种字符集支持不同于传统通过 UNICODE 实现的多字符集支持，我们的这种实现更加适合于嵌入式系统。如果要实现 UNICODE，只需将 UNICODE 看成是一种新的字符集实现即可。
- MiniGUI-Lite 版本。这个版本在提高系统健壮性的同时，通过一系列创新途径，避免了传统 C/S 结构的弱点，为 PDA 等嵌入式系统提供了一个高效、稳定的 GUI 系统。

### 1.5 MiniGUI 的主要技术参数

#### 1.5.1 MiniGUI 的占用空间大小

- Linux 内核： 300K ～ 500K（由系统决定）
- MiniGUI 支持库： 300K ～ 400 K（由编译配置决定）
- MiniGUI 字体、位图等资源：800K
- 汉字输入法：400K
- 应用程序： 500K ～ 2M（由系统决定）

总计应该在 1M 到 2M 左右。如果不需要某些特征，系统容量还可以更少。

#### 1.5.2 MiniGUI 支持哪些硬件

MiniGUI 对硬件要求主要体现在显示设备上。在 MiniGUI 0.3.xx 的开发中，我们引入了图形和输入抽象层（Graphics and Input Abstract Layer，GAL 和 IAL）的概念。抽象层的概念类似 Linux 内核虚拟文件系统的概念。它定义了一组不依赖于任何特殊硬件的抽象接口，所有顶层的图形操作和输入处理都建立在抽象接口之上。而用于实现这一抽象接口的底层代码称为“图形引擎”或“输入引擎”，类似操作系统中的驱动程序。这将大大方便 MiniGUI 对新硬件的适应性――只要根据我们的抽象接口编写相应的图形引擎即可。因为大多数嵌入式系统均提供对 Linux FrameBuffer 的支持，所以，通常情况下，对硬件的支持往往就取决于输入设备。因为我们已经通过 Native Graphics Engine 的实现，支持了常见的 Linux FrameBuffer 显示模式，这些引擎可以移植到任何支持 Linux FrameBuffer 的嵌入式系统上。

#### 1.5.3 MiniGUI 的移植性

MiniGUI 是在符合 POSIX 标准的 C 函数库之上建立的图形用户界面支持系统，可移植到任何 POSIX 兼容系统。但要注意的是，MiniGUI 所使用的低层图形或者输入接口，一般是系统特有的，必须重新编写。

## 2 MiniGUI 的设计目标和重要特色

### 2.1 设计目标：小巧和可配置

MiniGUI 最初是为了满足一个工业控制系统（计算机数控系统）的需求而设计和开发的。这个工业控制系统是清华大学为一台数控机床设计的计算机数控系统（CNC）。在比较 DOS、Windows 98、Windows NT、Linux 等系统之后，该项目组决定选择 RT-Linux 作为实时操作系统，以便满足 2ms 甚至更高的实时性。但是图形用户界面是一个问题，因为 X Window 不适合于实时控制系统，并且当时 X Window 系统的本地化也不尽人意。因此，决定自己开发一套图形用户界面支持系统。这就是 MiniGUI 产生的背景。显然，MiniGUI 一开始就针对实时系统而设计，因此，在设计之初就考虑到了小巧、高性能和高效率。目前，这个数控系统的开发已近尾声，MiniGUI 在其中担当了非常重要的角色。

在考虑到其他不同于数控系统的嵌入式系统时，为了满足千变万化的需求，必须要求 GUI 系统是可配置的。在 CNC 系统中得到成功应用之后，我们立即着手于 MiniGUI 可配置的设计。我们通过 Linux 下的 Automake 和 Autoconf 接口，实现了大量的编译配置选项，通过这些选项可指定 MiniGUI 库中包括哪些功能而同时不包括哪些功能。

因此，MiniGUI 是一个非常适合于工业控制实时系统以及嵌入式系统的可定制的、小巧的图形用户界面支持系统。

### 2.2 重要特色

#### 2.2.1 多线程和多窗口

MiniGUI 中的窗口基本分四类，分别为主窗口、对话框、控件和主窗口中的子窗口。

MiniGUI 中的主窗口和 Windows 应用程序的主窗口概念类似，但有一些重要的不同，MiniGUI 中的每个主窗口及其附属主窗口对应于一个单独的线程，通过函数调用可建立主窗口以及对应的线程。每个线程有一个消息队列，属于同一线程的所有主窗口从这一消息队列中获取消息并由窗口过程（回调函数）进行处理。

#### 2.2.2 对话框和标准控件

MiniGUI 中的对话框是一种特殊的窗口，对话框一般和控件一起使用，这两个概念和 Windows 或 X Window 中的相关概念是类似的。MiniGUI 支持的控件类型有：

- 静态框：文本、图标或矩形框等。
- 文本框：单行或多行的文本编辑框。
- 按钮：单选钮、复选框和一般按钮等。
- 列表框。
- 进度条。
- 工具栏。
- 拖动条。
- 树型控件。
- 月历控件。

#### 2.2.3 其他 GUI 元素

MiniGUI 还支持层级式菜单、插入符、定时器、光标、快捷键等常见的 GUI 元素。

#### 2.2.4 消息和消息循环

在任何 GUI 系统中，均有事件或消息驱动的概念。在MiniGUI中，我们使用消息驱动作为应用程序的创建构架。

在消息驱动的应用程序中，计算机外设发生的事件，例如键盘键的敲击、鼠标键的按击等，都由支持系统收集，将其以事先的约定格式翻译为特定的消息。应用程序一般包含有自己的消息队列，系统将消息发送到应用程序的消息队列中。应用程序可以建立一个循环，在这个循环中读取消息并处理消息，直到特定的消息传来为止。这样的循环称为消息循环。一般地，消息由代表消息的一个整型数和消息的附加参数组成。

应用程序一般要提供一个处理消息的标准函数。在消息循环中，系统可以调用此函数，应用程序在此函数中处理相应的消息。

#### 2.2.5 图形和输入抽象层

在 MiniGUI 0.3.xx 的开发中，我们引入了图形和输入抽象层（Graphics and Input Abstract Layer，GAL 和 IAL）的概念。抽象层的概念类似 Linux 内核虚拟文件系统的概念。它定义了一组不依赖于任何特殊硬件的抽象接口，所有顶层的图形操作和输入处理都建立在抽象接口之上。而用于实现这一抽象接口的底层代码称为“图形引擎”或“输入引擎”，类似操作系统中的驱动程序。这实际是一种面向对象的程序结构。利用 GAL 和 IAL，MiniGUI 可以在许多图形引擎上运行，比如 SVGALib 和 LibGGI，并且可以非常方便地将 MiniGUI 移植到其他 POSIX 系统上，只需要根据我们的抽象层接口实现新的图形引擎即可。目前，我们已经编写了基于 SVGALib 和 LibGGI 的图形引擎。利用 LibGGI， MiniGUI 应用程序可以运行在 X Window 上，将大大方便应用程序的调试。我们目前正在进行 MiniGUI 私有图形引擎的设计开发。通过 MiniGUI 的私有图形引擎，我们可以最大程度地针对窗口系统对图形引擎进行优化，最终提高系统的图形性能和效率。

#### 2.2.6 多字体和多字符集支持

在成功引入 GAL 和 IAL 之后，我们又在处理字体和字符集的模块当中引入了逻辑字体的概念。逻辑字体是 MiniGUI 用来处理文本（包括文本输出和文本分析）的顶层接口。逻辑字体接口将各种不同的字体（比如宋体、黑体和揩体）和字体格式（比如等宽字体、变宽字体等光栅字体和 TrueType 等矢量字体），以及各种不同字符集（ISO-8859、GB2312、Big5、UNICODE等）综合了起来，从而可以通过统一的接口显示不同字符集的不同字体的文本，并且还可以分析各种字符集文本的组成，比如字符、单词等。在多字体和多字符集的支持中，我们也采用了面向对象的软件技术，使得添加新的字体支持和新的字符集支持非常方便。目前，MiniGUI 能够支持各种光栅字体和 TrueType、Type 1 等矢量字体，并能够支持 GB2312、Big5 等多字节字符集，UNICODE 的支持正在开发当中。

#### 2.2.7 MiniGUI-Lite

前面提及，MiniGUI-Lite 是我们为了解决 MiniGUI 的健壮性问题而开发的一个版本，并且专门针对嵌入式系统在体系结构上进行了特殊设计。大家都知道 MiniGUI 0.9.96 及以前版本基于 LinuxThreads 实现。因此，如果要启动一个基于 MiniGUI 的新应用程序，就必须退出当前程序并启动新程序，否则，我们只能通过“dlopen”动态装载程序，并以新线程的形式启动。尽管后者能够在某种程度上扩展应用程序，但这并不是一种好方法，因为进程中的任何一个线程均有可能破坏整个进程。

现在你可以使用 MiniGUI-Lite 一次运行不止一个 MiniGUI 应用程序。MiniGUI Lite 实际是 MiniGUI 的轻量级版本，这个版本不再使用 LinuxThreads。我们可以从一个称为“mginit”的程序中启动其他 MiniGUI 程序. 和 X Window 一样，前者称为客户，而后者称为服务器。客户通过 UNIX Domain Socket 连接到服务器，而服务器接受来自客户的请求并响应。服务器为客户提供资源的共享，并且向客户发送鼠标和键盘事件。如果因为某种原因客户意外终止的话，服务器可以继续运行，丝毫不会受到影响。在我们的发布版本中，有一个称为 mglite-exec 的包，这个包里有一个 mginit 程序，该程序建立了一个虚拟控制台窗口。我们可以从这个虚拟控制台的命令行启动该软件包中其他的程序，甚至可以通过 gdb 调试这些程序。

我们可以在 MiniGUI-Lite 程序中创建多个窗口，但不能启动新的线程建立窗口。这是 MiniGUI-Lite 区别于 MiniGUI 原有版本的最大不同。除此之外，其他几乎所有的 API 都和 MiniGUI 原有版本是兼容的。因此，从 MiniGUI 原有版本向 MiniGUI-Lite 版本的移植是非常简单的。实际上，MiniGUI-Lite 只在 MiniGUI 原有版本的基础上增加了为数不多的几个函数。

### 2.3 MiniGUI 的体系结构

#### 2.3.1 多线程的分层设计

从整体结构上看，MiniGUI 是分层设计的，见图 1。在最底层，GAL 和 IAL 提供底层图形接口以及鼠标和键盘的驱动；中间层是 MiniGUI 的核心层，其中包括了窗口系统必不可少的各个模块；最顶层是 API，即编程接口。

GAL 和 IAL 为 MiniGUI 提供了底层的 Linux 控制台或者 X Window 上的图形接口以及输入接口，而 Pthread 是用于提供内核级线程支持的 C 函数库。

MiniGUI 本身运行在多线程模式下，它的许多模块都以单独的线程运行，同时，MiniGUI 还利用线程来支持多窗口。从本质上讲，每个线程有一个消息队列，消息队列是实现线程数据交换和同步的关键数据接口。一个线程向消息队列中发送消息，而另一个线程从这个消息队列中获取消息，同一个线程中创建的窗口可共享同一个消息队列。利用消息队列和多线程之间的同步机制，可以实现下面要讲到的微客户/服务器机制。

多线程有其一定的好处，但不方便的是不同的线程共享了同一个地址空间，因此，客户线程可能会破坏系统服务器线程的数据，但有一个重要的优势是，由于共享地址空间，线程之间就没有额外的数据复制开销。

由于 MiniGUI 是面向嵌入式或实时控制系统的，因此，这种应用环境下的应用程序往往具有单一的功能，从而使得采用多线程而非多进程模式实现图形界面有了一定的实际意义，也更加符合 MiniGUI 之“mini”的特色。

#### 2.3.2 微客户/服务器结构

在多线程环境中，与多进程间的通讯机制类似，线程之间也有交互和同步的需求。比如，用来管理窗口的线程维持全局的窗口列表，而其他线程不能直接修改这些全局的数据结构，而必须依据“先来先服务”的原则，依次处理每个线程的请求，这就是一般性的客户/服务器模式。MiniGUI 利用线程之间的同步操作实现了客户线程和服务器线程之间的微客户/服务器机制，之所以这样命名，是因为客户和服务器是同一进程中的不同线程。

微客户/服务器机制的核心实现主要集中在消息队列数据结构上。比如，MiniGUI 中的 desktop 微服务器管理窗口的创建和销毁。当一个线程要求 desktop 微服务器建立一个窗口时，该线程首先在 desktop 的消息队列中放置一条消息，然后进入休眠状态而等待 desktop 处理这一请求，当 desktop 处理完成当前任务之后，或正处于休眠状态时，它可以立即处理这一请求，请求处理完成时，desktop 将唤醒等待的线程，并返回一个处理结果。

#### 2.3.3 MiniGUI-Lite 的实现技术

MiniGUI-Lite版是 MiniGUI 支持客户服务（C/S）方式的多进程系统，在运行过程中有且仅有一个服务器程序在运行，其余的MiniGUI应用程序为客户。这里简单描述 MiniGUI 的一些具体实现技术：

1. 每个进程维护自己的主窗口 Z 序，同一进程创建的主窗口之间互相剪切。也就是说，除这个进程只有一个线程，只有一个消息循环之外，它与原有的 MiniGUI 版本之间没有任何区别。每个进程在进行屏幕绘制时，不需要考虑其他进程。
2. 建立一个简单的客户/服务器体系，但确保最小化进程间的数据复制功能。因此，在服务器和客户之间传递的数据仅限于输入设备的输入数据，以及客户和服务器之间的某些请求和响应数据。
3. 有一个服务器进程（mginit），它负责初始化一些输入设备，并且通过 UNIX Domain 套接字将输入设备的消息发送到前台的 MiniGUI-Lite 客户进程。
4. 服务器和客户被分别限定在屏幕的某两个不相交矩形内进行绘制，同一时刻，只能有一个客户及服务器进行屏幕绘制。其他客户可继续运行，但屏幕输入被屏蔽。服务器可以利用 API 接口将某个客户切换到前台。同时，服务器和客户之间采用信号和 System V 信号量进行同步。
5. 服务器还采用 System V IPC 机制提供一些资源的共享，包括位图、图标、鼠标、字体等等，以便减少实际内存的消耗。

### 2.4 面向对象技术在 MiniGUI 中的运用

#### 2.4.1 控件类和控件

MiniGUI 中的每个控件都属于某种子窗口类，是对应子窗口类的实例。这类似于面向对象技术中类和对象的关系。

每个控件的消息实际都是有该控件所属控件类的回调函数处理的，从而可以让每个属于统一控件类的控件均保持有相同的用户界面和处理行为。

但是，如果我们在调用某个控件类的回调函数之前，首先调用自己定义的某个回调函数的话，我们就可以让该控件重载控件类的某些处理行为，从而让该控件一方面继承控件类的大部分处理行为，另一方面又具有自己的特殊行为。这实际就是面向对象中的继承和派生。比如，一般的编辑框会接收所有的键盘输入，当我们希望自己的编辑框只接收数字时，就可以用这种办法屏蔽非数字的字符输入。

#### 2.4.2 GAL 和 IAL

系统维护一个已注册图形引擎数组，保存每个图形引擎数据结构的指针。系统利用一个指针保存当前使用的图形引擎。一般而言，系统中至少有两个图形引擎，一个是“哑”图形引擎，不进行任何实际的图形输出；一个是实际要使用的图形引擎，比如 LibGGI 或者 SVGALib。每个图形引擎的数据结构定义了该图形引擎的一些信息，比如标识符、属性等，更重要的是，它实现了 GAL 所定义的各个接口，包括初始化和终止、图形上下文管理、画点处理函数、画线处理函数、矩形框填充函数、调色板函数等等。

如果在某个实际项目中所使用的图形硬件比较特殊，现有的图形引擎均不支持。这时，我们就可以安照 GAL 所定义的接口实现自己的图形引擎，并指定 MiniGUI 使用这种私有的图形引擎即可。这种软件技术实际就是面向对象多态性的具体体现。

利用 GAL 和 IAL，大大提高了 MiniGUI 的可移植性，并且使得程序的开发和调试变得更加容易。我们可以在 X Window 上开发和调试自己的 MiniGUI 程序，通过重新编译就可以让 MiniGUI 应用程序运行在特殊的嵌入式硬件平台上。

#### 2.4.3 字符集和字体支持

相对 GAL 和 IAL 而言，MiniGUI 中的字符集和字体支持更加复杂，涉及到的内容也较多。前面提到，我们通过逻辑字体这一接口，实现了文字输出和文本分析两个功能。实际这两个功能是相互关联的。在进行文本输出时，尤其在处理多字节字符集，比如 GB2312 或者 Big5 时，首先要对文本进行分析，以便判断是否是一个属于该字符集的双字节字符。

### 2.5 典型应用

1. HappyLinux 安装程序

   HappyLinux 是由联想公司开发的 Linux 简体中文发行版。安装程序基于 MiniGUI 开发。其源代码在 Red Hat Linux 6.0 安装程序的基础上移植而来，主要的移植工作由魏永明完成。在该安装程序中，我们添加了其他一些特色，以便更加适合普通用户，比如在线帮助。图 2 和图 3 是 HappyLinux 安装程序的典型屏幕。

2. VACS-III CNC 系统

   VACS 指 Virtual Axies Control System（虚拟轴机床控制系统）。VACS-III 是一个建立于 RT-Linux 上的计算机数控（CNC）系统，由清华大学精密仪器系制造工程研究所开发。它使用 MiniGUI 作为用户界面支持库。图 4 是 VACS-III 系统的界面。

3. Ehome

   Ehome 是一个采用 Web 技术进行小区网上购物、物业管理的智能家居设备。其客户端实际是一个 Web 浏览器，图 5 是该浏览器的界面框架。图 6 是正在进行网上购物的 ehome。

4. 其他
   - VCOnGUI，即 Virtual Console On MiniGUI，是 MiniGUI 上的虚拟控制台，即运行在 MiniGUI 上的 Linux 控制台仿真器。见图 7。
   - Bomb 游戏，是 Windows 扫雷游戏的克隆。见图 8。
   - Russia Block 是经典的俄罗斯方块游戏的 MiniGUI 版本。见图 9。

   - 图 10 给出了 MiniGUI 的高级字体支持功能。

### 2.6 MiniGUI 在实时嵌入式系统中的典型应用

作为 MiniGUI 在实时嵌入式系统中应用实例，我们向大家介绍两个项目。一个是蓝点北京研发中心正在开发的基于 Linux 的 PDA 软件，另外一个是清华大学正在开发基于 RT-Linux 的数控系统。前者建立在典型的嵌入式硬件平台之上，实时性要求较低；而后者建立在标准 PC 工控机上，是典型的时间关键的、高实时性系统，要求达到 2ms 的中断处理响应能力，并且要进行大量的实时浮点运算。这两个项目目前均进入后期测试阶段。MiniGUI 在这两个项目中的成功应用，说明了 MiniGUI 非常适合于嵌入式系统和实时系统。

图 11 是蓝点公司开发的基于 MiniGUI 的 PDA 软件界面；图 12 是该公司基于 MiniGUI 开发的浏览器正在浏览蓝点公司网站。

## 3 GUI 系统的重要算法

这里简要提供一些有关 GUI 系统重要算法的信息。

### 3.1 消息传递

现代 GUI 系统一般均使用消息或事件驱动的编程模型。因此，消息或事件的传递功能是 GUI 系统首先面对的一个重要功能。消息传递中需要注意到的一些问题有：

- 消息一般附带有相关的数据，这些数据对各种消息具有不同的含义，在多窗口环境，尤其是多进程环境下，消息数据的有效传递非常重要。
- 消息作为窗口间进行数据交换的一种方式，要提供多种传递机制。某些情况下，发送消息的窗口要等到这个消息处理完成之后，知道处理的结果之后才能继续执行；而有些情况下，发送消息的窗口只是简单地向接收消息的窗口通知某些事件的发生，一般发送出消息之后就返回。后一种情况类似于邮寄信件，所以通常称为邮寄消息。更有一种较为复杂的情况，就是等待一个可能长时间无法被处理的消息时，发送的消息的窗口设置一个超时值，以便能够在消息得不到及时处理的情况下能够恢复执行。
- 某些特殊消息的处理也需要注意，比如定时器。当某个定时器的频率很高，而处理这个定时器的窗口的反应速度又很慢，这时如果采用邮寄消息或者发送消息的方式，窗口的消息队列最终就会塞满。
- 最后一个问题是消息优先级的问题。一般情况下，要考虑优先处理鼠标或键盘的输入消息，其次才是 PAINT、定时器等消息。

### 3.2 图形上下文和坐标映射

#### 3.2.1 图形设备

在 MiniGUI 中，采用了在 Windows 和 X Window 中普遍采用的图形设备概念。每个图形设备定义了计算机显示屏幕上的一个矩形输出区域。

在调用图形输出函数时，均要求指定经初始化，或经建立的图形设备上下文，或设备环境（DC）。

每个图形输出均局限在图形设备指定的矩形区域内。

在多窗口系统中，各个图形设备之间的输出互相剪切,以避免图形输出之间互相影响。

#### 3.2.2 剪切域

剪切域就是在图形设备上定义的一个区域，所有在该图形设备上进行的图形输出，超过剪切域的部分，均被裁剪。只有在剪切域上的图形输出才是可见的输出。

MiniGUI 中的剪切域，定义为矩形剪切域的集合。

#### 3.2.3 映射模式

映射模式指定了特定图形输出的坐标值如何映射到图形设备的坐标值。

图形设备的坐标系原点定义为图形设备矩形区域的左上角。向右为正 X 坐标轴方向；向下为正 Y 坐标轴方向。这一坐标系称为设备坐标系。

通过 GDI 模块的映射模式操作函数，可定义自己的逻辑坐标系。逻辑坐标系可以是设备坐标系的水平或垂直反转，缩放，或者偏移。

多数 GDI 输出函数指定的是逻辑坐标系。

默认情况下，逻辑坐标系和设备坐标系是重合的。

### 3.3 窗口管理

窗口管理和剪切的关系非常密切。当窗口 A 的一部分被另外一个窗口 B 覆盖时，在窗口 A 中任何一个绘图操作都不应该影响窗口 B。为了达到这个目标，窗口 A 中的绘图就要被剪切。而在多窗口环境中，哪个窗口的哪一部分应该被剪切就由窗口的 Z 序决定。窗口的建立、销毁、显示、隐藏等操作，均要修改窗口 Z 序。MiniGUI 实际维护着两个 Z 序，一个是普通窗口形成的 Z 序，另外一个是顶层窗口（即永远处于普通窗口之上的窗口）形成的 Z 序。

### 3.4 剪切算法

当因为窗口的互相覆盖产生剪切时，首先要有一个高效的剪切域维护算法。通常，窗口的剪切域定义为互不相交的矩形集合。GUI 系统的底层图形引擎在进行输出时，要根据当前输出的剪切域进行输出的剪切操作。MiniGUI 目前采用的图形引擎尚不支持剪切域，只支持剪切矩形，从而有一些性能损失，这也是我们决定编写私有图形引擎的原因。

## 4 与 MiniGUI 联系

如果您对 MiniGUI 感兴趣，可参考如下站点获得详细信息：
http://www.minigui.org

您也可以从如下站点下载最新的 MiniGUI 完整代码：
ftp://minigui.org/pub/minigui/

如果您在利用 MiniGUI 进行开发的过程中遇到困难，请订阅我们的邮件列表。提问、解答或者发表您的高见：

- 订阅：minigui-devel-subscribe@egroups.com
- 发信：minigui-devel@egroups.com
- 解除订阅：minigui-devel-unsubscribe@egroups.com

如果您需要和 MiniGUI 项目合作，请联系：

魏永明
电话：010-68945638，13501385446
电子邮件：ymwei@minigui.org