minigui的GAL和IAL引擎各是什么东西?
GAL图形抽象层
IAL输入抽象层
为了把底层图形设备和上层图形接口分离开来,提高
MiniGUI 图形系统的可移植性,
MiniGUI
中引入了图形抽象层(Graphics Abstract Layer,GAL)的概念。图形抽象层定义
了一组不依赖于任何特殊硬件的抽象接口,
所有顶层的图形操作都建立在这些抽象接口之上。
而用于实现这一抽象接口的底层代码称为“图形引擎”
,类似操作系统中的驱动程序。利用
GAL,MiniGUI
可以在许多已有的图形函数库上运行,比如 SVGALib 和 LibGGI。并且可以
非常方便地将
MiniGUI 移植到其他 POSIX 系统上,只需要根据我们的抽象层接口实现新的
图形引擎即可。比如,在基于
Linux 的系统上,我们可以在 Linux FrameBuffer 驱动程序的
基础上建立通用的
MiniGUI 图形引擎。实际上,包含在 MiniGUI 1.0.00 版本中的私有图形引
擎(Native
Engine)就是建立在 FrameBuffer 之上的图形引擎。一般而言,基于 Linux 的嵌
入式系统均会提供
FrameBuffer 支持,这样私有图形引擎可以运行在一般的 PC 上,也可以
运行在特定的嵌入式系统上。
本章将介绍
MiniGUI 的 IAL 接口,并重点介绍如何开发针对特定嵌入式系统的输入引擎。尽管这个主题已经超出了一般的
MiniGUI 编程范围,但出于该主题的重要性考虑,我们在本篇最后一章中包含了该内容。
而输入设备的处理却没有统一的接口。在
PC 上,我们通常使用键盘和鼠标,而在嵌入式系统上,可能只有触摸屏和为数不多的几个键。在这种情况下,提供一个抽象的输入层,就显得格外重要
MiniGUI
的 IAL 接口
typedef struct tagINPUT
{
char* id;
// Initialization and termination
BOOL (*init_input) (struct tagINPUT
*input, const char* mdev, const char* mtype);
void (*term_input) (void);
// Mouse operations
int (*update_mouse) (void);
int (*get_mouse_xy) (int* x, int* y);
void (*set_mouse_xy) (int x, int y);
int (*get_mouse_button) (void);
void (*set_mouse_range) (int minx, int
miny,int maxx,int maxy);
// Keyboard operations
int (*update_keyboard) (void);
char* (*get_keyboard_state) (void);
void (*suspend_keyboard) (void);
void (*resume_keyboard) (void);
void (*set_leds) (unsigned int leds);
// Event
#ifdef _LITE_VERSION
int (*wait_event) (int which, int maxfd,
fd_set *in, fd_set *out, fd_set *except,
struct timeval *timeout);
#else
int (*wait_event) (int which, fd_set
*in, fd_set *out, fd_set *except,
struct timeval *timeout);
#endif
char mdev [MAX_PATH + 1];
} INPUT;
extern INPUT* cur_input;
在 src/ial/ial.c 中,定义了 MiniGUI 支持的所有输入引擎信息:
#define
LEN_ENGINE_NAME 16
#define
LEN_MTYPE_NAME 16
static
INPUT inputs [] =
{
#ifdef
_SVGALIB
{"SVGALib", InitSVGALibInput,
TermSVGALibInput},
#endif
#ifdef
_LIBGGI
{"LibGGI", InitLibGGIInput,
TermLibGGIInput},
#endif
#ifdef
_EP7211_IAL
{"EP7211", InitEP7211Input,
TermEP7211Input},
#endif
#ifdef
_ADS_IAL
{"ADS", InitADSInput,
TermADSInput},
#endif
#ifdef
_IPAQ_IAL
{"iPAQ", InitIPAQInput,
TermIPAQInput},
#endif
#ifdef
_VR4181_IAL
{"VR4181", InitVR4181Input,
TermVR4181Input},
#endif
#ifdef
_HELIO_IAL
{"Helio", InitHelioInput,
TermHelioInput},
#endif
#ifdef
_NATIVE_IAL_ENGINE
{"Console", InitNativeInput,
TermNativeInput},
#endif
#ifdef
_TFSTB_IAL
{"TF-STB", InitTFSTBInput,
TermTFSTBInput},
#endif
#ifdef
_T800_IAL
{"T800", InitT800Input,
TermT800Input},
#endif
#ifdef
_DUMMY_IAL
{"Dummy", InitDummyInput,
TermDummyInput},
#endif
#ifdef
_QVFB_IAL
{"QVFB", InitQVFBInput,
TermQVFBInput},
#endif
};
INPUT*
cur_input;
- InitIPAQInput 函数就是我们在
src/ial/ial.c 中所定义的 iPAQ 输入引擎的初始化函数。该函数打开了两个设备:/dev/
h3600_ts 和 /dev/
h3600_key。前者是触摸屏的设备文件, 后者是按键的设备文件。 类似 PC 上的 /dev/psaux 设备和 /dev/tty
设备。在成功打开这两个设备文件之后,该函数设置了 INPUT 结构的其它一些成
员。注意,其中一些成员被赋值为
NULL。
- mouse_update 函数始终返回 1,表明更新鼠标状态成功。
- mouse_getxy 函数返回由其它函数准备好的鼠标位置数据,并做了适当的边界检查
-
mouse_getbutton 函数返回了触摸屏状态,即用户是否触摸了屏幕,相当于是否按
下了左键。
- keyboard_update 函数根据其它函数准备好的键盘信息,适当填充了 state 数组。
-
keyboard_state 函数直接返回了 state 数组的地址。
- wait_event 函数是输入引擎的核心函数。这个函数首先将先前打开的两个设备的文件描述符与传入的 in 文件描述符集合并在了一起,然后调用了 select 系统调用。当 select 系统调用返回大于 0 的值时,该函数检查在两个文件描述符上是否有可
读的数据等待读取,如果是,则分别从两个文件描述符中读取触摸屏和按键数据
- 在minigui的配置文件中使用新的类型,在INPUT数组添加新的IAL。
minigui桌面程序设计:
- 图层的概念。托管窗口的概念?
根窗口就是所有窗口的祖先。
CreateInfo.hHosting:该域表示的是将要建立的主窗口使用哪个主窗口的消息队列。
使用其他主窗口消息队列的主窗口,我们称为“被托管”的主窗口。在
MiniGUI 中,
托管的概念非常重要,一般要遵循如下规则:
MiniGUI-Threads 中每个线程创建的第一个主窗口,其托管窗口必须是桌面,即
HWND_DESKTOP,该线程的其他窗口,必须由属于同一线程的已有主窗口作为
托管窗口。系统在托管窗口为
HWND_DESKTOP 时创建新的消息队列,而在指
定非桌面的窗口作为托管窗口时,使用该托管窗口的消息队列,也就是说,同一
线程中的所有主窗口应该使用同一个消息队列。
MiniGUI-Processes 中的所有主窗口也应该以类似的规则指定托管窗口,将所有
主窗口看成是属于同一线程就可以了。
- 设备上下文的概念?
应用程序一般在一个图形上下文(graphics
context)上调用图形系统提供的绘制原语进行绘制。上下文是一个记录了绘制原语所使用的图形属性的对象。这些属性通常包括:
设备上下文,应该是一种对于图形操作的封装和抽象,通过设备上下文进行图像方面的操作。
- Automake,autoconf简单使用
主要文件:
Configure.in
Make .am
源代码文件
操作:
Aclocal : | Aclocal.m4(解释configure.in) |
Autoconf: | 根据configure.in生成configure |
autoMake : | 根据make.am生成Makefile.in文件 |
Configure | 根据make.in文件生成makefile文件 |
Make | 编译源代码 |
源文档 <http://tech.sina.com.cn/s/2004-10-19/1115443045.shtml>
针对上面提到的各个命令,我们再做些详细的介绍。
1、
autoscan
autoscan是用来扫描源代码目录生成configure.scan文件的。autoscan可以用目录名做为参数,但如果你不使用参数的话,那么
autoscan将认为使用的是当前目录。autoscan将扫描你所指定目录中的源文件,并创建configure.scan文件。
2、
configure.scan
configure.scan包含了
系统配置的基本选项,里面都是一些宏定义。我们需要将它改名为configure.in
3、
aclocal
aclocal是一个perl
脚本程序。aclocal根据configure.in文件的内容,自动生成aclocal.m4文件。aclocal的定义是:“aclocal - create
aclocal.m4 by scanning configure.ac”。
4、
autoconf
autoconf是用来产生configure文件的。configure是一个脚本,它能设置源程序来适应各种不同的操作系统平台,并且根据不同的系统来产生合适的Makefile,从而可以使你的源代码能在不同的操作系统平台上被编译出来。
configure.in文件的内容是一些宏,这些宏经过autoconf
处理后会变成检查系统特性、环境变量、软件必须的参数的shell脚本。configure.in文件中的宏的顺序并没有规定,但是你必须在所有宏的最前
面和最后面分别加上AC_INIT宏和AC_OUTPUT宏。
在configure.ini中:
#号表示注释,这个宏后面的内容将被忽略。
AC_INIT(FILE)
这个宏用来检查源代码所在的路径。
AM_INIT_AUTOMAKE(PACKAGE,
VERSION)
这个宏是必须的,它描述了我们将要生成的软件包的名字及其版本号:PACKAGE是软件包的名字,VERSION是版本号。当你使用make
dist命令时,它会给你生成一个类似helloworld-1.0.tar.gz的软件发行包,其中就有对应的软件包的名字和版本号。
AC_PROG_CC
这个宏将检查系统所用的C编译器。
AC_OUTPUT(FILE)
这个宏是我们要输出的Makefile的名字。
我们在使用automake时,实际上还需要用到其他的一些宏,但我们可以用aclocal
来帮我们自动产生。执行aclocal后我们会得到aclocal.m4文件。
产生了configure.in和aclocal.m4
两个宏文件后,我们就可以使用autoconf来产生configure文件了。
5、
Makefile.am
Makefile.am是用来生成Makefile.in的,需要你手工书写。Makefile.am中定义了一些内容:
AUTOMAKE_OPTIONS
这个是automake的选项。在执行automake时,它会检查目录下是否存在标准GNU软件包中应具备的各种文件,例如AUTHORS、ChangeLog、NEWS等文件。我们将其设置成foreign时,automake会改用一般软件包的标准来检查。
bin_PROGRAMS
这个是指定我们所要产生的可执行文件的文件名。如果你要产生多个可执行文件,那么在各个名字间用空格隔开。
helloworld_SOURCES
这个是指定产生“helloworld”时所需要的源代码。如果它用到了多个源文件,那么请使用空格符号将它们隔开。比如需要
helloworld.h,helloworld.c那么请写成helloworld_SOURCES= helloworld.h helloworld.c。
如果你在bin_PROGRAMS定义了多个可执行文件,则对应每个可执行文件都要定义相对的filename_SOURCES。
6、
automake
我们使用automake
--add-missing来产生Makefile.in。
选项--add-missing的定义是“add
missing standard files to package”,它会让automake加入一个标准的软件包所必须的一些文件。
我们用automake产生出来的Makefile.in文件是符合GNU
Makefile惯例的,接下来我们只要执行configure这个shell 脚本就可以产生合适的 Makefile 文件了。
7、
Makefile
在符合GNU
Makefiel惯例的Makefile中,包含了一些基本的预先定义的操作:
make
根据Makefile编译源代码,连接,生成目标文件,可执行文件。
make
clean
清除上次的make命令所产生的object文件(后缀为“.o”的文件)及可执行文件。
make
install
将编译成功的可执行文件安装到系统目录中,一般为/usr/local/bin目录。
make
dist
产生发布软件包文件(即distribution
package)。这个命令将会将可执行文件及相关文件打包成一个tar.gz压缩的文件用来作为发布软件的软件包。
它会在当前目录下生成一个名字类似“PACKAGE-VERSION.tar.gz”的文件。PACKAGE和VERSION,是我们在configure.in中定义的AM_INIT_AUTOMAKE(PACKAGE,
VERSION)。
make
distcheck
生成发布软件包并对其进行测试检查,以确定发布包的正确性。这个操作将自动把压缩包文件解开,然后执行configure命令,并且执行make,来确认编译不出现错误,最后提示你软件包已经准备好,可以发布了。
===============================================
helloworld-1.0.tar.gz
is ready for distribution
===============================================
make
distclean
类似make
clean,但同时也将configure生成的文件全部删除掉,包括Makefile。
结束语
通过上面的介绍,你应该可以很容易地生成一个你自己的符合GNU惯例的Makefile文件及对应的项目文件。
如果你想写出更复杂的且符合惯例的Makefile,你可以参考一些开放代码的项目中的configure.in和Makefile.am文件,比如:嵌入式数据库sqlite,单元测试cppunit。