GTK 4 中的媒体

显示动态图像变得越来越重要。GTK 4 将使 GTK 应用程序更容易显示动画;无论是程序化动画、webm 文件还是直播流。

一切皆可绘制

在查看动画之前,值得花一些时间了解 GTK 用于可绘制内容的底层抽象。在 GTK 2 和 3 中,主要是 GdkPixbuf:您加载一个文件,然后获得一个像素数据块(或多或少采用单一格式)。如果你想对其进行动画处理,可以使用 GdkPixbufAnimation,但可以公平地说它不是一个非常成功的 API。

GTK 4 引入了一个名为 GdkPaintable 的新 API,其灵感来自 CSS Houdini 项目。它非常灵活——任何可以合理绘制的东西都可以是一个 GdkPaintable。内容可以是可调整大小的(如 svg),或者随时间变化(如 webm)。

通常显示图像内容的 Widget,例如 GtkImage 或 GtkPicture 知道如何使用可绘制对象。过去以某种形式生成像素数据的许多东西现在可以表示为可绘制对象:纹理图标,甚至是 Widget

如果您有更专业的需求,可以使用 gtk_snapshot_to_paintable() 将 GtkSnapshot 中捕获的任何内容转换为可绘制对象。如果您创建了一个想要绘制可绘制对象的自定义 Widget,这非常简单。只需调用 gdk_paintable_snapshot()

开始动画

正如我之前所说,可绘制对象可以随时间更改其内容。它们只需要发出 ::contents-changed 信号,GtkPicture 等 Widget 就会执行正确的操作并更新其显示。

那么,我们从哪里获得一个可以更改其内容的 GdkPaintable 呢?我们可以使用 GTK 4 的内置 GtkMediaFile API 从文件中加载它。这是一个高层 API,类似于 GstPlayer:您输入一个 URI,然后得到一个具有 play() 函数和 pause() 函数的对象,并且可以用作可绘制对象。

GTK 附带了 GtkMediaFile 的两个实现,一个使用 gstreamer,另一个使用 ffmpeg。由于我们不想让其中任何一个成为 GTK 的硬依赖项,它们都是可加载的模块。

您可以打开 GTK 检查器来找出正在使用的是哪个

保持控制

GtkMediaFile API 是 gtk4-widget-factory 在其首页上演示动画 GTK 徽标的方式

正如您所见,它不仅仅是一个移动的图片,还有媒体控件——您可以通过使用 GtkVideo Widget 免费获得这些控件。

超越基础

从文件中加载动画可能不是那么令人兴奋,所以这里有另一个 例子,它更进一步。这是一个周末小项目,它结合了 GtkVideo、libportalpipewire,演示如何在 GTK 应用程序中显示视频流。

坏消息是我们还没有为支持胶水代码找到永久的家(GstSink、GdkPaintable 和 GtkMediaStream)。它不适合 GTK,因为如上所述,我们不想依赖 gstreamer,它也不适合 gstreamer,因为 GTK 4 尚未发布。我们肯定会尽快解决这个问题,因为将 gstreamer 管道转换为几行代码的可绘制对象非常方便。

好消息是,代码的核心只有几行

fd = xdp_portal_open_pipewire_remote_for_camera (portal);
stream = gtk_gst_media_stream_new_for_pipewire_fd (fd, NULL);
gtk_video_set_media_stream (video, stream);

 

GTK 4 中的自定义 Widget – 操作

(这是关于 GTK 4 中自定义 Widget 系列的第五部分。第 1 部分第 2 部分第 3 部分第 4 部分)。

激活所有东西

GTK 中的许多东西都可以被激活:按钮、复选框、开关、菜单项等等。通常,可以通过多种方式实现相同的任务,例如将选择复制到剪贴板可以通过 Control-C 快捷键和上下文菜单中的项目来实现。

在 GTK 内部,有很多种方式可以进行:可能会发出一个信号(::activate,或 ::mnemonic-activate,或一个按键绑定信号),可能会调用一个回调,或者可能会激活一个 GAction。这些在 GTK 4 中都不是全新的,但我们正在朝着使用 GActions 作为连接操作的主要机制的方向发展。

操作

操作在 GTK 应用程序中可以以各种形式出现。

首先,有全局应用程序操作,添加到 GtkApplication 或 GtkApplicationWindow(两者都实现了 GActionGroup 接口)。这是操作在 GTK 3 中首次出现的地方,主要目的是在会话总线上导出它们以用于应用程序菜单。

我们还允许通过调用 gtk_widget_insert_action_group() 将操作与 Widget 关联。以这种方式添加的操作仅在操作源于 Widget 层次结构下方时才会被考虑激活。

在 GTK 4 中创建操作的新方法是通过 gtk_widget_class_install_action() 在 class_init 函数中声明操作,类似于使用 g_object_class_install_property() 声明属性的方式。以这种方式创建的操作对 Widget 的每个实例都可用。

以下是 GtkColorSwatch 中的一个示例

gtk_widget_class_install_action (widget_class,
                                 "color.customize", "(dddd)",
                                 customize_color);

当 color.customize 操作被激活时,将调用 customize_color 函数。如您所见,操作可以声明它们期望参数。这是使用 GVariant 语法;您需要提供四个双精度值。

一个方便的简写允许您创建一个有状态的操作来设置您的 Widget 类的属性

gtk_widget_class_install_property_action (widget_class,
                                         "misc.toggle-visibility",
                                         "visibility");

这将声明一个名为 misc.toggle-visibility 的操作,该操作切换布尔值 visibility 属性的值。

可操作对象和菜单

声明操作只是第一步,您还需要以某种形式将操作连接到 UI。对于实现 actionable 接口的按钮或开关等 Widget,这就像设置 action-name 属性一样简单

gtk_actionable_set_action_name (GTK_ACTIONABLE (button),
                                "misc.toggle-visibility");

当然,您也可以在 ui 文件中执行此操作。

如果您想从菜单中激活操作,您可能会使用从 XML 构建的菜单模型,如下所示

<menu id="menu">
  <section>
    <item>
      <attribute name="label">Show text</attribute>
      <attribute name="action">misc.toggle-visibility</attribute>
    </item>
  </section>
</menu>

在 GTK 3 中,您将连接到 ::populate-popup 信号以将项目添加到标签或条目的上下文菜单中。在 GTK 4 中,这是通过向 Widget 添加菜单模型来完成的

gtk_entry_set_extra_menu (entry, menu_model);

深入了解

要了解有关 GTK 4 中操作的更多信息,您可以阅读 GTK 文档中的 操作概述