本书针对使用Linux构建嵌入式系统的一个关键环节——图形用户界面(GUI),首先讲述了Linux编程的高级技巧,包括多进程、多线程等技术;然后通过实例重点讲述了窗口系统的基本知识与实现技巧,为读者开发自己的面向嵌入式Linux的GUI环境提供了一个参考实现范例。重点包括:LGUI多窗口的设计与实现、LGUI的消息管理、窗口与无效区的管理、设备上下文与图形设备接口的设计与实现等。
本书适用于使用Linux构建嵌入式系统的软件工程师以及希望深入了解窗口系统实现原理的读者。
第一个问题,为什么要写这本书?
现在很多面向嵌入式Linux编程的书籍理论性很强,但并不针对某一领域,对于解决某一领域的特定问题指导性较弱。
利用嵌入式Linux来构建系统,应用于便携式终端产品的居多,就软件方面而言,这类产品主要有两个环节需要把握:一是Linux内核(包括驱动)的移植;二是GUI(Graphical User Interface,即图形用户界面)层与应用层软件的设计。本书就是基于后一个环节展开的。
有人说,嵌入式Linux的最大问题是其GUI没有统一标准。但不知道这是它的缺点还是优点,是否应该由如Microsoft或Nokia这种级别的公司在这个操作系统平台上构建一个全世界都一样的用户界面,然后大家都用它的API来开发应用程序呢?这个问题暂且不讨论。嵌入式产品对于界面的需要千差万别,MP3、MP4、导航仪、电视机顶盒、手机等五花八门。如果所有的界面都从“开始”菜单开始,操作起来不一定都很方便,另外,操作方式是用手指、遥控器、鼠标还是别的什么东西是可以选择的,因此,对于嵌入式产品,作者认为个性化用户界面才是合适的,
任何一个GUI都不可能有如此好的适应性和可配置性,把一个PDA风格的GUI系统移植到机顶盒上,或把一个手机风格的GUI移植到工控机里都是没有意义的。解决问题的最好办法,就是自己构建一个小型的GUI环境,只针对具体应用,与其他系统无关。
那么,可能有人会说,量体裁衣,开发一个适合于自有项目的GUI环境固然很好,但这会不会很复杂,是不是会使项目周期拉长呢?本书可以告诉你,开发一个小型的嵌入式GUI系统其实很容易!何况网络上有如此之多的开源代码可供参考。当然,无偿复制开源软件用于商业目的是不允许的。但人们的思想是自由的,这一点谁也否认不了。
另外,现在已经开发完并开源的面向嵌入式Linux的GUI系统固然很多,而且还有一些人又在开发这个“柜”、那个“柜”的,但没有人仔细讨论到底一个嵌入式Linux GUI系统的体系结构如何能让使用者从全局把握系统,从而开发出自己的GUI环境,作者认为这是“授之以鱼”还是“授之以渔”的问题。
所以,作者写了这本书,通过嵌入式Linux特定环节的应用实例,即中间件层的GUI软件,来阐释Linux开发,同时使读者对于消息驱动的、轻量级窗口系统的实现有较为彻底的理解。
第二个问题,这本书有什么特点?
本书只针对GUI这个环节讨论技术问题,讨论其如何在嵌入式Linux上实现,并用到了Linux开发的技术细节,所以本书第一个特点是针对性强。
另外,作者不想把这本书搞成一个Linux编程的百科全书,讲清楚一个问题是最重要的,所以本书第二个特点是精炼。
本书出版之前,其早期版本作者一直放在网站上,有很多人下载并在网络上传播。这样做的目的不为赚钱,只希望对大家都有所帮助。
由于时间有限,书中可能还存在一些错误。另外,嵌入式Linux以及GUI技术的飞速发展,使得书中提到的一些概念有可能不再新颖,或者其中提到的GUI的实现方法不见得适用于任何项目。但通过本书,可以了解到作者对于一个小型窗口系统的实现思路。如果书中提到的概念或用于示例的LGUI实现代码有任何错误,欢迎读者批评指正。
本书能够顺利完成并出版,得到了很多老师与朋友的帮助,首先要感谢我的导师——北京大学人机交互与多媒体实验室的王衡副教授,她给了我大量的指导与帮助。另外,奚小君、秦艺丹、李夏、李文阳、王文翩、刘彦军、夏华、刘成功、王成、郑浩、张明、张小铃、李志华、赵处一、王成明、李自忠、秦仕军、范佳新、王小良等朋友也给予了大力支持,在此向他们表示感谢!
第1章 概论1
1.1 嵌入式系统的基本概念1
1.2 嵌入式系统的特征1
1.3 选择Linux构建嵌入式系统2
1.4 GUI在嵌入式Linux系统中的地位及要求3
1.5 用户界面概况4
1.5.1 用户界面的历史4
1.5.2 图形用户界面的特征4
1.5.3 图形用户界面系统的结构模型5
1.5.4 用户界面的发展:GUI+新人机交互技术6
1.6 Linux图形环境及桌面平台简介6
1.7 各种嵌入式Linux上的图形库与GUI系统介绍13
1.7.1 Qt/Embedded13
1.7.2 MicroWindows/NanoX14
1.7.3 MiniGUI15
1.7.4 OpenGUI16
1.7.5 GTK+17
1.8 Linux系统中的多语言问题18
1.9 一个嵌入式LinuxGUI系统开发的实例21
1.9.1 开发GUI系统主要考虑的问题22
1.9.2 后续讲解的实例24
第2章 Linux基本编程知识25
2.1 编译器的使用25
2.2 函数库的使用27
2.3 Makefile28
2.4 GDB30
2.5 建立交叉编译环境34
2.5.1 什么是交叉编译环境34
2.5.2 交叉编译的基本概念34
2.5.3 建立arm_linux交叉编译环境34
2.6 Linux下常见的图形库编程简介42
2.6.1 Qt43
2.6.2 GTK+57
第3章 Linux高级程序设计简介62
3.1 LinuxIPC介绍62
3.1.1 信号63
3.1.2 管道68
3.1.3 消息队列71
3.1.4 信号量71
3.1.5 共享内存71
3.1.6 DomainSocket73
3.2 Linux多线程编程介绍77
3.2.1 创建线程78
3.2.2 线程的退出与取消81
3.2.3 线程退出时的同步问题83
3.2.4 线程清理函数83
3.2.5 线程取消状态84
3.2.6 线程同步84
3.2.7 第三方函数库94
3.3 FrameBuffer编程简介95
第4章 基本体系结构100
4.1 基础知识100
4.1.1 嵌入式Linux的GUI到底有什么用100
4.1.2 如何定义基本体系结构101
4.1.3 为什么用客户机/服务器结构101
4.1.4 为什么要多进程102
4.1.5 为什么要多线程103
4.2 体系结构综述103
4.2.1 客户机与服务器之间的通信通道103
4.2.2 客户机需要与服务器交换什么信息105
4.2.3 服务器对客户机进程的管理107
4.3 进程创建与进程的管理109
第5章 多窗口的设计与实现110
5.1 窗口树110
5.2 窗口的Z序112
5.3 窗口的剪切与剪切域112
5.3.1 如何生成窗口剪切域112
5.3.2 窗口/控件剪切域的生成过程113
5.3.3 窗口剪切域的存储方法114
5.4 进程主窗口的初始剪切域与进程内窗体剪切域115
5.5 客户端对剪切域的管理116
5.6 窗口类的注册管理117
5.6.1 注册内容118
5.6.2 如何管理注册窗口类118
5.6.3 注册窗口类如何发挥作用121
第6章 GUI中的消息管理123
6.1 外部事件收集与分发123
6.2 消息队列125
6.3 GUI的消息125
6.3.1 LGUI的消息队列结构126
6.3.2 通知消息(NotifyMessage)128
6.3.3 邮寄消息129
6.3.4 同步消息131
6.3.5 绘制消息132
6.3.6 其他消息发送方式134
6.4 LGUI中消息堆的内存管理134
第7章 窗口输出及无效区的管理137
7.1 窗口的客户区与非客户区137
7.2 坐标系统137
7.3 输出管理机制138
7.4 无效区139
第8章 DC与GDI的设计与实现142
8.1 设备上下文DC的描述142
8.2 GDI145
8.3 预定义GDI对象的实现145
8.4 GDI对象的描述结构及创建方法146
8.5 将GDI对象选入DC中147
8.6 GDI绘图及优化147
8.7 图形库156
8.7.1 GD156
8.7.2 Cairo157
8.7.3 AGG157
8.7.4 GDI与GDI+160
第9章 控件实现163
9.1 如何实现一个控件163
9.2 不同消息的处理过程169
第10章 定制GUI对图像的支持174
10.1 GUI中图像解码的基本需求174
10.2 BMP文件175
10.3 JPEG文件176
10.4 GIF文件177
10.5 PNG文件178
第11章 字库及输入法的实现180
11.1 字符集与字符编码180
11.1.1 ASCII码180
11.1.2 DBCS双字符集180
11.1.3 Unicode181
11.2 在嵌入式GUI中如何支持字符集与编码183
11.3 在GUI中选择合适的字符集184
11.4 关于字库的问题185
11.5 FreeType189
11.6 输入法192
第12章 GUI的移植194
12.1 操作系统适配层194
12.2 输入设备的抽象198
12.3 显示设备的差异199
第13章 LGUI应用开发模式200
13.1 应用开发的模式200
13.2 开发调试方法202
13.3 应用程序简例203
第14章 GUI系统的效率问题206
后记——LGUI开发的一些体会208
参考文献210
这时候就需要一个“技术部经理”出来说话,他来协调每个人发言的时间,以便每个人表达的信息都能为别人所了解。那么这个协调与被协调的关系算不算是一个客户机/服务器结构呢?一般意义上讲应该说不算,因为所谓客户机/服务器结构应该是:客户机发出请求,服务器进行处理,并将处理的结果返回到客户机。技术部开会的时候并不是每个工程师发请求到技术部经理,由技术部经理完成处理后返回信息到工程师。在这个系统中,技术部经理只是一个协调者的角色,而不是服务者的角色,所以并不是通常意义上讲的客户机/服务器结构。但是另一方面,客户端有胖瘦之分,客户端要求服务器端处理的事情可能很复杂,也可能很简单。在很复杂的情况下,客户端很少自己做事情,大部分事情都由服务器端完成;相反,客户端可能要求服务器做很少的事情,大部分事情由自己完成。无论何种情况,它们之间有一个请求与被请求的关系、协调与被协调的关系。所以,在这里不必过多讨论这是不是严格意义上的客户机/服务器结构,姑且认为协调者的角色就是服务器,被协调者的角色就是客户机。
在多个进程同时运行的情况下,任何一个进程在对屏幕进行输出的时候,都需要了解当前屏幕上的哪些区域是町以输出的,哪些区域是不可以输出的。具体实现的时候,有两种方法:一是所有的输出都由一个服务进程来完成,由这个服务进程来确定当前对于哪些屏幕区域的输出请求是允许的,哪些是不允许的,这样就避免了多个进程对于屏幕区域的竞争;另一种方法就是其他进程只从服务进程那里请求并得到允许输出的区域,而具体的输出操作由自己完成。前一种方法面临的问题是需要在进程之间不停地传递大量数据。不同进程之间除非通过IPc,否则因为不同的进程空问不允许互相访问数据,大块的数据需要在进程之间传递,这是非常耗费资源的操作,这在嵌入式环境中更是不可取的。而后一种方法需要输出的进程只请求允许输出的屏幕区域,输出的操作由进程自己完成,相对而言.效率会有很大提高。而LGUI就是采取了这种方式。
4.1.4 为什么要多进程
从GUI的角度讲,多进程实际上是多个进程对于屏幕的输出管理。如果有很多进程在同时运行,但并没有屏幕输出的要求,就谈不上多进程的管理。
LGUI是一个支持多进程、多线程的客户机/服务器系统。为什么要多进程?单个进程不是更简单吗?
当然,并不是所有的嵌入式环境都要求多个进程同时运行,或者同时要求进行屏幕输出。例如,一个机顶盒的GUI系统,就不会这样复杂。但在一些复杂的嵌入式环境中,多进程是必需的,例如PDA等。不能要求用户在PDA中添加一项功能,就重新将系统编译一下。