暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

袋鼠 GTK4 版升级报告(第一阶段)

1291

袋鼠数据库工具(基于 GTK3 开发) 已于 2021-10-29 日通过了基于 GTK4 框架及其依赖库的编译,整个升级过程耗时约6个星期,遇到了许多典型性的问题,觉得有分享价值,就总结提炼出来形成这个报告。


项目信息

我们先对项目做一个大概的预览,了解一下项目的基本情况,有助于加深对后面的内容的理解:

  • 开发者: 1 (人)

  • 开发机器: ThinkPad T450 + Windows 10

  • 源码文件: 364(个)

  • 界面定义文件: 23(个)

  • 图标文件(SVG): 58(个)

  • 操作熟练: 280(个)

  • 支持平台: Windows, macOS, Linux


开发环境

袋鼠数据库工具的开发环境是基于 MSYS2 工具套件搭建的,IDE使用 VSCode,详细情况如下:

功能特性工具名称采用版本
包管理器pacman6.0.1
编译器GCC + Vala10.3 0.54.2
终端mintty3.5.1
集成开发环境Visual Studio Code + Vala1.60
构建器meson + ninja0.58
安装包工具NSIS3.0.6
虚拟机VirtualBox6.1


袋鼠数据库工具 集成了很多第三方库,第三方库及其官网、版本明细如下:

功能特性第三方库采用版本
编译器Vala0.54.2
基础库GLib22.68.1
界面框架GTK3 --> GTK43.24.30 --> 4.4.0
界面适配库libhandy --> libadwaita1.4.0  --> 1.0.0 alpha2
编辑器GtkSourceView4 --> GtkSourceView54.8.2 --> 5.2.0
地图libshumateunknown
JSONjson-glib1.6.6
数据库访问libgda6.0.0
容器libgee0.20.3
SSHlibssh21.9.0
XMLlibxml22.9.12
加解密OpenSSL1.1.1.k
编码uchardet0.0.7
插件支持libpeas1.30.0
文件格式libarchive3.5.1
HTTPlibsoup2.72.0
模板template-glib3.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 APIGTK4 API升级推荐
add
pack_start
prepend
append
append
pack_endinsert_child_afterappend
reorder_childreorder_child_afterreorder_child_after
foreach/get_childrenget_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);

        GTK4 中的完成同样功能的代码是这样子的:

          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>


              文章转载自袋鼠数据库工具,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

              评论