summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2021-09-18 13:25:47 -0400
committerMatthias Clasen <mclasen@redhat.com>2021-09-18 17:35:00 -0400
commit4a89cfe2c938512c4580d3697cc08a64e41f5f36 (patch)
treed61d6a74e72d00cb93f061741f6c0750c518341b
parentc9135546b6bd764c6fd07add93f7fc3ca246d2d8 (diff)
downloadgtk+-4a89cfe2c938512c4580d3697cc08a64e41f5f36.tar.gz
Add delayed loading for textures
Add a private GdkPaintable implementation that loads a texture in a thread, and does not show anything until the texture is loaded. This avoid blocking on image loading in the main thread.
-rw-r--r--gtk/gdkpixbufutils.c14
-rw-r--r--gtk/gtkloader.c186
-rw-r--r--gtk/gtkloaderprivate.h35
-rw-r--r--gtk/meson.build1
4 files changed, 229 insertions, 7 deletions
diff --git a/gtk/gdkpixbufutils.c b/gtk/gdkpixbufutils.c
index df8c542deb..59c87a97e9 100644
--- a/gtk/gdkpixbufutils.c
+++ b/gtk/gdkpixbufutils.c
@@ -580,7 +580,7 @@ gdk_paintable_new_from_bytes_scaled (GBytes *bytes,
int scale_factor)
{
LoaderData loader_data;
- GdkTexture *texture;
+ GdkPaintable *inner;
GdkPaintable *paintable;
loader_data.scale_factor = scale_factor;
@@ -588,8 +588,8 @@ gdk_paintable_new_from_bytes_scaled (GBytes *bytes,
if (gdk_texture_can_load (bytes))
{
/* We know these formats can't be scaled */
- texture = gdk_texture_new_from_bytes (bytes, NULL);
- if (texture == NULL)
+ inner = GDK_PAINTABLE (gdk_texture_new_from_bytes (bytes, NULL));
+ if (inner == NULL)
return NULL;
}
else
@@ -608,16 +608,16 @@ gdk_paintable_new_from_bytes_scaled (GBytes *bytes,
if (!success)
return NULL;
- texture = gdk_texture_new_for_pixbuf (gdk_pixbuf_loader_get_pixbuf (loader));
+ inner = GDK_PAINTABLE (gdk_texture_new_for_pixbuf (gdk_pixbuf_loader_get_pixbuf (loader)));
g_object_unref (loader);
}
if (loader_data.scale_factor != 1)
- paintable = gtk_scaler_new (GDK_PAINTABLE (texture), loader_data.scale_factor);
+ paintable = gtk_scaler_new (inner, loader_data.scale_factor);
else
- paintable = g_object_ref ((GdkPaintable *)texture);
+ paintable = g_object_ref ((GdkPaintable *)inner);
- g_object_unref (texture);
+ g_object_unref (inner);
return paintable;
}
diff --git a/gtk/gtkloader.c b/gtk/gtkloader.c
new file mode 100644
index 0000000000..737b0685bc
--- /dev/null
+++ b/gtk/gtkloader.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright © 2018 Benjamin Otte
+ *
+ * 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/>.
+ *
+ * Authors: Benjamin Otte <otte@gnome.org>
+ */
+
+#include "config.h"
+
+#include "gtkloaderprivate.h"
+
+#include "gtksnapshot.h"
+
+struct _GtkLoader
+{
+ GObject parent_instance;
+
+ GdkTexture *texture;
+};
+
+struct _GtkLoaderClass
+{
+ GObjectClass parent_class;
+};
+
+static void
+gtk_loader_paintable_snapshot (GdkPaintable *paintable,
+ GdkSnapshot *snapshot,
+ double width,
+ double height)
+{
+ GtkLoader *self = GTK_LOADER (paintable);
+
+ if (self->texture)
+ gdk_paintable_snapshot (GDK_PAINTABLE (self->texture), snapshot, width, height);
+}
+
+static GdkPaintable *
+gtk_loader_paintable_get_current_image (GdkPaintable *paintable)
+{
+ GtkLoader *self = GTK_LOADER (paintable);
+
+ if (self->texture)
+ return gdk_paintable_get_current_image (GDK_PAINTABLE (self->texture));
+
+ // FIXME: return a loading image
+ return NULL;
+}
+
+static int
+gtk_loader_paintable_get_intrinsic_width (GdkPaintable *paintable)
+{
+ GtkLoader *self = GTK_LOADER (paintable);
+
+ if (self->texture)
+ return gdk_paintable_get_intrinsic_width (GDK_PAINTABLE (self->texture));
+
+ return 16;
+}
+
+static int
+gtk_loader_paintable_get_intrinsic_height (GdkPaintable *paintable)
+{
+ GtkLoader *self = GTK_LOADER (paintable);
+
+ if (self->texture)
+ return gdk_paintable_get_intrinsic_height (GDK_PAINTABLE (self->texture));
+
+ return 16;
+}
+
+static double
+gtk_loader_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable)
+{
+ GtkLoader *self = GTK_LOADER (paintable);
+
+ if (self->texture)
+ return gdk_paintable_get_intrinsic_aspect_ratio (GDK_PAINTABLE (self->texture));
+
+ return 0;
+};
+
+static void
+gtk_loader_paintable_init (GdkPaintableInterface *iface)
+{
+ iface->snapshot = gtk_loader_paintable_snapshot;
+ iface->get_current_image = gtk_loader_paintable_get_current_image;
+ iface->get_intrinsic_width = gtk_loader_paintable_get_intrinsic_width;
+ iface->get_intrinsic_height = gtk_loader_paintable_get_intrinsic_height;
+ iface->get_intrinsic_aspect_ratio = gtk_loader_paintable_get_intrinsic_aspect_ratio;
+}
+
+G_DEFINE_TYPE_EXTENDED (GtkLoader, gtk_loader, G_TYPE_OBJECT, 0,
+ G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
+ gtk_loader_paintable_init))
+
+static void
+gtk_loader_dispose (GObject *object)
+{
+ GtkLoader *self = GTK_LOADER (object);
+
+ g_clear_object (&self->texture);
+
+ G_OBJECT_CLASS (gtk_loader_parent_class)->dispose (object);
+}
+
+static void
+gtk_loader_class_init (GtkLoaderClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->dispose = gtk_loader_dispose;
+}
+
+static void
+gtk_loader_init (GtkLoader *self)
+{
+}
+
+static void
+load_texture_in_thread (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ GBytes *bytes = task_data;
+ GdkTexture *texture;
+ GError *error = NULL;
+
+ texture = gdk_texture_new_from_bytes (bytes, &error);
+
+ if (texture)
+ g_task_return_pointer (task, texture, g_object_unref);
+ else
+ g_task_return_error (task, error);
+}
+
+static void
+texture_finished (GObject *source,
+ GAsyncResult *result,
+ gpointer data)
+{
+ GtkLoader *self = GTK_LOADER (source);
+ GdkTexture *texture;
+ GError *error = NULL;
+
+ texture = g_task_propagate_pointer (G_TASK (result), &error);
+
+ if (texture)
+ {
+ self->texture = g_object_ref (texture);
+
+ gdk_paintable_invalidate_size (GDK_PAINTABLE (self));
+ gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
+ }
+}
+
+GdkPaintable *
+gtk_loader_new (GBytes *bytes)
+{
+ GtkLoader *self;
+ GTask *task;
+
+ g_return_val_if_fail (bytes != NULL, NULL);
+
+ self = g_object_new (GTK_TYPE_LOADER, NULL);
+
+ task = g_task_new (self, NULL, texture_finished, NULL);
+ g_task_set_task_data (task, g_bytes_ref (bytes), (GDestroyNotify)g_bytes_unref);
+ g_task_run_in_thread (task, load_texture_in_thread);
+ g_object_unref (task);
+
+ return GDK_PAINTABLE (self);
+}
diff --git a/gtk/gtkloaderprivate.h b/gtk/gtkloaderprivate.h
new file mode 100644
index 0000000000..4ae56eef5e
--- /dev/null
+++ b/gtk/gtkloaderprivate.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2021 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.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/>.
+ *
+ * Authors: Matthias Clasen <mclasen@redhat.com>
+ */
+
+#ifndef __GTK_LOADER_H__
+#define __GTK_LOADER_H__
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_LOADER (gtk_loader_get_type ())
+
+G_DECLARE_FINAL_TYPE (GtkLoader, gtk_loader, GTK, LOADER, GObject)
+
+GdkPaintable * gtk_loader_new (GBytes *bytes);
+
+G_END_DECLS
+
+#endif /* __GTK_SCALER_H__ */
diff --git a/gtk/meson.build b/gtk/meson.build
index bc097fdd6f..747096a7d4 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -116,6 +116,7 @@ gtk_private_sources = files([
'gtkiconhelper.c',
'gtkjoinedmenu.c',
'gtkkineticscrolling.c',
+ 'gtkloader.c',
'gtkmagnifier.c',
'gtkmenusectionbox.c',
'gtkmenutracker.c',