clapper-gtk: video: Split code into subclass

Create a base class called "ClapperGtkAv" and subclass it into "ClapperGtkVideo".
This allows to have player and session inhibit logic in base class and share it
with other subclassed widgets.
This commit is contained in:
Rafał Dzięgiel
2025-08-01 16:17:27 +02:00
parent c21e1c1c6a
commit 4301a9a9fa
8 changed files with 788 additions and 326 deletions

View File

@@ -0,0 +1,645 @@
/* Clapper GTK Integration Library
* Copyright (C) 2025 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, see
* <https://www.gnu.org/licenses/>.
*/
/**
* ClapperGtkAv:
*
* A base class for GTK audio and video widgets.
*
* See [class@ClapperGtk.Video].
*
* # Actions
*
* #ClapperGtkAv defines a set of built-in actions:
*
* ```yaml
* - "av.toggle-play": toggle play/pause
* - "av.play": start/resume playback
* - "av.pause": pause playback
* - "av.stop": stop playback
* - "av.seek": seek to position (variant "d")
* - "av.seek-custom": seek to position using seek method (variant "(di)")
* - "av.toggle-mute": toggle mute state
* - "av.set-mute": set mute state (variant "b")
* - "av.volume-up": increase volume by 2%
* - "av.volume-down": decrease volume by 2%
* - "av.set-volume": set volume to specified value (variant "d")
* - "av.speed-up": increase speed (from 0.05x - 2x range to nearest quarter)
* - "av.speed-down": decrease speed (from 0.05x - 2x range to nearest quarter)
* - "av.set-speed": set speed to specified value (variant "d")
* - "av.previous-item": select previous item in queue
* - "av.next-item": select next item in queue
* - "av.select-item": select item at specified index in queue (variant "u")
* ```
*
* Since: 0.10
*/
#include "config.h"
#include <math.h>
#include "clapper-gtk-av.h"
#define PERCENTAGE_ROUND(a) (round ((gdouble) a / 0.01) * 0.01)
#define DEFAULT_AUTO_INHIBIT FALSE
#define GST_CAT_DEFAULT clapper_gtk_av_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
typedef struct _ClapperGtkAvPrivate ClapperGtkAvPrivate;
struct _ClapperGtkAvPrivate
{
ClapperPlayer *player;
gboolean auto_inhibit;
guint inhibit_cookie;
};
#define parent_class clapper_gtk_av_parent_class
G_DEFINE_TYPE_WITH_PRIVATE (ClapperGtkAv, clapper_gtk_av, GTK_TYPE_WIDGET)
enum
{
PROP_0,
PROP_PLAYER,
PROP_AUTO_INHIBIT,
PROP_INHIBITED,
PROP_LAST
};
static gboolean provider_added = FALSE;
static GParamSpec *param_specs[PROP_LAST] = { NULL, };
static void
toggle_play_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkAv *self = CLAPPER_GTK_AV_CAST (widget);
ClapperPlayer *player = clapper_gtk_av_get_player (self);
switch (clapper_player_get_state (player)) {
case CLAPPER_PLAYER_STATE_PLAYING:
clapper_player_pause (player);
break;
case CLAPPER_PLAYER_STATE_STOPPED:
case CLAPPER_PLAYER_STATE_PAUSED:
clapper_player_play (player);
break;
default:
break;
}
}
static void
play_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkAv *self = CLAPPER_GTK_AV_CAST (widget);
ClapperPlayer *player = clapper_gtk_av_get_player (self);
clapper_player_play (player);
}
static void
pause_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkAv *self = CLAPPER_GTK_AV_CAST (widget);
ClapperPlayer *player = clapper_gtk_av_get_player (self);
clapper_player_pause (player);
}
static void
stop_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkAv *self = CLAPPER_GTK_AV_CAST (widget);
ClapperPlayer *player = clapper_gtk_av_get_player (self);
clapper_player_stop (player);
}
static void
seek_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkAv *self = CLAPPER_GTK_AV_CAST (widget);
ClapperPlayer *player = clapper_gtk_av_get_player (self);
gdouble position = g_variant_get_double (parameter);
clapper_player_seek (player, position);
}
static void
seek_custom_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkAv *self = CLAPPER_GTK_AV_CAST (widget);
ClapperPlayer *player = clapper_gtk_av_get_player (self);
ClapperPlayerSeekMethod method = CLAPPER_PLAYER_SEEK_METHOD_NORMAL;
gdouble position = 0;
g_variant_get (parameter, "(di)", &position, &method);
clapper_player_seek_custom (player, position, method);
}
static void
toggle_mute_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkAv *self = CLAPPER_GTK_AV_CAST (widget);
ClapperPlayer *player = clapper_gtk_av_get_player (self);
clapper_player_set_mute (player, !clapper_player_get_mute (player));
}
static void
set_mute_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkAv *self = CLAPPER_GTK_AV_CAST (widget);
ClapperPlayer *player = clapper_gtk_av_get_player (self);
gboolean mute = g_variant_get_boolean (parameter);
clapper_player_set_mute (player, mute);
}
static void
volume_up_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkAv *self = CLAPPER_GTK_AV_CAST (widget);
ClapperPlayer *player = clapper_gtk_av_get_player (self);
gdouble volume = (clapper_player_get_volume (player) + 0.02);
if (volume > 2.0)
volume = 2.0;
clapper_player_set_volume (player, PERCENTAGE_ROUND (volume));
}
static void
volume_down_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkAv *self = CLAPPER_GTK_AV_CAST (widget);
ClapperPlayer *player = clapper_gtk_av_get_player (self);
gdouble volume = (clapper_player_get_volume (player) - 0.02);
if (volume < 0)
volume = 0;
clapper_player_set_volume (player, PERCENTAGE_ROUND (volume));
}
static void
set_volume_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkAv *self = CLAPPER_GTK_AV_CAST (widget);
ClapperPlayer *player = clapper_gtk_av_get_player (self);
gdouble volume = g_variant_get_double (parameter);
clapper_player_set_volume (player, volume);
}
static void
speed_up_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkAv *self = CLAPPER_GTK_AV_CAST (widget);
ClapperPlayer *player = clapper_gtk_av_get_player (self);
gdouble dest, speed = clapper_player_get_speed (player);
if (speed >= 2.0)
return;
dest = 0.25;
while (speed >= dest)
dest += 0.25;
if (dest > 2.0)
dest = 2.0;
clapper_player_set_speed (player, dest);
}
static void
speed_down_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkAv *self = CLAPPER_GTK_AV_CAST (widget);
ClapperPlayer *player = clapper_gtk_av_get_player (self);
gdouble dest, speed = clapper_player_get_speed (player);
if (speed <= 0.05)
return;
dest = 2.0;
while (speed <= dest)
dest -= 0.25;
if (dest < 0.05)
dest = 0.05;
clapper_player_set_speed (player, dest);
}
static void
set_speed_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkAv *self = CLAPPER_GTK_AV_CAST (widget);
ClapperPlayer *player = clapper_gtk_av_get_player (self);
gdouble speed = g_variant_get_double (parameter);
clapper_player_set_speed (player, speed);
}
static void
previous_item_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkAv *self = CLAPPER_GTK_AV_CAST (widget);
ClapperPlayer *player = clapper_gtk_av_get_player (self);
clapper_queue_select_previous_item (clapper_player_get_queue (player));
}
static void
next_item_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkAv *self = CLAPPER_GTK_AV_CAST (widget);
ClapperPlayer *player = clapper_gtk_av_get_player (self);
clapper_queue_select_next_item (clapper_player_get_queue (player));
}
static void
select_item_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkAv *self = CLAPPER_GTK_AV_CAST (widget);
ClapperPlayer *player = clapper_gtk_av_get_player (self);
guint index = g_variant_get_uint32 (parameter);
clapper_queue_select_index (clapper_player_get_queue (player), index);
}
static void
_ensure_css_provider (void)
{
GdkDisplay *display;
if (provider_added)
return;
display = gdk_display_get_default ();
if (G_LIKELY (display != NULL)) {
GtkCssProvider *provider = gtk_css_provider_new ();
gtk_css_provider_load_from_resource (provider,
CLAPPER_GTK_RESOURCE_PREFIX "/css/styles.css");
gtk_style_context_add_provider_for_display (display,
(GtkStyleProvider *) provider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION - 1);
g_object_unref (provider);
provider_added = TRUE;
}
}
static inline void
_set_inhibit_session (ClapperGtkAv *self, gboolean inhibit)
{
ClapperGtkAvPrivate *priv = clapper_gtk_av_get_instance_private (self);
GtkRoot *root;
GApplication *app;
gboolean inhibited = (priv->inhibit_cookie != 0);
if (inhibited == inhibit)
return;
GST_DEBUG_OBJECT (self, "Trying to %sinhibit session...", (inhibit) ? "" : "un");
root = gtk_widget_get_root (GTK_WIDGET (self));
if (!root && !GTK_IS_WINDOW (root)) {
GST_WARNING_OBJECT (self, "Cannot %sinhibit session "
"without root window", (inhibit) ? "" : "un");
return;
}
/* NOTE: Not using application from window prop,
* as it goes away early when unrooting */
app = g_application_get_default ();
if (!app && !GTK_IS_APPLICATION (app)) {
GST_WARNING_OBJECT (self, "Cannot %sinhibit session "
"without window application set", (inhibit) ? "" : "un");
return;
}
if (inhibited) {
gtk_application_uninhibit (GTK_APPLICATION (app), priv->inhibit_cookie);
priv->inhibit_cookie = 0;
}
if (inhibit) {
priv->inhibit_cookie = gtk_application_inhibit (GTK_APPLICATION (app),
GTK_WINDOW (root), GTK_APPLICATION_INHIBIT_IDLE,
"Media is playing");
}
GST_DEBUG_OBJECT (self, "Session %sinhibited", (inhibit) ? "" : "un");
g_object_notify_by_pspec (G_OBJECT (self), param_specs[PROP_INHIBITED]);
}
static void
_player_state_changed_cb (ClapperPlayer *player,
GParamSpec *pspec G_GNUC_UNUSED, ClapperGtkAv *self)
{
ClapperGtkAvPrivate *priv = clapper_gtk_av_get_instance_private (self);
if (priv->auto_inhibit) {
ClapperPlayerState state = clapper_player_get_state (player);
_set_inhibit_session (self, state == CLAPPER_PLAYER_STATE_PLAYING);
}
}
/**
* clapper_gtk_av_get_player:
* @av: a #ClapperGtkAv
*
* Get #ClapperPlayer used by this #ClapperGtkAv instance.
*
* Returns: (transfer none): a #ClapperPlayer used by widget.
*
* Since: 0.10
*/
ClapperPlayer *
clapper_gtk_av_get_player (ClapperGtkAv *self)
{
ClapperGtkAvPrivate *priv;
g_return_val_if_fail (CLAPPER_GTK_IS_AV (self), NULL);
priv = clapper_gtk_av_get_instance_private (self);
return priv->player;
}
/**
* clapper_gtk_av_set_auto_inhibit:
* @av: a #ClapperGtkAv
* @inhibit: whether to enable automatic session inhibit
*
* Set whether widget should try to automatically inhibit session
* from idling (and possibly screen going black) when media is playing.
*
* Since: 0.10
*/
void
clapper_gtk_av_set_auto_inhibit (ClapperGtkAv *self, gboolean inhibit)
{
ClapperGtkAvPrivate *priv;
g_return_if_fail (CLAPPER_GTK_IS_AV (self));
priv = clapper_gtk_av_get_instance_private (self);
if (priv->auto_inhibit != inhibit) {
priv->auto_inhibit = inhibit;
/* Uninhibit if we were auto inhibited earlier */
if (!priv->auto_inhibit)
_set_inhibit_session (self, FALSE);
g_object_notify_by_pspec (G_OBJECT (self), param_specs[PROP_AUTO_INHIBIT]);
}
}
/**
* clapper_gtk_av_get_auto_inhibit:
* @av: a #ClapperGtkAv
*
* Get whether automatic session inhibit is enabled.
*
* Returns: %TRUE if enabled, %FALSE otherwise.
*
* Since: 0.10
*/
gboolean
clapper_gtk_av_get_auto_inhibit (ClapperGtkAv *self)
{
ClapperGtkAvPrivate *priv;
g_return_val_if_fail (CLAPPER_GTK_IS_AV (self), FALSE);
priv = clapper_gtk_av_get_instance_private (self);
return priv->auto_inhibit;
}
/**
* clapper_gtk_av_get_inhibited:
* @av: a #ClapperGtkAv
*
* Get whether session is currently inhibited by
* [property@ClapperGtk.Av:auto-inhibit].
*
* Returns: %TRUE if inhibited, %FALSE otherwise.
*
* Since: 0.10
*/
gboolean
clapper_gtk_av_get_inhibited (ClapperGtkAv *self)
{
ClapperGtkAvPrivate *priv;
g_return_val_if_fail (CLAPPER_GTK_IS_AV (self), FALSE);
priv = clapper_gtk_av_get_instance_private (self);
return (priv->inhibit_cookie != 0);
}
static void
clapper_gtk_av_root (GtkWidget *widget)
{
ClapperGtkAv *self = CLAPPER_GTK_AV_CAST (widget);
ClapperGtkAvPrivate *priv = clapper_gtk_av_get_instance_private (self);
_ensure_css_provider ();
GTK_WIDGET_CLASS (parent_class)->root (widget);
if (priv->auto_inhibit) {
ClapperPlayerState state = clapper_player_get_state (priv->player);
_set_inhibit_session (self, state == CLAPPER_PLAYER_STATE_PLAYING);
}
}
static void
clapper_gtk_av_unroot (GtkWidget *widget)
{
ClapperGtkAv *self = CLAPPER_GTK_AV_CAST (widget);
_set_inhibit_session (self, FALSE);
GTK_WIDGET_CLASS (parent_class)->unroot (widget);
}
static void
clapper_gtk_av_init (ClapperGtkAv *self)
{
ClapperGtkAvPrivate *priv = clapper_gtk_av_get_instance_private (self);
priv->auto_inhibit = DEFAULT_AUTO_INHIBIT;
}
static void
clapper_gtk_av_constructed (GObject *object)
{
ClapperGtkAv *self = CLAPPER_GTK_AV_CAST (object);
ClapperGtkAvPrivate *priv = clapper_gtk_av_get_instance_private (self);
GstElement *afilter;
priv->player = clapper_player_new ();
g_signal_connect (priv->player, "notify::state",
G_CALLBACK (_player_state_changed_cb), self);
afilter = gst_element_factory_make ("scaletempo", NULL);
if (G_LIKELY (afilter != NULL))
clapper_player_set_audio_filter (priv->player, afilter);
G_OBJECT_CLASS (parent_class)->constructed (object);
}
static void
clapper_gtk_av_dispose (GObject *object)
{
ClapperGtkAv *self = CLAPPER_GTK_AV_CAST (object);
ClapperGtkAvPrivate *priv = clapper_gtk_av_get_instance_private (self);
/* Something else might still be holding a reference on the player,
* thus we should disconnect everything before disposing template */
if (priv->player) {
g_signal_handlers_disconnect_by_func (priv->player,
_player_state_changed_cb, self);
}
gst_clear_object (&priv->player);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
clapper_gtk_av_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
ClapperGtkAv *self = CLAPPER_GTK_AV_CAST (object);
switch (prop_id) {
case PROP_PLAYER:
g_value_set_object (value, clapper_gtk_av_get_player (self));
break;
case PROP_AUTO_INHIBIT:
g_value_set_boolean (value, clapper_gtk_av_get_auto_inhibit (self));
break;
case PROP_INHIBITED:
g_value_set_boolean (value, clapper_gtk_av_get_inhibited (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
clapper_gtk_av_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
ClapperGtkAv *self = CLAPPER_GTK_AV_CAST (object);
switch (prop_id) {
case PROP_AUTO_INHIBIT:
clapper_gtk_av_set_auto_inhibit (self, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
clapper_gtk_av_class_init (ClapperGtkAvClass *klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
GtkWidgetClass *widget_class = (GtkWidgetClass *) klass;
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clappergtkav", GST_DEBUG_FG_MAGENTA,
"Clapper GTK AV");
widget_class->root = clapper_gtk_av_root;
widget_class->unroot = clapper_gtk_av_unroot;
gobject_class->constructed = clapper_gtk_av_constructed;
gobject_class->get_property = clapper_gtk_av_get_property;
gobject_class->set_property = clapper_gtk_av_set_property;
gobject_class->dispose = clapper_gtk_av_dispose;
/**
* ClapperGtkAv:player:
*
* A #ClapperPlayer used by widget.
*/
param_specs[PROP_PLAYER] = g_param_spec_object ("player",
NULL, NULL, CLAPPER_TYPE_PLAYER,
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* ClapperGtkAv:auto-inhibit:
*
* Try to automatically inhibit session when media is playing.
*/
param_specs[PROP_AUTO_INHIBIT] = g_param_spec_boolean ("auto-inhibit",
NULL, NULL, DEFAULT_AUTO_INHIBIT,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* ClapperGtkAv:inhibited:
*
* Get whether session is currently inhibited by playback.
*/
param_specs[PROP_INHIBITED] = g_param_spec_boolean ("inhibited",
NULL, NULL, FALSE,
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, PROP_LAST, param_specs);
gtk_widget_class_install_action (widget_class, "av.toggle-play", NULL, toggle_play_action_cb);
gtk_widget_class_install_action (widget_class, "av.play", NULL, play_action_cb);
gtk_widget_class_install_action (widget_class, "av.pause", NULL, pause_action_cb);
gtk_widget_class_install_action (widget_class, "av.stop", NULL, stop_action_cb);
gtk_widget_class_install_action (widget_class, "av.seek", "d", seek_action_cb);
gtk_widget_class_install_action (widget_class, "av.seek-custom", "(di)", seek_custom_action_cb);
gtk_widget_class_install_action (widget_class, "av.toggle-mute", NULL, toggle_mute_action_cb);
gtk_widget_class_install_action (widget_class, "av.set-mute", "b", set_mute_action_cb);
gtk_widget_class_install_action (widget_class, "av.volume-up", NULL, volume_up_action_cb);
gtk_widget_class_install_action (widget_class, "av.volume-down", NULL, volume_down_action_cb);
gtk_widget_class_install_action (widget_class, "av.set-volume", "d", set_volume_action_cb);
gtk_widget_class_install_action (widget_class, "av.speed-up", NULL, speed_up_action_cb);
gtk_widget_class_install_action (widget_class, "av.speed-down", NULL, speed_down_action_cb);
gtk_widget_class_install_action (widget_class, "av.set-speed", "d", set_speed_action_cb);
gtk_widget_class_install_action (widget_class, "av.previous-item", NULL, previous_item_action_cb);
gtk_widget_class_install_action (widget_class, "av.next-item", NULL, next_item_action_cb);
gtk_widget_class_install_action (widget_class, "av.select-item", "u", select_item_action_cb);
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GENERIC);
gtk_widget_class_set_css_name (widget_class, "clapper-gtk-av");
}

View File

@@ -0,0 +1,60 @@
/* Clapper GTK Integration Library
* Copyright (C) 2025 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, see
* <https://www.gnu.org/licenses/>.
*/
#pragma once
#if !defined(__CLAPPER_GTK_INSIDE__) && !defined(CLAPPER_GTK_COMPILATION)
#error "Only <clapper-gtk/clapper-gtk.h> can be included directly."
#endif
#include <glib.h>
#include <glib-object.h>
#include <gtk/gtk.h>
#include <clapper/clapper.h>
#include <clapper-gtk/clapper-gtk-visibility.h>
G_BEGIN_DECLS
#define CLAPPER_GTK_TYPE_AV (clapper_gtk_av_get_type())
#define CLAPPER_GTK_AV_CAST(obj) ((ClapperGtkAv *)(obj))
CLAPPER_GTK_API
G_DECLARE_DERIVABLE_TYPE (ClapperGtkAv, clapper_gtk_av, CLAPPER_GTK, AV, GtkWidget)
struct _ClapperGtkAvClass
{
GtkWidgetClass parent_class;
/*< private >*/
gpointer padding[4];
};
CLAPPER_GTK_API
ClapperPlayer * clapper_gtk_av_get_player (ClapperGtkAv *av);
CLAPPER_GTK_API
void clapper_gtk_av_set_auto_inhibit (ClapperGtkAv *av, gboolean inhibit);
CLAPPER_GTK_API
gboolean clapper_gtk_av_get_auto_inhibit (ClapperGtkAv *av);
CLAPPER_GTK_API
gboolean clapper_gtk_av_get_inhibited (ClapperGtkAv *av);
G_END_DECLS

View File

@@ -21,7 +21,7 @@
#include <glib/gi18n-lib.h>
#include "clapper-gtk-utils-private.h"
#include "clapper-gtk-video.h"
#include "clapper-gtk-av.h"
static gboolean initialized = FALSE;
@@ -29,18 +29,18 @@ static gboolean initialized = FALSE;
* clapper_gtk_get_player_from_ancestor:
* @widget: a #GtkWidget
*
* Get [class@Clapper.Player] used by [class@ClapperGtk.Video] ancestor of @widget.
* Get [class@Clapper.Player] used by [class@ClapperGtk.Av] ancestor of @widget.
*
* This utility is a convenience wrapper for calling [method@Gtk.Widget.get_ancestor]
* of type `CLAPPER_GTK_TYPE_VIDEO` and [method@ClapperGtk.Video.get_player] with
* of type `CLAPPER_GTK_TYPE_AV` and [method@ClapperGtk.Av.get_player] with
* additional %NULL checking and type casting.
*
* This is meant to be used mainly for custom widget development as an easy access to the
* underlying parent [class@Clapper.Player] object. If you want to get the player from
* [class@ClapperGtk.Video] widget itself, use [method@ClapperGtk.Video.get_player] instead.
* [class@ClapperGtk.Av] widget itself, use [method@ClapperGtk.Av.get_player] instead.
*
* Rememeber that this function will return %NULL when widget does not have
* a [class@ClapperGtk.Video] ancestor in widget hierarchy (widget is not yet placed).
* a [class@ClapperGtk.Av] ancestor in widget hierarchy (widget is not yet placed).
*
* Returns: (transfer none) (nullable): a #ClapperPlayer from ancestor of a @widget.
*/
@@ -52,8 +52,8 @@ clapper_gtk_get_player_from_ancestor (GtkWidget *widget)
g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
if ((parent = gtk_widget_get_ancestor (widget, CLAPPER_GTK_TYPE_VIDEO)))
player = clapper_gtk_video_get_player (CLAPPER_GTK_VIDEO_CAST (parent));
if ((parent = gtk_widget_get_ancestor (widget, CLAPPER_GTK_TYPE_AV)))
player = clapper_gtk_av_get_player (CLAPPER_GTK_AV_CAST (parent));
return player;
}

View File

@@ -22,8 +22,8 @@
* A ready to be used GTK video widget implementing Clapper API.
*
* #ClapperGtkVideo is the main widget exposed by `ClapperGtk` API. It both displays
* videos played by [class@Clapper.Player] (exposed as its property) and manages
* revealing and fading of any additional widgets overlaid on top of it.
* videos played by [class@Clapper.Player] (exposed as [property@ClapperGtk.Av:player] property)
* and manages revealing and fading of any additional widgets overlaid on top of it.
*
* Other widgets provided by `ClapperGtk` library, once placed anywhere on video
* (including nesting within another widget like [class@Gtk.Box]) will automatically
@@ -34,7 +34,7 @@
* # Basic usage
*
* A typical use case is to embed video widget as part of your app where video playback
* is needed. Get the [class@Clapper.Player] belonging to the video widget and start adding
* is needed. Get the [class@Clapper.Player] belonging to the AV widget and start adding
* new [class@Clapper.MediaItem] items to the [class@Clapper.Queue] for playback.
* For more information please refer to the Clapper playback library documentation.
*
@@ -46,27 +46,8 @@
*
* # Actions
*
* #ClapperGtkVideo defines a set of built-in actions:
*
* ```yaml
* - "video.toggle-play": toggle play/pause
* - "video.play": start/resume playback
* - "video.pause": pause playback
* - "video.stop": stop playback
* - "video.seek": seek to position (variant "d")
* - "video.seek-custom": seek to position using seek method (variant "(di)")
* - "video.toggle-mute": toggle mute state
* - "video.set-mute": set mute state (variant "b")
* - "video.volume-up": increase volume by 2%
* - "video.volume-down": decrease volume by 2%
* - "video.set-volume": set volume to specified value (variant "d")
* - "video.speed-up": increase speed (from 0.05x - 2x range to nearest quarter)
* - "video.speed-down": decrease speed (from 0.05x - 2x range to nearest quarter)
* - "video.set-speed": set speed to specified value (variant "d")
* - "video.previous-item": select previous item in queue
* - "video.next-item": select next item in queue
* - "video.select-item": select item at specified index in queue (variant "u")
* ```
* You can use built-in actions of parent [class@ClapperGtk.Av].
* See its documentation, for the list of available ones.
*
* # ClapperGtkVideo as GtkBuildable
*
@@ -93,8 +74,6 @@
#include "config.h"
#include <math.h>
#include "clapper-gtk-enums.h"
#include "clapper-gtk-video.h"
#include "clapper-gtk-lead-container.h"
@@ -102,11 +81,8 @@
#include "clapper-gtk-buffering-animation-private.h"
#include "clapper-gtk-video-placeholder-private.h"
#define PERCENTAGE_ROUND(a) (round ((gdouble) a / 0.01) * 0.01)
#define DEFAULT_FADE_DELAY 3000
#define DEFAULT_TOUCH_FADE_DELAY 5000
#define DEFAULT_AUTO_INHIBIT FALSE
#define MIN_MOTION_DELAY 100000
@@ -115,7 +91,7 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
struct _ClapperGtkVideo
{
GtkWidget parent;
ClapperGtkAv parent;
GtkWidget *overlay;
GtkWidget *status;
@@ -125,10 +101,8 @@ struct _ClapperGtkVideo
GtkGesture *click_gesture;
/* Props */
ClapperPlayer *player;
guint fade_delay;
guint touch_fade_delay;
gboolean auto_inhibit;
GPtrArray *overlays;
GPtrArray *fading_overlays;
@@ -140,8 +114,6 @@ struct _ClapperGtkVideo
guint fade_timeout;
gboolean reveal, revealed;
guint inhibit_cookie;
/* Current pointer coords and type */
gdouble x, y;
gboolean is_touch;
@@ -174,17 +146,14 @@ _buildable_iface_init (GtkBuildableIface *iface)
}
#define parent_class clapper_gtk_video_parent_class
G_DEFINE_TYPE_WITH_CODE (ClapperGtkVideo, clapper_gtk_video, GTK_TYPE_WIDGET,
G_DEFINE_TYPE_WITH_CODE (ClapperGtkVideo, clapper_gtk_video, CLAPPER_GTK_TYPE_AV,
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, _buildable_iface_init))
enum
{
PROP_0,
PROP_PLAYER,
PROP_FADE_DELAY,
PROP_TOUCH_FADE_DELAY,
PROP_AUTO_INHIBIT,
PROP_INHIBITED,
PROP_LAST
};
@@ -195,209 +164,111 @@ enum
SIGNAL_LAST
};
static gboolean provider_added = FALSE;
static GParamSpec *param_specs[PROP_LAST] = { NULL, };
static guint signals[SIGNAL_LAST] = { 0, };
/* FIXME: 1.0: Remove these compat actions, since they were moved to base class */
static void
toggle_play_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkVideo *self = CLAPPER_GTK_VIDEO_CAST (widget);
ClapperPlayer *player = clapper_gtk_video_get_player (self);
switch (clapper_player_get_state (player)) {
case CLAPPER_PLAYER_STATE_PLAYING:
clapper_player_pause (player);
break;
case CLAPPER_PLAYER_STATE_STOPPED:
case CLAPPER_PLAYER_STATE_PAUSED:
clapper_player_play (player);
break;
default:
break;
}
gtk_widget_activate_action_variant (widget, "av.toggle-play", parameter);
}
static void
play_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkVideo *self = CLAPPER_GTK_VIDEO_CAST (widget);
ClapperPlayer *player = clapper_gtk_video_get_player (self);
clapper_player_play (player);
gtk_widget_activate_action_variant (widget, "av.play", parameter);
}
static void
pause_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkVideo *self = CLAPPER_GTK_VIDEO_CAST (widget);
ClapperPlayer *player = clapper_gtk_video_get_player (self);
clapper_player_pause (player);
gtk_widget_activate_action_variant (widget, "av.pause", parameter);
}
static void
stop_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkVideo *self = CLAPPER_GTK_VIDEO_CAST (widget);
ClapperPlayer *player = clapper_gtk_video_get_player (self);
clapper_player_stop (player);
gtk_widget_activate_action_variant (widget, "av.stop", parameter);
}
static void
seek_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkVideo *self = CLAPPER_GTK_VIDEO_CAST (widget);
ClapperPlayer *player = clapper_gtk_video_get_player (self);
gdouble position = g_variant_get_double (parameter);
clapper_player_seek (player, position);
gtk_widget_activate_action_variant (widget, "av.seek", parameter);
}
static void
seek_custom_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkVideo *self = CLAPPER_GTK_VIDEO_CAST (widget);
ClapperPlayer *player = clapper_gtk_video_get_player (self);
ClapperPlayerSeekMethod method = CLAPPER_PLAYER_SEEK_METHOD_NORMAL;
gdouble position = 0;
g_variant_get (parameter, "(di)", &position, &method);
clapper_player_seek_custom (player, position, method);
gtk_widget_activate_action_variant (widget, "av.seek-custom", parameter);
}
static void
toggle_mute_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkVideo *self = CLAPPER_GTK_VIDEO_CAST (widget);
ClapperPlayer *player = clapper_gtk_video_get_player (self);
clapper_player_set_mute (player, !clapper_player_get_mute (player));
gtk_widget_activate_action_variant (widget, "av.toggle-mute", parameter);
}
static void
set_mute_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkVideo *self = CLAPPER_GTK_VIDEO_CAST (widget);
ClapperPlayer *player = clapper_gtk_video_get_player (self);
gboolean mute = g_variant_get_boolean (parameter);
clapper_player_set_mute (player, mute);
gtk_widget_activate_action_variant (widget, "av.set-mute", parameter);
}
static void
volume_up_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkVideo *self = CLAPPER_GTK_VIDEO_CAST (widget);
ClapperPlayer *player = clapper_gtk_video_get_player (self);
gdouble volume = (clapper_player_get_volume (player) + 0.02);
if (volume > 2.0)
volume = 2.0;
clapper_player_set_volume (player, PERCENTAGE_ROUND (volume));
gtk_widget_activate_action_variant (widget, "av.volume-up", parameter);
}
static void
volume_down_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkVideo *self = CLAPPER_GTK_VIDEO_CAST (widget);
ClapperPlayer *player = clapper_gtk_video_get_player (self);
gdouble volume = (clapper_player_get_volume (player) - 0.02);
if (volume < 0)
volume = 0;
clapper_player_set_volume (player, PERCENTAGE_ROUND (volume));
gtk_widget_activate_action_variant (widget, "av.volume-down", parameter);
}
static void
set_volume_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkVideo *self = CLAPPER_GTK_VIDEO_CAST (widget);
ClapperPlayer *player = clapper_gtk_video_get_player (self);
gdouble volume = g_variant_get_double (parameter);
clapper_player_set_volume (player, volume);
gtk_widget_activate_action_variant (widget, "av.set-volume", parameter);
}
static void
speed_up_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkVideo *self = CLAPPER_GTK_VIDEO_CAST (widget);
ClapperPlayer *player = clapper_gtk_video_get_player (self);
gdouble dest, speed = clapper_player_get_speed (player);
if (speed >= 2.0)
return;
dest = 0.25;
while (speed >= dest)
dest += 0.25;
if (dest > 2.0)
dest = 2.0;
clapper_player_set_speed (player, dest);
gtk_widget_activate_action_variant (widget, "av.speed-up", parameter);
}
static void
speed_down_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkVideo *self = CLAPPER_GTK_VIDEO_CAST (widget);
ClapperPlayer *player = clapper_gtk_video_get_player (self);
gdouble dest, speed = clapper_player_get_speed (player);
if (speed <= 0.05)
return;
dest = 2.0;
while (speed <= dest)
dest -= 0.25;
if (dest < 0.05)
dest = 0.05;
clapper_player_set_speed (player, dest);
gtk_widget_activate_action_variant (widget, "av.speed-down", parameter);
}
static void
set_speed_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkVideo *self = CLAPPER_GTK_VIDEO_CAST (widget);
ClapperPlayer *player = clapper_gtk_video_get_player (self);
gdouble speed = g_variant_get_double (parameter);
clapper_player_set_speed (player, speed);
gtk_widget_activate_action_variant (widget, "av.set-speed", parameter);
}
static void
previous_item_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkVideo *self = CLAPPER_GTK_VIDEO_CAST (widget);
ClapperPlayer *player = clapper_gtk_video_get_player (self);
clapper_queue_select_previous_item (clapper_player_get_queue (player));
gtk_widget_activate_action_variant (widget, "av.previous-item", parameter);
}
static void
next_item_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkVideo *self = CLAPPER_GTK_VIDEO_CAST (widget);
ClapperPlayer *player = clapper_gtk_video_get_player (self);
clapper_queue_select_next_item (clapper_player_get_queue (player));
gtk_widget_activate_action_variant (widget, "av.next-item", parameter);
}
static void
select_item_action_cb (GtkWidget *widget, const gchar *action_name, GVariant *parameter)
{
ClapperGtkVideo *self = CLAPPER_GTK_VIDEO_CAST (widget);
ClapperPlayer *player = clapper_gtk_video_get_player (self);
guint index = g_variant_get_uint32 (parameter);
clapper_queue_select_index (clapper_player_get_queue (player), index);
gtk_widget_activate_action_variant (widget, "av.select-item", parameter);
}
static void
@@ -871,73 +742,6 @@ touch_released_cb (GtkGestureClick *click, gint n_press,
_reset_fade_timeout (self);
}
static void
_ensure_css_provider (void)
{
GdkDisplay *display;
if (provider_added)
return;
display = gdk_display_get_default ();
if (G_LIKELY (display != NULL)) {
GtkCssProvider *provider = gtk_css_provider_new ();
gtk_css_provider_load_from_resource (provider,
CLAPPER_GTK_RESOURCE_PREFIX "/css/styles.css");
gtk_style_context_add_provider_for_display (display,
(GtkStyleProvider *) provider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION - 1);
g_object_unref (provider);
provider_added = TRUE;
}
}
static inline void
_set_inhibit_session (ClapperGtkVideo *self, gboolean inhibit)
{
GtkRoot *root;
GApplication *app;
gboolean inhibited = (self->inhibit_cookie != 0);
if (inhibited == inhibit)
return;
GST_DEBUG_OBJECT (self, "Trying to %sinhibit session...", (inhibit) ? "" : "un");
root = gtk_widget_get_root (GTK_WIDGET (self));
if (!root && !GTK_IS_WINDOW (root)) {
GST_WARNING_OBJECT (self, "Cannot %sinhibit session "
"without root window", (inhibit) ? "" : "un");
return;
}
/* NOTE: Not using application from window prop,
* as it goes away early when unrooting */
app = g_application_get_default ();
if (!app && !GTK_IS_APPLICATION (app)) {
GST_WARNING_OBJECT (self, "Cannot %sinhibit session "
"without window application set", (inhibit) ? "" : "un");
return;
}
if (inhibited) {
gtk_application_uninhibit (GTK_APPLICATION (app), self->inhibit_cookie);
self->inhibit_cookie = 0;
}
if (inhibit) {
self->inhibit_cookie = gtk_application_inhibit (GTK_APPLICATION (app),
GTK_WINDOW (root), GTK_APPLICATION_INHIBIT_IDLE,
"Video is playing");
}
GST_DEBUG_OBJECT (self, "Session %sinhibited", (inhibit) ? "" : "un");
g_object_notify_by_pspec (G_OBJECT (self), param_specs[PROP_INHIBITED]);
}
static inline void
_set_buffering_animation_enabled (ClapperGtkVideo *self, gboolean enabled)
{
@@ -963,9 +767,6 @@ _player_state_changed_cb (ClapperPlayer *player,
{
ClapperPlayerState state = clapper_player_get_state (player);
if (self->auto_inhibit)
_set_inhibit_session (self, state == CLAPPER_PLAYER_STATE_PLAYING);
_set_buffering_animation_enabled (self, state == CLAPPER_PLAYER_STATE_BUFFERING);
}
@@ -1106,7 +907,7 @@ _fading_overlay_revealed_cb (GtkRevealer *revealer,
*
* Creates a new #ClapperGtkVideo instance.
*
* Newly created video widget will also set some default GStreamer elements
* Newly created video widget will also have set some default GStreamer elements
* on its [class@Clapper.Player]. This includes Clapper own video sink and
* a "scaletempo" element as audio filter. Both can still be changed after
* construction by setting corresponding player properties.
@@ -1187,19 +988,21 @@ clapper_gtk_video_add_fading_overlay (ClapperGtkVideo *self, GtkWidget *widget)
}
/**
* clapper_gtk_video_get_player:
* clapper_gtk_video_get_player: (skip)
* @video: a #ClapperGtkVideo
*
* Get #ClapperPlayer used by this #ClapperGtkVideo instance.
*
* Returns: (transfer none): a #ClapperPlayer used by video.
*
* Deprecated: 0.10: Use [method@ClapperGtk.Av.get_player] instead.
*/
ClapperPlayer *
clapper_gtk_video_get_player (ClapperGtkVideo *self)
{
g_return_val_if_fail (CLAPPER_GTK_IS_VIDEO (self), NULL);
return self->player;
return clapper_gtk_av_get_player (CLAPPER_GTK_AV_CAST (self));
}
/**
@@ -1275,60 +1078,58 @@ clapper_gtk_video_get_touch_fade_delay (ClapperGtkVideo *self)
}
/**
* clapper_gtk_video_set_auto_inhibit:
* clapper_gtk_video_set_auto_inhibit: (skip)
* @video: a #ClapperGtkVideo
* @inhibit: whether to enable automatic session inhibit
*
* Set whether video should try to automatically inhibit session
* from idling (and possibly screen going black) when video is playing.
*
* Deprecated: 0.10: Use [method@ClapperGtk.Av.set_auto_inhibit] instead.
*/
void
clapper_gtk_video_set_auto_inhibit (ClapperGtkVideo *self, gboolean inhibit)
{
g_return_if_fail (CLAPPER_GTK_IS_VIDEO (self));
if (self->auto_inhibit != inhibit) {
self->auto_inhibit = inhibit;
/* Uninhibit if we were auto inhibited earlier */
if (!self->auto_inhibit)
_set_inhibit_session (self, FALSE);
g_object_notify_by_pspec (G_OBJECT (self), param_specs[PROP_AUTO_INHIBIT]);
}
clapper_gtk_av_set_auto_inhibit (CLAPPER_GTK_AV_CAST (self), inhibit);
}
/**
* clapper_gtk_video_get_auto_inhibit:
* clapper_gtk_video_get_auto_inhibit: (skip)
* @video: a #ClapperGtkVideo
*
* Get whether automatic session inhibit is enabled.
*
* Returns: %TRUE if enabled, %FALSE otherwise.
*
* Deprecated: 0.10: Use [method@ClapperGtk.Av.get_auto_inhibit] instead.
*/
gboolean
clapper_gtk_video_get_auto_inhibit (ClapperGtkVideo *self)
{
g_return_val_if_fail (CLAPPER_GTK_IS_VIDEO (self), FALSE);
return self->auto_inhibit;
return clapper_gtk_av_get_auto_inhibit (CLAPPER_GTK_AV_CAST (self));
}
/**
* clapper_gtk_video_get_inhibited:
* clapper_gtk_video_get_inhibited: (skip)
* @video: a #ClapperGtkVideo
*
* Get whether session is currently inhibited by
* [property@ClapperGtk.Video:auto-inhibit].
* [property@ClapperGtk.Av:auto-inhibit].
*
* Returns: %TRUE if inhibited, %FALSE otherwise.
*
* Deprecated: 0.10: Use [method@ClapperGtk.Av.get_inhibited] instead.
*/
gboolean
clapper_gtk_video_get_inhibited (ClapperGtkVideo *self)
{
g_return_val_if_fail (CLAPPER_GTK_IS_VIDEO (self), FALSE);
return (self->inhibit_cookie != 0);
return clapper_gtk_av_get_inhibited (CLAPPER_GTK_AV_CAST (self));
}
static void
@@ -1337,8 +1138,6 @@ clapper_gtk_video_root (GtkWidget *widget)
ClapperGtkVideo *self = CLAPPER_GTK_VIDEO_CAST (widget);
GtkRoot *root;
_ensure_css_provider ();
GTK_WIDGET_CLASS (parent_class)->root (widget);
root = gtk_widget_get_root (widget);
@@ -1350,11 +1149,6 @@ clapper_gtk_video_root (GtkWidget *widget)
G_CALLBACK (_window_is_active_cb), self);
_window_is_active_cb (window, NULL, self);
}
if (self->auto_inhibit) {
ClapperPlayerState state = clapper_player_get_state (self->player);
_set_inhibit_session (self, state == CLAPPER_PLAYER_STATE_PLAYING);
}
}
static void
@@ -1368,8 +1162,6 @@ clapper_gtk_video_unroot (GtkWidget *widget)
_window_is_active_cb, self);
}
_set_inhibit_session (self, FALSE);
GTK_WIDGET_CLASS (parent_class)->unroot (widget);
}
@@ -1385,7 +1177,6 @@ clapper_gtk_video_init (ClapperGtkVideo *self)
self->fade_delay = DEFAULT_FADE_DELAY;
self->touch_fade_delay = DEFAULT_TOUCH_FADE_DELAY;
self->auto_inhibit = DEFAULT_AUTO_INHIBIT;
/* Ensure private types */
g_type_ensure (CLAPPER_GTK_TYPE_STATUS);
@@ -1400,15 +1191,18 @@ static void
clapper_gtk_video_constructed (GObject *object)
{
ClapperGtkVideo *self = CLAPPER_GTK_VIDEO_CAST (object);
GstElement *afilter, *vsink;
GstElement *vsink;
ClapperPlayer *player;
ClapperQueue *queue;
self->player = clapper_player_new ();
queue = clapper_player_get_queue (self->player);
G_OBJECT_CLASS (parent_class)->constructed (object);
g_signal_connect (self->player, "notify::state",
player = clapper_gtk_av_get_player (CLAPPER_GTK_AV_CAST (self));
queue = clapper_player_get_queue (player);
g_signal_connect (player, "notify::state",
G_CALLBACK (_player_state_changed_cb), self);
g_signal_connect (self->player, "notify::video-sink",
g_signal_connect (player, "notify::video-sink",
G_CALLBACK (_video_sink_changed_cb), self);
vsink = gst_element_factory_make ("clappersink", NULL);
@@ -1428,28 +1222,23 @@ clapper_gtk_video_constructed (GObject *object)
}
}
clapper_player_set_video_sink (self->player, vsink);
clapper_player_set_video_sink (player, vsink);
}
afilter = gst_element_factory_make ("scaletempo", NULL);
if (G_LIKELY (afilter != NULL))
clapper_player_set_audio_filter (self->player, afilter);
g_signal_connect (self->player, "error",
g_signal_connect (player, "error",
G_CALLBACK (_player_error_cb), self);
g_signal_connect (self->player, "missing-plugin",
g_signal_connect (player, "missing-plugin",
G_CALLBACK (_player_missing_plugin_cb), self);
g_signal_connect (queue, "notify::current-item",
G_CALLBACK (_queue_current_item_changed_cb), self);
G_OBJECT_CLASS (parent_class)->constructed (object);
}
static void
clapper_gtk_video_dispose (GObject *object)
{
ClapperGtkVideo *self = CLAPPER_GTK_VIDEO_CAST (object);
ClapperPlayer *player;
if (self->notify_revealed_id != 0) {
GtkRevealer *revealer = GTK_REVEALER (g_ptr_array_index (self->fading_overlays, 0));
@@ -1460,18 +1249,20 @@ clapper_gtk_video_dispose (GObject *object)
g_clear_handle_id (&self->fade_timeout, g_source_remove);
player = clapper_gtk_av_get_player (CLAPPER_GTK_AV_CAST (self));
/* Something else might still be holding a reference on the player,
* thus we should disconnect everything before disposing template */
if (self->player) {
ClapperQueue *queue = clapper_player_get_queue (self->player);
if (player) { // NULL if dispose run multiple times
ClapperQueue *queue = clapper_player_get_queue (player);
g_signal_handlers_disconnect_by_func (self->player,
g_signal_handlers_disconnect_by_func (player,
_player_state_changed_cb, self);
g_signal_handlers_disconnect_by_func (self->player,
g_signal_handlers_disconnect_by_func (player,
_video_sink_changed_cb, self);
g_signal_handlers_disconnect_by_func (self->player,
g_signal_handlers_disconnect_by_func (player,
_player_error_cb, self);
g_signal_handlers_disconnect_by_func (self->player,
g_signal_handlers_disconnect_by_func (player,
_player_missing_plugin_cb, self);
g_signal_handlers_disconnect_by_func (queue,
@@ -1481,7 +1272,6 @@ clapper_gtk_video_dispose (GObject *object)
gtk_widget_dispose_template (GTK_WIDGET (object), CLAPPER_GTK_TYPE_VIDEO);
g_clear_pointer (&self->overlay, gtk_widget_unparent);
gst_clear_object (&self->player);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
@@ -1504,21 +1294,12 @@ clapper_gtk_video_get_property (GObject *object, guint prop_id,
ClapperGtkVideo *self = CLAPPER_GTK_VIDEO_CAST (object);
switch (prop_id) {
case PROP_PLAYER:
g_value_set_object (value, clapper_gtk_video_get_player (self));
break;
case PROP_FADE_DELAY:
g_value_set_uint (value, clapper_gtk_video_get_fade_delay (self));
break;
case PROP_TOUCH_FADE_DELAY:
g_value_set_uint (value, clapper_gtk_video_get_touch_fade_delay (self));
break;
case PROP_AUTO_INHIBIT:
g_value_set_boolean (value, clapper_gtk_video_get_auto_inhibit (self));
break;
case PROP_INHIBITED:
g_value_set_boolean (value, clapper_gtk_video_get_inhibited (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1538,9 +1319,6 @@ clapper_gtk_video_set_property (GObject *object, guint prop_id,
case PROP_TOUCH_FADE_DELAY:
clapper_gtk_video_set_touch_fade_delay (self, g_value_get_uint (value));
break;
case PROP_AUTO_INHIBIT:
clapper_gtk_video_set_auto_inhibit (self, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1565,15 +1343,6 @@ clapper_gtk_video_class_init (ClapperGtkVideoClass *klass)
gobject_class->dispose = clapper_gtk_video_dispose;
gobject_class->finalize = clapper_gtk_video_finalize;
/**
* ClapperGtkVideo:player:
*
* A #ClapperPlayer used by video.
*/
param_specs[PROP_PLAYER] = g_param_spec_object ("player",
NULL, NULL, CLAPPER_TYPE_PLAYER,
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* ClapperGtkVideo:fade-delay:
*
@@ -1593,24 +1362,6 @@ clapper_gtk_video_class_init (ClapperGtkVideoClass *klass)
NULL, NULL, 1, G_MAXUINT, DEFAULT_TOUCH_FADE_DELAY,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* ClapperGtkVideo:auto-inhibit:
*
* Try to automatically inhibit session when video is playing.
*/
param_specs[PROP_AUTO_INHIBIT] = g_param_spec_boolean ("auto-inhibit",
NULL, NULL, DEFAULT_AUTO_INHIBIT,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* ClapperGtkVideo:inhibited:
*
* Get whether session is currently inhibited by the video.
*/
param_specs[PROP_INHIBITED] = g_param_spec_boolean ("inhibited",
NULL, NULL, FALSE,
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* ClapperGtkVideo::toggle-fullscreen:
* @video: a #ClapperGtkVideo
@@ -1642,6 +1393,8 @@ clapper_gtk_video_class_init (ClapperGtkVideoClass *klass)
g_object_class_install_properties (gobject_class, PROP_LAST, param_specs);
/* FIXME: 1.0: Remove these actions, since they were moved to
* base class AV widget, but are here for compat reasons. */
gtk_widget_class_install_action (widget_class, "video.toggle-play", NULL, toggle_play_action_cb);
gtk_widget_class_install_action (widget_class, "video.play", NULL, play_action_cb);
gtk_widget_class_install_action (widget_class, "video.pause", NULL, pause_action_cb);

View File

@@ -27,6 +27,7 @@
#include <gtk/gtk.h>
#include <clapper/clapper.h>
#include <clapper-gtk/clapper-gtk-av.h>
#include <clapper-gtk/clapper-gtk-visibility.h>
G_BEGIN_DECLS
@@ -35,7 +36,7 @@ G_BEGIN_DECLS
#define CLAPPER_GTK_VIDEO_CAST(obj) ((ClapperGtkVideo *)(obj))
CLAPPER_GTK_API
G_DECLARE_FINAL_TYPE (ClapperGtkVideo, clapper_gtk_video, CLAPPER_GTK, VIDEO, GtkWidget)
G_DECLARE_FINAL_TYPE (ClapperGtkVideo, clapper_gtk_video, CLAPPER_GTK, VIDEO, ClapperGtkAv)
CLAPPER_GTK_API
GtkWidget * clapper_gtk_video_new (void);
@@ -46,7 +47,7 @@ void clapper_gtk_video_add_overlay (ClapperGtkVideo *video, GtkWidget *widget);
CLAPPER_GTK_API
void clapper_gtk_video_add_fading_overlay (ClapperGtkVideo *video, GtkWidget *widget);
CLAPPER_GTK_API
CLAPPER_GTK_DEPRECATED_FOR(clapper_gtk_av_get_player)
ClapperPlayer * clapper_gtk_video_get_player (ClapperGtkVideo *video);
CLAPPER_GTK_API
@@ -61,13 +62,13 @@ void clapper_gtk_video_set_touch_fade_delay (ClapperGtkVideo *video, guint delay
CLAPPER_GTK_API
guint clapper_gtk_video_get_touch_fade_delay (ClapperGtkVideo *video);
CLAPPER_GTK_API
CLAPPER_GTK_DEPRECATED_FOR(clapper_gtk_av_set_auto_inhibit)
void clapper_gtk_video_set_auto_inhibit (ClapperGtkVideo *video, gboolean inhibit);
CLAPPER_GTK_API
CLAPPER_GTK_DEPRECATED_FOR(clapper_gtk_av_get_auto_inhibit)
gboolean clapper_gtk_video_get_auto_inhibit (ClapperGtkVideo *video);
CLAPPER_GTK_API
CLAPPER_GTK_DEPRECATED_FOR(clapper_gtk_av_get_inhibited)
gboolean clapper_gtk_video_get_inhibited (ClapperGtkVideo *video);
G_END_DECLS

View File

@@ -23,6 +23,7 @@
#include <clapper-gtk/clapper-gtk-enums.h>
#include <clapper-gtk/clapper-gtk-version.h>
#include <clapper-gtk/clapper-gtk-av.h>
#include <clapper-gtk/clapper-gtk-billboard.h>
#include <clapper-gtk/clapper-gtk-container.h>
#include <clapper-gtk/clapper-gtk-extra-menu-button.h>

View File

@@ -90,6 +90,7 @@ clappergtk_conf_inc = [
clappergtk_headers = [
'clapper-gtk.h',
'clapper-gtk-av.h',
'clapper-gtk-enums.h',
'clapper-gtk-billboard.h',
'clapper-gtk-container.h',
@@ -109,6 +110,7 @@ clappergtk_headers = [
clappergtk_visibility_header,
]
clappergtk_sources = [
'clapper-gtk-av.c',
'clapper-gtk-billboard.c',
'clapper-gtk-buffering-animation.c',
'clapper-gtk-buffering-paintable.c',

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface domain="clapper-gtk">
<template class="ClapperGtkVideo" parent="GtkWidget">
<template class="ClapperGtkVideo" parent="ClapperGtkAv">
<child type="overlay">
<object class="ClapperGtkStatus" id="status">
<property name="halign">center</property>