重大新闻

对于即将到来的 GTK 4.6,我们对大量的尺寸调整基础设施进行了全面改进,以使小部件更加紧凑,并确保我们的尺寸调整基础设施真正做到其所说的。

halign/valign

当使用 GtkWidget::halignGtkWidget::valign 属性时,GTK 4.4 会查看小部件的默认大小,然后相应地放置小部件。当其中一个值设置为填充时,这会留下很多额外的空间。在 GTK 4.6 中,GTK 将测量相对于填充尺寸的另一个尺寸的大小。这使得小部件更薄,但避免了额外的空间。

A centered label with empty space in GTK 4.4
GTK 4.4 中带有空白空间的居中标签

A centered label with no extra space in GTK 4.6
GTK 4.6 中没有额外空间的居中标签

如果您喜欢旧的行为该怎么办?

如果您不在任何一个方向使用填充,则行为将与之前相同。因此,更新另一个维度使其不为默认填充,您应该可以恢复旧的行为。

GtkBox

GtkBox 已经学会了根据需要为小部件分配大小。在 GTK 4.4 中,大小总是平均分配给具有相同默认大小的子项。GTK 4.6 将查询子项的实际大小,以决定将多少额外大小分配给哪个子项。

您可以在示例中看到这一点,其中给定的框足够容纳 3、4、5 或 6 行文本。

GTK 4.4 中左对齐的框
GTK 4.6 中左对齐的框

GtkLabel

正如您在上面看到的,GtkLabel 也学会了正确地换行到任何给定的行数。这使得标签可以占用比以前少得多的宽度,因此当它们可以简单地换行时,它们不再占用空白空间。

xalign 和 halign

值得指出的是,在很多情况下,应用程序使用了 GtkWidget::halign = GTK_HALIGN_START;,而它们应该使用 GtkLabel::xalign = 0.0;。前者将小部件尽可能地向左对齐,而后者将分配空间内的文本向左对齐。因此,如果您的小部件突然看起来粘在左边缘,您可能需要考虑一下。

GtkWindow

GtkWindow 已经学会了如何使最小尺寸适应宽高比。因此,您现在可以以任何您喜欢的方式调整窗口大小,它们永远不会变得太小,但它们总是会变得尽可能小,无论您想让它们扁平而宽还是又细又高。

一个新的警告

在进行这项工作时,我们发现一些小部件不符合测量要求,并添加了一个新的警告。因此,如果您看到类似这样的内容
Gtk-CRITICAL **: 00:48:33.319: gtk_widget_measure: assertion 'for_size >= minimum opposite size' failed: 23 >= 42
这意味着您有一个小部件报告的尺寸为 -1 的最小尺寸大于它报告的用于不同尺寸的最小尺寸,这是不应该发生的。您可以使用 GTK_DEBUG=size-request 并重定向到文件以找到有问题的窗口小部件。我们还添加了代码来解决任何警告问题,但它仍然应该被修复。毕竟,如果一个小部件报告了错误的尺寸,那么它很可能做错了什么。

纹理和可绘制对象

在 GTK4 中,我们一直在尝试为图像数据找到更好的解决方案。在 GTK3 中,我们用于此目的的对象是 pixbufsCairo surfaces。但它们不再满足要求,因此现在我们有了 GdkTextureGdkPaintable

GdkTexture

GdkTextureGdkPixbuf 的替代品。为什么它更好?
首先,它更简单。API 如下所示

int gdk_texture_get_width (GdkTexture *texture);
int gdk_texture_get_height (GdkTexture *texture);

void gdk_texture_download (GdkTexture *texture,
                           guchar     *data,
                           gsize       stride);

因此它是一个 2D 像素数组,如果需要,您可以下载像素。它还保证是不可变的,因此像素永远不会改变。存在许多构造函数,可以从文件、资源、数据或 pixbuf 创建纹理。

但是纹理和 pixbuf 之间的最大区别在于它们不暴露用于存储像素的内存。事实上,在调用 gdk_texture_download() 之前,该数据甚至不需要存在。
这用于 GL 纹理。例如,GtkGLArea 小部件使用此方法来传递数据。预计 GStreamer 也将以 GL 纹理的形式传递视频。

GdkPaintable

但有时,您会遇到比不可变的一堆像素更复杂的东西。例如,您可能有一个动画 GIF 或一个可缩放的 SVG。这就是 GdkPaintable 的用武之地。
抽象地说,GdkPaintable 是一个接口,用于知道如何在任何大小下渲染自身的对象。受 CSS 图像 的启发,它们可以选择提供 GTK 小部件可用于放置它们的内在尺寸信息。
因此,GdkPaintable 接口的核心是使可绘制对象渲染自身的函数,以及提供大小信息的 3 个函数

void gdk_paintable_snapshot (GdkPaintable *paintable,
                             GdkSnapshot  *snapshot,
                             double        width,
                             double        height);

int gdk_paintable_get_intrinsic_width (GdkPaintable *paintable);
int gdk_paintable_get_intrinsic_height (GdkPaintable *paintable);
double gdk_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable);

除此之外,可绘制对象可以在其内容或大小更改时发出 “invalidate-contents” 和 “invalidate-size” 信号。

为了使这一点更加具体,让我们以可缩放的 SVG 为例:可绘制对象的实现将返回无内在大小(这些大小函数的返回值 0 可以实现这一点),并且无论何时绘制它,它都会在给定大小下精确地绘制自己。
或者以动画 GIF 为例:它会将其像素大小作为其内在大小,并将动画的当前帧缩放到给定大小。并且每当应该显示动画的下一帧时,它都会发出“invalidate-size”信号。
最后但并非最不重要的一点是,GdkTexture 实现了此接口。

我们目前正在更改 GTK3 中接受 GdkPixbuf 的所有代码,以使其现在接受 GdkPaintableGtkImage 小部件当然已经更改,拖放图标或 GtkAboutDialog 也是如此。存在允许应用程序向 GTK CSS 引擎提供可绘制对象的实验性补丁。

现在,如果您将所有这些关于 GStreamer 可能提供由 GL 图像支持的纹理,并创建可以上传到 CSS 的动画的可绘制对象的信息放在一起,您可能会 看到它将走向何方