Compare commits

..

76 Commits

Author SHA1 Message Date
Matthias Clasen 406a32d825 Fix the build 2023-02-12 16:31:40 -05:00
Matthias Clasen beabe8c33b gsk: Drop an unnecessary call
The renderer should make all the necessary
make_current calls.
2023-02-12 15:12:43 -05:00
Matthias Clasen 90500519d6 gst: Add a comment about context confusion 2023-02-12 15:12:43 -05:00
Matthias Clasen 06921674a9 gsk: Only wait if we need to
If the texture was created in the same context
we are using it in, then waiting on the sync
will be a no-op.
2023-02-12 15:12:43 -05:00
Matthias Clasen a91fa9a680 gltexture: Only wait if we need to
If the texture was created in the same context
we are downloading it from, then waiting on the
sync will be a no-op.
2023-02-12 15:12:43 -05:00
Matthias Clasen ead40dc834 gldriver: Add a sync when creating textures 2023-02-12 15:12:43 -05:00
Matthias Clasen 2be928b569 gstreamer: Defer the sync
Don't sync right when we receive the buffer,
pass it along with the texture to be executed
later in the renderer.
2023-02-12 15:12:43 -05:00
Matthias Clasen 621ba6d67c Export gdk_gl_texture_new_with_sync
Otherwise we can't use it in the loadable modules,
like the GStreamer media stream.

This change puts gdk_gl_texture_new_with_sync into
the private, but exported bucket for now. We will
make new public APIs for textures (including
synchronization) when we add color management support.
2023-02-12 15:12:43 -05:00
Matthias Clasen af929a8787 glarea: Synchronize
Create a fence object and pass it along when
creating the GL texture, so that the GL renderer
can wait for the texture to be ready.
2023-02-12 15:12:43 -05:00
Matthias Clasen ef986f4256 gsk: Synchronize when using textures
Pass the GLsync object from texture into our
command queue, and when executing the queue,
wait on the sync object the first time we
use its associated texture.
2023-02-12 15:12:41 -05:00
Matthias Clasen ab36c275cf gltexture: Synchronize when downloading
If the GL texture has a sync object, wait
on it before downloading the data.
2023-02-12 15:09:21 -05:00
Matthias Clasen 720327bc00 gltexture: Optionally take a sync object
Add a new (private, for now) constructor takes
a GLsync together with a texture id, for synchronization.
2023-02-12 15:09:21 -05:00
Matthias Clasen 679d510059 Merge branch 'template-child-dispose-order' into 'main'
gtk: Set widget template children to NULL before destroy unref

See merge request GNOME/gtk!4611
2023-02-12 16:36:52 +00:00
Matthias Clasen 0c2b437643 Merge branch 'main' into 'main'
Add note about widgets implementing the interface adding the `horizontal`/`vertical` CSS classes

See merge request GNOME/gtk!5391
2023-02-12 16:28:12 +00:00
madmurphy 0764cf0c9c Add note about widgets implementing the interface adding the horizontal/vertical CSS classes 2023-02-12 16:28:12 +00:00
Matthias Clasen 557a1ed879 Merge branch 'no-more-lpr' into 'main'
printing: Drop the lpr backend

See merge request GNOME/gtk!5500
2023-02-12 15:29:27 +00:00
Matthias Clasen c28b6a3ee6 Merge branch 'texture-atlas-crash' into 'main'
gl: Avoid a crash in the texture library

Closes #5175

See merge request GNOME/gtk!5501
2023-02-12 15:28:06 +00:00
Matthias Clasen dd22e2aea9 printing: Drop the lpr backend
We want to consolidate and get to fewer print
backends (ideally only one), and the future is cpdb.
2023-02-12 10:10:06 -05:00
Matthias Clasen 7f3ea15d80 Update POTFILES.in 2023-02-12 10:09:22 -05:00
Matthias Clasen d3dfdd214f gl: Avoid a crash in the texture library
entry->texture can be NULL, so check before
using it.

Fixes: #5175
2023-02-12 10:01:11 -05:00
Matthias Clasen b6c3cf4eee gl: Maintain state when truncating
When we truncate the command queue because it
is too big, we were messing up our state accounting
and running into criticals as a consequence.

This can be reproduced by opening a well-populated
fishbowl demo in the inspectors recorder.

Fixes: #5188
2023-02-12 09:56:32 -05:00
Matthias Clasen 157ef1d395 Deprecate GtkVolumeButton
Too specialized.
2023-02-12 09:48:49 -05:00
Matthias Clasen d0263f563a NEWS: Updates 2023-02-12 09:21:38 -05:00
Matthias Clasen 83b48bb25f Merge branch 'mask-nodes-rebased' into 'main'
gsk: Introduce mask nodes

See merge request GNOME/gtk!5497
2023-02-12 14:11:47 +00:00
Matthias Clasen 81e9eca256 Merge branch 'nacho/scalebutton-active' into 'main'
gtkscalebutton: add active property

See merge request GNOME/gtk!5492
2023-02-12 14:01:27 +00:00
Ignacio Casal Quinteiro 44c2d585b8 gtkscalebutton: add active property 2023-02-12 14:01:26 +00:00
Matthias Clasen 348803af7d Add a mask node demo 2023-02-12 08:35:25 -05:00
Matthias Clasen c8bfea7aa1 Add a test for mask nodes 2023-02-12 08:35:25 -05:00
Matthias Clasen 8f47e885f0 Add gtk_snapshot_push_mask 2023-02-12 08:35:25 -05:00
Matthias Clasen a9f50f1f7a gl: Support mask nodes
Add a shader for masking.
2023-02-12 08:35:25 -05:00
Matthias Clasen 0d58e5365d gsk: Introduce mask nodes
Add GskMaskNode, and support it in the render node
parser, in the inspector and in GtkSnapshot.

The rendering is just fallback for now.

Based on old work by Timm Bäder.
2023-02-12 08:35:25 -05:00
Ekaterine Papava d00d4c4475 Update Georgian translation 2023-02-12 12:30:05 +00:00
Piotr Drąg a6e7c38236 Update POTFILES.in 2023-02-12 13:20:48 +01:00
Matthias Clasen eee7e59265 Merge branch 'fix_editable_label' into 'main'
Remove timeout when disposing GtkEditableLabel

Closes #5584

See merge request GNOME/gtk!5499
2023-02-12 02:55:45 +00:00
Matthias Clasen c2cb1ffe9e Merge branch 'wip/wl-dispatch-helper' into 'main'
wayland: Add event queue dispatch helper

See merge request GNOME/gtk!5498
2023-02-12 01:01:29 +00:00
Alexandros Theodotou d918a77d34 Remove timeout when disposing GtkEditableLabel
Fixes: #5584
2023-02-12 09:45:07 +09:00
Matthias Clasen 2285ef3824 Merge branch 'scaled-textures' into 'main'
Scaled textures

See merge request GNOME/gtk!5488
2023-02-11 22:16:43 +00:00
Jonas Ådahl b2a2bf819d wayland/launch-context: Use dispatch helper
Otherwise we risk a busy loop if e.g. the pipe broke.
2023-02-11 23:14:53 +01:00
Jonas Ådahl dd9433b50e wayland: Add event queue dispatch helper
Dispatch failing should always fatal; use a helper to centralize the
error handling everywhere.
2023-02-11 23:13:39 +01:00
Matthias Clasen 67c53e46f9 Add gtk_snapshot_append_scaled_texture
This is the snapshot api corresponding to
gsk_texture_scale_node_new.
2023-02-11 15:09:38 -05:00
Matthias Clasen 238e7ec351 Add a test for scaled textures 2023-02-11 15:09:38 -05:00
Matthias Clasen d916659781 gl: Handle GskTextureScaleNodes 2023-02-11 15:09:38 -05:00
Matthias Clasen 82c02574f1 gl: Make texture slicing more flexible
Allow to specify the filtering to use for the slices,
and allow forcing the number of slices. This will be
used in the next commit.
2023-02-11 15:09:38 -05:00
Matthias Clasen 26e6d2106b gl: Pass filters down from visit_texture_node
For now, we always pass GL_LINEAR.
2023-02-11 15:09:38 -05:00
Matthias Clasen 625ffa2d96 gtk-demo: Add filtering to the zoom demo 2023-02-11 15:09:38 -05:00
Matthias Clasen dd3eedd510 gtk-demo: Rewrite the zoom demo slightly
Use a texture directly instead of a paintable.
This will be used in the following commit to
introduce filters.
2023-02-11 15:09:38 -05:00
Matthias Clasen dc3a72cf38 nodeparser: Support texture-scale nodes 2023-02-11 15:09:38 -05:00
Matthias Clasen b937c19dd4 gsk: Introduce GskTextureScaleNode 2023-02-11 15:09:38 -05:00
Matthias Clasen 04c3af537c Merge branch 'wip/handle-more-wl-dispatch-failures' into 'main'
wayland: Handle dispatch failing in a couple of more places

See merge request GNOME/gtk!5495
2023-02-11 19:56:45 +00:00
Matthias Clasen cc43f5dcde gsk: Generate mipmaps when requested
If the min_filter requires it, call
glGenerateMipmap for our textures.
2023-02-11 09:29:03 -05:00
Matthias Clasen c74d7afce5 gsk: Don't limit filters too much
GL does not allow mipmapping for mag filters,
but it doesn't have a problem with it for min
filters.
2023-02-11 09:29:03 -05:00
Matthias Clasen 52e18eb7fb Merge branch 'matthiasc/for-main' into 'main'
gdkevents.c: Fix up folding

See merge request GNOME/gtk!5496
2023-02-11 14:18:42 +00:00
Matthias Clasen c0b5b4b8c1 gskrendernodeimpl.c: Use folding
Instead of homegrown markup.
2023-02-11 09:00:07 -05:00
Matthias Clasen d497e721c9 gdkevents.c: Fix up folding
The modeline was lost at some point,
and superfluous spacing inserted.
2023-02-11 08:59:51 -05:00
Jonas Ådahl a7fb9a6865 wayland: Handle dispatch failing in a couple of more places
Without doing this, we'll end up with risking GTK processes sitting
eating 100% CPU instead of just exit(1):ing.
2023-02-11 11:42:21 +01:00
Marek Kašík 2365d9be18 Merge branch 'cpdb' into 'main'
New CPDB print backend for GTK Print Dialog

See merge request GNOME/gtk!4930
2023-02-10 23:10:20 +00:00
tinytrebuchet 41b60bbd6c New CPDB print backend for GTK Print Dialog
The Common Print Dialog Backends (CPDB) concept has GUI-toolkit-independent
backends for each print technology (CUPS, Print to File, cloud printing
services, ...) and each print dialog (GTK, Qt, Chromium, ...) is supposed
to use this backend, so that changes in print technologies can be centrally
and quickly covered by changing the backends and everything new gets available
in all print dialogs.

This commit provides a GTK print dialog backend to add support for the CPDB
concept. It communicates with all installed CPDB backends and so gives support
for all these print technologies to the GTK print dialog.

To make use of CPDB the GTK print dialog is supposed to be installed with this
backend and the 'Print To File' backend, and not any others to prevent printer
duplication.
2023-02-11 01:13:48 +05:30
Emin Tufan Çetin f0d3d011ea Update Turkish translation 2023-02-10 05:57:42 +00:00
Matthias Clasen 48e141a42c Merge branch 'avoid-criticals-tracker' into 'main'
searchengine: Avoid criticals when tracker init failed

See merge request GNOME/gtk!5489
2023-02-09 19:43:31 +00:00
Gaël Bonithon 6215b38e64 searchengine: Emit a simple warning when tracker init failed
Failure is allowed by nature of GInitable, and this avoids unnecessary
crashing of programs running with G_DEBUG=fatal-criticals.
2023-02-09 19:46:30 +01:00
Gaël Bonithon 41490f9624 searchengine: Add missing sanity check 2023-02-09 19:25:04 +01:00
Vasil Pupkin 45e6e9a7d1 Update Belarusian translation 2023-02-08 21:48:28 +00:00
Matthias Clasen 9991d6834d Merge branch 'stop-testing-pixbuf-formats' into 'main'
Drop pixbuf format tests

See merge request GNOME/gtk!5486
2023-02-07 18:48:39 +00:00
Matthias Clasen ddf8c4dd1a Drop pixbuf format tests
We have our own loaders for the formats we
always want to support, so we don't need to
check for what gdk-pixbuf supports.
2023-02-07 07:54:22 -05:00
Matthias Clasen 970072ef65 Merge branch 'file-dialog-fixes' into 'main'
filedialog: Robustness fixes

See merge request GNOME/gtk!5485
2023-02-07 12:42:09 +00:00
Matthias Clasen f8321029fc filedialog: Robustness fixes
This code was not working well.
2023-02-06 23:16:17 +01:00
Matthias Clasen f83cab01ec filechooserportal: Fix an oversight 2023-02-06 20:28:35 +01:00
Sabri Ünal 8a74770ec1 Update Turkish translation 2023-02-06 09:19:35 +00:00
Matthias Clasen 39c503c108 Merge branch 'matthiasc/for-main' into 'main'
CONTRIBUTING: Updates

See merge request GNOME/gtk!5483
2023-02-06 06:53:14 +00:00
Matthias Clasen fc32b8242b CONTRIBUTING: Updates
Mention matrix instead of irc, and ask
for display/graphics as essential info
in issues.
2023-02-06 07:35:11 +01:00
Piotr Drąg 7c2b4eb0e7 Update Polish translation 2023-02-05 15:22:00 +01:00
Matthias Clasen d8b0aea6b7 Merge branch 'rename-openuri-portal' into 'main'
Use a Gtk prefix for dbus-generated code

Closes #5572

See merge request GNOME/gtk!5482
2023-02-05 08:27:09 +00:00
Matthias Clasen 190d8ef8ff Use a Gtk prefix for dbus-generated code
Copying this file from GIO without renaming it
was not the greatest idea in retrospect.

Fixes: #5572
2023-02-05 09:09:22 +01:00
Cheng-Chia Tseng 15e9194b59 Update Chinese (Taiwan) translation 2023-02-04 16:28:15 +00:00
Matthias Clasen 0257da6cc0 Post-release version bump 2023-02-04 17:01:51 +01:00
Jason Francis 3fc7c97979 gtk: Set widget template children to NULL before destroy unref 2022-05-14 10:13:39 -04:00
87 changed files with 10083 additions and 9694 deletions
+2 -1
View File
@@ -21,7 +21,7 @@ many things that we value:
Please, do not use the issue tracker for support questions. If you have
questions on how to use GTK effectively, you can use:
- the `#gtk` IRC channel on irc.gnome.org
- the `gtk` [room on matrix](https://matrix.to/#/#gtk:gnome.org)
- the [gtk tag on the GNOME Discourse instance](https://discourse.gnome.org/tag/gtk)
You can also look at the GTK tag on [Stack
@@ -44,6 +44,7 @@ If you're reporting a bug make sure to list:
0. which version of GTK are you using?
0. which operating system are you using?
0. what display and graphics driver are you using?
0. the necessary steps to reproduce the issue
0. the expected outcome
0. a description of the behavior; screenshots are also welcome
+28
View File
@@ -1,3 +1,31 @@
Overview of Changes in 4.9.4, xx-xx-xxxx
========================================
* Printing:
- Add a CPDB print backend
* GtkFileDialog:
- Robustness fixes
* GtkScaleButton:
- Add an 'active' property
* Fix conflicting type names between gtk and gio
* Gsk:
- Settable filtering for scaled textures
- Add mask nodes
* Wayland:
- Handle dispatch failing in more places
* Translation updates:
Belarusian
Chinese (Taiwan)
Georgian
Turkish
Overview of Changes in 4.9.3, 04-02-2023
========================================
+7
View File
@@ -215,6 +215,12 @@
<file>demo3widget.h</file>
<file>demo3widget.ui</file>
</gresource>
<gresource prefix="/mask">
<file>demo4widget.c</file>
<file>demo4widget.h</file>
<file>hsla.h</file>
<file>hsla.c</file>
</gresource>
<gresource prefix="/paintable_svg">
<file>svgpaintable.h</file>
<file>svgpaintable.c</file>
@@ -311,6 +317,7 @@
<file>list_store.c</file>
<file>main.c</file>
<file>markup.c</file>
<file>mask.c</file>
<file>menu.c</file>
<file>overlay.c</file>
<file>overlay_decorative.c</file>
+43 -24
View File
@@ -3,7 +3,8 @@
enum
{
PROP_PAINTABLE = 1,
PROP_TEXTURE = 1,
PROP_FILTER,
PROP_SCALE
};
@@ -11,8 +12,9 @@ struct _Demo3Widget
{
GtkWidget parent_instance;
GdkPaintable *paintable;
GdkTexture *texture;
float scale;
GskScalingFilter filter;
GtkWidget *menu;
};
@@ -28,6 +30,7 @@ static void
demo3_widget_init (Demo3Widget *self)
{
self->scale = 1.f;
self->filter = GSK_SCALING_FILTER_LINEAR;
gtk_widget_init_template (GTK_WIDGET (self));
}
@@ -36,7 +39,7 @@ demo3_widget_dispose (GObject *object)
{
Demo3Widget *self = DEMO3_WIDGET (object);
g_clear_object (&self->paintable);
g_clear_object (&self->texture);
gtk_widget_dispose_template (GTK_WIDGET (self), DEMO3_TYPE_WIDGET);
@@ -50,12 +53,13 @@ demo3_widget_snapshot (GtkWidget *widget,
Demo3Widget *self = DEMO3_WIDGET (widget);
int x, y, width, height;
double w, h;
GskRenderNode *node;
width = gtk_widget_get_width (widget);
height = gtk_widget_get_height (widget);
w = self->scale * gdk_paintable_get_intrinsic_width (self->paintable);
h = self->scale * gdk_paintable_get_intrinsic_height (self->paintable);
w = self->scale * gdk_texture_get_width (self->texture);
h = self->scale * gdk_texture_get_height (self->texture);
x = MAX (0, (width - ceil (w)) / 2);
y = MAX (0, (height - ceil (h)) / 2);
@@ -63,7 +67,11 @@ demo3_widget_snapshot (GtkWidget *widget,
gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_save (snapshot);
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (x, y));
gdk_paintable_snapshot (self->paintable, snapshot, w, h);
node = gsk_texture_scale_node_new (self->texture,
&GRAPHENE_RECT_INIT (0, 0, w, h),
self->filter);
gtk_snapshot_append_node (snapshot, node);
gsk_render_node_unref (node);
gtk_snapshot_restore (snapshot);
gtk_snapshot_pop (snapshot);
}
@@ -81,9 +89,9 @@ demo3_widget_measure (GtkWidget *widget,
int size;
if (orientation == GTK_ORIENTATION_HORIZONTAL)
size = gdk_paintable_get_intrinsic_width (self->paintable);
size = gdk_texture_get_width (self->texture);
else
size = gdk_paintable_get_intrinsic_height (self->paintable);
size = gdk_texture_get_height (self->texture);
*minimum = *natural = self->scale * size;
}
@@ -113,9 +121,9 @@ demo3_widget_set_property (GObject *object,
switch (prop_id)
{
case PROP_PAINTABLE:
g_clear_object (&self->paintable);
self->paintable = g_value_dup_object (value);
case PROP_TEXTURE:
g_clear_object (&self->texture);
self->texture = g_value_dup_object (value);
gtk_widget_queue_resize (GTK_WIDGET (object));
break;
@@ -124,6 +132,11 @@ demo3_widget_set_property (GObject *object,
gtk_widget_queue_resize (GTK_WIDGET (object));
break;
case PROP_FILTER:
self->filter = g_value_get_enum (value);
gtk_widget_queue_resize (GTK_WIDGET (object));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -140,14 +153,18 @@ demo3_widget_get_property (GObject *object,
switch (prop_id)
{
case PROP_PAINTABLE:
g_value_set_object (value, self->paintable);
case PROP_TEXTURE:
g_value_set_object (value, self->texture);
break;
case PROP_SCALE:
g_value_set_float (value, self->scale);
break;
case PROP_FILTER:
g_value_set_enum (value, self->filter);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -205,16 +222,21 @@ demo3_widget_class_init (Demo3WidgetClass *class)
widget_class->measure = demo3_widget_measure;
widget_class->size_allocate = demo3_widget_size_allocate;
g_object_class_install_property (object_class, PROP_PAINTABLE,
g_param_spec_object ("paintable", "Paintable", "Paintable",
GDK_TYPE_PAINTABLE,
g_object_class_install_property (object_class, PROP_TEXTURE,
g_param_spec_object ("texture", NULL, NULL,
GDK_TYPE_TEXTURE,
G_PARAM_READWRITE));
g_object_class_install_property (object_class, PROP_SCALE,
g_param_spec_float ("scale", "Scale", "Scale",
g_param_spec_float ("scale", NULL, NULL,
0.0, 10.0, 1.0,
G_PARAM_READWRITE));
g_object_class_install_property (object_class, PROP_FILTER,
g_param_spec_enum ("filter", NULL, NULL,
GSK_TYPE_SCALING_FILTER, GSK_SCALING_FILTER_LINEAR,
G_PARAM_READWRITE));
/* These are the actions that we are using in the menu */
gtk_widget_class_install_action (widget_class, "zoom.in", NULL, zoom_cb);
gtk_widget_class_install_action (widget_class, "zoom.out", NULL, zoom_cb);
@@ -229,16 +251,13 @@ GtkWidget *
demo3_widget_new (const char *resource)
{
Demo3Widget *self;
GdkPixbuf *pixbuf;
GdkPaintable *paintable;
GdkTexture *texture;
pixbuf = gdk_pixbuf_new_from_resource (resource, NULL);
paintable = GDK_PAINTABLE (gdk_texture_new_for_pixbuf (pixbuf));
texture = gdk_texture_new_from_resource (resource);
self = g_object_new (DEMO3_TYPE_WIDGET, "paintable", paintable, NULL);
self = g_object_new (DEMO3_TYPE_WIDGET, "texture", texture, NULL);
g_object_unref (pixbuf);
g_object_unref (paintable);
g_object_unref (texture);
return GTK_WIDGET (self);
}
+123
View File
@@ -0,0 +1,123 @@
#include <math.h>
#include "demo4widget.h"
#include "hsla.h"
struct _Demo4Widget
{
GtkWidget parent_instance;
PangoLayout *layout;
GskColorStop stops[8];
gsize n_stops;
guint tick;
};
struct _Demo4WidgetClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE (Demo4Widget, demo4_widget, GTK_TYPE_WIDGET)
static void
rotate_color (GdkRGBA *rgba)
{
GdkHSLA hsla;
_gdk_hsla_init_from_rgba (&hsla, rgba);
hsla.hue -= 1;
_gdk_rgba_init_from_hsla (rgba, &hsla);
}
static gboolean
rotate_colors (GtkWidget *widget,
GdkFrameClock *clock,
gpointer user_data)
{
Demo4Widget *self = DEMO4_WIDGET (widget);
for (unsigned int i = 0; i < self->n_stops; i++)
rotate_color (&self->stops[i].color);
gtk_widget_queue_draw (widget);
return G_SOURCE_CONTINUE;
}
static void
demo4_widget_init (Demo4Widget *self)
{
PangoFontDescription *desc;
self->n_stops = 8;
self->stops[0].offset = 0;
self->stops[0].color = (GdkRGBA) { 1, 0, 0, 1 };
for (unsigned int i = 1; i < self->n_stops; i++)
{
GdkHSLA hsla;
self->stops[i].offset = i / (double)(self->n_stops - 1);
_gdk_hsla_init_from_rgba (&hsla, &self->stops[i - 1].color);
hsla.hue += 360.0 / (double)(self->n_stops - 1);
_gdk_rgba_init_from_hsla (&self->stops[i].color, &hsla);
}
self->layout = gtk_widget_create_pango_layout (GTK_WIDGET (self), "123");
desc = pango_font_description_from_string ("Cantarell Bold 210");
pango_layout_set_font_description (self->layout, desc);
pango_font_description_free (desc);
self->tick = gtk_widget_add_tick_callback (GTK_WIDGET (self), rotate_colors, NULL, NULL);
}
static void
demo4_widget_dispose (GObject *object)
{
Demo4Widget *self = DEMO4_WIDGET (object);
g_clear_object (&self->layout);
gtk_widget_remove_tick_callback (GTK_WIDGET (self), self->tick);
G_OBJECT_CLASS (demo4_widget_parent_class)->dispose (object);
}
static void
demo4_widget_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
Demo4Widget *self = DEMO4_WIDGET (widget);
int width, height;
width = gtk_widget_get_width (widget);
height = gtk_widget_get_height (widget);
gtk_snapshot_push_mask (snapshot);
gtk_snapshot_append_layout (snapshot, self->layout, &(GdkRGBA) { 0, 0, 0, 1 });
gtk_snapshot_pop (snapshot);
gtk_snapshot_append_linear_gradient (snapshot,
&GRAPHENE_RECT_INIT (0, 0, width, height),
&GRAPHENE_POINT_INIT (0, 0),
&GRAPHENE_POINT_INIT (width, height),
self->stops,
self->n_stops);
gtk_snapshot_pop (snapshot);
}
static void
demo4_widget_class_init (Demo4WidgetClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->dispose = demo4_widget_dispose;
widget_class->snapshot = demo4_widget_snapshot;
}
GtkWidget *
demo4_widget_new (void)
{
return g_object_new (DEMO4_TYPE_WIDGET, NULL);
}
+8
View File
@@ -0,0 +1,8 @@
#pragma once
#include <gtk/gtk.h>
#define DEMO4_TYPE_WIDGET (demo4_widget_get_type ())
G_DECLARE_FINAL_TYPE (Demo4Widget, demo4_widget, DEMO4, WIDGET, GtkWidget)
GtkWidget * demo4_widget_new (void);
+146
View File
@@ -0,0 +1,146 @@
#include <gdk/gdk.h>
#include "hsla.h"
void
_gdk_hsla_init_from_rgba (GdkHSLA *hsla,
const GdkRGBA *rgba)
{
float min;
float max;
float red;
float green;
float blue;
float delta;
g_return_if_fail (hsla != NULL);
g_return_if_fail (rgba != NULL);
red = rgba->red;
green = rgba->green;
blue = rgba->blue;
if (red > green)
{
if (red > blue)
max = red;
else
max = blue;
if (green < blue)
min = green;
else
min = blue;
}
else
{
if (green > blue)
max = green;
else
max = blue;
if (red < blue)
min = red;
else
min = blue;
}
hsla->lightness = (max + min) / 2;
hsla->saturation = 0;
hsla->hue = 0;
hsla->alpha = rgba->alpha;
if (max != min)
{
if (hsla->lightness <= 0.5)
hsla->saturation = (max - min) / (max + min);
else
hsla->saturation = (max - min) / (2 - max - min);
delta = max -min;
if (red == max)
hsla->hue = (green - blue) / delta;
else if (green == max)
hsla->hue = 2 + (blue - red) / delta;
else if (blue == max)
hsla->hue = 4 + (red - green) / delta;
hsla->hue *= 60;
if (hsla->hue < 0.0)
hsla->hue += 360;
}
}
void
_gdk_rgba_init_from_hsla (GdkRGBA *rgba,
const GdkHSLA *hsla)
{
float hue;
float lightness;
float saturation;
float m1, m2;
lightness = hsla->lightness;
saturation = hsla->saturation;
if (lightness <= 0.5)
m2 = lightness * (1 + saturation);
else
m2 = lightness + saturation - lightness * saturation;
m1 = 2 * lightness - m2;
rgba->alpha = hsla->alpha;
if (saturation == 0)
{
rgba->red = lightness;
rgba->green = lightness;
rgba->blue = lightness;
}
else
{
hue = hsla->hue + 120;
while (hue > 360)
hue -= 360;
while (hue < 0)
hue += 360;
if (hue < 60)
rgba->red = m1 + (m2 - m1) * hue / 60;
else if (hue < 180)
rgba->red = m2;
else if (hue < 240)
rgba->red = m1 + (m2 - m1) * (240 - hue) / 60;
else
rgba->red = m1;
hue = hsla->hue;
while (hue > 360)
hue -= 360;
while (hue < 0)
hue += 360;
if (hue < 60)
rgba->green = m1 + (m2 - m1) * hue / 60;
else if (hue < 180)
rgba->green = m2;
else if (hue < 240)
rgba->green = m1 + (m2 - m1) * (240 - hue) / 60;
else
rgba->green = m1;
hue = hsla->hue - 120;
while (hue > 360)
hue -= 360;
while (hue < 0)
hue += 360;
if (hue < 60)
rgba->blue = m1 + (m2 - m1) * hue / 60;
else if (hue < 180)
rgba->blue = m2;
else if (hue < 240)
rgba->blue = m1 + (m2 - m1) * (240 - hue) / 60;
else
rgba->blue = m1;
}
}
+15
View File
@@ -0,0 +1,15 @@
#pragma once
typedef struct _GdkHSLA GdkHSLA;
struct _GdkHSLA {
float hue;
float saturation;
float lightness;
float alpha;
};
void _gdk_hsla_init_from_rgba (GdkHSLA *hsla,
const GdkRGBA *rgba);
void _gdk_rgba_init_from_hsla (GdkRGBA *rgba,
const GdkHSLA *hsla);
+46
View File
@@ -0,0 +1,46 @@
/* Masking
*
* Demonstrates mask nodes.
*
* This demo uses a text node as mask for
* an animated linear gradient.
*/
#include <gtk/gtk.h>
#include "demo4widget.h"
GtkWidget *
do_mask (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
if (!window)
{
GtkWidget *box;
GtkWidget *widget;
window = gtk_window_new ();
gtk_window_set_title (GTK_WINDOW (window), "Mask Nodes");
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_window_set_child (GTK_WINDOW (window), box);
widget = demo4_widget_new ();
gtk_widget_set_hexpand (widget, TRUE);
gtk_widget_set_vexpand (widget, TRUE);
gtk_box_append (GTK_BOX (box), widget);
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}
+12 -1
View File
@@ -22,9 +22,11 @@ do_menu (GtkWidget *do_widget)
if (!window)
{
GtkWidget *box;
GtkWidget *box2;
GtkWidget *sw;
GtkWidget *widget;
GtkWidget *scale;
GtkWidget *dropdown;
window = gtk_window_new ();
gtk_window_set_title (GTK_WINDOW (window), "Menu");
@@ -43,10 +45,19 @@ do_menu (GtkWidget *do_widget)
widget = demo3_widget_new ("/transparent/portland-rose.jpg");
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), widget);
box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_append (GTK_BOX (box), box2);
scale = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 0.01, 10.0, 0.1);
gtk_range_set_value (GTK_RANGE (scale), 1.0);
gtk_box_append (GTK_BOX (box), scale);
gtk_widget_set_hexpand (scale, TRUE);
gtk_box_append (GTK_BOX (box2), scale);
dropdown = gtk_drop_down_new (G_LIST_MODEL (gtk_string_list_new ((const char *[]){ "Linear", "Nearest", "Trilinear", NULL })), NULL);
gtk_box_append (GTK_BOX (box2), dropdown);
g_object_bind_property (dropdown, "selected", widget, "filter", G_BINDING_DEFAULT);
g_object_bind_property (gtk_range_get_adjustment (GTK_RANGE (scale)), "value",
widget, "scale",
G_BINDING_BIDIRECTIONAL);
+3
View File
@@ -46,6 +46,7 @@ demos = files([
'links.c',
'listbox.c',
'listbox_controls.c',
'mask.c',
'menu.c',
'flowbox.c',
'list_store.c',
@@ -114,6 +115,7 @@ extra_demo_sources = files([
'gtkshadertoy.c',
'gtkshaderstack.c',
'gskshaderpaintable.c',
'hsla.c',
'puzzlepiece.c',
'bluroverlay.c',
'demoimage.c',
@@ -126,6 +128,7 @@ extra_demo_sources = files([
'four_point_transform.c',
'demo2widget.c',
'demo3widget.c',
'demo4widget.c',
'pixbufpaintable.c',
'script-names.c',
'unicode-names.c',
+15
View File
@@ -297,6 +297,21 @@ The default texture is a 10x10 checkerboard with the top left and bottom right
representation for this texture is `url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABmJLR0QA/wD/AP+gvaeTAAAAKUlEQVQYlWP8z3DmPwMaYGQwYUQXY0IXwAUGUCGGoxkYGBiweXAoeAYAz44F3e3U1xUAAAAASUVORK5CYII=")
`.
### texture-scale
| property | syntax | default | printed |
| -------- | ---------------- | ---------------------- | ----------- |
| bounds | `<rect>` | 50 | always |
| texture | `<url>` | *see below* | always |
| filter | `filter` | *see below* | non-default |
Creates a node like `gsk_texture_scale_node_new()` with the given properties.
The default texture is a 10x10 checkerboard, just like for texture.
The possible filter values are `linear`, `nearest` and `trilinear`, with
`linear` being the default.
### transform
| property | syntax | default | printed |
+3 -3
View File
@@ -115,7 +115,7 @@ Instead of gtk_show_uri(), you should use GtkUriLauncher or GtkFileLauncher.
This is an oldfashioned widget that does not do all that much anymore, since
it no longer has a resize handle for the window.
## GtkLockButton is going away
## GtkLockButton and GtkVolumeButton are going away
This is an very specialized widget that should better live with the application
where it is used.
These are very specialized widgets that should better live with the application
where they are used.
+2 -12
View File
@@ -1511,7 +1511,6 @@ gdk_button_event_get_button (GdkEvent *event)
}
/* }}} */
/* {{{ GdkKeyEvent */
/**
@@ -1972,7 +1971,6 @@ gdk_key_event_get_match (GdkEvent *event,
}
/* }}} */
/* {{{ GdkTouchEvent */
/**
@@ -2109,7 +2107,6 @@ gdk_touch_event_get_emulating_pointer (GdkEvent *event)
}
/* }}} */
/* {{{ GdkCrossingEvent */
/**
@@ -2253,7 +2250,6 @@ gdk_crossing_event_get_detail (GdkEvent *event)
}
/* }}} */
/* {{{ GdkDeleteEvent */
/**
@@ -2284,7 +2280,6 @@ gdk_delete_event_new (GdkSurface *surface)
}
/* }}} */
/* {{{ GdkFocusEvent */
/**
@@ -2341,7 +2336,6 @@ gdk_focus_event_get_in (GdkEvent *event)
}
/* }}} */
/* {{{ GdkScrollEvent */
/**
@@ -2600,7 +2594,6 @@ gdk_scroll_event_get_unit (GdkEvent *event)
}
/* }}} */
/* {{{ GdkTouchpadEvent */
/**
@@ -2859,7 +2852,6 @@ gdk_touchpad_event_get_pinch_scale (GdkEvent *event)
}
/* }}} */
/* {{{ GdkPadEvent */
/**
@@ -3033,7 +3025,6 @@ gdk_pad_event_get_group_mode (GdkEvent *event,
}
/* }}} */
/* {{{ GdkMotionEvent */
/**
@@ -3195,7 +3186,6 @@ gdk_event_get_history (GdkEvent *event,
}
/* }}} */
/* {{{ GdkProximityEvent */
/**
@@ -3258,7 +3248,6 @@ gdk_proximity_event_new (GdkEventType type,
}
/* }}} */
/* {{{ GdkDNDEvent */
/**
@@ -3364,7 +3353,6 @@ gdk_dnd_event_get_drop (GdkEvent *event)
}
/* }}} */
/* {{{ GdkGrabBrokenEvent */
/**
@@ -3442,3 +3430,5 @@ gdk_grab_broken_event_get_implicit (GdkEvent *event)
}
/* }}} */
/* vim:set foldmethod=marker expandtab: */
+52
View File
@@ -39,6 +39,7 @@ struct _GdkGLTexture {
GdkGLContext *context;
guint id;
GLsync sync;
GdkTexture *saved;
@@ -64,6 +65,7 @@ drop_gl_resources (GdkGLTexture *self)
g_clear_object (&self->context);
self->id = 0;
self->sync = NULL;
}
static void
@@ -99,6 +101,10 @@ gdk_gl_texture_invoke_callback (gpointer data)
context = gdk_display_get_gl_context (gdk_gl_context_get_display (invoke->self->context));
gdk_gl_context_make_current (context);
if (invoke->self->sync && context != invoke->self->context)
glWaitSync (invoke->self->sync, 0, GL_TIMEOUT_IGNORED);
glBindTexture (GL_TEXTURE_2D, invoke->self->id);
invoke->func (invoke->self, context, invoke->data);
@@ -440,6 +446,46 @@ gdk_gl_texture_new (GdkGLContext *context,
int height,
GDestroyNotify destroy,
gpointer data)
{
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
g_return_val_if_fail (id != 0, NULL);
g_return_val_if_fail (width > 0, NULL);
g_return_val_if_fail (height > 0, NULL);
return gdk_gl_texture_new_with_sync (context, id, NULL, width, height, destroy, data);
}
/*< private >
* gdk_gl_texture_new_with_sync:
* @context: a `GdkGLContext`
* @id: the ID of a texture that was created with @context
* @sync: (nullable): an optional GLsync object
* @width: the nominal width of the texture
* @height: the nominal height of the texture
* @destroy: a destroy notify that will be called when the GL resources
* are released
* @data: data that gets passed to @destroy
*
* Creates a new texture for an existing GL texture.
*
* If @sync is given, consumers of the texture are required to wait on
* it before attempting to use the GL texture.
*
* The GL texture and the sync object must stay alive unmodified until
* @destroy is called, which will happen when the GdkTexture object is
* finalized, or due to an explicit call of [method@Gdk.GLTexture.release].
*
* Return value: (transfer full) (type GdkGLTexture): A newly-created
* `GdkTexture`
*/
GdkTexture *
gdk_gl_texture_new_with_sync (GdkGLContext *context,
guint id,
gpointer sync,
int width,
int height,
GDestroyNotify destroy,
gpointer data)
{
GdkGLTexture *self;
@@ -455,6 +501,7 @@ gdk_gl_texture_new (GdkGLContext *context,
self->context = g_object_ref (context);
self->id = id;
self->sync = sync;
self->destroy = destroy;
self->data = data;
@@ -463,3 +510,8 @@ gdk_gl_texture_new (GdkGLContext *context,
return GDK_TEXTURE (self);
}
gpointer
gdk_gl_texture_get_sync (GdkGLTexture *self)
{
return self->sync;
}
+10
View File
@@ -9,6 +9,16 @@ G_BEGIN_DECLS
GdkGLContext * gdk_gl_texture_get_context (GdkGLTexture *self);
guint gdk_gl_texture_get_id (GdkGLTexture *self);
gpointer gdk_gl_texture_get_sync (GdkGLTexture *self);
GDK_AVAILABLE_IN_4_10
GdkTexture * gdk_gl_texture_new_with_sync (GdkGLContext *context,
guint id,
gpointer sync,
int width,
int height,
GDestroyNotify destroy,
gpointer data);
G_END_DECLS
+1 -1
View File
@@ -87,7 +87,7 @@ gdk_wayland_app_launch_context_get_startup_notify_id (GAppLaunchContext *context
xdg_activation_token_v1_commit (token);
while (app_launch_data.token == NULL)
wl_display_dispatch_queue (display->wl_display, event_queue);
gdk_wayland_display_dispatch_queue (GDK_DISPLAY (display), event_queue);
xdg_activation_token_v1_destroy (token);
id = app_launch_data.token;
+14
View File
@@ -2694,3 +2694,17 @@ gdk_wayland_display_query_registry (GdkDisplay *display,
return FALSE;
}
void
gdk_wayland_display_dispatch_queue (GdkDisplay *display,
struct wl_event_queue *event_queue)
{
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
if (wl_display_dispatch_queue (display_wayland->wl_display, event_queue) == -1)
{
g_message ("Error %d (%s) dispatching to Wayland display.",
errno, g_strerror (errno));
_exit (1);
}
}
+3
View File
@@ -158,6 +158,9 @@ struct _GdkWaylandDisplayClass
gboolean gdk_wayland_display_prefers_ssd (GdkDisplay *display);
void gdk_wayland_display_dispatch_queue (GdkDisplay *display,
struct wl_event_queue *event_queue);
G_END_DECLS
#endif /* __GDK_WAYLAND_DISPLAY__ */
+4 -3
View File
@@ -1334,8 +1334,6 @@ gdk_wayland_surface_present_popup (GdkWaylandPopup *wayland_popup,
GdkPopupLayout *layout)
{
GdkSurface *surface = GDK_SURFACE (wayland_popup);
GdkWaylandDisplay *display_wayland =
GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (wayland_popup);
if (!wayland_surface->mapped)
@@ -1388,7 +1386,10 @@ gdk_wayland_surface_present_popup (GdkWaylandPopup *wayland_popup,
}
while (wayland_popup->display_server.xdg_popup && !is_relayout_finished (surface))
wl_display_dispatch_queue (display_wayland->wl_display, wayland_surface->event_queue);
{
gdk_wayland_display_dispatch_queue (surface->display,
wayland_surface->event_queue);
}
if (wayland_popup->display_server.xdg_popup)
{
+4 -1
View File
@@ -2119,7 +2119,10 @@ gdk_wayland_toplevel_focus (GdkToplevel *toplevel,
xdg_activation_token_v1_commit (token);
while (startup_id == NULL)
wl_display_dispatch_queue (display_wayland->wl_display, event_queue);
{
gdk_wayland_display_dispatch_queue (GDK_DISPLAY (display_wayland),
event_queue);
}
xdg_activation_token_v1_destroy (token);
wl_event_queue_destroy (event_queue);
+4
View File
@@ -250,6 +250,7 @@ collect_reused_child_nodes (GskRenderer *renderer,
/* Leaf nodes */
case GSK_TEXTURE_NODE:
case GSK_TEXTURE_SCALE_NODE:
case GSK_CAIRO_NODE:
case GSK_COLOR_NODE:
case GSK_BORDER_NODE:
@@ -269,6 +270,7 @@ collect_reused_child_nodes (GskRenderer *renderer,
case GSK_BLEND_NODE:
case GSK_CROSS_FADE_NODE:
case GSK_BLUR_NODE:
case GSK_MASK_NODE:
default:
@@ -845,6 +847,8 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
}
break; /* Fallback */
case GSK_MASK_NODE:
case GSK_TEXTURE_SCALE_NODE:
case GSK_TEXT_NODE:
case GSK_RADIAL_GRADIENT_NODE:
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
+20 -4
View File
@@ -403,6 +403,7 @@ gsk_gl_command_queue_dispose (GObject *object)
gsk_gl_command_batches_clear (&self->batches);
gsk_gl_command_binds_clear (&self->batch_binds);
gsk_gl_command_uniforms_clear (&self->batch_uniforms);
gsk_gl_syncs_clear (&self->syncs);
gsk_gl_buffer_destroy (&self->vertices);
@@ -425,6 +426,7 @@ gsk_gl_command_queue_init (GskGLCommandQueue *self)
gsk_gl_command_batches_init (&self->batches, 128);
gsk_gl_command_binds_init (&self->batch_binds, 1024);
gsk_gl_command_uniforms_init (&self->batch_uniforms, 2048);
gsk_gl_syncs_init (&self->syncs, 10);
gsk_gl_buffer_init (&self->vertices, GL_ARRAY_BUFFER, sizeof (GskGLDrawVertex));
}
@@ -570,7 +572,10 @@ gsk_gl_command_queue_end_draw (GskGLCommandQueue *self)
g_assert (self->batches.len > 0);
if (will_ignore_batch (self))
return;
{
self->in_draw = FALSE;
return;
}
batch = gsk_gl_command_batches_tail (&self->batches);
@@ -1095,17 +1100,25 @@ gsk_gl_command_queue_execute (GskGLCommandQueue *self,
if G_UNLIKELY (batch->draw.bind_count > 0)
{
const GskGLCommandBind *bind = &self->batch_binds.items[batch->draw.bind_offset];
for (guint i = 0; i < batch->draw.bind_count; i++)
{
if (textures[bind->texture] != bind->id)
{
GskGLSync *s;
if (active != bind->texture)
{
active = bind->texture;
glActiveTexture (GL_TEXTURE0 + bind->texture);
}
s = gsk_gl_syncs_get_sync (&self->syncs, bind->id);
if (s && s->sync)
{
glWaitSync ((GLsync) s->sync, 0, GL_TIMEOUT_IGNORED);
s->sync = NULL;
}
glBindTexture (GL_TEXTURE_2D, bind->id);
textures[bind->texture] = bind->id;
}
@@ -1233,6 +1246,7 @@ gsk_gl_command_queue_end_frame (GskGLCommandQueue *self)
self->batches.len = 0;
self->batch_binds.len = 0;
self->batch_uniforms.len = 0;
self->syncs.len = 0;
self->n_uploads = 0;
self->tail_batch_index = -1;
self->in_frame = FALSE;
@@ -1439,8 +1453,7 @@ gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self,
g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
g_assert (!GDK_IS_GL_TEXTURE (texture));
g_assert (min_filter == GL_LINEAR || min_filter == GL_NEAREST);
g_assert (mag_filter == GL_LINEAR || min_filter == GL_NEAREST);
g_assert (mag_filter == GL_LINEAR || mag_filter == GL_NEAREST);
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
@@ -1464,6 +1477,9 @@ gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self,
gsk_gl_command_queue_do_upload_texture (self, texture);
if (min_filter == GL_LINEAR_MIPMAP_LINEAR)
glGenerateMipmap (GL_TEXTURE_2D);
/* Restore previous texture state if any */
if (self->attachments->textures[0].id > 0)
glBindTexture (self->attachments->textures[0].target,
+39
View File
@@ -167,9 +167,15 @@ typedef union _GskGLCommandBatch
G_STATIC_ASSERT (sizeof (GskGLCommandBatch) == 32);
typedef struct _GskGLSync {
guint id;
gpointer sync;
} GskGLSync;
DEFINE_INLINE_ARRAY (GskGLCommandBatches, gsk_gl_command_batches, GskGLCommandBatch)
DEFINE_INLINE_ARRAY (GskGLCommandBinds, gsk_gl_command_binds, GskGLCommandBind)
DEFINE_INLINE_ARRAY (GskGLCommandUniforms, gsk_gl_command_uniforms, GskGLCommandUniform)
DEFINE_INLINE_ARRAY (GskGLSyncs, gsk_gl_syncs, GskGLSync)
struct _GskGLCommandQueue
{
@@ -225,6 +231,8 @@ struct _GskGLCommandQueue
*/
GskGLCommandUniforms batch_uniforms;
GskGLSyncs syncs;
/* Discovered max texture size when loading the command queue so that we
* can either scale down or slice textures to fit within this size. Assumed
* to be both height and width.
@@ -354,6 +362,37 @@ gsk_gl_command_queue_bind_framebuffer (GskGLCommandQueue *self,
return ret;
}
static inline GskGLSync *
gsk_gl_syncs_get_sync (GskGLSyncs *syncs,
guint id)
{
for (unsigned int i = 0; i < syncs->len; i++)
{
GskGLSync *sync = &syncs->items[i];
if (sync->id == id)
return sync;
}
return NULL;
}
static inline void
gsk_gl_syncs_add_sync (GskGLSyncs *syncs,
guint id,
gpointer sync)
{
GskGLSync *s;
s = gsk_gl_syncs_get_sync (syncs, id);
if (s)
g_assert (s->sync == sync);
else
{
s = gsk_gl_syncs_append (syncs);
s->id = id;
s->sync = sync;
}
}
G_END_DECLS
#endif /* __GSK_GL_COMMAND_QUEUE_PRIVATE_H__ */
+34 -19
View File
@@ -753,7 +753,7 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
{
if ((t = gdk_texture_get_render_data (texture, self)))
{
if (t->min_filter == min_filter && t->mag_filter == mag_filter)
if (t->min_filter == min_filter && t->mag_filter == mag_filter && t->texture_id)
return t->texture_id;
}
@@ -1195,6 +1195,10 @@ gsk_gl_driver_create_command_queue (GskGLDriver *self,
void
gsk_gl_driver_add_texture_slices (GskGLDriver *self,
GdkTexture *texture,
int min_filter,
int mag_filter,
guint min_cols,
guint min_rows,
GskGLTextureSlice **out_slices,
guint *out_n_slices)
{
@@ -1216,31 +1220,37 @@ gsk_gl_driver_add_texture_slices (GskGLDriver *self,
/* XXX: Too much? */
max_texture_size = self->command_queue->max_texture_size / 4;
tex_width = texture->width;
tex_height = texture->height;
cols = (texture->width / max_texture_size) + 1;
rows = (texture->height / max_texture_size) + 1;
cols = MAX ((texture->width / max_texture_size) + 1, min_cols);
rows = MAX ((texture->height / max_texture_size) + 1, min_rows);
n_slices = cols * rows;
if ((t = gdk_texture_get_render_data (texture, self)))
{
*out_slices = t->slices;
*out_n_slices = t->n_slices;
return;
if (t->n_slices == n_slices)
{
*out_slices = t->slices;
*out_n_slices = t->n_slices;
return;
}
gdk_texture_clear_render_data (texture);
}
n_slices = cols * rows;
slices = g_new0 (GskGLTextureSlice, n_slices);
memtex = gdk_memory_texture_from_texture (texture,
gdk_texture_get_format (texture));
for (guint col = 0; col < cols; col ++)
for (guint col = 0; col < cols; col++)
{
int slice_width = MIN (max_texture_size, texture->width - x);
int slice_width = col + 1 < cols ? tex_width / cols : tex_width - x;
for (guint row = 0; row < rows; row ++)
for (guint row = 0; row < rows; row++)
{
int slice_height = MIN (max_texture_size, texture->height - y);
int slice_height = row + 1 < rows ? tex_height / rows : tex_height - y;
int slice_index = (col * rows) + row;
GdkTexture *subtex;
guint texture_id;
@@ -1250,7 +1260,7 @@ gsk_gl_driver_add_texture_slices (GskGLDriver *self,
slice_width, slice_height);
texture_id = gsk_gl_command_queue_upload_texture (self->command_queue,
subtex,
GL_NEAREST, GL_NEAREST);
min_filter, mag_filter);
g_object_unref (subtex);
slices[slice_index].rect.x = x;
@@ -1319,6 +1329,7 @@ typedef struct _GskGLTextureState
{
GdkGLContext *context;
GLuint texture_id;
GLsync sync;
} GskGLTextureState;
static void
@@ -1331,6 +1342,7 @@ create_texture_from_texture_destroy (gpointer data)
gdk_gl_context_make_current (state->context);
glDeleteTextures (1, &state->texture_id);
glDeleteSync (state->sync);
g_clear_object (&state->context);
g_slice_free (GskGLTextureState, state);
}
@@ -1365,10 +1377,13 @@ gsk_gl_driver_create_gdk_texture (GskGLDriver *self,
texture->texture_id = 0;
gsk_gl_texture_free (texture);
return gdk_gl_texture_new (self->command_queue->context,
texture_id,
width,
height,
create_texture_from_texture_destroy,
state);
state->sync = glFenceSync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
return gdk_gl_texture_new_with_sync (self->command_queue->context,
texture_id,
state->sync,
width,
height,
create_texture_from_texture_destroy,
state);
}
+15 -4
View File
@@ -177,6 +177,10 @@ GskGLTexture * gsk_gl_driver_mark_texture_permanent (GskGLDriver *s
guint texture_id);
void gsk_gl_driver_add_texture_slices (GskGLDriver *self,
GdkTexture *texture,
int min_filter,
int mag_filter,
guint min_cols,
guint min_rows,
GskGLTextureSlice **out_slices,
guint *out_n_slices);
GskGLProgram * gsk_gl_driver_lookup_shader (GskGLDriver *self,
@@ -228,6 +232,10 @@ gsk_gl_driver_lookup_texture (GskGLDriver *self,
static inline void
gsk_gl_driver_slice_texture (GskGLDriver *self,
GdkTexture *texture,
int min_filter,
int mag_filter,
guint min_cols,
guint min_rows,
GskGLTextureSlice **out_slices,
guint *out_n_slices)
{
@@ -235,12 +243,15 @@ gsk_gl_driver_slice_texture (GskGLDriver *self,
if ((t = gdk_texture_get_render_data (texture, self)))
{
*out_slices = t->slices;
*out_n_slices = t->n_slices;
return;
if (min_cols == 0 && min_rows == 0)
{
*out_slices = t->slices;
*out_n_slices = t->n_slices;
return;
}
}
gsk_gl_driver_add_texture_slices (self, texture, out_slices, out_n_slices);
gsk_gl_driver_add_texture_slices (self, texture, min_filter, mag_filter, min_cols, min_rows, out_slices, out_n_slices);
}
G_END_DECLS
+21
View File
@@ -264,6 +264,27 @@ gsk_gl_program_set_uniform_texture (GskGLProgram *self,
texture_slot);
}
static inline void
gsk_gl_program_set_uniform_texture_with_sync (GskGLProgram *self,
guint key,
guint stamp,
GLenum texture_target,
GLenum texture_slot,
guint texture_id,
gpointer sync)
{
gsk_gl_attachment_state_bind_texture (self->driver->command_queue->attachments,
texture_target,
texture_slot,
texture_id);
gsk_gl_uniform_state_set_texture (self->uniforms,
self->program_info,
key,
stamp,
texture_slot);
gsk_gl_syncs_add_sync (&self->driver->command_queue->syncs, texture_id, sync);
}
static inline void
gsk_gl_program_set_uniform_matrix (GskGLProgram *self,
guint key,
+4
View File
@@ -60,6 +60,10 @@ GSK_GL_DEFINE_PROGRAM (linear_gradient,
GSK_GL_ADD_UNIFORM (3, LINEAR_GRADIENT_POINTS, u_points)
GSK_GL_ADD_UNIFORM (4, LINEAR_GRADIENT_REPEAT, u_repeat))
GSK_GL_DEFINE_PROGRAM (mask,
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("mask.glsl")),
GSK_GL_ADD_UNIFORM (1, MASK_SOURCE, u_mask))
GSK_GL_DEFINE_PROGRAM (outset_shadow,
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("outset_shadow.glsl")),
GSK_GL_ADD_UNIFORM (1, OUTSET_SHADOW_OUTLINE_RECT, u_outline_rect))
+236 -19
View File
@@ -190,6 +190,7 @@ typedef struct _GskGLRenderOffscreen
/* Return location for texture ID */
guint texture_id;
gpointer sync;
/* Whether to force creating a new texture, even if the
* input already is a texture
@@ -3277,6 +3278,56 @@ gsk_gl_render_job_visit_blend_node (GskGLRenderJob *job,
gsk_gl_render_job_end_draw (job);
}
static inline void
gsk_gl_render_job_visit_mask_node (GskGLRenderJob *job,
const GskRenderNode *node)
{
const GskRenderNode *source = gsk_mask_node_get_source (node);
const GskRenderNode *mask = gsk_mask_node_get_mask (node);
GskGLRenderOffscreen source_offscreen = {0};
GskGLRenderOffscreen mask_offscreen = {0};
source_offscreen.bounds = &node->bounds;
source_offscreen.force_offscreen = TRUE;
source_offscreen.reset_clip = TRUE;
mask_offscreen.bounds = &node->bounds;
mask_offscreen.force_offscreen = TRUE;
mask_offscreen.reset_clip = TRUE;
/* TODO: We create 2 textures here as big as the mask node, but both
* nodes might be a lot smaller than that.
*/
if (!gsk_gl_render_job_visit_node_with_offscreen (job, source, &source_offscreen))
{
gsk_gl_render_job_visit_node (job, source);
return;
}
g_assert (source_offscreen.was_offscreen);
if (!gsk_gl_render_job_visit_node_with_offscreen (job, mask, &mask_offscreen))
{
return;
}
g_assert (mask_offscreen.was_offscreen);
gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, mask));
gsk_gl_program_set_uniform_texture (job->current_program,
UNIFORM_SHARED_SOURCE, 0,
GL_TEXTURE_2D,
GL_TEXTURE0,
source_offscreen.texture_id);
gsk_gl_program_set_uniform_texture (job->current_program,
UNIFORM_MASK_SOURCE, 0,
GL_TEXTURE_2D,
GL_TEXTURE1,
mask_offscreen.texture_id);
gsk_gl_render_job_draw_offscreen_rect (job, &node->bounds);
gsk_gl_render_job_end_draw (job);
}
static inline void
gsk_gl_render_job_visit_color_matrix_node (GskGLRenderJob *job,
const GskRenderNode *node)
@@ -3443,12 +3494,21 @@ gsk_gl_render_job_visit_gl_shader_node (GskGLRenderJob *job,
static void
gsk_gl_render_job_upload_texture (GskGLRenderJob *job,
GdkTexture *texture,
int min_filter,
int mag_filter,
GskGLRenderOffscreen *offscreen)
{
if (gsk_gl_texture_library_can_cache ((GskGLTextureLibrary *)job->driver->icons_library,
GdkGLTexture *gl_texture = NULL;
if (GDK_IS_GL_TEXTURE (texture))
gl_texture = (GdkGLTexture *) texture;
if (min_filter == GL_LINEAR &&
mag_filter == GL_LINEAR &&
gsk_gl_texture_library_can_cache ((GskGLTextureLibrary *)job->driver->icons_library,
texture->width,
texture->height) &&
!GDK_IS_GL_TEXTURE (texture))
!gl_texture)
{
const GskGLIconData *icon_data;
@@ -3458,16 +3518,19 @@ gsk_gl_render_job_upload_texture (GskGLRenderJob *job,
}
else
{
offscreen->texture_id = gsk_gl_driver_load_texture (job->driver, texture, GL_LINEAR, GL_LINEAR);
offscreen->texture_id = gsk_gl_driver_load_texture (job->driver, texture, min_filter, mag_filter);
init_full_texture_region (offscreen);
if (gl_texture && offscreen->texture_id == gdk_gl_texture_get_id (gl_texture) &&
gdk_gl_texture_get_context (gl_texture) != gsk_gl_command_queue_get_context (job->command_queue))
offscreen->sync = gdk_gl_texture_get_sync (gl_texture);
}
}
static inline void
gsk_gl_render_job_visit_texture_node (GskGLRenderJob *job,
const GskRenderNode *node)
gsk_gl_render_job_visit_texture (GskGLRenderJob *job,
GdkTexture *texture,
const graphene_rect_t *bounds)
{
GdkTexture *texture = gsk_texture_node_get_texture (node);
int max_texture_size = job->command_queue->max_texture_size;
if G_LIKELY (texture->width <= max_texture_size &&
@@ -3475,32 +3538,33 @@ gsk_gl_render_job_visit_texture_node (GskGLRenderJob *job,
{
GskGLRenderOffscreen offscreen = {0};
gsk_gl_render_job_upload_texture (job, texture, &offscreen);
gsk_gl_render_job_upload_texture (job, texture, GL_LINEAR, GL_LINEAR, &offscreen);
g_assert (offscreen.texture_id);
g_assert (offscreen.was_offscreen == FALSE);
gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit));
gsk_gl_program_set_uniform_texture (job->current_program,
UNIFORM_SHARED_SOURCE, 0,
GL_TEXTURE_2D,
GL_TEXTURE0,
offscreen.texture_id);
gsk_gl_render_job_draw_offscreen (job, &node->bounds, &offscreen);
gsk_gl_program_set_uniform_texture_with_sync (job->current_program,
UNIFORM_SHARED_SOURCE, 0,
GL_TEXTURE_2D,
GL_TEXTURE0,
offscreen.texture_id,
offscreen.sync);
gsk_gl_render_job_draw_offscreen (job, bounds, &offscreen);
gsk_gl_render_job_end_draw (job);
}
else
{
float min_x = job->offset_x + node->bounds.origin.x;
float min_y = job->offset_y + node->bounds.origin.y;
float max_x = min_x + node->bounds.size.width;
float max_y = min_y + node->bounds.size.height;
float min_x = job->offset_x + bounds->origin.x;
float min_y = job->offset_y + bounds->origin.y;
float max_x = min_x + bounds->size.width;
float max_y = min_y + bounds->size.height;
float scale_x = (max_x - min_x) / texture->width;
float scale_y = (max_y - min_y) / texture->height;
GskGLTextureSlice *slices = NULL;
guint n_slices = 0;
gsk_gl_driver_slice_texture (job->driver, texture, &slices, &n_slices);
gsk_gl_driver_slice_texture (job->driver, texture, GL_NEAREST, GL_NEAREST, 0, 0, &slices, &n_slices);
g_assert (slices != NULL);
g_assert (n_slices > 0);
@@ -3535,6 +3599,151 @@ gsk_gl_render_job_visit_texture_node (GskGLRenderJob *job,
}
}
static inline void
gsk_gl_render_job_visit_texture_node (GskGLRenderJob *job,
const GskRenderNode *node)
{
GdkTexture *texture = gsk_texture_node_get_texture (node);
const graphene_rect_t *bounds = &node->bounds;
gsk_gl_render_job_visit_texture (job, texture, bounds);
}
static inline void
gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
const GskRenderNode *node)
{
GdkTexture *texture = gsk_texture_scale_node_get_texture (node);
const graphene_rect_t *bounds = &node->bounds;
GskScalingFilter scaling_filter = gsk_texture_scale_node_get_filter (node);
int min_filters[] = { GL_LINEAR, GL_NEAREST, GL_LINEAR_MIPMAP_LINEAR };
int mag_filters[] = { GL_LINEAR, GL_NEAREST, GL_LINEAR };
int min_filter = min_filters[scaling_filter];
int mag_filter = mag_filters[scaling_filter];
int max_texture_size = job->command_queue->max_texture_size;
if (scaling_filter == GSK_SCALING_FILTER_LINEAR)
{
gsk_gl_render_job_visit_texture (job, texture, bounds);
return;
}
if G_LIKELY (texture->width <= max_texture_size &&
texture->height <= max_texture_size)
{
GskGLRenderTarget *render_target;
GskGLRenderOffscreen offscreen = {0};
graphene_rect_t viewport;
graphene_rect_t prev_viewport;
graphene_matrix_t prev_projection;
float prev_alpha;
guint prev_fbo;
guint texture_id;
viewport = GRAPHENE_RECT_INIT (0, 0,
bounds->size.width,
bounds->size.height);
if (!gsk_gl_driver_create_render_target (job->driver,
(int) ceilf (viewport.size.width),
(int) ceilf (viewport.size.height),
get_target_format (job, node),
GL_LINEAR, GL_LINEAR,
&render_target))
{
/* viewport is too big, slice the texture and try again */
goto slice;
}
gsk_gl_render_job_upload_texture (job, texture, min_filter, mag_filter, &offscreen);
g_assert (offscreen.texture_id);
g_assert (offscreen.was_offscreen == FALSE);
gsk_gl_render_job_set_viewport (job, &viewport, &prev_viewport);
gsk_gl_render_job_set_projection_from_rect (job, &viewport, &prev_projection);
gsk_gl_render_job_set_modelview (job, NULL);
prev_alpha = gsk_gl_render_job_set_alpha (job, 1.0f);
gsk_gl_render_job_push_clip (job, &GSK_ROUNDED_RECT_INIT_FROM_RECT (viewport));
prev_fbo = gsk_gl_command_queue_bind_framebuffer (job->command_queue, render_target->framebuffer_id);
gsk_gl_command_queue_clear (job->command_queue, 0, &viewport);
gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit));
gsk_gl_program_set_uniform_texture (job->current_program,
UNIFORM_SHARED_SOURCE, 0,
GL_TEXTURE_2D,
GL_TEXTURE0,
offscreen.texture_id);
gsk_gl_render_job_draw_offscreen (job, &viewport, &offscreen);
gsk_gl_render_job_end_draw (job);
gsk_gl_render_job_pop_clip (job);
gsk_gl_render_job_pop_modelview (job);
gsk_gl_render_job_set_viewport (job, &prev_viewport, NULL);
gsk_gl_render_job_set_projection (job, &prev_projection);
gsk_gl_render_job_set_alpha (job, prev_alpha);
gsk_gl_command_queue_bind_framebuffer (job->command_queue, prev_fbo);
texture_id = gsk_gl_driver_release_render_target (job->driver, render_target, FALSE);
gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit));
gsk_gl_program_set_uniform_texture (job->current_program,
UNIFORM_SHARED_SOURCE, 0,
GL_TEXTURE_2D,
GL_TEXTURE0,
texture_id);
gsk_gl_render_job_draw_offscreen_rect (job, bounds);
gsk_gl_render_job_end_draw (job);
}
else
{
slice:
float min_x = bounds->origin.x;
float min_y = bounds->origin.y;
float max_x = min_x + bounds->size.width;
float max_y = min_y + bounds->size.height;
float scale_x = (max_x - min_x) / texture->width;
float scale_y = (max_y - min_y) / texture->height;
GskGLTextureSlice *slices = NULL;
guint n_slices = 0;
GdkGLContext *context = gsk_gl_driver_get_context (job->driver);
guint rows, cols;
/* Slice enough that neither the original texture nor the scaled texture
* exceed the texture size limit
*/
cols = (int)(MAX (bounds->size.width, texture->width) / (max_texture_size / 4)) + 1;
rows = (int)(MAX (bounds->size.height, texture->height) / (max_texture_size / 4)) + 1;
gsk_gl_driver_slice_texture (job->driver, texture, GL_NEAREST, GL_NEAREST, cols, rows, &slices, &n_slices);
g_assert (slices != NULL);
g_assert (n_slices > 0);
for (guint i = 0; i < n_slices; i ++)
{
const GskGLTextureSlice *slice = &slices[i];
float x1, x2, y1, y2;
GdkTexture *sub_texture;
GskRenderNode *sub_node;
x1 = min_x + (scale_x * slice->rect.x);
x2 = x1 + (slice->rect.width * scale_x);
y1 = min_y + (scale_y * slice->rect.y);
y2 = y1 + (slice->rect.height * scale_y);
sub_texture = gdk_gl_texture_new (context, slice->texture_id, slice->rect.width, slice->rect.height, NULL, NULL);
sub_node = gsk_texture_scale_node_new (sub_texture, &GRAPHENE_RECT_INIT (x1, y1, x2 - x1, y2 - y1), scaling_filter);
gsk_gl_render_job_visit_node (job, sub_node);
gsk_render_node_unref (sub_node);
g_object_unref (sub_texture);
}
}
}
static inline void
gsk_gl_render_job_visit_repeat_node (GskGLRenderJob *job,
const GskRenderNode *node)
@@ -3720,6 +3929,10 @@ gsk_gl_render_job_visit_node (GskGLRenderJob *job,
gsk_gl_render_job_visit_as_fallback (job, node);
break;
case GSK_MASK_NODE:
gsk_gl_render_job_visit_mask_node (job, node);
break;
case GSK_OPACITY_NODE:
gsk_gl_render_job_visit_opacity_node (job, node);
break;
@@ -3762,6 +3975,10 @@ gsk_gl_render_job_visit_node (GskGLRenderJob *job,
gsk_gl_render_job_visit_texture_node (job, node);
break;
case GSK_TEXTURE_SCALE_NODE:
gsk_gl_render_job_visit_texture_scale_node (job, node);
break;
case GSK_TRANSFORM_NODE:
gsk_gl_render_job_visit_transform_node (job, node);
break;
@@ -3808,7 +4025,7 @@ gsk_gl_render_job_visit_node_with_offscreen (GskGLRenderJob *job,
offscreen->force_offscreen == FALSE)
{
GdkTexture *texture = gsk_texture_node_get_texture (node);
gsk_gl_render_job_upload_texture (job, texture, offscreen);
gsk_gl_render_job_upload_texture (job, texture, GL_LINEAR, GL_LINEAR, offscreen);
g_assert (offscreen->was_offscreen == FALSE);
return TRUE;
}
+2 -1
View File
@@ -112,7 +112,8 @@ gsk_gl_texture_library_real_compact (GskGLTextureLibrary *self,
{
if (!entry->accessed)
{
gsk_gl_driver_release_texture (self->driver, entry->texture);
if (entry->texture)
gsk_gl_driver_release_texture (self->driver, entry->texture);
g_hash_table_iter_remove (&iter);
dropped++;
}
+19
View File
@@ -0,0 +1,19 @@
// VERTEX_SHADER:
// mask.glsl
void main() {
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
vUv = vec2(aUv.x, aUv.y);
}
// FRAGMENT_SHADER:
// mask.glsl
uniform sampler2D u_mask;
void main() {
vec4 source = GskTexture(u_source, vUv);
vec4 mask = GskTexture(u_mask, vUv);
gskSetOutputColor(vec4 (source * mask.a));
}
+4
View File
@@ -35,6 +35,7 @@
* @GSK_CONIC_GRADIENT_NODE: A node drawing a conic gradient
* @GSK_BORDER_NODE: A node stroking a border around an area
* @GSK_TEXTURE_NODE: A node drawing a `GdkTexture`
* @GSK_TEXTURE_SCALE_NODE: A node drawing a `GdkTexture` scaled and filtered
* @GSK_INSET_SHADOW_NODE: A node drawing an inset shadow
* @GSK_OUTSET_SHADOW_NODE: A node drawing an outset shadow
* @GSK_TRANSFORM_NODE: A node that renders its child after applying a matrix transform
@@ -45,6 +46,7 @@
* @GSK_ROUNDED_CLIP_NODE: A node that clips its child to a rounded rectangle
* @GSK_SHADOW_NODE: A node that draws a shadow below its child
* @GSK_BLEND_NODE: A node that blends two children together
* @GSK_MASK_NODE: A node that masks one child with another
* @GSK_CROSS_FADE_NODE: A node that cross-fades between two children
* @GSK_TEXT_NODE: A node containing a glyph string
* @GSK_BLUR_NODE: A node that applies a blur
@@ -65,6 +67,7 @@ typedef enum {
GSK_CONIC_GRADIENT_NODE,
GSK_BORDER_NODE,
GSK_TEXTURE_NODE,
GSK_TEXTURE_SCALE_NODE,
GSK_INSET_SHADOW_NODE,
GSK_OUTSET_SHADOW_NODE,
GSK_TRANSFORM_NODE,
@@ -75,6 +78,7 @@ typedef enum {
GSK_ROUNDED_CLIP_NODE,
GSK_SHADOW_NODE,
GSK_BLEND_NODE,
GSK_MASK_NODE,
GSK_CROSS_FADE_NODE,
GSK_TEXT_NODE,
GSK_BLUR_NODE,
+26 -1
View File
@@ -142,6 +142,7 @@ GskRenderNode * gsk_render_node_deserialize (GBytes
#define GSK_TYPE_DEBUG_NODE (gsk_debug_node_get_type())
#define GSK_TYPE_COLOR_NODE (gsk_color_node_get_type())
#define GSK_TYPE_TEXTURE_NODE (gsk_texture_node_get_type())
#define GSK_TYPE_TEXTURE_SCALE_NODE (gsk_texture_scale_node_get_type())
#define GSK_TYPE_LINEAR_GRADIENT_NODE (gsk_linear_gradient_node_get_type())
#define GSK_TYPE_REPEATING_LINEAR_GRADIENT_NODE (gsk_repeating_linear_gradient_node_get_type())
#define GSK_TYPE_RADIAL_GRADIENT_NODE (gsk_radial_gradient_node_get_type())
@@ -163,11 +164,13 @@ GskRenderNode * gsk_render_node_deserialize (GBytes
#define GSK_TYPE_CROSS_FADE_NODE (gsk_cross_fade_node_get_type())
#define GSK_TYPE_TEXT_NODE (gsk_text_node_get_type())
#define GSK_TYPE_BLUR_NODE (gsk_blur_node_get_type())
#define GSK_TYPE_MASK_NODE (gsk_mask_node_get_type())
#define GSK_TYPE_GL_SHADER_NODE (gsk_gl_shader_node_get_type())
typedef struct _GskDebugNode GskDebugNode;
typedef struct _GskColorNode GskColorNode;
typedef struct _GskTextureNode GskTextureNode;
typedef struct _GskTextureScaleNode GskTextureScaleNode;
typedef struct _GskLinearGradientNode GskLinearGradientNode;
typedef struct _GskRepeatingLinearGradientNode GskRepeatingLinearGradientNode;
typedef struct _GskRadialGradientNode GskRadialGradientNode;
@@ -189,6 +192,7 @@ typedef struct _GskBlendNode GskBlendNode;
typedef struct _GskCrossFadeNode GskCrossFadeNode;
typedef struct _GskTextNode GskTextNode;
typedef struct _GskBlurNode GskBlurNode;
typedef struct _GskMaskNode GskMaskNode;
typedef struct _GskGLShaderNode GskGLShaderNode;
GDK_AVAILABLE_IN_ALL
@@ -217,6 +221,17 @@ GskRenderNode * gsk_texture_node_new (GdkTexture
GDK_AVAILABLE_IN_ALL
GdkTexture * gsk_texture_node_get_texture (const GskRenderNode *node) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_10
GType gsk_texture_scale_node_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_4_10
GskRenderNode * gsk_texture_scale_node_new (GdkTexture *texture,
const graphene_rect_t *bounds,
GskScalingFilter filter);
GDK_AVAILABLE_IN_4_10
GdkTexture * gsk_texture_scale_node_get_texture (const GskRenderNode *node) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_10
GskScalingFilter gsk_texture_scale_node_get_filter (const GskRenderNode *node) G_GNUC_PURE;
GDK_AVAILABLE_IN_ALL
GType gsk_linear_gradient_node_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
@@ -516,8 +531,18 @@ GskRenderNode * gsk_blur_node_get_child (const GskRender
GDK_AVAILABLE_IN_ALL
float gsk_blur_node_get_radius (const GskRenderNode *node) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_10
GType gsk_mask_node_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_4_10
GskRenderNode * gsk_mask_node_new (GskRenderNode *source,
GskRenderNode *mask);
GDK_AVAILABLE_IN_4_10
GskRenderNode * gsk_mask_node_get_source (const GskRenderNode *node);
GDK_AVAILABLE_IN_4_10
GskRenderNode * gsk_mask_node_get_mask (const GskRenderNode *node);
GDK_AVAILABLE_IN_ALL
GType gsk_gl_shader_node_get_type (void) G_GNUC_CONST;
GType gsk_gl_shader_node_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GskRenderNode * gsk_gl_shader_node_new (GskGLShader *shader,
const graphene_rect_t *bounds,
+397 -23
View File
@@ -58,7 +58,7 @@ rectangle_init_from_graphene (cairo_rectangle_int_t *cairo,
cairo->height = ceilf (graphene->origin.y + graphene->size.height) - cairo->y;
}
/*** GSK_COLOR_NODE ***/
/* {{{ GSK_COLOR_NODE */
/**
* GskColorNode:
@@ -147,7 +147,8 @@ gsk_color_node_new (const GdkRGBA *rgba,
return node;
}
/*** GSK_LINEAR_GRADIENT_NODE ***/
/* }}} */
/* {{{ GSK_LINEAR_GRADIENT_NODE */
/**
* GskRepeatingLinearGradientNode:
@@ -420,7 +421,8 @@ gsk_linear_gradient_node_get_color_stops (const GskRenderNode *node,
return self->stops;
}
/*** GSK_RADIAL_GRADIENT_NODE ***/
/* }}} */
/* {{{ GSK_RADIAL_GRADIENT_NODE */
/**
* GskRepeatingRadialGradientNode:
@@ -790,7 +792,8 @@ gsk_radial_gradient_node_get_end (const GskRenderNode *node)
return self->end;
}
/*** GSK_CONIC_GRADIENT_NODE ***/
/* }}} */
/* {{{ GSK_CONIC_GRADIENT_NODE */
/**
* GskConicGradientNode:
@@ -1147,7 +1150,8 @@ gsk_conic_gradient_node_get_angle (const GskRenderNode *node)
return self->angle;
}
/*** GSK_BORDER_NODE ***/
/* }}} */
/* {{{ GSK_BORDER_NODE */
/**
* GskBorderNode:
@@ -1459,7 +1463,8 @@ gsk_border_node_get_uniform_color (const GskRenderNode *self)
return node->uniform_color;
}
/*** GSK_TEXTURE_NODE ***/
/* }}} */
/* {{{ GSK_TEXTURE_NODE */
/**
* GskTextureNode:
@@ -1576,7 +1581,193 @@ gsk_texture_node_new (GdkTexture *texture,
return node;
}
/*** GSK_INSET_SHADOW_NODE ***/
/* }}} */
/* {{{ GSK_TEXTURE_SCALE_NODE */
/**
* GskTextureScaleNode:
*
* A render node for a `GdkTexture`.
*/
struct _GskTextureScaleNode
{
GskRenderNode render_node;
GdkTexture *texture;
GskScalingFilter filter;
};
static void
gsk_texture_scale_node_finalize (GskRenderNode *node)
{
GskTextureScaleNode *self = (GskTextureScaleNode *) node;
GskRenderNodeClass *parent_class = g_type_class_peek (g_type_parent (GSK_TYPE_TEXTURE_SCALE_NODE));
g_clear_object (&self->texture);
parent_class->finalize (node);
}
static void
gsk_texture_scale_node_draw (GskRenderNode *node,
cairo_t *cr)
{
GskTextureScaleNode *self = (GskTextureScaleNode *) node;
cairo_surface_t *surface;
cairo_pattern_t *pattern;
cairo_matrix_t matrix;
cairo_filter_t filters[] = {
CAIRO_FILTER_BILINEAR,
CAIRO_FILTER_NEAREST,
CAIRO_FILTER_GOOD,
};
cairo_t *cr2;
cairo_surface_t *surface2;
surface2 = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
(int) ceilf (node->bounds.size.width),
(int) ceilf (node->bounds.size.height));
cr2 = cairo_create (surface2);
cairo_set_source_rgba (cr2, 0, 0, 0, 0);
cairo_paint (cr2);
surface = gdk_texture_download_surface (self->texture);
pattern = cairo_pattern_create_for_surface (surface);
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
cairo_matrix_init_scale (&matrix,
gdk_texture_get_width (self->texture) / node->bounds.size.width,
gdk_texture_get_height (self->texture) / node->bounds.size.height);
cairo_pattern_set_matrix (pattern, &matrix);
cairo_pattern_set_filter (pattern, filters[self->filter]);
cairo_set_source (cr2, pattern);
cairo_pattern_destroy (pattern);
cairo_surface_destroy (surface);
cairo_rectangle (cr2, 0, 0, node->bounds.size.width, node->bounds.size.height);
cairo_fill (cr2);
cairo_destroy (cr2);
cairo_save (cr);
pattern = cairo_pattern_create_for_surface (surface2);
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
cairo_matrix_init_identity (&matrix);
cairo_matrix_translate (&matrix,
-node->bounds.origin.x,
-node->bounds.origin.y);
cairo_pattern_set_matrix (pattern, &matrix);
cairo_set_source (cr, pattern);
cairo_pattern_destroy (pattern);
cairo_surface_destroy (surface2);
gsk_cairo_rectangle (cr, &node->bounds);
cairo_fill (cr);
cairo_restore (cr);
}
static void
gsk_texture_scale_node_diff (GskRenderNode *node1,
GskRenderNode *node2,
cairo_region_t *region)
{
GskTextureScaleNode *self1 = (GskTextureScaleNode *) node1;
GskTextureScaleNode *self2 = (GskTextureScaleNode *) node2;
if (graphene_rect_equal (&node1->bounds, &node2->bounds) &&
self1->texture == self2->texture &&
self1->filter == self2->filter)
return;
gsk_render_node_diff_impossible (node1, node2, region);
}
/**
* gsk_texture_scale_node_get_texture:
* @node: (type GskTextureNode): a `GskRenderNode` of type %GSK_TEXTURE_SCALE_NODE
*
* Retrieves the `GdkTexture` used when creating this `GskRenderNode`.
*
* Returns: (transfer none): the `GdkTexture`
*
* Since: 4.10
*/
GdkTexture *
gsk_texture_scale_node_get_texture (const GskRenderNode *node)
{
const GskTextureScaleNode *self = (const GskTextureScaleNode *) node;
return self->texture;
}
/**
* gsk_texture_scale_node_get_filter:
* @node: (type GskTextureNode): a `GskRenderNode` of type %GSK_TEXTURE_SCALE_NODE
*
* Retrieves the `GskScalingFilter` used when creating this `GskRenderNode`.
*
* Returns: (transfer none): the `GskScalingFilter`
*
* Since: 4.10
*/
GskScalingFilter
gsk_texture_scale_node_get_filter (const GskRenderNode *node)
{
const GskTextureScaleNode *self = (const GskTextureScaleNode *) node;
return self->filter;
}
/**
* gsk_texture_scale_node_new:
* @texture: the texture to scale
* @bounds: the size of the texture to scale to
* @filter: how to scale the texture
*
* Creates a node that scales the texture to the size given by the
* bounds and the filter and then places it at the bounds' position.
*
* This node is intended for tight control over scaling applied
* to a texture, such as in image editors and requires the
* application to be aware of the whole render tree as further
* transforms may be applied that conflict with the desired effect
* of this node.
*
* Returns: (transfer full) (type GskTextureScaleNode): A new `GskRenderNode`
*
* Since: 4.10
*/
GskRenderNode *
gsk_texture_scale_node_new (GdkTexture *texture,
const graphene_rect_t *bounds,
GskScalingFilter filter)
{
GskTextureScaleNode *self;
GskRenderNode *node;
g_return_val_if_fail (GDK_IS_TEXTURE (texture), NULL);
g_return_val_if_fail (bounds != NULL, NULL);
self = gsk_render_node_alloc (GSK_TEXTURE_SCALE_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
self->texture = g_object_ref (texture);
graphene_rect_init_from_rect (&node->bounds, bounds);
self->filter = filter;
node->prefers_high_depth = gdk_memory_format_prefers_high_depth (gdk_texture_get_format (texture));
return node;
}
/* }}} */
/* {{{ GSK_INSET_SHADOW_NODE */
/**
* GskInsetShadowNode:
@@ -2132,7 +2323,8 @@ gsk_inset_shadow_node_get_blur_radius (const GskRenderNode *node)
return self->blur_radius;
}
/*** GSK_OUTSET_SHADOW_NODE ***/
/* }}} */
/* {{{ GSK_OUTSET_SHADOW_NODE */
/**
* GskOutsetShadowNode:
@@ -2438,7 +2630,8 @@ gsk_outset_shadow_node_get_blur_radius (const GskRenderNode *node)
return self->blur_radius;
}
/*** GSK_CAIRO_NODE ***/
/* }}} */
/* {{{ GSK_CAIRO_NODE */
/**
* GskCairoNode:
@@ -2576,7 +2769,8 @@ gsk_cairo_node_get_draw_context (GskRenderNode *node)
return res;
}
/**** GSK_CONTAINER_NODE ***/
/* }}} */
/* {{{ GSK_CONTAINER_NODE */
/**
* GskContainerNode:
@@ -2835,7 +3029,8 @@ gsk_container_node_is_disjoint (const GskRenderNode *node)
return self->disjoint;
}
/*** GSK_TRANSFORM_NODE ***/
/* }}} */
/* {{{ GSK_TRANSFORM_NODE */
/**
* GskTransformNode:
@@ -3058,7 +3253,8 @@ gsk_transform_node_get_translate (const GskRenderNode *node,
*dy = self->dy;
}
/*** GSK_OPACITY_NODE ***/
/* }}} */
/* {{{ GSK_OPACITY_NODE */
/**
* GskOpacityNode:
@@ -3185,7 +3381,8 @@ gsk_opacity_node_get_opacity (const GskRenderNode *node)
return self->opacity;
}
/*** GSK_COLOR_MATRIX_NODE ***/
/* }}} */
/* {{{ GSK_COLOR_MATRIX_NODE */
/**
* GskColorMatrixNode:
@@ -3406,7 +3603,8 @@ gsk_color_matrix_node_get_color_offset (const GskRenderNode *node)
return &self->color_offset;
}
/*** GSK_REPEAT_NODE ***/
/* }}} */
/* {{{ GSK_REPEAT_NODE */
/**
* GskRepeatNode:
@@ -3542,7 +3740,8 @@ gsk_repeat_node_get_child_bounds (const GskRenderNode *node)
return &self->child_bounds;
}
/*** GSK_CLIP_NODE ***/
/* }}} */
/* {{{ GSK_CLIP_NODE */
/**
* GskClipNode:
@@ -3676,7 +3875,8 @@ gsk_clip_node_get_clip (const GskRenderNode *node)
return &self->clip;
}
/*** GSK_ROUNDED_CLIP_NODE ***/
/* }}} */
/* {{{ GSK_ROUNDED_CLIP_NODE */
/**
* GskRoundedClipNode:
@@ -3810,7 +4010,8 @@ gsk_rounded_clip_node_get_clip (const GskRenderNode *node)
return &self->clip;
}
/*** GSK_SHADOW_NODE ***/
/* }}} */
/* {{{ GSK_SHADOW_NODE */
/**
* GskShadowNode:
@@ -4050,7 +4251,8 @@ gsk_shadow_node_get_n_shadows (const GskRenderNode *node)
return self->n_shadows;
}
/*** GSK_BLEND_NODE ***/
/* }}} */
/* {{{ GSK_BLEND_NODE */
/**
* GskBlendNode:
@@ -4244,7 +4446,8 @@ gsk_blend_node_get_blend_mode (const GskRenderNode *node)
return self->blend_mode;
}
/*** GSK_CROSS_FADE_NODE ***/
/* }}} */
/* {{{ GSK_CROSS_FADE_NODE */
/**
* GskCrossFadeNode:
@@ -4395,7 +4598,8 @@ gsk_cross_fade_node_get_progress (const GskRenderNode *node)
return self->progress;
}
/*** GSK_TEXT_NODE ***/
/* }}} */
/* {{{ GSK_TEXT_NODE */
/**
* GskTextNode:
@@ -4660,7 +4864,8 @@ gsk_text_node_get_offset (const GskRenderNode *node)
return &self->offset;
}
/*** GSK_BLUR_NODE ***/
/* }}} */
/* {{{ GSK_BLUR_NODE */
/**
* GskBlurNode:
@@ -4979,7 +5184,137 @@ gsk_blur_node_get_radius (const GskRenderNode *node)
return self->radius;
}
/*** GSK_DEBUG_NODE ***/
/* }}} */
/* {{{ GSK_MASK_NODE */
/**
* GskMaskNode:
*
* A render node masking one child node with another.
*
* Since: 4.10
*/
typedef struct _GskMaskNode GskMaskNode;
struct _GskMaskNode
{
GskRenderNode render_node;
GskRenderNode *mask;
GskRenderNode *source;
};
static void
gsk_mask_node_finalize (GskRenderNode *node)
{
GskMaskNode *self = (GskMaskNode *) node;
gsk_render_node_unref (self->source);
gsk_render_node_unref (self->mask);
}
static void
gsk_mask_node_draw (GskRenderNode *node,
cairo_t *cr)
{
GskMaskNode *self = (GskMaskNode *) node;
cairo_pattern_t *mask_pattern;
cairo_push_group (cr);
gsk_render_node_draw (self->source, cr);
cairo_pop_group_to_source (cr);
cairo_push_group (cr);
gsk_render_node_draw (self->mask, cr);
mask_pattern = cairo_pop_group (cr);
cairo_mask (cr, mask_pattern);
}
static void
gsk_mask_node_diff (GskRenderNode *node1,
GskRenderNode *node2,
cairo_region_t *region)
{
GskMaskNode *self1 = (GskMaskNode *) node1;
GskMaskNode *self2 = (GskMaskNode *) node2;
gsk_render_node_diff (self1->source, self2->source, region);
gsk_render_node_diff (self1->mask, self2->mask, region);
}
/**
* gsk_mask_node_new:
* @source: The bottom node to be drawn
* @mask: The node to be blended onto the @bottom node
*
* Creates a `GskRenderNode` that will use @blend_mode to blend the @top
* node onto the @bottom node.
*
* Returns: (transfer full) (type GskMaskNode): A new `GskRenderNode`
*
* Since: 4.10
*/
GskRenderNode *
gsk_mask_node_new (GskRenderNode *source,
GskRenderNode *mask)
{
GskMaskNode *self;
g_return_val_if_fail (GSK_IS_RENDER_NODE (source), NULL);
g_return_val_if_fail (GSK_IS_RENDER_NODE (mask), NULL);
self = gsk_render_node_alloc (GSK_MASK_NODE);
self->source = gsk_render_node_ref (source);
self->mask = gsk_render_node_ref (mask);
graphene_rect_union (&source->bounds, &mask->bounds, &self->render_node.bounds);
return &self->render_node;
}
/**
* gsk_mask_node_get_source:
* @node: (type GskBlendNode): a mask `GskRenderNode`
*
* Retrieves the source `GskRenderNode` child of the @node.
*
* Returns: (transfer none): the source child node
*
* Since: 4.10
*/
GskRenderNode *
gsk_mask_node_get_source (const GskRenderNode *node)
{
const GskMaskNode *self = (const GskMaskNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_MASK_NODE), NULL);
return self->source;
}
/**
* gsk_mask_node_get_mask:
* @node: (type GskBlendNode): a mask `GskRenderNode`
*
* Retrieves the mask `GskRenderNode` child of the @node.
*
* Returns: (transfer none): the mask child node
*
* Since: 4.10
*/
GskRenderNode *
gsk_mask_node_get_mask (const GskRenderNode *node)
{
const GskMaskNode *self = (const GskMaskNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_MASK_NODE), NULL);
return self->mask;
}
/* }}} */
/* {{{ GSK_DEBUG_NODE */
/**
* GskDebugNode:
@@ -5104,7 +5439,8 @@ gsk_debug_node_get_message (const GskRenderNode *node)
return self->message;
}
/*** GSK_GL_SHADER_NODE ***/
/* }}} */
/* {{{ GSK_GL_SHADER_NODE */
/**
* GskGLShaderNode:
@@ -5309,6 +5645,8 @@ gsk_gl_shader_node_get_args (const GskRenderNode *node)
return self->args;
}
/* }}} */
GType gsk_render_node_types[GSK_RENDER_NODE_TYPE_N_TYPES];
#ifndef I_
@@ -5333,6 +5671,7 @@ GSK_DEFINE_RENDER_NODE_TYPE (gsk_repeating_radial_gradient_node, GSK_REPEATING_R
GSK_DEFINE_RENDER_NODE_TYPE (gsk_conic_gradient_node, GSK_CONIC_GRADIENT_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_border_node, GSK_BORDER_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_texture_node, GSK_TEXTURE_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_texture_scale_node, GSK_TEXTURE_SCALE_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_inset_shadow_node, GSK_INSET_SHADOW_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_outset_shadow_node, GSK_OUTSET_SHADOW_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_transform_node, GSK_TRANSFORM_NODE)
@@ -5346,6 +5685,7 @@ GSK_DEFINE_RENDER_NODE_TYPE (gsk_blend_node, GSK_BLEND_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_cross_fade_node, GSK_CROSS_FADE_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_text_node, GSK_TEXT_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_blur_node, GSK_BLUR_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_mask_node, GSK_MASK_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_gl_shader_node, GSK_GL_SHADER_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_debug_node, GSK_DEBUG_NODE)
@@ -5512,6 +5852,22 @@ gsk_render_node_init_types_once (void)
gsk_render_node_types[GSK_TEXTURE_NODE] = node_type;
}
{
const GskRenderNodeTypeInfo node_info =
{
GSK_TEXTURE_SCALE_NODE,
sizeof (GskTextureScaleNode),
NULL,
gsk_texture_scale_node_finalize,
gsk_texture_scale_node_draw,
NULL,
gsk_texture_scale_node_diff,
};
GType node_type = gsk_render_node_type_register_static (I_("GskTextureScaleNode"), &node_info);
gsk_render_node_types[GSK_TEXTURE_SCALE_NODE] = node_type;
}
{
const GskRenderNodeTypeInfo node_info =
{
@@ -5720,6 +6076,22 @@ gsk_render_node_init_types_once (void)
gsk_render_node_types[GSK_BLUR_NODE] = node_type;
}
{
const GskRenderNodeTypeInfo node_info =
{
GSK_MASK_NODE,
sizeof (GskMaskNode),
NULL,
gsk_mask_node_finalize,
gsk_mask_node_draw,
NULL,
gsk_mask_node_diff,
};
GType node_type = gsk_render_node_type_register_static (I_("GskMaskNode"), &node_info);
gsk_render_node_types[GSK_MASK_NODE] = node_type;
}
{
const GskRenderNodeTypeInfo node_info =
{
@@ -5884,3 +6256,5 @@ gsk_render_node_init_types (void)
g_once_init_leave (&register_types__volatile, initialized);
}
}
/* vim:set foldmethod=marker expandtab: */
+155
View File
@@ -600,6 +600,32 @@ clear_shadows (gpointer inout_shadows)
g_array_set_size (*(GArray **) inout_shadows, 0);
}
static const struct
{
GskScalingFilter filter;
const char *name;
} scaling_filters[] = {
{ GSK_SCALING_FILTER_LINEAR, "linear" },
{ GSK_SCALING_FILTER_NEAREST, "nearest" },
{ GSK_SCALING_FILTER_TRILINEAR, "trilinear" },
};
static gboolean
parse_scaling_filter (GtkCssParser *parser,
gpointer out_filter)
{
for (unsigned int i = 0; i < G_N_ELEMENTS (scaling_filters); i++)
{
if (gtk_css_parser_try_ident (parser, scaling_filters[i].name))
{
*(GskScalingFilter *) out_filter = scaling_filters[i].filter;
return TRUE;
}
}
return FALSE;
}
static const struct
{
GskBlendMode mode;
@@ -1350,6 +1376,31 @@ parse_glshader_node (GtkCssParser *parser)
return node;
}
static GskRenderNode *
parse_mask_node (GtkCssParser *parser)
{
GskRenderNode *source = NULL;
GskRenderNode *mask = NULL;
const Declaration declarations[] = {
{ "source", parse_node, clear_node, &source },
{ "mask", parse_node, clear_node, &mask },
};
GskRenderNode *result;
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
if (source == NULL)
source = create_default_render_node ();
if (mask == NULL)
mask = gsk_color_node_new (&GDK_RGBA("AAFF00"), &GRAPHENE_RECT_INIT (0, 0, 50, 50));
result = gsk_mask_node_new (source, mask);
gsk_render_node_unref (source);
gsk_render_node_unref (mask);
return result;
}
static GskRenderNode *
parse_border_node (GtkCssParser *parser)
{
@@ -1389,6 +1440,30 @@ parse_texture_node (GtkCssParser *parser)
return node;
}
static GskRenderNode *
parse_texture_scale_node (GtkCssParser *parser)
{
graphene_rect_t bounds = GRAPHENE_RECT_INIT (0, 0, 50, 50);
GdkTexture *texture = NULL;
GskScalingFilter filter = GSK_SCALING_FILTER_LINEAR;
const Declaration declarations[] = {
{ "bounds", parse_rect, NULL, &bounds },
{ "texture", parse_texture, clear_texture, &texture },
{ "filter", parse_scaling_filter, NULL, &filter }
};
GskRenderNode *node;
parse_declarations (parser, declarations, G_N_ELEMENTS (declarations));
if (texture == NULL)
texture = create_default_texture ();
node = gsk_texture_scale_node_new (texture, &bounds, filter);
g_object_unref (texture);
return node;
}
static GskRenderNode *
parse_cairo_node (GtkCssParser *parser)
{
@@ -1861,8 +1936,10 @@ parse_node (GtkCssParser *parser,
{ "shadow", parse_shadow_node },
{ "text", parse_text_node },
{ "texture", parse_texture_node },
{ "texture-scale", parse_texture_scale_node },
{ "transform", parse_transform_node },
{ "glshader", parse_glshader_node },
{ "mask", parse_mask_node },
};
GskRenderNode **node_p = out_node;
guint i;
@@ -2757,6 +2834,73 @@ render_node_print (Printer *p,
}
break;
case GSK_TEXTURE_SCALE_NODE:
{
GdkTexture *texture = gsk_texture_scale_node_get_texture (node);
GskScalingFilter filter = gsk_texture_scale_node_get_filter (node);
GBytes *bytes;
start_node (p, "texture-scale");
append_rect_param (p, "bounds", &node->bounds);
if (filter != GSK_SCALING_FILTER_LINEAR)
{
_indent (p);
for (unsigned int i = 0; i < G_N_ELEMENTS (scaling_filters); i++)
{
if (scaling_filters[i].filter == filter)
{
g_string_append_printf (p->str, "filter: %s;\n", scaling_filters[i].name);
break;
}
}
}
_indent (p);
switch (gdk_texture_get_format (texture))
{
case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
case GDK_MEMORY_B8G8R8A8:
case GDK_MEMORY_A8R8G8B8:
case GDK_MEMORY_R8G8B8A8:
case GDK_MEMORY_A8B8G8R8:
case GDK_MEMORY_R8G8B8:
case GDK_MEMORY_B8G8R8:
case GDK_MEMORY_R16G16B16:
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
case GDK_MEMORY_R16G16B16A16:
bytes = gdk_texture_save_to_png_bytes (texture);
g_string_append (p->str, "texture: url(\"data:image/png;base64,");
break;
case GDK_MEMORY_R16G16B16_FLOAT:
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
case GDK_MEMORY_R16G16B16A16_FLOAT:
case GDK_MEMORY_R32G32B32_FLOAT:
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
case GDK_MEMORY_R32G32B32A32_FLOAT:
bytes = gdk_texture_save_to_tiff_bytes (texture);
g_string_append (p->str, "texture: url(\"data:image/tiff;base64,");
break;
case GDK_MEMORY_N_FORMATS:
default:
g_assert_not_reached ();
}
b64 = base64_encode_with_linebreaks (g_bytes_get_data (bytes, NULL),
g_bytes_get_size (bytes));
append_escaping_newlines (p->str, b64);
g_free (b64);
g_string_append (p->str, "\");\n");
end_node (p);
g_bytes_unref (bytes);
}
break;
case GSK_TEXT_NODE:
{
const graphene_point_t *offset = gsk_text_node_get_offset (node);
@@ -2982,6 +3126,17 @@ render_node_print (Printer *p,
}
break;
case GSK_MASK_NODE:
{
start_node (p, "mask");
append_node_param (p, "source", gsk_mask_node_get_source (node));
append_node_param (p, "mask", gsk_mask_node_get_mask (node));
end_node (p);
}
break;
case GSK_NOT_A_RENDER_NODE:
g_assert_not_reached ();
break;
+1
View File
@@ -19,6 +19,7 @@ gsk_private_gl_shaders = [
'gl/resources/repeat.glsl',
'gl/resources/custom.glsl',
'gl/resources/filled_border.glsl',
'gl/resources/mask.glsl',
]
gsk_public_sources = files([
+6
View File
@@ -440,6 +440,9 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
g_array_append_val (self->render_ops, op);
return;
case GSK_TEXTURE_SCALE_NODE:
goto fallback;
case GSK_COLOR_NODE:
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
pipeline_type = GSK_VULKAN_PIPELINE_COLOR;
@@ -501,6 +504,9 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
g_array_append_val (self->render_ops, op);
return;
case GSK_MASK_NODE:
goto fallback;
case GSK_COLOR_MATRIX_NODE:
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX;
@@ -35,6 +35,8 @@
#include "gtkprivate.h"
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
/**
* GtkVolumeButton:
*
@@ -49,7 +49,7 @@ struct _GtkVolumeButton
GDK_AVAILABLE_IN_ALL
GType gtk_volume_button_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GDK_DEPRECATED_IN_4_10
GtkWidget* gtk_volume_button_new (void);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkVolumeButton, g_object_unref)
+2
View File
@@ -49,6 +49,7 @@ gtk_deprecated_sources = [
'deprecated/gtktreepopover.c',
'deprecated/gtktreeview.c',
'deprecated/gtktreeviewcolumn.c',
'deprecated/gtkvolumebutton.c',
]
gtk_deprecated_headers = [
@@ -106,4 +107,5 @@ gtk_deprecated_headers = [
'deprecated/gtktreestore.h',
'deprecated/gtktreeview.h',
'deprecated/gtktreeviewcolumn.h',
'deprecated/gtkvolumebutton.h',
]
-52
View File
@@ -1,52 +0,0 @@
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright 2017 Red Hat, Inc.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* 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.1 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 __G_OPEN_URI_PORTAL_H__
#include "gtkwindow.h"
#include <glib.h>
#include <gio/gio.h>
G_BEGIN_DECLS
gboolean g_openuri_portal_is_available (void);
void g_openuri_portal_open_async (GFile *file,
gboolean open_folder,
GtkWindow *window,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean g_openuri_portal_open_finish (GAsyncResult *result,
GError **error);
void g_openuri_portal_open_uri_async (const char *uri,
GtkWindow *window,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean g_openuri_portal_open_uri_finish (GAsyncResult *result,
GError **error);
G_END_DECLS
#endif
+1 -1
View File
@@ -290,7 +290,7 @@
#include <gtk/gtkversion.h>
#include <gtk/gtkvideo.h>
#include <gtk/gtkviewport.h>
#include <gtk/gtkvolumebutton.h>
#include <gtk/deprecated/gtkvolumebutton.h>
#include <gtk/gtkwidget.h>
#include <gtk/gtkwidgetpaintable.h>
#include <gtk/gtkwindow.h>
+10 -3
View File
@@ -72,6 +72,8 @@ struct _GtkEditableLabel
GtkWidget *stack;
GtkWidget *label;
GtkWidget *entry;
guint stop_editing_soon_id;
};
struct _GtkEditableLabelClass
@@ -196,10 +198,12 @@ static gboolean
stop_editing_soon (gpointer data)
{
GtkEventController *controller = data;
GtkWidget *widget = gtk_event_controller_get_widget (controller);
GtkEditableLabel *self = GTK_EDITABLE_LABEL (gtk_event_controller_get_widget (controller));
if (!gtk_event_controller_focus_contains_focus (GTK_EVENT_CONTROLLER_FOCUS (controller)))
gtk_editable_label_stop_editing (GTK_EDITABLE_LABEL (widget), TRUE);
gtk_editable_label_stop_editing (self, TRUE);
self->stop_editing_soon_id = 0;
return FALSE;
}
@@ -208,7 +212,8 @@ static void
gtk_editable_label_focus_out (GtkEventController *controller,
GtkEditableLabel *self)
{
g_timeout_add (100, stop_editing_soon, controller);
if (self->stop_editing_soon_id == 0)
self->stop_editing_soon_id = g_timeout_add (100, stop_editing_soon, controller);
}
static void
@@ -361,6 +366,8 @@ gtk_editable_label_dispose (GObject *object)
self->entry = NULL;
self->label = NULL;
g_clear_handle_id (&self->stop_editing_soon_id, g_source_remove);
G_OBJECT_CLASS (gtk_editable_label_parent_class)->dispose (object);
}
+1 -1
View File
@@ -207,7 +207,7 @@ send_close (FilechooserPortalData *data)
message = g_dbus_message_new_method_call (PORTAL_BUS_NAME,
PORTAL_OBJECT_PATH,
PORTAL_FILECHOOSER_INTERFACE,
PORTAL_REQUEST_INTERFACE,
"Close");
g_dbus_message_set_body (message,
g_variant_new ("(o)", data->portal_handle));
+1 -1
View File
@@ -96,7 +96,7 @@
#include "gtkexpression.h"
#ifndef G_OS_WIN32
#include "gopenuriportal.h"
#include "gtkopenuriportal.h"
#endif
#include <cairo-gobject.h>
+3 -3
View File
@@ -694,7 +694,7 @@ gtk_file_dialog_set_initial_file (GtkFileDialog *self,
GFile *folder;
GFileInfo *info;
if (g_file_equal (self->initial_file, file))
if (self->initial_file && g_file_equal (self->initial_file, file))
return;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INITIAL_FILE]);
@@ -707,7 +707,7 @@ gtk_file_dialog_set_initial_file (GtkFileDialog *self,
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INITIAL_FOLDER]);
info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME, 0, NULL, NULL);
if (g_file_info_get_edit_name (info) != NULL)
if (info && g_file_info_get_edit_name (info) != NULL)
{
if (g_set_str (&self->initial_name, g_file_info_get_edit_name (info)))
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INITIAL_NAME]);
@@ -724,7 +724,7 @@ gtk_file_dialog_set_initial_file (GtkFileDialog *self,
g_free (name);
g_free (relative);
}
g_object_unref (info);
g_clear_object (&info);
g_object_unref (folder);
}
else
+6 -6
View File
@@ -22,7 +22,7 @@
#include "gtkfilelauncher.h"
#include "gtkdialogerror.h"
#include "gopenuriportal.h"
#include "gtkopenuriportal.h"
#include "deprecated/gtkshow.h"
#include <glib/gi18n-lib.h>
@@ -219,7 +219,7 @@ open_done (GObject *source,
GTask *task = G_TASK (data);
GError *error = NULL;
if (!g_openuri_portal_open_finish (result, &error))
if (!gtk_openuri_portal_open_finish (result, &error))
g_task_return_error (task, error);
else
g_task_return_boolean (task, TRUE);
@@ -367,9 +367,9 @@ gtk_file_launcher_launch (GtkFileLauncher *self,
}
#ifndef G_OS_WIN32
if (g_openuri_portal_is_available ())
if (gtk_openuri_portal_is_available ())
{
g_openuri_portal_open_async (self->file, FALSE, parent, cancellable, open_done, task);
gtk_openuri_portal_open_async (self->file, FALSE, parent, cancellable, open_done, task);
}
else
#endif
@@ -461,9 +461,9 @@ gtk_file_launcher_open_containing_folder (GtkFileLauncher *self,
}
#ifndef G_OS_WIN32
if (g_openuri_portal_is_available ())
if (gtk_openuri_portal_is_available ())
{
g_openuri_portal_open_async (self->file, TRUE, parent, cancellable, open_done, task);
gtk_openuri_portal_open_async (self->file, TRUE, parent, cancellable, open_done, task);
}
else
#endif
+12 -5
View File
@@ -32,6 +32,7 @@
#include "gtksnapshot.h"
#include "gtkrenderlayoutprivate.h"
#include "gtkcssnodeprivate.h"
#include "gdk/gdkgltextureprivate.h"
#include <epoxy/gl.h>
@@ -144,6 +145,7 @@
typedef struct {
guint id;
GLsync sync;
int width;
int height;
GdkTexture *holder;
@@ -394,6 +396,8 @@ delete_one_texture (gpointer data)
texture->id = 0;
}
g_clear_pointer (&texture->sync, glDeleteSync);
g_free (texture);
}
@@ -673,6 +677,7 @@ release_texture (gpointer data)
{
Texture *texture = data;
texture->holder = NULL;
g_clear_pointer (&texture->sync, glDeleteSync);
}
static void
@@ -735,11 +740,13 @@ gtk_gl_area_snapshot (GtkWidget *widget,
priv->texture = NULL;
priv->textures = g_list_prepend (priv->textures, texture);
texture->holder = gdk_gl_texture_new (priv->context,
texture->id,
texture->width,
texture->height,
release_texture, texture);
texture->sync = glFenceSync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
texture->holder = gdk_gl_texture_new_with_sync (priv->context,
texture->id,
texture->sync,
texture->width,
texture->height,
release_texture, texture);
/* Our texture is rendered by OpenGL, so it is upside down,
* compared to what GSK expects, so flip it back.
+33 -33
View File
@@ -26,7 +26,7 @@
#include <string.h>
#include <glib/gstdio.h>
#include "gopenuriportal.h"
#include "gtkopenuriportal.h"
#include "xdp-dbus.h"
#include "gtkwindowprivate.h"
#include "gtkprivate.h"
@@ -43,7 +43,7 @@
#endif
static GXdpOpenURI *openuri;
static GtkXdpOpenURI *openuri;
static gboolean
init_openuri_portal (void)
@@ -57,10 +57,10 @@ init_openuri_portal (void)
if (connection != NULL)
{
openuri = gxdp_open_uri_proxy_new_sync (connection, 0,
PORTAL_BUS_NAME,
PORTAL_OBJECT_PATH,
NULL, &error);
openuri = gtk_xdp_open_uri_proxy_new_sync (connection, 0,
PORTAL_BUS_NAME,
PORTAL_OBJECT_PATH,
NULL, &error);
if (openuri == NULL)
{
g_warning ("Cannot create OpenURI portal proxy: %s", error->message);
@@ -83,7 +83,7 @@ init_openuri_portal (void)
}
gboolean
g_openuri_portal_is_available (void)
gtk_openuri_portal_is_available (void)
{
return init_openuri_portal ();
}
@@ -169,7 +169,7 @@ open_call_done (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
GXdpOpenURI *portal = GXDP_OPEN_URI (source);
GtkXdpOpenURI *portal = GTK_XDP_OPEN_URI (source);
GTask *task = user_data;
OpenUriData *data = g_task_get_task_data (task);
GError *error = NULL;
@@ -179,13 +179,13 @@ open_call_done (GObject *source,
switch (data->call)
{
case OPEN_FILE:
res = gxdp_open_uri_call_open_file_finish (portal, &path, NULL, result, &error);
res = gtk_xdp_open_uri_call_open_file_finish (portal, &path, NULL, result, &error);
break;
case OPEN_FOLDER:
res = gxdp_open_uri_call_open_directory_finish (portal, &path, NULL, result, &error);
res = gtk_xdp_open_uri_call_open_directory_finish (portal, &path, NULL, result, &error);
break;
case OPEN_URI:
res = gxdp_open_uri_call_open_uri_finish (portal, &path, result, &error);
res = gtk_xdp_open_uri_call_open_uri_finish (portal, &path, result, &error);
break;
default:
g_assert_not_reached ();
@@ -341,7 +341,7 @@ open_uri (OpenUriData *data,
if (open_folder)
{
data->call = OPEN_FOLDER;
gxdp_open_uri_call_open_directory (openuri,
gtk_xdp_open_uri_call_open_directory (openuri,
parent_window ? parent_window : "",
g_variant_new ("h", fd_id),
opts,
@@ -353,7 +353,7 @@ open_uri (OpenUriData *data,
else
{
data->call = OPEN_FILE;
gxdp_open_uri_call_open_file (openuri,
gtk_xdp_open_uri_call_open_file (openuri,
parent_window ? parent_window : "",
g_variant_new ("h", fd_id),
opts,
@@ -373,7 +373,7 @@ open_uri (OpenUriData *data,
uri = g_file_get_uri (file);
data->call = OPEN_URI;
gxdp_open_uri_call_open_uri (openuri,
gtk_xdp_open_uri_call_open_uri (openuri,
parent_window ? parent_window : "",
uri ? uri : data->uri,
opts,
@@ -441,12 +441,12 @@ window_handle_exported (GtkWindow *window,
}
void
g_openuri_portal_open_async (GFile *file,
gboolean open_folder,
GtkWindow *parent,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
gtk_openuri_portal_open_async (GFile *file,
gboolean open_folder,
GtkWindow *parent,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
OpenUriData *data;
@@ -465,27 +465,27 @@ g_openuri_portal_open_async (GFile *file,
data->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
data->task = g_task_new (parent, cancellable, callback, user_data);
g_task_set_check_cancellable (data->task, FALSE);
g_task_set_source_tag (data->task, g_openuri_portal_open_async);
g_task_set_source_tag (data->task, gtk_openuri_portal_open_async);
if (!parent || !gtk_window_export_handle (parent, window_handle_exported, data))
window_handle_exported (parent, NULL, data);
}
gboolean
g_openuri_portal_open_finish (GAsyncResult *result,
GError **error)
gtk_openuri_portal_open_finish (GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == g_openuri_portal_open_async, FALSE);
g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == gtk_openuri_portal_open_async, FALSE);
return g_task_propagate_boolean (G_TASK (result), error);
}
void
g_openuri_portal_open_uri_async (const char *uri,
GtkWindow *parent,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
gtk_openuri_portal_open_uri_async (const char *uri,
GtkWindow *parent,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
OpenUriData *data;
@@ -503,17 +503,17 @@ g_openuri_portal_open_uri_async (const char *uri,
data->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
data->task = g_task_new (parent, cancellable, callback, user_data);
g_task_set_check_cancellable (data->task, FALSE);
g_task_set_source_tag (data->task, g_openuri_portal_open_uri_async);
g_task_set_source_tag (data->task, gtk_openuri_portal_open_uri_async);
if (!parent || !gtk_window_export_handle (parent, window_handle_exported, data))
window_handle_exported (parent, NULL, data);
}
gboolean
g_openuri_portal_open_uri_finish (GAsyncResult *result,
GError **error)
gtk_openuri_portal_open_uri_finish (GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == g_openuri_portal_open_uri_async, FALSE);
g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == gtk_openuri_portal_open_uri_async, FALSE);
return g_task_propagate_boolean (G_TASK (result), error);
}
+52
View File
@@ -0,0 +1,52 @@
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright 2017 Red Hat, Inc.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* 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.1 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 __G_OPEN_URI_PORTAL_H__
#include "gtkwindow.h"
#include <glib.h>
#include <gio/gio.h>
G_BEGIN_DECLS
gboolean gtk_openuri_portal_is_available (void);
void gtk_openuri_portal_open_async (GFile *file,
gboolean open_folder,
GtkWindow *window,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean gtk_openuri_portal_open_finish (GAsyncResult *result,
GError **error);
void gtk_openuri_portal_open_uri_async (const char *uri,
GtkWindow *window,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean gtk_openuri_portal_open_uri_finish (GAsyncResult *result,
GError **error);
G_END_DECLS
#endif
+7
View File
@@ -36,6 +36,13 @@
*
* `GtkOrientable` is more flexible in that it allows the orientation to be
* changed at runtime, allowing the widgets to flip.
*
* ## CSS nodes
*
* `GtkWidget` types implementing the `GtkOrientable` interface will
* automatically acquire the `horizontal` or `vertical` CSS class depending on
* the value of the [property@Gtk.Orientable:orientation] property.
*/
+41 -1
View File
@@ -95,7 +95,8 @@ enum
PROP_VALUE,
PROP_SIZE,
PROP_ADJUSTMENT,
PROP_ICONS
PROP_ICONS,
PROP_ACTIVE
};
typedef struct
@@ -256,6 +257,17 @@ gtk_scale_button_class_init (GtkScaleButtonClass *klass)
G_TYPE_STRV,
GTK_PARAM_READWRITE));
/**
* GtkScaleButton:active: (attributes org.gtk.Property.get=gtk_scale_button_get_active)
*
* If the scale button should be pressed in.
*/
g_object_class_install_property (gobject_class,
PROP_ACTIVE,
g_param_spec_boolean ("active", NULL, NULL,
FALSE,
GTK_PARAM_READABLE));
/**
* GtkScaleButton::value-changed:
* @button: the object which received the signal
@@ -394,6 +406,8 @@ gtk_scale_button_toggled (GtkScaleButton *button)
GtkScaleButtonPrivate *priv = gtk_scale_button_get_instance_private (button);
gboolean active;
g_object_notify (G_OBJECT (button), "active");
active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->button));
if (active)
@@ -515,6 +529,9 @@ gtk_scale_button_get_property (GObject *object,
case PROP_ICONS:
g_value_set_boxed (value, priv->icon_list);
break;
case PROP_ACTIVE:
g_value_set_boolean (value, gtk_scale_button_get_active (button));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -768,6 +785,29 @@ gtk_scale_button_get_popup (GtkScaleButton *button)
return priv->dock;
}
/**
* gtk_scale_button_get_active: (attributes org.gtk.Method.get_property=active)
* @button: a `GtkScaleButton`
*
* Queries a `GtkScaleButton` and returns its current state.
*
* Returns %TRUE if the scale button is pressed in and %FALSE
* if it is raised.
*
* Returns: whether the button is pressed
*
* Since: 4.10
*/
gboolean
gtk_scale_button_get_active (GtkScaleButton *button)
{
GtkScaleButtonPrivate *priv = gtk_scale_button_get_instance_private (button);
g_return_val_if_fail (GTK_IS_SCALE_BUTTON (button), FALSE);
return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->button));
}
static void
gtk_scale_button_set_orientation_private (GtkScaleButton *button,
GtkOrientation orientation)
+2
View File
@@ -96,6 +96,8 @@ GDK_AVAILABLE_IN_ALL
GtkWidget * gtk_scale_button_get_minus_button (GtkScaleButton *button);
GDK_AVAILABLE_IN_ALL
GtkWidget * gtk_scale_button_get_popup (GtkScaleButton *button);
GDK_AVAILABLE_IN_4_10
gboolean gtk_scale_button_get_active (GtkScaleButton *button);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkScaleButton, g_object_unref)
+7 -4
View File
@@ -97,8 +97,11 @@ finalize (GObject *object)
g_clear_object (&engine->search_query);
g_clear_object (&engine->search_location_query);
tracker_sparql_connection_close (engine->sparql_conn);
g_clear_object (&engine->sparql_conn);
if (engine->sparql_conn != NULL)
{
tracker_sparql_connection_close (engine->sparql_conn);
g_clear_object (&engine->sparql_conn);
}
G_OBJECT_CLASS (gtk_search_engine_tracker3_parent_class)->finalize (object);
}
@@ -369,8 +372,8 @@ gtk_search_engine_tracker3_new (void)
NULL, &error, NULL);
if (!engine)
{
g_critical ("Could not init tracker3 search engine: %s",
error->message);
g_warning ("Could not init tracker3 search engine: %s",
error->message);
g_error_free (error);
}
+118
View File
@@ -121,6 +121,9 @@ struct _GtkSnapshotState {
struct {
char *message;
} debug;
struct {
GskRenderNode *mask_node;
} mask;
} data;
};
@@ -1241,6 +1244,79 @@ gtk_snapshot_push_blend (GtkSnapshot *snapshot,
NULL);
}
static GskRenderNode *
gtk_snapshot_collect_mask_source (GtkSnapshot *snapshot,
GtkSnapshotState *state,
GskRenderNode **nodes,
guint n_nodes)
{
GskRenderNode *source_child, *mask_child, *mask_node;
mask_child = gsk_render_node_ref (state->data.mask.mask_node);
source_child = gtk_snapshot_collect_default (snapshot, state, nodes, n_nodes);
if (source_child == NULL || mask_child == NULL)
return NULL;
mask_node = gsk_mask_node_new (source_child, mask_child);
gsk_render_node_unref (source_child);
gsk_render_node_unref (mask_child);
return mask_node;
}
static void
gtk_snapshot_clear_mask_source (GtkSnapshotState *state)
{
g_clear_pointer (&(state->data.mask.mask_node), gsk_render_node_unref);
}
static GskRenderNode *
gtk_snapshot_collect_mask_mask (GtkSnapshot *snapshot,
GtkSnapshotState *state,
GskRenderNode **nodes,
guint n_nodes)
{
GtkSnapshotState *prev_state = gtk_snapshot_get_previous_state (snapshot);
g_assert (prev_state->collect_func == gtk_snapshot_collect_mask_source);
prev_state->data.mask.mask_node = gtk_snapshot_collect_default (snapshot, state, nodes, n_nodes);
return NULL;
}
/**
* gtk_snapshot_push_mask:
* @snapshot: a #GtkSnapshot
*
* Until the first call to [method@Gtk.Snapshot.pop], the
* mask image for the mask operation will be recorded.
* After that call, the source image will be recorded until
* the second call to [method@Gtk.Snapshot.pop].
*
* Calling this function requires 2 subsequent calls to gtk_snapshot_pop().
*
* Since: 4.10
*/
void
gtk_snapshot_push_mask (GtkSnapshot *snapshot)
{
GtkSnapshotState *current_state = gtk_snapshot_get_current_state (snapshot);
GtkSnapshotState *source_state;
source_state = gtk_snapshot_push_state (snapshot,
current_state->transform,
gtk_snapshot_collect_mask_source,
gtk_snapshot_clear_mask_source);
gtk_snapshot_push_state (snapshot,
source_state->transform,
gtk_snapshot_collect_mask_mask,
NULL);
}
static GskRenderNode *
gtk_snapshot_collect_cross_fade_end (GtkSnapshot *snapshot,
GtkSnapshotState *state,
@@ -1918,6 +1994,10 @@ gtk_snapshot_append_cairo (GtkSnapshot *snapshot,
* Creates a new render node drawing the @texture
* into the given @bounds and appends it to the
* current render node of @snapshot.
*
* If the texture needs to be scaled to fill @bounds,
* linear filtering is used. See [method@Gtk.Snapshot.append_scaled_texture]
* if you need other filtering, such as nearest-neighbour.
*/
void
gtk_snapshot_append_texture (GtkSnapshot *snapshot,
@@ -1939,6 +2019,44 @@ gtk_snapshot_append_texture (GtkSnapshot *snapshot,
gtk_snapshot_append_node_internal (snapshot, node);
}
/**
* gtk_snapshot_append_scaled_texture:
* @snapshot: a `GtkSnapshot`
* @texture: the texture to render
* @filter: the filter to use
* @bounds: the bounds for the new node
*
* Creates a new render node drawing the @texture
* into the given @bounds and appends it to the
* current render node of @snapshot.
*
* In contrast to [method@Gtk.Snapshot.append_texture],
* this function provides control about how the filter
* that is used when scaling.
*
* Since: 4.10
*/
void
gtk_snapshot_append_scaled_texture (GtkSnapshot *snapshot,
GdkTexture *texture,
GskScalingFilter filter,
const graphene_rect_t *bounds)
{
GskRenderNode *node;
graphene_rect_t real_bounds;
float scale_x, scale_y, dx, dy;
g_return_if_fail (snapshot != NULL);
g_return_if_fail (GDK_IS_TEXTURE (texture));
g_return_if_fail (bounds != NULL);
gtk_snapshot_ensure_affine (snapshot, &scale_x, &scale_y, &dx, &dy);
gtk_graphene_rect_scale_affine (bounds, scale_x, scale_y, dx, dy, &real_bounds);
node = gsk_texture_scale_node_new (texture, &real_bounds, filter);
gtk_snapshot_append_node_internal (snapshot, node);
}
/**
* gtk_snapshot_append_color:
* @snapshot: a `GtkSnapshot`
+8
View File
@@ -95,6 +95,9 @@ void gtk_snapshot_push_shadow (GtkSnapshot
GDK_AVAILABLE_IN_ALL
void gtk_snapshot_push_blend (GtkSnapshot *snapshot,
GskBlendMode blend_mode);
GDK_AVAILABLE_IN_4_10
void gtk_snapshot_push_mask (GtkSnapshot *snapshot);
GDK_AVAILABLE_IN_ALL
void gtk_snapshot_push_cross_fade (GtkSnapshot *snapshot,
double progress);
@@ -152,6 +155,11 @@ GDK_AVAILABLE_IN_ALL
void gtk_snapshot_append_texture (GtkSnapshot *snapshot,
GdkTexture *texture,
const graphene_rect_t *bounds);
GDK_AVAILABLE_IN_4_10
void gtk_snapshot_append_scaled_texture (GtkSnapshot *snapshot,
GdkTexture *texture,
GskScalingFilter filter,
const graphene_rect_t *bounds);
GDK_AVAILABLE_IN_ALL
void gtk_snapshot_append_color (GtkSnapshot *snapshot,
const GdkRGBA *color,
+4 -4
View File
@@ -22,7 +22,7 @@
#include "gtkurilauncher.h"
#include "gtkdialogerror.h"
#include "gopenuriportal.h"
#include "gtkopenuriportal.h"
#include "deprecated/gtkshow.h"
#include <glib/gi18n-lib.h>
@@ -221,7 +221,7 @@ open_done (GObject *source,
GTask *task = G_TASK (data);
GError *error = NULL;
if (!g_openuri_portal_open_uri_finish (result, &error))
if (!gtk_openuri_portal_open_uri_finish (result, &error))
g_task_return_error (task, error);
else
g_task_return_boolean (task, TRUE);
@@ -300,8 +300,8 @@ gtk_uri_launcher_launch (GtkUriLauncher *self,
}
#ifndef G_OS_WIN32
if (g_openuri_portal_is_available ())
g_openuri_portal_open_uri_async (self->uri, parent, cancellable, open_done, task);
if (gtk_openuri_portal_is_available ())
gtk_openuri_portal_open_uri_async (self->uri, parent, cancellable, open_done, task);
else
#endif
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+47 -25
View File
@@ -7442,6 +7442,7 @@ gtk_widget_real_destroy (GtkWidget *object)
{
GtkWidgetClass *class;
GSList *l;
GHashTable *auto_children;
#ifdef G_ENABLE_CONSISTENCY_CHECKS
GSList *assertions = NULL;
@@ -7490,8 +7491,52 @@ gtk_widget_real_destroy (GtkWidget *object)
}
#endif /* G_ENABLE_CONSISTENCY_CHECKS */
/* Release references to all automated children */
g_object_set_qdata (G_OBJECT (widget), quark_auto_children, NULL);
/* Prepare to release references to all automated children */
auto_children = g_object_steal_qdata (G_OBJECT (widget), quark_auto_children);
/* Set any automatic private data pointers to NULL and release child references */
for (class = GTK_WIDGET_GET_CLASS (widget);
GTK_IS_WIDGET_CLASS (class);
class = g_type_class_peek_parent (class))
{
GHashTable *auto_child_hash = NULL;
if (!class->priv->template)
continue;
if (auto_children)
{
GType type = G_TYPE_FROM_CLASS (class);
g_hash_table_steal_extended (auto_children,
GSIZE_TO_POINTER (type),
NULL,
(gpointer *) &auto_child_hash);
}
for (l = class->priv->template->children; l; l = l->next)
{
AutomaticChildClass *child_class = l->data;
if (child_class->offset != 0)
{
gpointer field_p;
/* Nullify instance private data for internal children */
field_p = G_STRUCT_MEMBER_P (widget, child_class->offset);
(* (gpointer *) field_p) = NULL;
}
/* Release the references in order after setting the pointer to NULL */
if (auto_child_hash)
g_hash_table_remove (auto_child_hash, child_class->name);
}
g_clear_pointer (&auto_child_hash, g_hash_table_unref);
}
/* Free the child reference hash table */
g_clear_pointer (&auto_children, g_hash_table_unref);
#ifdef G_ENABLE_CONSISTENCY_CHECKS
for (l = assertions; l; l = l->next)
@@ -7509,29 +7554,6 @@ gtk_widget_real_destroy (GtkWidget *object)
}
g_slist_free (assertions);
#endif /* G_ENABLE_CONSISTENCY_CHECKS */
/* Set any automatic private data pointers to NULL */
for (class = GTK_WIDGET_GET_CLASS (widget);
GTK_IS_WIDGET_CLASS (class);
class = g_type_class_peek_parent (class))
{
if (!class->priv->template)
continue;
for (l = class->priv->template->children; l; l = l->next)
{
AutomaticChildClass *child_class = l->data;
if (child_class->offset != 0)
{
gpointer field_p;
/* Nullify instance private data for internal children */
field_p = G_STRUCT_MEMBER_P (widget, child_class->offset);
(* (gpointer *) field_p) = NULL;
}
}
}
}
/* Callers of add_mnemonic_label() should disconnect on ::destroy */
+30
View File
@@ -264,6 +264,7 @@ create_list_model_for_render_node (GskRenderNode *node)
case GSK_CAIRO_NODE:
case GSK_TEXT_NODE:
case GSK_TEXTURE_NODE:
case GSK_TEXTURE_SCALE_NODE:
case GSK_COLOR_NODE:
case GSK_LINEAR_GRADIENT_NODE:
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
@@ -304,6 +305,10 @@ create_list_model_for_render_node (GskRenderNode *node)
return create_render_node_list_model ((GskRenderNode *[2]) { gsk_blend_node_get_bottom_child (node),
gsk_blend_node_get_top_child (node) }, 2);
case GSK_MASK_NODE:
return create_render_node_list_model ((GskRenderNode *[2]) { gsk_mask_node_get_source (node),
gsk_mask_node_get_mask (node) }, 2);
case GSK_CROSS_FADE_NODE:
return create_render_node_list_model ((GskRenderNode *[2]) { gsk_cross_fade_node_get_start_child (node),
gsk_cross_fade_node_get_end_child (node) }, 2);
@@ -402,6 +407,8 @@ node_type_name (GskRenderNodeType type)
return "Border";
case GSK_TEXTURE_NODE:
return "Texture";
case GSK_TEXTURE_SCALE_NODE:
return "Scaled Texture";
case GSK_INSET_SHADOW_NODE:
return "Inset Shadow";
case GSK_OUTSET_SHADOW_NODE:
@@ -422,6 +429,8 @@ node_type_name (GskRenderNodeType type)
return "Shadow";
case GSK_BLEND_NODE:
return "Blend";
case GSK_MASK_NODE:
return "Mask";
case GSK_CROSS_FADE_NODE:
return "CrossFade";
case GSK_TEXT_NODE:
@@ -459,6 +468,7 @@ node_name (GskRenderNode *node)
case GSK_ROUNDED_CLIP_NODE:
case GSK_SHADOW_NODE:
case GSK_BLEND_NODE:
case GSK_MASK_NODE:
case GSK_CROSS_FADE_NODE:
case GSK_TEXT_NODE:
case GSK_BLUR_NODE:
@@ -476,6 +486,11 @@ node_name (GskRenderNode *node)
GdkTexture *texture = gsk_texture_node_get_texture (node);
return g_strdup_printf ("%dx%d Texture", gdk_texture_get_width (texture), gdk_texture_get_height (texture));
}
case GSK_TEXTURE_SCALE_NODE:
{
GdkTexture *texture = gsk_texture_node_get_texture (node);
return g_strdup_printf ("%dx%d Texture, Filter %d", gdk_texture_get_width (texture), gdk_texture_get_height (texture), gsk_texture_scale_node_get_filter (node));
}
}
}
@@ -933,6 +948,18 @@ populate_render_node_properties (GListStore *store,
}
break;
case GSK_TEXTURE_SCALE_NODE:
{
GdkTexture *texture = g_object_ref (gsk_texture_scale_node_get_texture (node));
GskScalingFilter filter = gsk_texture_scale_node_get_filter (node);
g_list_store_append (store, object_property_new ("Texture", "", texture));
tmp = g_enum_to_string (GSK_TYPE_SCALING_FILTER, filter);
add_text_row (store, "Filter", tmp);
g_free (tmp);
}
break;
case GSK_COLOR_NODE:
add_color_row (store, "Color", gsk_color_node_get_color (node));
break;
@@ -1112,6 +1139,9 @@ populate_render_node_properties (GListStore *store,
}
break;
case GSK_MASK_NODE:
break;
case GSK_BLUR_NODE:
add_float_row (store, "Radius", gsk_blur_node_get_radius (node));
break;
+2 -4
View File
@@ -391,7 +391,6 @@ gtk_public_sources = files([
'gtkversion.c',
'gtkvideo.c',
'gtkviewport.c',
'gtkvolumebutton.c',
'gtkwidget.c',
'gtkwidgetfocus.c',
'gtkwidgetpaintable.c',
@@ -613,7 +612,6 @@ gtk_public_headers = files([
'gtkurilauncher.h',
'gtkvideo.h',
'gtkviewport.h',
'gtkvolumebutton.h',
'gtkwidget.h',
'gtkwidgetpaintable.h',
'gtkwindow.h',
@@ -758,7 +756,7 @@ if not (x11_enabled or win32_enabled)
endif
if not os_win32
gtk_sources += ['gopenuriportal.c', ]
gtk_sources += ['gtkopenuriportal.c', ]
endif
gen_gtk_gresources_xml = find_program('gen-gtk-gresources-xml.py')
@@ -991,7 +989,7 @@ else
xdp_dbus_generated = gnome.gdbus_codegen('xdp-dbus',
sources : 'org.freedesktop.portal.OpenURI.xml',
interface_prefix : 'org.freedesktop.portal.',
namespace : 'GXdp',
namespace : 'GtkXdp',
)
endif
+1 -1
View File
@@ -1,5 +1,5 @@
project('gtk', 'c',
version: '4.9.3',
version: '4.9.4',
default_options: [
'buildtype=debugoptimized',
'warning_level=1',
+5
View File
@@ -41,6 +41,11 @@ option('media-gstreamer',
# Print backends
option('print-cpdb',
type: 'feature',
value: 'disabled',
description : 'Build the cpdb print backend')
option('print-cups',
type: 'feature',
value: 'auto',
+15 -9
View File
@@ -21,6 +21,7 @@
#include "config.h"
#include "gtkgstsinkprivate.h"
#include "gdkgltextureprivate.h"
#include "gtkgstpaintableprivate.h"
@@ -290,17 +291,22 @@ gtk_gst_sink_texture_from_buffer (GtkGstSink *self,
GstGLSyncMeta *sync_meta;
sync_meta = gst_buffer_get_gl_sync_meta (buffer);
if (sync_meta) {
if (sync_meta)
gst_gl_sync_meta_set_sync_point (sync_meta, self->gst_context);
gst_gl_sync_meta_wait (sync_meta, self->gst_gdk_context);
}
texture = gdk_gl_texture_new (self->gdk_context,
*(guint *) frame->data[0],
frame->info.width,
frame->info.height,
(GDestroyNotify) video_frame_free,
frame);
/* Note: using the gdk_context here is a (harmless) lie,
* since the texture really originates in the gst_context.
* But that is not a GdkGLContext. It is harmless, because
* we are never using the texture in the gdk_context, so we
* never make the (erroneous) decision to ignore the sync.
*/
texture = gdk_gl_texture_new_with_sync (self->gdk_context,
*(guint *) frame->data[0],
sync_meta ? sync_meta->data : NULL,
frame->info.width,
frame->info.height,
(GDestroyNotify) video_frame_free,
frame);
*pixel_aspect_ratio = ((double) frame->info.par_n) / ((double) frame->info.par_d);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,43 @@
/* GTK - The GIMP Toolkit
* gtkprintbackendcpdb.h: Default implementation of GtkPrintBackend
* for the Common Print Dialog Backends (CPDB)
* Copyright (C) 2022, 2023 TinyTrebuchet <tinytrebuchet@protonmail.com>
*
* 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 __GTK_PRINT_BACKEND_CPDB_H__
#define __GTK_PRINT_BACKEND_CPDB_H__
#include <glib-object.h>
#include <gtk/gtk.h>
#include "gtkprintbackendprivate.h"
G_BEGIN_DECLS
#define GTK_TYPE_PRINT_BACKEND_CPDB (gtk_print_backend_cpdb_get_type ())
#define GTK_PRINT_BACKEND_CPDB(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PRINT_BACKEND_CPDB, GtkPrintBackendCpdb))
#define GTK_IS_PRINT_BACKEND_CPDB(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PRINT_BACKEND_CPDB))
typedef struct _GtkPrintBackendCpdbClass GtkPrintBackendCpdbClass;
typedef struct _GtkPrintBackendCpdb GtkPrintBackendCpdb;
GtkPrintBackend *gtk_print_backend_cpdb_new (void);
GType gtk_print_backend_cpdb_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __GTK_PRINT_BACKEND_CPDB_H__ */
+1 -81
View File
@@ -55,6 +55,7 @@
#include "gtkcupsutils.h"
#include "gtkcupssecretsutils.h"
#include "gtkprintbackendutils.h"
#include <gtkprintutils.h>
#include "gtkprivate.h"
@@ -6483,87 +6484,6 @@ foreach_option_get_settings (GtkPrinterOption *option,
gtk_print_settings_set (settings, option->name, value);
}
static gboolean
supports_am_pm (void)
{
struct tm tmp_tm = { 0 };
char time[8];
int length;
length = strftime (time, sizeof (time), "%p", &tmp_tm);
return length != 0;
}
/* Converts local time to UTC time. Local time has to be in one of these
* formats: HH:MM:SS, HH:MM, HH:MM:SS {am, pm}, HH:MM {am, pm}, HH {am, pm},
* {am, pm} HH:MM:SS, {am, pm} HH:MM, {am, pm} HH.
* Returns a newly allocated string holding UTC time in HH:MM:SS format
* or NULL.
*/
static char *
localtime_to_utctime (const char *local_time)
{
const char *formats_0[] = {" %I : %M : %S %p ", " %p %I : %M : %S ",
" %H : %M : %S ",
" %I : %M %p ", " %p %I : %M ",
" %H : %M ",
" %I %p ", " %p %I "};
const char *formats_1[] = {" %H : %M : %S ", " %H : %M "};
const char *end = NULL;
struct tm *actual_local_time;
struct tm *actual_utc_time;
struct tm local_print_time;
struct tm utc_print_time;
struct tm diff_time;
char *utc_time = NULL;
int i, n;
if (local_time == NULL || local_time[0] == '\0')
return NULL;
n = supports_am_pm () ? G_N_ELEMENTS (formats_0) : G_N_ELEMENTS (formats_1);
for (i = 0; i < n; i++)
{
local_print_time.tm_hour = 0;
local_print_time.tm_min = 0;
local_print_time.tm_sec = 0;
if (supports_am_pm ())
end = strptime (local_time, formats_0[i], &local_print_time);
else
end = strptime (local_time, formats_1[i], &local_print_time);
if (end != NULL && end[0] == '\0')
break;
}
if (end != NULL && end[0] == '\0')
{
time_t rawtime;
time (&rawtime);
actual_utc_time = g_memdup2 (gmtime (&rawtime), sizeof (struct tm));
actual_local_time = g_memdup2 (localtime (&rawtime), sizeof (struct tm));
diff_time.tm_hour = actual_utc_time->tm_hour - actual_local_time->tm_hour;
diff_time.tm_min = actual_utc_time->tm_min - actual_local_time->tm_min;
diff_time.tm_sec = actual_utc_time->tm_sec - actual_local_time->tm_sec;
utc_print_time.tm_hour = ((local_print_time.tm_hour + diff_time.tm_hour) + 24) % 24;
utc_print_time.tm_min = ((local_print_time.tm_min + diff_time.tm_min) + 60) % 60;
utc_print_time.tm_sec = ((local_print_time.tm_sec + diff_time.tm_sec) + 60) % 60;
utc_time = g_strdup_printf ("%02d:%02d:%02d",
utc_print_time.tm_hour,
utc_print_time.tm_min,
utc_print_time.tm_sec);
}
return utc_time;
}
static void
cups_printer_get_settings_from_options (GtkPrinter *printer,
GtkPrinterOptionSet *options,
-478
View File
@@ -1,478 +0,0 @@
/* GTK - The GIMP Toolkit
* gtkprintbackendlpr.c: LPR implementation of GtkPrintBackend
* for printing to lpr
* Copyright (C) 2006, 2007 Red Hat, Inc.
*
* 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/>.
*/
#include "config.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <cairo.h>
#include <cairo-ps.h>
#include <glib/gi18n-lib.h>
#include <gtk/gtk.h>
#include "gtkprinterprivate.h"
#include "gtkprivate.h"
#include "gtkprintbackendlpr.h"
typedef struct _GtkPrintBackendLprClass GtkPrintBackendLprClass;
#define GTK_PRINT_BACKEND_LPR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_BACKEND_LPR, GtkPrintBackendLprClass))
#define GTK_IS_PRINT_BACKEND_LPR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_BACKEND_LPR))
#define GTK_PRINT_BACKEND_LPR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_BACKEND_LPR, GtkPrintBackendLprClass))
#define _LPR_MAX_CHUNK_SIZE 8192
struct _GtkPrintBackendLprClass
{
GtkPrintBackendClass parent_class;
};
struct _GtkPrintBackendLpr
{
GtkPrintBackend parent_instance;
};
static GObjectClass *backend_parent_class;
static void lpr_printer_get_settings_from_options (GtkPrinter *printer,
GtkPrinterOptionSet *options,
GtkPrintSettings *settings);
static GtkPrinterOptionSet *lpr_printer_get_options (GtkPrinter *printer,
GtkPrintSettings *settings,
GtkPageSetup *page_setup,
GtkPrintCapabilities capabilities);
static void lpr_printer_prepare_for_print (GtkPrinter *printer,
GtkPrintJob *print_job,
GtkPrintSettings *settings,
GtkPageSetup *page_setup);
static cairo_surface_t * lpr_printer_create_cairo_surface (GtkPrinter *printer,
GtkPrintSettings *settings,
double width,
double height,
GIOChannel *cache_io);
static void gtk_print_backend_lpr_print_stream (GtkPrintBackend *print_backend,
GtkPrintJob *job,
GIOChannel *data_io,
GtkPrintJobCompleteFunc callback,
gpointer user_data,
GDestroyNotify dnotify);
G_DEFINE_DYNAMIC_TYPE (GtkPrintBackendLpr, gtk_print_backend_lpr, GTK_TYPE_PRINT_BACKEND)
G_MODULE_EXPORT
void
g_io_module_load (GIOModule *module)
{
g_type_module_use (G_TYPE_MODULE (module));
gtk_print_backend_lpr_register_type (G_TYPE_MODULE (module));
g_io_extension_point_implement (GTK_PRINT_BACKEND_EXTENSION_POINT_NAME,
GTK_TYPE_PRINT_BACKEND_LPR,
"lpr",
10);
}
G_MODULE_EXPORT
void
g_io_module_unload (GIOModule *module)
{
}
G_MODULE_EXPORT
char **
g_io_module_query (void)
{
char *eps[] = {
(char *)GTK_PRINT_BACKEND_EXTENSION_POINT_NAME,
NULL
};
return g_strdupv (eps);
}
/**
* gtk_print_backend_lpr_new:
*
* Creates a new #GtkPrintBackendLpr object. #GtkPrintBackendLpr
* implements the #GtkPrintBackend interface with direct access to
* the filesystem using Unix/Linux API calls
*
* Returns: the new #GtkPrintBackendLpr object
**/
GtkPrintBackend *
gtk_print_backend_lpr_new (void)
{
return g_object_new (GTK_TYPE_PRINT_BACKEND_LPR, NULL);
}
static void
gtk_print_backend_lpr_class_init (GtkPrintBackendLprClass *class)
{
GtkPrintBackendClass *backend_class = GTK_PRINT_BACKEND_CLASS (class);
backend_parent_class = g_type_class_peek_parent (class);
backend_class->print_stream = gtk_print_backend_lpr_print_stream;
backend_class->printer_create_cairo_surface = lpr_printer_create_cairo_surface;
backend_class->printer_get_options = lpr_printer_get_options;
backend_class->printer_get_settings_from_options = lpr_printer_get_settings_from_options;
backend_class->printer_prepare_for_print = lpr_printer_prepare_for_print;
}
static void
gtk_print_backend_lpr_class_finalize (GtkPrintBackendLprClass *class)
{
}
static cairo_status_t
_cairo_write (void *closure,
const unsigned char *data,
unsigned int length)
{
GIOChannel *io = (GIOChannel *)closure;
gsize written;
GError *error;
error = NULL;
GTK_DEBUG (PRINTING, "LPR Backend: Writing %i byte chunk to temp file", length);
while (length > 0)
{
g_io_channel_write_chars (io, (const char *)data, length, &written, &error);
if (error != NULL)
{
GTK_DEBUG (PRINTING, "LPR Backend: Error writing to temp file, %s", error->message);
g_error_free (error);
return CAIRO_STATUS_WRITE_ERROR;
}
GTK_DEBUG (PRINTING, "LPR Backend: Wrote %" G_GSIZE_FORMAT " bytes to temp file", written);
data += written;
length -= written;
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_surface_t *
lpr_printer_create_cairo_surface (GtkPrinter *printer,
GtkPrintSettings *settings,
double width,
double height,
GIOChannel *cache_io)
{
cairo_surface_t *surface;
surface = cairo_ps_surface_create_for_stream (_cairo_write, cache_io, width, height);
cairo_surface_set_fallback_resolution (surface,
2.0 * gtk_print_settings_get_printer_lpi (settings),
2.0 * gtk_print_settings_get_printer_lpi (settings));
return surface;
}
typedef struct {
GtkPrintBackend *backend;
GtkPrintJobCompleteFunc callback;
GtkPrintJob *job;
gpointer user_data;
GDestroyNotify dnotify;
GIOChannel *in;
} _PrintStreamData;
static void
lpr_print_cb (GtkPrintBackendLpr *print_backend,
GError *error,
gpointer user_data)
{
_PrintStreamData *ps = (_PrintStreamData *) user_data;
if (ps->in != NULL)
g_io_channel_unref (ps->in);
if (ps->callback)
ps->callback (ps->job, ps->user_data, error);
if (ps->dnotify)
ps->dnotify (ps->user_data);
gtk_print_job_set_status (ps->job,
error ? GTK_PRINT_STATUS_FINISHED_ABORTED
: GTK_PRINT_STATUS_FINISHED);
if (ps->job)
g_object_unref (ps->job);
g_free (ps);
}
static gboolean
lpr_write (GIOChannel *source,
GIOCondition con,
gpointer user_data)
{
char buf[_LPR_MAX_CHUNK_SIZE];
gsize bytes_read;
GError *error;
GIOStatus status;
_PrintStreamData *ps = (_PrintStreamData *) user_data;
error = NULL;
status =
g_io_channel_read_chars (source,
buf,
_LPR_MAX_CHUNK_SIZE,
&bytes_read,
&error);
if (status != G_IO_STATUS_ERROR)
{
gsize bytes_written;
g_io_channel_write_chars (ps->in,
buf,
bytes_read,
&bytes_written,
&error);
}
if (error != NULL || status == G_IO_STATUS_EOF)
{
lpr_print_cb (GTK_PRINT_BACKEND_LPR (ps->backend),
error, user_data);
if (error != NULL)
{
GTK_DEBUG (PRINTING, "LPR Backend: %s", error->message);
g_error_free (error);
}
return FALSE;
}
GTK_DEBUG (PRINTING, "LPR Backend: Writing %" G_GSIZE_FORMAT " byte chunk to lpr pipe", bytes_read);
return TRUE;
}
#define LPR_COMMAND "lpr"
static void
gtk_print_backend_lpr_print_stream (GtkPrintBackend *print_backend,
GtkPrintJob *job,
GIOChannel *data_io,
GtkPrintJobCompleteFunc callback,
gpointer user_data,
GDestroyNotify dnotify)
{
GError *print_error = NULL;
_PrintStreamData *ps;
GtkPrintSettings *settings;
int argc;
int in_fd;
char **argv = NULL;
const char *cmd_line;
settings = gtk_print_job_get_settings (job);
cmd_line = gtk_print_settings_get (settings, "lpr-commandline");
if (cmd_line == NULL)
cmd_line = LPR_COMMAND;
ps = g_new0 (_PrintStreamData, 1);
ps->callback = callback;
ps->user_data = user_data;
ps->dnotify = dnotify;
ps->job = g_object_ref (job);
ps->in = NULL;
/* spawn lpr with pipes and pipe ps file to lpr */
if (!g_shell_parse_argv (cmd_line, &argc, &argv, &print_error))
goto out;
if (!g_spawn_async_with_pipes (NULL,
argv,
NULL,
G_SPAWN_SEARCH_PATH,
NULL,
NULL,
NULL,
&in_fd,
NULL,
NULL,
&print_error))
goto out;
ps->in = g_io_channel_unix_new (in_fd);
g_io_channel_set_encoding (ps->in, NULL, &print_error);
if (print_error != NULL)
goto out;
g_io_channel_set_close_on_unref (ps->in, TRUE);
g_io_add_watch (data_io,
G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP,
(GIOFunc) lpr_write,
ps);
out:
if (argv != NULL)
g_strfreev (argv);
if (print_error != NULL)
{
lpr_print_cb (GTK_PRINT_BACKEND_LPR (print_backend), print_error, ps);
g_error_free (print_error);
if (ps->in != NULL)
g_io_channel_unref (ps->in);
if (ps->job)
g_object_unref (ps->job);
g_free (ps);
}
}
static void
gtk_print_backend_lpr_init (GtkPrintBackendLpr *backend)
{
GtkPrinter *printer;
printer = g_object_new (GTK_TYPE_PRINTER,
"name", _("Print to LPR"),
"backend", backend,
"is-virtual", FALSE,
"accepts-pdf", TRUE,
"accepts-ps", TRUE,
NULL);
gtk_printer_set_has_details (printer, TRUE);
gtk_printer_set_icon_name (printer, "printer");
gtk_printer_set_is_active (printer, TRUE);
gtk_printer_set_is_default (printer, TRUE);
gtk_print_backend_add_printer (GTK_PRINT_BACKEND (backend), printer);
g_object_unref (printer);
gtk_print_backend_set_list_done (GTK_PRINT_BACKEND (backend));
}
static GtkPrinterOptionSet *
lpr_printer_get_options (GtkPrinter *printer,
GtkPrintSettings *settings,
GtkPageSetup *page_setup,
GtkPrintCapabilities capabilities)
{
GtkPrinterOptionSet *set;
GtkPrinterOption *option;
const char *command;
const char *n_up[] = {"1", "2", "4", "6", "9", "16" };
set = gtk_printer_option_set_new ();
option = gtk_printer_option_new ("gtk-n-up", _("Pages Per Sheet"), GTK_PRINTER_OPTION_TYPE_PICKONE);
gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (n_up), n_up, n_up);
gtk_printer_option_set (option, "1");
gtk_printer_option_set_add (set, option);
g_object_unref (option);
option = gtk_printer_option_new ("gtk-main-page-custom-input", _("Command Line"), GTK_PRINTER_OPTION_TYPE_STRING);
gtk_printer_option_set_activates_default (option, TRUE);
option->group = g_strdup ("GtkPrintDialogExtension");
if (settings != NULL &&
(command = gtk_print_settings_get (settings, "lpr-commandline"))!= NULL)
gtk_printer_option_set (option, command);
else
gtk_printer_option_set (option, LPR_COMMAND);
gtk_printer_option_set_add (set, option);
return set;
}
static void
lpr_printer_get_settings_from_options (GtkPrinter *printer,
GtkPrinterOptionSet *options,
GtkPrintSettings *settings)
{
GtkPrinterOption *option;
option = gtk_printer_option_set_lookup (options, "gtk-main-page-custom-input");
if (option)
gtk_print_settings_set (settings, "lpr-commandline", option->value);
option = gtk_printer_option_set_lookup (options, "gtk-n-up");
if (option)
gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_NUMBER_UP, option->value);
option = gtk_printer_option_set_lookup (options, "gtk-n-up-layout");
if (option)
gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_NUMBER_UP_LAYOUT, option->value);
}
static void
lpr_printer_prepare_for_print (GtkPrinter *printer,
GtkPrintJob *print_job,
GtkPrintSettings *settings,
GtkPageSetup *page_setup)
{
double scale;
GtkPrintPages pages;
GtkPageRange *ranges;
int n_ranges;
pages = gtk_print_settings_get_print_pages (settings);
gtk_print_job_set_pages (print_job, pages);
if (pages == GTK_PRINT_PAGES_RANGES)
ranges = gtk_print_settings_get_page_ranges (settings, &n_ranges);
else
{
ranges = NULL;
n_ranges = 0;
}
gtk_print_job_set_page_ranges (print_job, ranges, n_ranges);
gtk_print_job_set_collate (print_job, gtk_print_settings_get_collate (settings));
gtk_print_job_set_reverse (print_job, gtk_print_settings_get_reverse (settings));
gtk_print_job_set_num_copies (print_job, gtk_print_settings_get_n_copies (settings));
gtk_print_job_set_n_up (print_job, gtk_print_settings_get_number_up (settings));
gtk_print_job_set_n_up_layout (print_job, gtk_print_settings_get_number_up_layout (settings));
scale = gtk_print_settings_get_scale (settings);
if (scale != 100.0)
gtk_print_job_set_scale (print_job, scale / 100.0);
gtk_print_job_set_page_set (print_job, gtk_print_settings_get_page_set (settings));
gtk_print_job_set_rotate (print_job, TRUE);
}
@@ -1,41 +0,0 @@
/* GTK - The GIMP Toolkit
* gtkprintbackendlpr.h: LPR implementation of GtkPrintBackend
* for printing to lpr
* Copyright (C) 2006, 2007 Red Hat, Inc.
*
* 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 __GTK_PRINT_BACKEND_LPR_H__
#define __GTK_PRINT_BACKEND_LPR_H__
#include <glib-object.h>
#include "gtkprintbackendprivate.h"
G_BEGIN_DECLS
#define GTK_TYPE_PRINT_BACKEND_LPR (gtk_print_backend_lpr_get_type ())
#define GTK_PRINT_BACKEND_LPR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PRINT_BACKEND_LPR, GtkPrintBackendLpr))
#define GTK_IS_PRINT_BACKEND_LPR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PRINT_BACKEND_LPR))
typedef struct _GtkPrintBackendLpr GtkPrintBackendLpr;
GtkPrintBackend *gtk_print_backend_lpr_new (void);
GType gtk_print_backend_lpr_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __GTK_PRINT_BACKEND_LPR_H__ */
@@ -0,0 +1,128 @@
/* GTK - The GIMP Toolkit
* gtkprintbackendcups.h: Default implementation of GtkPrintBackend
* for the Common Unix Print System (CUPS)
* Copyright (C) 2006, 2007 Red Hat, Inc.
*
* 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/>.
*/
#include <glib.h>
#include <sys/random.h>
#include "gtkprintbackendutils.h"
/* Converts local time to UTC time. Local time has to be in one of these
* formats: HH:MM:SS, HH:MM, HH:MM:SS {am, pm}, HH:MM {am, pm}, HH {am, pm},
* {am, pm} HH:MM:SS, {am, pm} HH:MM, {am, pm} HH.
* Returns a newly allocated string holding UTC time in HH:MM:SS format
* or NULL.
*/
char *
localtime_to_utctime (const char *local_time)
{
const char *formats_0[] = {" %I : %M : %S %p ", " %p %I : %M : %S ",
" %H : %M : %S ",
" %I : %M %p ", " %p %I : %M ",
" %H : %M ",
" %I %p ", " %p %I "};
const char *formats_1[] = {" %H : %M : %S ", " %H : %M "};
const char *end = NULL;
struct tm *actual_local_time;
struct tm *actual_utc_time;
struct tm local_print_time;
struct tm utc_print_time;
struct tm diff_time;
char *utc_time = NULL;
int i, n;
if (local_time == NULL || local_time[0] == '\0')
return NULL;
n = supports_am_pm () ? G_N_ELEMENTS (formats_0) : G_N_ELEMENTS (formats_1);
for (i = 0; i < n; i++)
{
local_print_time.tm_hour = 0;
local_print_time.tm_min = 0;
local_print_time.tm_sec = 0;
if (supports_am_pm ())
end = strptime (local_time, formats_0[i], &local_print_time);
else
end = strptime (local_time, formats_1[i], &local_print_time);
if (end != NULL && end[0] == '\0')
break;
}
if (end != NULL && end[0] == '\0')
{
time_t rawtime;
time (&rawtime);
actual_utc_time = g_memdup2 (gmtime (&rawtime), sizeof (struct tm));
actual_local_time = g_memdup2 (localtime (&rawtime), sizeof (struct tm));
diff_time.tm_hour = actual_utc_time->tm_hour - actual_local_time->tm_hour;
diff_time.tm_min = actual_utc_time->tm_min - actual_local_time->tm_min;
diff_time.tm_sec = actual_utc_time->tm_sec - actual_local_time->tm_sec;
utc_print_time.tm_hour = ((local_print_time.tm_hour + diff_time.tm_hour) + 24) % 24;
utc_print_time.tm_min = ((local_print_time.tm_min + diff_time.tm_min) + 60) % 60;
utc_print_time.tm_sec = ((local_print_time.tm_sec + diff_time.tm_sec) + 60) % 60;
utc_time = g_strdup_printf ("%02d:%02d:%02d",
utc_print_time.tm_hour,
utc_print_time.tm_min,
utc_print_time.tm_sec);
}
return utc_time;
}
gboolean
supports_am_pm (void)
{
struct tm tmp_tm = { 0 };
char time[8];
int length;
length = strftime (time, sizeof (time), "%p", &tmp_tm);
return length != 0;
}
/*
* Generate a random string of "n" length
*/
char *
random_string (int n)
{
const char charset[] = "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
char *str = g_new0 (char, n+1);
getrandom (str, n, 0);
for (int i=0; i<n; i++)
{
int rand = str[i] + 128;
int idx = rand % ((int) sizeof charset);
str[i] = charset[idx];
}
str[n] = '\0';
return str;
}
@@ -0,0 +1,27 @@
/* GTK - The GIMP Toolkit
* gtkprintbackendcups.h: Default implementation of GtkPrintBackend
* for the Common Unix Print System (CUPS)
* Copyright (C) 2006, 2007 Red Hat, Inc.
*
* 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 __GTK_PRINT_BACKEND_UTILS_H__
#define __GTK_PRINT_BACKEND_UTILS_H__
char *random_string (int size);
char *localtime_to_utctime (const char *local_time);
gboolean supports_am_pm (void);
#endif /* __GTK_PRINT_BACKEND_UTILS_H__ */
+137
View File
@@ -0,0 +1,137 @@
/* GtkPrinterCpdb
* Copyright (C) 2022, 2023 TinyTrebuchet <tinytrebuchet@protonmail.com>
*
* 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/>.
*/
#include <gtkprintercpdb.h>
enum {
PROP_0,
PROP_PRINTER_OBJ
};
static void gtk_printer_cpdb_init (GtkPrinterCpdb *printer);
static void gtk_printer_cpdb_class_init (GtkPrinterCpdbClass *class);
static GType gtk_printer_cpdb_type = 0;
static void gtk_printer_cpdb_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void gtk_printer_cpdb_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
void
gtk_printer_cpdb_register_type (GTypeModule *module)
{
const GTypeInfo object_info =
{
sizeof (GtkPrinterCpdbClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) gtk_printer_cpdb_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GtkPrinterCpdb),
0, /* n_preallocs */
(GInstanceInitFunc) gtk_printer_cpdb_init,
};
gtk_printer_cpdb_type = g_type_module_register_type (module,
GTK_TYPE_PRINTER,
"GtkPrinterCpdb",
&object_info, 0);
}
GType
gtk_printer_cpdb_get_type (void)
{
return gtk_printer_cpdb_type;
}
static void
gtk_printer_cpdb_class_init (GtkPrinterCpdbClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = gtk_printer_cpdb_set_property;
object_class->get_property = gtk_printer_cpdb_get_property;
g_object_class_install_property (G_OBJECT_CLASS (klass),
PROP_PRINTER_OBJ,
g_param_spec_pointer ("printer-obj",
NULL,
NULL,
G_PARAM_READWRITE));
}
static void
gtk_printer_cpdb_init (GtkPrinterCpdb *self)
{
}
static void
gtk_printer_cpdb_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkPrinterCpdb *printer_cpdb = GTK_PRINTER_CPDB (object);
switch (prop_id)
{
case PROP_PRINTER_OBJ:
printer_cpdb->printer_obj = g_value_get_pointer (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_printer_cpdb_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkPrinterCpdb *printer_cpdb = GTK_PRINTER_CPDB (object);
switch (prop_id)
{
case PROP_PRINTER_OBJ:
g_value_set_pointer (value, printer_cpdb->printer_obj);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
cpdb_printer_obj_t *
gtk_printer_cpdb_get_printer_obj (GtkPrinterCpdb *cpdb_printer)
{
return cpdb_printer->printer_obj;
}
void
gtk_printer_cpdb_set_printer_obj (GtkPrinterCpdb *cpdb_printer,
cpdb_printer_obj_t *printer_obj)
{
cpdb_printer->printer_obj = printer_obj;
}
+46
View File
@@ -0,0 +1,46 @@
/* GtkPrinterCpdb
* Copyright (C) 2022, 2023 TinyTrebuchet <tinytrebuchet@protonmail.com>
*
* 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 __GTK_PRINTER_CPDB_H__
#define __GTK_PRINTER_CPDB_H__
#include <glib-object.h>
#include <cpdb/cpdb-frontend.h>
#include <gtk/gtkprinterprivate.h>
G_BEGIN_DECLS
#define GTK_TYPE_PRINTER_CPDB (gtk_printer_cpdb_get_type ())
G_DECLARE_FINAL_TYPE (GtkPrinterCpdb, gtk_printer_cpdb, GTK, PRINTER_CPDB, GtkPrinter)
struct _GtkPrinterCpdb
{
GtkPrinter parent_instance;
cpdb_printer_obj_t *printer_obj;
};
void gtk_printer_cpdb_register_type (GTypeModule *module);
cpdb_printer_obj_t *gtk_printer_cpdb_get_printer_obj (GtkPrinterCpdb *cpdb_printer);
void gtk_printer_cpdb_set_printer_obj (GtkPrinterCpdb *cpdb_printer,
cpdb_printer_obj_t *printer_obj);
G_END_DECLS
#endif /* __GTK_PRINTER_CPDB_H__ */
+20 -12
View File
@@ -10,8 +10,26 @@ printbackends_args = [
'-DGTK_PRINT_BACKEND_ENABLE_UNSUPPORTED',
] + common_cflags
cpdb_dep = dependency('cpdb-frontend', version : '>=1.0', required: get_option('print-cpdb'))
cups_dep = dependency('cups', version : '>=2.0', required: get_option('print-cups'))
if cups_dep.found()
# Use cpdb backend if present and enabled.
# If not, use cups if present.
if get_option('print-cpdb').enabled() and cpdb_dep.found()
print_backends += 'cpdb'
shared_module('printbackend-cpdb',
sources: [
'gtkprintbackendcpdb.c',
'gtkprintercpdb.c',
'gtkprintbackendutils.c',
],
c_args: printbackends_args,
dependencies: [libgtk_dep, cpdb_dep],
install_dir: printbackends_install_dir,
install: true,
)
elif cups_dep.found()
print_backends += 'cups'
shared_module('printbackend-cups',
sources: [
@@ -19,6 +37,7 @@ if cups_dep.found()
'gtkprintercups.c',
'gtkcupsutils.c',
'gtkcupssecretsutils.c',
'gtkprintbackendutils.c',
],
c_args: printbackends_args,
dependencies: [libgtk_dep, cups_dep, colord_dep],
@@ -26,17 +45,6 @@ if cups_dep.found()
install_dir: printbackends_install_dir,
install: true,
)
else
# Automatic fall-back to the lpr backend
print_backends += 'lpr'
shared_module('printbackend-lpr',
sources: 'gtkprintbackendlpr.c',
c_args: printbackends_args,
dependencies: libgtk_dep,
name_suffix: module_suffix,
install_dir: printbackends_install_dir,
install: true,
)
endif
# The 'file' print backend cannot be disabled
+2 -2
View File
@@ -104,6 +104,7 @@ gtk/deprecated/gtktreesortable.c
gtk/deprecated/gtktreestore.c
gtk/deprecated/gtktreeview.c
gtk/deprecated/gtktreeviewcolumn.c
gtk/deprecated/gtkvolumebutton.c
gtk/gtkaboutdialog.c
gtk/gtkaccelgroup.c
gtk/gtkaccessible.c
@@ -339,7 +340,6 @@ gtk/gtktreelistmodel.c
gtk/gtktreelistrowsorter.c
gtk/gtkvideo.c
gtk/gtkviewport.c
gtk/gtkvolumebutton.c
gtk/gtkwidget.c
gtk/gtkwidgetpaintable.c
gtk/gtkwindow.c
@@ -409,9 +409,9 @@ gtk/ui/gtkstatusbar.ui
gtk/ui/gtkvolumebutton.ui
modules/media/gtkffmediafile.c
modules/media/gtkgstsink.c
modules/printbackends/gtkprintbackendcpdb.c
modules/printbackends/gtkprintbackendcups.c
modules/printbackends/gtkprintbackendfile.c
modules/printbackends/gtkprintbackendlpr.c
modules/printbackends/gtkprintercups.c
tools/encodesymbolic.c
tools/gtk-builder-tool.c
+3049 -5988
View File
File diff suppressed because it is too large Load Diff
+700 -678
View File
File diff suppressed because it is too large Load Diff
+907 -870
View File
File diff suppressed because it is too large Load Diff
+217 -217
View File
File diff suppressed because it is too large Load Diff
+1042 -1013
View File
File diff suppressed because it is too large Load Diff
-1
View File
@@ -19,7 +19,6 @@ tests = [
{ 'name': 'glcontext' },
{ 'name': 'keysyms' },
{ 'name': 'memorytexture' },
{ 'name': 'pixbuf' },
{ 'name': 'rectangle' },
{ 'name': 'rgba' },
{ 'name': 'seat' },
-42
View File
@@ -1,42 +0,0 @@
#include <gdk-pixbuf/gdk-pixbuf.h>
static void
test_format (gconstpointer d)
{
const char *f = d;
GSList *formats;
gboolean found;
found = FALSE;
formats = gdk_pixbuf_get_formats ();
for (GSList *l = formats; l && !found; l = l->next)
{
GdkPixbufFormat *format = l->data;
char *name;
name = gdk_pixbuf_format_get_name (format);
if (strcmp (name, f) == 0)
found = TRUE;
g_free (name);
}
g_slist_free (formats);
g_assert_true (found);
}
int
main (int argc, char *argv[])
{
(g_test_init) (&argc, &argv, NULL);
g_test_add_data_func ("/pixbuf/format/png", "png", test_format);
g_test_add_data_func ("/pixbuf/format/jpeg", "jpeg", test_format);
return g_test_run ();
}
+20
View File
@@ -0,0 +1,20 @@
mask {
source: container {
color {
color: red;
bounds: 0 0 50 50;
}
color {
color: yellow;
bounds: 50 0 50 50;
}
color {
color: magenta;
bounds: 0 50 100 50;
}
}
mask: color {
color: black;
bounds: 20 20 50 50;
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

@@ -0,0 +1,7 @@
container {
texture-scale {
texture: url("some-10x10-image-with-content.png");
bounds: 0 0 100 100;
filter: nearest;
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 334 B

+2
View File
@@ -54,6 +54,7 @@ compare_render_tests = [
'inset-shadow-multiple',
'invalid-transform',
'issue-3615',
'mask',
'nested-rounded-clips',
'opacity_clip',
'opacity-overdraw',
@@ -75,6 +76,7 @@ compare_render_tests = [
'transform-in-transform',
'transform-in-transform-in-transform',
'rounded-clip-in-clip-3d', # not really 3d, but cairo fails it
'scaled-texture',
]
# these are too sensitive to differences in the renderers
+108
View File
@@ -2689,6 +2689,113 @@ test_expressions (void)
}
}
#define MY_GTK_BOX_TEMPLATE "\
<interface>\n\
<template class=\"MyGtkBox\" parent=\"GtkWidget\">\n\
<child>\n\
<object class=\"GtkLabel\" id=\"label\">\n\
<property name=\"label\">First</property>\n\
</object>\n\
</child>\n\
<child>\n\
<object class=\"GtkLabel\" id=\"label2\">\n\
<property name=\"label\">Second</property>\n\
</object>\n\
</child>\n\
</template>\n\
</interface>\n"
#define MY_TYPE_GTK_BOX (my_gtk_box_get_type ())
G_DECLARE_FINAL_TYPE (MyGtkBox, my_gtk_box, MY, GTK_BOX, GtkWidget)
struct _MyGtkBox
{
GtkWidget parent_instance;
GtkLabel *label;
GtkLabel *label2;
};
G_DEFINE_TYPE (MyGtkBox, my_gtk_box, GTK_TYPE_WIDGET);
static void
my_gtk_box_init (MyGtkBox *grid)
{
gtk_widget_init_template (GTK_WIDGET (grid));
}
static void
my_gtk_box_dispose (GObject *obj)
{
MyGtkBox *my_gtk_box = MY_GTK_BOX (obj);
GtkWidget *child;
while ((child = gtk_widget_get_first_child (GTK_WIDGET (my_gtk_box))))
gtk_widget_unparent (child);
G_OBJECT_CLASS (my_gtk_box_parent_class)->dispose (obj);
}
static void
my_gtk_box_class_init (MyGtkBoxClass *klass)
{
GBytes *template = g_bytes_new_static (MY_GTK_BOX_TEMPLATE, strlen (MY_GTK_BOX_TEMPLATE));
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
gtk_widget_class_set_template (widget_class, template);
gtk_widget_class_bind_template_child (widget_class, MyGtkBox, label);
gtk_widget_class_bind_template_child (widget_class, MyGtkBox, label2);
G_OBJECT_CLASS (klass)->dispose = my_gtk_box_dispose;
}
typedef struct
{
MyGtkBox *my_gtk_box;
guint destroy_count;
} BoxDestroyData;
static void
my_label_destroy (GtkLabel *label, BoxDestroyData *data)
{
g_assert_true (MY_IS_GTK_BOX (data->my_gtk_box));
/* Make sure the other label is null if it was disposed first */
g_assert_true (!data->my_gtk_box->label2 || GTK_IS_LABEL (data->my_gtk_box->label2));
data->destroy_count++;
}
static void
my_label2_destroy (GtkLabel *label2, BoxDestroyData *data)
{
g_assert_true (MY_IS_GTK_BOX (data->my_gtk_box));
/* Make sure the other label is null if it was disposed first */
g_assert_true (!data->my_gtk_box->label || GTK_IS_LABEL (data->my_gtk_box->label));
data->destroy_count++;
}
static void
test_child_dispose_order (void)
{
BoxDestroyData data = { 0, };
/* make sure the type we are trying to register does not exist */
g_assert_false (g_type_from_name ("MyGtkBox"));
/* create the template object */
data.my_gtk_box = g_object_ref_sink (g_object_new (MY_TYPE_GTK_BOX, NULL));
/* Check everything is fine */
g_assert_true (g_type_from_name ("MyGtkBox"));
g_assert_true (MY_IS_GTK_BOX (data.my_gtk_box));
g_assert_true (GTK_IS_LABEL (data.my_gtk_box->label));
g_assert_true (GTK_IS_LABEL (data.my_gtk_box->label2));
/* Check if both labels are destroyed */
g_signal_connect (data.my_gtk_box->label, "destroy", G_CALLBACK (my_label_destroy), &data);
g_signal_connect (data.my_gtk_box->label2, "destroy", G_CALLBACK (my_label2_destroy), &data);
g_object_unref (data.my_gtk_box);
g_assert_cmpuint (data.destroy_count, ==, 2);
}
int
main (int argc, char **argv)
{
@@ -2736,6 +2843,7 @@ main (int argc, char **argv)
g_test_add_func ("/Builder/Shortcuts", test_shortcuts);
g_test_add_func ("/Builder/Transforms", test_transforms);
g_test_add_func ("/Builder/Expressions", test_expressions);
g_test_add_func ("/Builder/Child Dispose Order", test_child_dispose_order);
return g_test_run();
}