# 袋鼠 GTK4 版升级报告(第一阶段)
袋鼠数据库工具(基于 GTK3 开发) 已于 2021-10-29 日通过了基于 GTK4 框架及其依赖库的编译,整个升级过程耗时约6个星期,遇到了许多典型性的问题,觉得有分享价值,就总结提炼出来形成这个报告。
# 项目信息
我们先对项目做一个大概的预览,了解一下项目的基本情况,有助于加深对后面的内容的理解:
- 开发者: 1 人
- 开发机器: ThinkPad T450 + Windows 10
- 源码文件: 364(个)
- 界面定义文件: 23(个)
- 图标文件(SVG): 58(个)
- 操作熟练: 280(个)
- 支持平台: Windows, macOS, Linux
# 开发环境
袋鼠数据库工具的开发环境是基于 MSYS2 工具套件搭建的,IDE使用 VSCode,详细情况如下:
功能特性 | 工具名称 | 采用版本 |
---|---|---|
包管理器 | pacman | 6.0.1 |
编译器 | GCC + Vala | 10.3 / 0.54.2 |
终端 | mintty | 3.5.1 |
集成开发环境 | Visual Studio Code + Vala | 1.60 |
构建器 | meson + ninja | 0.58 |
安装包工具 | NSIS | 3.0.6 |
虚拟机 | VirtualBox | 6.1 |
袋鼠数据库工具 集成了很多第三方库,第三方库及其官网、版本明细如下:
功能特性 | 第三方库 | 采用版本 |
---|---|---|
编译器 | Vala (opens new window) | 0.54.2 |
基础库 | GLib2 (opens new window) | 2.68.1 |
界面框架 | GTK3 --> GTK4 (opens new window) | 3.24.30 --> 4.4.0 |
界面适配库 | libhandy (opens new window) --> libadwaita (opens new window) | 1.4.0 --> 1.0.0 alpha2 |
编辑器 | GtkSourceView4 --> GtkSourceView5 (opens new window) | 4.8.2 --> 5.2.0 |
地图 | libshumate (opens new window) | unknown |
JSON | json-glib (opens new window) | 1.6.6 |
数据库访问 | libgda (opens new window) | 6.0.0 |
容器 | libgee (opens new window) | 0.20.3 |
SSH | libssh2 (opens new window) | 1.9.0 |
XML | libxml2 (opens new window) | 2.9.12 |
加解密 | OpenSSL (opens new window) | 1.1.1.k |
编码 | uchardet (opens new window) | 0.0.7 |
插件支持 | libpeas (opens new window) | 1.30.0 |
文件格式 | libarchive (opens new window) | 3.5.1 |
HTTP | libsoup (opens new window) | 2.72.0 |
模板 | template-glib (opens new window) | 3.34.0 |
# GTK4 升级过程摘要
为实现GTK4版编译通过,先后对代码进行了5轮重构和问题修复,每一轮都产生并修复了大量问题,面对兼容性产生的巨大的工作量,一度想放弃升级到GTK4版,短暂停留后继续攻坚,终于通过了编译:
轮次 | 重构与修复重点 | 问题数 |
---|---|---|
第一轮 | 1. 修复名字空间方面的问题 2. 修复移除的API问题 | 400+ |
第二轮 | 1. 修复容器控件GtkContainer相关问题 2. 修复唯一控件GtkBin相关问题 | 1720+ |
第三轮 | 1. 修复剪贴板相关问题 2. 修复鼠标、键盘等输入事件问题 | 1454 |
第四轮 | 1. 修复GtkBuilder相关问题 2. 修复界面定义相关问题 | 800+ |
第五轮 | 修复新增的 final 标记相关问题: GtkPaned GtkScrolledWindow GtkStack GtkOverlay GtkNotebook GtkTreeViewColumn Gtk.ComboBoxText Gtk.Assistant | 8 个控件类问题 共 1430+ 个 |
通过持续6周的努力,最终迎来了袋鼠GTK4版编译通过(10/29/2021), 欣喜若狂,立即执行编译通过的程序,有点丑有点不正常,很多功能无法正常使用,它宣示GTK4编译通过只是整个升级工作的万里长征第一步,还需许多的工作需要做。
# 关键问题分析和解决方案
现在我将把升级过程中的一些关键的、典型问题做一些列举分析并提供解决方案,或许对读者有一些帮助。
# 1. 容器控件 API
在 GTK4 中, 容器类 GtkContainer 已经被移除,新的控件体系允许每一个控件都能添加子控件,相应的API也有变化,一致性在减弱,未来也许会重新规范为一个接口类并集成到每一个控件中;GTK4版提供的容器 API 主要有: prepend/append/insert/remove:
GTK3 API | GTK4 API | 升级推荐 |
---|---|---|
add pack_start | prepend append | append |
pack_end | insert_child_after | append |
reorder_child | reorder_child_after | reorder_child_after |
foreach/get_children | get_first_child get_next_sibling get_prev_sibling get_last_child |
# 2. 唯一子控件 API
在 GTK4 中, , 唯一子控件类GtkBin 已经被移除, 新的控件体系允许每一个控件都能添加子控件, 部分控件类提供了 child 属性来直接引用或设置它的唯一子控件,或者是第一个子控件;
# 3. 剪贴板 API
在 GTK3 中, 我们可以使用下面的代码获取或者检测剪贴板中的图片:
Gtk.Clipboard clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD);
Pixbuf? pixbuf = clipboard.wait_for_image();
GTK4 中的完成同样功能的代码是这样子的:
Pixbuf? pixbuf = null;
Value value = GLib.Value(typeof(Pixbuf));
Gdk.Clipboard clipboard = this.get_clipboard();
if (clipboard.content.get_value(ref value)) {
pixbuf = (Pixbuf)value.get_boxed();
}
# 4. 用户输入(鼠标点击和键盘输入)
简单粗暴的直接分享一些关于用户输入的参考代码,用于快速更新 GTK3 中的用户输入事件代码:
treeview.key_press_event.connect(key_press_handler);
treeview.key_release_event.connect(key_release_handler);
treeview.button_press_event.connect(button_press_handler);
treeview.button_release_event.connect(button_release_handler);
treeview.motion_notify_event.connect(mouse_move_handler);
treeview.enter_notify_event.connect(mouse_enter_handler);
treeview.leave_notify_event.connect(mouse_leave_handler);
treeview.scroll_event.connect(scroll_event_handler);
treeview.focus_in_event.connect(focus_enter_event_handler);
treeview.focus_out_event.connect(focus_leave_event_handler);
var key_input_event = new Gtk.EventControllerKey();
key_input_event.key_pressed.connect(key_press_handler);
key_input_event.key_released.connect(key_release_handler);
treeview.add_controller(key_input_event);
var mouse_button_event = new Gtk.GestureClick();
mouse_button_event.pressed.connect(button_press_handler);
mouse_button_event.released.connect(button_release_handler);
treeview.add_controller(mouse_button_event);
var mouse_motion_event = new Gtk.EventControllerMotion();
mouse_motion_event.motion.connect(mouse_move_handler);
mouse_motion_event.enter.connect(mouse_enter_handler);
mouse_motion_event.leave.connect(mouse_leave_handler);
treeview.add_controller(mouse_motion_event);
var view_scroll_event = new Gtk.EventControllerScroll();
view_scroll_event.scroll.connect(scroll_event_handler);
treeview.add_controller(view_scroll_event);
var view_focus_event = new Gtk.EventControllerFocus();
view_focus_event.enter.connect(focus_enter_event_handler);
view_focus_event.leave.connect(focus_leave_event_handler);
treeview.add_controller(view_focus_event);
# 5. GtkBuilder 和 界面定义文件
下面的命令行可以直接升级更新GTK3定义的界面定义文件(*.ui):
gtk-builder-tool simplify --3to4 --replace <filename.ui>
如果只想查看升级更新后的界面定义文件内容而不更新文件,可以去掉参数 --replace
,如下所示:
gtk-builder-tool simplify --3to4 <filename.ui>
← 博客文章 苹果系统 GTK 应用打包新思路 →