lib: Introduce Clapper GTK integration library

An easy to use GTK integration library. Meant as a GtkVideo alternative.

While GtkVideo is more of a simple example of video playback under GTK4, this
acts as a full-fledged video player in the form of a GtkWidget that can be placed
anywhere within application.

The widget offers customization options for both top header and bottom playback
controls panels. The Clapper playback API is exposed under widget "player" property
making it easy for the programmer to set media and control playback programically.

The new library will be distributed with Clapper player. This includes public headers
and GObject Introspection support.

Licensed under LGPL-2.1-or-later.
This commit is contained in:
Rafał Dzięgiel
2024-03-13 20:58:00 +01:00
parent d7f069d6c3
commit 675ddc85a1
91 changed files with 11030 additions and 0 deletions

View File

@@ -0,0 +1,177 @@
/* Clapper GTK Integration Library
* Copyright (C) 2024 Rafał Dzięgiel <rafostar.github@gmail.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.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, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "clapper-gtk-buffering-paintable-private.h"
#define CIRCLE_MAX_SIZE 48
#define CIRCLE_SPACING 10
#define CIRCLE_OUTLINE 2
#define INTRINSIC_SIZE 184 // 3 * CIRCLE_MAX_SIZE + 4 * CIRCLE_SPACING
#define BLACK ((GdkRGBA) { 0, 0, 0, 1 })
#define WHITE ((GdkRGBA) { 1, 1, 1, 1 })
struct _ClapperGtkBufferingPaintable
{
GObject parent;
gfloat sizes[3]; // current size of each circle
gboolean reverses[3]; // grow/shrink direction
gboolean initialized[3]; // big enough to start growing the next one
};
static GdkPaintableFlags
clapper_gtk_buffering_paintable_get_flags (GdkPaintable *paintable)
{
return GDK_PAINTABLE_STATIC_SIZE;
}
static gint
clapper_gtk_buffering_paintable_get_intrinsic_size (GdkPaintable *paintable)
{
return INTRINSIC_SIZE;
}
static void
_draw_scaled_circle (GdkSnapshot *snapshot, gfloat scale)
{
GskRoundedRect outline;
gfloat half_size = ((gfloat) CIRCLE_MAX_SIZE / 2) * scale;
gfloat inside_size = ((gfloat) (CIRCLE_MAX_SIZE - 2 * CIRCLE_OUTLINE) / 2) * scale;
/* Draw white inner circle */
gsk_rounded_rect_init_from_rect (&outline,
&GRAPHENE_RECT_INIT (-inside_size, -inside_size, 2 * inside_size, 2 * inside_size), inside_size);
gtk_snapshot_append_border (snapshot, &outline,
(gfloat[4]) { inside_size, inside_size, inside_size, inside_size },
(GdkRGBA[4]) { WHITE, WHITE, WHITE, WHITE });
/* Draw black circle border */
gsk_rounded_rect_init_from_rect (&outline,
&GRAPHENE_RECT_INIT (-half_size, -half_size, 2 * half_size, 2 * half_size), half_size);
gtk_snapshot_append_border (snapshot, &outline,
(gfloat[4]) { CIRCLE_OUTLINE, CIRCLE_OUTLINE, CIRCLE_OUTLINE, CIRCLE_OUTLINE },
(GdkRGBA[4]) { BLACK, BLACK, BLACK, BLACK });
}
static void
clapper_gtk_buffering_paintable_snapshot (GdkPaintable *paintable,
GdkSnapshot *snapshot, gdouble width, gdouble height)
{
ClapperGtkBufferingPaintable *self = CLAPPER_GTK_BUFFERING_PAINTABLE_CAST (paintable);
guint i;
gtk_snapshot_save (snapshot);
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (0, height / 2));
gtk_snapshot_scale (snapshot, MIN (width, height) / INTRINSIC_SIZE, MIN (width, height) / INTRINSIC_SIZE);
for (i = 0; i < 3; ++i) {
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (CIRCLE_SPACING + CIRCLE_MAX_SIZE / 2, 0));
_draw_scaled_circle (snapshot, self->sizes[i]);
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (CIRCLE_MAX_SIZE / 2, 0));
}
gtk_snapshot_restore (snapshot);
}
static GdkPaintable *
clapper_gtk_buffering_paintable_get_current_image (GdkPaintable *paintable)
{
ClapperGtkBufferingPaintable *self = CLAPPER_GTK_BUFFERING_PAINTABLE_CAST (paintable);
ClapperGtkBufferingPaintable *copy = clapper_gtk_buffering_paintable_new ();
guint i;
/* Only current sizes are needed for static image */
for (i = 0; i < 3; ++i)
copy->sizes[i] = self->sizes[i];
return GDK_PAINTABLE (copy);
}
static void
_paintable_iface_init (GdkPaintableInterface *iface)
{
iface->get_flags = clapper_gtk_buffering_paintable_get_flags;
iface->get_intrinsic_width = clapper_gtk_buffering_paintable_get_intrinsic_size;
iface->get_intrinsic_height = clapper_gtk_buffering_paintable_get_intrinsic_size;
iface->snapshot = clapper_gtk_buffering_paintable_snapshot;
iface->get_current_image = clapper_gtk_buffering_paintable_get_current_image;
}
#define parent_class clapper_gtk_buffering_paintable_parent_class
G_DEFINE_TYPE_WITH_CODE (ClapperGtkBufferingPaintable, clapper_gtk_buffering_paintable, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE, _paintable_iface_init))
ClapperGtkBufferingPaintable *
clapper_gtk_buffering_paintable_new (void)
{
return g_object_new (CLAPPER_GTK_TYPE_BUFFERING_PAINTABLE, NULL);
}
void
clapper_gtk_buffering_paintable_step (ClapperGtkBufferingPaintable *self)
{
guint i;
for (i = 0; i < 3; ++i) {
/* If previous circle is not big enough
* do not start animating the next one */
if (i > 0 && !self->initialized[i - 1])
break;
if (!self->initialized[i] && self->sizes[i] >= 0.3)
self->initialized[i] = TRUE;
self->sizes[i] += (self->reverses[i]) ? -0.04 : 0.04;
if (self->sizes[i] > 1.0) {
self->sizes[i] = 1.0;
self->reverses[i] = TRUE;
} else if (self->sizes[i] < 0.0) {
self->sizes[i] = 0.0;
self->reverses[i] = FALSE;
}
}
gdk_paintable_invalidate_contents ((GdkPaintable *) self);
}
void
clapper_gtk_buffering_paintable_reset (ClapperGtkBufferingPaintable *self)
{
guint i;
for (i = 0; i < 3; ++i) {
self->sizes[i] = 0;
self->reverses[i] = FALSE;
self->initialized[i] = FALSE;
}
gdk_paintable_invalidate_contents ((GdkPaintable *) self);
}
static void
clapper_gtk_buffering_paintable_init (ClapperGtkBufferingPaintable *self)
{
}
static void
clapper_gtk_buffering_paintable_class_init (ClapperGtkBufferingPaintableClass *klass)
{
}