【问题标题】:How do I determine non-rectangular drawing regions in Gtk+ 3 with cairo?如何使用 cairo 在 Gtk+ 3 中确定非矩形绘图区域?
【发布时间】:2026-01-12 10:25:02
【问题描述】:

Gtk+ 3 migration guide 展示了如何使用GdkEventExpose.region 字段为重新渲染小部件提供细粒度区域。我们已经在 Inkscape 中做了类似的事情,以避免在我们的绘图画布上渲染过多复杂的东西。

但是,指南中的示例显示了如何为旧的 Gtk+ 2 的expose_event 处理程序执行此操作。

我如何在新的 Gtk+ 3 绘图处理程序中执行等效操作,该处理程序接收“已剪辑”的 Cairo 上下文作为参数,而不是 GdkEventExpose

我想一种可能性是在“已剪裁”的 cairo 上下文中使用 cairo_copy_clip_rectangle_list 来获取构成要绘制区域的矩形列表。有没有人有使用这个的经验?这似乎是一种明智的做法?

【问题讨论】:

    标签: c gtk cairo gtk3 inkscape


    【解决方案1】:

    是的,您应该在小部件的 ::draw() 信号处理程序中获得的 cairo_t 上使用 cairo_copy_clip_rectangle_list()。请参阅此提交以获取示例: http://git.gnome.org/browse/vte/commit/?id=21a064ac8b5925108b0ab9bd6516664c8cd3e268

    【讨论】:

    • 谢谢...只是发现了这个答案!我最终使用您指出的方法实现了它:)
    【解决方案2】:

    由于我没有太多线索,我决定检查源代码。 GDK 在窗口上发出GDK_EXPOSE 事件并为此创建GdkEventExpose 实例。

    然后通过gtk_widget_send_expose() 在gtk/gtkmain.c 中处理此事件:

    http://git.gnome.org/browse/gtk+/tree/gtk/gtkwidget.c?id=eecb9607a5c0ee38eadb446545beccd0922cb0b8#n6104

    此函数将cairo_t 剪辑为GdkEventExpose.region,正如您在文档中已经了解的那样。

    然后调用_gtk_widget_draw_internal() 发出实际的绘图信号:

    http://git.gnome.org/browse/gtk+/tree/gtk/gtkwidget.c?id=eecb9607a5c0ee38eadb446545beccd0922cb0b8#n5726

    据我所知,这里没有任何内容可以让您直接访问剪辑区域。在gtk_widget_send_expose() 中,GdkEvent 作为用户数据添加到 cairo 上下文中。但是,这是不可访问的,因为所有涉及的函数和变量都是静态的。所以你必须使用cairo_copy_clip_rectangle_list()

    但是,这听起来效率很低。首先gdk_cairo_region 将区域转换为对cairo_rectangle 的多个调用,然后cairo 将其从其内部表示转换为cairo_rectangle_list_t(如果剪辑由于某种原因不是区域,则可能会失败)。如果您发现这很慢,那么将一些快捷方式直接添加到 gtk 可能是有意义的。

    【讨论】: