Skip to content

简介 ​

本文的目的 ​

AWTK 全称 Toolkit AnyWhere,是 ZLG 开发的开源 GUI 引擎,详情可前往 官网 查看。AWTK 的源码可前往 GitHub 仓库 下载。

本文是为了介绍如何把 AWTK 移植到各种嵌入式平台上而编写的,并且还将说明 AWTK 代码结构、堆栈需求以及相关功能模块等各种信息,帮助读者全方面认知 AWTK。

本文基于 AWTK 1.6.1 编写,由于不同版本 AWTK 的代码结构和资源有所不同,所以其他版本可能会存在差异。

开发环境(编译器) ​

需要支持 gnu99 版本或者以上的 C/C++ 编译器。

AWTK 主要运行流程 ​

启动 AWTK 程序时,运行流程如下图所示,其中标红的函数是在移植 AWTK 时需重点关注的函数,它们通常需要根据实际平台实现或者重载:

流程图中的 platform_disaptch_input 函数是在使用 awtk/src/main_loop/main_loop_raw.inc 文件实现设备事件分发时才需要重载,具体方法详见下文第5章。

1、main 函数

AWTK 程序启动时,默认调用 AWTK 内置的 main 函数,函数实现请参考:awtk/src/awtk_main.inc,它会依次调用下列主要函数:

(1) tk_init 函数:初始化 AWTK。

(2) assets_init 函数:加载项目资源。

(3) application_init 函数:初始化应用程序,通常由用户实现。

(4) tk_run 函数:启动 AWTK GUI 主循环(main_loop)。

(5) application_exit 函数:退出应用程序,用于释放应用程序相关资源,通常由用户实现。

如果用户想要使用系统 main 函数,可以在 awtk_main.inc 文件前定义宏 USE_GUI_MAIN,并且在系统 main 函数中调用 gui_app_start 函数启动 AWTK,该函数与 AWTK 内置 main 函数的实现类似,示例代码如下:

c
#define USE_GUI_MAIN 1   /* 使用系统 main 函数时,请定义本宏*/

#include "awtk_main.inc"
int main(int argc, char* argv[]) {
  return gui_app_start(LCD_WIDTH, LCD_HEIGHT); /* 启动 AWTK(需指定 LCD 的宽高) */
}

2、tk_init 函数

tk_init 函数主要用于初始化 AWTK,它会依次调用下列主要函数:

(1) platform_prepare 函数:初始化平台相关的准备模块,比如内存管理器和时间管理器等。

(2) main_loop_init 函数:初始化 AWTK 的主循环,其中会调用 platform_create_lcd 函数初始化 LCD,通常用户会在该函数中设置 LCD 相关的 Framebuffer。

(3) 完成其他的一些初始化任务。

3、application_init 函数

application_init 函数一般用于应用程序初始化,用户通常在该函数中执行程序初始化代码,并打开第一个 GUI 窗口。

4、tk_run 函数

tk_run 函数用于启动 AWTK 的主循环,它会让 GUI 线程不断循环调用以下函数:

(1) main_loop_dispatch_input 函数:获取输入设备的信息,其中会调用 platform_disaptch_input 函数将输入设备信息分发至主循环,用户通常会在该函数中实现输入设备的移植。

(2) event_source_manager_dispatch 函数:处理输入设备信息。

(3) main_loop_dispatch_events 函数:处理定时器和 idle 等消息源。

(4) window_manager_check_and_layout 函数:完成 UI 布局的相关操作。

(6) window_manager_paint 函数:深度遍历树状结构的 UI 树,并且把相关的 UI 控件绘制到屏幕上面,早画的控件会被晚画的控件覆盖。

在 UI 树中,窗口管理器(window_manager)是树顶,窗口管理器下可以有很多窗口,每个窗口下可以有很多控件。

5、tk_quit 函数

当程序调用 tk_quit 函数后,就会退出 AWTK 的主循环,并释放所有 AWTK 相关的资源。

6、application_exit 函数

application_exit 函数一般用于退出应用程序,该函数通常是给用户释放应用程序相关的资源。

AWTK 代码目录结构 ​

了解 AWTK 在嵌入式下的核心代码以及相关功能模块有利于项目的移植和调试,AWTK 代码目录结构详见下表:

文件/目录说明备注
src/awtk_global.c主要负责 AWTK 的初始化以及退出 AWTK 的相关操作
src/baseAWTK 底层最基础的逻辑代码
src/blendAWTK 颜色融合的算法代码
src/clip_board剪切板模块
src/dialog_highlighters对话框高亮模块
src/ext_widgets扩展控件模块
src/font_loader字体解码器的代码显示字体时使用
src/graphic_buffer显示 buffer 对象的代码
src/image_loader图片解码器的代码解码图片时使用
src/input_engines输入法引擎模块
src/input_methods输入法模块
src/layouters布局模块
src/lcdAWTK 内置的 LCD 实现代码
src/main_loop平台相关的消息循环机制代码
src/native_window平台相关的物理窗口的实现代码
src/platforms通用平台下多线程和文件系统等与平台相关的代码
src/tkcAWTK 提供的通用函数库
src/ui_loader解析 AWTK 的 UI 文件的代码
src/vgcanvas矢量画布模块
src/widget_animators控件动画模块
src/widgets基础控件的代码
src/window_animators窗口动画模块
src/window_manager窗口管理器的代码
3rd/aggeAGGE 矢量画布引擎的代码,AWTK 默认使用该引擎支持 AGGE 矢量画布时使用
3rd/gladWindows 的 OpenGL 转接层的代码支持 OpenGL 使用
3rd/gpinyin谷歌拼音输入法的代码
3rd/libunibreakUNICODE 换行算法代码
3rd/nanovgnanovg 库,AWTK 默认使用该引擎,通常与 AGGE 配合使用支持矢量画布时使用
3rd/stbstb 库,AWTK 默认使用该引擎,实现图片/字体的解码功能解码图片时使用

AWTK 的代码主要放在 awtk/src 目录以及 awtk/3rd 目录,其中 3rd 目录主要用于存放第三方的类库。

上面提到的所有文件夹和文件都可以直接添加到移植项目中,只需要配置好相关的宏就可以使用了,功能模块相关的宏定义详见本文附录二,但是有些模块需要注意:

  1. 需要确定程序是基于 OpenGL 还是基于 Framebuffer 开发,如果基于 Framebuffer 开发,需要添加 lcd_mem_xxx 的所有文件和 native_window_raw.c 文件,如果基于 OpenGL 开发,就需要添加 lcd_nanovg.c 和 native_window_fb_gl.c 文件。
  2. 如果是裸系统平台,一般会使用 main_loop_raw.inc 文件实现 AWTK 主循环,而在嵌入式 Linux 平台一般会使用 main_loop_simple.c 文件。
  3. platforms 文件夹下提供了一些常见平台的平台相关的移植模块,可以根据具体平台选择性添加。
  4. 3rd/nanovg 文件夹中分别提供了 agge、gl 和 base 的相关代码,如果支持矢量画布功能,则 base 中的代码必须全部添加到项目中,并且基于 OpenGL 开发的程序需要添加 gl 相关代码,而基于 Framebuffer 开发的程序需要添加 agge 相关代码。
  5. 在移植的过程中,添加头文件路径,awtk 的话只需要增加 awtk/src 和 awtk/src/ext_widgets 的路径即可,如果使用到 3rd 的功能模块的话,还需要添加相关的 3rd 文件夹的路径(例如:使用到 AGGE 矢量画布的话,就需要添加 awtk/3rd/agge,awtk/3rd/nanovg 和 awtk/3rd/nanovg/base 目录)。

此处主要列出了 AWTK 代码结构并提到了一些添加文件时的注意事项,如果读者想要了解更详细的构建移植工程的过程,可以参考 STM32H743 移植笔记 以及 NXP LPC1768 移植笔记,里面详细记录了 Keil 工程的构建过程。

官方移植案例 ​

AWTK 提供了部分常见平台和操作系统的移植案例,如 PC Windows、PC Linux、嵌入式Linux、嵌入式无操作系统平台等,用户可以直接使用或参考这些工程做实际开发。详情请浏览《AWTK生态共建计划》文档。