Screenshot test helper has issues with synchronizing rendering (assertion in _cairo_surface_has_mime_data)

I have a helper function


to take screenshots of GtkWindows during unit-tests (that run on xvfb). I used those to e.g update the docs for a release. This has been working fine for years, but is failing since a while with:
./../../../src/cairo-surface.c:1734: cairo_surface_mark_dirty_rectangle: Assertion! _cairo_surface_has_mime
_data (surface)’ failed`.

Here is a backtrace:

2  0x00007ffff041177f in __assert_fail_base (fmt=0x7ffff0573bc0 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", assertion=0x7ffff196f2c0 "! _cairo_surface_has_mime_data (surface)", file=0x7ffff196f130 "../../../../src/cairo-surface.c", line=1734, function=0x7ffff196f620 "cairo_surface_mark_dirty_rectangle") at assert.c:92
#3  0x00007ffff041f542 in __GI___assert_fail (assertion=0x7ffff196f2c0 "! _cairo_surface_has_mime_data (surface)", file=0x7ffff196f130 "../../../../src/cairo-surface.c", line=1734, function=0x7ffff196f620 "cairo_surface_mark_dirty_rectangle") at assert.c:101
#4  0x00007ffff190061f in cairo_surface_mark_dirty_rectangle () at /usr/lib/x86_64-linux-gnu/libcairo.so.2
#5  0x00007ffff1901645 in cairo_surface_mark_dirty () at /usr/lib/x86_64-linux-gnu/libcairo.so.2
#6  0x00007ffff1e7459c in gdk_pixbuf_get_from_window () at /usr/lib/x86_64-linux-gnu/libgdk-3.so.0
#7  0x00005555555ef547 in make_screenshot (widget=widget@entry=0x555555e93100) at tests/bt-check-ui.c:358
#8  0x00005555555ef5ba in check_make_widget_screenshot (widget=0x555555e93100, name=0x5555555f7425 "mono-source")
    at tests/bt-check-ui.c:458
#9  0x000055555557ea52 in test_bt_machine_properties_dialog_create (_i=<optimized out>)

which is suggesting that a call to cairo_surface_flush would help. This makes my make_screenshot helper work again, but it looks overly complicated, right?:

  const cairo_rectangle_int_t c_rect = {0, 0, ww, wh };
  cairo_region_t *c_region = cairo_region_create_rectangle (&c_rect);
  if (c_region) {
    GdkDrawingContext *dc = gdk_window_begin_draw_frame (window, c_region);
    if (dc) {
      cairo_t *cr = gdk_drawing_context_get_cairo_context (dc);
      cairo_surface_t *surface = cairo_get_target (cr);
      cairo_surface_flush (surface);
      gdk_window_end_draw_frame (window, dc);
    } else {
      LOG_WARNING ("failed to begin_draw_frame");
    }
    cairo_region_destroy (c_region);
  } else {
    LOG_WARNING ("failed to create cairo region");
  }

Any better idea?

No, this is how the API is meant to be used.

You’re reaching for a low level bit of functionality (typically implemented by GTK’s main rendering code), so you’ll need to be more verbose than usual.

Thanks for the reply. I was wondering because the resulting screenshots are mostly black. What I am wondering is that the docs for gdk_pixbuf_get_from_window() does not mention anything about those failure modes. I think it would be much more useful to have a function that supports the user in getting a screenshot.

1 Like

So doing

  const cairo_rectangle_int_t c_rect = { 0, 0, ww, wh };
  cairo_region_t *c_region = cairo_region_create_rectangle (&c_rect);
  if (c_region) {
    GdkDrawingContext *dc = gdk_window_begin_draw_frame (window, c_region);
    if (dc) {
      cairo_t *cr = gdk_drawing_context_get_cairo_context (dc);
      cairo_surface_t *surface = cairo_get_target (cr);
      cairo_surface_flush (surface);

      gdk_window_end_draw_frame (window, dc);
    } else {
      GST_WARNING ("failed to begin_draw_frame");
    }
    cairo_region_destroy (c_region);
  } else {
    GST_WARNING ("failed to create cairo region");
  }

will fix the assertion, but then I get black windows. If I gtk_widget_queue_draw() afterwards I get good screenshots, but again the assertion for some of the windows.

The question is still open - how to reliably take screenshots of GtkWindows?