gtk2/testsuite/reftests/reftest-snapshot.c

310 lines
8.4 KiB
C
Raw Normal View History

/*
* Copyright (C) 2011 Red Hat Inc.
*
* Author:
* Benjamin Otte <otte@gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "reftest-snapshot.h"
#include "reftest-module.h"
#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#include <cairo-xlib.h>
#endif
#include <string.h>
typedef enum {
SNAPSHOT_WINDOW,
SNAPSHOT_DRAW
} SnapshotMode;
static GtkWidget *
builder_get_toplevel (GtkBuilder *builder)
{
GSList *list, *walk;
GtkWidget *window = NULL;
list = gtk_builder_get_objects (builder);
for (walk = list; walk; walk = walk->next)
{
if (GTK_IS_WINDOW (walk->data) &&
gtk_widget_get_parent (walk->data) == NULL)
{
window = walk->data;
break;
}
}
g_slist_free (list);
return window;
}
static gboolean
quit_when_idle (gpointer loop)
{
g_main_loop_quit (loop);
return G_SOURCE_REMOVE;
}
static gint inhibit_count;
static GMainLoop *loop;
void
reftest_inhibit_snapshot (void)
{
inhibit_count++;
}
void
reftest_uninhibit_snapshot (void)
{
g_assert (inhibit_count > 0);
inhibit_count--;
if (inhibit_count == 0)
g_idle_add (quit_when_idle, loop);
}
static void
check_for_draw (GdkEvent *event, gpointer data)
{
2017-08-28 23:11:45 +00:00
if (gdk_event_get_event_type (event) == GDK_EXPOSE)
{
reftest_uninhibit_snapshot ();
gdk_event_handler_set ((GdkEventFunc) gtk_main_do_event, NULL, NULL);
}
gtk_main_do_event (event);
}
static void
GdkWindow -> GdkSurface initial type rename This renames the GdkWindow class and related classes (impl, backend subclasses) to surface. Additionally it renames related types: GdkWindowAttr, GdkWindowPaint, GdkWindowWindowClass, GdkWindowType, GdkWindowTypeHint, GdkWindowHints, GdkWindowState, GdkWindowEdge This is an automatic conversion using the below commands: git sed -f g GdkWindowWindowClass GdkSurfaceSurfaceClass git sed -f g GdkWindow GdkSurface git sed -f g "gdk_window\([ _\(\),;]\|$\)" "gdk_surface\1" # Avoid hitting gdk_windowing git sed -f g "GDK_WINDOW\([ _\(]\|$\)" "GDK_SURFACE\1" # Avoid hitting GDK_WINDOWING git sed "GDK_\([A-Z]*\)IS_WINDOW\([_ (]\|$\)" "GDK_\1IS_SURFACE\2" git sed GDK_TYPE_WINDOW GDK_TYPE_SURFACE git sed -f g GdkPointerWindowInfo GdkPointerSurfaceInfo git sed -f g "BROADWAY_WINDOW" "BROADWAY_SURFACE" git sed -f g "broadway_window" "broadway_surface" git sed -f g "BroadwayWindow" "BroadwaySurface" git sed -f g "WAYLAND_WINDOW" "WAYLAND_SURFACE" git sed -f g "wayland_window" "wayland_surface" git sed -f g "WaylandWindow" "WaylandSurface" git sed -f g "X11_WINDOW" "X11_SURFACE" git sed -f g "x11_window" "x11_surface" git sed -f g "X11Window" "X11Surface" git sed -f g "WIN32_WINDOW" "WIN32_SURFACE" git sed -f g "win32_window" "win32_surface" git sed -f g "Win32Window" "Win32Surface" git sed -f g "QUARTZ_WINDOW" "QUARTZ_SURFACE" git sed -f g "quartz_window" "quartz_surface" git sed -f g "QuartzWindow" "QuartzSurface" git checkout NEWS* po-properties
2018-03-20 10:40:08 +00:00
snapshot_window_native (GdkSurface *window,
cairo_t *cr)
{
#ifdef GDK_WINDOWING_X11
GdkWindow -> GdkSurface initial type rename This renames the GdkWindow class and related classes (impl, backend subclasses) to surface. Additionally it renames related types: GdkWindowAttr, GdkWindowPaint, GdkWindowWindowClass, GdkWindowType, GdkWindowTypeHint, GdkWindowHints, GdkWindowState, GdkWindowEdge This is an automatic conversion using the below commands: git sed -f g GdkWindowWindowClass GdkSurfaceSurfaceClass git sed -f g GdkWindow GdkSurface git sed -f g "gdk_window\([ _\(\),;]\|$\)" "gdk_surface\1" # Avoid hitting gdk_windowing git sed -f g "GDK_WINDOW\([ _\(]\|$\)" "GDK_SURFACE\1" # Avoid hitting GDK_WINDOWING git sed "GDK_\([A-Z]*\)IS_WINDOW\([_ (]\|$\)" "GDK_\1IS_SURFACE\2" git sed GDK_TYPE_WINDOW GDK_TYPE_SURFACE git sed -f g GdkPointerWindowInfo GdkPointerSurfaceInfo git sed -f g "BROADWAY_WINDOW" "BROADWAY_SURFACE" git sed -f g "broadway_window" "broadway_surface" git sed -f g "BroadwayWindow" "BroadwaySurface" git sed -f g "WAYLAND_WINDOW" "WAYLAND_SURFACE" git sed -f g "wayland_window" "wayland_surface" git sed -f g "WaylandWindow" "WaylandSurface" git sed -f g "X11_WINDOW" "X11_SURFACE" git sed -f g "x11_window" "x11_surface" git sed -f g "X11Window" "X11Surface" git sed -f g "WIN32_WINDOW" "WIN32_SURFACE" git sed -f g "win32_window" "win32_surface" git sed -f g "Win32Window" "Win32Surface" git sed -f g "QUARTZ_WINDOW" "QUARTZ_SURFACE" git sed -f g "quartz_window" "quartz_surface" git sed -f g "QuartzWindow" "QuartzSurface" git checkout NEWS* po-properties
2018-03-20 10:40:08 +00:00
if (GDK_IS_X11_SURFACE (window))
{
cairo_surface_t *surface;
XWindowAttributes attrs;
GdkSurface: Rename various functions and variables This is an automatic rename of various things related to the window->surface rename. Public symbols changed by this is: GDK_MODE_WINDOW gdk_device_get_window_at_position gdk_device_get_window_at_position_double gdk_device_get_last_event_window gdk_display_get_monitor_at_window gdk_drag_context_get_source_window gdk_drag_context_get_dest_window gdk_drag_context_get_drag_window gdk_draw_context_get_window gdk_drawing_context_get_window gdk_gl_context_get_window gdk_synthesize_window_state gdk_surface_get_window_type gdk_x11_display_set_window_scale gsk_renderer_new_for_window gsk_renderer_get_window gtk_text_view_buffer_to_window_coords gtk_tree_view_convert_widget_to_bin_window_coords gtk_tree_view_convert_tree_to_bin_window_coords The commands that generated this are: git sed -f g "GDK window" "GDK surface" git sed -f g window_impl surface_impl (cd gdk; git sed -f g impl_window impl_surface) git sed -f g WINDOW_IMPL SURFACE_IMPL git sed -f g GDK_MODE_WINDOW GDK_MODE_SURFACE git sed -f g gdk_draw_context_get_window gdk_draw_context_get_surface git sed -f g gdk_drawing_context_get_window gdk_drawing_context_get_surface git sed -f g gdk_gl_context_get_window gdk_gl_context_get_surface git sed -f g gsk_renderer_get_window gsk_renderer_get_surface git sed -f g gsk_renderer_new_for_window gsk_renderer_new_for_surface (cd gdk; git sed -f g window_type surface_type) git sed -f g gdk_surface_get_window_type gdk_surface_get_surface_type git sed -f g window_at_position surface_at_position git sed -f g event_window event_surface git sed -f g window_coord surface_coord git sed -f g window_state surface_state git sed -f g window_cursor surface_cursor git sed -f g window_scale surface_scale git sed -f g window_events surface_events git sed -f g monitor_at_window monitor_at_surface git sed -f g window_under_pointer surface_under_pointer (cd gdk; git sed -f g for_window for_surface) git sed -f g window_anchor surface_anchor git sed -f g WINDOW_IS_TOPLEVEL SURFACE_IS_TOPLEVEL git sed -f g native_window native_surface git sed -f g source_window source_surface git sed -f g dest_window dest_surface git sed -f g drag_window drag_surface git sed -f g input_window input_surface git checkout NEWS* po-properties po docs/reference/gtk/migrating-3to4.xml
2018-03-20 11:05:26 +00:00
if (gdk_surface_get_surface_type (window) == GDK_SURFACE_TOPLEVEL ||
gdk_surface_get_surface_type (window) == GDK_SURFACE_TEMP)
{
/* give the WM/server some time to sync. They need it.
* Also, do use popups instead of toplevels in your tests
* whenever you can.
*/
GdkWindow -> GdkSurface initial type rename This renames the GdkWindow class and related classes (impl, backend subclasses) to surface. Additionally it renames related types: GdkWindowAttr, GdkWindowPaint, GdkWindowWindowClass, GdkWindowType, GdkWindowTypeHint, GdkWindowHints, GdkWindowState, GdkWindowEdge This is an automatic conversion using the below commands: git sed -f g GdkWindowWindowClass GdkSurfaceSurfaceClass git sed -f g GdkWindow GdkSurface git sed -f g "gdk_window\([ _\(\),;]\|$\)" "gdk_surface\1" # Avoid hitting gdk_windowing git sed -f g "GDK_WINDOW\([ _\(]\|$\)" "GDK_SURFACE\1" # Avoid hitting GDK_WINDOWING git sed "GDK_\([A-Z]*\)IS_WINDOW\([_ (]\|$\)" "GDK_\1IS_SURFACE\2" git sed GDK_TYPE_WINDOW GDK_TYPE_SURFACE git sed -f g GdkPointerWindowInfo GdkPointerSurfaceInfo git sed -f g "BROADWAY_WINDOW" "BROADWAY_SURFACE" git sed -f g "broadway_window" "broadway_surface" git sed -f g "BroadwayWindow" "BroadwaySurface" git sed -f g "WAYLAND_WINDOW" "WAYLAND_SURFACE" git sed -f g "wayland_window" "wayland_surface" git sed -f g "WaylandWindow" "WaylandSurface" git sed -f g "X11_WINDOW" "X11_SURFACE" git sed -f g "x11_window" "x11_surface" git sed -f g "X11Window" "X11Surface" git sed -f g "WIN32_WINDOW" "WIN32_SURFACE" git sed -f g "win32_window" "win32_surface" git sed -f g "Win32Window" "Win32Surface" git sed -f g "QUARTZ_WINDOW" "QUARTZ_SURFACE" git sed -f g "quartz_window" "quartz_surface" git sed -f g "QuartzWindow" "QuartzSurface" git checkout NEWS* po-properties
2018-03-20 10:40:08 +00:00
gdk_display_sync (gdk_surface_get_display (window));
g_timeout_add (500, quit_when_idle, loop);
g_main_loop_run (loop);
}
GdkWindow -> GdkSurface initial type rename This renames the GdkWindow class and related classes (impl, backend subclasses) to surface. Additionally it renames related types: GdkWindowAttr, GdkWindowPaint, GdkWindowWindowClass, GdkWindowType, GdkWindowTypeHint, GdkWindowHints, GdkWindowState, GdkWindowEdge This is an automatic conversion using the below commands: git sed -f g GdkWindowWindowClass GdkSurfaceSurfaceClass git sed -f g GdkWindow GdkSurface git sed -f g "gdk_window\([ _\(\),;]\|$\)" "gdk_surface\1" # Avoid hitting gdk_windowing git sed -f g "GDK_WINDOW\([ _\(]\|$\)" "GDK_SURFACE\1" # Avoid hitting GDK_WINDOWING git sed "GDK_\([A-Z]*\)IS_WINDOW\([_ (]\|$\)" "GDK_\1IS_SURFACE\2" git sed GDK_TYPE_WINDOW GDK_TYPE_SURFACE git sed -f g GdkPointerWindowInfo GdkPointerSurfaceInfo git sed -f g "BROADWAY_WINDOW" "BROADWAY_SURFACE" git sed -f g "broadway_window" "broadway_surface" git sed -f g "BroadwayWindow" "BroadwaySurface" git sed -f g "WAYLAND_WINDOW" "WAYLAND_SURFACE" git sed -f g "wayland_window" "wayland_surface" git sed -f g "WaylandWindow" "WaylandSurface" git sed -f g "X11_WINDOW" "X11_SURFACE" git sed -f g "x11_window" "x11_surface" git sed -f g "X11Window" "X11Surface" git sed -f g "WIN32_WINDOW" "WIN32_SURFACE" git sed -f g "win32_window" "win32_surface" git sed -f g "Win32Window" "Win32Surface" git sed -f g "QUARTZ_WINDOW" "QUARTZ_SURFACE" git sed -f g "quartz_window" "quartz_surface" git sed -f g "QuartzWindow" "QuartzSurface" git checkout NEWS* po-properties
2018-03-20 10:40:08 +00:00
XGetWindowAttributes (gdk_x11_display_get_xdisplay (gdk_surface_get_display (window)),
gdk_x11_surface_get_xid (window),
&attrs);
GdkWindow -> GdkSurface initial type rename This renames the GdkWindow class and related classes (impl, backend subclasses) to surface. Additionally it renames related types: GdkWindowAttr, GdkWindowPaint, GdkWindowWindowClass, GdkWindowType, GdkWindowTypeHint, GdkWindowHints, GdkWindowState, GdkWindowEdge This is an automatic conversion using the below commands: git sed -f g GdkWindowWindowClass GdkSurfaceSurfaceClass git sed -f g GdkWindow GdkSurface git sed -f g "gdk_window\([ _\(\),;]\|$\)" "gdk_surface\1" # Avoid hitting gdk_windowing git sed -f g "GDK_WINDOW\([ _\(]\|$\)" "GDK_SURFACE\1" # Avoid hitting GDK_WINDOWING git sed "GDK_\([A-Z]*\)IS_WINDOW\([_ (]\|$\)" "GDK_\1IS_SURFACE\2" git sed GDK_TYPE_WINDOW GDK_TYPE_SURFACE git sed -f g GdkPointerWindowInfo GdkPointerSurfaceInfo git sed -f g "BROADWAY_WINDOW" "BROADWAY_SURFACE" git sed -f g "broadway_window" "broadway_surface" git sed -f g "BroadwayWindow" "BroadwaySurface" git sed -f g "WAYLAND_WINDOW" "WAYLAND_SURFACE" git sed -f g "wayland_window" "wayland_surface" git sed -f g "WaylandWindow" "WaylandSurface" git sed -f g "X11_WINDOW" "X11_SURFACE" git sed -f g "x11_window" "x11_surface" git sed -f g "X11Window" "X11Surface" git sed -f g "WIN32_WINDOW" "WIN32_SURFACE" git sed -f g "win32_window" "win32_surface" git sed -f g "Win32Window" "Win32Surface" git sed -f g "QUARTZ_WINDOW" "QUARTZ_SURFACE" git sed -f g "quartz_window" "quartz_surface" git sed -f g "QuartzWindow" "QuartzSurface" git checkout NEWS* po-properties
2018-03-20 10:40:08 +00:00
surface = cairo_xlib_surface_create (gdk_x11_display_get_xdisplay (gdk_surface_get_display (window)),
gdk_x11_surface_get_xid (window),
attrs.visual,
attrs.width,
attrs.height);
cairo_set_source_surface (cr, surface, 0, 0);
cairo_paint (cr);
cairo_surface_destroy (surface);
}
#endif
}
static cairo_surface_t *
snapshot_widget (GtkWidget *widget, SnapshotMode mode)
{
cairo_surface_t *surface;
cairo_t *cr;
g_assert (gtk_widget_get_realized (widget));
loop = g_main_loop_new (NULL, FALSE);
/* We wait until the widget is drawn for the first time.
* We can not wait for a GtkWidget::draw event, because that might not
* happen if the window is fully obscured by windowed child widgets.
* Alternatively, we could wait for an expose event on widget's window.
* Both of these are rather hairy, not sure what's best.
*
* We also use an inhibit mechanism, to give module functions a chance
* to delay the snapshot.
*/
reftest_inhibit_snapshot ();
gdk_event_handler_set (check_for_draw, NULL, NULL);
g_main_loop_run (loop);
surface = gdk_surface_create_similar_surface (gtk_widget_get_surface (widget),
CAIRO_CONTENT_COLOR,
gtk_widget_get_allocated_width (widget),
gtk_widget_get_allocated_height (widget));
cr = cairo_create (surface);
switch (mode)
{
case SNAPSHOT_WINDOW:
snapshot_window_native (gtk_widget_get_surface (widget), cr);
break;
case SNAPSHOT_DRAW:
{
GtkSnapshot *snapshot = gtk_snapshot_new (FALSE, "ReftestSnapshot");
GdkPaintable *paintable = gtk_widget_paintable_new (widget);
GskRenderNode *node;
gdk_paintable_snapshot (paintable,
snapshot,
gtk_widget_get_allocated_width (widget),
gtk_widget_get_allocated_height (widget));
g_object_unref (paintable);
node = gtk_snapshot_free_to_node (snapshot);
gsk_render_node_draw (node, cr);
}
break;
default:
g_assert_not_reached();
break;
}
cairo_destroy (cr);
g_main_loop_unref (loop);
gtk_widget_destroy (widget);
return surface;
}
static void
connect_signals (GtkBuilder *builder,
GObject *object,
const gchar *signal_name,
const gchar *handler_name,
GObject *connect_object,
GConnectFlags flags,
gpointer user_data)
{
ReftestModule *module;
const char *directory;
GCallback func;
GClosure *closure;
char **split;
directory = user_data;
split = g_strsplit (handler_name, ":", -1);
switch (g_strv_length (split))
{
case 1:
func = gtk_builder_lookup_callback_symbol (builder, split[0]);
if (func)
{
module = NULL;
}
else
{
module = reftest_module_new_self ();
if (module == NULL)
{
g_error ("glib compiled without module support.");
return;
}
func = reftest_module_lookup (module, split[0]);
if (!func)
{
g_error ("failed to lookup handler for name '%s' when connecting signals", split[0]);
return;
}
}
break;
case 2:
if (g_getenv ("REFTEST_MODULE_DIR"))
directory = g_getenv ("REFTEST_MODULE_DIR");
module = reftest_module_new (directory, split[0]);
if (module == NULL)
{
g_error ("Could not load module '%s' from '%s' when looking up '%s'", split[0], directory, handler_name);
return;
}
func = reftest_module_lookup (module, split[1]);
if (!func)
{
g_error ("failed to lookup handler for name '%s' in module '%s'", split[1], split[0]);
return;
}
break;
default:
g_error ("Could not connect signal handler named '%s'", handler_name);
return;
}
g_strfreev (split);
if (connect_object)
{
if (flags & G_CONNECT_SWAPPED)
closure = g_cclosure_new_object_swap (func, connect_object);
else
closure = g_cclosure_new_object (func, connect_object);
}
else
{
if (flags & G_CONNECT_SWAPPED)
closure = g_cclosure_new_swap (func, NULL, NULL);
else
closure = g_cclosure_new (func, NULL, NULL);
}
if (module)
g_closure_add_finalize_notifier (closure, module, (GClosureNotify) reftest_module_unref);
g_signal_connect_closure (object, signal_name, closure, flags & G_CONNECT_AFTER ? TRUE : FALSE);
}
cairo_surface_t *
reftest_snapshot_ui_file (const char *ui_file)
{
GtkWidget *window;
GtkBuilder *builder;
GError *error = NULL;
char *directory;
directory = g_path_get_dirname (ui_file);
builder = gtk_builder_new ();
gtk_builder_add_from_file (builder, ui_file, &error);
g_assert_no_error (error);
gtk_builder_connect_signals_full (builder, connect_signals, directory);
window = builder_get_toplevel (builder);
g_object_unref (builder);
g_free (directory);
g_assert (window);
gtk_widget_show (window);
return snapshot_widget (window, SNAPSHOT_WINDOW);
}