Taking a screenshot in GTK4 from pygobject, or Gsk support in pygobject

I posted an issue on gitlab (https://gitlab.gnome.org/GNOME/pygobject/-/issues/439), but was told to post it here instead.

I have an application written using pygobject with Gtk4. I have been working on a feature which allows the application to take screenshots of itself for documentation purposes.

I believe the “front door” for taking a screenshot would be:

  1. Get a Gtk.Snapshot
  2. Grab the main Gsk.RenderNode from it.
  3. Use a Gsk.Renderer to convert the RenderNode to a Gdk.Texture
  4. Save the Gdk.Texture to a file.

There are other ways, involving cairo , but every way I’ve found depends on Gsk in some way or another.

I have noticed a few issues when using these Gsk objects:

  1. Gsk.CairoRenderer.render_texture seems to expect a GObject as the first argument, but it actually takes a GskRenderNode which is not a GObject . As a result, I don’t believe it can be used.
  2. GskRenderNode.serialize causes the application to seg. fault.
  3. GskRenderNode.draw to a cairo.Context causes the application to seg. fault.

My questions are as follows: Is Gsk supported in pygobject? Will it be supported in the future? What is the best way to take a screenshot of the application?

2 Likes

There is also GtkWidgetPaintable.

GSK exposes introspection data, so: yes, it is supported by any language binding that uses introspection.

@ebassi
I believe these bindings may be broken then. Here’s some example code to explain why I think the bindings may be broken. This is all from the master branch of pygobject:

Python 3.8.6 (default, Sep 30 2020, 04:00:38) 
[GCC 10.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from gi.repository import Gsk, Graphene, Gdk
<stdin>:1: PyGIWarning: Gsk was imported without specifying a version first. Use gi.require_version('Gsk', '4.0') before import to ensure that the right version gets loaded.

# Create a Gsk.RenderNode
>>> rect = Graphene.Rect().init(0, 0, 100, 100) # Create a rectangle
>>> color = Gdk.RGBA() # Create a color
>>> color_node = Gsk.ColorNode.new(color, rect) # Create a color node

<stdin>:1: Warning: g_object_get_qdata: assertion 'G_IS_OBJECT (object)' failed
<stdin>:1: Warning: g_object_is_floating: assertion 'G_IS_OBJECT (object)' failed

** (process:226131): CRITICAL **: 11:14:09.836: pygobject_register_wrapper: assertion 'PyObject_TypeCheck(self, &PyGObject_Type)' failed

# Something is already upset, because it expects Gsk.RenderNode to be a GObject, and it isn't.
>>> renderer = Gsk.CairoRenderer.new() # Create a renderer
>>> renderer.render_texture(color_node, None)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: expected GObject but got <gi.repository.Gsk.ColorNode object at 0x7f3a7d16efa0>
# It _really_ wants Gsk.RenderNode to be a GObject

This same error happens when I grab the Gsk.RenderNode from the Gtk.Snapshot, although sometimes it seg. faults as well. In fact, in the above example, if you do a help(color_node) you will get a seg fault.

By my understanding, the bindings really expect Gsk.RenderNode to be a GObject, and it isn’t one.

@matthiasc
As for GtkWidgetPaintable, I don’t see a way to turn that into a screenshot without calling the snapshot function. It appears I really want a Gdk.Texture object, and to get one I need to run through a Gsk.Renderer with a Gdk or Gtk Snapshot.

Edit: I believe this may be related: Recent gtk 3.98, Nim example fails to compile

and to get one I need to run through a Gsk.Renderer with a Gdk or Gtk Snapshot

That is true, indeed.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.