mirror of
https://github.com/Rafostar/clapper.git
synced 2025-08-29 23:32:04 +02:00
We need to ensure types that are not part of public API, otherwise GtkBuilder will fail to use them
(e81aad25a1/gtk/glade/README.glade (L15)
).
806 lines
26 KiB
C
806 lines
26 KiB
C
/* 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.
|
|
*/
|
|
|
|
/**
|
|
* ClapperGtkExtraMenuButton:
|
|
*
|
|
* A menu button with extra options.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <math.h>
|
|
#include <glib/gi18n-lib.h>
|
|
#include <clapper/clapper.h>
|
|
|
|
#include "clapper-gtk-extra-menu-button.h"
|
|
#include "clapper-gtk-stream-check-button-private.h"
|
|
#include "clapper-gtk-utils-private.h"
|
|
|
|
#define PERCENTAGE_ROUND(a) (round ((gdouble) a / 0.01) * 0.01)
|
|
|
|
#define DEFAULT_CAN_OPEN_SUBTITLES FALSE
|
|
|
|
#define GST_CAT_DEFAULT clapper_gtk_extra_menu_button_debug
|
|
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
|
|
|
struct _ClapperGtkExtraMenuButton
|
|
{
|
|
GtkWidget parent;
|
|
|
|
GtkWidget *menu_button;
|
|
|
|
GtkWidget *volume_box;
|
|
GtkWidget *volume_button;
|
|
GtkWidget *volume_spin;
|
|
|
|
GtkWidget *speed_box;
|
|
GtkWidget *speed_button;
|
|
GtkWidget *speed_spin;
|
|
|
|
GtkWidget *top_separator;
|
|
|
|
GtkWidget *video_list_view;
|
|
GtkScrolledWindow *video_sw;
|
|
|
|
GtkWidget *audio_list_view;
|
|
GtkScrolledWindow *audio_sw;
|
|
|
|
GtkWidget *subtitle_list_view;
|
|
GtkScrolledWindow *subtitle_sw;
|
|
|
|
ClapperPlayer *player;
|
|
ClapperMediaItem *current_item;
|
|
|
|
GSimpleActionGroup *action_group;
|
|
|
|
gboolean mute;
|
|
|
|
GBinding *volume_binding;
|
|
GBinding *speed_binding;
|
|
|
|
GBinding *video_binding;
|
|
GBinding *audio_binding;
|
|
GBinding *subtitle_binding;
|
|
|
|
gboolean can_open_subtitles;
|
|
};
|
|
|
|
#define parent_class clapper_gtk_extra_menu_button_parent_class
|
|
G_DEFINE_TYPE (ClapperGtkExtraMenuButton, clapper_gtk_extra_menu_button, GTK_TYPE_WIDGET)
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
PROP_VOLUME_VISIBLE,
|
|
PROP_SPEED_VISIBLE,
|
|
PROP_CAN_OPEN_SUBTITLES,
|
|
PROP_LAST
|
|
};
|
|
|
|
enum
|
|
{
|
|
SIGNAL_OPEN_SUBTITLES,
|
|
SIGNAL_LAST
|
|
};
|
|
|
|
static GParamSpec *param_specs[PROP_LAST] = { NULL, };
|
|
static guint signals[SIGNAL_LAST] = { 0, };
|
|
|
|
static void
|
|
_set_action_enabled (ClapperGtkExtraMenuButton *self, const gchar *name, gboolean enabled)
|
|
{
|
|
GAction *action = g_action_map_lookup_action (G_ACTION_MAP (self->action_group), name);
|
|
gboolean was_enabled = g_action_get_enabled (action);
|
|
|
|
if (was_enabled == enabled)
|
|
return;
|
|
|
|
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), enabled);
|
|
}
|
|
|
|
static gboolean
|
|
_double_transform_func (GBinding *binding, const GValue *from_value,
|
|
GValue *to_value, gpointer user_data G_GNUC_UNUSED)
|
|
{
|
|
gdouble val_dbl = g_value_get_double (from_value);
|
|
|
|
g_value_set_double (to_value, PERCENTAGE_ROUND (val_dbl));
|
|
return TRUE;
|
|
}
|
|
|
|
static gint
|
|
volume_spin_input_cb (GtkSpinButton *spin_button, gdouble *value, ClapperGtkExtraMenuButton *self)
|
|
{
|
|
const gchar *text = gtk_editable_get_text (GTK_EDITABLE (spin_button));
|
|
gdouble volume = g_strtod (text, NULL);
|
|
|
|
if (volume < 0)
|
|
volume = 0;
|
|
else if (volume > 200)
|
|
volume = 200;
|
|
|
|
volume /= 100.0;
|
|
|
|
if (volume > 0.99 && volume < 1.01)
|
|
volume = 1.0;
|
|
|
|
*value = volume;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
volume_spin_output_cb (GtkSpinButton *spin_button, ClapperGtkExtraMenuButton *self)
|
|
{
|
|
GtkAdjustment *adjustment = gtk_spin_button_get_adjustment (spin_button);
|
|
gdouble volume = gtk_adjustment_get_value (adjustment);
|
|
gchar *volume_str;
|
|
|
|
volume_str = g_strdup_printf ("%.0lf%%", volume * 100);
|
|
gtk_editable_set_text (GTK_EDITABLE (spin_button), volume_str);
|
|
g_free (volume_str);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
volume_spin_changed_cb (GtkSpinButton *spin_button, ClapperGtkExtraMenuButton *self)
|
|
{
|
|
GtkAdjustment *adjustment = gtk_spin_button_get_adjustment (spin_button);
|
|
gdouble volume = gtk_adjustment_get_value (adjustment);
|
|
|
|
gtk_button_set_icon_name (GTK_BUTTON (self->volume_button),
|
|
clapper_gtk_get_icon_name_for_volume ((!self->mute) ? volume : 0));
|
|
}
|
|
|
|
static gint
|
|
speed_spin_input_cb (GtkSpinButton *spin_button, gdouble *value, ClapperGtkExtraMenuButton *self)
|
|
{
|
|
const gchar *text = gtk_editable_get_text (GTK_EDITABLE (spin_button));
|
|
gdouble speed = g_strtod (text, NULL);
|
|
|
|
if (speed < 0.05)
|
|
speed = 0.05;
|
|
else if (speed > 2.0)
|
|
speed = 2.0;
|
|
|
|
if (speed > 0.99 && speed < 1.01)
|
|
speed = 1.0;
|
|
|
|
*value = speed;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
speed_spin_output_cb (GtkSpinButton *spin_button, ClapperGtkExtraMenuButton *self)
|
|
{
|
|
GtkAdjustment *adjustment = gtk_spin_button_get_adjustment (spin_button);
|
|
gdouble speed = gtk_adjustment_get_value (adjustment);
|
|
gchar *speed_str;
|
|
|
|
speed_str = g_strdup_printf ("%.2lfx", speed);
|
|
gtk_editable_set_text (GTK_EDITABLE (spin_button), speed_str);
|
|
g_free (speed_str);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
speed_spin_changed_cb (GtkSpinButton *spin_button, ClapperGtkExtraMenuButton *self)
|
|
{
|
|
GtkAdjustment *adjustment = gtk_spin_button_get_adjustment (spin_button);
|
|
gdouble speed = gtk_adjustment_get_value (adjustment);
|
|
|
|
gtk_button_set_icon_name (GTK_BUTTON (self->speed_button),
|
|
clapper_gtk_get_icon_name_for_speed (speed));
|
|
}
|
|
|
|
static void
|
|
visible_submenu_changed_cb (GtkPopoverMenu *popover_menu,
|
|
GParamSpec *pspec G_GNUC_UNUSED, ClapperGtkExtraMenuButton *self)
|
|
{
|
|
gchar *name = NULL;
|
|
gboolean in_video, in_audio, in_subtitles;
|
|
|
|
g_object_get (popover_menu, "visible-submenu", &name, NULL);
|
|
|
|
/* TODO: Check if we have to compare translated strings here */
|
|
GST_DEBUG ("Visible submenu changed to: \"%s\"", name);
|
|
|
|
in_video = (g_strcmp0 (name, _("Video")) == 0);
|
|
in_audio = (g_strcmp0 (name, _("Audio")) == 0);
|
|
in_subtitles = (g_strcmp0 (name, _("Subtitles")) == 0);
|
|
|
|
/* XXX: This works around the issue where popover does not adapt its
|
|
* width when navigating submenus making spin buttons unnecesary centered */
|
|
gtk_scrolled_window_set_propagate_natural_width (self->video_sw, in_video);
|
|
gtk_scrolled_window_set_propagate_natural_width (self->audio_sw, in_audio);
|
|
gtk_scrolled_window_set_propagate_natural_width (self->subtitle_sw, in_subtitles);
|
|
|
|
g_free (name);
|
|
}
|
|
|
|
static void
|
|
_subtitles_enabled_changed_cb (ClapperPlayer *player,
|
|
GParamSpec *pspec G_GNUC_UNUSED, ClapperGtkExtraMenuButton *self)
|
|
{
|
|
GAction *action = g_action_map_lookup_action (
|
|
G_ACTION_MAP (self->action_group), "subtitle-stream-enabled");
|
|
GVariant *variant = g_action_get_state (action);
|
|
gboolean was_enabled, enabled;
|
|
|
|
was_enabled = g_variant_get_boolean (variant);
|
|
enabled = clapper_player_get_subtitles_enabled (player);
|
|
|
|
g_variant_unref (variant);
|
|
|
|
if (was_enabled == enabled)
|
|
return;
|
|
|
|
variant = g_variant_ref_sink (g_variant_new_boolean (enabled));
|
|
|
|
g_simple_action_set_state (G_SIMPLE_ACTION (action), variant);
|
|
g_variant_unref (variant);
|
|
}
|
|
|
|
static void
|
|
_player_mute_changed_cb (ClapperPlayer *player,
|
|
GParamSpec *pspec G_GNUC_UNUSED, ClapperGtkExtraMenuButton *self)
|
|
{
|
|
self->mute = clapper_player_get_mute (player);
|
|
|
|
volume_spin_changed_cb (GTK_SPIN_BUTTON (self->volume_spin), self);
|
|
}
|
|
|
|
static void
|
|
_queue_current_item_changed_cb (ClapperQueue *queue,
|
|
GParamSpec *pspec G_GNUC_UNUSED, ClapperGtkExtraMenuButton *self)
|
|
{
|
|
ClapperMediaItem *current_item = clapper_queue_get_current_item (queue);
|
|
|
|
/* NOTE: This is also called after popover "map" signal */
|
|
|
|
if (gst_object_replace ((GstObject **) &self->current_item, GST_OBJECT_CAST (current_item))) {
|
|
_set_action_enabled (self, "open-subtitle-stream",
|
|
(self->can_open_subtitles && self->current_item != NULL));
|
|
}
|
|
|
|
gst_clear_object (¤t_item);
|
|
}
|
|
|
|
static void
|
|
change_subtitle_stream_enabled (GSimpleAction *action, GVariant *value, gpointer user_data)
|
|
{
|
|
ClapperGtkExtraMenuButton *self = CLAPPER_GTK_EXTRA_MENU_BUTTON_CAST (user_data);
|
|
gboolean enable = g_variant_get_boolean (value);
|
|
|
|
if (G_LIKELY (self->player != NULL))
|
|
clapper_player_set_subtitles_enabled (self->player, enable);
|
|
|
|
g_simple_action_set_state (action, value);
|
|
}
|
|
|
|
static void
|
|
open_subtitle_stream (GSimpleAction *action, GVariant *param, gpointer user_data)
|
|
{
|
|
ClapperGtkExtraMenuButton *self = CLAPPER_GTK_EXTRA_MENU_BUTTON_CAST (user_data);
|
|
|
|
/* We should not be here otherwise */
|
|
if (G_LIKELY (self->can_open_subtitles && self->current_item != NULL))
|
|
g_signal_emit (self, signals[SIGNAL_OPEN_SUBTITLES], 0, self->current_item);
|
|
}
|
|
|
|
static void
|
|
_determine_top_separator_visibility (ClapperGtkExtraMenuButton *self)
|
|
{
|
|
gboolean visible = gtk_widget_get_visible (self->volume_box)
|
|
|| gtk_widget_get_visible (self->speed_box);
|
|
|
|
gtk_widget_set_visible (self->top_separator, visible);
|
|
}
|
|
|
|
/**
|
|
* clapper_gtk_extra_menu_button_new:
|
|
*
|
|
* Creates a new #ClapperGtkExtraMenuButton instance.
|
|
*
|
|
* Returns: a new extra menu button #GtkWidget.
|
|
*/
|
|
GtkWidget *
|
|
clapper_gtk_extra_menu_button_new (void)
|
|
{
|
|
return g_object_new (CLAPPER_GTK_TYPE_EXTRA_MENU_BUTTON, NULL);
|
|
}
|
|
|
|
/**
|
|
* clapper_gtk_extra_menu_button_set_volume_visible:
|
|
* @button: a #ClapperGtkExtraMenuButton
|
|
* @visible: whether visible
|
|
*
|
|
* Set whether volume control inside popover should be visible.
|
|
*/
|
|
void
|
|
clapper_gtk_extra_menu_button_set_volume_visible (ClapperGtkExtraMenuButton *self, gboolean visible)
|
|
{
|
|
g_return_if_fail (CLAPPER_GTK_IS_EXTRA_MENU_BUTTON (self));
|
|
|
|
if (gtk_widget_get_visible (self->volume_box) != visible) {
|
|
gtk_widget_set_visible (self->volume_box, visible);
|
|
_determine_top_separator_visibility (self);
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), param_specs[PROP_VOLUME_VISIBLE]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* clapper_gtk_extra_menu_button_get_volume_visible:
|
|
* @button: a #ClapperGtkExtraMenuButton
|
|
*
|
|
* Get whether volume control inside popover is visible.
|
|
*
|
|
* Returns: TRUE if volume control is visible, %FALSE otherwise.
|
|
*/
|
|
gboolean
|
|
clapper_gtk_extra_menu_button_get_volume_visible (ClapperGtkExtraMenuButton *self)
|
|
{
|
|
g_return_val_if_fail (CLAPPER_GTK_IS_EXTRA_MENU_BUTTON (self), FALSE);
|
|
|
|
return gtk_widget_get_visible (self->volume_box);
|
|
}
|
|
|
|
/**
|
|
* clapper_gtk_extra_menu_button_set_speed_visible:
|
|
* @button: a #ClapperGtkExtraMenuButton
|
|
* @visible: whether visible
|
|
*
|
|
* Set whether speed control inside popover should be visible.
|
|
*/
|
|
void
|
|
clapper_gtk_extra_menu_button_set_speed_visible (ClapperGtkExtraMenuButton *self, gboolean visible)
|
|
{
|
|
g_return_if_fail (CLAPPER_GTK_IS_EXTRA_MENU_BUTTON (self));
|
|
|
|
if (gtk_widget_get_visible (self->speed_box) != visible) {
|
|
gtk_widget_set_visible (self->speed_box, visible);
|
|
_determine_top_separator_visibility (self);
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), param_specs[PROP_SPEED_VISIBLE]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* clapper_gtk_extra_menu_button_get_speed_visible:
|
|
* @button: a #ClapperGtkExtraMenuButton
|
|
*
|
|
* Get whether speed control inside popover is visible.
|
|
*
|
|
* Returns: %TRUE if speed control is visible, %FALSE otherwise.
|
|
*/
|
|
gboolean
|
|
clapper_gtk_extra_menu_button_get_speed_visible (ClapperGtkExtraMenuButton *self)
|
|
{
|
|
g_return_val_if_fail (CLAPPER_GTK_IS_EXTRA_MENU_BUTTON (self), FALSE);
|
|
|
|
return gtk_widget_get_visible (self->speed_box);
|
|
}
|
|
|
|
/**
|
|
* clapper_gtk_extra_menu_button_set_can_open_subtitles:
|
|
* @button: a #ClapperGtkExtraMenuButton
|
|
* @allowed: whether opening subtitles should be allowed
|
|
*
|
|
* Set whether an option to open external subtitle stream should be allowed.
|
|
*
|
|
* Note that this [class@Gtk.Widget] can only add subtitles to currently playing
|
|
* [class@Clapper.MediaItem]. When no media is selected, option to open subtitles
|
|
* will not be shown regardless how this option is set.
|
|
*/
|
|
void
|
|
clapper_gtk_extra_menu_button_set_can_open_subtitles (ClapperGtkExtraMenuButton *self, gboolean allowed)
|
|
{
|
|
gboolean changed;
|
|
|
|
g_return_if_fail (CLAPPER_GTK_IS_EXTRA_MENU_BUTTON (self));
|
|
|
|
if ((changed = self->can_open_subtitles != allowed)) {
|
|
self->can_open_subtitles = allowed;
|
|
|
|
_set_action_enabled (self, "open-subtitle-stream",
|
|
(self->can_open_subtitles && self->current_item != NULL));
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), param_specs[PROP_CAN_OPEN_SUBTITLES]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* clapper_gtk_extra_menu_button_get_can_open_subtitles:
|
|
* @button: a #ClapperGtkExtraMenuButton
|
|
*
|
|
* Get whether an option to open external subtitle stream inside popover is visible.
|
|
*
|
|
* Returns: %TRUE if open subtitles is visible, %FALSE otherwise.
|
|
*/
|
|
gboolean
|
|
clapper_gtk_extra_menu_button_get_can_open_subtitles (ClapperGtkExtraMenuButton *self)
|
|
{
|
|
g_return_val_if_fail (CLAPPER_GTK_IS_EXTRA_MENU_BUTTON (self), FALSE);
|
|
|
|
return self->can_open_subtitles;
|
|
}
|
|
|
|
static void
|
|
clapper_gtk_extra_menu_button_init (ClapperGtkExtraMenuButton *self)
|
|
{
|
|
static GActionEntry action_entries[] = {
|
|
{ "subtitle-stream-enabled", NULL, NULL, "true", change_subtitle_stream_enabled },
|
|
{ "open-subtitle-stream", open_subtitle_stream, NULL, NULL, NULL },
|
|
};
|
|
|
|
/* Ensure private types */
|
|
g_type_ensure (CLAPPER_GTK_TYPE_STREAM_CHECK_BUTTON);
|
|
|
|
gtk_widget_init_template (GTK_WIDGET (self));
|
|
|
|
self->action_group = g_simple_action_group_new ();
|
|
|
|
g_object_bind_property (self, "css-classes", self->menu_button,
|
|
"css-classes", G_BINDING_DEFAULT);
|
|
|
|
g_action_map_add_action_entries (G_ACTION_MAP (self->action_group),
|
|
action_entries, G_N_ELEMENTS (action_entries), self);
|
|
gtk_widget_insert_action_group (GTK_WIDGET (self),
|
|
"clappergtk", G_ACTION_GROUP (self->action_group));
|
|
|
|
/* Set default values */
|
|
self->can_open_subtitles = DEFAULT_CAN_OPEN_SUBTITLES;
|
|
_set_action_enabled (self, "open-subtitle-stream", self->can_open_subtitles);
|
|
}
|
|
|
|
static void
|
|
clapper_gtk_extra_menu_button_compute_expand (GtkWidget *widget,
|
|
gboolean *hexpand_p, gboolean *vexpand_p)
|
|
{
|
|
GtkWidget *child;
|
|
gboolean hexpand = FALSE;
|
|
gboolean vexpand = FALSE;
|
|
|
|
if ((child = gtk_widget_get_first_child (widget))) {
|
|
hexpand = gtk_widget_compute_expand (child, GTK_ORIENTATION_HORIZONTAL);
|
|
vexpand = gtk_widget_compute_expand (child, GTK_ORIENTATION_VERTICAL);
|
|
}
|
|
|
|
*hexpand_p = hexpand;
|
|
*vexpand_p = vexpand;
|
|
}
|
|
|
|
static void
|
|
clapper_gtk_extra_menu_button_realize (GtkWidget *widget)
|
|
{
|
|
ClapperGtkExtraMenuButton *self = CLAPPER_GTK_EXTRA_MENU_BUTTON_CAST (widget);
|
|
|
|
GST_TRACE_OBJECT (self, "Realize");
|
|
|
|
if ((self->player = clapper_gtk_get_player_from_ancestor (GTK_WIDGET (self)))) {
|
|
ClapperStreamList *stream_list;
|
|
GtkSingleSelection *selection;
|
|
|
|
g_signal_connect (self->player, "notify::mute",
|
|
G_CALLBACK (_player_mute_changed_cb), self);
|
|
self->mute = clapper_player_get_mute (self->player);
|
|
|
|
stream_list = clapper_player_get_video_streams (self->player);
|
|
selection = gtk_single_selection_new (gst_object_ref (stream_list));
|
|
gtk_single_selection_set_autoselect (selection, FALSE);
|
|
|
|
self->video_binding = g_object_bind_property (stream_list, "current-index",
|
|
selection, "selected", G_BINDING_SYNC_CREATE);
|
|
|
|
gtk_list_view_set_model (GTK_LIST_VIEW (self->video_list_view),
|
|
GTK_SELECTION_MODEL (selection));
|
|
g_object_unref (selection);
|
|
|
|
stream_list = clapper_player_get_audio_streams (self->player);
|
|
selection = gtk_single_selection_new (gst_object_ref (stream_list));
|
|
gtk_single_selection_set_autoselect (selection, FALSE);
|
|
|
|
self->audio_binding = g_object_bind_property (stream_list, "current-index",
|
|
selection, "selected", G_BINDING_SYNC_CREATE);
|
|
|
|
gtk_list_view_set_model (GTK_LIST_VIEW (self->audio_list_view),
|
|
GTK_SELECTION_MODEL (selection));
|
|
g_object_unref (selection);
|
|
|
|
stream_list = clapper_player_get_subtitle_streams (self->player);
|
|
selection = gtk_single_selection_new (gst_object_ref (stream_list));
|
|
gtk_single_selection_set_autoselect (selection, FALSE);
|
|
|
|
self->subtitle_binding = g_object_bind_property (stream_list, "current-index",
|
|
selection, "selected", G_BINDING_SYNC_CREATE);
|
|
|
|
gtk_list_view_set_model (GTK_LIST_VIEW (self->subtitle_list_view),
|
|
GTK_SELECTION_MODEL (selection));
|
|
g_object_unref (selection);
|
|
}
|
|
|
|
GTK_WIDGET_CLASS (parent_class)->realize (widget);
|
|
}
|
|
|
|
static void
|
|
clapper_gtk_extra_menu_button_unrealize (GtkWidget *widget)
|
|
{
|
|
ClapperGtkExtraMenuButton *self = CLAPPER_GTK_EXTRA_MENU_BUTTON_CAST (widget);
|
|
|
|
GST_TRACE_OBJECT (self, "Unrealize");
|
|
|
|
g_clear_pointer (&self->video_binding, g_binding_unbind);
|
|
g_clear_pointer (&self->audio_binding, g_binding_unbind);
|
|
g_clear_pointer (&self->subtitle_binding, g_binding_unbind);
|
|
|
|
gtk_list_view_set_model (GTK_LIST_VIEW (self->video_list_view), NULL);
|
|
gtk_list_view_set_model (GTK_LIST_VIEW (self->audio_list_view), NULL);
|
|
gtk_list_view_set_model (GTK_LIST_VIEW (self->subtitle_list_view), NULL);
|
|
|
|
if (self->player) {
|
|
g_signal_handlers_disconnect_by_func (self->player, _player_mute_changed_cb, self);
|
|
|
|
self->player = NULL;
|
|
}
|
|
|
|
GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
|
|
}
|
|
|
|
static void
|
|
popover_map_cb (GtkWidget *widget, ClapperGtkExtraMenuButton *self)
|
|
{
|
|
ClapperQueue *queue;
|
|
|
|
GST_TRACE_OBJECT (self, "Popover map");
|
|
|
|
if (G_UNLIKELY (self->player == NULL))
|
|
return;
|
|
|
|
queue = clapper_player_get_queue (self->player);
|
|
|
|
self->volume_binding = g_object_bind_property_full (self->player, "volume",
|
|
self->volume_spin, "value",
|
|
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE,
|
|
(GBindingTransformFunc) _double_transform_func,
|
|
(GBindingTransformFunc) _double_transform_func,
|
|
NULL, NULL);
|
|
self->speed_binding = g_object_bind_property_full (self->player, "speed",
|
|
self->speed_spin, "value",
|
|
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE,
|
|
(GBindingTransformFunc) _double_transform_func,
|
|
(GBindingTransformFunc) _double_transform_func,
|
|
NULL, NULL);
|
|
|
|
g_signal_connect (self->player, "notify::subtitles-enabled",
|
|
G_CALLBACK (_subtitles_enabled_changed_cb), self);
|
|
_subtitles_enabled_changed_cb (self->player, NULL, self);
|
|
|
|
g_signal_connect (queue, "notify::current-item",
|
|
G_CALLBACK (_queue_current_item_changed_cb), self);
|
|
_queue_current_item_changed_cb (queue, NULL, self);
|
|
}
|
|
|
|
static void
|
|
popover_unmap_cb (GtkWidget *widget, ClapperGtkExtraMenuButton *self)
|
|
{
|
|
ClapperQueue *queue;
|
|
|
|
GST_TRACE_OBJECT (self, "Popover unmap");
|
|
|
|
if (G_UNLIKELY (self->player == NULL))
|
|
return;
|
|
|
|
queue = clapper_player_get_queue (self->player);
|
|
|
|
g_clear_pointer (&self->volume_binding, g_binding_unbind);
|
|
g_clear_pointer (&self->speed_binding, g_binding_unbind);
|
|
|
|
g_signal_handlers_disconnect_by_func (self->player, _subtitles_enabled_changed_cb, self);
|
|
g_signal_handlers_disconnect_by_func (queue, _queue_current_item_changed_cb, self);
|
|
}
|
|
|
|
static void
|
|
clapper_gtk_extra_menu_button_dispose (GObject *object)
|
|
{
|
|
ClapperGtkExtraMenuButton *self = CLAPPER_GTK_EXTRA_MENU_BUTTON_CAST (object);
|
|
|
|
gtk_widget_dispose_template (GTK_WIDGET (object), CLAPPER_GTK_TYPE_EXTRA_MENU_BUTTON);
|
|
|
|
g_clear_pointer (&self->menu_button, gtk_widget_unparent);
|
|
|
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
clapper_gtk_extra_menu_button_finalize (GObject *object)
|
|
{
|
|
ClapperGtkExtraMenuButton *self = CLAPPER_GTK_EXTRA_MENU_BUTTON_CAST (object);
|
|
|
|
GST_TRACE_OBJECT (self, "Finalize");
|
|
|
|
gst_clear_object (&self->current_item);
|
|
g_object_unref (self->action_group);
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
clapper_gtk_extra_menu_button_get_property (GObject *object, guint prop_id,
|
|
GValue *value, GParamSpec *pspec)
|
|
{
|
|
ClapperGtkExtraMenuButton *self = CLAPPER_GTK_EXTRA_MENU_BUTTON_CAST (object);
|
|
|
|
switch (prop_id) {
|
|
case PROP_VOLUME_VISIBLE:
|
|
g_value_set_boolean (value, clapper_gtk_extra_menu_button_get_volume_visible (self));
|
|
break;
|
|
case PROP_SPEED_VISIBLE:
|
|
g_value_set_boolean (value, clapper_gtk_extra_menu_button_get_speed_visible (self));
|
|
break;
|
|
case PROP_CAN_OPEN_SUBTITLES:
|
|
g_value_set_boolean (value, clapper_gtk_extra_menu_button_get_can_open_subtitles (self));
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
clapper_gtk_extra_menu_button_set_property (GObject *object, guint prop_id,
|
|
const GValue *value, GParamSpec *pspec)
|
|
{
|
|
ClapperGtkExtraMenuButton *self = CLAPPER_GTK_EXTRA_MENU_BUTTON_CAST (object);
|
|
|
|
switch (prop_id) {
|
|
case PROP_VOLUME_VISIBLE:
|
|
clapper_gtk_extra_menu_button_set_volume_visible (self, g_value_get_boolean (value));
|
|
break;
|
|
case PROP_SPEED_VISIBLE:
|
|
clapper_gtk_extra_menu_button_set_speed_visible (self, g_value_get_boolean (value));
|
|
break;
|
|
case PROP_CAN_OPEN_SUBTITLES:
|
|
clapper_gtk_extra_menu_button_set_can_open_subtitles (self, g_value_get_boolean (value));
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
clapper_gtk_extra_menu_button_class_init (ClapperGtkExtraMenuButtonClass *klass)
|
|
{
|
|
GObjectClass *gobject_class = (GObjectClass *) klass;
|
|
GtkWidgetClass *widget_class = (GtkWidgetClass *) klass;
|
|
|
|
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clappergtkextramenubutton", 0,
|
|
"Clapper GTK Extra Menu Button");
|
|
clapper_gtk_init_translations ();
|
|
|
|
gobject_class->get_property = clapper_gtk_extra_menu_button_get_property;
|
|
gobject_class->set_property = clapper_gtk_extra_menu_button_set_property;
|
|
gobject_class->dispose = clapper_gtk_extra_menu_button_dispose;
|
|
gobject_class->finalize = clapper_gtk_extra_menu_button_finalize;
|
|
|
|
widget_class->compute_expand = clapper_gtk_extra_menu_button_compute_expand;
|
|
widget_class->realize = clapper_gtk_extra_menu_button_realize;
|
|
widget_class->unrealize = clapper_gtk_extra_menu_button_unrealize;
|
|
|
|
/**
|
|
* ClapperGtkExtraMenuButton:volume-visible:
|
|
*
|
|
* Visibility of volume control inside popover.
|
|
*/
|
|
param_specs[PROP_VOLUME_VISIBLE] = g_param_spec_boolean ("volume-visible",
|
|
NULL, NULL, TRUE,
|
|
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
|
|
|
/**
|
|
* ClapperGtkExtraMenuButton:speed-visible:
|
|
*
|
|
* Visibility of speed control inside popover.
|
|
*/
|
|
param_specs[PROP_SPEED_VISIBLE] = g_param_spec_boolean ("speed-visible",
|
|
NULL, NULL, TRUE,
|
|
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
|
|
|
/**
|
|
* ClapperGtkExtraMenuButton:can-open-subtitles:
|
|
*
|
|
* Visibility of open subtitles option inside popover.
|
|
*/
|
|
param_specs[PROP_CAN_OPEN_SUBTITLES] = g_param_spec_boolean ("can-open-subtitles",
|
|
NULL, NULL, FALSE,
|
|
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
|
|
|
/**
|
|
* ClapperGtkExtraMenuButton::open-subtitles:
|
|
* @button: a #ClapperGtkExtraMenuButton
|
|
* @item: a #ClapperMediaItem
|
|
*
|
|
* A signal that user wants to open subtitles file.
|
|
*
|
|
* Implementation should add a way for user to select subtitles to open
|
|
* such as by e.g. using [class@Gtk.FileDialog] and then add them to the
|
|
* @item using [method@Clapper.MediaItem.set_suburi] method.
|
|
*
|
|
* This signal will pass the [class@Clapper.MediaItem] that was current when
|
|
* user clicked the open button and subtitles should be added to this @item.
|
|
* This avoids situations where another item starts playing before user selects
|
|
* subtitles file to be opened. When using asynchronous operations to open file,
|
|
* implementation should [method@GObject.Object.ref] the item to ensure that it
|
|
* stays valid until finish.
|
|
*
|
|
* Note that this signal will not be emitted if open button is not visible by
|
|
* setting [method@ClapperGtk.ExtraMenuButton.set_can_open_subtitles] to %TRUE,
|
|
* so you do not have to implement handler for it otherwise.
|
|
*/
|
|
signals[SIGNAL_OPEN_SUBTITLES] = g_signal_new ("open-subtitles",
|
|
G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
|
|
0, NULL, NULL, NULL, G_TYPE_NONE, 1, CLAPPER_TYPE_MEDIA_ITEM);
|
|
|
|
g_object_class_install_properties (gobject_class, PROP_LAST, param_specs);
|
|
|
|
gtk_widget_class_set_template_from_resource (widget_class,
|
|
CLAPPER_GTK_RESOURCE_PREFIX "/ui/clapper-gtk-extra-menu-button.ui");
|
|
|
|
gtk_widget_class_bind_template_child (widget_class, ClapperGtkExtraMenuButton, menu_button);
|
|
|
|
gtk_widget_class_bind_template_child (widget_class, ClapperGtkExtraMenuButton, volume_box);
|
|
gtk_widget_class_bind_template_child (widget_class, ClapperGtkExtraMenuButton, volume_button);
|
|
gtk_widget_class_bind_template_child (widget_class, ClapperGtkExtraMenuButton, volume_spin);
|
|
|
|
gtk_widget_class_bind_template_child (widget_class, ClapperGtkExtraMenuButton, speed_box);
|
|
gtk_widget_class_bind_template_child (widget_class, ClapperGtkExtraMenuButton, speed_button);
|
|
gtk_widget_class_bind_template_child (widget_class, ClapperGtkExtraMenuButton, speed_spin);
|
|
|
|
gtk_widget_class_bind_template_child (widget_class, ClapperGtkExtraMenuButton, top_separator);
|
|
|
|
gtk_widget_class_bind_template_child (widget_class, ClapperGtkExtraMenuButton, video_list_view);
|
|
gtk_widget_class_bind_template_child (widget_class, ClapperGtkExtraMenuButton, video_sw);
|
|
|
|
gtk_widget_class_bind_template_child (widget_class, ClapperGtkExtraMenuButton, audio_list_view);
|
|
gtk_widget_class_bind_template_child (widget_class, ClapperGtkExtraMenuButton, audio_sw);
|
|
|
|
gtk_widget_class_bind_template_child (widget_class, ClapperGtkExtraMenuButton, subtitle_list_view);
|
|
gtk_widget_class_bind_template_child (widget_class, ClapperGtkExtraMenuButton, subtitle_sw);
|
|
|
|
gtk_widget_class_bind_template_callback (widget_class, volume_spin_input_cb);
|
|
gtk_widget_class_bind_template_callback (widget_class, volume_spin_output_cb);
|
|
gtk_widget_class_bind_template_callback (widget_class, volume_spin_changed_cb);
|
|
|
|
gtk_widget_class_bind_template_callback (widget_class, speed_spin_input_cb);
|
|
gtk_widget_class_bind_template_callback (widget_class, speed_spin_output_cb);
|
|
gtk_widget_class_bind_template_callback (widget_class, speed_spin_changed_cb);
|
|
|
|
gtk_widget_class_bind_template_callback (widget_class, popover_map_cb);
|
|
gtk_widget_class_bind_template_callback (widget_class, popover_unmap_cb);
|
|
gtk_widget_class_bind_template_callback (widget_class, visible_submenu_changed_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_BUTTON);
|
|
gtk_widget_class_set_css_name (widget_class, "clapper-gtk-extra-menu-button");
|
|
}
|