Compare commits
127 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ed087f2a30 | |||
| df54c81d7f | |||
| 3ccd45b9e0 | |||
| 0d08d2d63a | |||
| 40de4d590a | |||
| 111a440dda | |||
| 9df3067bb8 | |||
| 46c7128094 | |||
| 781b5aac86 | |||
| df28f92187 | |||
| 59f95e1e1f | |||
| 0a2467ce3b | |||
| d6acfd81c7 | |||
| 697d0e9ed9 | |||
| a21409c61b | |||
| e825ca92e7 | |||
| ed3740933e | |||
| 0f1a8bfe20 | |||
| f78330139f | |||
| 5e973006b4 | |||
| b1c5475046 | |||
| ea3c2f4889 | |||
| 2aeb9f61a6 | |||
| 11151379df | |||
| fc15f027ec | |||
| 63dc543d0e | |||
| 4befa6b653 | |||
| c454c1ad2c | |||
| 84c5472752 | |||
| 88d02b8f91 | |||
| 8c9717119d | |||
| b3063fe3a0 | |||
| bf4c44fbf1 | |||
| 92273b5d19 | |||
| 710a326db2 | |||
| 8851d75ba8 | |||
| ed8db31f81 | |||
| d40636b6b0 | |||
| fddc1a9708 | |||
| 4ea6ee4567 | |||
| 9286c1c0fa | |||
| 82166f8d72 | |||
| cf96e92b8b | |||
| 1140c20309 | |||
| 5228506b6f | |||
| 6fd807ae0d | |||
| cd78d1a69a | |||
| fe590578f9 | |||
| ae4e72d944 | |||
| 00d4b62dce | |||
| c0cd978311 | |||
| cd14236dfe | |||
| fb9413d464 | |||
| 7f22c023de | |||
| bda1701301 | |||
| 399a03f475 | |||
| 8f75be4647 | |||
| daec615286 | |||
| 2695f32eb3 | |||
| 9ec2875543 | |||
| 5b735cff00 | |||
| ae10683e95 | |||
| 0c39051cbe | |||
| 1cd7d4f7cd | |||
| 34b6993d15 | |||
| c99536c752 | |||
| 2e70e041f1 | |||
| aed3ab1e85 | |||
| 6c08ea6283 | |||
| 4c986971fd | |||
| 9b9141fea9 | |||
| 8471405b7f | |||
| c77cc127ea | |||
| 89500c5d84 | |||
| e48cc71656 | |||
| db10f1ff64 | |||
| 020e4e5bfa | |||
| bbf11f749b | |||
| 0ca16c5a7e | |||
| 11085dccae | |||
| f9ca3f0143 | |||
| 512cbcb6e0 | |||
| 78f320c01d | |||
| f661d097a6 | |||
| c481c01322 | |||
| 2059da9967 | |||
| cc6b7a5ea0 | |||
| 66d16d19c1 | |||
| 77dc24be86 | |||
| 829676c93d | |||
| e02836f989 | |||
| 841ca89956 | |||
| 509a219fcb | |||
| 5313aa28d6 | |||
| 984e205ddb | |||
| e3bf255d2f | |||
| 07d823e9ff | |||
| 3bf8f49ead | |||
| ea982b5564 | |||
| d0c6c6251e | |||
| c04db84c48 | |||
| 9155bbaafb | |||
| 8420dc7682 | |||
| 9dde2ebf67 | |||
| 999db0f9c8 | |||
| 34a5eb01e3 | |||
| cf76f81409 | |||
| c4a2f3b5fb | |||
| 7a98ef45e1 | |||
| 907fc8d21e | |||
| 51b889bf8f | |||
| d1d2ae6c25 | |||
| 53cbbf8cf2 | |||
| 145e45db26 | |||
| 4e2f35fdf2 | |||
| 81377767a2 | |||
| 6aed0210a4 | |||
| 9992e35c59 | |||
| 79a9f700c4 | |||
| ea95e22a75 | |||
| 625e930222 | |||
| 0eaf85704b | |||
| 55d2522fb0 | |||
| 0f57ab4a54 | |||
| ae8d209e50 | |||
| a422f45544 | |||
| 2378965e92 |
+3
-2
@@ -1,7 +1,7 @@
|
||||
## Makefile.am for GTK+
|
||||
include $(top_srcdir)/Makefile.decl
|
||||
|
||||
SRC_SUBDIRS = gdk gtk modules demos tests testsuite examples
|
||||
SRC_SUBDIRS = gdk gsk gtk modules demos tests testsuite examples
|
||||
SUBDIRS = po po-properties $(SRC_SUBDIRS) docs build
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
|
||||
@@ -45,7 +45,7 @@ gdk-x11-4.0.pc gdk-win32-4.0.pc gdk-quartz-4.0.pc gdk-broadway-4.0.pc gdk-waylan
|
||||
cp gdk-4.0.pc $@
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = gdk-4.0.pc gtk+-4.0.pc gail-4.0.pc
|
||||
pkgconfig_DATA = gdk-4.0.pc gsk-4.0.pc gtk+-4.0.pc gail-4.0.pc
|
||||
pkgconfig_DATA += ${GDK_BACKENDS:%=gtk+-%-4.0.pc}
|
||||
pkgconfig_DATA += ${GDK_BACKENDS:%=gdk-%-4.0.pc}
|
||||
|
||||
@@ -62,6 +62,7 @@ DISTCLEANFILES = \
|
||||
gtk+-broadway-4.0.pc \
|
||||
gtk+-wayland-4.0.pc \
|
||||
gtk+-mir-4.0.pc \
|
||||
gsk-4.0.pc \
|
||||
gdk-4.0.pc \
|
||||
gdk-x11-4.0.pc \
|
||||
gdk-win32-4.0.pc \
|
||||
|
||||
+27
-1
@@ -64,6 +64,7 @@ m4_define([wayland_protocols_required_version], [1.7])
|
||||
m4_define([mirclient_required_version], [0.22.0])
|
||||
m4_define([mircookie_required_version], [0.17.0])
|
||||
m4_define([epoxy_required_version], [1.0])
|
||||
m4_define([graphene_required_version], [1.2])
|
||||
GLIB_REQUIRED_VERSION=glib_required_version
|
||||
PANGO_REQUIRED_VERSION=pango_required_version
|
||||
ATK_REQUIRED_VERSION=atk_required_version
|
||||
@@ -1365,6 +1366,26 @@ AC_SUBST(GDK_EXTRA_CFLAGS)
|
||||
AC_SUBST(GDK_DEP_LIBS)
|
||||
AC_SUBST(GDK_DEP_CFLAGS)
|
||||
|
||||
########################################
|
||||
# Check for GSK flags
|
||||
########################################
|
||||
|
||||
GSK_EXTRA_LIBS=
|
||||
GSK_EXTRA_CFLAGS=
|
||||
|
||||
GSK_PACKAGES="gdk-pixbuf-2.0 >= gdk_pixbuf_required_version cairo >= cairo_required_version cairo-gobject >= cairo_required_version graphene-1.0 >= graphene_required_version"
|
||||
GSK_PRIVATE_PACKAGES="epoxy >= epoxy_required_version"
|
||||
|
||||
PKG_CHECK_MODULES(GSK_DEP, $PANGO_PACKAGES $GSK_PACKAGES $GSK_PRIVATE_PACKAGES)
|
||||
GSK_DEP_LIBS="$GSK_EXTRA_LIBS $GSK_DEP_LIBS $MATH_LIB"
|
||||
GSK_DEP_CFLAGS="$GSK_DEP_CFLAGS $GSK_EXTRA_CFLAGS"
|
||||
|
||||
AC_SUBST(GSK_PACKAGES)
|
||||
AC_SUBST(GSK_PRIVATE_PACKAGES)
|
||||
AC_SUBST(GSK_EXTRA_LIBS)
|
||||
AC_SUBST(GSK_EXTRA_CFLAGS)
|
||||
AC_SUBST(GSK_DEP_LIBS)
|
||||
AC_SUBST(GSK_DEP_CFLAGS)
|
||||
|
||||
########################################
|
||||
# Check for Accessibility Toolkit flags
|
||||
@@ -1379,7 +1400,7 @@ fi
|
||||
PKG_CHECK_MODULES(ATK, $ATK_PACKAGES)
|
||||
|
||||
GTK_PACKAGES="atk >= atk_required_version cairo >= cairo_required_version cairo-gobject >= cairo_required_version gdk-pixbuf-2.0 >= gdk_pixbuf_required_version gio-2.0 >= glib_required_version"
|
||||
GTK_PRIVATE_PACKAGES="$ATK_PACKAGES $WAYLAND_PACKAGES $MIR_PACKAGES epoxy >= epoxy_required_version"
|
||||
GTK_PRIVATE_PACKAGES="$ATK_PACKAGES $WAYLAND_PACKAGES $MIR_PACKAGES epoxy >= epoxy_required_version graphene-1.0 >= graphene_required_version"
|
||||
if test "x$enable_x11_backend" = xyes -o "x$enable_wayland_backend" = xyes; then
|
||||
GTK_PRIVATE_PACKAGES="$GTK_PRIVATE_PACKAGES pangoft2"
|
||||
fi
|
||||
@@ -1923,6 +1944,7 @@ config.h.win32
|
||||
gtk-zip.sh
|
||||
Makefile
|
||||
gdk-4.0.pc
|
||||
gsk-4.0.pc
|
||||
gtk+-4.0.pc
|
||||
gtk+-unix-print-4.0.pc
|
||||
gail-4.0.pc
|
||||
@@ -1955,6 +1977,7 @@ testsuite/css/parser/Makefile
|
||||
testsuite/css/nodes/Makefile
|
||||
testsuite/css/style/Makefile
|
||||
testsuite/gdk/Makefile
|
||||
testsuite/gsk/Makefile
|
||||
testsuite/gtk/Makefile
|
||||
testsuite/reftests/Makefile
|
||||
testsuite/tools/Makefile
|
||||
@@ -1962,6 +1985,8 @@ docs/Makefile
|
||||
docs/reference/Makefile
|
||||
docs/reference/gdk/Makefile
|
||||
docs/reference/gdk/version.xml
|
||||
docs/reference/gsk/Makefile
|
||||
docs/reference/gsk/version.xml
|
||||
docs/reference/gtk/Makefile
|
||||
docs/reference/gtk/gtk4.types
|
||||
docs/reference/gtk/version.xml
|
||||
@@ -1985,6 +2010,7 @@ gdk/quartz/Makefile
|
||||
gdk/wayland/Makefile
|
||||
gdk/mir/Makefile
|
||||
gdk/gdkversionmacros.h
|
||||
gsk/Makefile
|
||||
gtk/Makefile
|
||||
gtk/makefile.msc
|
||||
gtk/gtkversion.h
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
## Process this file with automake to produce Makefile.in
|
||||
include $(top_srcdir)/Makefile.decl
|
||||
|
||||
SUBDIRS = gdk gtk
|
||||
SUBDIRS = gdk gsk gtk
|
||||
|
||||
GITIGNOREFILES = */*.1
|
||||
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
AUTOMAKE_OPTIONS = 1.6
|
||||
|
||||
# The name of the module.
|
||||
DOC_MODULE = gsk3
|
||||
|
||||
# The top-level SGML file.
|
||||
DOC_MAIN_SGML_FILE = gsk-docs.xml
|
||||
|
||||
# Extra options to supply to gtkdoc-scan
|
||||
SCAN_OPTIONS = --deprecated-guards=GDK_DISABLE_DEPRECATED \
|
||||
--ignore-decorators=G_GNUC_WARN_UNUSED_RESULT
|
||||
|
||||
# The directory containing the source code. Relative to $(srcdir)
|
||||
DOC_SOURCE_DIR = $(top_srcdir)/gsk
|
||||
|
||||
# Used for dependencies
|
||||
HFILE_GLOB = $(top_srcdir)/gsk/*.h
|
||||
CFILE_GLOB = $(top_srcdir)/gsk/*.c
|
||||
|
||||
# Header files to ignore when scanning
|
||||
IGNORE_HFILES = \
|
||||
gskcairorendererprivate.h \
|
||||
gskdebugprivate.h \
|
||||
gskdriverprivate.h \
|
||||
gskprofilerprivate.h \
|
||||
gskglrendererprivate.h \
|
||||
gskprivate.h \
|
||||
gskprofilerprivate.h \
|
||||
gskrendererprivate.h \
|
||||
gskrendernodeprivate.h \
|
||||
gskshaderbiulderprivate.h
|
||||
|
||||
# Extra files to add when scanning
|
||||
EXTRA_HFILES =
|
||||
|
||||
# CFLAGS and LDFLAGS for compiling scan program. Only needed
|
||||
# if $(DOC_MODULE).types is non-empty.
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_builddir) \
|
||||
-I$(top_builddir)/gsk \
|
||||
$(GTK_DEBUG_FLAGS) \
|
||||
$(GDK_DEP_CFLAGS)
|
||||
|
||||
GTKDOC_LIBS = $(top_builddir)/gsk/libgsk-3.la $(GDK_DEP_LIBS)
|
||||
|
||||
# Extra options to supply to gtkdoc-mkdb
|
||||
MKDB_OPTIONS=--output-format=xml --name-space=gsk
|
||||
|
||||
# Extra SGML files that are included by DOC_MAIN_SGML_FILE
|
||||
content_files = \
|
||||
version.xml
|
||||
|
||||
# Images to copy into HTML directory
|
||||
HTML_IMAGES =
|
||||
|
||||
if ENABLE_DOC_CROSS_REFERENCES
|
||||
# Extra options to supply to gtkdoc-fixref
|
||||
FIXXREF_OPTIONS= \
|
||||
--extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html/gobject \
|
||||
--extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html/glib \
|
||||
--extra-dir=$(CAIRO_PREFIX)/share/gtk-doc/html/cairo
|
||||
endif
|
||||
|
||||
include $(top_srcdir)/gtk-doc.make
|
||||
|
||||
# Other files to distribute
|
||||
EXTRA_DIST += version.xml.in
|
||||
|
||||
if ENABLE_GTK_DOC
|
||||
TESTS_ENVIRONMENT = cd $(srcdir) && \
|
||||
DOC_MODULE=$(DOC_MODULE) DOC_MAIN_SGML_FILE=$(DOC_MAIN_SGML_FILE) \
|
||||
SRCDIR=$(abs_srcdir) BUILDDIR=$(abs_builddir)
|
||||
#TESTS = $(GTKDOC_CHECK)
|
||||
endif
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
|
||||
<bookinfo>
|
||||
<title>GSK 3 Reference Manual</title>
|
||||
<releaseinfo>
|
||||
This document is for the GSK 3 library, version &version;
|
||||
The latest versions can be found online at
|
||||
<ulink role="online-location" url="http://developer.gnome.org/gdk3/">http://developer.gnome.org/gsk3/</ulink>.
|
||||
</releaseinfo>
|
||||
</bookinfo>
|
||||
|
||||
<reference id="reference">
|
||||
<title>API Reference</title>
|
||||
<xi:include href="xml/GskRenderer.xml" />
|
||||
<xi:include href="xml/GskRenderNode.xml" />
|
||||
<xi:include href="xml/GskRenderNodeIter.xml" />
|
||||
</reference>
|
||||
|
||||
<index id="api-index-full">
|
||||
<title>Index of all symbols</title>
|
||||
<xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
|
||||
</book>
|
||||
@@ -0,0 +1,87 @@
|
||||
<SECTION>
|
||||
<FILE>GskRenderer</FILE>
|
||||
gsk_renderer_get_for_display
|
||||
gsk_renderer_set_viewport
|
||||
gsk_renderer_get_viewport
|
||||
gsk_renderer_set_scale_factor
|
||||
gsk_renderer_get_scale_factor
|
||||
gsk_renderer_set_window
|
||||
gsk_renderer_get_window
|
||||
gsk_renderer_get_display
|
||||
gsk_renderer_realize
|
||||
gsk_renderer_unrealize
|
||||
gsk_renderer_create_render_node
|
||||
gsk_renderer_render
|
||||
<SUBSECTION Standard>
|
||||
GSK_IS_RENDERER
|
||||
GSK_RENDERER
|
||||
GSK_TYPE_RENDERER
|
||||
GskRenderer
|
||||
GskRendererClass
|
||||
gsk_renderer_get_type
|
||||
GSK_TYPE_SCALING_FILTER
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>GskRenderNode</FILE>
|
||||
gsk_render_node_ref
|
||||
gsk_render_node_unref
|
||||
gsk_render_node_get_parent
|
||||
gsk_render_node_get_first_child
|
||||
gsk_render_node_get_last_child
|
||||
gsk_render_node_get_next_sibling
|
||||
gsk_render_node_get_previous_sibling
|
||||
gsk_render_node_append_child
|
||||
gsk_render_node_prepend_child
|
||||
gsk_render_node_insert_child_at_pos
|
||||
gsk_render_node_insert_child_before
|
||||
gsk_render_node_insert_child_after
|
||||
gsk_render_node_remove_child
|
||||
gsk_render_node_replace_child
|
||||
gsk_render_node_remove_all_children
|
||||
gsk_render_node_get_n_children
|
||||
gsk_render_node_contains
|
||||
gsk_render_node_set_bounds
|
||||
gsk_render_node_set_transform
|
||||
gsk_render_node_set_anchor_point
|
||||
gsk_render_node_set_opacity
|
||||
gsk_render_node_set_hidden
|
||||
gsk_render_node_is_hidden
|
||||
gsk_render_node_set_opaque
|
||||
gsk_render_node_is_opaque
|
||||
gsk_render_node_get_draw_context
|
||||
GskBlendMode
|
||||
gsk_render_node_set_blend_mode
|
||||
GskScalingFilter
|
||||
gsk_render_node_set_scaling_filters
|
||||
gsk_render_node_get_scale_factor
|
||||
gsk_render_node_set_name
|
||||
gsk_value_set_render_node
|
||||
gsk_value_take_render_node
|
||||
gsk_value_get_render_node
|
||||
gsk_value_dup_render_node
|
||||
<SUBSECTION Standard>
|
||||
GSK_IS_RENDER_NODE
|
||||
GSK_RENDER_NODE
|
||||
GSK_TYPE_RENDER_NODE
|
||||
GSK_VALUE_HOLDS_RENDER_NODE
|
||||
GskRenderNode
|
||||
GskRenderNodeClass
|
||||
gsk_render_node_get_type
|
||||
GSK_TYPE_BLEND_MODE
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>GskRenderNodeIter</FILE>
|
||||
gsk_render_node_iter_new
|
||||
gsk_render_node_iter_free
|
||||
gsk_render_node_iter_init
|
||||
gsk_render_node_iter_is_valid
|
||||
gsk_render_node_iter_prev
|
||||
gsk_render_node_iter_next
|
||||
gsk_render_node_iter_remove
|
||||
<SUBSECTION Standard>
|
||||
GSK_TYPE_RENDER_NODE_ITER
|
||||
GskRenderNodeIter
|
||||
gsk_render_node_iter_get_type
|
||||
</SECTION>
|
||||
@@ -0,0 +1,3 @@
|
||||
gsk_render_node_get_type
|
||||
gsk_render_node_iter_get_type
|
||||
gsk_renderer_get_type
|
||||
@@ -0,0 +1 @@
|
||||
@GTK_VERSION@
|
||||
@@ -83,6 +83,13 @@ void gdk_cairo_draw_from_gl (cairo_t *cr,
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GdkDrawingContext * gdk_cairo_get_drawing_context (cairo_t *cr);
|
||||
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
void gdk_cairo_surface_upload_to_gl (cairo_surface_t *surface,
|
||||
int target,
|
||||
int width,
|
||||
int height,
|
||||
GdkGLContext *context);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_CAIRO_H__ */
|
||||
|
||||
+45
@@ -814,3 +814,48 @@ gdk_gl_texture_from_surface (cairo_surface_t *surface,
|
||||
glDisable (GL_SCISSOR_TEST);
|
||||
glDeleteTextures (1, &texture_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_cairo_surface_upload_to_gl:
|
||||
* @surface: a Cairo surface
|
||||
* @target: a GL texture target
|
||||
* @width: the width of the texture @target
|
||||
* @height: the height of the texture @target
|
||||
* @context: (nullable): a #GdkGLContext, or %NULL to use the currently
|
||||
* bound context
|
||||
*
|
||||
* Uploads the contents of a Cairo @surface to a GL texture @target.
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
void
|
||||
gdk_cairo_surface_upload_to_gl (cairo_surface_t *surface,
|
||||
int target,
|
||||
int width,
|
||||
int height,
|
||||
GdkGLContext *context)
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
cairo_surface_t *tmp;
|
||||
double device_x_offset, device_y_offset;
|
||||
|
||||
g_return_if_fail (surface != NULL);
|
||||
g_return_if_fail (context == NULL || GDK_IS_GL_CONTEXT (context));
|
||||
|
||||
if (context == NULL)
|
||||
context = gdk_gl_context_get_current ();
|
||||
|
||||
cairo_surface_flush (surface);
|
||||
|
||||
cairo_surface_get_device_offset (surface, &device_x_offset, &device_y_offset);
|
||||
|
||||
rect.x = (int) device_x_offset;
|
||||
rect.y = (int) device_y_offset;
|
||||
rect.width = width;
|
||||
rect.height = height;
|
||||
tmp = cairo_surface_map_to_image (surface, &rect);
|
||||
|
||||
gdk_gl_context_upload_texture (context, tmp, rect.width, rect.height, target);
|
||||
|
||||
cairo_surface_unmap_image (surface, tmp);
|
||||
}
|
||||
|
||||
+5
-1
@@ -472,6 +472,8 @@ struct _GdkPoint
|
||||
* @GDK_GL_ERROR_NOT_AVAILABLE: OpenGL support is not available
|
||||
* @GDK_GL_ERROR_UNSUPPORTED_FORMAT: The requested visual format is not supported
|
||||
* @GDK_GL_ERROR_UNSUPPORTED_PROFILE: The requested profile is not supported
|
||||
* @GDK_GL_ERROR_COMPILATION_FAILED: The shader compilation failed (available since 3.22)
|
||||
* @GDK_GL_ERROR_LINK_FAILED: The shader linking failed (available since 3.22)
|
||||
*
|
||||
* Error enumeration for #GdkGLContext.
|
||||
*
|
||||
@@ -480,7 +482,9 @@ struct _GdkPoint
|
||||
typedef enum {
|
||||
GDK_GL_ERROR_NOT_AVAILABLE,
|
||||
GDK_GL_ERROR_UNSUPPORTED_FORMAT,
|
||||
GDK_GL_ERROR_UNSUPPORTED_PROFILE
|
||||
GDK_GL_ERROR_UNSUPPORTED_PROFILE,
|
||||
GDK_GL_ERROR_COMPILATION_FAILED,
|
||||
GDK_GL_ERROR_LINK_FAILED
|
||||
} GdkGLError;
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
targets=@GDK_BACKENDS@
|
||||
|
||||
Name: GSK
|
||||
Description: GTK+ Scene Graph Kit
|
||||
Version: @VERSION@
|
||||
Requires: gdk-@GTK_API_VERSION@ @GSK_PACKAGES@
|
||||
Requires.private: @GSK_PRIVATE_PACKAGES@
|
||||
Libs: -L${libdir} -lgsk-3 @GSK_EXTRA_LIBS@
|
||||
Cflags: -I${includedir}/gsk-@GTK_API_VERSION@ @GSK_EXTRA_CFLAGS@
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
include $(top_srcdir)/Makefile.decl
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-DG_LOG_DOMAIN=\"Gsk\" \
|
||||
-DGSK_COMPILATION \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/gdk \
|
||||
-I$(top_builddir) \
|
||||
-I$(top_builddir)/gsk \
|
||||
$(GTK_DEBUG_FLAGS) \
|
||||
$(GTK_WARN_FLAGS) \
|
||||
$(GSK_DEP_CFLAGS)
|
||||
|
||||
# libtool stuff: set version and export symbols for resolving
|
||||
# since automake doesn't support conditionalized libsomething_la_LDFLAGS
|
||||
# we use the general approach here
|
||||
LDADD = \
|
||||
$(GTK_LINK_FLAGS) \
|
||||
-version-info $(LT_VERSION_INFO) \
|
||||
-export-dynamic \
|
||||
-rpath $(libdir) \
|
||||
$(no_undefined)
|
||||
|
||||
BUILT_SOURCES =
|
||||
|
||||
CLEANFILES =
|
||||
DISTCLEANFILES =
|
||||
|
||||
lib_LTLIBRARIES =
|
||||
|
||||
gsk_public_source_h = \
|
||||
gskenums.h \
|
||||
gskrenderer.h \
|
||||
gskrendernode.h \
|
||||
gskrendernodeiter.h \
|
||||
gsktypes.h
|
||||
gsk_private_source_h = \
|
||||
gskcairorendererprivate.h \
|
||||
gskdebugprivate.h \
|
||||
gskgldriverprivate.h \
|
||||
gskglprofilerprivate.h \
|
||||
gskglrendererprivate.h \
|
||||
gskprivate.h \
|
||||
gskprofilerprivate.h \
|
||||
gskrendererprivate.h \
|
||||
gskrendernodeprivate.h \
|
||||
gskshaderbuilderprivate.h
|
||||
gsk_private_source_c = \
|
||||
gskprivate.c
|
||||
gsk_built_source_h = \
|
||||
gskenumtypes.h \
|
||||
gskresources.h
|
||||
gsk_built_source_c = \
|
||||
gskenumtypes.c \
|
||||
gskresources.c
|
||||
gsk_source_c = \
|
||||
gskcairorenderer.c \
|
||||
gskdebug.c \
|
||||
gskgldriver.c \
|
||||
gskglprofiler.c \
|
||||
gskglrenderer.c \
|
||||
gskprofiler.c \
|
||||
gskrenderer.c \
|
||||
gskrendernode.c \
|
||||
gskrendernodeiter.c \
|
||||
gskshaderbuilder.c
|
||||
|
||||
all_sources = \
|
||||
$(gsk_public_source_h) \
|
||||
$(gsk_private_source_h) \
|
||||
$(gsk_built_source_h) \
|
||||
$(gsk_private_source_c) \
|
||||
$(gsk_source_c)
|
||||
|
||||
BUILT_SOURCES += $(gsk_built_source_h) $(gsk_built_source_c) gsk.resources.xml
|
||||
|
||||
gskenumtypes.h: $(gsk_public_source_h) gskenumtypes.h.template
|
||||
$(AM_V_GEN) $(GLIB_MKENUMS) --template $(filter %.template,$^) $(filter-out %.template,$^) > \
|
||||
gskenumtypes.h.tmp && \
|
||||
mv gskenumtypes.h.tmp gskenumtypes.h
|
||||
|
||||
gskenumtypes.c: $(gsk_public_source_h) gskenumtypes.c.template
|
||||
$(AM_V_GEN) $(GLIB_MKENUMS) --template $(filter %.template,$^) $(filter-out %.template,$^) > \
|
||||
gskenumtypes.c.tmp && \
|
||||
mv gskenumtypes.c.tmp gskenumtypes.c
|
||||
|
||||
EXTRA_DIST += gskenumtypes.h.template gskenumtypes.c.template
|
||||
DISTCLEANFILES += gskenumtypes.h gskenumtypes.c
|
||||
|
||||
resource_files = $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --generate-dependencies $(builddir)/gsk.resources.xml)
|
||||
|
||||
gsk.resources.xml: Makefile.am
|
||||
$(AM_V_GEN) echo "<?xml version='1.0' encoding='UTF-8'?>" > $@; \
|
||||
echo "<gresources>" >> $@; \
|
||||
echo " <gresource prefix='/org/gtk/libgsk'>" >> $@; \
|
||||
for f in $(top_srcdir)/gsk/resources/glsl/*; do \
|
||||
n=`basename $$f`; \
|
||||
echo " <file alias='glsl/$$n'>resources/glsl/$$n</file>" >> $@; \
|
||||
done; \
|
||||
echo " </gresource>" >> $@; \
|
||||
echo "</gresources>" >> $@
|
||||
|
||||
gskresources.h: gsk.resources.xml
|
||||
$(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) $< \
|
||||
--target=$@ --sourcedir=$(srcdir) --c-name _gsk --generate-header --manual-register
|
||||
|
||||
gskresources.c: gsk.resources.xml $(resource_files)
|
||||
$(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) $< \
|
||||
--target=$@ --sourcedir=$(srcdir) --c-name _gsk --generate-source --manual-register
|
||||
|
||||
EXTRA_DIST += $(resource_files)
|
||||
CLEANFILES += gsk.resources.xml
|
||||
DISTCLEANFILES += gskresources.h gskresources.c
|
||||
|
||||
libgsk_4_la_SOURCES = $(all_sources)
|
||||
nodist_libgsk_4_la_SOURCES = $(gsk_built_source_h) $(gsk_built_source_c)
|
||||
libgsk_4_la_CFLAGS = $(AM_CFLAGS) $(GDK_HIDDEN_VISIBILITY_CFLAGS)
|
||||
libgsk_4_la_LIBADD = $(GSK_DEP_LIBS) $(top_builddir)/gdk/libgdk-4.la
|
||||
libgsk_4_la_LDFLAGS = $(LDADD)
|
||||
|
||||
lib_LTLIBRARIES += libgsk-4.la
|
||||
|
||||
gskincludedir = $(includedir)/gtk-4.0/gsk
|
||||
gskinclude_HEADERS = $(gsk_public_source_h) gskenumtypes.h gsk.h
|
||||
|
||||
-include $(INTROSPECTION_MAKEFILE)
|
||||
INTROSPECTION_GIRS =
|
||||
INTROSPECTION_SCANNER_ENV = \
|
||||
CC="$(CC)"
|
||||
INTROSPECTION_SCANNER_ARGS = \
|
||||
--add-include-path=../gdk \
|
||||
--warn-all
|
||||
INTROSPECTION_COMPILER_ARGS = \
|
||||
--includedir=$(srcdir) \
|
||||
--includedir=. \
|
||||
--includedir=../gdk
|
||||
|
||||
if HAVE_INTROSPECTION
|
||||
|
||||
introspection_files = $(filter-out $(wildcard *private.h),$(all_sources))
|
||||
|
||||
Gsk-4.0.gir: libgsk-4.la Makefile
|
||||
Gsk_4_0_gir_SCANNERFLAGS = \
|
||||
--add-include-path=$(top_builddir)/gdk \
|
||||
--include-uninstalled=$(top_builddir)/gdk/Gdk-4.0.gir \
|
||||
--c-include="gsk/gsk.h"
|
||||
Gsk_4_0_gir_LIBS = libgsk-4.la $(top_builddir)/gdk/libgdk-4.la
|
||||
Gsk_4_0_gir_FILES = $(introspection_files)
|
||||
Gsk_4_0_gir_CFLAGS = $(AM_CPPFLAGS)
|
||||
Gsk_4_0_gir_EXPORT_PACKAGES = gsk-4.0
|
||||
Gsk_4_0_gir_INCLUDES = GObject-2.0 cairo-1.0 Graphene-1.0
|
||||
INTROSPECTION_GIRS += Gsk-4.0.gir
|
||||
|
||||
girdir = $(datadir)/gir-1.0
|
||||
gir_DATA = $(INTROSPECTION_GIRS)
|
||||
|
||||
typelibsdir = $(libdir)/girepository-1.0
|
||||
typelibs_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
|
||||
|
||||
CLEANFILES += $(gir_DATA) $(typelibs_DATA)
|
||||
|
||||
endif
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
||||
@@ -0,0 +1,33 @@
|
||||
/* GSK - The GTK Scene Kit
|
||||
* Copyright 2016 Endless
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __GSK_H__
|
||||
#define __GSK_H__
|
||||
|
||||
#define __GSK_H_INSIDE__
|
||||
|
||||
#include <gsk/gskenums.h>
|
||||
#include <gsk/gskrenderer.h>
|
||||
#include <gsk/gskrendernode.h>
|
||||
#include <gsk/gskrendernodeiter.h>
|
||||
|
||||
#include <gsk/gsktypes.h>
|
||||
#include <gsk/gskenumtypes.h>
|
||||
|
||||
#undef __GSK_H_INSIDE__
|
||||
|
||||
#endif /* __GSK_H__ */
|
||||
@@ -0,0 +1,185 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gskcairorendererprivate.h"
|
||||
|
||||
#include "gskdebugprivate.h"
|
||||
#include "gskrendererprivate.h"
|
||||
#include "gskrendernodeiter.h"
|
||||
#include "gskrendernodeprivate.h"
|
||||
|
||||
struct _GskCairoRenderer
|
||||
{
|
||||
GskRenderer parent_instance;
|
||||
|
||||
graphene_rect_t viewport;
|
||||
};
|
||||
|
||||
struct _GskCairoRendererClass
|
||||
{
|
||||
GskRendererClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GskCairoRenderer, gsk_cairo_renderer, GSK_TYPE_RENDERER)
|
||||
|
||||
static gboolean
|
||||
gsk_cairo_renderer_realize (GskRenderer *renderer)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_cairo_renderer_unrealize (GskRenderer *renderer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_cairo_renderer_render_node (GskCairoRenderer *self,
|
||||
GskRenderNode *node,
|
||||
cairo_t *cr)
|
||||
{
|
||||
GskRenderNodeIter iter;
|
||||
GskRenderNode *child;
|
||||
gboolean pop_group = FALSE;
|
||||
graphene_matrix_t mvp;
|
||||
cairo_matrix_t ctm;
|
||||
graphene_rect_t frame;
|
||||
|
||||
if (gsk_render_node_is_hidden (node))
|
||||
return;
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
if (!gsk_render_node_has_surface (node))
|
||||
goto out;
|
||||
|
||||
gsk_render_node_get_world_matrix (node, &mvp);
|
||||
if (graphene_matrix_to_2d (&mvp, &ctm.xx, &ctm.yx, &ctm.xy, &ctm.yy, &ctm.x0, &ctm.y0))
|
||||
{
|
||||
GSK_NOTE (CAIRO, g_print ("CTM = { .xx = %g, .yx = %g, .xy = %g, .yy = %g, .x0 = %g, .y0 = %g }\n",
|
||||
ctm.xx, ctm.yx,
|
||||
ctm.xy, ctm.yy,
|
||||
ctm.x0, ctm.y0));
|
||||
cairo_transform (cr, &ctm);
|
||||
}
|
||||
else
|
||||
g_critical ("Invalid non-affine transformation for node %p", node);
|
||||
|
||||
gsk_render_node_get_bounds (node, &frame);
|
||||
GSK_NOTE (CAIRO, g_print ("CLIP = { .x = %g, .y = %g, .width = %g, .height = %g }\n",
|
||||
frame.origin.x, frame.origin.y,
|
||||
frame.size.width, frame.size.height));
|
||||
|
||||
if (!GSK_RENDER_MODE_CHECK (GEOMETRY))
|
||||
{
|
||||
cairo_rectangle (cr, frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
|
||||
cairo_clip (cr);
|
||||
}
|
||||
|
||||
if (!gsk_render_node_is_opaque (node) && gsk_render_node_get_opacity (node) != 1.0)
|
||||
{
|
||||
GSK_NOTE (CAIRO, g_print ("Pushing opacity group (opacity:%g)\n",
|
||||
gsk_render_node_get_opacity (node)));
|
||||
cairo_push_group (cr);
|
||||
pop_group = TRUE;
|
||||
}
|
||||
|
||||
GSK_NOTE (CAIRO, g_print ("Rendering surface %p for node %s[%p] at %g, %g\n",
|
||||
gsk_render_node_get_surface (node),
|
||||
node->name,
|
||||
node,
|
||||
frame.origin.x, frame.origin.y));
|
||||
cairo_set_source_surface (cr, gsk_render_node_get_surface (node), frame.origin.x, frame.origin.y);
|
||||
cairo_paint (cr);
|
||||
|
||||
if (GSK_RENDER_MODE_CHECK (GEOMETRY))
|
||||
{
|
||||
cairo_save (cr);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
||||
cairo_rectangle (cr, frame.origin.x - 1, frame.origin.y - 1, frame.size.width + 2, frame.size.height + 2);
|
||||
cairo_set_line_width (cr, 2);
|
||||
cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
|
||||
cairo_stroke (cr);
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
cairo_matrix_invert (&ctm);
|
||||
cairo_transform (cr, &ctm);
|
||||
|
||||
out:
|
||||
if (gsk_render_node_get_n_children (node) != 0)
|
||||
{
|
||||
GSK_NOTE (CAIRO, g_print ("Drawing %d children of node [%p]\n",
|
||||
gsk_render_node_get_n_children (node),
|
||||
node));
|
||||
gsk_render_node_iter_init (&iter, node);
|
||||
while (gsk_render_node_iter_next (&iter, &child))
|
||||
gsk_cairo_renderer_render_node (self, child, cr);
|
||||
}
|
||||
|
||||
if (pop_group)
|
||||
{
|
||||
cairo_pop_group_to_source (cr);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
||||
cairo_paint_with_alpha (cr, gsk_render_node_get_opacity (node));
|
||||
}
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_cairo_renderer_render (GskRenderer *renderer,
|
||||
GskRenderNode *root)
|
||||
{
|
||||
GskCairoRenderer *self = GSK_CAIRO_RENDERER (renderer);
|
||||
GdkDrawingContext *context = gsk_renderer_get_drawing_context (renderer);
|
||||
cairo_t *cr;
|
||||
|
||||
if (context != NULL)
|
||||
cr = gdk_drawing_context_get_cairo_context (context);
|
||||
else
|
||||
cr = gsk_renderer_get_cairo_context (renderer);
|
||||
|
||||
if (cr == NULL)
|
||||
return;
|
||||
|
||||
gsk_renderer_get_viewport (renderer, &self->viewport);
|
||||
|
||||
cairo_save (cr);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
||||
cairo_set_source_rgba (cr, 0, 0, 0, 0);
|
||||
cairo_paint (cr);
|
||||
cairo_restore (cr);
|
||||
|
||||
if (GSK_RENDER_MODE_CHECK (GEOMETRY))
|
||||
{
|
||||
cairo_save (cr);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
||||
cairo_rectangle (cr,
|
||||
self->viewport.origin.x,
|
||||
self->viewport.origin.y,
|
||||
self->viewport.size.width,
|
||||
self->viewport.size.height);
|
||||
cairo_set_source_rgba (cr, 0, 0, 0.85, 0.5);
|
||||
cairo_stroke (cr);
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
gsk_cairo_renderer_render_node (self, root, cr);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_cairo_renderer_class_init (GskCairoRendererClass *klass)
|
||||
{
|
||||
GskRendererClass *renderer_class = GSK_RENDERER_CLASS (klass);
|
||||
|
||||
renderer_class->realize = gsk_cairo_renderer_realize;
|
||||
renderer_class->unrealize = gsk_cairo_renderer_unrealize;
|
||||
renderer_class->render = gsk_cairo_renderer_render;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_cairo_renderer_init (GskCairoRenderer *self)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef __GSK_CAIRO_RENDERER_PRIVATE_H__
|
||||
#define __GSK_CAIRO_RENDERER_PRIVATE_H__
|
||||
|
||||
#include <cairo.h>
|
||||
#include <gsk/gskrenderer.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_CAIRO_RENDERER (gsk_cairo_renderer_get_type ())
|
||||
|
||||
#define GSK_CAIRO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_CAIRO_RENDERER, GskCairoRenderer))
|
||||
#define GSK_IS_CAIRO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_CAIRO_RENDERER))
|
||||
#define GSK_CAIRO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_CAIRO_RENDERER, GskCairoRendererClass))
|
||||
#define GSK_IS_CAIRO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_CAIRO_RENDERER))
|
||||
#define GSK_CAIRO_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_CAIRO_RENDERER, GskCairoRendererClass))
|
||||
|
||||
typedef struct _GskCairoRenderer GskCairoRenderer;
|
||||
typedef struct _GskCairoRendererClass GskCairoRendererClass;
|
||||
|
||||
GType gsk_cairo_renderer_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GskRenderer *gsk_cairo_renderer_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_CAIRO_RENDERER_PRIVATE_H__ */
|
||||
@@ -0,0 +1,62 @@
|
||||
#include "gskdebugprivate.h"
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
static const GDebugKey gsk_debug_keys[] = {
|
||||
{ "rendernode", GSK_DEBUG_RENDER_NODE },
|
||||
{ "renderer", GSK_DEBUG_RENDERER },
|
||||
{ "cairo", GSK_DEBUG_CAIRO },
|
||||
{ "opengl", GSK_DEBUG_OPENGL },
|
||||
{ "shaders", GSK_DEBUG_SHADERS },
|
||||
{ "transforms", GSK_DEBUG_TRANSFORMS },
|
||||
{ "surface", GSK_DEBUG_SURFACE }
|
||||
};
|
||||
#endif
|
||||
|
||||
static const GDebugKey gsk_rendering_keys[] = {
|
||||
{ "geometry", GSK_RENDERING_MODE_GEOMETRY },
|
||||
{ "shaders", GSK_RENDERING_MODE_SHADERS },
|
||||
};
|
||||
|
||||
gboolean
|
||||
gsk_check_debug_flags (GskDebugFlags flags)
|
||||
{
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
static volatile gsize gsk_debug_flags__set;
|
||||
static guint gsk_debug_flags;
|
||||
|
||||
if (g_once_init_enter (&gsk_debug_flags__set))
|
||||
{
|
||||
const char *env = g_getenv ("GSK_DEBUG");
|
||||
|
||||
gsk_debug_flags = g_parse_debug_string (env,
|
||||
(GDebugKey *) gsk_debug_keys,
|
||||
G_N_ELEMENTS (gsk_debug_keys));
|
||||
|
||||
g_once_init_leave (&gsk_debug_flags__set, TRUE);
|
||||
}
|
||||
|
||||
return (gsk_debug_flags & flags) != 0;
|
||||
#else
|
||||
return FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
gboolean
|
||||
gsk_check_rendering_flags (GskRenderingMode flags)
|
||||
{
|
||||
static volatile gsize gsk_rendering_flags__set;
|
||||
static guint gsk_rendering_flags;
|
||||
|
||||
if (g_once_init_enter (&gsk_rendering_flags__set))
|
||||
{
|
||||
const char *env = g_getenv ("GSK_RENDERING_MODE");
|
||||
|
||||
gsk_rendering_flags = g_parse_debug_string (env,
|
||||
(GDebugKey *) gsk_rendering_keys,
|
||||
G_N_ELEMENTS (gsk_rendering_keys));
|
||||
|
||||
g_once_init_leave (&gsk_rendering_flags__set, TRUE);
|
||||
}
|
||||
|
||||
return (gsk_rendering_flags & flags) != 0;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
#ifndef __GSK_DEBUG_PRIVATE_H__
|
||||
#define __GSK_DEBUG_PRIVATE_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum {
|
||||
GSK_DEBUG_RENDER_NODE = 1 << 0,
|
||||
GSK_DEBUG_RENDERER = 1 << 1,
|
||||
GSK_DEBUG_CAIRO = 1 << 2,
|
||||
GSK_DEBUG_OPENGL = 1 << 3,
|
||||
GSK_DEBUG_SHADERS = 1 << 4,
|
||||
GSK_DEBUG_TRANSFORMS = 1 << 5,
|
||||
GSK_DEBUG_SURFACE = 1 << 6
|
||||
} GskDebugFlags;
|
||||
|
||||
typedef enum {
|
||||
GSK_RENDERING_MODE_GEOMETRY = 1 << 0,
|
||||
GSK_RENDERING_MODE_SHADERS = 1 << 1
|
||||
} GskRenderingMode;
|
||||
|
||||
gboolean gsk_check_debug_flags (GskDebugFlags flags);
|
||||
|
||||
gboolean gsk_check_rendering_flags (GskRenderingMode flags);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
|
||||
#define GSK_DEBUG_CHECK(type) G_UNLIKELY (gsk_check_debug_flags (GSK_DEBUG_ ## type))
|
||||
#define GSK_DEBUG_CHECK2(type1,type2) G_UNLIKELY (gsk_check_debug_flags (GSK_DEBUG_ ## type1 | GSK_DEBUG_ ## type2))
|
||||
#define GSK_RENDER_MODE_CHECK(type) G_UNLIKELY (gsk_check_rendering_flags (GSK_RENDERING_MODE_ ## type))
|
||||
|
||||
#define GSK_NOTE(type,action) G_STMT_START { \
|
||||
if (GSK_DEBUG_CHECK (type)) { \
|
||||
action; \
|
||||
} } G_STMT_END
|
||||
|
||||
#define GSK_NOTE2(type1,type2,action) G_STMT_START { \
|
||||
if (GSK_DEBUG_CHECK2 (type1, type2)) { \
|
||||
action; \
|
||||
} } G_STMT_END
|
||||
#else
|
||||
|
||||
#define GSK_RENDER_MODE_CHECK(type) 0
|
||||
#define GSK_DEBUG_CHECK(type) 0
|
||||
#define GSK_DEBUG_CHECK2(type1,type2) 0
|
||||
#define GSK_NOTE(type,action)
|
||||
#define GSK_NOTE2(type1,type2,action)
|
||||
|
||||
#endif
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_DEBUG_PRIVATE_H__ */
|
||||
@@ -0,0 +1,85 @@
|
||||
/* GSK - The GTK Scene Kit
|
||||
* Copyright 2016 Endless
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __GSK_ENUMS_H__
|
||||
#define __GSK_ENUMS_H__
|
||||
|
||||
#if !defined (__GSK_H_INSIDE__) && !defined (GSK_COMPILATION)
|
||||
#error "Only <gsk/gsk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
/**
|
||||
* GskScalingFilter:
|
||||
* @GSK_SCALING_FILTER_LINEAR: linear interpolation filter
|
||||
* @GSK_SCALING_FILTER_NEAREST: nearest neighbor interpolation filter
|
||||
* @GSK_SCALING_FILTER_TRILINEAR: linear interpolation along each axis,
|
||||
* plus mipmap generation, with linear interpolation along the mipmap
|
||||
* levels
|
||||
*
|
||||
* The filters used when scaling texture data.
|
||||
*
|
||||
* The actual implementation of each filter is deferred to the
|
||||
* rendering pipeline.
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
typedef enum {
|
||||
GSK_SCALING_FILTER_LINEAR,
|
||||
GSK_SCALING_FILTER_NEAREST,
|
||||
GSK_SCALING_FILTER_TRILINEAR
|
||||
} GskScalingFilter;
|
||||
|
||||
/**
|
||||
* GskBlendMode:
|
||||
* @GSK_BLEND_MODE_DEFAULT: The default blend mode, which specifies no blending
|
||||
* @GSK_BLEND_MODE_MULTIPLY: The source color is multiplied by the destination
|
||||
* and replaces the destination
|
||||
* @GSK_BLEND_MODE_SCREEN: ...
|
||||
* @GSK_BLEND_MODE_OVERLAY: ...
|
||||
* @GSK_BLEND_MODE_DARKEN: ...
|
||||
* @GSK_BLEND_MODE_LIGHTEN: ...
|
||||
* @GSK_BLEND_MODE_COLOR_DODGE: ...
|
||||
* @GSK_BLEND_MODE_COLOR_BURN: ...
|
||||
* @GSK_BLEND_MODE_HARD_LIGHT: ...
|
||||
* @GSK_BLEND_MODE_SOFT_LIGHT: ...
|
||||
* @GSK_BLEND_MODE_DIFFERENCE: ...
|
||||
* @GSK_BLEND_MODE_EXCLUSION: ...
|
||||
*
|
||||
* The blend modes available for render nodes.
|
||||
*
|
||||
* The implementation of each blend mode is deferred to the
|
||||
* rendering pipeline.
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
typedef enum {
|
||||
GSK_BLEND_MODE_DEFAULT = 0,
|
||||
|
||||
GSK_BLEND_MODE_MULTIPLY,
|
||||
GSK_BLEND_MODE_SCREEN,
|
||||
GSK_BLEND_MODE_OVERLAY,
|
||||
GSK_BLEND_MODE_DARKEN,
|
||||
GSK_BLEND_MODE_LIGHTEN,
|
||||
GSK_BLEND_MODE_COLOR_DODGE,
|
||||
GSK_BLEND_MODE_COLOR_BURN,
|
||||
GSK_BLEND_MODE_HARD_LIGHT,
|
||||
GSK_BLEND_MODE_SOFT_LIGHT,
|
||||
GSK_BLEND_MODE_DIFFERENCE,
|
||||
GSK_BLEND_MODE_EXCLUSION
|
||||
} GskBlendMode;
|
||||
|
||||
#endif /* __GSK_TYPES_H__ */
|
||||
@@ -0,0 +1,38 @@
|
||||
/*** BEGIN file-header ***/
|
||||
#include "config.h"
|
||||
#include "gskenumtypes.h"
|
||||
#include <gsk.h>
|
||||
|
||||
/*** END file-header ***/
|
||||
|
||||
/*** BEGIN file-production ***/
|
||||
/* enumerations from "@filename@" */
|
||||
/*** END file-production ***/
|
||||
|
||||
/*** BEGIN value-header ***/
|
||||
GType
|
||||
@enum_name@_get_type (void)
|
||||
{
|
||||
static volatile gsize g_define_type_id__volatile = 0;
|
||||
|
||||
if (g_once_init_enter (&g_define_type_id__volatile))
|
||||
{
|
||||
static const G@Type@Value values[] = {
|
||||
/*** END value-header ***/
|
||||
|
||||
/*** BEGIN value-production ***/
|
||||
{ @VALUENAME@, "@VALUENAME@", "@valuenick@" },
|
||||
/*** END value-production ***/
|
||||
|
||||
/*** BEGIN value-tail ***/
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
GType g_define_type_id =
|
||||
g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
|
||||
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
|
||||
}
|
||||
|
||||
return g_define_type_id__volatile;
|
||||
}
|
||||
|
||||
/*** END value-tail ***/
|
||||
@@ -0,0 +1,24 @@
|
||||
/*** BEGIN file-header ***/
|
||||
#ifndef __GSK_ENUM_TYPES_H__
|
||||
#define __GSK_ENUM_TYPES_H__
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
/*** END file-header ***/
|
||||
|
||||
/*** BEGIN file-production ***/
|
||||
|
||||
/* enumerations from "@filename@" */
|
||||
/*** END file-production ***/
|
||||
|
||||
/*** BEGIN value-header ***/
|
||||
GDK_AVAILABLE_IN_ALL GType @enum_name@_get_type (void) G_GNUC_CONST;
|
||||
#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
|
||||
/*** END value-header ***/
|
||||
|
||||
/*** BEGIN file-tail ***/
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_ENUM_TYPES_H__ */
|
||||
/*** END file-tail ***/
|
||||
@@ -0,0 +1,751 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gskgldriverprivate.h"
|
||||
|
||||
#include "gskdebugprivate.h"
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
typedef struct {
|
||||
GLuint texture_id;
|
||||
int width;
|
||||
int height;
|
||||
GLuint min_filter;
|
||||
GLuint mag_filter;
|
||||
GArray *fbos;
|
||||
gboolean in_use : 1;
|
||||
} Texture;
|
||||
|
||||
typedef struct {
|
||||
GLuint vao_id;
|
||||
GLuint buffer_id;
|
||||
GLuint position_id;
|
||||
GLuint uv_id;
|
||||
GskQuadVertex *quads;
|
||||
int n_quads;
|
||||
gboolean in_use : 1;
|
||||
} Vao;
|
||||
|
||||
typedef struct {
|
||||
GLuint fbo_id;
|
||||
GLuint depth_stencil_id;
|
||||
} Fbo;
|
||||
|
||||
struct _GskGLDriver
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GdkGLContext *gl_context;
|
||||
|
||||
Fbo default_fbo;
|
||||
|
||||
GHashTable *textures;
|
||||
GHashTable *vaos;
|
||||
|
||||
Texture *bound_source_texture;
|
||||
Texture *bound_mask_texture;
|
||||
Vao *bound_vao;
|
||||
Fbo *bound_fbo;
|
||||
|
||||
gboolean in_frame : 1;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_GL_CONTEXT = 1,
|
||||
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *gsk_gl_driver_properties[N_PROPS];
|
||||
|
||||
G_DEFINE_TYPE (GskGLDriver, gsk_gl_driver, G_TYPE_OBJECT)
|
||||
|
||||
static Texture *
|
||||
texture_new (void)
|
||||
{
|
||||
return g_slice_new0 (Texture);
|
||||
}
|
||||
|
||||
static void
|
||||
texture_free (gpointer data)
|
||||
{
|
||||
Texture *t = data;
|
||||
|
||||
g_clear_pointer (&t->fbos, g_array_unref);
|
||||
glDeleteTextures (1, &t->texture_id);
|
||||
g_slice_free (Texture, t);
|
||||
}
|
||||
|
||||
static void
|
||||
fbo_clear (gpointer data)
|
||||
{
|
||||
Fbo *f = data;
|
||||
|
||||
if (f->depth_stencil_id != 0)
|
||||
glDeleteRenderbuffers (1, &f->depth_stencil_id);
|
||||
|
||||
glDeleteFramebuffers (1, &f->fbo_id);
|
||||
}
|
||||
|
||||
static Vao *
|
||||
vao_new (void)
|
||||
{
|
||||
return g_slice_new0 (Vao);
|
||||
}
|
||||
|
||||
static void
|
||||
vao_free (gpointer data)
|
||||
{
|
||||
Vao *v = data;
|
||||
|
||||
g_free (v->quads);
|
||||
glDeleteBuffers (1, &v->buffer_id);
|
||||
glDeleteVertexArrays (1, &v->vao_id);
|
||||
g_slice_free (Vao, v);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_driver_finalize (GObject *gobject)
|
||||
{
|
||||
GskGLDriver *self = GSK_GL_DRIVER (gobject);
|
||||
|
||||
gdk_gl_context_make_current (self->gl_context);
|
||||
|
||||
g_clear_pointer (&self->textures, g_hash_table_unref);
|
||||
g_clear_pointer (&self->vaos, g_hash_table_unref);
|
||||
|
||||
if (self->gl_context == gdk_gl_context_get_current ())
|
||||
gdk_gl_context_clear_current ();
|
||||
|
||||
g_clear_object (&self->gl_context);
|
||||
|
||||
G_OBJECT_CLASS (gsk_gl_driver_parent_class)->finalize (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_driver_set_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GskGLDriver *self = GSK_GL_DRIVER (gobject);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_GL_CONTEXT:
|
||||
self->gl_context = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_driver_get_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GskGLDriver *self = GSK_GL_DRIVER (gobject);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_GL_CONTEXT:
|
||||
g_value_set_object (value, self->gl_context);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_driver_class_init (GskGLDriverClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->set_property = gsk_gl_driver_set_property;
|
||||
gobject_class->get_property = gsk_gl_driver_get_property;
|
||||
gobject_class->finalize = gsk_gl_driver_finalize;
|
||||
|
||||
gsk_gl_driver_properties[PROP_GL_CONTEXT] =
|
||||
g_param_spec_object ("gl-context", "GL Context", "The GL context used by the driver",
|
||||
GDK_TYPE_GL_CONTEXT,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPS, gsk_gl_driver_properties);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_driver_init (GskGLDriver *self)
|
||||
{
|
||||
self->textures = g_hash_table_new_full (NULL, NULL, NULL, texture_free);
|
||||
self->vaos = g_hash_table_new_full (NULL, NULL, NULL, vao_free);
|
||||
}
|
||||
|
||||
GskGLDriver *
|
||||
gsk_gl_driver_new (GdkGLContext *context)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
|
||||
|
||||
return g_object_new (GSK_TYPE_GL_DRIVER,
|
||||
"gl-context", context,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_driver_begin_frame (GskGLDriver *driver)
|
||||
{
|
||||
g_return_if_fail (GSK_IS_GL_DRIVER (driver));
|
||||
g_return_if_fail (!driver->in_frame);
|
||||
|
||||
driver->in_frame = TRUE;
|
||||
|
||||
glGetIntegerv (GL_FRAMEBUFFER_BINDING, (GLint *) &(driver->default_fbo.fbo_id));
|
||||
driver->bound_fbo = &driver->default_fbo;
|
||||
|
||||
glActiveTexture (GL_TEXTURE0);
|
||||
glBindTexture (GL_TEXTURE_2D, 0);
|
||||
|
||||
glActiveTexture (GL_TEXTURE0 + 1);
|
||||
glBindTexture (GL_TEXTURE_2D, 0);
|
||||
|
||||
glBindVertexArray (0);
|
||||
glUseProgram (0);
|
||||
|
||||
glActiveTexture (GL_TEXTURE0);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_driver_end_frame (GskGLDriver *driver)
|
||||
{
|
||||
g_return_if_fail (GSK_IS_GL_DRIVER (driver));
|
||||
g_return_if_fail (driver->in_frame);
|
||||
|
||||
glBindTexture (GL_TEXTURE_2D, 0);
|
||||
glUseProgram (0);
|
||||
glBindVertexArray (0);
|
||||
|
||||
driver->bound_source_texture = NULL;
|
||||
driver->bound_mask_texture = NULL;
|
||||
driver->bound_vao = NULL;
|
||||
driver->bound_fbo = NULL;
|
||||
|
||||
GSK_NOTE (OPENGL,
|
||||
g_print ("*** Frame end: textures=%d, vaos=%d\n",
|
||||
g_hash_table_size (driver->textures),
|
||||
g_hash_table_size (driver->vaos)));
|
||||
|
||||
driver->in_frame = FALSE;
|
||||
}
|
||||
|
||||
int
|
||||
gsk_gl_driver_collect_textures (GskGLDriver *driver)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
gpointer value_p = NULL;
|
||||
int old_size;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), 0);
|
||||
g_return_val_if_fail (!driver->in_frame, 0);
|
||||
|
||||
old_size = g_hash_table_size (driver->textures);
|
||||
|
||||
g_hash_table_iter_init (&iter, driver->textures);
|
||||
while (g_hash_table_iter_next (&iter, NULL, &value_p))
|
||||
{
|
||||
Texture *t = value_p;
|
||||
|
||||
if (t->in_use)
|
||||
{
|
||||
t->in_use = FALSE;
|
||||
g_clear_pointer (&t->fbos, g_array_unref);
|
||||
}
|
||||
else
|
||||
g_hash_table_iter_remove (&iter);
|
||||
}
|
||||
|
||||
return old_size - g_hash_table_size (driver->textures);
|
||||
}
|
||||
|
||||
int
|
||||
gsk_gl_driver_collect_vaos (GskGLDriver *driver)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
gpointer value_p = NULL;
|
||||
int old_size;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), 0);
|
||||
g_return_val_if_fail (!driver->in_frame, 0);
|
||||
|
||||
old_size = g_hash_table_size (driver->vaos);
|
||||
|
||||
g_hash_table_iter_init (&iter, driver->vaos);
|
||||
while (g_hash_table_iter_next (&iter, NULL, &value_p))
|
||||
{
|
||||
Vao *v = value_p;
|
||||
|
||||
if (v->in_use)
|
||||
v->in_use = FALSE;
|
||||
else
|
||||
g_hash_table_iter_remove (&iter);
|
||||
}
|
||||
|
||||
return old_size - g_hash_table_size (driver->vaos);
|
||||
}
|
||||
|
||||
static Texture *
|
||||
gsk_gl_driver_get_texture (GskGLDriver *driver,
|
||||
int texture_id)
|
||||
{
|
||||
Texture *t;
|
||||
|
||||
if (g_hash_table_lookup_extended (driver->textures, GINT_TO_POINTER (texture_id), NULL, (gpointer *) &t))
|
||||
return t;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Vao *
|
||||
gsk_gl_driver_get_vao (GskGLDriver *driver,
|
||||
int vao_id)
|
||||
{
|
||||
Vao *v;
|
||||
|
||||
if (g_hash_table_lookup_extended (driver->vaos, GINT_TO_POINTER (vao_id), NULL, (gpointer *) &v))
|
||||
return v;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Fbo *
|
||||
gsk_gl_driver_get_fbo (GskGLDriver *driver,
|
||||
int texture_id)
|
||||
{
|
||||
Texture *t = gsk_gl_driver_get_texture (driver, texture_id);
|
||||
|
||||
if (t->fbos == NULL)
|
||||
return &driver->default_fbo;
|
||||
|
||||
return &g_array_index (t->fbos, Fbo, 0);
|
||||
}
|
||||
|
||||
static Texture *
|
||||
find_texture_by_size (GHashTable *textures,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
gpointer value_p = NULL;
|
||||
|
||||
g_hash_table_iter_init (&iter, textures);
|
||||
while (g_hash_table_iter_next (&iter, NULL, &value_p))
|
||||
{
|
||||
Texture *t = value_p;
|
||||
|
||||
if (t->width == width && t->height == height)
|
||||
return t;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
gsk_gl_driver_create_texture (GskGLDriver *driver,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
guint texture_id;
|
||||
Texture *t;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), -1);
|
||||
|
||||
t = find_texture_by_size (driver->textures, width, height);
|
||||
if (t != NULL && !t->in_use)
|
||||
{
|
||||
GSK_NOTE (OPENGL, g_print ("Reusing Texture(%d) for size %dx%d\n",
|
||||
t->texture_id, t->width, t->height));
|
||||
t->in_use = TRUE;
|
||||
return t->texture_id;
|
||||
}
|
||||
|
||||
glGenTextures (1, &texture_id);
|
||||
|
||||
t = texture_new ();
|
||||
t->texture_id = texture_id;
|
||||
t->width = width;
|
||||
t->height = height;
|
||||
t->min_filter = GL_NEAREST;
|
||||
t->mag_filter = GL_NEAREST;
|
||||
t->in_use = TRUE;
|
||||
g_hash_table_insert (driver->textures, GINT_TO_POINTER (texture_id), t);
|
||||
|
||||
return t->texture_id;
|
||||
}
|
||||
|
||||
static Vao *
|
||||
find_vao (GHashTable *vaos,
|
||||
int position_id,
|
||||
int uv_id,
|
||||
int n_quads,
|
||||
GskQuadVertex *quads)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
gpointer value_p = NULL;
|
||||
|
||||
g_hash_table_iter_init (&iter, vaos);
|
||||
while (g_hash_table_iter_next (&iter, NULL, &value_p))
|
||||
{
|
||||
Vao *v = value_p;
|
||||
|
||||
if (v->position_id != position_id || v->uv_id != uv_id)
|
||||
continue;
|
||||
|
||||
if (v->n_quads != n_quads)
|
||||
continue;
|
||||
|
||||
if (memcmp (v->quads, quads, sizeof (GskQuadVertex) * n_quads) == 0)
|
||||
return v;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
gsk_gl_driver_create_vao_for_quad (GskGLDriver *driver,
|
||||
int position_id,
|
||||
int uv_id,
|
||||
int n_quads,
|
||||
GskQuadVertex *quads)
|
||||
|
||||
{
|
||||
GLuint vao_id, buffer_id;
|
||||
Vao *v;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), -1);
|
||||
g_return_val_if_fail (driver->in_frame, -1);
|
||||
|
||||
v = find_vao (driver->vaos, position_id, uv_id, n_quads, quads);
|
||||
if (v != NULL && !v->in_use)
|
||||
{
|
||||
GSK_NOTE (OPENGL, g_print ("Reusing VAO(%d)\n", v->vao_id));
|
||||
v->in_use = TRUE;
|
||||
return v->vao_id;
|
||||
}
|
||||
|
||||
glGenVertexArrays (1, &vao_id);
|
||||
glBindVertexArray (vao_id);
|
||||
|
||||
glGenBuffers (1, &buffer_id);
|
||||
glBindBuffer (GL_ARRAY_BUFFER, buffer_id);
|
||||
glBufferData (GL_ARRAY_BUFFER, sizeof (GskQuadVertex) * n_quads, quads, GL_STATIC_DRAW);
|
||||
|
||||
glEnableVertexAttribArray (position_id);
|
||||
glVertexAttribPointer (position_id, 2, GL_FLOAT, GL_FALSE,
|
||||
sizeof (GskQuadVertex),
|
||||
(void *) G_STRUCT_OFFSET (GskQuadVertex, position));
|
||||
|
||||
glEnableVertexAttribArray (uv_id);
|
||||
glVertexAttribPointer (uv_id, 2, GL_FLOAT, GL_FALSE,
|
||||
sizeof (GskQuadVertex),
|
||||
(void *) G_STRUCT_OFFSET (GskQuadVertex, uv));
|
||||
|
||||
glBindBuffer (GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray (0);
|
||||
|
||||
v = vao_new ();
|
||||
v->vao_id = vao_id;
|
||||
v->buffer_id = buffer_id;
|
||||
v->position_id = position_id;
|
||||
v->uv_id = uv_id;
|
||||
v->n_quads = n_quads;
|
||||
v->quads = g_memdup (quads, sizeof (GskQuadVertex) * n_quads);
|
||||
v->in_use = TRUE;
|
||||
g_hash_table_insert (driver->vaos, GINT_TO_POINTER (vao_id), v);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
if (GSK_DEBUG_CHECK (OPENGL))
|
||||
{
|
||||
int i;
|
||||
g_print ("New VAO(%d) for quad[%d] : {\n", v->vao_id, n_quads);
|
||||
for (i = 0; i < n_quads; i++)
|
||||
{
|
||||
g_print (" { x:%.2f, y:%.2f } { u:%.2f, v:%.2f }\n",
|
||||
quads[i].position[0], quads[i].position[1],
|
||||
quads[i].uv[0], quads[i].uv[1]);
|
||||
}
|
||||
g_print ("}\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
return vao_id;
|
||||
}
|
||||
|
||||
int
|
||||
gsk_gl_driver_create_render_target (GskGLDriver *driver,
|
||||
int texture_id,
|
||||
gboolean add_depth_buffer,
|
||||
gboolean add_stencil_buffer)
|
||||
{
|
||||
GLuint fbo_id, depth_stencil_buffer_id;
|
||||
Texture *t;
|
||||
Fbo f;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), -1);
|
||||
g_return_val_if_fail (driver->in_frame, -1);
|
||||
|
||||
t = gsk_gl_driver_get_texture (driver, texture_id);
|
||||
if (t == NULL)
|
||||
return -1;
|
||||
|
||||
if (t->fbos == NULL)
|
||||
{
|
||||
t->fbos = g_array_new (FALSE, FALSE, sizeof (Fbo));
|
||||
g_array_set_clear_func (t->fbos, fbo_clear);
|
||||
}
|
||||
|
||||
glGenFramebuffers (1, &fbo_id);
|
||||
glBindFramebuffer (GL_FRAMEBUFFER, fbo_id);
|
||||
glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, t->texture_id, 0);
|
||||
|
||||
if (add_depth_buffer || add_stencil_buffer)
|
||||
glGenRenderbuffersEXT (1, &depth_stencil_buffer_id);
|
||||
else
|
||||
depth_stencil_buffer_id = 0;
|
||||
|
||||
glBindRenderbuffer (GL_RENDERBUFFER, depth_stencil_buffer_id);
|
||||
|
||||
if (add_depth_buffer || add_stencil_buffer)
|
||||
{
|
||||
if (add_stencil_buffer)
|
||||
glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, t->width, t->height);
|
||||
else
|
||||
glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, t->width, t->height);
|
||||
|
||||
if (add_depth_buffer)
|
||||
glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
|
||||
GL_RENDERBUFFER, depth_stencil_buffer_id);
|
||||
|
||||
if (add_stencil_buffer)
|
||||
glFramebufferRenderbufferEXT (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
|
||||
GL_RENDERBUFFER, depth_stencil_buffer_id);
|
||||
}
|
||||
|
||||
f.fbo_id = fbo_id;
|
||||
f.depth_stencil_id = depth_stencil_buffer_id;
|
||||
|
||||
g_array_append_val (t->fbos, f);
|
||||
|
||||
glBindFramebuffer (GL_FRAMEBUFFER, driver->default_fbo.fbo_id);
|
||||
|
||||
return fbo_id;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_driver_bind_source_texture (GskGLDriver *driver,
|
||||
int texture_id)
|
||||
{
|
||||
Texture *t;
|
||||
|
||||
g_return_if_fail (GSK_IS_GL_DRIVER (driver));
|
||||
g_return_if_fail (driver->in_frame);
|
||||
|
||||
t = gsk_gl_driver_get_texture (driver, texture_id);
|
||||
if (t == NULL)
|
||||
{
|
||||
g_critical ("No texture %d found.", texture_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (driver->bound_source_texture != t)
|
||||
{
|
||||
glActiveTexture (GL_TEXTURE0);
|
||||
glBindTexture (GL_TEXTURE_2D, t->texture_id);
|
||||
|
||||
driver->bound_source_texture = t;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_driver_bind_mask_texture (GskGLDriver *driver,
|
||||
int texture_id)
|
||||
{
|
||||
Texture *t;
|
||||
|
||||
g_return_if_fail (GSK_IS_GL_DRIVER (driver));
|
||||
g_return_if_fail (driver->in_frame);
|
||||
|
||||
t = gsk_gl_driver_get_texture (driver, texture_id);
|
||||
if (t == NULL)
|
||||
{
|
||||
g_critical ("No texture %d found.", texture_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (driver->bound_mask_texture != t)
|
||||
{
|
||||
glActiveTexture (GL_TEXTURE0 + 1);
|
||||
glBindTexture (GL_TEXTURE_2D, t->texture_id);
|
||||
|
||||
glActiveTexture (GL_TEXTURE0);
|
||||
|
||||
driver->bound_mask_texture = t;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_driver_bind_vao (GskGLDriver *driver,
|
||||
int vao_id)
|
||||
{
|
||||
Vao *v;
|
||||
|
||||
g_return_if_fail (GSK_IS_GL_DRIVER (driver));
|
||||
g_return_if_fail (driver->in_frame);
|
||||
|
||||
v = gsk_gl_driver_get_vao (driver, vao_id);
|
||||
if (v == NULL)
|
||||
{
|
||||
g_critical ("No VAO %d found.", vao_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (driver->bound_vao != v)
|
||||
{
|
||||
glBindVertexArray (v->vao_id);
|
||||
glBindBuffer (GL_ARRAY_BUFFER, v->buffer_id);
|
||||
glEnableVertexAttribArray (v->position_id);
|
||||
glEnableVertexAttribArray (v->uv_id);
|
||||
|
||||
driver->bound_vao = v;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
gsk_gl_driver_bind_render_target (GskGLDriver *driver,
|
||||
int texture_id)
|
||||
{
|
||||
int status;
|
||||
Fbo *f;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), FALSE);
|
||||
g_return_val_if_fail (driver->in_frame, FALSE);
|
||||
|
||||
f = gsk_gl_driver_get_fbo (driver, texture_id);
|
||||
if (f == NULL)
|
||||
{
|
||||
g_critical ("No render target associated to texture %d found.", texture_id);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (f != driver->bound_fbo)
|
||||
{
|
||||
glBindFramebuffer (GL_FRAMEBUFFER, f->fbo_id);
|
||||
|
||||
driver->bound_fbo = f;
|
||||
}
|
||||
|
||||
status = glCheckFramebufferStatus (GL_FRAMEBUFFER);
|
||||
|
||||
return status == GL_FRAMEBUFFER_COMPLETE;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_driver_destroy_texture (GskGLDriver *driver,
|
||||
int texture_id)
|
||||
{
|
||||
g_return_if_fail (GSK_IS_GL_DRIVER (driver));
|
||||
|
||||
g_hash_table_remove (driver->textures, GINT_TO_POINTER (texture_id));
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_driver_destroy_vao (GskGLDriver *driver,
|
||||
int vao_id)
|
||||
{
|
||||
g_return_if_fail (GSK_IS_GL_DRIVER (driver));
|
||||
|
||||
g_hash_table_remove (driver->vaos, GINT_TO_POINTER (vao_id));
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_driver_set_texture_parameters (GskGLDriver *driver,
|
||||
int min_filter,
|
||||
int mag_filter)
|
||||
{
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
|
||||
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_driver_init_texture_empty (GskGLDriver *driver,
|
||||
int texture_id)
|
||||
{
|
||||
Texture *t;
|
||||
|
||||
g_return_if_fail (GSK_IS_GL_DRIVER (driver));
|
||||
|
||||
t = gsk_gl_driver_get_texture (driver, texture_id);
|
||||
if (t == NULL)
|
||||
{
|
||||
g_critical ("No texture %d found.", texture_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(driver->bound_source_texture == t || driver->bound_mask_texture == t))
|
||||
{
|
||||
g_critical ("You must bind the texture before initializing it.");
|
||||
return;
|
||||
}
|
||||
|
||||
gsk_gl_driver_set_texture_parameters (driver, t->min_filter, t->mag_filter);
|
||||
|
||||
if (gdk_gl_context_get_use_es (driver->gl_context))
|
||||
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, t->width, t->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
else
|
||||
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, t->width, t->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
glBindTexture (GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_driver_init_texture_with_surface (GskGLDriver *driver,
|
||||
int texture_id,
|
||||
cairo_surface_t *surface,
|
||||
int min_filter,
|
||||
int mag_filter)
|
||||
{
|
||||
Texture *t;
|
||||
|
||||
g_return_if_fail (GSK_IS_GL_DRIVER (driver));
|
||||
|
||||
t = gsk_gl_driver_get_texture (driver, texture_id);
|
||||
if (t == NULL)
|
||||
{
|
||||
g_critical ("No texture %d found.", texture_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(driver->bound_source_texture == t || driver->bound_mask_texture == t))
|
||||
{
|
||||
g_critical ("You must bind the texture before initializing it.");
|
||||
return;
|
||||
}
|
||||
|
||||
gsk_gl_driver_set_texture_parameters (driver, min_filter, mag_filter);
|
||||
|
||||
gdk_cairo_surface_upload_to_gl (surface, GL_TEXTURE_2D, t->width, t->height, NULL);
|
||||
|
||||
t->min_filter = min_filter;
|
||||
t->mag_filter = mag_filter;
|
||||
|
||||
if (t->min_filter != GL_NEAREST)
|
||||
glGenerateMipmap (GL_TEXTURE_2D);
|
||||
|
||||
glBindTexture (GL_TEXTURE_2D, 0);
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
#ifndef __GSK_GL_DRIVER_PRIVATE_H__
|
||||
#define __GSK_GL_DRIVER_PRIVATE_H__
|
||||
|
||||
#include <cairo.h>
|
||||
#include <gdk/gdk.h>
|
||||
#include <graphene.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_GL_DRIVER (gsk_gl_driver_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (GskGLDriver, gsk_gl_driver, GSK, GL_DRIVER, GObject)
|
||||
|
||||
typedef struct {
|
||||
float position[2];
|
||||
float uv[2];
|
||||
} GskQuadVertex;
|
||||
|
||||
GskGLDriver * gsk_gl_driver_new (GdkGLContext *context);
|
||||
|
||||
void gsk_gl_driver_begin_frame (GskGLDriver *driver);
|
||||
void gsk_gl_driver_end_frame (GskGLDriver *driver);
|
||||
|
||||
int gsk_gl_driver_create_texture (GskGLDriver *driver,
|
||||
int width,
|
||||
int height);
|
||||
int gsk_gl_driver_create_vao_for_quad (GskGLDriver *driver,
|
||||
int position_id,
|
||||
int uv_id,
|
||||
int n_vertices,
|
||||
GskQuadVertex *vertices);
|
||||
int gsk_gl_driver_create_render_target (GskGLDriver *driver,
|
||||
int texture_id,
|
||||
gboolean add_depth_buffer,
|
||||
gboolean add_stencil_buffer);
|
||||
|
||||
void gsk_gl_driver_bind_source_texture (GskGLDriver *driver,
|
||||
int texture_id);
|
||||
void gsk_gl_driver_bind_mask_texture (GskGLDriver *driver,
|
||||
int texture_id);
|
||||
void gsk_gl_driver_bind_vao (GskGLDriver *driver,
|
||||
int vao_id);
|
||||
gboolean gsk_gl_driver_bind_render_target (GskGLDriver *driver,
|
||||
int texture_id);
|
||||
|
||||
void gsk_gl_driver_init_texture_empty (GskGLDriver *driver,
|
||||
int texture_id);
|
||||
void gsk_gl_driver_init_texture_with_surface (GskGLDriver *driver,
|
||||
int texture_id,
|
||||
cairo_surface_t *surface,
|
||||
int min_filter,
|
||||
int mag_filter);
|
||||
|
||||
void gsk_gl_driver_destroy_texture (GskGLDriver *driver,
|
||||
int texture_id);
|
||||
void gsk_gl_driver_destroy_vao (GskGLDriver *driver,
|
||||
int vao_id);
|
||||
|
||||
int gsk_gl_driver_collect_textures (GskGLDriver *driver);
|
||||
int gsk_gl_driver_collect_vaos (GskGLDriver *driver);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_GL_DRIVER_PRIVATE_H__ */
|
||||
@@ -0,0 +1,175 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gskglprofilerprivate.h"
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
#define N_QUERIES 4
|
||||
|
||||
struct _GskGLProfiler
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GdkGLContext *gl_context;
|
||||
|
||||
/* Creating GL queries is kind of expensive, so we pay the
|
||||
* price upfront and create a circular buffer of queries
|
||||
*/
|
||||
GLuint gl_queries[N_QUERIES];
|
||||
GLuint active_query;
|
||||
|
||||
gboolean has_timer : 1;
|
||||
gboolean first_frame : 1;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_GL_CONTEXT = 1,
|
||||
|
||||
N_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *gsk_gl_profiler_properties[N_PROPERTIES];
|
||||
|
||||
G_DEFINE_TYPE (GskGLProfiler, gsk_gl_profiler, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
gsk_gl_profiler_finalize (GObject *gobject)
|
||||
{
|
||||
GskGLProfiler *self = GSK_GL_PROFILER (gobject);
|
||||
|
||||
glDeleteQueries (N_QUERIES, self->gl_queries);
|
||||
|
||||
g_clear_object (&self->gl_context);
|
||||
|
||||
G_OBJECT_CLASS (gsk_gl_profiler_parent_class)->finalize (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_profiler_set_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GskGLProfiler *self = GSK_GL_PROFILER (gobject);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_GL_CONTEXT:
|
||||
self->gl_context = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_profiler_get_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GskGLProfiler *self = GSK_GL_PROFILER (gobject);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_GL_CONTEXT:
|
||||
g_value_set_object (value, self->gl_context);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_profiler_class_init (GskGLProfilerClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->set_property = gsk_gl_profiler_set_property;
|
||||
gobject_class->get_property = gsk_gl_profiler_get_property;
|
||||
gobject_class->finalize = gsk_gl_profiler_finalize;
|
||||
|
||||
gsk_gl_profiler_properties[PROP_GL_CONTEXT] =
|
||||
g_param_spec_object ("gl-context",
|
||||
"GL Context",
|
||||
"The GdkGLContext used by the GL profiler",
|
||||
GDK_TYPE_GL_CONTEXT,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPERTIES, gsk_gl_profiler_properties);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_profiler_init (GskGLProfiler *self)
|
||||
{
|
||||
glGenQueries (N_QUERIES, self->gl_queries);
|
||||
|
||||
self->first_frame = TRUE;
|
||||
self->has_timer = epoxy_has_gl_extension ("GL_ARB_timer_query");
|
||||
}
|
||||
|
||||
GskGLProfiler *
|
||||
gsk_gl_profiler_new (GdkGLContext *context)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
|
||||
|
||||
return g_object_new (GSK_TYPE_GL_PROFILER, "gl-context", context, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_profiler_begin_gpu_region (GskGLProfiler *profiler)
|
||||
{
|
||||
GLuint query_id;
|
||||
|
||||
g_return_if_fail (GSK_IS_GL_PROFILER (profiler));
|
||||
|
||||
if (!profiler->has_timer)
|
||||
return;
|
||||
|
||||
query_id = profiler->gl_queries[profiler->active_query];
|
||||
glBeginQuery (GL_TIME_ELAPSED, query_id);
|
||||
}
|
||||
|
||||
guint64
|
||||
gsk_gl_profiler_end_gpu_region (GskGLProfiler *profiler)
|
||||
{
|
||||
GLuint last_query_id;
|
||||
GLint res;
|
||||
GLuint64 elapsed;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_GL_PROFILER (profiler), 0);
|
||||
|
||||
if (!profiler->has_timer)
|
||||
return 0;
|
||||
|
||||
glEndQuery (GL_TIME_ELAPSED);
|
||||
|
||||
if (profiler->active_query == 0)
|
||||
last_query_id = N_QUERIES - 1;
|
||||
else
|
||||
last_query_id = profiler->active_query - 1;
|
||||
|
||||
/* Advance iterator */
|
||||
profiler->active_query += 1;
|
||||
if (profiler->active_query == N_QUERIES)
|
||||
profiler->active_query = 0;
|
||||
|
||||
/* If this is the first frame we already have a result */
|
||||
if (profiler->first_frame)
|
||||
{
|
||||
profiler->first_frame = FALSE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
glGetQueryObjectiv (profiler->gl_queries[last_query_id], GL_QUERY_RESULT_AVAILABLE, &res);
|
||||
if (res == 1)
|
||||
glGetQueryObjectui64v (profiler->gl_queries[last_query_id], GL_QUERY_RESULT, &elapsed);
|
||||
else
|
||||
elapsed = 0;
|
||||
|
||||
return elapsed;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef __GSK_GL_PROFILER_PRIVATE_H__
|
||||
#define __GSK_GL_PROFILER_PRIVATE_H__
|
||||
|
||||
#include <gsk/gsktypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_GL_PROFILER (gsk_gl_profiler_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (GskGLProfiler, gsk_gl_profiler, GSK, GL_PROFILER, GObject)
|
||||
|
||||
GskGLProfiler * gsk_gl_profiler_new (GdkGLContext *context);
|
||||
|
||||
void gsk_gl_profiler_begin_gpu_region (GskGLProfiler *profiler);
|
||||
guint64 gsk_gl_profiler_end_gpu_region (GskGLProfiler *profiler);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_GL_PROFILER_PRIVATE_H__ */
|
||||
@@ -0,0 +1,980 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gskglrendererprivate.h"
|
||||
|
||||
#include "gskdebugprivate.h"
|
||||
#include "gskenums.h"
|
||||
#include "gskgldriverprivate.h"
|
||||
#include "gskglprofilerprivate.h"
|
||||
#include "gskprofilerprivate.h"
|
||||
#include "gskrendererprivate.h"
|
||||
#include "gskrendernodeprivate.h"
|
||||
#include "gskrendernodeiter.h"
|
||||
#include "gskshaderbuilderprivate.h"
|
||||
|
||||
#include "gskprivate.h"
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
#define SHADER_VERSION_GLES 110
|
||||
#define SHADER_VERSION_GL_LEGACY 120
|
||||
#define SHADER_VERSION_GL3 150
|
||||
|
||||
typedef struct {
|
||||
int render_target_id;
|
||||
int vao_id;
|
||||
int buffer_id;
|
||||
int texture_id;
|
||||
int program_id;
|
||||
|
||||
int mvp_location;
|
||||
int source_location;
|
||||
int mask_location;
|
||||
int uv_location;
|
||||
int position_location;
|
||||
int alpha_location;
|
||||
int blendMode_location;
|
||||
} RenderData;
|
||||
|
||||
typedef struct {
|
||||
/* Back pointer to the node, only meant for comparison */
|
||||
GskRenderNode *node;
|
||||
|
||||
graphene_point3d_t min;
|
||||
graphene_point3d_t max;
|
||||
|
||||
graphene_size_t size;
|
||||
|
||||
graphene_matrix_t mvp;
|
||||
|
||||
gboolean opaque : 1;
|
||||
float opacity;
|
||||
float z;
|
||||
|
||||
const char *name;
|
||||
|
||||
GskBlendMode blend_mode;
|
||||
|
||||
RenderData render_data;
|
||||
RenderData *parent_data;
|
||||
|
||||
GArray *children;
|
||||
} RenderItem;
|
||||
|
||||
enum {
|
||||
MVP,
|
||||
SOURCE,
|
||||
MASK,
|
||||
ALPHA,
|
||||
BLEND_MODE,
|
||||
N_UNIFORMS
|
||||
};
|
||||
|
||||
enum {
|
||||
POSITION,
|
||||
UV,
|
||||
N_ATTRIBUTES
|
||||
};
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
typedef struct {
|
||||
GQuark frames;
|
||||
GQuark draw_calls;
|
||||
} ProfileCounters;
|
||||
|
||||
typedef struct {
|
||||
GQuark cpu_time;
|
||||
GQuark gpu_time;
|
||||
} ProfileTimers;
|
||||
#endif
|
||||
|
||||
struct _GskGLRenderer
|
||||
{
|
||||
GskRenderer parent_instance;
|
||||
|
||||
graphene_matrix_t mvp;
|
||||
graphene_frustum_t frustum;
|
||||
|
||||
guint frame_buffer;
|
||||
guint depth_stencil_buffer;
|
||||
guint texture_id;
|
||||
|
||||
GQuark uniforms[N_UNIFORMS];
|
||||
GQuark attributes[N_ATTRIBUTES];
|
||||
|
||||
GdkGLContext *gl_context;
|
||||
GskGLDriver *gl_driver;
|
||||
GskGLProfiler *gl_profiler;
|
||||
GskShaderBuilder *shader_builder;
|
||||
|
||||
int blend_program_id;
|
||||
int blit_program_id;
|
||||
|
||||
GArray *render_items;
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
ProfileCounters profile_counters;
|
||||
ProfileTimers profile_timers;
|
||||
#endif
|
||||
|
||||
gboolean has_buffers : 1;
|
||||
};
|
||||
|
||||
struct _GskGLRendererClass
|
||||
{
|
||||
GskRendererClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GskGLRenderer, gsk_gl_renderer, GSK_TYPE_RENDERER)
|
||||
|
||||
static void
|
||||
gsk_gl_renderer_dispose (GObject *gobject)
|
||||
{
|
||||
GskGLRenderer *self = GSK_GL_RENDERER (gobject);
|
||||
|
||||
g_clear_object (&self->gl_context);
|
||||
|
||||
G_OBJECT_CLASS (gsk_gl_renderer_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_renderer_create_buffers (GskGLRenderer *self,
|
||||
int width,
|
||||
int height,
|
||||
int scale_factor)
|
||||
{
|
||||
if (self->has_buffers)
|
||||
return;
|
||||
|
||||
GSK_NOTE (OPENGL, g_print ("Creating buffers (w:%d, h:%d, scale:%d)\n", width, height, scale_factor));
|
||||
|
||||
if (self->texture_id == 0)
|
||||
{
|
||||
self->texture_id = gsk_gl_driver_create_texture (self->gl_driver,
|
||||
width * scale_factor,
|
||||
height * scale_factor);
|
||||
gsk_gl_driver_bind_source_texture (self->gl_driver, self->texture_id);
|
||||
gsk_gl_driver_init_texture_empty (self->gl_driver, self->texture_id);
|
||||
}
|
||||
|
||||
gsk_gl_driver_create_render_target (self->gl_driver, self->texture_id, TRUE, TRUE);
|
||||
|
||||
self->has_buffers = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_renderer_destroy_buffers (GskGLRenderer *self)
|
||||
{
|
||||
if (self->gl_context == NULL)
|
||||
return;
|
||||
|
||||
if (!self->has_buffers)
|
||||
return;
|
||||
|
||||
GSK_NOTE (OPENGL, g_print ("Destroying buffers\n"));
|
||||
|
||||
gdk_gl_context_make_current (self->gl_context);
|
||||
|
||||
if (self->texture_id != 0)
|
||||
{
|
||||
gsk_gl_driver_destroy_texture (self->gl_driver, self->texture_id);
|
||||
self->texture_id = 0;
|
||||
}
|
||||
|
||||
self->has_buffers = FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_gl_renderer_create_programs (GskGLRenderer *self)
|
||||
{
|
||||
GskShaderBuilder *builder;
|
||||
GError *error = NULL;
|
||||
gboolean res = FALSE;
|
||||
|
||||
builder = gsk_shader_builder_new ();
|
||||
|
||||
gsk_shader_builder_set_resource_base_path (builder, "/org/gtk/libgsk/glsl");
|
||||
|
||||
self->uniforms[MVP] = gsk_shader_builder_add_uniform (builder, "uMVP");
|
||||
self->uniforms[SOURCE] = gsk_shader_builder_add_uniform (builder, "uSource");
|
||||
self->uniforms[MASK] = gsk_shader_builder_add_uniform (builder, "uMask");
|
||||
self->uniforms[ALPHA] = gsk_shader_builder_add_uniform (builder, "uAlpha");
|
||||
self->uniforms[BLEND_MODE] = gsk_shader_builder_add_uniform (builder, "uBlendMode");
|
||||
|
||||
self->attributes[POSITION] = gsk_shader_builder_add_attribute (builder, "aPosition");
|
||||
self->attributes[UV] = gsk_shader_builder_add_attribute (builder, "aUv");
|
||||
|
||||
if (gdk_gl_context_get_use_es (self->gl_context))
|
||||
{
|
||||
gsk_shader_builder_set_version (builder, SHADER_VERSION_GLES);
|
||||
gsk_shader_builder_set_vertex_preamble (builder, "es2_common.vs.glsl");
|
||||
gsk_shader_builder_set_fragment_preamble (builder, "es2_common.fs.glsl");
|
||||
gsk_shader_builder_add_define (builder, "GSK_GLES", "1");
|
||||
}
|
||||
else if (gdk_gl_context_is_legacy (self->gl_context))
|
||||
{
|
||||
gsk_shader_builder_set_version (builder, SHADER_VERSION_GL_LEGACY);
|
||||
gsk_shader_builder_set_vertex_preamble (builder, "gl_common.vs.glsl");
|
||||
gsk_shader_builder_set_fragment_preamble (builder, "gl_common.fs.glsl");
|
||||
gsk_shader_builder_add_define (builder, "GSK_LEGACY", "1");
|
||||
}
|
||||
else
|
||||
{
|
||||
gsk_shader_builder_set_version (builder, SHADER_VERSION_GL3);
|
||||
gsk_shader_builder_set_vertex_preamble (builder, "gl3_common.vs.glsl");
|
||||
gsk_shader_builder_set_fragment_preamble (builder, "gl3_common.fs.glsl");
|
||||
gsk_shader_builder_add_define (builder, "GSK_GL3", "1");
|
||||
}
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
if (GSK_RENDER_MODE_CHECK (SHADERS))
|
||||
gsk_shader_builder_add_define (builder, "GSK_DEBUG", "1");
|
||||
#endif
|
||||
|
||||
self->blend_program_id =
|
||||
gsk_shader_builder_create_program (builder, "blend.vs.glsl", "blend.fs.glsl", &error);
|
||||
if (error != NULL)
|
||||
{
|
||||
g_critical ("Unable to create 'blend' program: %s", error->message);
|
||||
g_error_free (error);
|
||||
g_object_unref (builder);
|
||||
goto out;
|
||||
}
|
||||
|
||||
self->blit_program_id =
|
||||
gsk_shader_builder_create_program (builder, "blit.vs.glsl", "blit.fs.glsl", &error);
|
||||
if (error != NULL)
|
||||
{
|
||||
g_critical ("Unable to create 'blit' program: %s", error->message);
|
||||
g_error_free (error);
|
||||
g_object_unref (builder);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Keep a pointer to query for the uniform and attribute locations
|
||||
* when rendering the scene
|
||||
*/
|
||||
self->shader_builder = builder;
|
||||
|
||||
res = TRUE;
|
||||
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_renderer_destroy_programs (GskGLRenderer *self)
|
||||
{
|
||||
g_clear_object (&self->shader_builder);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_gl_renderer_realize (GskRenderer *renderer)
|
||||
{
|
||||
GskGLRenderer *self = GSK_GL_RENDERER (renderer);
|
||||
GError *error = NULL;
|
||||
|
||||
/* If we didn't get a GdkGLContext before realization, try creating
|
||||
* one now, for our exclusive use.
|
||||
*/
|
||||
if (self->gl_context == NULL)
|
||||
{
|
||||
GdkWindow *window = gsk_renderer_get_window (renderer);
|
||||
|
||||
if (window == NULL)
|
||||
return FALSE;
|
||||
|
||||
self->gl_context = gdk_window_create_gl_context (window, &error);
|
||||
if (error != NULL)
|
||||
{
|
||||
g_critical ("Unable to create GL context for renderer: %s",
|
||||
error->message);
|
||||
g_error_free (error);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
gdk_gl_context_realize (self->gl_context, &error);
|
||||
if (error != NULL)
|
||||
{
|
||||
g_critical ("Unable to realize GL renderer: %s", error->message);
|
||||
g_error_free (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gdk_gl_context_make_current (self->gl_context);
|
||||
|
||||
g_assert (self->gl_driver == NULL);
|
||||
self->gl_driver = gsk_gl_driver_new (self->gl_context);
|
||||
self->gl_profiler = gsk_gl_profiler_new (self->gl_context);
|
||||
|
||||
GSK_NOTE (OPENGL, g_print ("Creating buffers and programs\n"));
|
||||
if (!gsk_gl_renderer_create_programs (self))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_renderer_unrealize (GskRenderer *renderer)
|
||||
{
|
||||
GskGLRenderer *self = GSK_GL_RENDERER (renderer);
|
||||
|
||||
if (self->gl_context == NULL)
|
||||
return;
|
||||
|
||||
gdk_gl_context_make_current (self->gl_context);
|
||||
|
||||
/* We don't need to iterate to destroy the associated GL resources,
|
||||
* as they will be dropped when we finalize the GskGLDriver
|
||||
*/
|
||||
g_clear_pointer (&self->render_items, g_array_unref);
|
||||
|
||||
gsk_gl_renderer_destroy_buffers (self);
|
||||
gsk_gl_renderer_destroy_programs (self);
|
||||
|
||||
g_clear_object (&self->gl_profiler);
|
||||
g_clear_object (&self->gl_driver);
|
||||
|
||||
if (self->gl_context == gdk_gl_context_get_current ())
|
||||
gdk_gl_context_clear_current ();
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_renderer_resize_viewport (GskGLRenderer *self,
|
||||
const graphene_rect_t *viewport,
|
||||
int scale_factor)
|
||||
{
|
||||
int width = viewport->size.width * scale_factor;
|
||||
int height = viewport->size.height * scale_factor;
|
||||
|
||||
GSK_NOTE (OPENGL, g_print ("glViewport(0, 0, %d, %d) [scale:%d]\n",
|
||||
width,
|
||||
height,
|
||||
scale_factor));
|
||||
|
||||
glViewport (0, 0, width, height);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_renderer_update_frustum (GskGLRenderer *self,
|
||||
const graphene_matrix_t *modelview,
|
||||
const graphene_matrix_t *projection)
|
||||
{
|
||||
GSK_NOTE (TRANSFORMS, g_print ("Updating the modelview/projection\n"));
|
||||
|
||||
graphene_matrix_multiply (modelview, projection, &self->mvp);
|
||||
|
||||
graphene_frustum_init_from_matrix (&self->frustum, &self->mvp);
|
||||
|
||||
GSK_NOTE (TRANSFORMS,
|
||||
g_print ("Renderer MVP:\n");
|
||||
graphene_matrix_print (&self->mvp);
|
||||
g_print ("\n"));
|
||||
}
|
||||
|
||||
#define N_VERTICES 6
|
||||
|
||||
static inline int
|
||||
node_depth (GskRenderNode *node)
|
||||
{
|
||||
int ret = 0;
|
||||
while (node->parent)
|
||||
{
|
||||
ret++;
|
||||
node = node->parent;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
render_item (GskGLRenderer *self,
|
||||
RenderItem *item)
|
||||
{
|
||||
float mvp[16];
|
||||
float opacity;
|
||||
|
||||
if (item->children != NULL)
|
||||
{
|
||||
if (gsk_gl_driver_bind_render_target (self->gl_driver, item->render_data.render_target_id))
|
||||
{
|
||||
glViewport (0, 0, item->size.width, item->size.height);
|
||||
|
||||
glClearColor (0.0, 0.0, 0.0, 0.0);
|
||||
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
gsk_gl_driver_bind_vao (self->gl_driver, item->render_data.vao_id);
|
||||
|
||||
glUseProgram (item->render_data.program_id);
|
||||
|
||||
if (item->render_data.texture_id != 0)
|
||||
{
|
||||
/* Use texture unit 0 for the source */
|
||||
glUniform1i (item->render_data.source_location, 0);
|
||||
gsk_gl_driver_bind_source_texture (self->gl_driver, item->render_data.texture_id);
|
||||
|
||||
if (item->parent_data != NULL)
|
||||
{
|
||||
glUniform1i (item->render_data.blendMode_location, item->blend_mode);
|
||||
|
||||
/* Use texture unit 1 for the mask */
|
||||
if (item->parent_data->texture_id != 0)
|
||||
{
|
||||
glUniform1i (item->render_data.mask_location, 1);
|
||||
gsk_gl_driver_bind_mask_texture (self->gl_driver, item->parent_data->texture_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Pass the opacity component */
|
||||
if (item->children != NULL || item->opaque)
|
||||
opacity = 1.0;
|
||||
else
|
||||
opacity = item->opacity;
|
||||
|
||||
glUniform1f (item->render_data.alpha_location, opacity);
|
||||
|
||||
/* Pass the mvp to the vertex shader */
|
||||
GSK_NOTE (TRANSFORMS, graphene_matrix_print (&item->mvp));
|
||||
graphene_matrix_to_float (&item->mvp, mvp);
|
||||
glUniformMatrix4fv (item->render_data.mvp_location, 1, GL_FALSE, mvp);
|
||||
|
||||
/* Draw the quad */
|
||||
GSK_NOTE2 (OPENGL, TRANSFORMS,
|
||||
g_print ("%*sDrawing item <%s>[%p] (w:%g, h:%g) with opacity: %g blend mode: %d\n",
|
||||
2 * node_depth (item->node), "",
|
||||
item->name,
|
||||
item,
|
||||
item->size.width, item->size.height,
|
||||
item->opaque ? 1 : item->opacity,
|
||||
item->blend_mode));
|
||||
|
||||
glDrawArrays (GL_TRIANGLES, 0, N_VERTICES);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
gsk_profiler_counter_inc (gsk_renderer_get_profiler (GSK_RENDERER (self)),
|
||||
self->profile_counters.draw_calls);
|
||||
#endif
|
||||
|
||||
/* Render all children items, so we can take the result
|
||||
* render target texture during the compositing
|
||||
*/
|
||||
if (item->children != NULL)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < item->children->len; i++)
|
||||
{
|
||||
RenderItem *child = &g_array_index (item->children, RenderItem, i);
|
||||
|
||||
render_item (self, child);
|
||||
}
|
||||
|
||||
/* Bind the parent render target */
|
||||
if (item->parent_data != NULL)
|
||||
gsk_gl_driver_bind_render_target (self->gl_driver, item->parent_data->render_target_id);
|
||||
|
||||
/* Bind the same VAO, as the render target is created with the same size
|
||||
* and vertices as the texture target
|
||||
*/
|
||||
gsk_gl_driver_bind_vao (self->gl_driver, item->render_data.vao_id);
|
||||
|
||||
/* Since we're rendering the target texture, we only need the blit program */
|
||||
glUseProgram (self->blit_program_id);
|
||||
|
||||
/* Use texture unit 0 for the render target */
|
||||
glUniform1i (item->render_data.source_location, 0);
|
||||
gsk_gl_driver_bind_source_texture (self->gl_driver, item->render_data.render_target_id);
|
||||
|
||||
/* Pass the opacity component; if we got here, we know that the original render
|
||||
* target is neither fully opaque nor at full opacity
|
||||
*/
|
||||
glUniform1f (item->render_data.alpha_location, item->opacity);
|
||||
|
||||
/* Pass the mvp to the vertex shader */
|
||||
GSK_NOTE (TRANSFORMS, graphene_matrix_print (&item->mvp));
|
||||
graphene_matrix_to_float (&item->mvp, mvp);
|
||||
glUniformMatrix4fv (item->render_data.mvp_location, 1, GL_FALSE, mvp);
|
||||
|
||||
/* Draw the quad */
|
||||
GSK_NOTE2 (OPENGL, TRANSFORMS,
|
||||
g_print ("%*sDrawing offscreen item <%s>[%p] (w:%g, h:%g) with opacity: %g\n",
|
||||
2 * node_depth (item->node), "",
|
||||
item->name,
|
||||
item,
|
||||
item->size.width, item->size.height,
|
||||
item->opacity));
|
||||
|
||||
glDrawArrays (GL_TRIANGLES, 0, N_VERTICES);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
get_gl_scaling_filters (GskRenderNode *node,
|
||||
int *min_filter_r,
|
||||
int *mag_filter_r)
|
||||
{
|
||||
switch (node->min_filter)
|
||||
{
|
||||
case GSK_SCALING_FILTER_NEAREST:
|
||||
*min_filter_r = GL_NEAREST;
|
||||
break;
|
||||
|
||||
case GSK_SCALING_FILTER_LINEAR:
|
||||
*min_filter_r = GL_LINEAR;
|
||||
break;
|
||||
|
||||
case GSK_SCALING_FILTER_TRILINEAR:
|
||||
*min_filter_r = GL_LINEAR_MIPMAP_LINEAR;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (node->mag_filter)
|
||||
{
|
||||
case GSK_SCALING_FILTER_NEAREST:
|
||||
*mag_filter_r = GL_NEAREST;
|
||||
break;
|
||||
|
||||
/* There's no point in using anything above GL_LINEAR for
|
||||
* magnification filters
|
||||
*/
|
||||
case GSK_SCALING_FILTER_LINEAR:
|
||||
case GSK_SCALING_FILTER_TRILINEAR:
|
||||
*mag_filter_r = GL_LINEAR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static gboolean
|
||||
check_in_frustum (const graphene_frustum_t *frustum,
|
||||
RenderItem *item)
|
||||
{
|
||||
graphene_box_t aabb;
|
||||
|
||||
graphene_box_init (&aabb, &item->min, &item->max);
|
||||
graphene_matrix_transform_box (&item->mvp, &aabb, &aabb);
|
||||
|
||||
return graphene_frustum_intersects_box (frustum, &aabb);
|
||||
}
|
||||
#endif
|
||||
|
||||
static float
|
||||
project_item (const graphene_matrix_t *projection,
|
||||
const graphene_matrix_t *modelview)
|
||||
{
|
||||
graphene_vec4_t vec;
|
||||
|
||||
graphene_matrix_get_row (modelview, 3, &vec);
|
||||
graphene_matrix_transform_vec4 (projection, &vec, &vec);
|
||||
|
||||
return graphene_vec4_get_z (&vec) / graphene_vec4_get_w (&vec);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
render_node_needs_render_target (GskRenderNode *node)
|
||||
{
|
||||
if (!gsk_render_node_is_opaque (node))
|
||||
{
|
||||
double opacity = gsk_render_node_get_opacity (node);
|
||||
|
||||
if (opacity < 1.0)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_renderer_add_render_item (GskGLRenderer *self,
|
||||
const graphene_matrix_t *projection,
|
||||
GArray *render_items,
|
||||
GskRenderNode *node,
|
||||
RenderItem *parent)
|
||||
{
|
||||
graphene_rect_t viewport;
|
||||
GskRenderNodeIter iter;
|
||||
graphene_matrix_t mv;
|
||||
graphene_rect_t bounds;
|
||||
GskRenderNode *child;
|
||||
RenderItem item;
|
||||
RenderItem *ritem = NULL;
|
||||
int program_id;
|
||||
int scale_factor;
|
||||
|
||||
if (gsk_render_node_is_hidden (node))
|
||||
{
|
||||
GSK_NOTE (OPENGL, g_print ("Skipping hidden node <%s>[%p]\n",
|
||||
node->name != NULL ? node->name : "unnamed",
|
||||
node));
|
||||
return;
|
||||
}
|
||||
|
||||
memset (&item, 0, sizeof (RenderItem));
|
||||
|
||||
gsk_renderer_get_viewport (GSK_RENDERER (self), &viewport);
|
||||
|
||||
scale_factor = gsk_render_node_get_scale_factor (node);
|
||||
if (scale_factor < 1)
|
||||
scale_factor = 1;
|
||||
|
||||
gsk_render_node_get_bounds (node, &bounds);
|
||||
|
||||
item.node = node;
|
||||
item.name = node->name != NULL ? node->name : "unnamed";
|
||||
|
||||
/* The texture size */
|
||||
item.size.width = bounds.size.width * scale_factor;
|
||||
item.size.height = bounds.size.height * scale_factor;
|
||||
|
||||
/* Each render item is an axis-aligned bounding box that we
|
||||
* transform using the given transformation matrix
|
||||
*/
|
||||
item.min.x = bounds.origin.x;
|
||||
item.min.y = bounds.origin.y;
|
||||
item.min.z = 0.f;
|
||||
|
||||
item.max.x = item.min.x + bounds.size.width;
|
||||
item.max.y = item.min.y + bounds.size.height;
|
||||
item.max.z = 0.f;
|
||||
|
||||
/* The location of the item, in normalized world coordinates */
|
||||
gsk_render_node_get_world_matrix (node, &mv);
|
||||
graphene_matrix_multiply (&mv, &self->mvp, &item.mvp);
|
||||
item.z = project_item (projection, &mv);
|
||||
|
||||
item.opaque = gsk_render_node_is_opaque (node);
|
||||
item.opacity = gsk_render_node_get_opacity (node);
|
||||
|
||||
item.blend_mode = gsk_render_node_get_blend_mode (node);
|
||||
|
||||
/* Back-pointer to the parent node */
|
||||
if (parent != NULL)
|
||||
item.parent_data = &(parent->render_data);
|
||||
else
|
||||
item.parent_data = NULL;
|
||||
|
||||
/* Select the program to use */
|
||||
if (parent != NULL)
|
||||
program_id = self->blend_program_id;
|
||||
else
|
||||
program_id = self->blit_program_id;
|
||||
|
||||
item.render_data.program_id = program_id;
|
||||
|
||||
/* Retrieve all the uniforms and attributes */
|
||||
item.render_data.source_location =
|
||||
gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[SOURCE]);
|
||||
item.render_data.mask_location =
|
||||
gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[MASK]);
|
||||
item.render_data.mvp_location =
|
||||
gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[MVP]);
|
||||
item.render_data.alpha_location =
|
||||
gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[ALPHA]);
|
||||
item.render_data.blendMode_location =
|
||||
gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[BLEND_MODE]);
|
||||
|
||||
item.render_data.position_location =
|
||||
gsk_shader_builder_get_attribute_location (self->shader_builder, program_id, self->attributes[POSITION]);
|
||||
item.render_data.uv_location =
|
||||
gsk_shader_builder_get_attribute_location (self->shader_builder, program_id, self->attributes[UV]);
|
||||
|
||||
if (render_node_needs_render_target (node))
|
||||
{
|
||||
item.render_data.render_target_id =
|
||||
gsk_gl_driver_create_texture (self->gl_driver, item.size.width, item.size.height);
|
||||
gsk_gl_driver_init_texture_empty (self->gl_driver, item.render_data.render_target_id);
|
||||
gsk_gl_driver_create_render_target (self->gl_driver, item.render_data.render_target_id, TRUE, TRUE);
|
||||
|
||||
item.children = g_array_sized_new (FALSE, FALSE, sizeof (RenderItem),
|
||||
gsk_render_node_get_n_children (node));
|
||||
}
|
||||
else
|
||||
{
|
||||
item.render_data.render_target_id = self->texture_id;
|
||||
item.children = NULL;
|
||||
}
|
||||
|
||||
if (gsk_render_node_has_texture (node))
|
||||
{
|
||||
item.render_data.texture_id = gsk_render_node_get_texture (node);
|
||||
}
|
||||
else if (gsk_render_node_has_surface (node))
|
||||
{
|
||||
cairo_surface_t *surface = gsk_render_node_get_surface (node);
|
||||
int gl_min_filter = GL_NEAREST, gl_mag_filter = GL_NEAREST;
|
||||
|
||||
get_gl_scaling_filters (node, &gl_min_filter, &gl_mag_filter);
|
||||
|
||||
/* Upload the Cairo surface to a GL texture */
|
||||
item.render_data.texture_id = gsk_gl_driver_create_texture (self->gl_driver,
|
||||
item.size.width,
|
||||
item.size.height);
|
||||
gsk_gl_driver_bind_source_texture (self->gl_driver, item.render_data.texture_id);
|
||||
gsk_gl_driver_init_texture_with_surface (self->gl_driver,
|
||||
item.render_data.texture_id,
|
||||
surface,
|
||||
gl_min_filter,
|
||||
gl_mag_filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If the node does not draw anything, we skip it */
|
||||
if (item.render_data.render_target_id == self->texture_id)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Create the vertex buffers holding the geometry of the quad */
|
||||
{
|
||||
GskQuadVertex vertex_data[N_VERTICES] = {
|
||||
{ { item.min.x, item.min.y }, { 0, 0 }, },
|
||||
{ { item.min.x, item.max.y }, { 0, 1 }, },
|
||||
{ { item.max.x, item.min.y }, { 1, 0 }, },
|
||||
|
||||
{ { item.max.x, item.max.y }, { 1, 1 }, },
|
||||
{ { item.min.x, item.max.y }, { 0, 1 }, },
|
||||
{ { item.max.x, item.min.y }, { 1, 0 }, },
|
||||
};
|
||||
|
||||
item.render_data.vao_id =
|
||||
gsk_gl_driver_create_vao_for_quad (self->gl_driver,
|
||||
item.render_data.position_location,
|
||||
item.render_data.uv_location,
|
||||
N_VERTICES,
|
||||
vertex_data);
|
||||
}
|
||||
|
||||
GSK_NOTE (OPENGL, g_print ("%*sAdding node <%s>[%p] to render items\n",
|
||||
2 * node_depth (node), "",
|
||||
node->name != NULL ? node->name : "unnamed",
|
||||
node));
|
||||
g_array_append_val (render_items, item);
|
||||
ritem = &g_array_index (render_items, RenderItem, render_items->len - 1);
|
||||
|
||||
if (item.children != NULL)
|
||||
render_items = item.children;
|
||||
|
||||
out:
|
||||
gsk_render_node_iter_init (&iter, node);
|
||||
while (gsk_render_node_iter_next (&iter, &child))
|
||||
gsk_gl_renderer_add_render_item (self, projection, render_items, child, ritem);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_gl_renderer_validate_tree (GskGLRenderer *self,
|
||||
GskRenderNode *root,
|
||||
const graphene_matrix_t *projection)
|
||||
{
|
||||
int n_nodes;
|
||||
|
||||
if (self->gl_context == NULL)
|
||||
{
|
||||
GSK_NOTE (OPENGL, g_print ("No valid GL context associated to the renderer"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
n_nodes = gsk_render_node_get_size (root);
|
||||
|
||||
gdk_gl_context_make_current (self->gl_context);
|
||||
|
||||
self->render_items = g_array_sized_new (FALSE, FALSE, sizeof (RenderItem), n_nodes);
|
||||
|
||||
gsk_gl_driver_begin_frame (self->gl_driver);
|
||||
|
||||
GSK_NOTE (OPENGL, g_print ("RenderNode -> RenderItem\n"));
|
||||
gsk_gl_renderer_add_render_item (self, projection, self->render_items, root, NULL);
|
||||
|
||||
GSK_NOTE (OPENGL, g_print ("Total render items: %d of max:%d\n",
|
||||
self->render_items->len,
|
||||
n_nodes));
|
||||
|
||||
gsk_gl_driver_end_frame (self->gl_driver);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_renderer_clear_tree (GskGLRenderer *self)
|
||||
{
|
||||
int removed_textures, removed_vaos;
|
||||
|
||||
if (self->gl_context == NULL)
|
||||
return;
|
||||
|
||||
gdk_gl_context_make_current (self->gl_context);
|
||||
|
||||
g_clear_pointer (&self->render_items, g_array_unref);
|
||||
|
||||
removed_textures = gsk_gl_driver_collect_textures (self->gl_driver);
|
||||
removed_vaos = gsk_gl_driver_collect_vaos (self->gl_driver);
|
||||
|
||||
GSK_NOTE (OPENGL, g_print ("Collected: %d textures, %d vaos\n",
|
||||
removed_textures,
|
||||
removed_vaos));
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_renderer_clear (GskGLRenderer *self)
|
||||
{
|
||||
GSK_NOTE (OPENGL, g_print ("Clearing viewport\n"));
|
||||
glClearColor (0, 0, 0, 0);
|
||||
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
}
|
||||
|
||||
#define ORTHO_NEAR_PLANE -10000
|
||||
#define ORTHO_FAR_PLANE 10000
|
||||
|
||||
static void
|
||||
gsk_gl_renderer_render (GskRenderer *renderer,
|
||||
GskRenderNode *root)
|
||||
{
|
||||
GskGLRenderer *self = GSK_GL_RENDERER (renderer);
|
||||
graphene_matrix_t modelview, projection;
|
||||
graphene_rect_t viewport;
|
||||
guint i;
|
||||
int scale_factor;
|
||||
GdkDrawingContext *context;
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
GskProfiler *profiler;
|
||||
gint64 gpu_time, cpu_time;
|
||||
#endif
|
||||
|
||||
if (self->gl_context == NULL)
|
||||
return;
|
||||
|
||||
context = gsk_renderer_get_drawing_context (renderer);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
profiler = gsk_renderer_get_profiler (renderer);
|
||||
#endif
|
||||
|
||||
gdk_gl_context_make_current (self->gl_context);
|
||||
|
||||
gsk_renderer_get_viewport (renderer, &viewport);
|
||||
scale_factor = gsk_renderer_get_scale_factor (renderer);
|
||||
|
||||
gsk_gl_driver_begin_frame (self->gl_driver);
|
||||
gsk_gl_renderer_create_buffers (self, viewport.size.width, viewport.size.height, scale_factor);
|
||||
gsk_gl_driver_end_frame (self->gl_driver);
|
||||
|
||||
/* Set up the modelview and projection matrices to fit our viewport */
|
||||
graphene_matrix_init_scale (&modelview, scale_factor, scale_factor, 1.0);
|
||||
graphene_matrix_init_ortho (&projection,
|
||||
0, viewport.size.width * scale_factor,
|
||||
viewport.size.height * scale_factor, 0,
|
||||
ORTHO_NEAR_PLANE,
|
||||
ORTHO_FAR_PLANE);
|
||||
|
||||
gsk_gl_renderer_update_frustum (self, &modelview, &projection);
|
||||
|
||||
if (!gsk_gl_renderer_validate_tree (self, root, &projection))
|
||||
goto out;
|
||||
|
||||
gsk_gl_driver_begin_frame (self->gl_driver);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
gsk_gl_profiler_begin_gpu_region (self->gl_profiler);
|
||||
gsk_profiler_timer_begin (profiler, self->profile_timers.cpu_time);
|
||||
#endif
|
||||
|
||||
/* Ensure that the viewport is up to date */
|
||||
if (gsk_gl_driver_bind_render_target (self->gl_driver, self->texture_id))
|
||||
gsk_gl_renderer_resize_viewport (self, &viewport, scale_factor);
|
||||
|
||||
gsk_gl_renderer_clear (self);
|
||||
|
||||
glEnable (GL_DEPTH_TEST);
|
||||
glDepthFunc (GL_LEQUAL);
|
||||
|
||||
glEnable (GL_BLEND);
|
||||
glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
GSK_NOTE (OPENGL, g_print ("Rendering %u items\n", self->render_items->len));
|
||||
for (i = 0; i < self->render_items->len; i++)
|
||||
{
|
||||
RenderItem *item = &g_array_index (self->render_items, RenderItem, i);
|
||||
|
||||
render_item (self, item);
|
||||
}
|
||||
|
||||
/* Draw the output of the GL rendering to the window */
|
||||
gsk_gl_driver_end_frame (self->gl_driver);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
gsk_profiler_counter_inc (profiler, self->profile_counters.frames);
|
||||
|
||||
cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time);
|
||||
gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time);
|
||||
|
||||
gpu_time = gsk_gl_profiler_end_gpu_region (self->gl_profiler);
|
||||
gsk_profiler_timer_set (profiler, self->profile_timers.gpu_time, gpu_time);
|
||||
|
||||
gsk_profiler_push_samples (profiler);
|
||||
#endif
|
||||
|
||||
out:
|
||||
{
|
||||
GdkWindow *window;
|
||||
cairo_t *cr;
|
||||
|
||||
if (context != NULL)
|
||||
{
|
||||
/* XXX: Add GdkDrawingContext API */
|
||||
cr = gdk_drawing_context_get_cairo_context (context);
|
||||
window = gdk_drawing_context_get_window (context);
|
||||
}
|
||||
else
|
||||
{
|
||||
cr = gsk_renderer_get_cairo_context (renderer);
|
||||
window = gsk_renderer_get_window (renderer);
|
||||
}
|
||||
|
||||
gdk_cairo_draw_from_gl (cr, window,
|
||||
self->texture_id,
|
||||
GL_TEXTURE,
|
||||
scale_factor,
|
||||
0, 0,
|
||||
viewport.size.width * scale_factor,
|
||||
viewport.size.height * scale_factor);
|
||||
}
|
||||
|
||||
gdk_gl_context_make_current (self->gl_context);
|
||||
gsk_gl_renderer_clear_tree (self);
|
||||
gsk_gl_renderer_destroy_buffers (self);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_renderer_class_init (GskGLRendererClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
GskRendererClass *renderer_class = GSK_RENDERER_CLASS (klass);
|
||||
|
||||
gobject_class->dispose = gsk_gl_renderer_dispose;
|
||||
|
||||
renderer_class->realize = gsk_gl_renderer_realize;
|
||||
renderer_class->unrealize = gsk_gl_renderer_unrealize;
|
||||
renderer_class->render = gsk_gl_renderer_render;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_renderer_init (GskGLRenderer *self)
|
||||
{
|
||||
gsk_ensure_resources ();
|
||||
|
||||
graphene_matrix_init_identity (&self->mvp);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
{
|
||||
GskProfiler *profiler = gsk_renderer_get_profiler (GSK_RENDERER (self));
|
||||
|
||||
self->profile_counters.frames = gsk_profiler_add_counter (profiler, "frames", "Frames", FALSE);
|
||||
self->profile_counters.draw_calls = gsk_profiler_add_counter (profiler, "draws", "glDrawArrays", TRUE);
|
||||
|
||||
self->profile_timers.cpu_time = gsk_profiler_add_timer (profiler, "cpu-time", "CPU time", FALSE, TRUE);
|
||||
self->profile_timers.gpu_time = gsk_profiler_add_timer (profiler, "gpu-time", "GPU time", FALSE, TRUE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef __GSK_GL_RENDERER_PRIVATE_H__
|
||||
#define __GSK_GL_RENDERER_PRIVATE_H__
|
||||
|
||||
#include <gsk/gskrenderer.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_GL_RENDERER (gsk_gl_renderer_get_type ())
|
||||
|
||||
#define GSK_GL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_GL_RENDERER, GskGLRenderer))
|
||||
#define GSK_IS_GL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_GL_RENDERER))
|
||||
#define GSK_GL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_GL_RENDERER, GskGLRendererClass))
|
||||
#define GSK_IS_GL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_GL_RENDERER))
|
||||
#define GSK_GL_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_GL_RENDERER, GskGLRendererClass))
|
||||
|
||||
typedef struct _GskGLRenderer GskGLRenderer;
|
||||
typedef struct _GskGLRendererClass GskGLRendererClass;
|
||||
|
||||
GType gsk_gl_renderer_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_GL_RENDERER_PRIVATE_H__ */
|
||||
@@ -0,0 +1,16 @@
|
||||
#include "gskresources.h"
|
||||
|
||||
static gpointer
|
||||
register_resources (gpointer data)
|
||||
{
|
||||
_gsk_register_resource ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_ensure_resources (void)
|
||||
{
|
||||
static GOnce register_resources_once = G_ONCE_INIT;
|
||||
|
||||
g_once (®ister_resources_once, register_resources, NULL);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef __GSK_PRIVATE_H__
|
||||
#define __GSK_PRIVATE_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void gsk_ensure_resources (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_PRIVATE_H__ */
|
||||
@@ -0,0 +1,470 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gskprofilerprivate.h"
|
||||
|
||||
#define MAX_SAMPLES 32
|
||||
|
||||
typedef struct {
|
||||
GQuark id;
|
||||
char *description;
|
||||
gint64 value;
|
||||
gint64 n_samples;
|
||||
gboolean can_reset : 1;
|
||||
} NamedCounter;
|
||||
|
||||
typedef struct {
|
||||
GQuark id;
|
||||
char *description;
|
||||
gint64 value;
|
||||
gint64 start_time;
|
||||
gint64 min_value;
|
||||
gint64 max_value;
|
||||
gint64 avg_value;
|
||||
gint64 n_samples;
|
||||
gboolean in_flight : 1;
|
||||
gboolean can_reset : 1;
|
||||
gboolean invert : 1;
|
||||
} NamedTimer;
|
||||
|
||||
typedef struct {
|
||||
GQuark id;
|
||||
gint64 value;
|
||||
} Sample;
|
||||
|
||||
struct _GskProfiler
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GHashTable *counters;
|
||||
GHashTable *timers;
|
||||
|
||||
Sample timer_samples[MAX_SAMPLES];
|
||||
guint last_sample;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GskProfiler, gsk_profiler, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
named_counter_free (gpointer data)
|
||||
{
|
||||
NamedCounter *counter = data;
|
||||
|
||||
if (data == NULL)
|
||||
return;
|
||||
|
||||
g_free (counter->description);
|
||||
|
||||
g_slice_free (NamedCounter, counter);
|
||||
}
|
||||
|
||||
static void
|
||||
named_timer_free (gpointer data)
|
||||
{
|
||||
NamedTimer *timer = data;
|
||||
|
||||
if (data == NULL)
|
||||
return;
|
||||
|
||||
g_free (timer->description);
|
||||
|
||||
g_slice_free (NamedTimer, timer);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_profiler_finalize (GObject *gobject)
|
||||
{
|
||||
GskProfiler *self = GSK_PROFILER (gobject);
|
||||
|
||||
g_clear_pointer (&self->counters, g_hash_table_unref);
|
||||
g_clear_pointer (&self->timers, g_hash_table_unref);
|
||||
|
||||
G_OBJECT_CLASS (gsk_profiler_parent_class)->finalize (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_profiler_class_init (GskProfilerClass *klass)
|
||||
{
|
||||
G_OBJECT_CLASS (klass)->finalize = gsk_profiler_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_profiler_init (GskProfiler *self)
|
||||
{
|
||||
self->counters = g_hash_table_new_full (g_direct_hash, g_direct_equal,
|
||||
NULL,
|
||||
named_counter_free);
|
||||
self->timers = g_hash_table_new_full (g_direct_hash, g_direct_equal,
|
||||
NULL,
|
||||
named_timer_free);
|
||||
}
|
||||
|
||||
GskProfiler *
|
||||
gsk_profiler_new (void)
|
||||
{
|
||||
return g_object_new (GSK_TYPE_PROFILER, NULL);
|
||||
}
|
||||
|
||||
static NamedCounter *
|
||||
named_counter_new (GQuark id,
|
||||
const char *description,
|
||||
gboolean can_reset)
|
||||
{
|
||||
NamedCounter *res = g_slice_new0 (NamedCounter);
|
||||
|
||||
res->id = id;
|
||||
res->description = g_strdup (description);
|
||||
res->can_reset = can_reset;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static NamedCounter *
|
||||
gsk_profiler_get_counter (GskProfiler *profiler,
|
||||
GQuark id)
|
||||
{
|
||||
return g_hash_table_lookup (profiler->counters, GINT_TO_POINTER (id));
|
||||
}
|
||||
|
||||
GQuark
|
||||
gsk_profiler_add_counter (GskProfiler *profiler,
|
||||
const char *counter_name,
|
||||
const char *description,
|
||||
gboolean can_reset)
|
||||
{
|
||||
NamedCounter *counter;
|
||||
GQuark id;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_PROFILER (profiler), 0);
|
||||
|
||||
id = g_quark_from_string (counter_name);
|
||||
counter = gsk_profiler_get_counter (profiler, id);
|
||||
if (counter != NULL)
|
||||
{
|
||||
g_critical ("Cannot add a counter '%s' as one already exists.", counter_name);
|
||||
return counter->id;
|
||||
}
|
||||
|
||||
counter = named_counter_new (id, description, can_reset);
|
||||
g_hash_table_insert (profiler->counters, GINT_TO_POINTER (id), counter);
|
||||
|
||||
return counter->id;
|
||||
}
|
||||
|
||||
static NamedTimer *
|
||||
named_timer_new (GQuark id,
|
||||
const char *description,
|
||||
gboolean invert,
|
||||
gboolean can_reset)
|
||||
{
|
||||
NamedTimer *res = g_slice_new0 (NamedTimer);
|
||||
|
||||
res->id = id;
|
||||
res->description = g_strdup (description);
|
||||
res->invert = invert;
|
||||
res->can_reset = can_reset;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static NamedTimer *
|
||||
gsk_profiler_get_timer (GskProfiler *profiler,
|
||||
GQuark id)
|
||||
{
|
||||
return g_hash_table_lookup (profiler->timers, GINT_TO_POINTER (id));
|
||||
}
|
||||
|
||||
GQuark
|
||||
gsk_profiler_add_timer (GskProfiler *profiler,
|
||||
const char *timer_name,
|
||||
const char *description,
|
||||
gboolean invert,
|
||||
gboolean can_reset)
|
||||
{
|
||||
NamedTimer *timer;
|
||||
GQuark id;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_PROFILER (profiler), 0);
|
||||
|
||||
id = g_quark_from_string (timer_name);
|
||||
timer = gsk_profiler_get_timer (profiler, id);
|
||||
if (timer != NULL)
|
||||
{
|
||||
g_critical ("Cannot add a timer '%s' as one already exists.", timer_name);
|
||||
return timer->id;
|
||||
}
|
||||
|
||||
timer = named_timer_new (id, description, invert, can_reset);
|
||||
g_hash_table_insert (profiler->timers, GINT_TO_POINTER (id), timer);
|
||||
|
||||
return timer->id;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_profiler_counter_inc (GskProfiler *profiler,
|
||||
GQuark counter_id)
|
||||
{
|
||||
NamedCounter *counter;
|
||||
|
||||
g_return_if_fail (GSK_IS_PROFILER (profiler));
|
||||
|
||||
counter = gsk_profiler_get_counter (profiler, counter_id);
|
||||
if (counter == NULL)
|
||||
return;
|
||||
|
||||
counter->value += 1;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
gsk_profiler_timer_begin (GskProfiler *profiler,
|
||||
GQuark timer_id)
|
||||
{
|
||||
NamedTimer *timer;
|
||||
|
||||
g_return_if_fail (GSK_IS_PROFILER (profiler));
|
||||
|
||||
timer = gsk_profiler_get_timer (profiler, timer_id);
|
||||
if (timer == NULL)
|
||||
return;
|
||||
|
||||
if (timer->in_flight)
|
||||
return;
|
||||
|
||||
timer->in_flight = TRUE;
|
||||
timer->start_time = g_get_monotonic_time () * 1000;
|
||||
}
|
||||
|
||||
gint64
|
||||
gsk_profiler_timer_end (GskProfiler *profiler,
|
||||
GQuark timer_id)
|
||||
{
|
||||
NamedTimer *timer;
|
||||
gint64 diff;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_PROFILER (profiler), 0);
|
||||
|
||||
timer = gsk_profiler_get_timer (profiler, timer_id);
|
||||
if (timer == NULL)
|
||||
{
|
||||
g_critical ("No timer '%s' (id:%d) found; did you forget to call gsk_profiler_add_timer()?",
|
||||
g_quark_to_string (timer_id), timer_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!timer->in_flight)
|
||||
{
|
||||
g_critical ("Timer '%s' (id:%d) is not running; did you forget to call gsk_profiler_timer_begin()?",
|
||||
g_quark_to_string (timer->id), timer->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
diff = (g_get_monotonic_time () * 1000) - timer->start_time;
|
||||
|
||||
timer->in_flight = FALSE;
|
||||
timer->value += diff;
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_profiler_timer_set (GskProfiler *profiler,
|
||||
GQuark timer_id,
|
||||
gint64 value)
|
||||
{
|
||||
NamedTimer *timer;
|
||||
|
||||
g_return_if_fail (GSK_IS_PROFILER (profiler));
|
||||
|
||||
timer = gsk_profiler_get_timer (profiler, timer_id);
|
||||
if (timer == NULL)
|
||||
{
|
||||
g_critical ("No timer '%s' (id:%d) found; did you forget to call gsk_profiler_add_timer()?",
|
||||
g_quark_to_string (timer_id), timer_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (timer->in_flight)
|
||||
{
|
||||
g_critical ("Timer '%s' (id:%d) is running; are you sure you don't want to call "
|
||||
"gsk_profiler_timer_end() instead of gsk_profiler_timer_set()?",
|
||||
g_quark_to_string (timer_id), timer_id);
|
||||
}
|
||||
|
||||
timer->value = value;
|
||||
}
|
||||
|
||||
gint64
|
||||
gsk_profiler_counter_get (GskProfiler *profiler,
|
||||
GQuark counter_id)
|
||||
{
|
||||
NamedCounter *counter;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_PROFILER (profiler), 0);
|
||||
|
||||
counter = gsk_profiler_get_counter (profiler, counter_id);
|
||||
if (counter == NULL)
|
||||
{
|
||||
g_critical ("No counter '%s' (id:%d) found; did you forget to call gsk_profiler_add_counter()?",
|
||||
g_quark_to_string (counter_id), counter_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return counter->value;
|
||||
}
|
||||
|
||||
gint64
|
||||
gsk_profiler_timer_get (GskProfiler *profiler,
|
||||
GQuark timer_id)
|
||||
{
|
||||
NamedTimer *timer;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_PROFILER (profiler), 0);
|
||||
|
||||
timer = gsk_profiler_get_timer (profiler, timer_id);
|
||||
if (timer == NULL)
|
||||
{
|
||||
g_critical ("No timer '%s' (id:%d) found; did you forget to call gsk_profiler_add_timer()?",
|
||||
g_quark_to_string (timer_id), timer_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (timer->invert)
|
||||
return (gint64) (1000000000.0 / (double) timer->value);
|
||||
|
||||
return timer->value;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_profiler_reset (GskProfiler *profiler)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
gpointer value_p = NULL;
|
||||
|
||||
g_return_if_fail (GSK_IS_PROFILER (profiler));
|
||||
|
||||
g_hash_table_iter_init (&iter, profiler->counters);
|
||||
while (g_hash_table_iter_next (&iter, NULL, &value_p))
|
||||
{
|
||||
NamedCounter *counter = value_p;
|
||||
|
||||
if (counter->can_reset)
|
||||
counter->value = 0;
|
||||
}
|
||||
|
||||
g_hash_table_iter_init (&iter, profiler->timers);
|
||||
while (g_hash_table_iter_next (&iter, NULL, &value_p))
|
||||
{
|
||||
NamedTimer *timer = value_p;
|
||||
|
||||
if (timer->can_reset)
|
||||
{
|
||||
timer->value = 0;
|
||||
timer->min_value = 0;
|
||||
timer->max_value = 0;
|
||||
timer->avg_value = 0;
|
||||
timer->n_samples = 0;
|
||||
}
|
||||
}
|
||||
|
||||
profiler->last_sample = 0;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_profiler_push_samples (GskProfiler *profiler)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
gpointer value_p = NULL;
|
||||
guint last_sample;
|
||||
|
||||
g_return_if_fail (GSK_IS_PROFILER (profiler));
|
||||
|
||||
g_hash_table_iter_init (&iter, profiler->timers);
|
||||
while (g_hash_table_iter_next (&iter, NULL, &value_p))
|
||||
{
|
||||
NamedTimer *timer = value_p;
|
||||
Sample *s;
|
||||
|
||||
last_sample = profiler->last_sample;
|
||||
profiler->last_sample += 1;
|
||||
if (profiler->last_sample == MAX_SAMPLES)
|
||||
profiler->last_sample = 0;
|
||||
|
||||
s = &(profiler->timer_samples[last_sample]);
|
||||
s->id = timer->id;
|
||||
|
||||
if (timer->invert)
|
||||
s->value = (gint64) (1000000000.0 / (double) timer->value);
|
||||
else
|
||||
s->value = timer->value;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gsk_profiler_append_counters (GskProfiler *profiler,
|
||||
GString *buffer)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
gpointer value_p = NULL;
|
||||
|
||||
g_return_if_fail (GSK_IS_PROFILER (profiler));
|
||||
g_return_if_fail (buffer != NULL);
|
||||
|
||||
g_hash_table_iter_init (&iter, profiler->counters);
|
||||
while (g_hash_table_iter_next (&iter, NULL, &value_p))
|
||||
{
|
||||
NamedCounter *counter = value_p;
|
||||
|
||||
g_string_append_printf (buffer, "%s: %" G_GINT64_FORMAT "\n",
|
||||
counter->description,
|
||||
counter->value);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gsk_profiler_append_timers (GskProfiler *profiler,
|
||||
GString *buffer)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
gpointer value_p = NULL;
|
||||
int i;
|
||||
|
||||
g_return_if_fail (GSK_IS_PROFILER (profiler));
|
||||
g_return_if_fail (buffer != NULL);
|
||||
|
||||
for (i = 0; i < profiler->last_sample; i++)
|
||||
{
|
||||
Sample *s = &(profiler->timer_samples[i]);
|
||||
NamedTimer *timer;
|
||||
|
||||
if (s->id == 0)
|
||||
continue;
|
||||
|
||||
timer = gsk_profiler_get_timer (profiler, s->id);
|
||||
timer->min_value = MIN (timer->min_value, s->value);
|
||||
timer->max_value = MAX (timer->max_value, s->value);
|
||||
timer->avg_value += s->value;
|
||||
timer->n_samples += 1;
|
||||
}
|
||||
|
||||
g_hash_table_iter_init (&iter, profiler->timers);
|
||||
while (g_hash_table_iter_next (&iter, NULL, &value_p))
|
||||
{
|
||||
NamedTimer *timer = value_p;
|
||||
const char *unit = timer->invert ? "" : "usec";
|
||||
double scale = timer->invert ? 1.0 : 1000.0;
|
||||
|
||||
if (timer->n_samples != 0)
|
||||
timer->avg_value = timer->avg_value / timer->n_samples;
|
||||
|
||||
g_string_append_printf (buffer,
|
||||
"%s %s: "
|
||||
"Min:%.2f, "
|
||||
"Avg:%.2f, "
|
||||
"Max:%.2f\n",
|
||||
timer->description,
|
||||
unit,
|
||||
(double) timer->min_value / scale,
|
||||
(double) timer->avg_value / scale,
|
||||
(double) timer->max_value / scale);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#ifndef __GSK_PROFILER_PRIVATE_H__
|
||||
#define __GSK_PROFILER_PRIVATE_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_PROFILER (gsk_profiler_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (GskProfiler, gsk_profiler, GSK, PROFILER, GObject)
|
||||
|
||||
GskProfiler * gsk_profiler_new (void);
|
||||
|
||||
GQuark gsk_profiler_add_counter (GskProfiler *profiler,
|
||||
const char *counter_name,
|
||||
const char *description,
|
||||
gboolean can_reset);
|
||||
GQuark gsk_profiler_add_timer (GskProfiler *profiler,
|
||||
const char *timer_name,
|
||||
const char *description,
|
||||
gboolean invert,
|
||||
gboolean can_reset);
|
||||
|
||||
void gsk_profiler_counter_inc (GskProfiler *profiler,
|
||||
GQuark counter_id);
|
||||
void gsk_profiler_timer_begin (GskProfiler *profiler,
|
||||
GQuark timer_id);
|
||||
gint64 gsk_profiler_timer_end (GskProfiler *profiler,
|
||||
GQuark timer_id);
|
||||
void gsk_profiler_timer_set (GskProfiler *profiler,
|
||||
GQuark timer_id,
|
||||
gint64 value);
|
||||
|
||||
gint64 gsk_profiler_counter_get (GskProfiler *profiler,
|
||||
GQuark counter_id);
|
||||
gint64 gsk_profiler_timer_get (GskProfiler *profiler,
|
||||
GQuark timer_id);
|
||||
|
||||
void gsk_profiler_reset (GskProfiler *profiler);
|
||||
|
||||
void gsk_profiler_push_samples (GskProfiler *profiler);
|
||||
void gsk_profiler_append_counters (GskProfiler *profiler,
|
||||
GString *buffer);
|
||||
void gsk_profiler_append_timers (GskProfiler *profiler,
|
||||
GString *buffer);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_PROFILER_PRIVATE_H__ */
|
||||
@@ -0,0 +1,794 @@
|
||||
/* GSK - The GTK Scene Kit
|
||||
*
|
||||
* Copyright 2016 Endless
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:GskRenderer
|
||||
* @Title: GskRenderer
|
||||
* @Short_description: Renders a scene
|
||||
*
|
||||
* #GskRenderer is a class that renders a scene graph defined via a
|
||||
* tree of #GskRenderNode instances.
|
||||
*
|
||||
* Typically you will use a #GskRenderer instance with a #GdkDrawingContext
|
||||
* associated to a #GdkWindow, and call gsk_renderer_render() with the
|
||||
* drawing context and the scene to be rendered.
|
||||
*
|
||||
* It is necessary to realize a #GskRenderer instance using gsk_renderer_realize()
|
||||
* before calling gsk_renderer_render(), in order to create the appropriate
|
||||
* windowing system resources needed to render the scene.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gskrendererprivate.h"
|
||||
|
||||
#include "gskcairorendererprivate.h"
|
||||
#include "gskdebugprivate.h"
|
||||
#include "gskglrendererprivate.h"
|
||||
#include "gskprofilerprivate.h"
|
||||
#include "gskrendernodeprivate.h"
|
||||
|
||||
#include "gskenumtypes.h"
|
||||
|
||||
#include <graphene-gobject.h>
|
||||
#include <cairo-gobject.h>
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
#include <gdk/x11/gdkx.h>
|
||||
#endif
|
||||
#ifdef GDK_WINDOWING_WAYLAND
|
||||
#include <gdk/wayland/gdkwayland.h>
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
graphene_rect_t viewport;
|
||||
|
||||
GskScalingFilter min_filter;
|
||||
GskScalingFilter mag_filter;
|
||||
|
||||
GdkWindow *window;
|
||||
GdkDrawingContext *drawing_context;
|
||||
GskRenderNode *root_node;
|
||||
GdkDisplay *display;
|
||||
cairo_t *cairo_context;
|
||||
|
||||
GskProfiler *profiler;
|
||||
|
||||
int scale_factor;
|
||||
|
||||
gboolean is_realized : 1;
|
||||
} GskRendererPrivate;
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GskRenderer, gsk_renderer, G_TYPE_OBJECT)
|
||||
|
||||
enum {
|
||||
PROP_VIEWPORT = 1,
|
||||
PROP_SCALE_FACTOR,
|
||||
PROP_WINDOW,
|
||||
PROP_DISPLAY,
|
||||
PROP_DRAWING_CONTEXT,
|
||||
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *gsk_renderer_properties[N_PROPS];
|
||||
|
||||
#define GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD(obj,method) \
|
||||
g_critical ("Renderer of type '%s' does not implement GskRenderer::" # method, G_OBJECT_TYPE_NAME (obj))
|
||||
|
||||
static gboolean
|
||||
gsk_renderer_real_realize (GskRenderer *self)
|
||||
{
|
||||
GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD (self, realize);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_renderer_real_unrealize (GskRenderer *self)
|
||||
{
|
||||
GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD (self, unrealize);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_renderer_real_render (GskRenderer *self,
|
||||
GskRenderNode *root)
|
||||
{
|
||||
GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD (self, render);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_renderer_dispose (GObject *gobject)
|
||||
{
|
||||
GskRenderer *self = GSK_RENDERER (gobject);
|
||||
GskRendererPrivate *priv = gsk_renderer_get_instance_private (self);
|
||||
|
||||
gsk_renderer_unrealize (self);
|
||||
|
||||
g_clear_pointer (&priv->cairo_context, cairo_destroy);
|
||||
g_clear_object (&priv->window);
|
||||
g_clear_object (&priv->display);
|
||||
|
||||
G_OBJECT_CLASS (gsk_renderer_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_renderer_set_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GskRenderer *self = GSK_RENDERER (gobject);
|
||||
GskRendererPrivate *priv = gsk_renderer_get_instance_private (self);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_VIEWPORT:
|
||||
gsk_renderer_set_viewport (self, g_value_get_boxed (value));
|
||||
break;
|
||||
|
||||
case PROP_SCALE_FACTOR:
|
||||
gsk_renderer_set_scale_factor (self, g_value_get_int (value));
|
||||
break;
|
||||
|
||||
case PROP_WINDOW:
|
||||
gsk_renderer_set_window (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_DISPLAY:
|
||||
/* Construct-only */
|
||||
priv->display = g_value_dup_object (value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_renderer_get_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GskRenderer *self = GSK_RENDERER (gobject);
|
||||
GskRendererPrivate *priv = gsk_renderer_get_instance_private (self);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_VIEWPORT:
|
||||
g_value_set_boxed (value, &priv->viewport);
|
||||
break;
|
||||
|
||||
case PROP_SCALE_FACTOR:
|
||||
g_value_set_int (value, priv->scale_factor);
|
||||
break;
|
||||
|
||||
case PROP_WINDOW:
|
||||
g_value_set_object (value, priv->window);
|
||||
break;
|
||||
|
||||
case PROP_DRAWING_CONTEXT:
|
||||
g_value_set_object (value, priv->drawing_context);
|
||||
break;
|
||||
|
||||
case PROP_DISPLAY:
|
||||
g_value_set_object (value, priv->display);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_renderer_constructed (GObject *gobject)
|
||||
{
|
||||
GskRenderer *self = GSK_RENDERER (gobject);
|
||||
GskRendererPrivate *priv = gsk_renderer_get_instance_private (self);
|
||||
|
||||
if (priv->display == NULL)
|
||||
{
|
||||
GdkDisplayManager *manager = gdk_display_manager_get ();
|
||||
|
||||
priv->display = gdk_display_manager_get_default_display (manager);
|
||||
g_assert (priv->display != NULL);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (gsk_renderer_parent_class)->constructed (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_renderer_class_init (GskRendererClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
klass->realize = gsk_renderer_real_realize;
|
||||
klass->unrealize = gsk_renderer_real_unrealize;
|
||||
klass->render = gsk_renderer_real_render;
|
||||
|
||||
gobject_class->constructed = gsk_renderer_constructed;
|
||||
gobject_class->set_property = gsk_renderer_set_property;
|
||||
gobject_class->get_property = gsk_renderer_get_property;
|
||||
gobject_class->dispose = gsk_renderer_dispose;
|
||||
|
||||
/**
|
||||
* GskRenderer:viewport:
|
||||
*
|
||||
* The visible area used by the #GskRenderer to render its contents.
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
gsk_renderer_properties[PROP_VIEWPORT] =
|
||||
g_param_spec_boxed ("viewport",
|
||||
"Viewport",
|
||||
"The visible area used by the renderer",
|
||||
GRAPHENE_TYPE_RECT,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS |
|
||||
G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GskRenderer:display:
|
||||
*
|
||||
* The #GdkDisplay used by the #GskRenderer.
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
gsk_renderer_properties[PROP_DISPLAY] =
|
||||
g_param_spec_object ("display",
|
||||
"Display",
|
||||
"The GdkDisplay object used by the renderer",
|
||||
GDK_TYPE_DISPLAY,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
gsk_renderer_properties[PROP_WINDOW] =
|
||||
g_param_spec_object ("window",
|
||||
"Window",
|
||||
"The window associated to the renderer",
|
||||
GDK_TYPE_WINDOW,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GskRenderer:scale-factor:
|
||||
*
|
||||
* The scale factor used when rendering.
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
gsk_renderer_properties[PROP_SCALE_FACTOR] =
|
||||
g_param_spec_int ("scale-factor",
|
||||
"Scale Factor",
|
||||
"The scaling factor of the renderer",
|
||||
1, G_MAXINT,
|
||||
1,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS |
|
||||
G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GskRenderer:drawing-context:
|
||||
*
|
||||
* The drawing context used when rendering.
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
gsk_renderer_properties[PROP_DRAWING_CONTEXT] =
|
||||
g_param_spec_object ("drawing-context",
|
||||
"Drawing Context",
|
||||
"The drawing context used by the renderer",
|
||||
GDK_TYPE_DRAWING_CONTEXT,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPS, gsk_renderer_properties);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_renderer_init (GskRenderer *self)
|
||||
{
|
||||
GskRendererPrivate *priv = gsk_renderer_get_instance_private (self);
|
||||
|
||||
priv->profiler = gsk_profiler_new ();
|
||||
|
||||
priv->scale_factor = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_renderer_set_viewport:
|
||||
* @renderer: a #GskRenderer
|
||||
* @viewport: (nullable): the viewport rectangle used by the @renderer
|
||||
*
|
||||
* Sets the visible rectangle to be used as the viewport for
|
||||
* the rendering.
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
void
|
||||
gsk_renderer_set_viewport (GskRenderer *renderer,
|
||||
const graphene_rect_t *viewport)
|
||||
{
|
||||
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
|
||||
|
||||
g_return_if_fail (GSK_IS_RENDERER (renderer));
|
||||
|
||||
if (viewport == NULL)
|
||||
{
|
||||
graphene_rect_init (&priv->viewport, 0.f, 0.f, 0.f, 0.f);
|
||||
g_object_notify_by_pspec (G_OBJECT (renderer), gsk_renderer_properties[PROP_VIEWPORT]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (graphene_rect_equal (viewport, &priv->viewport))
|
||||
return;
|
||||
|
||||
graphene_rect_init_from_rect (&priv->viewport, viewport);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (renderer), gsk_renderer_properties[PROP_VIEWPORT]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_renderer_get_viewport:
|
||||
* @renderer: a #GskRenderer
|
||||
* @viewport: (out caller-allocates): return location for the viewport rectangle
|
||||
*
|
||||
* Retrieves the viewport of the #GskRenderer.
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
void
|
||||
gsk_renderer_get_viewport (GskRenderer *renderer,
|
||||
graphene_rect_t *viewport)
|
||||
{
|
||||
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
|
||||
|
||||
g_return_if_fail (GSK_IS_RENDERER (renderer));
|
||||
g_return_if_fail (viewport != NULL);
|
||||
|
||||
graphene_rect_init_from_rect (viewport, &priv->viewport);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_renderer_set_scale_factor:
|
||||
* @renderer: a #GskRenderer
|
||||
* @scale_factor: the new scale factor
|
||||
*
|
||||
* Sets the scale factor for the renderer.
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
void
|
||||
gsk_renderer_set_scale_factor (GskRenderer *renderer,
|
||||
int scale_factor)
|
||||
{
|
||||
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
|
||||
|
||||
g_return_if_fail (GSK_IS_RENDERER (renderer));
|
||||
|
||||
if (priv->scale_factor != scale_factor)
|
||||
{
|
||||
priv->scale_factor = scale_factor;
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (renderer), gsk_renderer_properties[PROP_SCALE_FACTOR]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_renderer_get_scale_factor:
|
||||
* @renderer: a #GskRenderer
|
||||
*
|
||||
* Gets the scale factor for the @renderer.
|
||||
*
|
||||
* Returns: the scale factor
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
int
|
||||
gsk_renderer_get_scale_factor (GskRenderer *renderer)
|
||||
{
|
||||
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDERER (renderer), 1);
|
||||
|
||||
return priv->scale_factor;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_renderer_set_window:
|
||||
* @renderer: a #GskRenderer
|
||||
* @window: the window to set
|
||||
*
|
||||
* Sets the window on which the @renderer is rendering.
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
void
|
||||
gsk_renderer_set_window (GskRenderer *renderer,
|
||||
GdkWindow *window)
|
||||
{
|
||||
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
|
||||
|
||||
g_return_if_fail (GSK_IS_RENDERER (renderer));
|
||||
g_return_if_fail (!priv->is_realized);
|
||||
g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
|
||||
|
||||
if (g_set_object (&priv->window, window))
|
||||
g_object_notify_by_pspec (G_OBJECT (renderer), gsk_renderer_properties[PROP_WINDOW]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_renderer_get_window:
|
||||
* @renderer: a #GskRenderer
|
||||
*
|
||||
* Retrieves the #GdkWindow set using gsk_renderer_set_window().
|
||||
*
|
||||
* Returns: (transfer none) (nullable): a #GdkWindow
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
GdkWindow *
|
||||
gsk_renderer_get_window (GskRenderer *renderer)
|
||||
{
|
||||
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
|
||||
|
||||
return priv->window;
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gsk_renderer_get_root_node:
|
||||
* @renderer: a #GskRenderer
|
||||
*
|
||||
* Retrieves the #GskRenderNode used by @renderer.
|
||||
*
|
||||
* Returns: (transfer none) (nullable): a #GskRenderNode
|
||||
*/
|
||||
GskRenderNode *
|
||||
gsk_renderer_get_root_node (GskRenderer *renderer)
|
||||
{
|
||||
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
|
||||
|
||||
return priv->root_node;
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gsk_renderer_get_drawing_context:
|
||||
* @renderer: a #GskRenderer
|
||||
*
|
||||
* Retrieves the #GdkDrawingContext used by @renderer.
|
||||
*
|
||||
* Returns: (transfer none) (nullable): a #GdkDrawingContext
|
||||
*/
|
||||
GdkDrawingContext *
|
||||
gsk_renderer_get_drawing_context (GskRenderer *renderer)
|
||||
{
|
||||
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
|
||||
|
||||
return priv->drawing_context;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_renderer_get_display:
|
||||
* @renderer: a #GskRenderer
|
||||
*
|
||||
* Retrieves the #GdkDisplay used when creating the #GskRenderer.
|
||||
*
|
||||
* Returns: (transfer none): a #GdkDisplay
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
GdkDisplay *
|
||||
gsk_renderer_get_display (GskRenderer *renderer)
|
||||
{
|
||||
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
|
||||
|
||||
return priv->display;
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gsk_renderer_is_realized:
|
||||
* @renderer: a #GskRenderer
|
||||
*
|
||||
* Checks whether the @renderer is realized or not.
|
||||
*
|
||||
* Returns: %TRUE if the #GskRenderer was realized, and %FALSE otherwise
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
gboolean
|
||||
gsk_renderer_is_realized (GskRenderer *renderer)
|
||||
{
|
||||
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDERER (renderer), FALSE);
|
||||
|
||||
return priv->is_realized;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_renderer_realize:
|
||||
* @renderer: a #GskRenderer
|
||||
*
|
||||
* Creates the resources needed by the @renderer to render the scene
|
||||
* graph.
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
gboolean
|
||||
gsk_renderer_realize (GskRenderer *renderer)
|
||||
{
|
||||
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDERER (renderer), FALSE);
|
||||
|
||||
if (priv->is_realized)
|
||||
return TRUE;
|
||||
|
||||
priv->is_realized = GSK_RENDERER_GET_CLASS (renderer)->realize (renderer);
|
||||
|
||||
return priv->is_realized;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_renderer_unrealize:
|
||||
* @renderer: a #GskRenderer
|
||||
*
|
||||
* Releases all the resources created by gsk_renderer_realize().
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
void
|
||||
gsk_renderer_unrealize (GskRenderer *renderer)
|
||||
{
|
||||
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
|
||||
|
||||
g_return_if_fail (GSK_IS_RENDERER (renderer));
|
||||
|
||||
if (!priv->is_realized)
|
||||
return;
|
||||
|
||||
GSK_RENDERER_GET_CLASS (renderer)->unrealize (renderer);
|
||||
|
||||
priv->is_realized = FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_renderer_render:
|
||||
* @renderer: a #GskRenderer
|
||||
* @root: a #GskRenderNode
|
||||
* @context: a #GdkDrawingContext
|
||||
*
|
||||
* Renders the scene graph, described by a tree of #GskRenderNode instances,
|
||||
* using the given #GdkDrawingContext.
|
||||
*
|
||||
* The @renderer will acquire a reference on the #GskRenderNode tree while
|
||||
* the rendering is in progress, and will make the tree immutable.
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
void
|
||||
gsk_renderer_render (GskRenderer *renderer,
|
||||
GskRenderNode *root,
|
||||
GdkDrawingContext *context)
|
||||
{
|
||||
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
|
||||
|
||||
g_return_if_fail (GSK_IS_RENDERER (renderer));
|
||||
g_return_if_fail (priv->is_realized);
|
||||
g_return_if_fail (GSK_IS_RENDER_NODE (root));
|
||||
g_return_if_fail (context == NULL || GDK_IS_DRAWING_CONTEXT (context));
|
||||
g_return_if_fail (priv->drawing_context == NULL);
|
||||
g_return_if_fail (priv->root_node == NULL);
|
||||
g_return_if_fail (root->renderer == renderer);
|
||||
|
||||
if (context != NULL)
|
||||
priv->drawing_context = g_object_ref (context);
|
||||
else
|
||||
{
|
||||
if (priv->cairo_context == NULL)
|
||||
{
|
||||
g_critical ("The given GskRenderer instance was not created using "
|
||||
"gsk_renderer_create_fallback(), but you forgot to pass "
|
||||
"a GdkDrawingContext.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
priv->root_node = gsk_render_node_ref (root);
|
||||
gsk_render_node_make_immutable (priv->root_node);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
gsk_profiler_reset (priv->profiler);
|
||||
#endif
|
||||
|
||||
GSK_RENDERER_GET_CLASS (renderer)->render (renderer, root);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
if (GSK_DEBUG_CHECK (RENDERER))
|
||||
{
|
||||
GString *buf = g_string_new ("*** Frame stats ***\n\n");
|
||||
|
||||
gsk_profiler_append_counters (priv->profiler, buf);
|
||||
g_string_append_c (buf, '\n');
|
||||
|
||||
gsk_profiler_append_timers (priv->profiler, buf);
|
||||
g_string_append_c (buf, '\n');
|
||||
|
||||
g_print ("%s\n***\n\n", buf->str);
|
||||
|
||||
g_string_free (buf, TRUE);
|
||||
}
|
||||
#endif
|
||||
|
||||
g_clear_object (&priv->drawing_context);
|
||||
g_clear_pointer (&priv->root_node, gsk_render_node_unref);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_renderer_create_render_node:
|
||||
* @renderer: a #GskRenderer
|
||||
*
|
||||
* Creates a new #GskRenderNode instance tied to the given @renderer.
|
||||
*
|
||||
* Returns: (transfer full): the new #GskRenderNode
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
GskRenderNode *
|
||||
gsk_renderer_create_render_node (GskRenderer *renderer)
|
||||
{
|
||||
g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
|
||||
|
||||
return gsk_render_node_new (renderer);
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gsk_renderer_get_profiler:
|
||||
* @renderer: a #GskRenderer
|
||||
*
|
||||
* Retrieves a pointer to the GskProfiler instance of the renderer.
|
||||
*
|
||||
* Returns: (transfer none): the profiler
|
||||
*/
|
||||
GskProfiler *
|
||||
gsk_renderer_get_profiler (GskRenderer *renderer)
|
||||
{
|
||||
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
|
||||
|
||||
return priv->profiler;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_renderer_get_for_display:
|
||||
* @display: a #GdkDisplay
|
||||
*
|
||||
* Creates an appropriate #GskRenderer instance for the given @display.
|
||||
*
|
||||
* Returns: (transfer full) (nullable): a #GskRenderer
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
GskRenderer *
|
||||
gsk_renderer_get_for_display (GdkDisplay *display)
|
||||
{
|
||||
static const char *use_software;
|
||||
|
||||
GType renderer_type = G_TYPE_INVALID;
|
||||
|
||||
if (use_software == NULL)
|
||||
{
|
||||
use_software = g_getenv ("GSK_USE_SOFTWARE");
|
||||
if (use_software == NULL)
|
||||
use_software = "0";
|
||||
}
|
||||
|
||||
if (use_software[0] != '0')
|
||||
return g_object_new (GSK_TYPE_CAIRO_RENDERER, "display", display, NULL);
|
||||
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
if (GDK_IS_X11_DISPLAY (display))
|
||||
renderer_type = GSK_TYPE_GL_RENDERER;
|
||||
else
|
||||
#endif
|
||||
#ifdef GDK_WINDOWING_WAYLAND
|
||||
if (GDK_IS_WAYLAND_DISPLAY (display))
|
||||
renderer_type = GSK_TYPE_GL_RENDERER;
|
||||
else
|
||||
#endif
|
||||
renderer_type = GSK_TYPE_CAIRO_RENDERER;
|
||||
|
||||
GSK_NOTE (RENDERER, g_print ("Creating renderer of type '%s' for display '%s'\n",
|
||||
g_type_name (renderer_type),
|
||||
G_OBJECT_TYPE_NAME (display)));
|
||||
|
||||
g_assert (renderer_type != G_TYPE_INVALID);
|
||||
|
||||
return g_object_new (renderer_type, "display", display, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_renderer_set_cairo_context (GskRenderer *renderer,
|
||||
cairo_t *cr)
|
||||
{
|
||||
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
|
||||
|
||||
g_clear_pointer (&priv->cairo_context, cairo_destroy);
|
||||
|
||||
if (cr != NULL)
|
||||
priv->cairo_context = cairo_reference (cr);
|
||||
}
|
||||
|
||||
cairo_t *
|
||||
gsk_renderer_get_cairo_context (GskRenderer *renderer)
|
||||
{
|
||||
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
|
||||
|
||||
return priv->cairo_context;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_renderer_create_fallback:
|
||||
* @renderer: a #GskRenderer
|
||||
* @viewport: the viewport for the fallback renderer
|
||||
* @cr: a Cairo context
|
||||
*
|
||||
* Creates a fallback #GskRenderer using the same display and window of
|
||||
* the given @renderer, and instructs it to render to a given Cairo
|
||||
* context.
|
||||
*
|
||||
* Typically, you'll use this function to implement fallback rendering
|
||||
* of #GskRenderNodes on an intermediate Cairo context, instead of using
|
||||
* the drawing context associated to a #GdkWindow's rendering buffer.
|
||||
*
|
||||
* Returns: (transfer full): a newly created fallback #GskRenderer instance
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
GskRenderer *
|
||||
gsk_renderer_create_fallback (GskRenderer *renderer,
|
||||
const graphene_rect_t *viewport,
|
||||
cairo_t *cr)
|
||||
{
|
||||
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
|
||||
GskRenderer *res;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
|
||||
g_return_val_if_fail (cr != NULL, NULL);
|
||||
|
||||
res = g_object_new (GSK_TYPE_CAIRO_RENDERER,
|
||||
"display", priv->display,
|
||||
"window", priv->window,
|
||||
"scale-factor", priv->scale_factor,
|
||||
"viewport", viewport,
|
||||
NULL);
|
||||
|
||||
gsk_renderer_set_cairo_context (res, cr);
|
||||
gsk_renderer_realize (res);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/* GSK - The GTK Scene Kit
|
||||
*
|
||||
* Copyright 2016 Endless
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __GSK_RENDERER_H__
|
||||
#define __GSK_RENDERER_H__
|
||||
|
||||
#if !defined (__GSK_H_INSIDE__) && !defined (GSK_COMPILATION)
|
||||
#error "Only <gsk/gsk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gsk/gsktypes.h>
|
||||
#include <gsk/gskrendernode.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_RENDERER (gsk_renderer_get_type ())
|
||||
|
||||
#define GSK_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_RENDERER, GskRenderer))
|
||||
#define GSK_IS_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_RENDERER))
|
||||
|
||||
typedef struct _GskRenderer GskRenderer;
|
||||
typedef struct _GskRendererClass GskRendererClass;
|
||||
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GType gsk_renderer_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GskRenderer * gsk_renderer_get_for_display (GdkDisplay *display);
|
||||
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
void gsk_renderer_set_viewport (GskRenderer *renderer,
|
||||
const graphene_rect_t *viewport);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
void gsk_renderer_get_viewport (GskRenderer *renderer,
|
||||
graphene_rect_t *viewport);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
void gsk_renderer_set_scale_factor (GskRenderer *renderer,
|
||||
int scale_factor);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
int gsk_renderer_get_scale_factor (GskRenderer *renderer);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
void gsk_renderer_set_window (GskRenderer *renderer,
|
||||
GdkWindow *window);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GdkWindow * gsk_renderer_get_window (GskRenderer *renderer);
|
||||
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GdkDisplay * gsk_renderer_get_display (GskRenderer *renderer);
|
||||
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
gboolean gsk_renderer_realize (GskRenderer *renderer);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
void gsk_renderer_unrealize (GskRenderer *renderer);
|
||||
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GskRenderNode * gsk_renderer_create_render_node (GskRenderer *renderer);
|
||||
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GskRenderer * gsk_renderer_create_fallback (GskRenderer *renderer,
|
||||
const graphene_rect_t *viewport,
|
||||
cairo_t *cr);
|
||||
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
void gsk_renderer_render (GskRenderer *renderer,
|
||||
GskRenderNode *root,
|
||||
GdkDrawingContext *context);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_RENDERER_H__ */
|
||||
@@ -0,0 +1,57 @@
|
||||
/* GSK - The GTK Scene Kit
|
||||
*
|
||||
* Copyright 2016 Endless
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __GSK_RENDERER_PRIVATE_H__
|
||||
#define __GSK_RENDERER_PRIVATE_H__
|
||||
|
||||
#include "gskrenderer.h"
|
||||
#include "gskprofilerprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_RENDERER, GskRendererClass))
|
||||
#define GSK_IS_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_RENDERER))
|
||||
#define GSK_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_RENDERER, GskRendererClass))
|
||||
|
||||
struct _GskRenderer
|
||||
{
|
||||
GObject parent_instance;
|
||||
};
|
||||
|
||||
struct _GskRendererClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
gboolean (* realize) (GskRenderer *renderer);
|
||||
void (* unrealize) (GskRenderer *renderer);
|
||||
|
||||
void (* render) (GskRenderer *renderer,
|
||||
GskRenderNode *root);
|
||||
};
|
||||
|
||||
gboolean gsk_renderer_is_realized (GskRenderer *renderer);
|
||||
|
||||
GskRenderNode * gsk_renderer_get_root_node (GskRenderer *renderer);
|
||||
GdkDrawingContext * gsk_renderer_get_drawing_context (GskRenderer *renderer);
|
||||
cairo_t * gsk_renderer_get_cairo_context (GskRenderer *renderer);
|
||||
|
||||
GskProfiler * gsk_renderer_get_profiler (GskRenderer *renderer);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_RENDERER_PRIVATE_H__ */
|
||||
+1581
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,146 @@
|
||||
/* GSK - The GTK Scene Kit
|
||||
*
|
||||
* Copyright 2016 Endless
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __GSK_RENDER_NODE_H__
|
||||
#define __GSK_RENDER_NODE_H__
|
||||
|
||||
#if !defined (__GSK_H_INSIDE__) && !defined (GSK_COMPILATION)
|
||||
#error "Only <gsk/gsk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gsk/gsktypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_RENDER_NODE (gsk_render_node_get_type ())
|
||||
|
||||
#define GSK_RENDER_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_RENDER_NODE, GskRenderNode))
|
||||
#define GSK_IS_RENDER_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_RENDER_NODE))
|
||||
|
||||
typedef struct _GskRenderNode GskRenderNode;
|
||||
typedef struct _GskRenderNodeClass GskRenderNodeClass;
|
||||
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GType gsk_render_node_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GskRenderNode * gsk_render_node_ref (GskRenderNode *node);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
void gsk_render_node_unref (GskRenderNode *node);
|
||||
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GskRenderNode * gsk_render_node_get_parent (GskRenderNode *node);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GskRenderNode * gsk_render_node_get_first_child (GskRenderNode *node);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GskRenderNode * gsk_render_node_get_last_child (GskRenderNode *node);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GskRenderNode * gsk_render_node_get_next_sibling (GskRenderNode *node);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GskRenderNode * gsk_render_node_get_previous_sibling (GskRenderNode *node);
|
||||
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GskRenderNode * gsk_render_node_append_child (GskRenderNode *node,
|
||||
GskRenderNode *child);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GskRenderNode * gsk_render_node_prepend_child (GskRenderNode *node,
|
||||
GskRenderNode *child);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GskRenderNode * gsk_render_node_insert_child_at_pos (GskRenderNode *node,
|
||||
GskRenderNode *child,
|
||||
int index_);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GskRenderNode * gsk_render_node_insert_child_before (GskRenderNode *node,
|
||||
GskRenderNode *child,
|
||||
GskRenderNode *sibling);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GskRenderNode * gsk_render_node_insert_child_after (GskRenderNode *node,
|
||||
GskRenderNode *child,
|
||||
GskRenderNode *sibling);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GskRenderNode * gsk_render_node_remove_child (GskRenderNode *node,
|
||||
GskRenderNode *child);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GskRenderNode * gsk_render_node_replace_child (GskRenderNode *node,
|
||||
GskRenderNode *new_child,
|
||||
GskRenderNode *old_child);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GskRenderNode * gsk_render_node_remove_all_children (GskRenderNode *node);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
guint gsk_render_node_get_n_children (GskRenderNode *node);
|
||||
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
gboolean gsk_render_node_contains (GskRenderNode *node,
|
||||
GskRenderNode *descendant);
|
||||
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
void gsk_render_node_set_bounds (GskRenderNode *node,
|
||||
const graphene_rect_t *bounds);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
void gsk_render_node_set_transform (GskRenderNode *node,
|
||||
const graphene_matrix_t *transform);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
void gsk_render_node_set_anchor_point (GskRenderNode *node,
|
||||
const graphene_point3d_t *offset);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
void gsk_render_node_set_opacity (GskRenderNode *node,
|
||||
double opacity);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
void gsk_render_node_set_hidden (GskRenderNode *node,
|
||||
gboolean hidden);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
gboolean gsk_render_node_is_hidden (GskRenderNode *node);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
void gsk_render_node_set_opaque (GskRenderNode *node,
|
||||
gboolean opaque);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
gboolean gsk_render_node_is_opaque (GskRenderNode *node);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
cairo_t * gsk_render_node_get_draw_context (GskRenderNode *node);
|
||||
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
void gsk_render_node_set_blend_mode (GskRenderNode *node,
|
||||
GskBlendMode blend_mode);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
void gsk_render_node_set_texture (GskRenderNode *node,
|
||||
int texture_id);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
void gsk_render_node_set_scaling_filter (GskRenderNode *node,
|
||||
GskScalingFilter min_filter,
|
||||
GskScalingFilter mag_filter);
|
||||
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
void gsk_render_node_set_name (GskRenderNode *node,
|
||||
const char *name);
|
||||
|
||||
#define GSK_VALUE_HOLDS_RENDER_NODE(value) (G_VALUE_HOLDS (value, GSK_TYPE_RENDER_NODE))
|
||||
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
void gsk_value_set_render_node (GValue *value,
|
||||
GskRenderNode *node);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
void gsk_value_take_render_node (GValue *value,
|
||||
GskRenderNode *node);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GskRenderNode * gsk_value_get_render_node (const GValue *value);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GskRenderNode * gsk_value_dup_render_node (const GValue *value);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_RENDER_NODE_H__ */
|
||||
@@ -0,0 +1,254 @@
|
||||
/* GSK - The GTK Scene Kit
|
||||
*
|
||||
* Copyright 2016 Endless
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:GskRenderNodeIter
|
||||
* @Title: GskRenderNodeIter
|
||||
* @Short_description: Iterator helper for render nodes
|
||||
*
|
||||
* TODO
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gskrendernodeiter.h"
|
||||
#include "gskrendernodeprivate.h"
|
||||
|
||||
typedef struct {
|
||||
GskRenderNode *root;
|
||||
GskRenderNode *current;
|
||||
gint64 age;
|
||||
gpointer reserved1;
|
||||
gpointer reserved2;
|
||||
} RealIter;
|
||||
|
||||
#define REAL_ITER(iter) ((RealIter *) (iter))
|
||||
|
||||
/**
|
||||
* gsk_render_node_iter_new: (constructor)
|
||||
*
|
||||
* Allocates a new #GskRenderNodeIter.
|
||||
*
|
||||
* Returns: (transfer full): the newly allocated #GskRenderNodeIter
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
GskRenderNodeIter *
|
||||
gsk_render_node_iter_new (void)
|
||||
{
|
||||
return g_slice_new (GskRenderNodeIter);
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gsk_render_node_iter_copy:
|
||||
* @src: a #GskRenderNodeIter
|
||||
*
|
||||
* Copies a #GskRenderNodeIter.
|
||||
*
|
||||
* Returns: (transfer full): a #GskRenderNodeIter
|
||||
*/
|
||||
static GskRenderNodeIter *
|
||||
gsk_render_node_iter_copy (GskRenderNodeIter *src)
|
||||
{
|
||||
return g_slice_dup (GskRenderNodeIter, src);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_render_node_iter_free:
|
||||
* @iter: a #GskRenderNodeIter
|
||||
*
|
||||
* Frees the resources allocated by gsk_render_node_iter_new().
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
void
|
||||
gsk_render_node_iter_free (GskRenderNodeIter *iter)
|
||||
{
|
||||
g_slice_free (GskRenderNodeIter, iter);
|
||||
}
|
||||
|
||||
G_DEFINE_BOXED_TYPE (GskRenderNodeIter, gsk_render_node_iter,
|
||||
gsk_render_node_iter_copy,
|
||||
gsk_render_node_iter_free)
|
||||
|
||||
/**
|
||||
* gsk_render_node_iter_init:
|
||||
* @iter: a #GskRenderNodeIter
|
||||
* @node: a #GskRenderNode
|
||||
*
|
||||
* Initializes a #GskRenderNodeIter for iterating over the
|
||||
* children of @node.
|
||||
*
|
||||
* It's safe to call this function multiple times on the same
|
||||
* #GskRenderNodeIter instance.
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
void
|
||||
gsk_render_node_iter_init (GskRenderNodeIter *iter,
|
||||
GskRenderNode *node)
|
||||
{
|
||||
RealIter *riter = REAL_ITER (iter);
|
||||
|
||||
g_return_if_fail (iter != NULL);
|
||||
g_return_if_fail (GSK_IS_RENDER_NODE (node));
|
||||
|
||||
riter->root = node;
|
||||
riter->age = node->age;
|
||||
riter->current = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_render_node_iter_is_valid:
|
||||
* @iter: a #GskRenderNodeIter
|
||||
*
|
||||
* Checks whether a #GskRenderNodeIter is associated to a #GskRenderNode,
|
||||
* or whether the associated node was modified while iterating.
|
||||
*
|
||||
* Returns: %TRUE if the iterator is still valid.
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
gboolean
|
||||
gsk_render_node_iter_is_valid (GskRenderNodeIter *iter)
|
||||
{
|
||||
RealIter *riter = REAL_ITER (iter);
|
||||
|
||||
g_return_val_if_fail (iter != NULL, FALSE);
|
||||
|
||||
if (riter->root == NULL)
|
||||
return FALSE;
|
||||
|
||||
return riter->root->age == riter->age;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_render_node_iter_next:
|
||||
* @iter: a #GskRenderNodeIter
|
||||
* @child: (out) (transfer none): return location for a #GskRenderNode
|
||||
*
|
||||
* Advances the @iter and retrieves the next child of the root #GskRenderNode
|
||||
* used to initialize the #GskRenderNodeIter.
|
||||
*
|
||||
* If the iterator could advance, this function returns %TRUE and sets the
|
||||
* @child argument with the child #GskRenderNode.
|
||||
*
|
||||
* If the iterator could not advance, this function returns %FALSE and the
|
||||
* contents of the @child argument are undefined.
|
||||
*
|
||||
* Returns: %TRUE if the iterator could advance, and %FALSE otherwise
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
gboolean
|
||||
gsk_render_node_iter_next (GskRenderNodeIter *iter,
|
||||
GskRenderNode **child)
|
||||
{
|
||||
RealIter *riter = REAL_ITER (iter);
|
||||
|
||||
g_return_val_if_fail (riter != NULL, FALSE);
|
||||
g_return_val_if_fail (riter->root != NULL, FALSE);
|
||||
g_return_val_if_fail (riter->root->age == riter->age, FALSE);
|
||||
|
||||
if (riter->current == NULL)
|
||||
riter->current = riter->root->first_child;
|
||||
else
|
||||
riter->current = riter->current->next_sibling;
|
||||
|
||||
if (child != NULL)
|
||||
*child = riter->current;
|
||||
|
||||
return riter->current != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_render_node_iter_prev:
|
||||
* @iter: a #GskRenderNodeIter
|
||||
* @child: (out) (transfer none): return location for a #GskRenderNode
|
||||
*
|
||||
* Advances the @iter and retrieves the previous child of the root
|
||||
* #GskRenderNode used to initialize the #GskRenderNodeIter.
|
||||
*
|
||||
* If the iterator could advance, this function returns %TRUE and sets the
|
||||
* @child argument with the child #GskRenderNode.
|
||||
*
|
||||
* If the iterator could not advance, this function returns %FALSE and the
|
||||
* contents of the @child argument are undefined.
|
||||
*
|
||||
* Returns: %TRUE if the iterator could advance, and %FALSE otherwise
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
gboolean
|
||||
gsk_render_node_iter_prev (GskRenderNodeIter *iter,
|
||||
GskRenderNode **child)
|
||||
{
|
||||
RealIter *riter = REAL_ITER (iter);
|
||||
|
||||
g_return_val_if_fail (riter != NULL, FALSE);
|
||||
g_return_val_if_fail (riter->root != NULL, FALSE);
|
||||
g_return_val_if_fail (riter->root->age == riter->age, FALSE);
|
||||
|
||||
if (riter->current == NULL)
|
||||
riter->current = riter->root->last_child;
|
||||
else
|
||||
riter->current = riter->current->prev_sibling;
|
||||
|
||||
if (child != NULL)
|
||||
*child = riter->current;
|
||||
|
||||
return riter->current != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_render_node_iter_remove:
|
||||
* @iter: a #GskRenderNodeIter
|
||||
*
|
||||
* Removes the child #GskRenderNode currently being visited by
|
||||
* the iterator.
|
||||
*
|
||||
* Calling this function on an invalid #GskRenderNodeIter results
|
||||
* in undefined behavior.
|
||||
*
|
||||
* Since: 3.22
|
||||
*/
|
||||
void
|
||||
gsk_render_node_iter_remove (GskRenderNodeIter *iter)
|
||||
{
|
||||
RealIter *riter = REAL_ITER (iter);
|
||||
GskRenderNode *tmp;
|
||||
|
||||
g_return_if_fail (riter != NULL);
|
||||
g_return_if_fail (riter->root != NULL);
|
||||
g_return_if_fail (riter->root->age == riter->age);
|
||||
g_return_if_fail (riter->current != NULL);
|
||||
|
||||
tmp = riter->current;
|
||||
|
||||
if (tmp != NULL)
|
||||
{
|
||||
riter->current = tmp->prev_sibling;
|
||||
|
||||
gsk_render_node_remove_child (riter->root, tmp);
|
||||
|
||||
riter->age += 1;
|
||||
|
||||
/* Safety net */
|
||||
g_assert (riter->age == riter->root->age);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
#ifndef __GSK_RENDER_NODE_ITER_H__
|
||||
#define __GSK_RENDER_NODE_ITER_H__
|
||||
|
||||
#include <gsk/gskrendernode.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_RENDER_NODE_ITER (gsk_render_node_iter_get_type())
|
||||
|
||||
typedef struct _GskRenderNodeIter GskRenderNodeIter;
|
||||
|
||||
struct _GskRenderNodeIter
|
||||
{
|
||||
/*< private >*/
|
||||
gpointer dummy1;
|
||||
gpointer dummy2;
|
||||
gint64 dummy3;
|
||||
gpointer dummy4;
|
||||
gpointer dummy5;
|
||||
};
|
||||
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GType gsk_render_node_iter_get_type (void) G_GNUC_CONST;
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
GskRenderNodeIter * gsk_render_node_iter_new (void);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
void gsk_render_node_iter_free (GskRenderNodeIter *iter);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
void gsk_render_node_iter_init (GskRenderNodeIter *iter,
|
||||
GskRenderNode *node);
|
||||
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
gboolean gsk_render_node_iter_is_valid (GskRenderNodeIter *iter);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
gboolean gsk_render_node_iter_prev (GskRenderNodeIter *iter,
|
||||
GskRenderNode **child);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
gboolean gsk_render_node_iter_next (GskRenderNodeIter *iter,
|
||||
GskRenderNode **child);
|
||||
GDK_AVAILABLE_IN_3_22
|
||||
void gsk_render_node_iter_remove (GskRenderNodeIter *iter);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* GSK_RENDER_NODE_ITER_H */
|
||||
@@ -0,0 +1,113 @@
|
||||
#ifndef __GSK_RENDER_NODE_PRIVATE_H__
|
||||
#define __GSK_RENDER_NODE_PRIVATE_H__
|
||||
|
||||
#include "gskrendernode.h"
|
||||
#include "gskrenderer.h"
|
||||
#include <cairo.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_RENDER_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_RENDER_NODE, GskRenderNodeClass))
|
||||
#define GSK_IS_RENDER_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_RENDER_NODE))
|
||||
#define GSK_RENDER_NODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_RENDER_NODE, GskRenderNodeClass))
|
||||
|
||||
struct _GskRenderNode
|
||||
{
|
||||
GTypeInstance parent_instance;
|
||||
|
||||
volatile int ref_count;
|
||||
|
||||
/* Back pointer to the renderer that created the node */
|
||||
GskRenderer *renderer;
|
||||
|
||||
/* The graph */
|
||||
GskRenderNode *parent;
|
||||
GskRenderNode *first_child;
|
||||
GskRenderNode *last_child;
|
||||
GskRenderNode *prev_sibling;
|
||||
GskRenderNode *next_sibling;
|
||||
|
||||
int n_children;
|
||||
|
||||
/* Use for debugging */
|
||||
char *name;
|
||||
|
||||
/* Tag updated when adding/removing children */
|
||||
gint64 age;
|
||||
|
||||
/* The contents of the node as a Cairo surface */
|
||||
cairo_surface_t *surface;
|
||||
|
||||
/* The contents of the node as a GL surface */
|
||||
int texture_id;
|
||||
|
||||
/* Paint opacity */
|
||||
double opacity;
|
||||
|
||||
/* Blend mode */
|
||||
GskBlendMode blend_mode;
|
||||
|
||||
/* Scaling filters */
|
||||
GskScalingFilter min_filter;
|
||||
GskScalingFilter mag_filter;
|
||||
|
||||
/* Clip rectangle */
|
||||
graphene_rect_t bounds;
|
||||
|
||||
/* Transformations relative to the root of the scene */
|
||||
graphene_matrix_t world_matrix;
|
||||
|
||||
/* Transformations applied to the node */
|
||||
graphene_matrix_t transform;
|
||||
|
||||
graphene_point3d_t anchor_point;
|
||||
|
||||
/* Bit fields; leave at the end */
|
||||
gboolean is_mutable : 1;
|
||||
gboolean hidden : 1;
|
||||
gboolean opaque : 1;
|
||||
gboolean transform_set : 1;
|
||||
gboolean needs_world_matrix_update : 1;
|
||||
};
|
||||
|
||||
struct _GskRenderNodeClass
|
||||
{
|
||||
GTypeClass parent_class;
|
||||
|
||||
void (* finalize) (GskRenderNode *node);
|
||||
};
|
||||
|
||||
GskRenderNode *gsk_render_node_new (GskRenderer *renderer);
|
||||
|
||||
void gsk_render_node_make_immutable (GskRenderNode *node);
|
||||
|
||||
void gsk_render_node_get_bounds (GskRenderNode *node,
|
||||
graphene_rect_t *frame);
|
||||
void gsk_render_node_get_transform (GskRenderNode *node,
|
||||
graphene_matrix_t *mv);
|
||||
double gsk_render_node_get_opacity (GskRenderNode *node);
|
||||
|
||||
cairo_surface_t *gsk_render_node_get_surface (GskRenderNode *node);
|
||||
|
||||
int gsk_render_node_get_texture (GskRenderNode *node);
|
||||
|
||||
gboolean gsk_render_node_has_surface (GskRenderNode *node);
|
||||
gboolean gsk_render_node_has_texture (GskRenderNode *node);
|
||||
|
||||
GskBlendMode gsk_render_node_get_blend_mode (GskRenderNode *node);
|
||||
|
||||
GskRenderNode *gsk_render_node_get_toplevel (GskRenderNode *node);
|
||||
|
||||
int gsk_render_node_get_scale_factor (GskRenderNode *node);
|
||||
|
||||
void gsk_render_node_update_world_matrix (GskRenderNode *node,
|
||||
gboolean force);
|
||||
|
||||
void gsk_render_node_get_world_matrix (GskRenderNode *node,
|
||||
graphene_matrix_t *mv);
|
||||
|
||||
int gsk_render_node_get_size (GskRenderNode *root);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_RENDER_NODE_PRIVATE_H__ */
|
||||
@@ -0,0 +1,482 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gskshaderbuilderprivate.h"
|
||||
|
||||
#include "gskdebugprivate.h"
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
typedef struct {
|
||||
int program_id;
|
||||
|
||||
GHashTable *uniform_locations;
|
||||
GHashTable *attribute_locations;
|
||||
} ShaderProgram;
|
||||
|
||||
struct _GskShaderBuilder
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
char *resource_base_path;
|
||||
char *vertex_preamble;
|
||||
char *fragment_preamble;
|
||||
|
||||
int version;
|
||||
|
||||
GPtrArray *defines;
|
||||
GPtrArray *uniforms;
|
||||
GPtrArray *attributes;
|
||||
|
||||
GHashTable *programs;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GskShaderBuilder, gsk_shader_builder, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
shader_program_free (gpointer data)
|
||||
{
|
||||
ShaderProgram *p = data;
|
||||
|
||||
g_clear_pointer (&p->uniform_locations, g_hash_table_unref);
|
||||
g_clear_pointer (&p->attribute_locations, g_hash_table_unref);
|
||||
|
||||
glDeleteProgram (p->program_id);
|
||||
|
||||
g_slice_free (ShaderProgram, data);
|
||||
}
|
||||
|
||||
static ShaderProgram *
|
||||
shader_program_new (int program_id)
|
||||
{
|
||||
ShaderProgram *p = g_slice_new (ShaderProgram);
|
||||
|
||||
p->program_id = program_id;
|
||||
|
||||
p->uniform_locations = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
p->attribute_locations = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_shader_builder_finalize (GObject *gobject)
|
||||
{
|
||||
GskShaderBuilder *self = GSK_SHADER_BUILDER (gobject);
|
||||
|
||||
g_free (self->resource_base_path);
|
||||
|
||||
g_clear_pointer (&self->defines, g_ptr_array_unref);
|
||||
g_clear_pointer (&self->uniforms, g_ptr_array_unref);
|
||||
g_clear_pointer (&self->attributes, g_ptr_array_unref);
|
||||
|
||||
g_clear_pointer (&self->programs, g_hash_table_unref);
|
||||
|
||||
G_OBJECT_CLASS (gsk_shader_builder_parent_class)->finalize (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_shader_builder_class_init (GskShaderBuilderClass *klass)
|
||||
{
|
||||
G_OBJECT_CLASS (klass)->finalize = gsk_shader_builder_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_shader_builder_init (GskShaderBuilder *self)
|
||||
{
|
||||
self->defines = g_ptr_array_new_with_free_func (g_free);
|
||||
self->uniforms = g_ptr_array_new_with_free_func (g_free);
|
||||
self->attributes = g_ptr_array_new_with_free_func (g_free);
|
||||
|
||||
self->programs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
|
||||
NULL,
|
||||
shader_program_free);
|
||||
}
|
||||
|
||||
GskShaderBuilder *
|
||||
gsk_shader_builder_new (void)
|
||||
{
|
||||
return g_object_new (GSK_TYPE_SHADER_BUILDER, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_shader_builder_set_resource_base_path (GskShaderBuilder *builder,
|
||||
const char *base_path)
|
||||
{
|
||||
g_return_if_fail (GSK_IS_SHADER_BUILDER (builder));
|
||||
|
||||
g_free (builder->resource_base_path);
|
||||
builder->resource_base_path = g_strdup (base_path);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_shader_builder_set_vertex_preamble (GskShaderBuilder *builder,
|
||||
const char *vertex_preamble)
|
||||
{
|
||||
g_return_if_fail (GSK_IS_SHADER_BUILDER (builder));
|
||||
|
||||
g_free (builder->vertex_preamble);
|
||||
builder->vertex_preamble = g_strdup (vertex_preamble);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_shader_builder_set_fragment_preamble (GskShaderBuilder *builder,
|
||||
const char *fragment_preamble)
|
||||
{
|
||||
g_return_if_fail (GSK_IS_SHADER_BUILDER (builder));
|
||||
|
||||
g_free (builder->fragment_preamble);
|
||||
builder->fragment_preamble = g_strdup (fragment_preamble);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_shader_builder_set_version (GskShaderBuilder *builder,
|
||||
int version)
|
||||
{
|
||||
g_return_if_fail (GSK_IS_SHADER_BUILDER (builder));
|
||||
|
||||
builder->version = version;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_shader_builder_add_define (GskShaderBuilder *builder,
|
||||
const char *define_name,
|
||||
const char *define_value)
|
||||
{
|
||||
g_return_if_fail (GSK_IS_SHADER_BUILDER (builder));
|
||||
g_return_if_fail (define_name != NULL && *define_name != '\0');
|
||||
g_return_if_fail (define_value != NULL && *define_name != '\0');
|
||||
|
||||
g_ptr_array_add (builder->defines, g_strdup (define_name));
|
||||
g_ptr_array_add (builder->defines, g_strdup (define_value));
|
||||
}
|
||||
|
||||
GQuark
|
||||
gsk_shader_builder_add_uniform (GskShaderBuilder *builder,
|
||||
const char *uniform_name)
|
||||
{
|
||||
g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), 0);
|
||||
g_return_val_if_fail (uniform_name != NULL, 0);
|
||||
|
||||
g_ptr_array_add (builder->uniforms, g_strdup (uniform_name));
|
||||
|
||||
return g_quark_from_string (uniform_name);
|
||||
}
|
||||
|
||||
GQuark
|
||||
gsk_shader_builder_add_attribute (GskShaderBuilder *builder,
|
||||
const char *attribute_name)
|
||||
{
|
||||
g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), 0);
|
||||
g_return_val_if_fail (attribute_name != NULL, 0);
|
||||
|
||||
g_ptr_array_add (builder->attributes, g_strdup (attribute_name));
|
||||
|
||||
return g_quark_from_string (attribute_name);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
lookup_shader_code (GString *code,
|
||||
const char *base_path,
|
||||
const char *shader_file,
|
||||
GError **error)
|
||||
{
|
||||
GBytes *source;
|
||||
char *path;
|
||||
|
||||
if (base_path != NULL)
|
||||
path = g_build_filename (base_path, shader_file, NULL);
|
||||
else
|
||||
path = g_strdup (shader_file);
|
||||
|
||||
source = g_resources_lookup_data (path, 0, error);
|
||||
g_free (path);
|
||||
|
||||
if (source == NULL)
|
||||
return FALSE;
|
||||
|
||||
g_string_append (code, g_bytes_get_data (source, NULL));
|
||||
|
||||
g_bytes_unref (source);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
gsk_shader_builder_compile_shader (GskShaderBuilder *builder,
|
||||
int shader_type,
|
||||
const char *shader_preamble,
|
||||
const char *shader_source,
|
||||
GError **error)
|
||||
{
|
||||
GString *code;
|
||||
char *source;
|
||||
int shader_id;
|
||||
int status;
|
||||
int i;
|
||||
|
||||
code = g_string_new (NULL);
|
||||
|
||||
if (builder->version > 0)
|
||||
{
|
||||
g_string_append_printf (code, "#version %d\n", builder->version);
|
||||
g_string_append_c (code, '\n');
|
||||
}
|
||||
|
||||
for (i = 0; i < builder->defines->len; i += 2)
|
||||
{
|
||||
const char *name = g_ptr_array_index (builder->defines, i);
|
||||
const char *value = g_ptr_array_index (builder->defines, i + 1);
|
||||
|
||||
g_string_append (code, "#define");
|
||||
g_string_append_c (code, ' ');
|
||||
g_string_append (code, name);
|
||||
g_string_append_c (code, ' ');
|
||||
g_string_append (code, value);
|
||||
g_string_append_c (code, '\n');
|
||||
|
||||
if (i == builder->defines->len - 2)
|
||||
g_string_append_c (code, '\n');
|
||||
}
|
||||
|
||||
if (!lookup_shader_code (code, builder->resource_base_path, shader_preamble, error))
|
||||
{
|
||||
g_string_free (code, TRUE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_string_append_c (code, '\n');
|
||||
|
||||
if (!lookup_shader_code (code, builder->resource_base_path, shader_source, error))
|
||||
{
|
||||
g_string_free (code, TRUE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
source = g_string_free (code, FALSE);
|
||||
|
||||
shader_id = glCreateShader (shader_type);
|
||||
glShaderSource (shader_id, 1, (const GLchar **) &source, NULL);
|
||||
glCompileShader (shader_id);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
if (GSK_DEBUG_CHECK (SHADERS))
|
||||
{
|
||||
g_print ("*** Compiling %s shader from '%s' + '%s' ***\n"
|
||||
"%s\n",
|
||||
shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
|
||||
shader_preamble, shader_source,
|
||||
source);
|
||||
}
|
||||
#endif
|
||||
|
||||
g_free (source);
|
||||
|
||||
glGetShaderiv (shader_id, GL_COMPILE_STATUS, &status);
|
||||
if (status == GL_FALSE)
|
||||
{
|
||||
int log_len;
|
||||
char *buffer;
|
||||
|
||||
glGetShaderiv (shader_id, GL_INFO_LOG_LENGTH, &log_len);
|
||||
|
||||
buffer = g_malloc0 (log_len + 1);
|
||||
glGetShaderInfoLog (shader_id, log_len, NULL, buffer);
|
||||
|
||||
g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_COMPILATION_FAILED,
|
||||
"Compilation failure in %s shader:\n%s",
|
||||
shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
|
||||
buffer);
|
||||
g_free (buffer);
|
||||
|
||||
glDeleteShader (shader_id);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return shader_id;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_shader_builder_cache_uniforms (GskShaderBuilder *builder,
|
||||
ShaderProgram *program)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < builder->uniforms->len; i++)
|
||||
{
|
||||
const char *uniform = g_ptr_array_index (builder->uniforms, i);
|
||||
int loc = glGetUniformLocation (program->program_id, uniform);
|
||||
|
||||
g_hash_table_insert (program->uniform_locations,
|
||||
GINT_TO_POINTER (g_quark_from_string (uniform)),
|
||||
GINT_TO_POINTER (loc));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_shader_builder_cache_attributes (GskShaderBuilder *builder,
|
||||
ShaderProgram *program)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < builder->attributes->len; i++)
|
||||
{
|
||||
const char *attribute = g_ptr_array_index (builder->attributes, i);
|
||||
int loc = glGetAttribLocation (program->program_id, attribute);
|
||||
|
||||
g_hash_table_insert (program->attribute_locations,
|
||||
GINT_TO_POINTER (g_quark_from_string (attribute)),
|
||||
GINT_TO_POINTER (loc));
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
gsk_shader_builder_create_program (GskShaderBuilder *builder,
|
||||
const char *vertex_shader,
|
||||
const char *fragment_shader,
|
||||
GError **error)
|
||||
{
|
||||
ShaderProgram *program;
|
||||
int vertex_id, fragment_id;
|
||||
int program_id;
|
||||
int status;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
|
||||
g_return_val_if_fail (vertex_shader != NULL, -1);
|
||||
g_return_val_if_fail (fragment_shader != NULL, -1);
|
||||
|
||||
vertex_id = gsk_shader_builder_compile_shader (builder, GL_VERTEX_SHADER,
|
||||
builder->vertex_preamble,
|
||||
vertex_shader,
|
||||
error);
|
||||
if (vertex_id < 0)
|
||||
return -1;
|
||||
|
||||
fragment_id = gsk_shader_builder_compile_shader (builder, GL_FRAGMENT_SHADER,
|
||||
builder->fragment_preamble,
|
||||
fragment_shader,
|
||||
error);
|
||||
if (fragment_id < 0)
|
||||
{
|
||||
glDeleteShader (vertex_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
program_id = glCreateProgram ();
|
||||
glAttachShader (program_id, vertex_id);
|
||||
glAttachShader (program_id, fragment_id);
|
||||
glLinkProgram (program_id);
|
||||
|
||||
glGetProgramiv (program_id, GL_LINK_STATUS, &status);
|
||||
if (status == GL_FALSE)
|
||||
{
|
||||
char *buffer = NULL;
|
||||
int log_len = 0;
|
||||
|
||||
glGetProgramiv (program_id, GL_INFO_LOG_LENGTH, &log_len);
|
||||
|
||||
buffer = g_malloc0 (log_len + 1);
|
||||
glGetProgramInfoLog (program_id, log_len, NULL, buffer);
|
||||
|
||||
g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_LINK_FAILED,
|
||||
"Linking failure in shader:\n%s", buffer);
|
||||
g_free (buffer);
|
||||
|
||||
glDeleteProgram (program_id);
|
||||
program_id = -1;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
program = shader_program_new (program_id);
|
||||
gsk_shader_builder_cache_uniforms (builder, program);
|
||||
gsk_shader_builder_cache_attributes (builder, program);
|
||||
|
||||
g_hash_table_insert (builder->programs, GINT_TO_POINTER (program_id), program);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
if (GSK_DEBUG_CHECK (SHADERS))
|
||||
{
|
||||
GHashTableIter iter;
|
||||
gpointer name_p, location_p;
|
||||
|
||||
g_hash_table_iter_init (&iter, program->uniform_locations);
|
||||
while (g_hash_table_iter_next (&iter, &name_p, &location_p))
|
||||
{
|
||||
g_print ("Uniform '%s' - location: %d\n",
|
||||
g_quark_to_string (GPOINTER_TO_INT (name_p)),
|
||||
GPOINTER_TO_INT (location_p));
|
||||
}
|
||||
|
||||
g_hash_table_iter_init (&iter, program->attribute_locations);
|
||||
while (g_hash_table_iter_next (&iter, &name_p, &location_p))
|
||||
{
|
||||
g_print ("Attribute '%s' - location: %d\n",
|
||||
g_quark_to_string (GPOINTER_TO_INT (name_p)),
|
||||
GPOINTER_TO_INT (location_p));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
out:
|
||||
if (vertex_id > 0)
|
||||
{
|
||||
glDetachShader (program_id, vertex_id);
|
||||
glDeleteShader (vertex_id);
|
||||
}
|
||||
|
||||
if (fragment_id > 0)
|
||||
{
|
||||
glDetachShader (program_id, fragment_id);
|
||||
glDeleteShader (fragment_id);
|
||||
}
|
||||
|
||||
return program_id;
|
||||
}
|
||||
|
||||
int
|
||||
gsk_shader_builder_get_uniform_location (GskShaderBuilder *builder,
|
||||
int program_id,
|
||||
GQuark uniform_quark)
|
||||
{
|
||||
ShaderProgram *p = NULL;
|
||||
gpointer loc_p = NULL;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
|
||||
g_return_val_if_fail (program_id >= 0, -1);
|
||||
|
||||
if (builder->uniforms->len == 0)
|
||||
return -1;
|
||||
|
||||
if (!g_hash_table_lookup_extended (builder->programs, GINT_TO_POINTER (program_id), NULL, (gpointer *) &p))
|
||||
return -1;
|
||||
|
||||
if (g_hash_table_lookup_extended (p->uniform_locations, GINT_TO_POINTER (uniform_quark), NULL, &loc_p))
|
||||
return GPOINTER_TO_INT (loc_p);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
gsk_shader_builder_get_attribute_location (GskShaderBuilder *builder,
|
||||
int program_id,
|
||||
GQuark attribute_quark)
|
||||
{
|
||||
ShaderProgram *p = NULL;
|
||||
gpointer loc_p = NULL;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
|
||||
g_return_val_if_fail (program_id >= 0, -1);
|
||||
|
||||
if (builder->attributes->len == 0)
|
||||
return -1;
|
||||
|
||||
if (!g_hash_table_lookup_extended (builder->programs, GINT_TO_POINTER (program_id), NULL, (gpointer *) &p))
|
||||
return -1;
|
||||
|
||||
if (g_hash_table_lookup_extended (p->attribute_locations, GINT_TO_POINTER (attribute_quark), NULL, &loc_p))
|
||||
return GPOINTER_TO_INT (loc_p);
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef __GSK_SHADER_BUILDER_PRIVATE_H__
|
||||
#define __GSK_SHADER_BUILDER_PRIVATE_H__
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <graphene.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_SHADER_BUILDER (gsk_shader_builder_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (GskShaderBuilder, gsk_shader_builder, GSK, SHADER_BUILDER, GObject)
|
||||
|
||||
GskShaderBuilder * gsk_shader_builder_new (void);
|
||||
|
||||
void gsk_shader_builder_set_version (GskShaderBuilder *builder,
|
||||
int version);
|
||||
void gsk_shader_builder_set_resource_base_path (GskShaderBuilder *builder,
|
||||
const char *base_path);
|
||||
void gsk_shader_builder_set_vertex_preamble (GskShaderBuilder *builder,
|
||||
const char *shader_preamble);
|
||||
void gsk_shader_builder_set_fragment_preamble (GskShaderBuilder *builder,
|
||||
const char *shader_preamble);
|
||||
|
||||
GQuark gsk_shader_builder_add_uniform (GskShaderBuilder *builder,
|
||||
const char *uniform_name);
|
||||
GQuark gsk_shader_builder_add_attribute (GskShaderBuilder *builder,
|
||||
const char *attribute_name);
|
||||
void gsk_shader_builder_add_define (GskShaderBuilder *builder,
|
||||
const char *define_name,
|
||||
const char *define_value);
|
||||
|
||||
int gsk_shader_builder_create_program (GskShaderBuilder *builder,
|
||||
const char *vertex_shader,
|
||||
const char *fragment_shader,
|
||||
GError **error);
|
||||
|
||||
int gsk_shader_builder_get_uniform_location (GskShaderBuilder *builder,
|
||||
int program_id,
|
||||
GQuark uniform_quark);
|
||||
int gsk_shader_builder_get_attribute_location (GskShaderBuilder *builder,
|
||||
int program_id,
|
||||
GQuark attribute_quark);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_SHADER_BUILDER_PRIVATE_H__ */
|
||||
@@ -0,0 +1,29 @@
|
||||
/* GSK - The GTK Scene Kit
|
||||
* Copyright 2016 Endless
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __GSK_TYPES_H__
|
||||
#define __GSK_TYPES_H__
|
||||
|
||||
#if !defined (__GSK_H_INSIDE__) && !defined (GSK_COMPILATION)
|
||||
#error "Only <gsk/gsk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <graphene.h>
|
||||
#include <gdk/gdk.h>
|
||||
#include <gsk/gskenums.h>
|
||||
|
||||
#endif /* __GSK_TYPES_H__ */
|
||||
@@ -0,0 +1,62 @@
|
||||
vec3 BlendMultiply(vec3 Cb, vec3 Cs) {
|
||||
return Cb * Cs;
|
||||
}
|
||||
|
||||
vec3 BlendScreen(vec3 Cb, vec3 Cs) {
|
||||
return Cb + Cs - (Cb * Cs);
|
||||
}
|
||||
|
||||
vec3 BlendHardLight(vec3 Cb, vec3 Cs) {
|
||||
vec3 m = BlendMultiply(Cb, 2.0 * Cs);
|
||||
vec3 s = BlendScreen(Cb, 2.0 * Cs - 1.0);
|
||||
vec3 edge = vec3(0.5, 0.5, 0.5);
|
||||
|
||||
/* Use mix() and step() to avoid a branch */
|
||||
return mix(m, s, step(edge, Cs));
|
||||
}
|
||||
|
||||
vec3 BlendOverlay(vec3 Cb, vec3 Cs) {
|
||||
return BlendHardLight(Cs, Cb);
|
||||
}
|
||||
|
||||
vec3 BlendDarken(vec3 Cb, vec3 Cs) {
|
||||
return min(Cb, Cs);
|
||||
}
|
||||
|
||||
vec3 BlendLighten(vec3 Cb, vec3 Cs) {
|
||||
return max(Cb, Cs);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 Cs = Texture(uSource, vUv);
|
||||
vec4 Cb = Texture(uMask, vUv);
|
||||
vec3 res;
|
||||
|
||||
if (uBlendMode == 0) {
|
||||
res = Cs.xyz;
|
||||
}
|
||||
else if (uBlendMode == 1) {
|
||||
res = BlendMultiply(Cb.xyz, Cs.xyz);
|
||||
}
|
||||
else if (uBlendMode == 2) {
|
||||
res = BlendScreen(Cb.xyz, Cs.xyz);
|
||||
}
|
||||
else if (uBlendMode == 3) {
|
||||
res = BlendOverlay(Cb.xyz, Cs.xyz);
|
||||
}
|
||||
else if (uBlendMode == 4) {
|
||||
res = BlendDarken(Cb.xyz, Cs.xyz);
|
||||
}
|
||||
else if (uBlendMode == 5) {
|
||||
res = BlendLighten(Cb.xyz, Cs.xyz);
|
||||
}
|
||||
else if (uBlendMode == 8) {
|
||||
res = BlendHardLight(Cb.xyz, Cs.xyz);
|
||||
}
|
||||
else {
|
||||
// Use red for debugging missing blend modes
|
||||
res = vec3(1.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
setOutputColor(vec4(res, Cs.a * uAlpha));
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
void main() {
|
||||
gl_Position = uMVP * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
// Flip the sampling
|
||||
vUv = vec2(aUv.x, aUv.y);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
void main() {
|
||||
vec4 diffuse = Texture(uSource, vUv);
|
||||
|
||||
setOutputColor(vec4(diffuse.xyz, diffuse.a * uAlpha));
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
void main() {
|
||||
gl_Position = uMVP * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
// Flip the sampling
|
||||
vUv = vec2(aUv.x, aUv.y);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
precision mediump float;
|
||||
|
||||
uniform mat4 uMVP;
|
||||
uniform sampler2D uSource;
|
||||
uniform sampler2D uMask;
|
||||
uniform float uAlpha;
|
||||
uniform int uBlendMode;
|
||||
|
||||
varying vec2 vUv;
|
||||
|
||||
vec4 Texture(sampler2D sampler, vec2 texCoords) {
|
||||
return texture2D(sampler, texCoords);
|
||||
}
|
||||
|
||||
void setOutputColor(vec4 color) {
|
||||
gl_FragColor = color;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
uniform mat4 uMVP;
|
||||
|
||||
attribute vec2 aPosition;
|
||||
attribute vec2 aUv;
|
||||
|
||||
varying vec2 vUv;
|
||||
@@ -0,0 +1,19 @@
|
||||
precision highp float;
|
||||
|
||||
uniform sampler2D uSource;
|
||||
uniform sampler2D uMask;
|
||||
uniform mat4 uMVP;
|
||||
uniform float uAlpha;
|
||||
uniform int uBlendMode;
|
||||
|
||||
in vec2 vUv;
|
||||
|
||||
out vec4 outputColor;
|
||||
|
||||
vec4 Texture(sampler2D sampler, vec2 texCoords) {
|
||||
return texture(sampler, texCoords);
|
||||
}
|
||||
|
||||
void setOutputColor(vec4 color) {
|
||||
outputColor = color;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
uniform mat4 uMVP;
|
||||
|
||||
in vec2 aPosition;
|
||||
in vec2 aUv;
|
||||
|
||||
out vec2 vUv;
|
||||
@@ -0,0 +1,15 @@
|
||||
uniform mat4 uMVP;
|
||||
uniform sampler2D uSource;
|
||||
uniform sampler2D uMask;
|
||||
uniform float uAlpha;
|
||||
uniform int uBlendMode;
|
||||
|
||||
varying vec2 vUv;
|
||||
|
||||
vec4 Texture(sampler2D sampler, vec2 texCoords) {
|
||||
return texture2D(sampler, texCoords);
|
||||
}
|
||||
|
||||
void setOutputColor(vec4 color) {
|
||||
gl_FragColor = color;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
uniform mat4 uMVP;
|
||||
|
||||
attribute vec2 aPosition;
|
||||
attribute vec2 aUv;
|
||||
|
||||
varying vec2 vUv;
|
||||
+11
-2
@@ -27,6 +27,8 @@ AM_CPPFLAGS = \
|
||||
-I$(top_builddir)/gtk \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/gdk \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/gsk \
|
||||
$(GMODULE_CFLAGS) \
|
||||
$(GTK_DEBUG_FLAGS) \
|
||||
$(GTK_WARN_CFLAGS) \
|
||||
@@ -81,10 +83,12 @@ endif
|
||||
|
||||
libadd = \
|
||||
$(top_builddir)/gdk/libgdk-4.la \
|
||||
$(top_builddir)/gsk/libgsk-4.la \
|
||||
$(GMODULE_LIBS) \
|
||||
$(GTK_DEP_LIBS)
|
||||
deps = \
|
||||
$(top_builddir)/gdk/libgdk-4.la
|
||||
$(top_builddir)/gdk/libgdk-4.la \
|
||||
$(top_builddir)/gsk/libgsk-4.la
|
||||
|
||||
# libtool stuff: set version and export symbols for resolving
|
||||
# since automake doesn't support conditionalized libsomething_la_LDFLAGS
|
||||
@@ -1531,7 +1535,7 @@ Gtk_4_0_gir_CFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
-DGTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
|
||||
Gtk_4_0_gir_FILES = $(introspection_files)
|
||||
Gtk_4_0_gir_LIBS = libgtk-4.la $(top_builddir)/gdk/libgdk-4.la
|
||||
Gtk_4_0_gir_LIBS = libgtk-4.la $(top_builddir)/gsk/libgsk-4.la $(top_builddir)/gdk/libgdk-4.la
|
||||
Gtk_4_0_gir_EXPORT_PACKAGES = gtk+-4.0
|
||||
INTROSPECTION_GIRS = Gtk-4.0.gir
|
||||
|
||||
@@ -1559,6 +1563,7 @@ gtk_query_immodules_4_0_SOURCES = queryimmodules.c gtkutils.c
|
||||
gtk_query_immodules_4_0_LDADD = \
|
||||
libgtk-4.la \
|
||||
$(top_builddir)/gdk/libgdk-4.la \
|
||||
$(top_builddir)/gsk/libgsk-4.la \
|
||||
$(GMODULE_LIBS) \
|
||||
$(GTK_DEP_LIBS)
|
||||
|
||||
@@ -1569,24 +1574,28 @@ gtk_encode_symbolic_svg_SOURCES = encodesymbolic.c
|
||||
gtk_encode_symbolic_svg_LDADD = \
|
||||
$(GDK_PIXBUF_LIBS) \
|
||||
$(top_builddir)/gdk/libgdk-4.la \
|
||||
$(top_builddir)/gsk/libgsk-4.la \
|
||||
$(GTK_DEP_LIBS)
|
||||
|
||||
gtk_builder_tool_SOURCES = gtk-builder-tool.c
|
||||
gtk_builder_tool_LDADD = \
|
||||
libgtk-4.la \
|
||||
$(top_builddir)/gdk/libgdk-4.la \
|
||||
$(top_builddir)/gsk/libgsk-4.la \
|
||||
$(GTK_DEP_LIBS)
|
||||
|
||||
gtk_query_settings_SOURCES = gtk-query-settings.c
|
||||
gtk_query_settings_LDADD= \
|
||||
libgtk-4.la \
|
||||
$(top_builddir)/gdk/libgdk-4.la \
|
||||
$(top_builddir)/gsk/libgsk-4.la \
|
||||
$(GTK_DEP_LIBS)
|
||||
|
||||
gtk_launch_SOURCES = gtk-launch.c
|
||||
gtk_launch_LDADD = \
|
||||
libgtk-4.la \
|
||||
$(top_builddir)/gdk/libgdk-4.la \
|
||||
$(top_builddir)/gsk/libgsk-4.la \
|
||||
$(GTK_DEP_LIBS)
|
||||
|
||||
if OS_WIN32
|
||||
|
||||
+25
-8
@@ -139,8 +139,8 @@ static void gtk_accel_label_get_property (GObject *object,
|
||||
GParamSpec *pspec);
|
||||
static void gtk_accel_label_destroy (GtkWidget *widget);
|
||||
static void gtk_accel_label_finalize (GObject *object);
|
||||
static gboolean gtk_accel_label_draw (GtkWidget *widget,
|
||||
cairo_t *cr);
|
||||
static GskRenderNode *gtk_accel_label_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer);
|
||||
static const gchar *gtk_accel_label_get_string (GtkAccelLabel *accel_label);
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ gtk_accel_label_class_init (GtkAccelLabelClass *class)
|
||||
gobject_class->set_property = gtk_accel_label_set_property;
|
||||
gobject_class->get_property = gtk_accel_label_get_property;
|
||||
|
||||
widget_class->draw = gtk_accel_label_draw;
|
||||
widget_class->get_render_node = gtk_accel_label_get_render_node;
|
||||
widget_class->get_preferred_width = gtk_accel_label_get_preferred_width;
|
||||
widget_class->destroy = gtk_accel_label_destroy;
|
||||
|
||||
@@ -443,16 +443,17 @@ get_first_baseline (PangoLayout *layout)
|
||||
return PANGO_PIXELS (result);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_accel_label_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
static GskRenderNode *
|
||||
gtk_accel_label_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer)
|
||||
{
|
||||
GtkAccelLabel *accel_label = GTK_ACCEL_LABEL (widget);
|
||||
guint ac_width;
|
||||
GtkAllocation allocation;
|
||||
GtkRequisition requisition;
|
||||
GskRenderNode *res;
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_accel_label_parent_class)->draw (widget, cr);
|
||||
res = GTK_WIDGET_CLASS (gtk_accel_label_parent_class)->get_render_node (widget, renderer);
|
||||
|
||||
ac_width = gtk_accel_label_get_accel_width (accel_label);
|
||||
gtk_widget_get_allocation (widget, &allocation);
|
||||
@@ -465,6 +466,17 @@ gtk_accel_label_draw (GtkWidget *widget,
|
||||
PangoLayout *accel_layout;
|
||||
gint x;
|
||||
gint y;
|
||||
GtkAllocation alloc, clip;
|
||||
GskRenderNode *node;
|
||||
cairo_t *cr;
|
||||
|
||||
node = gtk_widget_create_render_node (widget, renderer, "AccelLabel Content");
|
||||
|
||||
gtk_widget_get_clip (widget, &clip);
|
||||
_gtk_widget_get_allocation (widget, &alloc);
|
||||
|
||||
cr = gsk_render_node_get_draw_context (node);
|
||||
cairo_translate (cr, alloc.x - clip.x, alloc.y - clip.y);
|
||||
|
||||
context = gtk_widget_get_style_context (widget);
|
||||
|
||||
@@ -485,9 +497,14 @@ gtk_accel_label_draw (GtkWidget *widget,
|
||||
gtk_style_context_restore (context);
|
||||
|
||||
g_object_unref (accel_layout);
|
||||
|
||||
cairo_destroy (cr);
|
||||
|
||||
gsk_render_node_append_child (res, node);
|
||||
gsk_render_node_unref (node);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
+11
-21
@@ -199,29 +199,19 @@ gtk_action_bar_set_child_property (GtkContainer *container,
|
||||
value);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_action_bar_render (GtkCssGadget *gadget,
|
||||
cairo_t *cr,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data)
|
||||
{
|
||||
GTK_WIDGET_CLASS (gtk_action_bar_parent_class)->draw (gtk_css_gadget_get_owner (gadget), cr);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_action_bar_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
static GskRenderNode *
|
||||
gtk_action_bar_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer)
|
||||
{
|
||||
GtkActionBarPrivate *priv = gtk_action_bar_get_instance_private (GTK_ACTION_BAR (widget));
|
||||
GskRenderNode *node = gtk_css_gadget_get_render_node (priv->gadget, renderer, FALSE);
|
||||
|
||||
gtk_css_gadget_draw (priv->gadget, cr);
|
||||
if (node == NULL)
|
||||
return NULL;
|
||||
|
||||
return FALSE;
|
||||
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, node);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -320,7 +310,7 @@ gtk_action_bar_class_init (GtkActionBarClass *klass)
|
||||
widget_class->show = gtk_action_bar_show;
|
||||
widget_class->hide = gtk_action_bar_hide;
|
||||
widget_class->destroy = gtk_action_bar_destroy;
|
||||
widget_class->draw = gtk_action_bar_draw;
|
||||
widget_class->get_render_node = gtk_action_bar_get_render_node;
|
||||
widget_class->size_allocate = gtk_action_bar_size_allocate;
|
||||
widget_class->get_preferred_width_for_height = gtk_action_bar_get_preferred_width_for_height;
|
||||
widget_class->get_preferred_height_and_baseline_for_width = gtk_action_bar_get_preferred_height_and_baseline_for_width;
|
||||
@@ -373,7 +363,7 @@ gtk_action_bar_init (GtkActionBar *action_bar)
|
||||
GTK_WIDGET (action_bar),
|
||||
gtk_action_bar_measure,
|
||||
gtk_action_bar_allocate,
|
||||
gtk_action_bar_render,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
+17
-48
@@ -92,8 +92,9 @@ static void gtk_button_box_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static gboolean gtk_button_box_draw (GtkWidget *widget,
|
||||
cairo_t *cr);
|
||||
static GskRenderNode *gtk_button_box_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer);
|
||||
|
||||
static void gtk_button_box_get_preferred_width (GtkWidget *widget,
|
||||
gint *minimum,
|
||||
gint *natural);
|
||||
@@ -143,13 +144,6 @@ static void gtk_button_box_allocate (GtkCssGadget *gadget,
|
||||
int baseline,
|
||||
GtkAllocation *out_clip,
|
||||
gpointer unused);
|
||||
static gboolean gtk_button_box_render (GtkCssGadget *gadget,
|
||||
cairo_t *cr,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data);
|
||||
|
||||
#define DEFAULT_CHILD_MIN_WIDTH 85
|
||||
#define DEFAULT_CHILD_MIN_HEIGHT 27
|
||||
@@ -197,7 +191,7 @@ gtk_button_box_class_init (GtkButtonBoxClass *class)
|
||||
widget_class->get_preferred_height_for_width = gtk_button_box_get_preferred_height_for_width;
|
||||
widget_class->get_preferred_height_and_baseline_for_width = gtk_button_box_get_preferred_height_and_baseline_for_width;
|
||||
widget_class->size_allocate = gtk_button_box_size_allocate;
|
||||
widget_class->draw = gtk_button_box_draw;
|
||||
widget_class->get_render_node = gtk_button_box_get_render_node;
|
||||
|
||||
container_class->remove = gtk_button_box_remove;
|
||||
container_class->add = gtk_button_box_add;
|
||||
@@ -296,49 +290,24 @@ gtk_button_box_class_init (GtkButtonBoxClass *class)
|
||||
gtk_widget_class_set_css_name (widget_class, "buttonbox");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_button_box_render (GtkCssGadget *gadget,
|
||||
cairo_t *cr,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
gpointer unused)
|
||||
{
|
||||
GtkWidget *widget;
|
||||
GList *children, *l;
|
||||
|
||||
widget = gtk_css_gadget_get_owner (gadget);
|
||||
children = gtk_container_get_children (GTK_CONTAINER (widget));
|
||||
|
||||
for (l = children; l; l = l->next)
|
||||
{
|
||||
GtkWidget *child = l->data;
|
||||
|
||||
gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
|
||||
}
|
||||
|
||||
g_list_free (children);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
gtk_button_box_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
static GskRenderNode *
|
||||
gtk_button_box_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer)
|
||||
{
|
||||
GtkButtonBoxPrivate *priv = GTK_BUTTON_BOX (widget)->priv;
|
||||
GtkCssGadget *gadget;
|
||||
GskRenderNode *res;
|
||||
|
||||
if (priv->layout_style == GTK_BUTTONBOX_EXPAND)
|
||||
gadget = gtk_box_get_gadget (GTK_BOX (widget));
|
||||
else
|
||||
gadget = priv->gadget;
|
||||
return GTK_WIDGET_CLASS (gtk_button_box_parent_class)->get_render_node (widget, renderer);
|
||||
|
||||
gtk_css_gadget_draw (gadget, cr);
|
||||
res = gtk_css_gadget_get_render_node (priv->gadget, renderer, FALSE);
|
||||
|
||||
return FALSE;
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -353,7 +322,7 @@ gtk_button_box_init (GtkButtonBox *button_box)
|
||||
GTK_WIDGET (button_box),
|
||||
gtk_button_box_measure,
|
||||
gtk_button_box_allocate,
|
||||
gtk_button_box_render,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
+17
-24
@@ -161,8 +161,6 @@ struct _GtkBoxChild
|
||||
|
||||
static void gtk_box_size_allocate (GtkWidget *widget,
|
||||
GtkAllocation *allocation);
|
||||
static gboolean gtk_box_draw (GtkWidget *widget,
|
||||
cairo_t *cr);
|
||||
|
||||
static void gtk_box_direction_changed (GtkWidget *widget,
|
||||
GtkTextDirection previous_direction);
|
||||
@@ -220,6 +218,9 @@ static void gtk_box_get_preferred_height_and_baseline_for_width (GtkWidget
|
||||
gint *minimum_baseline,
|
||||
gint *natural_baseline);
|
||||
|
||||
static GskRenderNode * gtk_box_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer);
|
||||
|
||||
static void gtk_box_buildable_init (GtkBuildableIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkBox, gtk_box, GTK_TYPE_CONTAINER,
|
||||
@@ -249,7 +250,7 @@ gtk_box_class_init (GtkBoxClass *class)
|
||||
object_class->get_property = gtk_box_get_property;
|
||||
object_class->dispose = gtk_box_dispose;
|
||||
|
||||
widget_class->draw = gtk_box_draw;
|
||||
widget_class->get_render_node = gtk_box_get_render_node;
|
||||
widget_class->size_allocate = gtk_box_size_allocate;
|
||||
widget_class->get_preferred_width = gtk_box_get_preferred_width;
|
||||
widget_class->get_preferred_height = gtk_box_get_preferred_height;
|
||||
@@ -417,30 +418,22 @@ gtk_box_get_property (GObject *object,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_box_draw_contents (GtkCssGadget *gadget,
|
||||
cairo_t *cr,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
gpointer unused)
|
||||
static GskRenderNode *
|
||||
gtk_box_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer)
|
||||
{
|
||||
GTK_WIDGET_CLASS (gtk_box_parent_class)->draw (gtk_css_gadget_get_owner (gadget), cr);
|
||||
GskRenderNode *res = gtk_css_gadget_get_render_node (GTK_BOX (widget)->priv->gadget,
|
||||
renderer,
|
||||
FALSE);
|
||||
|
||||
return FALSE;
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_box_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
{
|
||||
gtk_css_gadget_draw (GTK_BOX (widget)->priv->gadget, cr);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
count_expand_children (GtkBox *box,
|
||||
gint *visible_children,
|
||||
@@ -2061,7 +2054,7 @@ gtk_box_init (GtkBox *box)
|
||||
GTK_WIDGET (box),
|
||||
gtk_box_get_content_size,
|
||||
gtk_box_allocate_contents,
|
||||
gtk_box_draw_contents,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
|
||||
@@ -518,6 +518,12 @@ gtk_box_gadget_draw (GtkCssGadget *gadget,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_box_gadget_has_content (GtkCssGadget *gadget)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_box_gadget_finalize (GObject *object)
|
||||
{
|
||||
@@ -539,6 +545,7 @@ gtk_box_gadget_class_init (GtkBoxGadgetClass *klass)
|
||||
gadget_class->get_preferred_size = gtk_box_gadget_get_preferred_size;
|
||||
gadget_class->allocate = gtk_box_gadget_allocate;
|
||||
gadget_class->draw = gtk_box_gadget_draw;
|
||||
gadget_class->has_content = gtk_box_gadget_has_content;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
+14
-31
@@ -126,7 +126,8 @@ static void gtk_button_map (GtkWidget * widget);
|
||||
static void gtk_button_unmap (GtkWidget * widget);
|
||||
static void gtk_button_size_allocate (GtkWidget * widget,
|
||||
GtkAllocation * allocation);
|
||||
static gint gtk_button_draw (GtkWidget * widget, cairo_t *cr);
|
||||
static GskRenderNode *gtk_button_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer);
|
||||
static gint gtk_button_grab_broken (GtkWidget * widget,
|
||||
GdkEventGrabBroken * event);
|
||||
static gint gtk_button_key_release (GtkWidget * widget, GdkEventKey * event);
|
||||
@@ -195,13 +196,6 @@ static void gtk_button_allocate (GtkCssGadget *gadget,
|
||||
int baseline,
|
||||
GtkAllocation *out_clip,
|
||||
gpointer data);
|
||||
static gboolean gtk_button_render (GtkCssGadget *gadget,
|
||||
cairo_t *cr,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data);
|
||||
|
||||
static GParamSpec *props[LAST_PROP] = { NULL, };
|
||||
static guint button_signals[LAST_SIGNAL] = { 0 };
|
||||
@@ -240,7 +234,7 @@ gtk_button_class_init (GtkButtonClass *klass)
|
||||
widget_class->map = gtk_button_map;
|
||||
widget_class->unmap = gtk_button_unmap;
|
||||
widget_class->size_allocate = gtk_button_size_allocate;
|
||||
widget_class->draw = gtk_button_draw;
|
||||
widget_class->get_render_node = gtk_button_get_render_node;
|
||||
widget_class->grab_broken_event = gtk_button_grab_broken;
|
||||
widget_class->key_release_event = gtk_button_key_release;
|
||||
widget_class->enter_notify_event = gtk_button_enter_notify;
|
||||
@@ -519,7 +513,7 @@ gtk_button_init (GtkButton *button)
|
||||
GTK_WIDGET (button),
|
||||
gtk_button_measure,
|
||||
gtk_button_allocate,
|
||||
gtk_button_render,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
@@ -1305,31 +1299,20 @@ gtk_button_allocate (GtkCssGadget *gadget,
|
||||
gtk_container_get_children_clip (GTK_CONTAINER (widget), out_clip);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_button_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
static GskRenderNode *
|
||||
gtk_button_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer)
|
||||
{
|
||||
gtk_css_gadget_draw (GTK_BUTTON (widget)->priv->gadget, cr);
|
||||
GskRenderNode *res = gtk_css_gadget_get_render_node (GTK_BUTTON (widget)->priv->gadget,
|
||||
renderer,
|
||||
gtk_widget_has_visible_focus (widget));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
static gboolean
|
||||
gtk_button_render (GtkCssGadget *gadget,
|
||||
cairo_t *cr,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *widget;
|
||||
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
|
||||
|
||||
widget = gtk_css_gadget_get_owner (gadget);
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_button_parent_class)->draw (widget, cr);
|
||||
|
||||
return gtk_widget_has_visible_focus (widget);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
+26
-13
@@ -104,8 +104,9 @@ static void gtk_check_button_get_preferred_height_and_baseline_for_width (GtkWid
|
||||
gint *natural_baseline);
|
||||
static void gtk_check_button_size_allocate (GtkWidget *widget,
|
||||
GtkAllocation *allocation);
|
||||
static gboolean gtk_check_button_draw (GtkWidget *widget,
|
||||
cairo_t *cr);
|
||||
static GskRenderNode *gtk_check_button_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer);
|
||||
|
||||
|
||||
typedef struct {
|
||||
GtkCssGadget *gadget;
|
||||
@@ -213,7 +214,7 @@ gtk_check_button_class_init (GtkCheckButtonClass *class)
|
||||
widget_class->get_preferred_height_for_width = gtk_check_button_get_preferred_height_for_width;
|
||||
widget_class->get_preferred_height_and_baseline_for_width = gtk_check_button_get_preferred_height_and_baseline_for_width;
|
||||
widget_class->size_allocate = gtk_check_button_size_allocate;
|
||||
widget_class->draw = gtk_check_button_draw;
|
||||
widget_class->get_render_node = gtk_check_button_get_render_node;
|
||||
widget_class->state_flags_changed = gtk_check_button_state_flags_changed;
|
||||
widget_class->direction_changed = gtk_check_button_direction_changed;
|
||||
|
||||
@@ -490,21 +491,33 @@ gtk_check_button_size_allocate (GtkWidget *widget,
|
||||
}
|
||||
}
|
||||
|
||||
static gint
|
||||
gtk_check_button_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
static GskRenderNode *
|
||||
gtk_check_button_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer)
|
||||
{
|
||||
GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (GTK_CHECK_BUTTON (widget));
|
||||
GtkCssGadget *gadget;
|
||||
GskRenderNode *res;
|
||||
GskRenderNode *node;
|
||||
|
||||
if (gtk_toggle_button_get_mode (GTK_TOGGLE_BUTTON (widget)))
|
||||
gadget = priv->gadget;
|
||||
else
|
||||
gadget = GTK_BUTTON (widget)->priv->gadget;
|
||||
if (!gtk_toggle_button_get_mode (GTK_TOGGLE_BUTTON (widget)))
|
||||
return GTK_WIDGET_CLASS (gtk_check_button_parent_class)->get_render_node (widget, renderer);
|
||||
|
||||
gtk_css_gadget_draw (gadget, cr);
|
||||
res = gtk_css_gadget_get_render_node (priv->gadget,
|
||||
renderer,
|
||||
gtk_widget_has_visible_focus (widget));
|
||||
|
||||
return FALSE;
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
node = gtk_css_gadget_get_render_node (priv->indicator_gadget,
|
||||
renderer,
|
||||
FALSE);
|
||||
gsk_render_node_append_child (res, node);
|
||||
gsk_render_node_unref (node);
|
||||
|
||||
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
GtkCssNode *
|
||||
|
||||
+20
-28
@@ -31,6 +31,7 @@
|
||||
#include "gtkframe.h"
|
||||
#include "gtkiconprivate.h"
|
||||
#include "gtkbox.h"
|
||||
#include "gtkcontainerprivate.h"
|
||||
#include "gtkliststore.h"
|
||||
#include "gtkmain.h"
|
||||
#include "gtkmenuprivate.h"
|
||||
@@ -523,25 +524,6 @@ gtk_combo_box_allocate (GtkCssGadget *gadget,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_combo_box_render (GtkCssGadget *gadget,
|
||||
cairo_t *cr,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
|
||||
GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
|
||||
GtkComboBoxPrivate *priv = combo_box->priv;
|
||||
|
||||
gtk_container_propagate_draw (GTK_CONTAINER (widget),
|
||||
priv->box, cr);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_combo_box_get_preferred_width (GtkWidget *widget,
|
||||
gint *minimum_size,
|
||||
@@ -568,7 +550,8 @@ gtk_combo_box_get_preferred_height (GtkWidget *widget,
|
||||
gint min_width;
|
||||
|
||||
/* Combo box is height-for-width only
|
||||
* (so we always just reserve enough height for the minimum width) */
|
||||
* (so we always just reserve enough height for the minimum width)
|
||||
*/
|
||||
gtk_css_gadget_get_preferred_size (GTK_COMBO_BOX (widget)->priv->gadget,
|
||||
GTK_ORIENTATION_HORIZONTAL,
|
||||
-1,
|
||||
@@ -588,7 +571,8 @@ gtk_combo_box_get_preferred_width_for_height (GtkWidget *widget,
|
||||
gint *natural_size)
|
||||
{
|
||||
/* Combo box is height-for-width only
|
||||
* (so we assume we always reserved enough height for the minimum width) */
|
||||
* (so we assume we always reserved enough height for the minimum width)
|
||||
*/
|
||||
gtk_css_gadget_get_preferred_size (GTK_COMBO_BOX (widget)->priv->gadget,
|
||||
GTK_ORIENTATION_HORIZONTAL,
|
||||
avail_size,
|
||||
@@ -625,12 +609,20 @@ gtk_combo_box_size_allocate (GtkWidget *widget,
|
||||
gtk_widget_set_clip (widget, &clip);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_combo_box_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
static GskRenderNode *
|
||||
gtk_combo_box_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer)
|
||||
{
|
||||
gtk_css_gadget_draw (GTK_COMBO_BOX (widget)->priv->gadget, cr);
|
||||
return FALSE;
|
||||
GskRenderNode *res = gtk_css_gadget_get_render_node (GTK_COMBO_BOX (widget)->priv->gadget,
|
||||
renderer,
|
||||
FALSE);
|
||||
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -670,7 +662,7 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass)
|
||||
|
||||
widget_class = (GtkWidgetClass *)klass;
|
||||
widget_class->size_allocate = gtk_combo_box_size_allocate;
|
||||
widget_class->draw = gtk_combo_box_draw;
|
||||
widget_class->get_render_node = gtk_combo_box_get_render_node;
|
||||
widget_class->scroll_event = gtk_combo_box_scroll_event;
|
||||
widget_class->mnemonic_activate = gtk_combo_box_mnemonic_activate;
|
||||
widget_class->grab_focus = gtk_combo_box_grab_focus;
|
||||
@@ -1223,7 +1215,7 @@ gtk_combo_box_init (GtkComboBox *combo_box)
|
||||
GTK_WIDGET (combo_box),
|
||||
gtk_combo_box_measure,
|
||||
gtk_combo_box_allocate,
|
||||
gtk_combo_box_render,
|
||||
NULL,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
+133
-1
@@ -24,7 +24,6 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkcontainer.h"
|
||||
#include "gtkcontainerprivate.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
@@ -54,6 +53,7 @@
|
||||
#include "gtkpopovermenu.h"
|
||||
#include "gtkshortcutswindow.h"
|
||||
|
||||
|
||||
/* A handful of containers inside GTK+ are cheating and widgets
|
||||
* inside internal structure as direct children for the purpose
|
||||
* of forall().
|
||||
@@ -3397,3 +3397,135 @@ gtk_container_get_path_for_child (GtkContainer *container,
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
GtkContainer *container;
|
||||
GskRenderer *renderer;
|
||||
GskRenderNode *parent;
|
||||
GArray *child_infos;
|
||||
} RenderData;
|
||||
|
||||
static gboolean
|
||||
should_propagate_node (GtkWidget *child,
|
||||
RenderData *data)
|
||||
{
|
||||
if (!_gtk_widget_is_drawable (child))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
propagate_render_node (GtkWidget *child,
|
||||
gpointer data_)
|
||||
{
|
||||
RenderData *data = data_;
|
||||
GskRenderNode *node;
|
||||
GdkWindow *window, *w;
|
||||
GtkAllocation allocation;
|
||||
int x, y;
|
||||
graphene_matrix_t m;
|
||||
graphene_point3d_t tmp;
|
||||
|
||||
node = gtk_widget_get_render_node (child, data->renderer);
|
||||
if (node == NULL)
|
||||
return;
|
||||
|
||||
/* translate coordinates. Ugly business, that. */
|
||||
if (!_gtk_widget_get_has_window (GTK_WIDGET (data->container)))
|
||||
{
|
||||
gtk_widget_get_clip (GTK_WIDGET (data->container), &allocation);
|
||||
x = -allocation.x;
|
||||
y = -allocation.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
window = _gtk_widget_get_window (GTK_WIDGET (data->container));
|
||||
|
||||
for (w = _gtk_widget_get_window (child); w && w != window; w = gdk_window_get_parent (w))
|
||||
{
|
||||
int wx, wy;
|
||||
gdk_window_get_position (w, &wx, &wy);
|
||||
x += wx;
|
||||
y += wy;
|
||||
}
|
||||
|
||||
if (w == NULL)
|
||||
{
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
if (!_gtk_widget_get_has_window (child))
|
||||
{
|
||||
gtk_widget_get_clip (child, &allocation);
|
||||
x += allocation.x;
|
||||
y += allocation.y;
|
||||
}
|
||||
|
||||
graphene_matrix_init_translate (&m, graphene_point3d_init (&tmp, x, y, 0));
|
||||
gsk_render_node_set_transform (node, &m);
|
||||
|
||||
gsk_render_node_append_child (data->parent, node);
|
||||
gsk_render_node_unref (node);
|
||||
}
|
||||
|
||||
static void
|
||||
collect_child_infos (GtkWidget *widget,
|
||||
gpointer data_)
|
||||
{
|
||||
RenderData *data = data_;
|
||||
ChildOrderInfo info;
|
||||
GList *siblings;
|
||||
GdkWindow *window;
|
||||
|
||||
if (!should_propagate_node (widget, data))
|
||||
return;
|
||||
|
||||
info.child = widget;
|
||||
info.window_depth = G_MAXINT;
|
||||
|
||||
window = _gtk_widget_get_window (widget);
|
||||
if (window == NULL)
|
||||
return;
|
||||
|
||||
if (window != gtk_widget_get_window (GTK_WIDGET (data->container)))
|
||||
{
|
||||
siblings = gdk_window_peek_children (gdk_window_get_parent (window));
|
||||
info.window_depth = g_list_index (siblings, window);
|
||||
}
|
||||
|
||||
g_array_append_val (data->child_infos, info);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_container_propagate_render_node (GtkContainer *container,
|
||||
GskRenderer *renderer,
|
||||
GskRenderNode *parent_node)
|
||||
{
|
||||
RenderData data;
|
||||
int i;
|
||||
|
||||
data.container = container;
|
||||
data.renderer = renderer;
|
||||
data.parent = parent_node;
|
||||
|
||||
data.child_infos = g_array_new (FALSE, TRUE, sizeof (ChildOrderInfo));
|
||||
|
||||
gtk_container_forall (container, collect_child_infos, &data);
|
||||
|
||||
g_array_sort (data.child_infos, compare_children_for_draw);
|
||||
|
||||
for (i = 0; i < data.child_infos->len; i++)
|
||||
{
|
||||
ChildOrderInfo *info = &g_array_index (data.child_infos, ChildOrderInfo, i);
|
||||
|
||||
propagate_render_node (info->child, &data);
|
||||
}
|
||||
|
||||
g_array_free (data.child_infos, TRUE);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#define __GTK_CONTAINER_PRIVATE_H__
|
||||
|
||||
#include "gtkcontainer.h"
|
||||
#include <gsk/gsk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@@ -42,6 +43,10 @@ void _gtk_container_maybe_start_idle_sizer (GtkContainer *container);
|
||||
void gtk_container_get_children_clip (GtkContainer *container,
|
||||
GtkAllocation *out_clip);
|
||||
|
||||
void gtk_container_propagate_render_node (GtkContainer *container,
|
||||
GskRenderer *renderer,
|
||||
GskRenderNode *parent_node);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_CONTAINER_PRIVATE_H__ */
|
||||
|
||||
@@ -161,6 +161,14 @@ gtk_css_custom_gadget_draw (GtkCssGadget *gadget,
|
||||
return GTK_CSS_GADGET_CLASS (gtk_css_custom_gadget_parent_class)->draw (gadget, cr, x, y, width, height);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_css_custom_gadget_has_content (GtkCssGadget *gadget)
|
||||
{
|
||||
GtkCssCustomGadgetPrivate *priv = gtk_css_custom_gadget_get_instance_private (GTK_CSS_CUSTOM_GADGET (gadget));
|
||||
|
||||
return priv->draw_func != NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_custom_gadget_finalize (GObject *object)
|
||||
{
|
||||
@@ -183,6 +191,7 @@ gtk_css_custom_gadget_class_init (GtkCssCustomGadgetClass *klass)
|
||||
gadget_class->get_preferred_size = gtk_css_custom_gadget_get_preferred_size;
|
||||
gadget_class->allocate = gtk_css_custom_gadget_allocate;
|
||||
gadget_class->draw = gtk_css_custom_gadget_draw;
|
||||
gadget_class->has_content = gtk_css_custom_gadget_has_content;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
+166
-1
@@ -67,6 +67,7 @@ struct _GtkCssGadgetPrivate {
|
||||
GtkWidget *owner;
|
||||
GtkAllocation allocated_size;
|
||||
gint allocated_baseline;
|
||||
GtkAllocation clip;
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -242,7 +243,6 @@ gtk_css_gadget_set_property (GObject *object,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gtk_css_gadget_finalize (GObject *object)
|
||||
{
|
||||
@@ -253,6 +253,14 @@ gtk_css_gadget_finalize (GObject *object)
|
||||
G_OBJECT_CLASS (gtk_css_gadget_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_css_gadget_has_content (GtkCssGadget *gadget)
|
||||
{
|
||||
GtkCssGadgetClass *gadget_class = GTK_CSS_GADGET_GET_CLASS (gadget);
|
||||
|
||||
return gadget_class->draw != gtk_css_gadget_real_draw;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_gadget_class_init (GtkCssGadgetClass *klass)
|
||||
{
|
||||
@@ -266,6 +274,7 @@ gtk_css_gadget_class_init (GtkCssGadgetClass *klass)
|
||||
klass->allocate = gtk_css_gadget_real_allocate;
|
||||
klass->draw = gtk_css_gadget_real_draw;
|
||||
klass->style_changed = gtk_css_gadget_real_style_changed;
|
||||
klass->has_content = gtk_css_gadget_has_content;
|
||||
|
||||
properties[PROP_NODE] = g_param_spec_object ("node", "Node",
|
||||
"CSS node",
|
||||
@@ -734,6 +743,7 @@ gtk_css_gadget_allocate (GtkCssGadget *gadget,
|
||||
out_clip->y = 0;
|
||||
out_clip->width = 0;
|
||||
out_clip->height = 0;
|
||||
priv->clip = *out_clip;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -798,6 +808,161 @@ gtk_css_gadget_allocate (GtkCssGadget *gadget,
|
||||
allocation->height - margin.top - margin.bottom,
|
||||
&tmp_clip))
|
||||
gdk_rectangle_union (&tmp_clip, out_clip, out_clip);
|
||||
|
||||
priv->clip = *out_clip;
|
||||
}
|
||||
|
||||
GskRenderNode *
|
||||
gtk_css_gadget_get_render_node (GtkCssGadget *gadget,
|
||||
GskRenderer *renderer,
|
||||
gboolean draw_focus)
|
||||
{
|
||||
GtkCssGadgetPrivate *priv = gtk_css_gadget_get_instance_private (gadget);
|
||||
GtkBorder clip, margin, border, padding;
|
||||
GtkCssStyle *style;
|
||||
cairo_t *cr;
|
||||
GskRenderNode *box_node, *border_node;
|
||||
graphene_rect_t bounds;
|
||||
int width, height;
|
||||
int contents_x, contents_y, contents_width, contents_height;
|
||||
GtkAllocation margin_box;
|
||||
GtkAllocation clip_box;
|
||||
char *str;
|
||||
|
||||
if (!gtk_css_gadget_get_visible (gadget))
|
||||
return NULL;
|
||||
|
||||
margin_box = priv->allocated_size;
|
||||
clip_box = priv->clip;
|
||||
|
||||
width = clip_box.width;
|
||||
height = clip_box.height;
|
||||
|
||||
clip.left = margin_box.x - clip_box.x;
|
||||
clip.top = margin_box.y - clip_box.y;
|
||||
clip.right = clip_box.width - margin_box.width - clip.left;
|
||||
clip.bottom = clip_box.height - margin_box.height - clip.top;
|
||||
|
||||
if (width < 0 || height < 0)
|
||||
{
|
||||
g_warning ("Drawing a gadget with negative dimensions. "
|
||||
"Did you forget to allocate a size? (node %s owner %s)",
|
||||
gtk_css_node_get_name (gtk_css_gadget_get_node (gadget)),
|
||||
G_OBJECT_TYPE_NAME (gtk_css_gadget_get_owner (gadget)));
|
||||
width = gtk_widget_get_allocated_width (priv->owner);
|
||||
height = gtk_widget_get_allocated_height (priv->owner);
|
||||
}
|
||||
|
||||
graphene_rect_init (&bounds, 0, 0, width, height);
|
||||
|
||||
str = g_strconcat ("Box<", G_OBJECT_TYPE_NAME (gtk_css_gadget_get_owner (gadget)), ">", NULL);
|
||||
box_node = gsk_renderer_create_render_node (renderer);
|
||||
gsk_render_node_set_name (box_node, str);
|
||||
gsk_render_node_set_bounds (box_node, &bounds);
|
||||
g_free (str);
|
||||
|
||||
style = gtk_css_gadget_get_style (gadget);
|
||||
get_box_margin (style, &margin);
|
||||
get_box_border (style, &border);
|
||||
get_box_padding (style, &padding);
|
||||
|
||||
gtk_css_style_add_background_render_nodes (style,
|
||||
renderer,
|
||||
box_node,
|
||||
&bounds,
|
||||
G_OBJECT_TYPE_NAME (gtk_css_gadget_get_owner (gadget)),
|
||||
clip.left + margin.left,
|
||||
clip.top + margin.top,
|
||||
width - clip.left - clip.right - margin.left - margin.right,
|
||||
height - clip.top - clip.bottom - margin.top - margin.bottom,
|
||||
gtk_css_node_get_junction_sides (priv->node));
|
||||
|
||||
str = g_strconcat ("Border<", G_OBJECT_TYPE_NAME (gtk_css_gadget_get_owner (gadget)), ">", NULL);
|
||||
border_node = gsk_renderer_create_render_node (renderer);
|
||||
gsk_render_node_set_name (border_node, str);
|
||||
gsk_render_node_set_bounds (border_node, &bounds);
|
||||
cr = gsk_render_node_get_draw_context (border_node);
|
||||
|
||||
gtk_css_style_render_border (style,
|
||||
cr,
|
||||
clip.left + margin.left,
|
||||
clip.top + margin.top,
|
||||
width - clip.left - clip.right - margin.left - margin.right,
|
||||
height - clip.top - clip.bottom - margin.top - margin.bottom,
|
||||
0,
|
||||
gtk_css_node_get_junction_sides (priv->node));
|
||||
|
||||
cairo_destroy (cr);
|
||||
g_free (str);
|
||||
|
||||
gsk_render_node_append_child (box_node, border_node);
|
||||
gsk_render_node_unref (border_node);
|
||||
|
||||
contents_x = clip.left + margin.left + border.left + padding.left;
|
||||
contents_y = clip.top + margin.top + border.top + padding.top;
|
||||
contents_width = width - clip.left - clip.right - margin.left - margin.right - border.left - border.right - padding.left - padding.right;
|
||||
contents_height = height - clip.top - clip.bottom - margin.top - margin.bottom - border.top - border.bottom - padding.top - padding.bottom;
|
||||
|
||||
if (contents_width > 0 && contents_height > 0)
|
||||
{
|
||||
GtkCssGadgetClass *gadget_class = GTK_CSS_GADGET_GET_CLASS (gadget);
|
||||
graphene_rect_t content_bounds =
|
||||
GRAPHENE_RECT_INIT (0, 0, contents_width, contents_height);
|
||||
GskRenderNode *content_node = NULL;
|
||||
graphene_matrix_t content_transform;
|
||||
graphene_point3d_t tmp;
|
||||
|
||||
graphene_matrix_init_translate (&content_transform,
|
||||
graphene_point3d_init (&tmp, contents_x, contents_y, 0));
|
||||
|
||||
/* If there's an override in place, create a temporary node */
|
||||
if (gadget_class->has_content (gadget))
|
||||
{
|
||||
content_node = gsk_renderer_create_render_node (renderer);
|
||||
|
||||
str = g_strconcat ("DrawGadgetContent<", G_OBJECT_TYPE_NAME (gtk_css_gadget_get_owner (gadget)), ">", NULL);
|
||||
gsk_render_node_set_name (content_node, str);
|
||||
gsk_render_node_set_bounds (content_node, &content_bounds);
|
||||
gsk_render_node_set_transform (content_node, &content_transform);
|
||||
|
||||
cr = gsk_render_node_get_draw_context (content_node);
|
||||
|
||||
/* Compatibility mode: draw_focus is left to the draw() implementation */
|
||||
draw_focus = gadget_class->draw (gadget, cr,
|
||||
0, 0,
|
||||
contents_width, contents_height);
|
||||
|
||||
g_free (str);
|
||||
cairo_destroy (cr);
|
||||
|
||||
gsk_render_node_append_child (box_node, content_node);
|
||||
gsk_render_node_unref (content_node);
|
||||
}
|
||||
}
|
||||
|
||||
if (draw_focus)
|
||||
{
|
||||
GskRenderNode *focus_node = gsk_renderer_create_render_node (renderer);
|
||||
|
||||
str = g_strconcat ("Focus<", G_OBJECT_TYPE_NAME (gtk_css_gadget_get_owner (gadget)), ">", NULL);
|
||||
gsk_render_node_set_name (focus_node, str);
|
||||
gsk_render_node_set_bounds (focus_node, &bounds);
|
||||
|
||||
cr = gsk_render_node_get_draw_context (focus_node);
|
||||
gtk_css_style_render_outline (style,
|
||||
cr,
|
||||
clip.left + margin.left,
|
||||
clip.top + margin.top,
|
||||
width - clip.left - clip.right - margin.left - margin.right,
|
||||
height - clip.top - clip.bottom - margin.top - margin.bottom);
|
||||
g_free (str);
|
||||
cairo_destroy (cr);
|
||||
|
||||
gsk_render_node_append_child (box_node, focus_node);
|
||||
gsk_render_node_unref (focus_node);
|
||||
}
|
||||
|
||||
return box_node;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -70,6 +70,8 @@ struct _GtkCssGadgetClass
|
||||
|
||||
void (* style_changed) (GtkCssGadget *gadget,
|
||||
GtkCssStyleChange *change);
|
||||
|
||||
gboolean (* has_content) (GtkCssGadget *gadget);
|
||||
};
|
||||
|
||||
GType gtk_css_gadget_get_type (void) G_GNUC_CONST;
|
||||
@@ -125,6 +127,10 @@ void gtk_css_gadget_allocate (GtkCssGadget
|
||||
void gtk_css_gadget_draw (GtkCssGadget *gadget,
|
||||
cairo_t *cr);
|
||||
|
||||
GskRenderNode * gtk_css_gadget_get_render_node (GtkCssGadget *gadget,
|
||||
GskRenderer *renderer,
|
||||
gboolean draw_focus);
|
||||
|
||||
void gtk_css_gadget_queue_resize (GtkCssGadget *gadget);
|
||||
void gtk_css_gadget_queue_allocate (GtkCssGadget *gadget);
|
||||
void gtk_css_gadget_queue_draw (GtkCssGadget *gadget);
|
||||
@@ -139,6 +145,7 @@ void gtk_css_gadget_get_content_allocation (GtkCssGadget
|
||||
GtkAllocation *allocation,
|
||||
int *baseline);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_CSS_GADGET_PRIVATE_H__ */
|
||||
|
||||
+30
-8
@@ -181,8 +181,8 @@ static void gtk_expander_size_allocate (GtkWidget *widget,
|
||||
GtkAllocation *allocation);
|
||||
static void gtk_expander_map (GtkWidget *widget);
|
||||
static void gtk_expander_unmap (GtkWidget *widget);
|
||||
static gboolean gtk_expander_draw (GtkWidget *widget,
|
||||
cairo_t *cr);
|
||||
static GskRenderNode *gtk_expander_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer);
|
||||
|
||||
static gboolean gtk_expander_enter_notify (GtkWidget *widget,
|
||||
GdkEventCrossing *event);
|
||||
@@ -271,7 +271,7 @@ gtk_expander_class_init (GtkExpanderClass *klass)
|
||||
widget_class->size_allocate = gtk_expander_size_allocate;
|
||||
widget_class->map = gtk_expander_map;
|
||||
widget_class->unmap = gtk_expander_unmap;
|
||||
widget_class->draw = gtk_expander_draw;
|
||||
widget_class->get_render_node = gtk_expander_get_render_node;
|
||||
widget_class->enter_notify_event = gtk_expander_enter_notify;
|
||||
widget_class->leave_notify_event = gtk_expander_leave_notify;
|
||||
widget_class->focus = gtk_expander_focus;
|
||||
@@ -675,13 +675,35 @@ gtk_expander_unmap (GtkWidget *widget)
|
||||
gtk_widget_unmap (priv->label_widget);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_expander_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
static GskRenderNode *
|
||||
gtk_expander_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer)
|
||||
{
|
||||
gtk_css_gadget_draw (GTK_EXPANDER (widget)->priv->gadget, cr);
|
||||
GskRenderNode *res;
|
||||
GskRenderNode *node;
|
||||
|
||||
return FALSE;
|
||||
res = gtk_css_gadget_get_render_node (GTK_EXPANDER (widget)->priv->gadget,
|
||||
renderer,
|
||||
FALSE);
|
||||
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
node = gtk_css_gadget_get_render_node (GTK_EXPANDER (widget)->priv->title_gadget,
|
||||
renderer,
|
||||
FALSE);
|
||||
gsk_render_node_append_child (res, node);
|
||||
gsk_render_node_unref (node);
|
||||
|
||||
node = gtk_css_gadget_get_render_node (GTK_EXPANDER (widget)->priv->arrow_gadget,
|
||||
renderer,
|
||||
FALSE);
|
||||
gsk_render_node_append_child (res, node);
|
||||
gsk_render_node_unref (node);
|
||||
|
||||
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
+40
-50
@@ -382,31 +382,21 @@ gtk_flow_box_child_activate (GtkFlowBoxChild *child)
|
||||
gtk_flow_box_select_and_activate (box, child);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_flow_box_child_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
static GskRenderNode *
|
||||
gtk_flow_box_child_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer)
|
||||
{
|
||||
gtk_css_gadget_draw (CHILD_PRIV (GTK_FLOW_BOX_CHILD (widget))->gadget, cr);
|
||||
GtkFlowBoxChildPrivate *priv = CHILD_PRIV (widget);
|
||||
GskRenderNode *res = gtk_css_gadget_get_render_node (priv->gadget,
|
||||
renderer,
|
||||
gtk_widget_has_visible_focus (widget));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
static gboolean
|
||||
gtk_flow_box_child_render (GtkCssGadget *gadget,
|
||||
cairo_t *cr,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *widget;
|
||||
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
|
||||
|
||||
widget = gtk_css_gadget_get_owner (gadget);
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_flow_box_child_parent_class)->draw (widget, cr);
|
||||
|
||||
return gtk_widget_has_visible_focus (widget);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Size allocation {{{3 */
|
||||
@@ -595,7 +585,7 @@ gtk_flow_box_child_class_init (GtkFlowBoxChildClass *class)
|
||||
|
||||
object_class->finalize = gtk_flow_box_child_finalize;
|
||||
|
||||
widget_class->draw = gtk_flow_box_child_draw;
|
||||
widget_class->get_render_node = gtk_flow_box_child_get_render_node;
|
||||
widget_class->get_request_mode = gtk_flow_box_child_get_request_mode;
|
||||
widget_class->get_preferred_height = gtk_flow_box_child_get_preferred_height;
|
||||
widget_class->get_preferred_height_for_width = gtk_flow_box_child_get_preferred_height_for_width;
|
||||
@@ -642,7 +632,7 @@ gtk_flow_box_child_init (GtkFlowBoxChild *child)
|
||||
GTK_WIDGET (child),
|
||||
gtk_flow_box_child_measure,
|
||||
gtk_flow_box_child_allocate,
|
||||
gtk_flow_box_child_render,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
@@ -2627,44 +2617,37 @@ gtk_flow_box_measure (GtkCssGadget *gadget,
|
||||
|
||||
/* Drawing {{{3 */
|
||||
|
||||
static gboolean
|
||||
gtk_flow_box_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
static GskRenderNode *
|
||||
gtk_flow_box_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer)
|
||||
{
|
||||
gtk_css_gadget_draw (BOX_PRIV (widget)->gadget, cr);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_flow_box_render (GtkCssGadget *gadget,
|
||||
cairo_t *cr,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
|
||||
GtkFlowBox *box = GTK_FLOW_BOX (widget);
|
||||
GtkFlowBoxPrivate *priv = BOX_PRIV (box);
|
||||
GskRenderNode *res = gtk_css_gadget_get_render_node (priv->gadget,
|
||||
renderer,
|
||||
gtk_widget_has_visible_focus (widget));
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_flow_box_parent_class)->draw (widget, cr);
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
|
||||
|
||||
if (priv->rubberband_first && priv->rubberband_last)
|
||||
{
|
||||
GskRenderNode *node;
|
||||
cairo_t *cr;
|
||||
GtkStyleContext *context;
|
||||
GSequenceIter *iter, *iter1, *iter2;
|
||||
GdkRectangle line_rect, rect;
|
||||
GArray *lines;
|
||||
gboolean vertical;
|
||||
|
||||
context = gtk_widget_get_style_context (GTK_WIDGET (box));
|
||||
node = gtk_widget_create_render_node (widget, renderer, "FlowBox RubberBand");
|
||||
|
||||
cr = gsk_render_node_get_draw_context (node);
|
||||
|
||||
vertical = priv->orientation == GTK_ORIENTATION_VERTICAL;
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
context = gtk_widget_get_style_context (widget);
|
||||
gtk_style_context_save_to_node (context, priv->rubberband_node);
|
||||
|
||||
@@ -2728,7 +2711,10 @@ gtk_flow_box_render (GtkCssGadget *gadget,
|
||||
|
||||
cairo_save (cr);
|
||||
cairo_clip (cr);
|
||||
gtk_render_background (context, cr, x, y, width, height);
|
||||
gtk_render_background (context, cr,
|
||||
0, 0,
|
||||
gtk_widget_get_allocated_width (widget),
|
||||
gtk_widget_get_allocated_height (widget));
|
||||
cairo_restore (cr);
|
||||
|
||||
cairo_append_path (cr, path);
|
||||
@@ -2746,10 +2732,14 @@ G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
g_array_free (lines, TRUE);
|
||||
|
||||
gtk_style_context_restore (context);
|
||||
cairo_restore (cr);
|
||||
|
||||
cairo_destroy (cr);
|
||||
|
||||
gsk_render_node_append_child (res, node);
|
||||
gsk_render_node_unref (node);
|
||||
}
|
||||
|
||||
return gtk_widget_has_visible_focus (widget);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Autoscrolling {{{3 */
|
||||
@@ -3786,7 +3776,7 @@ gtk_flow_box_class_init (GtkFlowBoxClass *class)
|
||||
widget_class->realize = gtk_flow_box_realize;
|
||||
widget_class->unmap = gtk_flow_box_unmap;
|
||||
widget_class->focus = gtk_flow_box_focus;
|
||||
widget_class->draw = gtk_flow_box_draw;
|
||||
widget_class->get_render_node = gtk_flow_box_get_render_node;
|
||||
widget_class->key_press_event = gtk_flow_box_key_press_event;
|
||||
widget_class->get_request_mode = gtk_flow_box_get_request_mode;
|
||||
widget_class->get_preferred_width = gtk_flow_box_get_preferred_width;
|
||||
@@ -4148,7 +4138,7 @@ gtk_flow_box_init (GtkFlowBox *box)
|
||||
GTK_WIDGET (box),
|
||||
gtk_flow_box_measure,
|
||||
gtk_flow_box_allocate,
|
||||
gtk_flow_box_render,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
+19
-40
@@ -126,8 +126,8 @@ static void gtk_frame_get_property (GObject *object,
|
||||
guint param_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static gboolean gtk_frame_draw (GtkWidget *widget,
|
||||
cairo_t *cr);
|
||||
static GskRenderNode * gtk_frame_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer);
|
||||
static void gtk_frame_size_allocate (GtkWidget *widget,
|
||||
GtkAllocation *allocation);
|
||||
static void gtk_frame_remove (GtkContainer *container,
|
||||
@@ -192,13 +192,6 @@ static void gtk_frame_allocate_border (GtkCssGadget *gadget,
|
||||
int baseline,
|
||||
GtkAllocation *out_clip,
|
||||
gpointer data);
|
||||
static gboolean gtk_frame_render (GtkCssGadget *gadget,
|
||||
cairo_t *cr,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkFrame, gtk_frame, GTK_TYPE_BIN,
|
||||
@@ -261,7 +254,7 @@ gtk_frame_class_init (GtkFrameClass *class)
|
||||
|
||||
g_object_class_install_properties (gobject_class, LAST_PROP, frame_props);
|
||||
|
||||
widget_class->draw = gtk_frame_draw;
|
||||
widget_class->get_render_node = gtk_frame_get_render_node;
|
||||
widget_class->size_allocate = gtk_frame_size_allocate;
|
||||
widget_class->get_preferred_width = gtk_frame_get_preferred_width;
|
||||
widget_class->get_preferred_height = gtk_frame_get_preferred_height;
|
||||
@@ -317,7 +310,7 @@ gtk_frame_init (GtkFrame *frame)
|
||||
GTK_WIDGET (frame),
|
||||
gtk_frame_measure,
|
||||
gtk_frame_allocate,
|
||||
gtk_frame_render,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
priv->border_gadget = gtk_css_custom_gadget_new ("border",
|
||||
@@ -703,42 +696,28 @@ gtk_frame_get_shadow_type (GtkFrame *frame)
|
||||
return frame->priv->shadow_type;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_frame_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
static GskRenderNode *
|
||||
gtk_frame_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer)
|
||||
{
|
||||
gtk_css_gadget_draw (GTK_FRAME (widget)->priv->gadget, cr);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_frame_render (GtkCssGadget *gadget,
|
||||
cairo_t *cr,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *widget;
|
||||
GtkFramePrivate *priv;
|
||||
gint xc, yc, w, h;
|
||||
GtkFramePrivate *priv = GTK_FRAME (widget)->priv;
|
||||
GtkAllocation allocation;
|
||||
|
||||
widget = gtk_css_gadget_get_owner (gadget);
|
||||
priv = GTK_FRAME (widget)->priv;
|
||||
|
||||
cairo_save (cr);
|
||||
GskRenderNode *node;
|
||||
cairo_t *cr;
|
||||
int xc, yc, w, h;
|
||||
|
||||
gtk_widget_get_allocation (widget, &allocation);
|
||||
|
||||
node = gtk_widget_create_render_node (widget, renderer, "Frame");
|
||||
|
||||
cr = gsk_render_node_get_draw_context (node);
|
||||
|
||||
/* We want to use the standard gadget drawing for the border,
|
||||
* so we clip out the label allocation in order to get the
|
||||
* frame gap.
|
||||
*/
|
||||
xc = priv->label_allocation.x - allocation.x;
|
||||
yc = y;
|
||||
yc = allocation.y;
|
||||
w = priv->label_allocation.width;
|
||||
h = priv->label_allocation.height;
|
||||
|
||||
@@ -761,11 +740,11 @@ gtk_frame_render (GtkCssGadget *gadget,
|
||||
|
||||
gtk_css_gadget_draw (priv->border_gadget, cr);
|
||||
|
||||
cairo_restore (cr);
|
||||
cairo_destroy (cr);
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_frame_parent_class)->draw (widget, cr);
|
||||
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, node);
|
||||
|
||||
return FALSE;
|
||||
return node;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
+12
-19
@@ -1704,27 +1704,20 @@ gtk_grid_allocate (GtkCssGadget *gadget,
|
||||
gtk_container_get_children_clip (GTK_CONTAINER (grid), out_clip);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_grid_render (GtkCssGadget *gadget,
|
||||
cairo_t *cr,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data)
|
||||
static GskRenderNode *
|
||||
gtk_grid_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer)
|
||||
{
|
||||
GTK_WIDGET_CLASS (gtk_grid_parent_class)->draw (gtk_css_gadget_get_owner (gadget), cr);
|
||||
GskRenderNode *res = gtk_css_gadget_get_render_node (GTK_GRID (widget)->priv->gadget,
|
||||
renderer,
|
||||
FALSE);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
static gboolean
|
||||
gtk_grid_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
{
|
||||
gtk_css_gadget_draw (GTK_GRID (widget)->priv->gadget, cr);
|
||||
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
|
||||
|
||||
return FALSE;
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1744,7 +1737,7 @@ gtk_grid_class_init (GtkGridClass *class)
|
||||
widget_class->get_preferred_width_for_height = gtk_grid_get_preferred_width_for_height;
|
||||
widget_class->get_preferred_height_for_width = gtk_grid_get_preferred_height_for_width;
|
||||
widget_class->get_preferred_height_and_baseline_for_width = gtk_grid_get_preferred_height_and_baseline_for_width;
|
||||
widget_class->draw = gtk_grid_draw;
|
||||
widget_class->get_render_node = gtk_grid_get_render_node;
|
||||
|
||||
container_class->add = gtk_grid_add;
|
||||
container_class->remove = gtk_grid_remove;
|
||||
@@ -1851,7 +1844,7 @@ gtk_grid_init (GtkGrid *grid)
|
||||
GTK_WIDGET (grid),
|
||||
gtk_grid_measure,
|
||||
gtk_grid_allocate,
|
||||
gtk_grid_render,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
|
||||
+12
-22
@@ -1859,31 +1859,21 @@ gtk_header_bar_set_child_property (GtkContainer *container,
|
||||
}
|
||||
}
|
||||
|
||||
static gint
|
||||
gtk_header_bar_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
static GskRenderNode *
|
||||
gtk_header_bar_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer)
|
||||
{
|
||||
GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (GTK_HEADER_BAR (widget));
|
||||
GskRenderNode *res = gtk_css_gadget_get_render_node (priv->gadget,
|
||||
renderer,
|
||||
FALSE);
|
||||
|
||||
gtk_css_gadget_draw (priv->gadget, cr);
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
|
||||
|
||||
static gboolean
|
||||
gtk_header_bar_render_contents (GtkCssGadget *gadget,
|
||||
cairo_t *cr,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
gpointer unused)
|
||||
{
|
||||
GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_header_bar_parent_class)->draw (widget, cr);
|
||||
|
||||
return FALSE;
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1972,11 +1962,11 @@ gtk_header_bar_class_init (GtkHeaderBarClass *class)
|
||||
widget_class->get_preferred_height = gtk_header_bar_get_preferred_height;
|
||||
widget_class->get_preferred_height_for_width = gtk_header_bar_get_preferred_height_for_width;
|
||||
widget_class->get_preferred_width_for_height = gtk_header_bar_get_preferred_width_for_height;
|
||||
widget_class->draw = gtk_header_bar_draw;
|
||||
widget_class->realize = gtk_header_bar_realize;
|
||||
widget_class->unrealize = gtk_header_bar_unrealize;
|
||||
widget_class->hierarchy_changed = gtk_header_bar_hierarchy_changed;
|
||||
widget_class->direction_changed = gtk_header_bar_direction_changed;
|
||||
widget_class->get_render_node = gtk_header_bar_get_render_node;
|
||||
|
||||
container_class->add = gtk_header_bar_add;
|
||||
container_class->remove = gtk_header_bar_remove;
|
||||
@@ -2128,7 +2118,7 @@ gtk_header_bar_init (GtkHeaderBar *bar)
|
||||
GTK_WIDGET (bar),
|
||||
gtk_header_bar_get_content_size,
|
||||
gtk_header_bar_allocate_contents,
|
||||
gtk_header_bar_render_contents,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
|
||||
+36
-37
@@ -142,8 +142,8 @@ struct _GtkImagePrivate
|
||||
|
||||
|
||||
#define DEFAULT_ICON_SIZE GTK_ICON_SIZE_BUTTON
|
||||
static gint gtk_image_draw (GtkWidget *widget,
|
||||
cairo_t *cr);
|
||||
static GskRenderNode *gtk_image_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer);
|
||||
static void gtk_image_size_allocate (GtkWidget *widget,
|
||||
GtkAllocation*allocation);
|
||||
static void gtk_image_unmap (GtkWidget *widget);
|
||||
@@ -169,13 +169,6 @@ static void gtk_image_get_content_size (GtkCssGadget *gadget,
|
||||
gint *minimum_baseline,
|
||||
gint *natural_baseline,
|
||||
gpointer unused);
|
||||
static gboolean gtk_image_render_contents (GtkCssGadget *gadget,
|
||||
cairo_t *cr,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data);
|
||||
|
||||
static void gtk_image_style_updated (GtkWidget *widget);
|
||||
static void gtk_image_finalize (GObject *object);
|
||||
@@ -224,7 +217,7 @@ gtk_image_class_init (GtkImageClass *class)
|
||||
gobject_class->finalize = gtk_image_finalize;
|
||||
|
||||
widget_class = GTK_WIDGET_CLASS (class);
|
||||
widget_class->draw = gtk_image_draw;
|
||||
widget_class->get_render_node = gtk_image_get_render_node;
|
||||
widget_class->get_preferred_width = gtk_image_get_preferred_width;
|
||||
widget_class->get_preferred_height = gtk_image_get_preferred_height;
|
||||
widget_class->get_preferred_height_and_baseline_for_width = gtk_image_get_preferred_height_and_baseline_for_width;
|
||||
@@ -381,9 +374,8 @@ gtk_image_init (GtkImage *image)
|
||||
GTK_WIDGET (image),
|
||||
gtk_image_get_content_size,
|
||||
NULL,
|
||||
gtk_image_render_contents,
|
||||
NULL,
|
||||
NULL, NULL);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1418,33 +1410,35 @@ gtk_image_get_content_size (GtkCssGadget *gadget,
|
||||
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_image_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
static GskRenderNode *
|
||||
gtk_image_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer)
|
||||
{
|
||||
gtk_css_gadget_draw (GTK_IMAGE (widget)->priv->gadget,
|
||||
cr);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_image_render_contents (GtkCssGadget *gadget,
|
||||
cairo_t *cr,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *widget;
|
||||
GtkImage *image;
|
||||
GtkImagePrivate *priv;
|
||||
GtkImage *image = GTK_IMAGE (widget);
|
||||
GtkImagePrivate *priv = image->priv;
|
||||
gint w, h, baseline;
|
||||
gint x, y, width, height;
|
||||
GskRenderNode *res;
|
||||
GskRenderNode *node;
|
||||
GtkAllocation alloc, clip;
|
||||
cairo_t *cr;
|
||||
|
||||
widget = gtk_css_gadget_get_owner (gadget);
|
||||
image = GTK_IMAGE (widget);
|
||||
priv = image->priv;
|
||||
res = gtk_css_gadget_get_render_node (priv->gadget, renderer, FALSE);
|
||||
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
node = gtk_widget_create_render_node (widget, renderer, "Image Content");
|
||||
|
||||
gtk_widget_get_clip (widget, &clip);
|
||||
_gtk_widget_get_allocation (widget, &alloc);
|
||||
|
||||
cr = gsk_render_node_get_draw_context (node);
|
||||
cairo_translate (cr, alloc.x - clip.x, alloc.y - clip.y);
|
||||
x = 0;
|
||||
y = 0;
|
||||
width = alloc.width;
|
||||
height = alloc.height;
|
||||
|
||||
_gtk_icon_helper_get_size (priv->icon_helper, &w, &h);
|
||||
|
||||
@@ -1470,7 +1464,12 @@ gtk_image_render_contents (GtkCssGadget *gadget,
|
||||
_gtk_icon_helper_draw (priv->icon_helper, cr, x, y);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
cairo_destroy (cr);
|
||||
|
||||
gsk_render_node_append_child (res, node);
|
||||
gsk_render_node_unref (node);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
+38
-37
@@ -414,11 +414,12 @@ static void gtk_label_size_allocate (GtkWidget *widget,
|
||||
static void gtk_label_state_flags_changed (GtkWidget *widget,
|
||||
GtkStateFlags prev_state);
|
||||
static void gtk_label_style_updated (GtkWidget *widget);
|
||||
static gboolean gtk_label_draw (GtkWidget *widget,
|
||||
cairo_t *cr);
|
||||
static gboolean gtk_label_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction);
|
||||
|
||||
static GskRenderNode *gtk_label_get_render_node (GtkWidget *label,
|
||||
GskRenderer *renderer);
|
||||
|
||||
static void gtk_label_realize (GtkWidget *widget);
|
||||
static void gtk_label_unrealize (GtkWidget *widget);
|
||||
static void gtk_label_map (GtkWidget *widget);
|
||||
@@ -577,13 +578,6 @@ static void gtk_label_measure (GtkCssGadget *gadget,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline,
|
||||
gpointer unused);
|
||||
static gboolean gtk_label_render (GtkCssGadget *gadget,
|
||||
cairo_t *cr,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data);
|
||||
|
||||
static GtkBuildableIface *buildable_parent_iface = NULL;
|
||||
|
||||
@@ -631,7 +625,7 @@ gtk_label_class_init (GtkLabelClass *class)
|
||||
widget_class->state_flags_changed = gtk_label_state_flags_changed;
|
||||
widget_class->style_updated = gtk_label_style_updated;
|
||||
widget_class->query_tooltip = gtk_label_query_tooltip;
|
||||
widget_class->draw = gtk_label_draw;
|
||||
widget_class->get_render_node = gtk_label_get_render_node;
|
||||
widget_class->realize = gtk_label_realize;
|
||||
widget_class->unrealize = gtk_label_unrealize;
|
||||
widget_class->map = gtk_label_map;
|
||||
@@ -1393,7 +1387,7 @@ gtk_label_init (GtkLabel *label)
|
||||
GTK_WIDGET (label),
|
||||
gtk_label_measure,
|
||||
NULL,
|
||||
gtk_label_render,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
@@ -4234,39 +4228,41 @@ gtk_label_get_focus_link (GtkLabel *label)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_label_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
{
|
||||
gtk_css_gadget_draw (GTK_LABEL (widget)->priv->gadget, cr);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void layout_to_window_coords (GtkLabel *label,
|
||||
gint *x,
|
||||
gint *y);
|
||||
|
||||
static gboolean
|
||||
gtk_label_render (GtkCssGadget *gadget,
|
||||
cairo_t *cr,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data)
|
||||
static GskRenderNode *
|
||||
gtk_label_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer)
|
||||
{
|
||||
GtkWidget *widget;
|
||||
GtkLabel *label;
|
||||
GtkLabelPrivate *priv;
|
||||
GtkLabelSelectionInfo *info;
|
||||
GtkLabel *label = GTK_LABEL (widget);
|
||||
GtkLabelPrivate *priv = label->priv;
|
||||
GtkLabelSelectionInfo *info = priv->select_info;
|
||||
GtkStyleContext *context;
|
||||
gint x, y, width, height;
|
||||
gint lx, ly;
|
||||
cairo_t *cr;
|
||||
GtkAllocation alloc, clip;
|
||||
GskRenderNode *node;
|
||||
GskRenderNode *res;
|
||||
|
||||
widget = gtk_css_gadget_get_owner (gadget);
|
||||
label = GTK_LABEL (widget);
|
||||
priv = label->priv;
|
||||
info = priv->select_info;
|
||||
res = gtk_css_gadget_get_render_node (priv->gadget, renderer, FALSE);
|
||||
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
node = gtk_widget_create_render_node (widget, renderer, "Label Content");
|
||||
|
||||
gtk_widget_get_clip (widget, &clip);
|
||||
_gtk_widget_get_allocation (widget, &alloc);
|
||||
|
||||
cr = gsk_render_node_get_draw_context (node);
|
||||
cairo_translate (cr, alloc.x - clip.x, alloc.y - clip.y);
|
||||
x = 0;
|
||||
y = 0;
|
||||
width = alloc.width;
|
||||
height = alloc.height;
|
||||
|
||||
gtk_label_ensure_layout (label);
|
||||
|
||||
@@ -4377,7 +4373,12 @@ gtk_label_render (GtkCssGadget *gadget,
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
cairo_destroy (cr);
|
||||
|
||||
gsk_render_node_append_child (res, node);
|
||||
gsk_render_node_unref (node);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
||||
+30
-53
@@ -209,8 +209,9 @@ static GSequenceIter* gtk_list_box_get_previous_visible (GtkListBo
|
||||
GSequenceIter *iter);
|
||||
static GtkListBoxRow *gtk_list_box_get_first_focusable (GtkListBox *box);
|
||||
static GtkListBoxRow *gtk_list_box_get_last_focusable (GtkListBox *box);
|
||||
static gboolean gtk_list_box_draw (GtkWidget *widget,
|
||||
cairo_t *cr);
|
||||
static GskRenderNode * gtk_list_box_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer);
|
||||
|
||||
static void gtk_list_box_realize (GtkWidget *widget);
|
||||
static void gtk_list_box_add (GtkContainer *container,
|
||||
GtkWidget *widget);
|
||||
@@ -301,13 +302,6 @@ static void gtk_list_box_allocate (GtkCssGadget *gadget,
|
||||
int baseline,
|
||||
GtkAllocation *out_clip,
|
||||
gpointer data);
|
||||
static gboolean gtk_list_box_render (GtkCssGadget *gadget,
|
||||
cairo_t *cr,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data);
|
||||
|
||||
|
||||
|
||||
@@ -426,7 +420,7 @@ gtk_list_box_class_init (GtkListBoxClass *klass)
|
||||
widget_class->motion_notify_event = gtk_list_box_motion_notify_event;
|
||||
widget_class->show = gtk_list_box_show;
|
||||
widget_class->focus = gtk_list_box_focus;
|
||||
widget_class->draw = gtk_list_box_draw;
|
||||
widget_class->get_render_node = gtk_list_box_get_render_node;
|
||||
widget_class->realize = gtk_list_box_realize;
|
||||
widget_class->compute_expand = gtk_list_box_compute_expand;
|
||||
widget_class->get_request_mode = gtk_list_box_get_request_mode;
|
||||
@@ -663,7 +657,7 @@ gtk_list_box_init (GtkListBox *box)
|
||||
GTK_WIDGET (box),
|
||||
gtk_list_box_measure,
|
||||
gtk_list_box_allocate,
|
||||
gtk_list_box_render,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
@@ -2127,29 +2121,22 @@ gtk_list_box_focus (GtkWidget *widget,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_list_box_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
static GskRenderNode *
|
||||
gtk_list_box_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer)
|
||||
{
|
||||
gtk_css_gadget_draw (BOX_PRIV (widget)->gadget, cr);
|
||||
GtkListBox *box = GTK_LIST_BOX (widget);
|
||||
GtkListBoxPrivate *priv = BOX_PRIV (box);
|
||||
GskRenderNode *res = gtk_css_gadget_get_render_node (priv->gadget,
|
||||
renderer,
|
||||
FALSE);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
static gboolean
|
||||
gtk_list_box_render (GtkCssGadget *gadget,
|
||||
cairo_t *cr,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
|
||||
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_list_box_parent_class)->draw (widget, cr);
|
||||
|
||||
return FALSE;
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -3262,31 +3249,21 @@ gtk_list_box_row_hide (GtkWidget *widget)
|
||||
gtk_list_box_row_visibility_changed (box, row);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_list_box_row_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
static GskRenderNode *
|
||||
gtk_list_box_row_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer)
|
||||
{
|
||||
gtk_css_gadget_draw (ROW_PRIV (GTK_LIST_BOX_ROW (widget))->gadget, cr);
|
||||
GtkListBoxRowPrivate *priv = ROW_PRIV (widget);
|
||||
GskRenderNode *res = gtk_css_gadget_get_render_node (priv->gadget,
|
||||
renderer,
|
||||
gtk_widget_has_visible_focus (widget));
|
||||
|
||||
return GDK_EVENT_PROPAGATE;
|
||||
}
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
static gboolean
|
||||
gtk_list_box_row_render (GtkCssGadget *gadget,
|
||||
cairo_t *cr,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *widget;
|
||||
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
|
||||
|
||||
widget = gtk_css_gadget_get_owner (gadget);
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_list_box_row_parent_class)->draw (widget, cr);
|
||||
|
||||
return gtk_widget_has_visible_focus (widget);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -3750,7 +3727,7 @@ gtk_list_box_row_class_init (GtkListBoxRowClass *klass)
|
||||
|
||||
widget_class->show = gtk_list_box_row_show;
|
||||
widget_class->hide = gtk_list_box_row_hide;
|
||||
widget_class->draw = gtk_list_box_row_draw;
|
||||
widget_class->get_render_node = gtk_list_box_row_get_render_node;
|
||||
widget_class->get_preferred_height = gtk_list_box_row_get_preferred_height;
|
||||
widget_class->get_preferred_height_for_width = gtk_list_box_row_get_preferred_height_for_width;
|
||||
widget_class->get_preferred_width = gtk_list_box_row_get_preferred_width;
|
||||
@@ -3819,7 +3796,7 @@ gtk_list_box_row_init (GtkListBoxRow *row)
|
||||
GTK_WIDGET (row),
|
||||
gtk_list_box_row_measure,
|
||||
gtk_list_box_row_allocate,
|
||||
gtk_list_box_row_render,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
gtk_css_gadget_add_class (ROW_PRIV (row)->gadget, "activatable");
|
||||
|
||||
+17
-1
@@ -24,6 +24,8 @@
|
||||
#include "gtkbuildable.h"
|
||||
#include "gtkscrolledwindow.h"
|
||||
#include "gtkmarshalers.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
#include "gtkcontainerprivate.h"
|
||||
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkintl.h"
|
||||
@@ -482,6 +484,20 @@ gtk_overlay_unmap (GtkWidget *widget)
|
||||
GTK_WIDGET_CLASS (gtk_overlay_parent_class)->unmap (widget);
|
||||
}
|
||||
|
||||
static GskRenderNode *
|
||||
gtk_overlay_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer)
|
||||
{
|
||||
GskRenderNode *res = gtk_widget_create_render_node (widget, renderer, G_OBJECT_TYPE_NAME (widget));
|
||||
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_overlay_remove (GtkContainer *container,
|
||||
GtkWidget *widget)
|
||||
@@ -738,7 +754,6 @@ gtk_overlay_get_child_property (GtkContainer *container,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gtk_overlay_class_init (GtkOverlayClass *klass)
|
||||
{
|
||||
@@ -751,6 +766,7 @@ gtk_overlay_class_init (GtkOverlayClass *klass)
|
||||
widget_class->unrealize = gtk_overlay_unrealize;
|
||||
widget_class->map = gtk_overlay_map;
|
||||
widget_class->unmap = gtk_overlay_unmap;
|
||||
widget_class->get_render_node = gtk_overlay_get_render_node;
|
||||
|
||||
container_class->remove = gtk_overlay_remove;
|
||||
container_class->forall = gtk_overlay_forall;
|
||||
|
||||
@@ -428,6 +428,151 @@ gtk_css_style_render_background (GtkCssStyle *style,
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
static GskBlendMode
|
||||
translate_blend_mode (GtkCssBlendMode blend_mode)
|
||||
{
|
||||
switch (blend_mode)
|
||||
{
|
||||
case GTK_CSS_BLEND_MODE_COLOR_BURN: return GSK_BLEND_MODE_COLOR_BURN;
|
||||
case GTK_CSS_BLEND_MODE_COLOR_DODGE: return GSK_BLEND_MODE_COLOR_BURN;
|
||||
case GTK_CSS_BLEND_MODE_DARKEN: return GSK_BLEND_MODE_DARKEN;
|
||||
case GTK_CSS_BLEND_MODE_LIGHTEN: return GSK_BLEND_MODE_LIGHTEN;
|
||||
case GTK_CSS_BLEND_MODE_DIFFERENCE: return GSK_BLEND_MODE_DIFFERENCE;
|
||||
case GTK_CSS_BLEND_MODE_EXCLUSION: return GSK_BLEND_MODE_EXCLUSION;
|
||||
case GTK_CSS_BLEND_MODE_HARD_LIGHT: return GSK_BLEND_MODE_HARD_LIGHT;
|
||||
case GTK_CSS_BLEND_MODE_SOFT_LIGHT: return GSK_BLEND_MODE_SOFT_LIGHT;
|
||||
case GTK_CSS_BLEND_MODE_MULTIPLY: return GSK_BLEND_MODE_MULTIPLY;
|
||||
case GTK_CSS_BLEND_MODE_NORMAL: return GSK_BLEND_MODE_DEFAULT;
|
||||
case GTK_CSS_BLEND_MODE_OVERLAY: return GSK_BLEND_MODE_OVERLAY;
|
||||
case GTK_CSS_BLEND_MODE_SCREEN: return GSK_BLEND_MODE_SCREEN;
|
||||
case GTK_CSS_BLEND_MODE_SATURATE:
|
||||
case GTK_CSS_BLEND_MODE_LUMINOSITY:
|
||||
case GTK_CSS_BLEND_MODE_COLOR:
|
||||
case GTK_CSS_BLEND_MODE_HUE:
|
||||
default:
|
||||
g_warning ("CSS blend mode %d not supported by GSK yet", blend_mode);
|
||||
return GSK_BLEND_MODE_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gtk_css_style_add_background_render_nodes (GtkCssStyle *style,
|
||||
GskRenderer *renderer,
|
||||
GskRenderNode *parent_node,
|
||||
graphene_rect_t *bounds,
|
||||
const char *name,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble width,
|
||||
gdouble height,
|
||||
GtkJunctionSides junction)
|
||||
{
|
||||
GskRenderNode *bg_node;
|
||||
cairo_t *cr;
|
||||
GtkCssValue *background_image;
|
||||
GtkCssValue *blend_modes;
|
||||
GtkCssValue *box_shadow;
|
||||
const GdkRGBA *bg_color;
|
||||
GtkThemingBackground bg;
|
||||
gchar *str;
|
||||
gint number_of_layers;
|
||||
gint idx;
|
||||
|
||||
background_image = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_IMAGE);
|
||||
blend_modes = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_BLEND_MODE);
|
||||
bg_color = _gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_COLOR));
|
||||
box_shadow = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BOX_SHADOW);
|
||||
|
||||
/* This is the common default case of no background */
|
||||
if (gtk_rgba_is_clear (bg_color) &&
|
||||
_gtk_css_array_value_get_n_values (background_image) == 1 &&
|
||||
_gtk_css_image_value_get_image (_gtk_css_array_value_get_nth (background_image, 0)) == NULL &&
|
||||
_gtk_css_shadows_value_is_none (box_shadow))
|
||||
return;
|
||||
|
||||
bg.style = style;
|
||||
_gtk_theming_background_init_style (&bg, width, height, junction);
|
||||
|
||||
if (!_gtk_css_shadows_value_is_none (box_shadow))
|
||||
{
|
||||
str = g_strconcat ("Outer Shadow<", name, ">", NULL);
|
||||
bg_node = gsk_renderer_create_render_node (renderer);
|
||||
gsk_render_node_set_name (bg_node, str);
|
||||
gsk_render_node_set_bounds (bg_node, bounds);
|
||||
cr = gsk_render_node_get_draw_context (bg_node);
|
||||
cairo_translate (cr, x, y);
|
||||
_gtk_css_shadows_value_paint_box (box_shadow,
|
||||
cr,
|
||||
&bg.boxes[GTK_CSS_AREA_BORDER_BOX],
|
||||
FALSE);
|
||||
cairo_destroy (cr);
|
||||
g_free (str);
|
||||
|
||||
gsk_render_node_append_child (parent_node, bg_node);
|
||||
gsk_render_node_unref (bg_node);
|
||||
}
|
||||
|
||||
if (!gtk_rgba_is_clear (bg_color))
|
||||
{
|
||||
str = g_strconcat ("Background Color<", name, ">", NULL);
|
||||
bg_node = gsk_renderer_create_render_node (renderer);
|
||||
gsk_render_node_set_name (bg_node, str);
|
||||
gsk_render_node_set_bounds (bg_node, bounds);
|
||||
cr = gsk_render_node_get_draw_context (bg_node);
|
||||
cairo_translate (cr, x, y);
|
||||
_gtk_theming_background_paint_color (&bg, cr, bg_color, background_image);
|
||||
cairo_destroy (cr);
|
||||
g_free (str);
|
||||
|
||||
gsk_render_node_append_child (parent_node, bg_node);
|
||||
gsk_render_node_unref (bg_node);
|
||||
}
|
||||
|
||||
number_of_layers = _gtk_css_array_value_get_n_values (background_image);
|
||||
|
||||
for (idx = number_of_layers - 1; idx >= 0; idx--)
|
||||
{
|
||||
GtkCssBlendMode blend_mode;
|
||||
|
||||
blend_mode = _gtk_css_blend_mode_value_get (_gtk_css_array_value_get_nth (blend_modes, idx));
|
||||
|
||||
str = g_strdup_printf ("Background%d<%s>", idx, name);
|
||||
bg_node = gsk_renderer_create_render_node (renderer);
|
||||
|
||||
gsk_render_node_set_blend_mode (bg_node,
|
||||
translate_blend_mode (blend_mode));
|
||||
gsk_render_node_set_name (bg_node, str);
|
||||
gsk_render_node_set_bounds (bg_node, bounds);
|
||||
cr = gsk_render_node_get_draw_context (bg_node);
|
||||
cairo_translate (cr, x, y);
|
||||
_gtk_theming_background_paint_layer (&bg, idx, cr, GTK_CSS_BLEND_MODE_NORMAL);
|
||||
cairo_destroy (cr);
|
||||
g_free (str);
|
||||
|
||||
gsk_render_node_append_child (parent_node, bg_node);
|
||||
gsk_render_node_unref (bg_node);
|
||||
}
|
||||
|
||||
if (!_gtk_css_shadows_value_is_none (box_shadow))
|
||||
{
|
||||
str = g_strconcat ("Inner Shadow<", name, ">", NULL);
|
||||
bg_node = gsk_renderer_create_render_node (renderer);
|
||||
gsk_render_node_set_name (bg_node, str);
|
||||
gsk_render_node_set_bounds (bg_node, bounds);
|
||||
cr = gsk_render_node_get_draw_context (bg_node);
|
||||
cairo_translate (cr, x, y);
|
||||
_gtk_css_shadows_value_paint_box (box_shadow,
|
||||
cr,
|
||||
&bg.boxes[GTK_CSS_AREA_PADDING_BOX],
|
||||
TRUE);
|
||||
cairo_destroy (cr);
|
||||
g_free (str);
|
||||
|
||||
gsk_render_node_append_child (parent_node, bg_node);
|
||||
gsk_render_node_unref (bg_node);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
corner_value_is_right_angle (GtkCssValue *value)
|
||||
{
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "gtkcsstypesprivate.h"
|
||||
#include "gtktypes.h"
|
||||
#include "gsk/gsk.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@@ -36,6 +37,17 @@ void gtk_css_style_render_background (GtkCssStyle
|
||||
gdouble height,
|
||||
GtkJunctionSides junction);
|
||||
gboolean gtk_css_style_render_background_is_opaque (GtkCssStyle *style);
|
||||
void gtk_css_style_add_background_render_nodes (GtkCssStyle *style,
|
||||
GskRenderer *renderer,
|
||||
GskRenderNode *parent_node,
|
||||
graphene_rect_t *bounds,
|
||||
const char *name,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble width,
|
||||
gdouble height,
|
||||
GtkJunctionSides junction);
|
||||
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
+7
-7
@@ -123,13 +123,13 @@ gtk_spinner_size_allocate (GtkWidget *widget,
|
||||
gtk_widget_set_clip (widget, &clip);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_spinner_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
static GskRenderNode *
|
||||
gtk_spinner_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer)
|
||||
{
|
||||
gtk_css_gadget_draw (GTK_SPINNER (widget)->priv->gadget, cr);
|
||||
|
||||
return FALSE;
|
||||
return gtk_css_gadget_get_render_node (GTK_SPINNER (widget)->priv->gadget,
|
||||
renderer,
|
||||
FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -204,7 +204,7 @@ gtk_spinner_class_init (GtkSpinnerClass *klass)
|
||||
|
||||
widget_class = GTK_WIDGET_CLASS(klass);
|
||||
widget_class->size_allocate = gtk_spinner_size_allocate;
|
||||
widget_class->draw = gtk_spinner_draw;
|
||||
widget_class->get_render_node = gtk_spinner_get_render_node;
|
||||
widget_class->get_preferred_width = gtk_spinner_get_preferred_width;
|
||||
widget_class->get_preferred_height = gtk_spinner_get_preferred_height;
|
||||
|
||||
|
||||
+168
-16
@@ -6369,6 +6369,18 @@ gtk_cairo_set_marked_for_draw (cairo_t *cr,
|
||||
cairo_set_user_data (cr, &mark_for_draw_key, NULL, NULL);
|
||||
}
|
||||
|
||||
static GskRenderer *
|
||||
gtk_widget_get_renderer (GtkWidget *widget)
|
||||
{
|
||||
GtkWidget *toplevel;
|
||||
|
||||
toplevel = _gtk_widget_get_toplevel (widget);
|
||||
if (_gtk_widget_is_toplevel (toplevel))
|
||||
return gtk_window_get_renderer (GTK_WINDOW (toplevel));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_cairo_should_draw_window:
|
||||
* @cr: a cairo context
|
||||
@@ -6436,6 +6448,7 @@ gtk_widget_draw_internal (GtkWidget *widget,
|
||||
|
||||
if (gdk_cairo_get_clip_rectangle (cr, NULL))
|
||||
{
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_GET_CLASS (widget);
|
||||
GdkWindow *event_window = NULL;
|
||||
gboolean result;
|
||||
gboolean push_group;
|
||||
@@ -6468,17 +6481,46 @@ gtk_widget_draw_internal (GtkWidget *widget,
|
||||
g_warning ("%s %p is drawn without a current allocation. This should not happen.", G_OBJECT_TYPE_NAME (widget), widget);
|
||||
#endif
|
||||
|
||||
if (g_signal_has_handler_pending (widget, widget_signals[DRAW], 0, FALSE))
|
||||
/* If the widget uses GSK render nodes then we need a fallback path to
|
||||
* render on the Cairo context; otherwise we just go through the old
|
||||
* GtkWidget::draw path
|
||||
*/
|
||||
if (widget_class->get_render_node != NULL)
|
||||
{
|
||||
g_signal_emit (widget, widget_signals[DRAW],
|
||||
0, cr,
|
||||
&result);
|
||||
GskRenderer *renderer = gtk_widget_get_renderer (widget);
|
||||
GskRenderer *fallback;
|
||||
graphene_rect_t viewport;
|
||||
GskRenderNode *node;
|
||||
|
||||
graphene_rect_init (&viewport,
|
||||
widget->priv->clip.x,
|
||||
widget->priv->clip.y,
|
||||
widget->priv->clip.width,
|
||||
widget->priv->clip.height);
|
||||
fallback = gsk_renderer_create_fallback (renderer, &viewport, cr);
|
||||
node = gtk_widget_get_render_node (widget, fallback);
|
||||
if (node != NULL)
|
||||
{
|
||||
gsk_renderer_render (fallback, node, NULL);
|
||||
gsk_render_node_unref (node);
|
||||
}
|
||||
|
||||
g_object_unref (fallback);
|
||||
}
|
||||
else if (GTK_WIDGET_GET_CLASS (widget)->draw)
|
||||
else
|
||||
{
|
||||
cairo_save (cr);
|
||||
GTK_WIDGET_GET_CLASS (widget)->draw (widget, cr);
|
||||
cairo_restore (cr);
|
||||
if (g_signal_has_handler_pending (widget, widget_signals[DRAW], 0, FALSE))
|
||||
{
|
||||
g_signal_emit (widget, widget_signals[DRAW],
|
||||
0, cr,
|
||||
&result);
|
||||
}
|
||||
else if (GTK_WIDGET_GET_CLASS (widget)->draw)
|
||||
{
|
||||
cairo_save (cr);
|
||||
GTK_WIDGET_GET_CLASS (widget)->draw (widget, cr);
|
||||
cairo_restore (cr);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
@@ -16052,27 +16094,137 @@ gtk_widget_reset_controllers (GtkWidget *widget)
|
||||
}
|
||||
}
|
||||
|
||||
GskRenderNode *
|
||||
gtk_widget_create_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer,
|
||||
const char *name)
|
||||
{
|
||||
GskRenderNode *res = gsk_renderer_create_render_node (renderer);
|
||||
GtkAllocation clip;
|
||||
graphene_rect_t bounds;
|
||||
|
||||
gtk_widget_get_clip (widget, &clip);
|
||||
|
||||
graphene_rect_init (&bounds, 0, 0, clip.width, clip.height);
|
||||
|
||||
gsk_render_node_set_name (res, name);
|
||||
gsk_render_node_set_bounds (res, &bounds);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
GskRenderNode *
|
||||
gtk_widget_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer)
|
||||
{
|
||||
GtkWidgetClass *klass = GTK_WIDGET_GET_CLASS (widget);
|
||||
GskRenderNode *node;
|
||||
graphene_matrix_t m;
|
||||
graphene_point3d_t p;
|
||||
graphene_rect_t bounds;
|
||||
GtkAllocation clip;
|
||||
GtkAllocation alloc;
|
||||
|
||||
if (_gtk_widget_get_alloc_needed (widget))
|
||||
return NULL;
|
||||
|
||||
gtk_widget_get_clip (widget, &clip);
|
||||
_gtk_widget_get_allocation (widget, &alloc);
|
||||
graphene_rect_init (&bounds, 0, 0, clip.width, clip.height);
|
||||
graphene_matrix_init_translate (&m, graphene_point3d_init (&p, clip.x, clip.y, 0.f));
|
||||
|
||||
/* Compatibility mode: if the widget does not have a render node, we draw
|
||||
* using gtk_widget_draw() on a temporary node
|
||||
*/
|
||||
if (klass->get_render_node == NULL)
|
||||
{
|
||||
GskRenderNode *tmp;
|
||||
cairo_t *cr;
|
||||
char *str;
|
||||
|
||||
str = g_strconcat ("Fallback<", G_OBJECT_TYPE_NAME (widget), ">", NULL);
|
||||
|
||||
tmp = gsk_renderer_create_render_node (renderer);
|
||||
gsk_render_node_set_name (tmp, str);
|
||||
gsk_render_node_set_bounds (tmp, &bounds);
|
||||
gsk_render_node_set_transform (tmp, &m);
|
||||
|
||||
cr = gsk_render_node_get_draw_context (tmp);
|
||||
cairo_translate (cr, alloc.x - clip.x, alloc.y - clip.y);
|
||||
gtk_widget_draw_internal (widget, cr, TRUE);
|
||||
cairo_destroy (cr);
|
||||
|
||||
g_free (str);
|
||||
|
||||
node = tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
node = klass->get_render_node (widget, renderer);
|
||||
|
||||
/* Compatibility mode: if there's a ::draw signal handler, we add a
|
||||
* child node with the contents of the handler
|
||||
*/
|
||||
if (g_signal_has_handler_pending (widget, widget_signals[DRAW], 0, FALSE))
|
||||
{
|
||||
GskRenderNode *tmp;
|
||||
gboolean result;
|
||||
cairo_t *cr;
|
||||
char *str;
|
||||
|
||||
str = g_strconcat ("DrawSignal<", G_OBJECT_TYPE_NAME (widget), ">", NULL);
|
||||
|
||||
tmp = gsk_renderer_create_render_node (renderer);
|
||||
gsk_render_node_set_name (tmp, str);
|
||||
gsk_render_node_set_bounds (tmp, &bounds);
|
||||
|
||||
cr = gsk_render_node_get_draw_context (tmp);
|
||||
cairo_translate (cr, alloc.x - clip.x, alloc.y - clip.y);
|
||||
g_signal_emit (widget, widget_signals[DRAW], 0, cr, &result);
|
||||
cairo_destroy (cr);
|
||||
|
||||
g_free (str);
|
||||
|
||||
if (node != NULL)
|
||||
{
|
||||
gsk_render_node_append_child (node, tmp);
|
||||
gsk_render_node_unref (tmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
node = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_widget_render (GtkWidget *widget,
|
||||
GdkWindow *window,
|
||||
const cairo_region_t *region)
|
||||
{
|
||||
GdkDrawingContext *context;
|
||||
gboolean do_clip;
|
||||
cairo_t *cr;
|
||||
int x, y;
|
||||
GskRenderer *renderer;
|
||||
GskRenderNode *root;
|
||||
|
||||
/* We only render double buffered on native windows */
|
||||
if (!gdk_window_has_native (window))
|
||||
return;
|
||||
|
||||
renderer = gtk_widget_get_renderer (widget);
|
||||
if (renderer == NULL)
|
||||
return;
|
||||
|
||||
root = gtk_widget_get_render_node (widget, renderer);
|
||||
if (root == NULL)
|
||||
return;
|
||||
|
||||
context = gdk_window_begin_draw_frame (window, region);
|
||||
cr = gdk_drawing_context_get_cairo_context (context);
|
||||
|
||||
do_clip = _gtk_widget_get_translation_to_window (widget, window, &x, &y);
|
||||
cairo_translate (cr, -x, -y);
|
||||
|
||||
gtk_widget_draw_internal (widget, cr, do_clip);
|
||||
gsk_renderer_render (renderer, root, context);
|
||||
gsk_render_node_unref (root);
|
||||
|
||||
gdk_window_end_draw_frame (window, context);
|
||||
}
|
||||
|
||||
+4
-1
@@ -30,6 +30,7 @@
|
||||
#endif
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <gsk/gsk.h>
|
||||
#include <gtk/gtkaccelgroup.h>
|
||||
#include <gtk/gtkborder.h>
|
||||
#include <gtk/gtktypes.h>
|
||||
@@ -595,12 +596,14 @@ struct _GtkWidgetClass
|
||||
void (*queue_draw_region) (GtkWidget *widget,
|
||||
const cairo_region_t *region);
|
||||
|
||||
GskRenderNode *(* get_render_node) (GtkWidget *widget,
|
||||
GskRenderer *renderer);
|
||||
|
||||
/*< private >*/
|
||||
|
||||
GtkWidgetClassPrivate *priv;
|
||||
|
||||
/* Padding for future expansion */
|
||||
void (*_gtk_reserved6) (void);
|
||||
void (*_gtk_reserved7) (void);
|
||||
};
|
||||
|
||||
|
||||
@@ -297,6 +297,13 @@ void gtk_widget_render (GtkWidget
|
||||
const cairo_region_t *region);
|
||||
|
||||
|
||||
GskRenderNode * gtk_widget_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer);
|
||||
|
||||
GskRenderNode * gtk_widget_create_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer,
|
||||
const char *name);
|
||||
|
||||
/* inline getters */
|
||||
|
||||
static inline gboolean
|
||||
|
||||
+120
-69
@@ -30,11 +30,13 @@
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <graphene.h>
|
||||
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkwindowprivate.h"
|
||||
#include "gtkaccelgroupprivate.h"
|
||||
#include "gtkbindings.h"
|
||||
#include "gtkcontainerprivate.h"
|
||||
#include "gtkcsscornervalueprivate.h"
|
||||
#include "gtkcssiconthemevalueprivate.h"
|
||||
#include "gtkcssrgbavalueprivate.h"
|
||||
@@ -268,6 +270,8 @@ struct _GtkWindowPrivate
|
||||
GdkWindow *hardcoded_window;
|
||||
|
||||
GtkCssNode *decoration_node;
|
||||
|
||||
GskRenderer *renderer;
|
||||
};
|
||||
|
||||
static const GtkTargetEntry dnd_dest_targets [] = {
|
||||
@@ -440,8 +444,8 @@ static void gtk_window_real_activate_focus (GtkWindow *window);
|
||||
static void gtk_window_keys_changed (GtkWindow *window);
|
||||
static gboolean gtk_window_enable_debugging (GtkWindow *window,
|
||||
gboolean toggle);
|
||||
static gint gtk_window_draw (GtkWidget *widget,
|
||||
cairo_t *cr);
|
||||
static GskRenderNode *gtk_window_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer);
|
||||
static void gtk_window_unset_transient_for (GtkWindow *window);
|
||||
static void gtk_window_transient_parent_realized (GtkWidget *parent,
|
||||
GtkWidget *window);
|
||||
@@ -698,7 +702,6 @@ gtk_window_class_init (GtkWindowClass *klass)
|
||||
widget_class->focus_out_event = gtk_window_focus_out_event;
|
||||
widget_class->focus = gtk_window_focus;
|
||||
widget_class->move_focus = gtk_window_move_focus;
|
||||
widget_class->draw = gtk_window_draw;
|
||||
widget_class->window_state_event = gtk_window_state_event;
|
||||
widget_class->get_preferred_width = gtk_window_get_preferred_width;
|
||||
widget_class->get_preferred_width_for_height = gtk_window_get_preferred_width_for_height;
|
||||
@@ -706,6 +709,7 @@ gtk_window_class_init (GtkWindowClass *klass)
|
||||
widget_class->get_preferred_height_for_width = gtk_window_get_preferred_height_for_width;
|
||||
widget_class->state_flags_changed = gtk_window_state_flags_changed;
|
||||
widget_class->style_updated = gtk_window_style_updated;
|
||||
widget_class->get_render_node = gtk_window_get_render_node;
|
||||
|
||||
container_class->remove = gtk_window_remove;
|
||||
container_class->check_resize = gtk_window_check_resize;
|
||||
@@ -6886,6 +6890,12 @@ gtk_window_realize (GtkWidget *widget)
|
||||
|
||||
_gtk_widget_get_allocation (widget, &allocation);
|
||||
|
||||
if (priv->renderer == NULL)
|
||||
{
|
||||
priv->renderer = gsk_renderer_get_for_display (gtk_widget_get_display (widget));
|
||||
gsk_renderer_set_scale_factor (priv->renderer, gtk_widget_get_scale_factor (widget));
|
||||
}
|
||||
|
||||
if (gtk_widget_get_parent_window (widget))
|
||||
{
|
||||
attributes.x = allocation.x;
|
||||
@@ -6915,6 +6925,9 @@ gtk_window_realize (GtkWidget *widget)
|
||||
popover_realize (popover->widget, popover, window);
|
||||
}
|
||||
|
||||
gsk_renderer_set_window (priv->renderer, gdk_window);
|
||||
gsk_renderer_realize (priv->renderer);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -7002,6 +7015,9 @@ gtk_window_realize (GtkWidget *widget)
|
||||
gtk_widget_register_window (widget, gdk_window);
|
||||
gtk_widget_set_realized (widget, TRUE);
|
||||
|
||||
gsk_renderer_set_window (priv->renderer, gdk_window);
|
||||
gsk_renderer_realize (priv->renderer);
|
||||
|
||||
attributes.x = allocation.x;
|
||||
attributes.y = allocation.y;
|
||||
attributes.width = allocation.width;
|
||||
@@ -7125,6 +7141,9 @@ gtk_window_realize (GtkWidget *widget)
|
||||
}
|
||||
|
||||
check_scale_changed (window);
|
||||
|
||||
/* Renderer */
|
||||
gsk_renderer_realize (priv->renderer);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -7152,6 +7171,9 @@ gtk_window_unrealize (GtkWidget *widget)
|
||||
GList *link;
|
||||
gint i;
|
||||
|
||||
if (priv->renderer != NULL)
|
||||
gsk_renderer_unrealize (priv->renderer);
|
||||
|
||||
/* On unrealize, we reset the size of the window such
|
||||
* that we will re-apply the default sizing stuff
|
||||
* next time we show the window.
|
||||
@@ -7298,6 +7320,18 @@ _gtk_window_set_allocation (GtkWindow *window,
|
||||
child_allocation.width = allocation->width;
|
||||
child_allocation.height = allocation->height;
|
||||
|
||||
if (priv->renderer != NULL)
|
||||
{
|
||||
graphene_rect_t viewport;
|
||||
int scale;
|
||||
|
||||
scale = gtk_widget_get_scale_factor (widget);
|
||||
gsk_renderer_set_scale_factor (priv->renderer, scale);
|
||||
|
||||
graphene_rect_init (&viewport, 0, 0, allocation->width, allocation->height);
|
||||
gsk_renderer_set_viewport (priv->renderer, &viewport);
|
||||
}
|
||||
|
||||
get_shadow_width (window, &window_border);
|
||||
|
||||
if (_gtk_widget_get_realized (widget))
|
||||
@@ -9600,98 +9634,107 @@ gtk_window_compute_hints (GtkWindow *window,
|
||||
* Redrawing functions *
|
||||
***********************/
|
||||
|
||||
static gboolean
|
||||
gtk_window_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
static GskRenderNode *
|
||||
gtk_window_get_render_node (GtkWidget *widget,
|
||||
GskRenderer *renderer)
|
||||
{
|
||||
GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv;
|
||||
GtkStyleContext *context;
|
||||
gboolean ret = FALSE;
|
||||
GskRenderNode *node;
|
||||
GtkAllocation allocation;
|
||||
GtkBorder window_border;
|
||||
gint title_height;
|
||||
graphene_rect_t bounds;
|
||||
graphene_matrix_t m;
|
||||
graphene_point3d_t p;
|
||||
cairo_t *cr;
|
||||
|
||||
context = gtk_widget_get_style_context (widget);
|
||||
|
||||
get_shadow_width (GTK_WINDOW (widget), &window_border);
|
||||
_gtk_widget_get_allocation (widget, &allocation);
|
||||
|
||||
if (gtk_cairo_should_draw_window (cr, _gtk_widget_get_window (widget)))
|
||||
graphene_rect_init (&bounds, allocation.x, allocation.y, allocation.width, allocation.height);
|
||||
graphene_matrix_init_translate (&m, graphene_point3d_init (&p, allocation.x, allocation.y, 0.));
|
||||
|
||||
node = gsk_renderer_create_render_node (renderer);
|
||||
gsk_render_node_set_name (node, "Window Decoration");
|
||||
gsk_render_node_set_bounds (node, &bounds);
|
||||
gsk_render_node_set_transform (node, &m);
|
||||
|
||||
cr = gsk_render_node_get_draw_context (node);
|
||||
|
||||
if (priv->client_decorated &&
|
||||
priv->decorated &&
|
||||
!priv->fullscreen &&
|
||||
!priv->maximized)
|
||||
{
|
||||
if (priv->client_decorated &&
|
||||
priv->decorated &&
|
||||
!priv->fullscreen &&
|
||||
!priv->maximized)
|
||||
gtk_style_context_save_to_node (context, priv->decoration_node);
|
||||
|
||||
if (priv->use_client_shadow)
|
||||
{
|
||||
gtk_style_context_save_to_node (context, priv->decoration_node);
|
||||
GtkBorder padding, border;
|
||||
|
||||
if (priv->use_client_shadow)
|
||||
{
|
||||
GtkBorder padding, border;
|
||||
gtk_style_context_get_padding (context, &padding);
|
||||
gtk_style_context_get_border (context, &border);
|
||||
sum_borders (&border, &padding);
|
||||
|
||||
gtk_style_context_get_padding (context, &padding);
|
||||
gtk_style_context_get_border (context, &border);
|
||||
sum_borders (&border, &padding);
|
||||
|
||||
gtk_render_background (context, cr,
|
||||
window_border.left - border.left, window_border.top - border.top,
|
||||
allocation.width -
|
||||
(window_border.left + window_border.right - border.left - border.right),
|
||||
allocation.height -
|
||||
(window_border.top + window_border.bottom - border.top - border.bottom));
|
||||
gtk_render_frame (context, cr,
|
||||
window_border.left - border.left, window_border.top - border.top,
|
||||
allocation.width -
|
||||
(window_border.left + window_border.right - border.left - border.right),
|
||||
allocation.height -
|
||||
(window_border.top + window_border.bottom - border.top - border.bottom));
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_render_background (context, cr, 0, 0,
|
||||
allocation.width,
|
||||
allocation.height);
|
||||
|
||||
gtk_render_frame (context, cr, 0, 0,
|
||||
allocation.width,
|
||||
allocation.height);
|
||||
}
|
||||
|
||||
gtk_style_context_restore (context);
|
||||
gtk_render_background (context, cr,
|
||||
window_border.left - border.left, window_border.top - border.top,
|
||||
allocation.width -
|
||||
(window_border.left + window_border.right - border.left - border.right),
|
||||
allocation.height -
|
||||
(window_border.top + window_border.bottom - border.top - border.bottom));
|
||||
gtk_render_frame (context, cr,
|
||||
window_border.left - border.left, window_border.top - border.top,
|
||||
allocation.width -
|
||||
(window_border.left + window_border.right - border.left - border.right),
|
||||
allocation.height -
|
||||
(window_border.top + window_border.bottom - border.top - border.bottom));
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_app_paintable (widget))
|
||||
else
|
||||
{
|
||||
if (priv->title_box &&
|
||||
gtk_widget_get_visible (priv->title_box) &&
|
||||
gtk_widget_get_child_visible (priv->title_box))
|
||||
title_height = priv->title_height;
|
||||
else
|
||||
title_height = 0;
|
||||
gtk_render_background (context, cr, 0, 0,
|
||||
allocation.width,
|
||||
allocation.height);
|
||||
|
||||
gtk_render_background (context, cr,
|
||||
window_border.left,
|
||||
window_border.top + title_height,
|
||||
allocation.width -
|
||||
(window_border.left + window_border.right),
|
||||
allocation.height -
|
||||
(window_border.top + window_border.bottom +
|
||||
title_height));
|
||||
gtk_render_frame (context, cr,
|
||||
gtk_render_frame (context, cr, 0, 0,
|
||||
allocation.width,
|
||||
allocation.height);
|
||||
}
|
||||
gtk_style_context_restore (context);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_app_paintable (widget))
|
||||
{
|
||||
if (priv->title_box &&
|
||||
gtk_widget_get_visible (priv->title_box) &&
|
||||
gtk_widget_get_child_visible (priv->title_box))
|
||||
title_height = priv->title_height;
|
||||
else
|
||||
title_height = 0;
|
||||
|
||||
gtk_render_background (context, cr,
|
||||
window_border.left,
|
||||
window_border.top + title_height,
|
||||
allocation.width -
|
||||
(window_border.left + window_border.right),
|
||||
(window_border.left + window_border.right),
|
||||
allocation.height -
|
||||
(window_border.top + window_border.bottom +
|
||||
title_height));
|
||||
}
|
||||
(window_border.top + window_border.bottom + title_height));
|
||||
gtk_render_frame (context, cr,
|
||||
window_border.left,
|
||||
window_border.top + title_height,
|
||||
allocation.width -
|
||||
(window_border.left + window_border.right),
|
||||
allocation.height -
|
||||
(window_border.top + window_border.bottom + title_height));
|
||||
}
|
||||
|
||||
if (GTK_WIDGET_CLASS (gtk_window_parent_class)->draw)
|
||||
ret = GTK_WIDGET_CLASS (gtk_window_parent_class)->draw (widget, cr);
|
||||
cairo_destroy (cr);
|
||||
|
||||
return ret;
|
||||
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, node);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -11826,3 +11869,11 @@ gtk_window_unexport_handle (GtkWindow *window)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
GskRenderer *
|
||||
gtk_window_get_renderer (GtkWindow *window)
|
||||
{
|
||||
GtkWindowPrivate *priv = window->priv;
|
||||
|
||||
return priv->renderer;
|
||||
}
|
||||
|
||||
@@ -142,6 +142,8 @@ gboolean gtk_window_export_handle (GtkWindow *window,
|
||||
gpointer user_data);
|
||||
void gtk_window_unexport_handle (GtkWindow *window);
|
||||
|
||||
GskRenderer *gtk_window_get_renderer (GtkWindow *window);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_WINDOW_PRIVATE_H__ */
|
||||
|
||||
@@ -7,6 +7,8 @@ AM_CPPFLAGS = \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_builddir)/gdk \
|
||||
-I$(top_srcdir)/gdk \
|
||||
-I$(top_builddir)/gsk \
|
||||
-I$(top_srcdir)/gsk \
|
||||
$(GTK_DEBUG_FLAGS) \
|
||||
$(GTK_DEP_CFLAGS) \
|
||||
$(GDK_DEP_CFLAGS)
|
||||
@@ -16,6 +18,7 @@ DEPS = \
|
||||
|
||||
LDADD = \
|
||||
$(top_builddir)/gtk/libgtk-4.la \
|
||||
$(top_builddir)/gsk/libgsk-4.la \
|
||||
$(top_builddir)/gdk/libgdk-4.la \
|
||||
$(GTK_DEP_LIBS) \
|
||||
$(GDK_DEP_LIBS) \
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
include $(top_srcdir)/Makefile.decl
|
||||
|
||||
SUBDIRS = gdk gtk a11y css reftests tools
|
||||
SUBDIRS = gdk gsk gtk a11y css reftests tools
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
include $(top_srcdir)/Makefile.decl
|
||||
|
||||
NULL=
|
||||
|
||||
noinst_PROGRAMS = $(TEST_PROGS)
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_builddir)/gdk \
|
||||
-I$(top_srcdir)/gdk \
|
||||
-I$(top_builddir)/gsk \
|
||||
-I$(top_srcdir)/gsk \
|
||||
$(GTK_DEBUG_FLAGS) \
|
||||
$(GTK_DEP_CFLAGS)
|
||||
|
||||
LDADD = $(GTK_DEP_LIBS) $(top_builddir)/gsk/libgsk-4.la
|
||||
|
||||
TEST_PROGS += \
|
||||
$(NULL)
|
||||
|
||||
if BUILDOPT_INSTALL_TESTS
|
||||
insttestdir=$(pkglibexecdir)/installed-tests
|
||||
insttest_PROGRAMS = $(TEST_PROGS)
|
||||
|
||||
%.test: %$(EXEEXT) Makefile
|
||||
$(AM_V_GEN) (echo '[Test]' > $@.tmp; \
|
||||
echo 'Type=session' >> $@.tmp; \
|
||||
echo 'Exec=$(insttestdir)/$<' >> $@.tmp; \
|
||||
mv $@.tmp $@)
|
||||
|
||||
test_files = $(TEST_PROGRS:=.test)
|
||||
|
||||
DISTCLEANFILES = $(test_files)
|
||||
|
||||
testmetadir = $(datadir)/installed-tests/$(PACKAGE)
|
||||
testmeta_DATA = $(test_files)
|
||||
endif
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
||||
Reference in New Issue
Block a user