Shall applications call virtual function GtkWidgetClass:snapshot()?

When a virtual function is meant to be called from apps, there is sometimes
(usually?) a non-virtual function that calls the virtual function.
Examples: gtk_entry_buffer_get_length(), gtk_entry_buffer_get_text(),
gtk_expression_evaluate(), gtk_im_context_set_client_widget(),
gtk_im_context_get_preedit_string(), gtk_layout_manager_measure(),
gtk_media_stream_play(), gtk_shortcut_action_print(), gtk_sorter_compare().

There is no public function that just calls GtkWidgetClass:snapshot().
There is a public gtk_widget_snapshot_child() and a private gtk_widget_snapshot().
Is the recommended way of getting a GtkSnapshot or a GdkPaintable of a widget to call
the virtual function, or is there another way?

I ask because of issue gtkmm#162.
A comment in the issue notes that WidgetPaintable is not always a good alternative.

1 Like

Hi,

The normal way is to call Gtk.Widget.queue_draw , which will schedule an asynchronous call to snapshot() at the appropriate time during the rendering pipeline.

I’m not aware of usecases where it could make sense to call snapshot() directly, especially since you need a properly initialized GtkSnapshot object as parameter.

gtk_widget_queue_draw(), as its name suggests, redraws the widget.
The author of the gtkmm#162 issue wants to get a GdkPaintable with the present
contents of the widget. The snapshot is just an intermediate object.
Once you’ve got a snapshot, you can get a paintable with gtk_snapshot_to_paintable().
The issue author does not like the paintable that gtk_widget_paintable_new() returns.

What the author of the issue is doing is quite broken: you’re never supposed to call the virtual function of a widget directly. The only time you’re supposed to do that is when subclassing a widget and chaining up, e.g.

// Render the contents of the widget into a node
if (some_condition) {
  GtkSnapshot *inner_snapshot = gtk_snapshot_new ();

  GTK_WIDGET_CLASS (my_widget_parent_class)->snapshot (self, inner_snapshot);

  GskRender Node *node = gtk_snapshot_to_node (inner_snapshot);

  // do something with node, like apply a mask

  gtk_snapshot_append_node (render_snapshot, node);

  gsk_render_node_unref (node);
}

You should not be calling the snapshot() virtual function on an unsuspecting GtkWidget.

You should not be calling the snapshot() virtual function on an unsuspecting GtkWidget.

Thanks for the clarification. That’s what I suspected. Then I won’t make the kind
of Gtk::Widget method that the author of the issue wants in gtkmm.

Is there anything else you can do if (like the author of the issue) you don’t like
the GdkPaintable that gtk_widget_paintable_new() creates?

Not really, no. The reason why gtk_widget_snapshot() is private is that only the toolkit knows when to snapshot a widget; that’s also why GtkWidgetPaintable exists in the first place: the logic (including the invariants) of when a widget should be drawn is known only by the toolkit.

Your options are:

  • creating a custom widget that contains the widget you want to draw, and then snapshot the custom widget to a render node during the snapshot process
  • use a widget paintable

What the original author of the issue wants to do (kind of) worked in GTK3 because GTK was using immediate mode rendering; GTK4 moved to a deferred rendering pipeline, which means the rendering operations are serialised and compared between frames.

1 Like

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