MiniGUI 体系结构之二 多窗口管理和控件及控件类
读者很容易看出,在只有一个窗口的情况下,形成桌面剪切域的矩形最多只能有四个。
这样,我们可以将某个窗口全局剪切域归纳为原有剪切域中排除(Exclude)某个矩形而生成的:
清单 1 中的代码是在显示一个新窗口时,MiniGUI 处理被该窗口所覆盖的其他所有窗口的代码。这段代码调用了剪切域维护接口中的 SubtractClipRect 函数计算新的剪切域。
清单 1 显示新窗口时计算被新窗口覆盖的窗口的全局剪切域 |
但是,在某些情况下,我们必须重新计算所有窗口的全局剪切域,比如在移动某个窗口时。
清单 2 从剪切矩形私有堆中分配和释放剪切矩形 |
- 一种是对已经建立的控件实例进行子类化,子类化的结果是只影响这一个控件实例;
- 一种是对某个控件类进行子类化,将影响其后创建的所有该控件类的控件实例;
- 最后一种是在某个控件类的基础上新注册一个子类化的控件类,不会影响原有控件类。在 Windows 中,这种技术又称为超类化。
在 MiniGUI 中,控件的子类化实际是通过替换已有的窗口过程实现的。清单 4 中的代码就通过控件类创建了两个子类化的编辑框,一个只能输入数字,而另一个只能输入字母:
清单 4 控件的子类化 |
#define MAXLEN_CLASSNAME 15 |
在控件类的数据结构中包含了鼠标、光标、控件类的回调函数地址等等信息。在创建属于该控件类的控件时,这些信息会复制到控件数据结构中。这样,新的控件实例就继承了这种控件类的表象和行为。
该哈希表的哈希函数实际非常简单,它的返回值就是控件类名称首字母的英文字母表顺序值:
static int HashFunc (char* szClassname) |
控件结构相对复杂一些。其中包含了控件在父窗口中的位置信息、控件风格、扩展风格、控件鼠标、图标、控件回调函数地址等等:
typedef struct _CONTROL |
很显然,只要将控件的回调函数地址进行替换,就可以非常方便地对控件进行子类化操作。值得一提的是,主窗口的结构定义和控件数据结构定义基本上是相同的,只是在某些成员上有一些小小的差别。
为了实现 desktop 和 IME 窗口之间的交互,MiniGUI 为输入法窗口定义了如下消息,当活动窗口发生变化时,MiniGUI 会向 IME 窗口发送这些消息:
- 注册成为当前输入法;
- 处理 MSG_IME_SETTARGE 消息,并记录当前活动目标窗口;
- 翻译按键并将翻译后的结构通过 MSG_CHAR 消息发送到当前活动的目标窗口;
- 处理 MSG_IME_OPEN 和 MSG_IME_CLOSE 消息,在切换到需要输入法的活动窗口时自动显示输入法窗口。
为了解决 MiniGUI 版本因为线程而引入的一些问题,同时也为了让 MiniGUI更加适合于嵌入式系统,我们决定开发一个 MiniGUI Lite 版本。这个版本的开发目的是:
1. 保持与原先 MiniGUI 版本在源代码级 98% 以上的兼容。 2. 不再使用 LinuxThreads。 3. 可以同时运行多个基于 MiniGUI Lite 的应用程序,即多个进程,并且提供前后台进程的切换。有了上述认识,我们对 MiniGUI-Lite 版本进行了如下简化设计:
1. 每个进程维护自己的主窗口 Z 序,同一进程创建的主窗口之间互相剪切。也就是说,除这个进程只有一个线程,只有一个消息循环之外,它与原有的 MiniGUI 版本之间没有任何区别。每个进程在进行屏幕绘制时,不需要考虑其他进程。 2. 建立一个简单的客户/服务器体系,但确保最小化进程间的数据复制功能。因此,在服务器和客户之间传递的数据仅限于输入设备的输入数据,以及客户和服务器之 间的某些请求和响应数据。 3. 有一个服务器进程(mginit),它负责初始化一些输入设备,并且通过 UNIX Domain 套接字将输入设备的消息发送到前台的 MiniGUI Lite 客户进程。 4. 服务器和客户被分别限定在屏幕的某两个不相交矩形内进行绘制,同一时刻,只能有一个客户及服务器进行屏幕绘制。其他客户可继续运行,但屏幕输入被屏蔽。服 务器可以利用 API 接口将某个客户切换到前台。同时,服务器和客户之间采用信号和 System V 信号量进行同步。 5. 服务器还采用 System V IPC 机制提供一些资源的共享,包括位图、图标、鼠标、字体等等,以便减少实际内存的消耗。- MiniGUI 资源
- MiniGUI 邮件列表