summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/controls.ui5
-rw-r--r--docs/reference/meson.build4
-rw-r--r--docs/reference/totem-sections.txt6
-rw-r--r--meson.build1
-rw-r--r--src/backend/bacon-video-widget.c999
-rw-r--r--src/backend/bacon-video-widget.h22
-rw-r--r--src/backend/bvw-test.c36
-rw-r--r--src/backend/meson.build8
-rw-r--r--src/meson.build4
-rw-r--r--src/plugins/rotation/totem-rotation.c5
-rw-r--r--src/totem-object.c367
-rw-r--r--src/totem-private.h9
12 files changed, 420 insertions, 1046 deletions
diff --git a/data/controls.ui b/data/controls.ui
index a7ebe9468..a9b1b59e4 100644
--- a/data/controls.ui
+++ b/data/controls.ui
@@ -9,6 +9,11 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">0</property>
+ <property name="opacity">0.86</property>
+ <style>
+ <class name="osd"/>
+ <class name="bottom"/>
+ </style>
<child>
<object class="GtkToolItem" id="controls_toolbutton">
<property name="visible">True</property>
diff --git a/docs/reference/meson.build b/docs/reference/meson.build
index 6eec8d9d1..0aab998d7 100644
--- a/docs/reference/meson.build
+++ b/docs/reference/meson.build
@@ -2,15 +2,11 @@ doc_module = meson.project_name()
private_headers = [
'bacon-time-label.h',
- 'bacon-video-controls-actor.h',
- 'bacon-video-spinner-actor.h',
'bacon-video-widget-gst-missing-plugins.h',
'bacon-video-widget-properties.h',
- 'clock.h',
'gd-tagged-entry.h',
'icon-helpers.h',
'screenshot-filename-builder.h',
- 'totem-aspect-frame.h',
'totem-gallery-progress.h',
'totem-gallery.h',
'totem-grilo.h',
diff --git a/docs/reference/totem-sections.txt b/docs/reference/totem-sections.txt
index 814907b6d..2a10eb101 100644
--- a/docs/reference/totem-sections.txt
+++ b/docs/reference/totem-sections.txt
@@ -181,14 +181,8 @@ bacon_video_widget_is_seekable
bacon_video_widget_get_rate
bacon_video_widget_set_rate
bacon_video_widget_step
-bacon_video_widget_get_controls_object
-bacon_video_widget_get_header_controls_object
-bacon_video_widget_set_fullscreen
bacon_video_widget_set_next_language
bacon_video_widget_set_next_subtitle
-bacon_video_widget_show_popup
-bacon_video_widget_mark_popup_busy
-bacon_video_widget_unmark_popup_busy
<SUBSECTION Standard>
BVW_TYPE_ASPECT_RATIO
BVW_TYPE_AUDIO_OUTPUT_TYPE
diff --git a/meson.build b/meson.build
index f6e7a3cfe..b13b1cfa2 100644
--- a/meson.build
+++ b/meson.build
@@ -152,7 +152,6 @@ gst_pbutils_dep = dependency('gstreamer-pbutils-1.0')
peas_dep = dependency('libpeas-1.0', version: peas_req_version)
peas_gtk_dep = dependency('libpeas-gtk-1.0', version: peas_req_version)
totem_plparser_dep = dependency('totem-plparser', version: totem_plparser_req_version)
-clutter_gtk_dep = dependency('clutter-gtk-1.0', version: '>= 1.8.1')
m_dep = cc.find_library('m', required: true)
libgd = subproject(
diff --git a/src/backend/bacon-video-widget.c b/src/backend/bacon-video-widget.c
index 030e21224..0564e8598 100644
--- a/src/backend/bacon-video-widget.c
+++ b/src/backend/bacon-video-widget.c
@@ -63,9 +63,6 @@
/* for the cover metadata info */
#include <gst/tag/tag.h>
-#include <clutter-gst/clutter-gst.h>
-#include "totem-aspect-frame.h"
-
/* system */
#include <unistd.h>
#include <time.h>
@@ -83,8 +80,6 @@
#include "totem-gst-pixbuf-helpers.h"
#include "bacon-video-widget.h"
#include "bacon-video-widget-gst-missing-plugins.h"
-#include "bacon-video-controls-actor.h"
-#include "bacon-video-spinner-actor.h"
#include "bacon-video-widget-enums.h"
#define DEFAULT_USER_AGENT "Videos/"VERSION
@@ -92,7 +87,6 @@
#define DEFAULT_CONTROLS_WIDTH 600 /* In pixels */
#define LOGO_SIZE 256 /* Maximum size of the logo */
#define REWIND_OR_PREVIOUS 4000
-#define POPUP_HIDING_TIMEOUT 2
#define MAX_NETWORK_SPEED 10752
#define BUFFERING_LEFT_RATIO 1.1
@@ -127,6 +121,7 @@ enum
SIGNAL_SEEK_REQUESTED,
SIGNAL_TRACK_SKIP_REQUESTED,
SIGNAL_VOLUME_CHANGE_REQUESTED,
+ SIGNAL_PLAY_STARTING,
LAST_SIGNAL
};
@@ -150,7 +145,7 @@ enum
PROP_HUE,
PROP_AUDIO_OUTPUT_TYPE,
PROP_AV_OFFSET,
- PROP_REVEAL_CONTROLS
+ PROP_SHOW_CURSOR,
};
static const gchar *video_props_str[4] = {
@@ -162,7 +157,7 @@ static const gchar *video_props_str[4] = {
struct _BaconVideoWidget
{
- GtkClutterEmbed parent;
+ GtkOverlay parent;
char *user_agent;
@@ -178,8 +173,6 @@ struct _BaconVideoWidget
guint update_id;
guint fill_id;
- GdkPixbuf *logo_pixbuf;
-
gboolean media_has_video;
gboolean media_has_audio;
gint seekable; /* -1 = don't know, FALSE = no */
@@ -197,23 +190,10 @@ struct _BaconVideoWidget
gboolean got_redirect;
- ClutterActor *stage;
- ClutterActor *texture;
- ClutterActor *frame;
- ClutterActor *header_controls;
- ClutterActor *controls;
- ClutterActor *spinner;
-
- ClutterActor *logo_frame;
- ClutterContent *logo;
+ GtkWidget *stack;
GdkCursor *cursor;
- /* Controls */
- gboolean reveal_controls;
- guint transition_timeout_id;
- GHashTable *busy_popup_ht; /* key=reason string, value=gboolean */
-
/* Visual effects */
GstElement *audio_capsfilter;
GstElement *audio_pitchcontrol;
@@ -230,10 +210,6 @@ struct _BaconVideoWidget
gint video_width; /* Movie width */
gint video_height; /* Movie height */
- gint movie_par_n; /* Movie pixel aspect ratio numerator */
- gint movie_par_d; /* Movie pixel aspect ratio denominator */
- gint video_width_pixels; /* Scaled movie width */
- gint video_height_pixels; /* Scaled movie height */
gint video_fps_n;
gint video_fps_d;
@@ -279,7 +255,7 @@ struct _BaconVideoWidget
float rate;
};
-G_DEFINE_TYPE_WITH_CODE (BaconVideoWidget, bacon_video_widget, GTK_CLUTTER_TYPE_EMBED,
+G_DEFINE_TYPE_WITH_CODE (BaconVideoWidget, bacon_video_widget, GTK_TYPE_OVERLAY,
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
bacon_video_widget_initable_iface_init))
@@ -302,9 +278,6 @@ static gboolean bacon_video_widget_seek_time_no_lock (BaconVideoWidget *bvw,
gint64 _time,
GstSeekFlags flag,
GError **error);
-static void set_controls_visibility (BaconVideoWidget *bvw,
- gboolean visible,
- gboolean animate);
typedef struct {
GstTagList *tags;
@@ -399,245 +372,12 @@ bvw_check_if_video_decoder_is_missing (BaconVideoWidget * bvw)
}
static void
-set_display_pixel_aspect_ratio (GdkMonitor *monitor,
- GValue *value)
-{
- static const gint par[][2] = {
- {1, 1}, /* regular screen */
- {16, 15}, /* PAL TV */
- {11, 10}, /* 525 line Rec.601 video */
- {54, 59}, /* 625 line Rec.601 video */
- {64, 45}, /* 1280x1024 on 16:9 display */
- {5, 3}, /* 1280x1024 on 4:3 display */
- {4, 3} /* 800x600 on 16:9 display */
- };
- guint i;
- gint par_index;
- gdouble ratio;
- gdouble delta;
- GdkRectangle rect;
-
-#define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1])))
-
- /* first calculate the "real" ratio based on the X values;
- * which is the "physical" w/h divided by the w/h in pixels of the display */
- gdk_monitor_get_geometry (monitor, &rect);
-
- ratio = (gdouble) (gdk_monitor_get_width_mm (monitor) * rect.height) /
- (gdk_monitor_get_height_mm (monitor) * rect.width);
-
- GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
- /* now find the one from par[][2] with the lowest delta to the real one */
- delta = DELTA (0);
- par_index = 0;
-
- for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) {
- gdouble this_delta = DELTA (i);
-
- if (this_delta < delta) {
- par_index = i;
- delta = this_delta;
- }
- }
-
- GST_DEBUG ("Decided on index %d (%d/%d)", par_index,
- par[par_index][0], par[par_index][1]);
- gst_value_set_fraction (value, par[par_index][0], par[par_index][1]);
-}
-
-static void
-get_media_size (BaconVideoWidget *bvw, gint *width, gint *height)
-{
- if (bvw->media_has_video) {
- GValue disp_par = {0, };
- guint movie_par_n, movie_par_d, disp_par_n, disp_par_d, num, den;
-
- /* Create and init the fraction value */
- g_value_init (&disp_par, GST_TYPE_FRACTION);
-
- /* Square pixel is our default */
- gst_value_set_fraction (&disp_par, 1, 1);
-
- /* Now try getting display's pixel aspect ratio */
- if (gtk_widget_get_realized (GTK_WIDGET (bvw))) {
- GdkDisplay *display;
- GdkWindow *window;
- GdkMonitor *monitor;
-
- display = gtk_widget_get_display (GTK_WIDGET (bvw));
- window = gtk_widget_get_window (GTK_WIDGET (bvw));
- if (window)
- monitor = gdk_display_get_monitor_at_window (display, window);
- else
- monitor = gdk_display_get_primary_monitor (display);
- set_display_pixel_aspect_ratio (monitor, &disp_par);
- }
-
- disp_par_n = gst_value_get_fraction_numerator (&disp_par);
- disp_par_d = gst_value_get_fraction_denominator (&disp_par);
-
- GST_DEBUG ("display PAR is %d/%d", disp_par_n, disp_par_d);
-
- /* If movie pixel aspect ratio is enforced, use that */
- if (bvw->ratio_type != BVW_RATIO_AUTO) {
- switch (bvw->ratio_type) {
- case BVW_RATIO_SQUARE:
- movie_par_n = 1;
- movie_par_d = 1;
- break;
- case BVW_RATIO_FOURBYTHREE:
- movie_par_n = 4 * bvw->video_height;
- movie_par_d = 3 * bvw->video_width;
- break;
- case BVW_RATIO_ANAMORPHIC:
- movie_par_n = 16 * bvw->video_height;
- movie_par_d = 9 * bvw->video_width;
- break;
- case BVW_RATIO_DVB:
- movie_par_n = 20 * bvw->video_height;
- movie_par_d = 9 * bvw->video_width;
- break;
- /* handle these to avoid compiler warnings */
- case BVW_RATIO_AUTO:
- default:
- movie_par_n = 0;
- movie_par_d = 0;
- g_assert_not_reached ();
- }
- } else {
- /* Use the movie pixel aspect ratio if any */
- movie_par_n = bvw->movie_par_n;
- movie_par_d = bvw->movie_par_d;
- }
-
- GST_DEBUG ("movie PAR is %d/%d", movie_par_n, movie_par_d);
-
- if (bvw->video_width == 0 || bvw->video_height == 0) {
- GST_DEBUG ("width and/or height 0, assuming 1/1 ratio");
- num = 1;
- den = 1;
- } else if (!gst_video_calculate_display_ratio (&num, &den,
- bvw->video_width, bvw->video_height,
- movie_par_n, movie_par_d, disp_par_n, disp_par_d)) {
- GST_WARNING ("overflow calculating display aspect ratio!");
- num = 1; /* FIXME: what values to use here? */
- den = 1;
- }
-
- GST_DEBUG ("calculated scaling ratio %d/%d for video %dx%d", num, den,
- bvw->video_width, bvw->video_height);
-
- /* now find a width x height that respects this display ratio.
- * prefer those that have one of w/h the same as the incoming video
- * using wd / hd = num / den */
-
- /* start with same height, because of interlaced video */
- /* check hd / den is an integer scale factor, and scale wd with the PAR */
- if (bvw->video_height % den == 0) {
- GST_DEBUG ("keeping video height");
- bvw->video_width_pixels =
- (guint) gst_util_uint64_scale (bvw->video_height, num, den);
- bvw->video_height_pixels = bvw->video_height;
- } else if (bvw->video_width % num == 0) {
- GST_DEBUG ("keeping video width");
- bvw->video_width_pixels = bvw->video_width;
- bvw->video_height_pixels =
- (guint) gst_util_uint64_scale (bvw->video_width, den, num);
- } else {
- GST_DEBUG ("approximating while keeping video height");
- bvw->video_width_pixels =
- (guint) gst_util_uint64_scale (bvw->video_height, num, den);
- bvw->video_height_pixels = bvw->video_height;
- }
- GST_DEBUG ("scaling to %dx%d", bvw->video_width_pixels,
- bvw->video_height_pixels);
-
- *width = bvw->video_width_pixels;
- *height = bvw->video_height_pixels;
-
- /* Free the PAR fraction */
- g_value_unset (&disp_par);
- }
- else {
- if (bvw->logo_pixbuf) {
- *width = gdk_pixbuf_get_width (bvw->logo_pixbuf);
- *height = gdk_pixbuf_get_height (bvw->logo_pixbuf);
- if (*width == *height) {
- /* The icons will be square, so lie so we get a 16:9
- * ratio */
- *width = (int) ((float) *height / 9. * 16.);
- }
- } else {
- *width = 0;
- *height = 0;
- }
- }
-}
-
-static gboolean
-leave_notify_cb (GtkWidget *widget,
- GdkEventCrossing *event,
- gpointer user_data)
-{
- gboolean res = GDK_EVENT_PROPAGATE;
- BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (user_data);
- GdkDevice *device;
-
- if (event->detail != GDK_NOTIFY_NONLINEAR &&
- event->detail != GDK_NOTIFY_NONLINEAR_VIRTUAL)
- return res;
-
- device = gdk_event_get_source_device ((GdkEvent *) event);
- if (gdk_device_get_source (device) == GDK_SOURCE_TOUCHSCREEN)
- return res;
-
- if (bvw->reveal_controls) {
- gboolean not_busy;
-
- not_busy = g_hash_table_size (bvw->busy_popup_ht) == 0;
- if (not_busy) {
- GST_DEBUG ("will hide because we're not busy and cursor left");
- set_controls_visibility (bvw, FALSE, TRUE);
- }
- }
-
- return res;
-}
-
-static void
-bvw_set_logo (BaconVideoWidget *bvw, const gchar *name)
-{
- GtkIconTheme *theme;
- GError *error = NULL;
-
- theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (bvw)));
- bvw->logo_pixbuf = gtk_icon_theme_load_icon (theme, name, LOGO_SIZE, 0, &error);
-
- if (error) {
- g_warning ("An error occurred trying to open logo %s: %s", name, error->message);
- g_error_free (error);
- return;
- }
-}
-
-static void
bacon_video_widget_realize (GtkWidget * widget)
{
BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
- GtkWidget *toplevel;
GTK_WIDGET_CLASS (parent_class)->realize (widget);
- gtk_widget_set_realized (widget, TRUE);
-
- bvw_set_logo (bvw, APPLICATION_ID);
-
- /* setup the toplevel, ready to be resized */
- toplevel = gtk_widget_get_toplevel (widget);
- gtk_window_set_geometry_hints (GTK_WINDOW (toplevel), widget, NULL, 0);
- g_signal_connect (G_OBJECT (toplevel), "leave-notify-event",
- G_CALLBACK (leave_notify_cb), bvw);
-
bvw->missing_plugins_cancellable = g_cancellable_new ();
g_object_set_data_full (G_OBJECT (bvw), "missing-plugins-cancellable",
bvw->missing_plugins_cancellable, g_object_unref);
@@ -648,16 +388,9 @@ static void
bacon_video_widget_unrealize (GtkWidget *widget)
{
BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
- GtkWidget *toplevel;
GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
- gtk_widget_set_realized (widget, FALSE);
-
- toplevel = gtk_widget_get_toplevel (widget);
- g_signal_handlers_disconnect_by_func (G_OBJECT (toplevel),
- leave_notify_cb, bvw);
-
g_cancellable_cancel (bvw->missing_plugins_cancellable);
bvw->missing_plugins_cancellable = NULL;
g_object_set_data (G_OBJECT (bvw), "missing-plugins-cancellable", NULL);
@@ -668,119 +401,10 @@ set_current_actor (BaconVideoWidget *bvw)
{
gboolean draw_logo;
- if (bvw->stage == NULL)
- return;
-
- /* If there's only audio draw the logo as well. */
+ /* If there's only audio draw the logo */
draw_logo = bvw->media_has_audio && !bvw->media_has_video;
-
- if (draw_logo) {
- if (bvw->logo_pixbuf != NULL) {
- gboolean ret;
- GError *err = NULL;
-
- ret = clutter_image_set_data (CLUTTER_IMAGE (bvw->logo),
- gdk_pixbuf_get_pixels (bvw->logo_pixbuf),
- gdk_pixbuf_get_has_alpha (bvw->logo_pixbuf) ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888,
- gdk_pixbuf_get_width (bvw->logo_pixbuf),
- gdk_pixbuf_get_height (bvw->logo_pixbuf),
- gdk_pixbuf_get_rowstride (bvw->logo_pixbuf),
- &err);
- if (ret == FALSE) {
- g_warning ("clutter_image_set_data() failed %s", err->message);
- g_error_free (err);
- } else {
- clutter_actor_show (CLUTTER_ACTOR (bvw->logo_frame));
- clutter_actor_hide (CLUTTER_ACTOR (bvw->frame));
- return;
- }
- }
- }
-
- clutter_actor_show (CLUTTER_ACTOR (bvw->frame));
- clutter_actor_hide (CLUTTER_ACTOR (bvw->logo_frame));
-}
-
-static void
-unschedule_hiding_popup (BaconVideoWidget *bvw)
-{
- if (bvw->transition_timeout_id > 0)
- g_source_remove (bvw->transition_timeout_id);
- bvw->transition_timeout_id = 0;
-}
-
-static gboolean
-hide_popup_timeout_cb (BaconVideoWidget *bvw)
-{
- set_controls_visibility (bvw, FALSE, TRUE);
- unschedule_hiding_popup (bvw);
- return G_SOURCE_REMOVE;
-}
-
-static void
-schedule_hiding_popup (BaconVideoWidget *bvw)
-{
- unschedule_hiding_popup (bvw);
- bvw->transition_timeout_id = g_timeout_add_seconds (POPUP_HIDING_TIMEOUT, (GSourceFunc) hide_popup_timeout_cb, bvw);
- g_source_set_name_by_id (bvw->transition_timeout_id, "[totem] hide_popup_timeout_cb");
-}
-
-static void
-set_show_cursor (BaconVideoWidget *bvw,
- gboolean show_cursor)
-{
- GdkWindow *window;
-
- bvw->cursor_shown = show_cursor;
- window = gtk_widget_get_window (GTK_WIDGET (bvw));
-
- if (!window)
- return;
-
- if (show_cursor == FALSE) {
- GdkCursor *cursor;
- GdkDisplay *display;
-
- display = gdk_window_get_display (window);
- cursor = gdk_cursor_new_for_display (display, GDK_BLANK_CURSOR);
- gdk_window_set_cursor (window, cursor);
- g_object_unref (cursor);
- } else {
- gdk_window_set_cursor (window, bvw->cursor);
- }
-}
-
-static void
-set_controls_visibility (BaconVideoWidget *bvw,
- gboolean visible,
- gboolean animate)
-{
- guint8 opacity = visible ? OVERLAY_OPACITY : 0;
- gint header_controls_height;
- gfloat header_controls_y;
- guint duration;
-
- gtk_widget_get_preferred_height (gtk_clutter_actor_get_widget (GTK_CLUTTER_ACTOR (bvw->header_controls)),
- NULL,
- &header_controls_height);
- header_controls_y = visible ? 0 : -header_controls_height;
-
- duration = animate ? 250 : 0;
-
- /* FIXME:
- * Using a show/hide seems to not trigger the
- * controls to redraw, so let's change the opacity instead */
- clutter_actor_set_easing_duration (bvw->controls, duration);
- clutter_actor_set_easing_duration (bvw->header_controls, duration);
- clutter_actor_set_opacity (bvw->controls, opacity);
- clutter_actor_set_y (bvw->header_controls, header_controls_y);
-
- set_show_cursor (bvw, visible);
- if (visible && animate)
- schedule_hiding_popup (bvw);
-
- bvw->reveal_controls = visible;
- g_object_notify (G_OBJECT (bvw), "reveal-controls");
+ gtk_stack_set_visible_child_name (GTK_STACK (bvw->stack),
+ draw_logo ? "logo" : "video");
}
static void
@@ -802,22 +426,6 @@ translate_coords (GtkWidget *widget,
}
}
-static gboolean
-ignore_event (BaconVideoWidget *bvw,
- int x,
- int y)
-{
- ClutterActor *actor;
-
- actor = clutter_stage_get_actor_at_pos (CLUTTER_STAGE (bvw->stage), CLUTTER_PICK_REACTIVE, x, y);
-
- /* Eat the GTK+ event if we're not clicking on the video itself */
- if (actor == bvw->controls)
- return TRUE;
-
- return FALSE;
-}
-
/* need to use gstnavigation interface for these vmethods, to allow for the sink
to map screen coordinates to video coordinates in the presence of e.g.
hardware scaling */
@@ -827,8 +435,6 @@ bacon_video_widget_motion_notify (GtkWidget *widget, GdkEventMotion *event)
{
gboolean res = GDK_EVENT_PROPAGATE;
BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
- GdkDevice *device;
- int x, y;
g_return_val_if_fail (bvw->play != NULL, FALSE);
@@ -838,21 +444,6 @@ bacon_video_widget_motion_notify (GtkWidget *widget, GdkEventMotion *event)
if (GTK_WIDGET_CLASS (parent_class)->motion_notify_event)
res |= GTK_WIDGET_CLASS (parent_class)->motion_notify_event (widget, event);
- device = gdk_event_get_source_device ((GdkEvent *) event);
- if (gdk_device_get_source (device) == GDK_SOURCE_TOUCHSCREEN)
- return res;
-
- if (!bvw->reveal_controls)
- set_controls_visibility (bvw, TRUE, TRUE);
-
- translate_coords (widget, event->window, event->x, event->y, &x, &y);
- if (ignore_event (bvw, x, y)) {
- /* Is the mouse on the popups? */
- unschedule_hiding_popup (bvw);
- } else {
- schedule_hiding_popup (bvw);
- }
-
return res;
}
@@ -861,7 +452,6 @@ bacon_video_widget_button_press_or_release (GtkWidget *widget, GdkEventButton *e
{
gboolean res = FALSE;
BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
- int x, y;
GdkDevice *device;
device = gdk_event_get_source_device ((GdkEvent *) event);
@@ -870,10 +460,6 @@ bacon_video_widget_button_press_or_release (GtkWidget *widget, GdkEventButton *e
g_return_val_if_fail (bvw->play != NULL, FALSE);
- translate_coords (widget, event->window, event->x, event->y, &x, &y);
- if (ignore_event (bvw, x, y))
- return GDK_EVENT_STOP;
-
if (event->type != GDK_BUTTON_PRESS &&
event->type != GDK_BUTTON_RELEASE)
goto bail;
@@ -881,8 +467,10 @@ bacon_video_widget_button_press_or_release (GtkWidget *widget, GdkEventButton *e
if (bvw->navigation &&
event->button == 1 &&
bvw->is_menu != FALSE) {
+ int x, y;
const char *event_str;
event_str = (event->type == GDK_BUTTON_PRESS) ? "mouse-button-press" : "mouse-button-release";
+ translate_coords (widget, event->window, event->x, event->y, &x, &y);
gst_navigation_send_mouse_event (bvw->navigation,
event_str, event->button, x, y);
@@ -900,49 +488,6 @@ bail:
return res;
}
-static gboolean
-bacon_video_widget_handle_scroll (GtkWidget *widget,
- GdkEventScroll *event,
- BaconVideoWidget *bvw)
-{
- int x, y;
- gboolean forward;
- gdouble delta_y;
-
- g_return_val_if_fail (bvw->play != NULL, FALSE);
-
- if (event->direction != GDK_SCROLL_SMOOTH)
- return GDK_EVENT_PROPAGATE;
-
- if (widget == (gpointer) bvw) {
- translate_coords (widget, event->window, event->x, event->y, &x, &y);
- if (ignore_event (bvw, x, y))
- return GDK_EVENT_STOP;
- }
-
- gdk_event_get_scroll_deltas ((GdkEvent *) event, NULL, &delta_y);
- if (delta_y == 0.0)
- return GDK_EVENT_PROPAGATE;
- forward = delta_y >= 0.0 ? FALSE : TRUE;
-
- if (widget == (gpointer) bvw ||
- widget == g_object_get_data (G_OBJECT (bvw->controls), "seek_scale")) {
- if (bvw->seekable > 0)
- g_signal_emit (G_OBJECT (bvw), bvw_signals[SIGNAL_SEEK_REQUESTED], 0, forward);
- } else if (widget == g_object_get_data (G_OBJECT (bvw->controls), "volume_button")) {
- if (bacon_video_widget_can_set_volume (bvw))
- g_signal_emit (G_OBJECT (bvw), bvw_signals[SIGNAL_VOLUME_CHANGE_REQUESTED], 0, forward);
- }
-
- return GDK_EVENT_STOP;
-}
-
-static gboolean
-bacon_video_widget_scroll (GtkWidget *widget, GdkEventScroll *event)
-{
- return bacon_video_widget_handle_scroll (widget, event, BACON_VIDEO_WIDGET (widget));
-}
-
static void
bacon_video_widget_get_preferred_width (GtkWidget *widget,
gint *minimum,
@@ -980,8 +525,6 @@ bacon_video_widget_class_init (BaconVideoWidgetClass * klass)
GObjectClass *object_class;
GtkWidgetClass *widget_class;
- clutter_gst_init (NULL, NULL);
-
object_class = (GObjectClass *) klass;
widget_class = (GtkWidgetClass *) klass;
@@ -996,7 +539,6 @@ bacon_video_widget_class_init (BaconVideoWidgetClass * klass)
widget_class->motion_notify_event = bacon_video_widget_motion_notify;
widget_class->button_press_event = bacon_video_widget_button_press_or_release;
widget_class->button_release_event = bacon_video_widget_button_press_or_release;
- widget_class->scroll_event = bacon_video_widget_scroll;
/* GObject */
object_class->set_property = bacon_video_widget_set_property;
@@ -1174,14 +716,14 @@ bacon_video_widget_class_init (BaconVideoWidgetClass * klass)
G_PARAM_STATIC_STRINGS));
/**
- * BaconVideoWidget:reveal-controls:
+ * BaconVideoWidget:show-cursor:
*
- * Whether to show or hide the controls.
+ * Whether the mouse cursor is shown.
**/
- g_object_class_install_property (object_class, PROP_REVEAL_CONTROLS,
- g_param_spec_boolean ("reveal-controls", "Reveal controls",
- "Whether to show or hide the controls.", FALSE,
- G_PARAM_READABLE |
+ g_object_class_install_property (object_class, PROP_SHOW_CURSOR,
+ g_param_spec_boolean ("show-cursor", "Show cursor",
+ "Whether the mouse cursor is shown.", FALSE,
+ G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
/* Signals */
@@ -1384,6 +926,25 @@ bacon_video_widget_class_init (BaconVideoWidgetClass * klass)
0,
NULL, NULL,
g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+
+ /**
+ * BaconVideoWidget::play-starting:
+ * @bvw: the #BaconVideoWidget which received the signal
+ *
+ * Emitted when a movie will start playing, meaning it's not buffering, or paused
+ * waiting for plugins to be installed, drives to be mounted or authentication
+ * to succeed.
+ *
+ * This usually means that OSD popups can be hidden.
+ *
+ **/
+ bvw_signals[SIGNAL_PLAY_STARTING] =
+ g_signal_new ("play-starting",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
}
static void
@@ -1395,14 +956,11 @@ bacon_video_widget_init (BaconVideoWidget * bvw)
g_type_class_ref (BVW_TYPE_DVD_EVENT);
g_type_class_ref (BVW_TYPE_ROTATION);
- g_object_set (G_OBJECT (bvw), "use-layout-size", TRUE, NULL);
-
bvw->update_id = 0;
bvw->tagcache = NULL;
bvw->audiotags = NULL;
bvw->videotags = NULL;
bvw->volume = -1.0;
- bvw->movie_par_n = bvw->movie_par_d = 1;
bvw->rate = FORWARD_RATE;
bvw->tag_update_queue = g_async_queue_new_full ((GDestroyNotify) update_tags_delayed_data_destroy);
@@ -1421,8 +979,6 @@ bacon_video_widget_init (BaconVideoWidget * bvw)
bvw->auth_last_result = G_MOUNT_OPERATION_HANDLED;
bvw->auth_dialog = NULL;
- bvw->busy_popup_ht = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-
bacon_video_widget_gst_missing_plugins_block ();
}
@@ -1455,15 +1011,7 @@ bvw_handle_application_message (BaconVideoWidget *bvw, GstMessage *msg)
bvw_update_stream_info (bvw);
}
else if (strcmp (msg_name, "video-size") == 0) {
- int w, h;
-
g_signal_emit (bvw, bvw_signals[SIGNAL_GOT_METADATA], 0, NULL);
-
- /* This is necessary for the pixel-aspect-ratio of the
- * display to be taken into account. */
- get_media_size (bvw, &w, &h);
- clutter_actor_set_size (bvw->texture, w, h);
-
set_current_actor (bvw);
} else {
g_debug ("Unhandled application message %s", msg_name);
@@ -1600,7 +1148,7 @@ bvw_handle_element_message (BaconVideoWidget *bvw, GstMessage *msg)
val = gst_structure_get_value (structure, "file");
if (val == NULL)
goto done;
-
+
file = G_FILE (g_value_get_object (val));
if (file == NULL)
goto done;
@@ -1977,37 +1525,6 @@ bvw_check_missing_plugins_on_preroll (BaconVideoWidget * bvw)
}
static void
-update_orientation_from_video (BaconVideoWidget *bvw)
-{
- BvwRotation rotation = BVW_ROTATION_R_ZERO;
- char *orientation_str = NULL;
- gboolean ret;
- gdouble angle;
-
- /* Don't change the rotation if explicitely set */
- if (bvw->rotation != BVW_ROTATION_R_ZERO)
- return;
-
- ret = gst_tag_list_get_string_index (bvw->tagcache,
- GST_TAG_IMAGE_ORIENTATION, 0, &orientation_str);
- if (!ret || !orientation_str || g_str_equal (orientation_str, "rotate-0"))
- rotation = BVW_ROTATION_R_ZERO;
- else if (g_str_equal (orientation_str, "rotate-90"))
- rotation = BVW_ROTATION_R_90R;
- else if (g_str_equal (orientation_str, "rotate-180"))
- rotation = BVW_ROTATION_R_180;
- else if (g_str_equal (orientation_str, "rotate-270"))
- rotation = BVW_ROTATION_R_90L;
- else
- g_warning ("Unhandled orientation value: '%s'", orientation_str);
-
- g_free (orientation_str);
-
- angle = rotation * 90.0;
- totem_aspect_frame_set_rotation (TOTEM_ASPECT_FRAME (bvw->frame), angle);
-}
-
-static void
bvw_update_tags (BaconVideoWidget * bvw, GstTagList *tag_list, const gchar *type)
{
GstTagList **cache = NULL;
@@ -2048,8 +1565,6 @@ bvw_update_tags (BaconVideoWidget * bvw, GstTagList *tag_list, const gchar *type
g_signal_emit (bvw, bvw_signals[SIGNAL_GOT_METADATA], 0);
- update_orientation_from_video (bvw);
-
set_current_actor (bvw);
}
@@ -2215,15 +1730,6 @@ bvw_handle_buffering_message (GstMessage * message, BaconVideoWidget *bvw)
g_signal_emit (bvw, bvw_signals[SIGNAL_BUFFERING], 0, (gdouble) percent / 100.0);
if (percent >= 100) {
- clutter_actor_hide (bvw->spinner);
- /* Reset */
- g_object_set (G_OBJECT (bvw->spinner), "percent", 0.0, NULL);
- } else {
- clutter_actor_show (bvw->spinner);
- g_object_set (G_OBJECT (bvw->spinner), "percent", (float) percent, NULL);
- }
-
- if (percent >= 100) {
/* a 100% message means buffering is done */
bvw->buffering = FALSE;
/* if the desired state is playing, go back */
@@ -2833,29 +2339,12 @@ caps_set (GObject * obj,
/* Get video decoder caps */
s = gst_caps_get_structure (caps, 0);
if (s) {
- const GValue *movie_par;
-
/* We need at least width/height and framerate */
- if (!(gst_structure_get_fraction (s, "framerate", &bvw->video_fps_n,
+ if (!(gst_structure_get_fraction (s, "framerate", &bvw->video_fps_n,
&bvw->video_fps_d) &&
gst_structure_get_int (s, "width", &bvw->video_width) &&
gst_structure_get_int (s, "height", &bvw->video_height)))
return;
-
- /* Get the movie PAR if available */
- movie_par = gst_structure_get_value (s, "pixel-aspect-ratio");
- if (movie_par) {
- bvw->movie_par_n = gst_value_get_fraction_numerator (movie_par);
- bvw->movie_par_d = gst_value_get_fraction_denominator (movie_par);
- }
- else {
- /* Square pixels */
- bvw->movie_par_n = 1;
- bvw->movie_par_d = 1;
- }
-
- /* Now set for real */
- bacon_video_widget_set_aspect_ratio (bvw, bvw->ratio_type);
}
gst_caps_unref (caps);
@@ -2921,8 +2410,6 @@ bacon_video_widget_finalize (GObject * object)
g_type_class_unref (g_type_class_peek (BVW_TYPE_DVD_EVENT));
g_type_class_unref (g_type_class_peek (BVW_TYPE_ROTATION));
- unschedule_hiding_popup (bvw);
-
if (bvw->bus) {
/* make bus drop all messages to make sure none of our callbacks is ever
* called again (main loop might be run again to display error dialog) */
@@ -2938,7 +2425,6 @@ bacon_video_widget_finalize (GObject * object)
g_clear_pointer (&bvw->referrer, g_free);
g_clear_pointer (&bvw->mrl, g_free);
g_clear_pointer (&bvw->subtitle_uri, g_free);
- g_clear_pointer (&bvw->busy_popup_ht, g_hash_table_destroy);
g_clear_object (&bvw->clock);
@@ -3020,6 +2506,9 @@ bacon_video_widget_set_property (GObject * object, guint property_id,
case PROP_AV_OFFSET:
g_object_set_property (G_OBJECT (bvw->play), "av-offset", value);
break;
+ case PROP_SHOW_CURSOR:
+ bacon_video_widget_set_show_cursor (bvw, g_value_get_boolean (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -3080,8 +2569,8 @@ bacon_video_widget_get_property (GObject * object, guint property_id,
case PROP_AV_OFFSET:
g_object_get_property (G_OBJECT (bvw->play), "av-offset", value);
break;
- case PROP_REVEAL_CONTROLS:
- g_value_set_boolean (value, bvw->reveal_controls);
+ case PROP_SHOW_CURSOR:
+ g_value_set_boolean (value, bvw->cursor_shown);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -3678,113 +3167,6 @@ bacon_video_widget_set_audio_output_type (BaconVideoWidget *bvw,
set_audio_filter (bvw);
}
-/**
- * bacon_video_widget_show_popup:
- * @bvw: a #BaconVideoWidget
- *
- * Show the video controls popup, and schedule for it to be hidden again after
- * a timeout.
- *
- * Since: 3.12
- */
-void
-bacon_video_widget_show_popup (BaconVideoWidget *bvw)
-{
- g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
-
- set_controls_visibility (bvw, TRUE, FALSE);
- schedule_hiding_popup (bvw);
-}
-
-/**
- * bacon_video_widget_mark_popup_busy:
- * @bvw: a #BaconVideoWidget
- * @reason: human-readable reason for the controls popup being marked as busy
- *
- * Mark the video controls popup as busy, for the given @reason. Use
- * bacon_video_widget_unmark_popup_busy() to undo.
- *
- * Since: 3.12
- */
-void
-bacon_video_widget_mark_popup_busy (BaconVideoWidget *bvw,
- const char *reason)
-{
- g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
-
- g_hash_table_insert (bvw->busy_popup_ht,
- g_strdup (reason),
- GINT_TO_POINTER (1));
-
- set_controls_visibility (bvw, TRUE, FALSE);
-
- GST_DEBUG ("Adding popup busy for reason %s", reason);
-
- unschedule_hiding_popup (bvw);
-}
-
-/**
- * bacon_video_widget_unmark_popup_busy:
- * @bvw: a #BaconVideoWidget
- * @reason: human-readable reason for the controls popup being unmarked as busy
- *
- * Unmark the video controls popup as busy, for the given @reason. The popup
- * must previously have been marked as busy using
- * bacon_video_widget_mark_popup_busy().
- *
- * Since: 3.12
- */
-void
-bacon_video_widget_unmark_popup_busy (BaconVideoWidget *bvw,
- const char *reason)
-{
- g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
-
- g_hash_table_remove (bvw->busy_popup_ht, reason);
-
- GST_DEBUG ("Removing popup busy for reason %s", reason);
-
- if (g_hash_table_size (bvw->busy_popup_ht) == 0 &&
- clutter_actor_get_opacity (bvw->controls) != 0) {
- GST_DEBUG ("Will hide popup soon");
- schedule_hiding_popup (bvw);
- }
-}
-
-/**
- * bacon_video_widget_get_controls_object:
- * @bvw: a #BaconVideoWidget
- *
- * Get the widget which displays the video controls.
- *
- * Returns: (transfer none): controls widget
- * Since: 3.12
- */
-GObject *
-bacon_video_widget_get_controls_object (BaconVideoWidget *bvw)
-{
- g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), NULL);
-
- return G_OBJECT (bvw->controls);
-}
-
-/**
- * bacon_video_widget_get_header_controls_object:
- * @bvw: a #BaconVideoWidget
- *
- * Get the widget which displays the video header controls.
- *
- * Returns: (transfer none): header controls widget
- * Since: 3.20
- */
-GObject *
-bacon_video_widget_get_header_controls_object (BaconVideoWidget *bvw)
-{
- g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), NULL);
-
- return G_OBJECT (gtk_clutter_actor_get_widget (GTK_CLUTTER_ACTOR (bvw->header_controls)));
-}
-
/* =========================================== */
/* */
/* Play/Pause, Stop */
@@ -4059,8 +3441,6 @@ bacon_video_widget_open (BaconVideoWidget *bvw,
bvw->target_state = GST_STATE_PAUSED;
bvw_clear_missing_plugins_messages (bvw);
- bacon_video_widget_mark_popup_busy (bvw, "opening file");
-
gst_element_set_state (bvw->play, GST_STATE_PAUSED);
g_signal_emit (bvw, bvw_signals[SIGNAL_CHANNELS_CHANGE], 0);
@@ -4125,7 +3505,7 @@ bacon_video_widget_play (BaconVideoWidget * bvw, GError ** error)
return FALSE;
}
- bacon_video_widget_unmark_popup_busy (bvw, "opening file");
+ g_signal_emit (bvw, bvw_signals[SIGNAL_PLAY_STARTING], 0);
GST_DEBUG ("play");
gst_element_set_state (bvw->play, GST_STATE_PLAYING);
@@ -4334,10 +3714,10 @@ bvw_stop_play_pipeline (BaconVideoWidget * bvw)
g_clear_pointer (&bvw->download_filename, g_free);
bvw->buffering_left = -1;
bvw_reconfigure_fill_timeout (bvw, 0);
- bvw->movie_par_n = bvw->movie_par_d = 1;
- clutter_actor_hide (bvw->spinner);
- g_object_set (G_OBJECT (bvw->spinner), "percent", 0.0, NULL);
- totem_aspect_frame_set_internal_rotation (TOTEM_ASPECT_FRAME (bvw->frame), 0.0);
+ g_signal_emit (bvw, bvw_signals[SIGNAL_BUFFERING], 0, 100.0);
+ g_object_set (bvw->video_sink,
+ "rotate-method", GST_VIDEO_ORIENTATION_AUTO,
+ NULL);
GST_DEBUG ("stopped");
}
@@ -4800,6 +4180,43 @@ bacon_video_widget_get_volume (BaconVideoWidget * bvw)
}
/**
+ * bacon_video_widget_set_show_cursor:
+ * @bvw: a #BaconVideoWidget
+ * @show_cursor: %TRUE to show the cursor, %FALSE otherwise
+ *
+ * Sets whether the cursor should be shown when it is over the video
+ * widget. If @show_cursor is %FALSE, the cursor will be invisible
+ * when it is moved over the video widget.
+ **/
+void
+bacon_video_widget_set_show_cursor (BaconVideoWidget * bvw,
+ gboolean show_cursor)
+{
+ GdkWindow *window;
+
+ g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
+
+
+ bvw->cursor_shown = show_cursor;
+ window = gtk_widget_get_window (GTK_WIDGET (bvw));
+
+ if (!window)
+ return;
+
+ if (show_cursor == FALSE) {
+ GdkCursor *cursor;
+ GdkDisplay *display;
+
+ display = gdk_window_get_display (window);
+ cursor = gdk_cursor_new_for_display (display, GDK_BLANK_CURSOR);
+ gdk_window_set_cursor (window, cursor);
+ g_object_unref (cursor);
+ } else {
+ gdk_window_set_cursor (window, bvw->cursor);
+ }
+}
+
+/**
* bacon_video_widget_set_aspect_ratio:
* @bvw: a #BaconVideoWidget
* @ratio: the new aspect ratio
@@ -4810,18 +4227,41 @@ bacon_video_widget_get_volume (BaconVideoWidget * bvw)
**/
void
bacon_video_widget_set_aspect_ratio (BaconVideoWidget *bvw,
- BvwAspectRatio ratio)
+ BvwAspectRatio ratio)
{
- GstMessage *msg;
-
g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
bvw->ratio_type = ratio;
- msg = gst_message_new_application (GST_OBJECT (bvw->play),
- gst_structure_new ("video-size", "width", G_TYPE_INT,
- bvw->video_width, "height", G_TYPE_INT,
- bvw->video_height, NULL));
- gst_element_post_message (bvw->play, msg);
+
+ switch (bvw->ratio_type) {
+ case BVW_RATIO_SQUARE:
+ g_object_set (bvw->video_sink,
+ "video-aspect-ratio-override", 1, 1,
+ NULL);
+ break;
+ case BVW_RATIO_FOURBYTHREE:
+ g_object_set (bvw->video_sink,
+ "video-aspect-ratio-override", 4, 3,
+ NULL);
+ break;
+ case BVW_RATIO_ANAMORPHIC:
+ g_object_set (bvw->video_sink,
+ "video-aspect-ratio-override", 16, 9,
+ NULL);
+ break;
+ case BVW_RATIO_DVB:
+ g_object_set (bvw->video_sink,
+ "video-aspect-ratio-override", 20, 9,
+ NULL);
+ break;
+ /* handle these to avoid compiler warnings */
+ case BVW_RATIO_AUTO:
+ default:
+ g_object_set (bvw->video_sink,
+ "video-aspect-ratio-override", 0, 1,
+ NULL);
+ break;
+ }
}
/**
@@ -4854,11 +4294,7 @@ bacon_video_widget_set_zoom (BaconVideoWidget *bvw,
{
g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
- if (bvw->frame == NULL)
- return;
-
- totem_aspect_frame_set_expand (TOTEM_ASPECT_FRAME (bvw->frame),
- (mode == BVW_ZOOM_EXPAND));
+ g_debug ("%s not implemented", G_STRFUNC);
}
/**
@@ -4872,12 +4308,10 @@ bacon_video_widget_set_zoom (BaconVideoWidget *bvw,
BvwZoomMode
bacon_video_widget_get_zoom (BaconVideoWidget *bvw)
{
- gboolean expand;
+ g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), BVW_ZOOM_NONE);
- g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), 1.0);
-
- expand = totem_aspect_frame_get_expand (TOTEM_ASPECT_FRAME (bvw->frame));
- return expand ? BVW_ZOOM_EXPAND : BVW_ZOOM_NONE;
+ g_debug ("%s not implemented", G_STRFUNC);
+ return BVW_ZOOM_NONE;
}
/**
@@ -4891,22 +4325,15 @@ void
bacon_video_widget_set_rotation (BaconVideoWidget *bvw,
BvwRotation rotation)
{
- gfloat angle;
-
g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
- if (bvw->frame == NULL)
- return;
-
GST_DEBUG ("Rotating to %s (%f degrees) from %s",
g_enum_to_string (BVW_TYPE_ROTATION, rotation),
rotation * 90.0,
g_enum_to_string (BVW_TYPE_ROTATION, bvw->rotation));
bvw->rotation = rotation;
-
- angle = rotation * 90.0;
- totem_aspect_frame_set_rotation (TOTEM_ASPECT_FRAME (bvw->frame), angle);
+ g_object_set (bvw->video_sink, "rotate-method", rotation, NULL);
}
/**
@@ -5867,59 +5294,6 @@ bvw_set_playback_direction (BaconVideoWidget *bvw, gboolean forward)
return retval;
}
-static gboolean
-navigation_event (ClutterActor *actor,
- ClutterEvent *event,
- BaconVideoWidget *bvw)
-{
- ClutterGstFrame *frame =
- clutter_gst_video_sink_get_frame (CLUTTER_GST_VIDEO_SINK (bvw->video_sink));
- gfloat actor_width, actor_height;
- gfloat x, y;
-
- if (frame == NULL)
- return CLUTTER_EVENT_PROPAGATE;
-
- /* Get event coordinates into the actor's coordinates. */
- clutter_event_get_coords (event, &x, &y);
- clutter_actor_transform_stage_point (actor, x, y, &x, &y);
-
- clutter_actor_get_size (actor, &actor_width, &actor_height);
-
- /* Convert event's coordinates into the frame's coordinates. */
- x = x * frame->resolution.width / actor_width;
- y = y * frame->resolution.height / actor_height;
-
- if (event->type == CLUTTER_MOTION) {
- gst_navigation_send_mouse_event (GST_NAVIGATION (bvw->video_sink),
- "mouse-move", 0, x, y);
- } else if (event->type == CLUTTER_BUTTON_PRESS ||
- event->type == CLUTTER_BUTTON_RELEASE) {
- ClutterButtonEvent *bevent = (ClutterButtonEvent *) event;
- const char *type = (event->type == CLUTTER_BUTTON_PRESS) ?
- "mouse-button-press" : "mouse-button-release";
- gst_navigation_send_mouse_event (GST_NAVIGATION (bvw->video_sink), type,
- bevent->button, x, y);
- }
-
- return CLUTTER_EVENT_PROPAGATE;
-}
-
-static void
-listen_navigation_events (ClutterActor *actor,
- BaconVideoWidget *bvw)
-{
- const char * const events[] = {
- "button-press-event",
- "button-release-event",
- "motion-event"
- };
- guint i;
-
- for (i = 0; i < G_N_ELEMENTS (events); i++)
- g_signal_connect (actor, events[i], G_CALLBACK (navigation_event), bvw);
-}
-
static GstElement *
element_make_or_warn (const char *plugin,
const char *name)
@@ -5940,10 +5314,9 @@ bacon_video_widget_initable_init (GInitable *initable,
GstElement *audio_sink = NULL;
gchar *version_str;
GstPlayFlags flags;
- ClutterActor *layout;
- GstElement *audio_bin;
+ GtkWidget *tmp;
+ GstElement *glsinkbin, *audio_bin;
GstPad *audio_pad;
- GObject *item;
char *template;
bvw = BACON_VIDEO_WIDGET (initable);
@@ -5961,10 +5334,20 @@ bacon_video_widget_initable_init (GInitable *initable,
gst_pb_utils_init ();
+ gtk_widget_set_events (GTK_WIDGET (bvw),
+ gtk_widget_get_events (GTK_WIDGET (bvw)) |
+ GDK_SCROLL_MASK |
+ GDK_POINTER_MOTION_MASK |
+ GDK_BUTTON_MOTION_MASK |
+ GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_KEY_PRESS_MASK);
+
/* Instantiate all the fallible plugins */
bvw->play = element_make_or_warn ("playbin", "play");
bvw->audio_pitchcontrol = element_make_or_warn ("scaletempo", "scaletempo");
- bvw->video_sink = GST_ELEMENT (clutter_gst_video_sink_new ());
+ bvw->video_sink = element_make_or_warn ("gtkglsink", "video-sink");
+ glsinkbin = element_make_or_warn ("glsinkbin", "glsinkbin");
audio_sink = element_make_or_warn ("autoaudiosink", "audio-sink");
if (!bvw->play ||
@@ -6006,93 +5389,28 @@ bacon_video_widget_initable_init (GInitable *initable,
bvw->cursor_shown = TRUE;
- bvw->stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED (bvw));
- clutter_actor_set_text_direction (bvw->stage,
- CLUTTER_TEXT_DIRECTION_LTR);
- clutter_actor_set_layout_manager (bvw->stage,
- clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_FILL, CLUTTER_BIN_ALIGNMENT_FILL));
- clutter_actor_set_name (bvw->stage, "stage");
- clutter_actor_set_background_color (bvw->stage, CLUTTER_COLOR_Black);
-
- /* Video sink, with aspect frame */
- bvw->texture = g_object_new (CLUTTER_TYPE_ACTOR,
- "content", g_object_new (CLUTTER_GST_TYPE_CONTENT,
- "sink", bvw->video_sink,
- NULL),
- "name", "texture",
- "reactive", TRUE,
- NULL);
- listen_navigation_events (bvw->texture, bvw);
-
- /* The logo */
- bvw->logo_frame = clutter_actor_new ();
- clutter_actor_set_name (bvw->logo_frame, "logo-frame");
- bvw->logo = clutter_image_new ();
- clutter_actor_set_content (bvw->logo_frame, bvw->logo);
- clutter_actor_set_content_gravity (bvw->logo_frame, CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT);
- clutter_actor_add_child (bvw->stage, bvw->logo_frame);
- clutter_actor_hide (CLUTTER_ACTOR (bvw->logo_frame));
-
- /* The video */
- bvw->frame = totem_aspect_frame_new ();
- clutter_actor_set_name (bvw->frame, "frame");
- totem_aspect_frame_set_child (TOTEM_ASPECT_FRAME (bvw->frame), bvw->texture);
-
- clutter_actor_add_child (bvw->stage, bvw->frame);
-
- clutter_actor_set_child_above_sibling (bvw->stage,
- bvw->logo_frame,
- bvw->frame);
-
- /* The spinner */
- bvw->spinner = bacon_video_spinner_actor_new ();
- clutter_actor_set_name (bvw->spinner, "spinner");
- clutter_actor_add_child (bvw->stage, bvw->spinner);
- clutter_actor_set_child_above_sibling (bvw->stage,
- bvw->spinner,
- bvw->frame);
- clutter_actor_hide (bvw->spinner);
-
- /* Fullscreen header controls */
- bvw->header_controls = gtk_clutter_actor_new ();
- clutter_actor_set_opacity (bvw->header_controls, OVERLAY_OPACITY);
- clutter_actor_set_name (bvw->header_controls, "header-controls");
- clutter_actor_add_constraint (bvw->header_controls,
- clutter_bind_constraint_new (bvw->stage,
- CLUTTER_BIND_WIDTH,
- 0));
- layout = g_object_new (CLUTTER_TYPE_ACTOR,
- "layout-manager", clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER, CLUTTER_BIN_ALIGNMENT_START),
- NULL);
- clutter_actor_set_name (layout, "layout");
- clutter_actor_add_child (layout, bvw->header_controls);
- clutter_actor_add_child (bvw->stage, layout);
-
- /* The controls */
- bvw->controls = bacon_video_controls_actor_new ();
- clutter_actor_set_name (bvw->controls, "controls");
- layout = g_object_new (CLUTTER_TYPE_ACTOR,
- "layout-manager", clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER, CLUTTER_BIN_ALIGNMENT_END),
- NULL);
- clutter_actor_set_name (layout, "layout");
- clutter_actor_add_child (layout, bvw->controls);
+ /* Create video output widget and logo */
+ bvw->stack = gtk_stack_new ();
+ gtk_container_add (GTK_CONTAINER (bvw), bvw->stack);
+ gtk_widget_show (bvw->stack);
- clutter_actor_add_child (bvw->stage, layout);
- clutter_actor_set_child_above_sibling (bvw->stage,
- layout,
- bvw->logo_frame);
+ g_object_set (glsinkbin, "sink", bvw->video_sink, NULL);
+ g_object_get (bvw->video_sink, "widget", &tmp, NULL);
+ gtk_stack_add_named (GTK_STACK (bvw->stack), tmp, "video");
+ gtk_widget_show (tmp);
+ g_object_unref (tmp);
- clutter_actor_set_opacity (bvw->controls, 0);
+ tmp = gtk_image_new_from_icon_name (APPLICATION_ID, GTK_ICON_SIZE_DIALOG);
+ gtk_image_set_pixel_size (GTK_IMAGE (tmp), LOGO_SIZE);
+ gtk_stack_add_named (GTK_STACK (bvw->stack), tmp, "logo");
+ gtk_widget_show (tmp);
- item = g_object_get_data (G_OBJECT (bvw->controls), "seek_scale");
- g_signal_connect (item, "scroll-event",
- G_CALLBACK (bacon_video_widget_handle_scroll), bvw);
- item = g_object_get_data (G_OBJECT (bvw->controls), "volume_button");
- g_signal_connect (item, "scroll-event",
- G_CALLBACK (bacon_video_widget_handle_scroll), bvw);
+ g_object_set (bvw->video_sink,
+ "rotate-method", GST_VIDEO_ORIENTATION_AUTO,
+ NULL);
/* And tell playbin */
- g_object_set (bvw->play, "video-sink", bvw->video_sink, NULL);
+ g_object_set (bvw->play, "video-sink", glsinkbin, NULL);
/* Link the audiopitch element */
bvw->audio_capsfilter =
@@ -6228,23 +5546,6 @@ bacon_video_widget_set_rate (BaconVideoWidget *bvw,
return retval;
}
-/**
- * bacon_video_widget_set_fullscreen:
- * @bvw: a #BaconVideoWidget
- * @fullscreen: the new fullscreen state
- *
- * Sets the fullscreen state, enabling a toplevel header bar sliding from
- * the top of the video widget.
- **/
-void
-bacon_video_widget_set_fullscreen (BaconVideoWidget *bvw,
- gboolean fullscreen)
-{
- g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
-
- g_object_set (bvw->header_controls, "visible", fullscreen, NULL);
-}
-
/*
* vim: sw=2 ts=8 cindent noai bs=2
*/
diff --git a/src/backend/bacon-video-widget.h b/src/backend/bacon-video-widget.h
index 734dbdbe9..63ba2e16b 100644
--- a/src/backend/bacon-video-widget.h
+++ b/src/backend/bacon-video-widget.h
@@ -27,14 +27,10 @@
#pragma once
-#include <clutter-gtk/clutter-gtk.h>
-
-#ifndef glib_autoptr_clear_GtkClutterEmbed
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkClutterEmbed, g_object_unref)
-#endif
+#include <gtk/gtk.h>
#define BACON_TYPE_VIDEO_WIDGET (bacon_video_widget_get_type ())
-G_DECLARE_FINAL_TYPE(BaconVideoWidget, bacon_video_widget, BACON, VIDEO_WIDGET, GtkClutterEmbed)
+G_DECLARE_FINAL_TYPE(BaconVideoWidget, bacon_video_widget, BACON, VIDEO_WIDGET, GtkOverlay)
#define BVW_ERROR bacon_video_widget_error_quark ()
/**
@@ -144,8 +140,8 @@ gboolean bacon_video_widget_set_rate (BaconVideoWidget *bvw,
gfloat new_rate);
gfloat bacon_video_widget_get_rate (BaconVideoWidget *bvw);
-void bacon_video_widget_set_fullscreen (BaconVideoWidget *bvw,
- gboolean fullscreen);
+void bacon_video_widget_set_show_cursor (BaconVideoWidget *bvw,
+ gboolean show_cursor);
/* Metadata */
/**
@@ -415,13 +411,3 @@ BvwAudioOutputType bacon_video_widget_get_audio_output_type
(BaconVideoWidget *bvw);
void bacon_video_widget_set_audio_output_type (BaconVideoWidget *bvw,
BvwAudioOutputType type);
-
-/* OSD */
-void bacon_video_widget_show_popup (BaconVideoWidget *bvw);
-void bacon_video_widget_mark_popup_busy (BaconVideoWidget *bvw,
- const char *reason);
-void bacon_video_widget_unmark_popup_busy (BaconVideoWidget *bvw,
- const char *reason);
-
-GObject * bacon_video_widget_get_controls_object (BaconVideoWidget *bvw);
-GObject * bacon_video_widget_get_header_controls_object (BaconVideoWidget *bvw);
diff --git a/src/backend/bvw-test.c b/src/backend/bvw-test.c
index 60c173234..8174fce15 100644
--- a/src/backend/bvw-test.c
+++ b/src/backend/bvw-test.c
@@ -85,9 +85,6 @@ int main
XInitThreads ();
#endif
- if (gtk_clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
- g_assert_not_reached ();
-
context = g_option_context_new ("- Play audio and video inside a web browser");
baconoptiongroup = bacon_video_widget_get_option_group();
g_option_context_add_main_entries (context, option_entries, GETTEXT_PACKAGE);
@@ -123,38 +120,7 @@ int main
g_signal_connect (G_OBJECT (bvw), "got-redirect", G_CALLBACK (on_redirect), NULL);
g_signal_connect (G_OBJECT (bvw), "error", G_CALLBACK (error_cb), NULL);
- box = g_object_get_data (bacon_video_widget_get_controls_object (BACON_VIDEO_WIDGET (bvw)), "controls_box");
-
- /* Previous */
- item = gtk_tool_button_new (NULL, NULL);
- gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (item), "media-skip-backward-symbolic");
- gtk_box_pack_start (box, GTK_WIDGET (item), FALSE, FALSE, 0);
-
- /* Play/Pause */
- item = gtk_tool_button_new (NULL, NULL);
- gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (item), "media-playback-start-symbolic");
- gtk_box_pack_start (box, GTK_WIDGET (item), FALSE, FALSE, 0);
-
- /* Next */
- item = gtk_tool_button_new (NULL, NULL);
- gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (item), "media-skip-forward-symbolic");
- gtk_box_pack_start (box, GTK_WIDGET (item), FALSE, FALSE, 0);
-
- /* Separator */
- item = gtk_separator_tool_item_new ();
- gtk_box_pack_start (box, GTK_WIDGET (item), FALSE, FALSE, 0);
-
- /* Go button */
- item = g_object_get_data (bacon_video_widget_get_controls_object (BACON_VIDEO_WIDGET (bvw)), "go_button");
- image = gtk_image_new_from_icon_name ("view-more-symbolic", GTK_ICON_SIZE_SMALL_TOOLBAR);
- gtk_button_set_image (GTK_BUTTON (item), image);
-
- gtk_widget_show_all (GTK_WIDGET (box));
-
- gtk_container_add (GTK_CONTAINER (win),bvw);
-
- gtk_widget_realize (GTK_WIDGET (win));
- gtk_widget_realize (bvw);
+ gtk_container_add (GTK_CONTAINER (win), bvw);
gtk_widget_show (win);
gtk_widget_show (bvw);
diff --git a/src/backend/meson.build b/src/backend/meson.build
index c6df9b150..effdfe60e 100644
--- a/src/backend/meson.build
+++ b/src/backend/meson.build
@@ -35,12 +35,8 @@ endforeach
sources = files(
'bacon-time-label.c',
- 'bacon-video-controls-actor.c',
- 'bacon-video-spinner-actor.c',
'bacon-video-widget-gst-missing-plugins.c',
'bacon-video-widget.c',
- 'clock.c',
- 'totem-aspect-frame.c'
)
enum_headers = files('bacon-video-widget.h')
@@ -62,10 +58,6 @@ libbacon_video_widget_deps = [
gst_tag_dep,
dependency('gstreamer-audio-1.0'),
gst_video_dep,
- dependency('clutter-1.0', version: '>= 1.17.3'),
- dependency('clutter-gst-3.0', version: '>= 2.99.2'),
- clutter_gtk_dep,
- dependency('cairo', version: '>= 1.14.0'),
dependency('gsettings-desktop-schemas'),
m_dep,
libtotem_gst_helpers_dep,
diff --git a/src/meson.build b/src/meson.build
index b74fc1a6c..bc371baf3 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -6,12 +6,8 @@ subdir('backend')
enum_headers = files(
'backend/bacon-time-label.h',
- 'backend/bacon-video-controls-actor.h',
- 'backend/bacon-video-spinner-actor.h',
'backend/bacon-video-widget-gst-missing-plugins.h',
'backend/bacon-video-widget.h',
- 'backend/clock.h',
- 'backend/totem-aspect-frame.h',
'icon-helpers.h',
'totem-grilo.h',
'totem-interface.h',
diff --git a/src/plugins/rotation/totem-rotation.c b/src/plugins/rotation/totem-rotation.c
index 3402de98c..087915a09 100644
--- a/src/plugins/rotation/totem-rotation.c
+++ b/src/plugins/rotation/totem-rotation.c
@@ -160,8 +160,6 @@ update_state (TotemRotationPlugin *pi,
TotemRotationPluginPrivate *priv = pi->priv;
if (mrl == NULL) {
- bacon_video_widget_set_rotation (BACON_VIDEO_WIDGET (priv->bvw),
- BVW_ROTATION_R_ZERO);
g_simple_action_set_enabled (priv->rotate_left_action, FALSE);
g_simple_action_set_enabled (priv->rotate_right_action, FALSE);
} else {
@@ -298,9 +296,6 @@ impl_deactivate (PeasActivatable *plugin)
g_action_map_remove_action (G_ACTION_MAP (priv->totem), "rotate-left");
g_action_map_remove_action (G_ACTION_MAP (priv->totem), "rotate-right");
- bacon_video_widget_set_rotation (BACON_VIDEO_WIDGET (priv->bvw),
- BVW_ROTATION_R_ZERO);
-
priv->totem = NULL;
priv->bvw = NULL;
}
diff --git a/src/totem-object.c b/src/totem-object.c
index 8ba50a0b4..51d6f3cfe 100644
--- a/src/totem-object.c
+++ b/src/totem-object.c
@@ -77,6 +77,9 @@
#define DEFAULT_WINDOW_W 650
#define DEFAULT_WINDOW_H 500
+#define POPUP_HIDING_TIMEOUT 2 /* seconds */
+#define OVERLAY_OPACITY 0.86
+
#define TOTEM_SESSION_SAVE_TIMEOUT 10 /* seconds */
/* casts are to shut gcc up */
@@ -164,6 +167,7 @@ static void
totem_object_app_activate (GApplication *app)
{
Totem *totem;
+ GtkStyleContext *style_context;
totem = TOTEM_OBJECT (app);
@@ -178,14 +182,10 @@ totem_object_app_activate (GApplication *app)
totem->win = GTK_WIDGET (gtk_builder_get_object (totem->xml, "totem_main_window"));
#if DEVELOPMENT_VERSION
- {
- GtkStyleContext *style_context;
- style_context = gtk_widget_get_style_context (GTK_WIDGET (totem->win));
- gtk_style_context_add_class (style_context, "devel");
- }
+ style_context = gtk_widget_get_style_context (GTK_WIDGET (totem->win));
+ gtk_style_context_add_class (style_context, "devel");
#endif
-
/* Menubar */
totem->stack = GTK_WIDGET (gtk_builder_get_object (totem->xml, "tmw_main_stack"));
@@ -214,11 +214,30 @@ totem_object_app_activate (GApplication *app)
totem->controls_visibility = TOTEM_CONTROLS_UNDEFINED;
- totem->seek = g_object_get_data (totem->controls, "seek_scale");
+ totem->controls = gtk_builder_new ();
+ const char *objects[] = { "toolbar", NULL };
+ GError *error = NULL;
+ if (gtk_builder_add_objects_from_file (totem->controls, DATADIR "/totem/controls.ui", (gchar **) objects, &error) == 0)
+ g_assert_not_reached ();
+ gtk_grid_attach (GTK_GRID (totem->bvw_grid),
+ GTK_WIDGET (gtk_builder_get_object (totem->controls, "toolbar")),
+ 0, 2, 3, 1);
+ gtk_widget_set_hexpand (GTK_WIDGET (gtk_builder_get_object (totem->controls, "toolbar")), TRUE);
+ gtk_widget_set_vexpand (GTK_WIDGET (gtk_builder_get_object (totem->controls, "toolbar")), TRUE);
+ gtk_widget_set_valign (GTK_WIDGET (gtk_builder_get_object (totem->controls, "toolbar")), GTK_ALIGN_END);
+
+ totem->spinner = gtk_spinner_new ();
+ gtk_grid_attach (GTK_GRID (totem->bvw_grid), totem->spinner, 1, 2, 1, 1);
+ gtk_widget_set_vexpand (totem->spinner, TRUE);
+ gtk_widget_set_hexpand (totem->spinner, TRUE);
+ style_context = gtk_widget_get_style_context (totem->spinner);
+ gtk_style_context_add_class (style_context, "osd");
+
+ totem->seek = GTK_WIDGET (gtk_builder_get_object (totem->controls, "seek_scale"));
totem->seekadj = gtk_range_get_adjustment (GTK_RANGE (totem->seek));
- totem->volume = g_object_get_data (totem->controls, "volume_button");
- totem->time_label = g_object_get_data (totem->controls, "time_label");
- totem->time_rem_label = g_object_get_data (totem->controls, "time_rem_label");
+ totem->volume = GTK_WIDGET (gtk_builder_get_object (totem->controls, "volume_button"));
+ totem->time_label = BACON_TIME_LABEL (gtk_builder_get_object (totem->controls, "time_label"));
+ totem->time_rem_label = BACON_TIME_LABEL (gtk_builder_get_object (totem->controls, "time_rem_label"));
totem->pause_start = optionstate.pause;
totem_callback_connect (totem);
@@ -514,14 +533,13 @@ totem_object_class_init (TotemObjectClass *klass)
static void
totem_object_init (TotemObject *totem)
{
- if (gtk_clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
- g_warning ("gtk-clutter failed to initialise, expect problems from here on.");
-
totem->settings = g_settings_new (TOTEM_GSETTINGS_SCHEMA);
g_application_add_main_option_entries (G_APPLICATION (totem), all_options);
g_application_add_option_group (G_APPLICATION (totem), bacon_video_widget_get_option_group ());
+ totem->busy_popup_ht = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
totem_app_actions_setup (totem);
}
@@ -530,6 +548,7 @@ totem_object_finalize (GObject *object)
{
TotemObject *totem = TOTEM_OBJECT (object);
+ g_clear_pointer (&totem->busy_popup_ht, g_hash_table_destroy);
g_clear_pointer (&totem->title, g_free);
g_clear_pointer (&totem->subtitle, g_free);
g_clear_pointer (&totem->search_string, g_free);
@@ -992,6 +1011,41 @@ totem_object_set_current_subtitle (TotemObject *totem, const char *subtitle_uri)
totem_playlist_set_current_subtitle (totem->playlist, subtitle_uri);
}
+static void set_controls_visibility (TotemObject *totem,
+ gboolean visible,
+ gboolean animate);
+
+static void
+unschedule_hiding_popup (TotemObject *totem)
+{
+ if (totem->transition_timeout_id > 0)
+ g_source_remove (totem->transition_timeout_id);
+ totem->transition_timeout_id = 0;
+}
+
+static gboolean
+hide_popup_timeout_cb (TotemObject *totem)
+{
+ set_controls_visibility (totem, FALSE, TRUE);
+ unschedule_hiding_popup (totem);
+ return G_SOURCE_REMOVE;
+}
+
+static void
+schedule_hiding_popup (TotemObject *totem)
+{
+ unschedule_hiding_popup (totem);
+ totem->transition_timeout_id = g_timeout_add_seconds (POPUP_HIDING_TIMEOUT, (GSourceFunc) hide_popup_timeout_cb, totem);
+ g_source_set_name_by_id (totem->transition_timeout_id, "[totem] schedule_hiding_popup");
+}
+
+static void
+show_popup (TotemObject *totem)
+{
+ set_controls_visibility (totem, TRUE, FALSE);
+ schedule_hiding_popup (totem);
+}
+
void
totem_object_set_main_page (TotemObject *totem,
const char *page_id)
@@ -1029,7 +1083,7 @@ totem_object_set_main_page (TotemObject *totem,
gtk_widget_show (totem->gear_button);
gtk_widget_hide (totem->add_button);
gtk_widget_hide (totem->main_menu_button);
- bacon_video_widget_show_popup (totem->bvw);
+ show_popup (totem);
} else if (g_strcmp0 (page_id, "grilo") == 0) {
totem_grilo_start (TOTEM_GRILO (totem->grilo));
g_object_set (totem->header,
@@ -1235,6 +1289,10 @@ totem_remote_setting_get_type (void)
}
static void
+unmark_popup_busy (TotemObject *totem,
+ const char *reason);
+
+static void
reset_seek_status (TotemObject *totem)
{
/* Release the lock and reset everything so that we
@@ -1242,7 +1300,7 @@ reset_seek_status (TotemObject *totem)
if (totem->seek_lock != FALSE) {
totem->seek_lock = FALSE;
- bacon_video_widget_unmark_popup_busy (totem->bvw, "seek started");
+ unmark_popup_busy (totem, "seek started");
bacon_video_widget_seek (totem->bvw, 0, NULL);
bacon_video_widget_stop (totem->bvw);
play_pause_set_label (totem, STATE_STOPPED);
@@ -1638,19 +1696,18 @@ window_state_event_cb (GtkWidget *window,
totem_object_save_size (totem);
totem->controls_visibility = TOTEM_CONTROLS_FULLSCREEN;
- show_controls (totem, FALSE);
} else {
totem->controls_visibility = TOTEM_CONTROLS_VISIBLE;
- show_controls (totem, TRUE);
+ totem_object_save_size (totem);
}
- bacon_video_widget_set_fullscreen (totem->bvw,
- totem->controls_visibility == TOTEM_CONTROLS_FULLSCREEN);
-
action = g_action_map_lookup_action (G_ACTION_MAP (totem), "fullscreen");
g_simple_action_set_state (G_SIMPLE_ACTION (action),
g_variant_new_boolean (totem->controls_visibility == TOTEM_CONTROLS_FULLSCREEN));
+ if (totem->transition_timeout_id > 0)
+ set_controls_visibility (totem, TRUE, FALSE);
+
g_object_notify (G_OBJECT (totem), "fullscreen");
return FALSE;
@@ -1819,6 +1876,47 @@ totem_object_set_next_subtitle (TotemObject *totem,
totem->next_subtitle = g_strdup (subtitle);
}
+static void
+set_controls_visibility (TotemObject *totem,
+ gboolean visible,
+ gboolean animate)
+{
+ gtk_widget_set_visible (GTK_WIDGET (gtk_builder_get_object (totem->controls, "toolbar")), visible);
+ gtk_widget_set_visible (totem->fullscreen_header, visible &&
+ totem->controls_visibility == TOTEM_CONTROLS_FULLSCREEN);
+ bacon_video_widget_set_show_cursor (totem->bvw, visible);
+ if (visible && animate)
+ schedule_hiding_popup (totem);
+ totem->reveal_controls = visible;
+}
+
+static void
+mark_popup_busy (TotemObject *totem,
+ const char *reason)
+{
+ g_hash_table_insert (totem->busy_popup_ht,
+ g_strdup (reason),
+ GINT_TO_POINTER (1));
+ g_debug ("Adding popup busy for reason %s", reason);
+
+ set_controls_visibility (totem, TRUE, FALSE);
+ unschedule_hiding_popup (totem);
+}
+
+static void
+unmark_popup_busy (TotemObject *totem,
+ const char *reason)
+{
+ g_hash_table_remove (totem->busy_popup_ht, reason);
+ g_debug ("Removing popup busy for reason %s", reason);
+
+ if (g_hash_table_size (totem->busy_popup_ht) == 0 &&
+ gtk_widget_get_opacity (GTK_WIDGET (gtk_builder_get_object (totem->controls, "toolbar"))) != 0.0) {
+ g_debug ("Will hide popup soon");
+ schedule_hiding_popup (totem);
+ }
+}
+
/**
* totem_object_set_mrl:
* @totem: a #TotemObject
@@ -1866,7 +1964,7 @@ totem_object_set_mrl (TotemObject *totem,
/* Subtitle selection */
totem_object_set_sensitivity2 ("select-subtitle", FALSE);
- /* Set the logo */
+ /* Set the label */
update_mrl_label (totem, NULL);
g_object_notify (G_OBJECT (totem), "playing");
@@ -1886,6 +1984,7 @@ totem_object_set_mrl (TotemObject *totem,
g_application_mark_busy (G_APPLICATION (totem));
bacon_video_widget_open (totem->bvw, mrl);
+ mark_popup_busy (totem, "opening file");
if (subtitle) {
bacon_video_widget_set_text_subtitle (totem->bvw, subtitle);
} else if (autoload_sub) {
@@ -2373,8 +2472,9 @@ back_button_clicked_cb (GtkButton *button,
{
if (g_strcmp0 (totem_object_get_main_page (totem), "player") == 0) {
totem_playlist_clear (totem->playlist);
- gtk_window_unfullscreen (GTK_WINDOW (totem->win));
totem_object_set_main_page (totem, "grilo");
+ gtk_window_unfullscreen (GTK_WINDOW (totem->win));
+ bacon_video_widget_set_show_cursor (totem->bvw, TRUE);
} else {
totem_grilo_back_button_clicked (TOTEM_GRILO (totem->grilo));
}
@@ -2485,9 +2585,19 @@ on_error_event (BaconVideoWidget *bvw, char *message,
}
static void
-on_buffering_event (BaconVideoWidget *bvw, gdouble percentage, TotemObject *totem)
+on_buffering_event (BaconVideoWidget *bvw, gdouble percent, TotemObject *totem)
{
- //FIXME show that somehow
+ if (percent >= 1.0) {
+ gtk_spinner_stop (GTK_SPINNER (totem->spinner));
+ gtk_widget_hide (totem->spinner);
+ unmark_popup_busy (totem, "buffering");
+ } else {
+ g_autofree char *text = NULL;
+
+ mark_popup_busy (totem, "buffering");
+ gtk_widget_show (totem->spinner);
+ gtk_spinner_start (GTK_SPINNER (totem->spinner));
+ }
}
static void
@@ -2497,6 +2607,29 @@ on_download_buffering_event (BaconVideoWidget *bvw, gdouble level, TotemObject *
}
static void
+play_starting_cb (BaconVideoWidget *bvw,
+ TotemObject *totem)
+{
+ unmark_popup_busy (totem, "opening file");
+}
+
+static gboolean
+on_bvw_motion_notify_cb (BaconVideoWidget *bvw,
+ GdkEventMotion *event,
+ TotemObject *totem)
+{
+ if (!totem->reveal_controls)
+ set_controls_visibility (totem, TRUE, TRUE);
+
+ /* FIXME: handle hover
+ * if (hovering)
+ * unschedule_hiding_popup (bvw);
+ */
+
+ return GDK_EVENT_PROPAGATE;
+}
+
+static void
update_fill (TotemObject *totem, gdouble level)
{
if (level < 0.0) {
@@ -2594,6 +2727,34 @@ volume_button_value_changed_cb (GtkScaleButton *button, gdouble value, TotemObje
bacon_video_widget_set_volume (totem->bvw, value);
}
+static gboolean
+volume_button_scroll_event_cb (GtkWidget *widget,
+ GdkEventScroll *event,
+ gpointer user_data)
+{
+ TotemObject *totem = user_data;
+ gboolean increase;
+
+ if (event->direction == GDK_SCROLL_SMOOTH) {
+ gdouble delta_y;
+
+ gdk_event_get_scroll_deltas ((GdkEvent *) event, NULL, &delta_y);
+ if (delta_y == 0.0)
+ return GDK_EVENT_PROPAGATE;
+
+ increase = delta_y < 0.0;
+ } else if (event->direction == GDK_SCROLL_UP) {
+ increase = TRUE;
+ } else if (event->direction == GDK_SCROLL_DOWN) {
+ increase = SEEK_BACKWARD_OFFSET * 1000;
+ } else {
+ return GDK_EVENT_PROPAGATE;
+ }
+
+ totem_object_set_volume_relative (totem, increase ? VOLUME_UP_OFFSET : VOLUME_DOWN_OFFSET);
+ return GDK_EVENT_STOP;
+}
+
static void
update_volume_sliders (TotemObject *totem)
{
@@ -2629,7 +2790,7 @@ seek_slider_pressed_cb (GtkWidget *widget, GdkEventButton *event, TotemObject *t
event->button = GDK_BUTTON_PRIMARY;
totem->seek_lock = TRUE;
- bacon_video_widget_mark_popup_busy (totem->bvw, "seek started");
+ mark_popup_busy (totem, "seek started");
return FALSE;
}
@@ -2667,7 +2828,7 @@ seek_slider_released_cb (GtkWidget *widget, GdkEventButton *event, TotemObject *
/* set to FALSE here to avoid triggering a final seek when
* syncing the adjustments while being in direct seek mode */
totem->seek_lock = FALSE;
- bacon_video_widget_unmark_popup_busy (totem->bvw, "seek started");
+ unmark_popup_busy (totem, "seek started");
/* sync both adjustments */
adj = gtk_range_get_adjustment (GTK_RANGE (widget));
@@ -2679,6 +2840,33 @@ seek_slider_released_cb (GtkWidget *widget, GdkEventButton *event, TotemObject *
return FALSE;
}
+static gboolean
+seek_slider_scroll_event_cb (GtkWidget *widget,
+ GdkEventScroll *event,
+ gpointer user_data)
+{
+ TotemObject *totem = user_data;
+ gint64 offset;
+
+ if (event->direction == GDK_SCROLL_SMOOTH) {
+ gdouble delta_y;
+
+ gdk_event_get_scroll_deltas ((GdkEvent *) event, NULL, &delta_y);
+ if (delta_y == 0.0)
+ return GDK_EVENT_PROPAGATE;
+
+ offset = delta_y >= 0.0 ? SEEK_BACKWARD_OFFSET * 1000 : SEEK_FORWARD_OFFSET * 1000;
+ } else if (event->direction == GDK_SCROLL_UP) {
+ offset = SEEK_FORWARD_OFFSET * 1000;
+ } else if (event->direction == GDK_SCROLL_DOWN) {
+ offset = SEEK_BACKWARD_OFFSET * 1000;
+ } else {
+ return GDK_EVENT_PROPAGATE;
+ }
+ totem_object_seek_relative (totem, offset, FALSE);
+ return GDK_EVENT_STOP;
+}
+
gboolean
totem_object_open_files (TotemObject *totem, char **list)
{
@@ -2779,24 +2967,6 @@ totem_object_open_files_list (TotemObject *totem, GSList *list)
return changed;
}
-void
-show_controls (TotemObject *totem, gboolean was_fullscreen)
-{
- GtkWidget *bvw_box;
-
- if (totem->bvw == NULL)
- return;
-
- bvw_box = GTK_WIDGET (gtk_builder_get_object (totem->xml, "tmw_bvw_box"));
-
- if (totem->controls_visibility == TOTEM_CONTROLS_VISIBLE) {
- totem_object_save_size (totem);
- } else {
- /* We won't show controls in fullscreen */
- gtk_container_set_border_width (GTK_CONTAINER (bvw_box), 0);
- }
-}
-
/**
* totem_object_next_angle:
* @totem: a #TotemObject
@@ -3279,7 +3449,7 @@ totem_object_handle_key_press (TotemObject *totem, GdkEventKey *event)
case GDK_KEY_B:
case GDK_KEY_b:
totem_object_seek_previous (totem);
- bacon_video_widget_show_popup (totem->bvw);
+ show_popup (totem);
break;
case GDK_KEY_C:
case GDK_KEY_c:
@@ -3321,7 +3491,7 @@ totem_object_handle_key_press (TotemObject *totem, GdkEventKey *event)
case GDK_KEY_n:
case GDK_KEY_End:
totem_object_seek_next (totem);
- bacon_video_widget_show_popup (totem->bvw);
+ show_popup (totem);
break;
case GDK_KEY_OpenURL:
totem_object_set_fullscreen (totem, FALSE);
@@ -3426,7 +3596,7 @@ totem_object_handle_key_press (TotemObject *totem, GdkEventKey *event)
if (totem_object_is_seekable (totem)) {
totem_object_handle_seek (totem, event, is_forward);
- bacon_video_widget_show_popup (totem->bvw);
+ show_popup (totem);
}
} else {
if (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_Page_Down)
@@ -3437,7 +3607,7 @@ totem_object_handle_key_press (TotemObject *totem, GdkEventKey *event)
break;
case GDK_KEY_Home:
totem_object_seek (totem, 0);
- bacon_video_widget_show_popup (totem->bvw);
+ show_popup (totem);
break;
case GDK_KEY_Up:
if (bacon_video_widget_has_menus (totem->bvw) != FALSE)
@@ -3465,7 +3635,7 @@ totem_object_handle_key_press (TotemObject *totem, GdkEventKey *event)
break;
case GDK_KEY_Menu:
case GDK_KEY_F10:
- bacon_video_widget_show_popup (totem->bvw);
+ show_popup (totem);
if (totem->controls_visibility != TOTEM_CONTROLS_FULLSCREEN) {
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (totem->gear_button),
!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (totem->gear_button)));
@@ -3475,7 +3645,7 @@ totem_object_handle_key_press (TotemObject *totem, GdkEventKey *event)
}
break;
case GDK_KEY_Time:
- bacon_video_widget_show_popup (totem->bvw);
+ show_popup (totem);
break;
case GDK_KEY_equal:
if (mask == GDK_CONTROL_MASK)
@@ -3489,7 +3659,7 @@ totem_object_handle_key_press (TotemObject *totem, GdkEventKey *event)
case GDK_KEY_KP_Add:
if (mask != GDK_CONTROL_MASK) {
totem_object_seek_next (totem);
- bacon_video_widget_show_popup (totem->bvw);
+ show_popup (totem);
} else {
totem_object_set_zoom (totem, TRUE);
}
@@ -3498,7 +3668,7 @@ totem_object_handle_key_press (TotemObject *totem, GdkEventKey *event)
case GDK_KEY_KP_Subtract:
if (mask != GDK_CONTROL_MASK) {
totem_object_seek_previous (totem);
- bacon_video_widget_show_popup (totem->bvw);
+ show_popup (totem);
} else {
totem_object_set_zoom (totem, FALSE);
}
@@ -3534,33 +3704,6 @@ totem_object_handle_key_press (TotemObject *totem, GdkEventKey *event)
return retval;
}
-static void
-on_seek_requested_event (BaconVideoWidget *bvw,
- gboolean forward,
- TotemObject *totem)
-{
- gint64 offset;
-
- offset = forward ? SEEK_FORWARD_OFFSET * 1000 : SEEK_BACKWARD_OFFSET * 1000;
- totem_object_seek_relative (totem, offset, FALSE);
-}
-
-static void
-on_track_skip_requested_event (BaconVideoWidget *bvw,
- gboolean is_forward,
- TotemObject *totem)
-{
- totem_object_direction (totem, is_forward ? TOTEM_PLAYLIST_DIRECTION_NEXT : TOTEM_PLAYLIST_DIRECTION_PREVIOUS);
-}
-
-static void
-on_volume_change_requested_event (BaconVideoWidget *bvw,
- gboolean increase,
- TotemObject *totem)
-{
- totem_object_set_volume_relative (totem, increase ? VOLUME_UP_OFFSET : VOLUME_DOWN_OFFSET);
-}
-
gboolean
window_key_press_event_cb (GtkWidget *win, GdkEventKey *event, TotemObject *totem)
{
@@ -3776,9 +3919,9 @@ popup_menu_shown_cb (GtkToggleButton *button,
TotemObject *totem)
{
if (gtk_toggle_button_get_active (button))
- bacon_video_widget_mark_popup_busy (totem->bvw, "toolbar/go menu visible");
+ mark_popup_busy (totem, "toolbar/go menu visible");
else
- bacon_video_widget_unmark_popup_busy (totem->bvw, "toolbar/go menu visible");
+ unmark_popup_busy (totem, "toolbar/go menu visible");
}
static void
@@ -3787,9 +3930,9 @@ volume_button_menu_shown_cb (GObject *popover,
TotemObject *totem)
{
if (gtk_widget_is_visible (GTK_WIDGET (popover)))
- bacon_video_widget_mark_popup_busy (totem->bvw, "volume menu visible");
+ mark_popup_busy (totem, "volume menu visible");
else
- bacon_video_widget_unmark_popup_busy (totem->bvw, "volume menu visible");
+ unmark_popup_busy (totem, "volume menu visible");
}
static void
@@ -3854,7 +3997,7 @@ totem_callback_connect (TotemObject *totem)
g_variant_new_boolean (totem_playlist_get_repeat (totem->playlist)));
/* Controls */
- box = g_object_get_data (totem->controls, "controls_box");
+ box = GTK_BOX (gtk_builder_get_object (totem->controls, "controls_box"));
gtk_widget_insert_action_group (GTK_WIDGET (box), "app", G_ACTION_GROUP (totem));
/* Previous */
@@ -3880,18 +4023,22 @@ totem_callback_connect (TotemObject *totem)
G_CALLBACK (seek_slider_pressed_cb), totem);
g_signal_connect (totem->seek, "button-release-event",
G_CALLBACK (seek_slider_released_cb), totem);
+ g_signal_connect (totem->seek, "scroll-event",
+ G_CALLBACK (seek_slider_scroll_event_cb), totem);
g_signal_connect (totem->seekadj, "value-changed",
G_CALLBACK (seek_slider_changed_cb), totem);
/* Volume */
g_signal_connect (totem->volume, "value-changed",
G_CALLBACK (volume_button_value_changed_cb), totem);
+ g_signal_connect (totem->volume, "scroll-event",
+ G_CALLBACK (volume_button_scroll_event_cb), totem);
item = gtk_scale_button_get_popup (GTK_SCALE_BUTTON (totem->volume));
g_signal_connect (G_OBJECT (item), "notify::visible",
G_CALLBACK (volume_button_menu_shown_cb), totem);
/* Go button */
- item = g_object_get_data (totem->controls, "go_button");
+ item = GTK_WIDGET (gtk_builder_get_object (totem->controls, "go_button"));
menu = (GMenuModel *) gtk_builder_get_object (totem->xml, "gomenu");
gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (item), menu);
popover = gtk_menu_button_get_popover (GTK_MENU_BUTTON (item));
@@ -4040,17 +4187,17 @@ grilo_widget_setup (TotemObject *totem)
}
static void
-add_fullscreen_toolbar (TotemObject *totem)
+add_fullscreen_toolbar (TotemObject *totem,
+ GtkWidget *container)
{
- GtkWidget *container, *item;
+ GtkWidget *item;
GMenuModel *menu;
- container = GTK_WIDGET (bacon_video_widget_get_header_controls_object (totem->bvw));
-
totem->fullscreen_header = g_object_new (TOTEM_TYPE_MAIN_TOOLBAR,
"show-search-button", FALSE,
"show-select-button", FALSE,
"show-back-button", TRUE,
+ "opacity", OVERLAY_OPACITY,
NULL);
g_object_bind_property (totem->header, "title",
totem->fullscreen_header, "title", 0);
@@ -4079,8 +4226,12 @@ add_fullscreen_toolbar (TotemObject *totem)
G_CALLBACK (popup_menu_shown_cb), totem);
totem->fullscreen_gear_button = item;
- gtk_container_add (GTK_CONTAINER (container), totem->fullscreen_header);
+ gtk_grid_attach (GTK_GRID (container), totem->fullscreen_header, 0, 0, 3, 1);
+ gtk_widget_set_halign (totem->fullscreen_header, GTK_ALIGN_FILL);
+ gtk_widget_set_hexpand (totem->fullscreen_header, TRUE);
+ gtk_widget_set_opacity (totem->fullscreen_header, OVERLAY_OPACITY);
gtk_widget_show_all (totem->fullscreen_header);
+ gtk_widget_hide (totem->fullscreen_header);
}
void
@@ -4088,9 +4239,6 @@ video_widget_create (TotemObject *totem)
{
GError *err = NULL;
GtkContainer *container;
- BaconVideoWidget **bvw;
- GdkWindow *window;
- gboolean fullscreen;
totem->bvw = BACON_VIDEO_WIDGET (bacon_video_widget_new (&err));
@@ -4100,12 +4248,6 @@ video_widget_create (TotemObject *totem)
g_error_free (err);
}
- window = gtk_widget_get_window (totem->win);
-
- fullscreen = window && ((gdk_window_get_state (window) & GDK_WINDOW_STATE_FULLSCREEN) != 0);
- bacon_video_widget_set_fullscreen (totem->bvw, fullscreen);
- totem->controls = bacon_video_widget_get_controls_object (totem->bvw);
-
g_signal_connect_after (G_OBJECT (totem->bvw),
"button-press-event",
G_CALLBACK (on_video_button_press_event),
@@ -4143,23 +4285,28 @@ video_widget_create (TotemObject *totem)
G_CALLBACK (on_error_event),
totem);
g_signal_connect (G_OBJECT (totem->bvw),
- "seek-requested",
- G_CALLBACK (on_seek_requested_event),
+ "play-starting",
+ G_CALLBACK (play_starting_cb),
totem);
g_signal_connect (G_OBJECT (totem->bvw),
- "track-skip-requested",
- G_CALLBACK (on_track_skip_requested_event),
+ "scroll-event",
+ G_CALLBACK (seek_slider_scroll_event_cb),
totem);
g_signal_connect (G_OBJECT (totem->bvw),
- "volume-change-requested",
- G_CALLBACK (on_volume_change_requested_event),
+ "motion-notify-event",
+ G_CALLBACK (on_bvw_motion_notify_cb),
totem);
container = GTK_CONTAINER (gtk_builder_get_object (totem->xml, "tmw_bvw_box"));
gtk_container_add (container,
GTK_WIDGET (totem->bvw));
- add_fullscreen_toolbar (totem);
+ totem->bvw_grid = gtk_grid_new ();
+ gtk_overlay_add_overlay (GTK_OVERLAY (totem->bvw), totem->bvw_grid);
+ gtk_widget_set_halign (totem->bvw_grid, GTK_ALIGN_FILL);
+ gtk_widget_set_valign (totem->bvw_grid, GTK_ALIGN_FILL);
+ gtk_widget_show (totem->bvw_grid);
+ add_fullscreen_toolbar (totem, totem->bvw_grid);
/* Events for the widget video window as well */
gtk_widget_add_events (GTK_WIDGET (totem->bvw),
@@ -4175,15 +4322,7 @@ video_widget_create (TotemObject *totem)
target_table, G_N_ELEMENTS (target_table),
GDK_ACTION_MOVE);
- bvw = &(totem->bvw);
- g_object_add_weak_pointer (G_OBJECT (totem->bvw),
- (gpointer *) bvw);
-
gtk_widget_show (GTK_WIDGET (totem->bvw));
-
- /* FIXME: Otherwise we get a visible but
- * not realized widget ?!?! */
- gtk_widget_realize (GTK_WIDGET (totem->bvw));
}
/**
diff --git a/src/totem-private.h b/src/totem-private.h
index de6edb42d..12f31aa7c 100644
--- a/src/totem-private.h
+++ b/src/totem-private.h
@@ -46,7 +46,7 @@
widget = GTK_WIDGET (gtk_builder_get_object (xml, name)); \
gtk_widget_set_sensitive (widget, state); \
}
-#define totem_controls_set_sensitivity(name, state) gtk_widget_set_sensitive (g_object_get_data (totem->controls, name), state)
+#define totem_controls_set_sensitivity(name, state) gtk_widget_set_sensitive (GTK_WIDGET (gtk_builder_get_object (totem->controls, name)), state)
#define totem_object_set_sensitivity2(name, state) \
{ \
@@ -75,12 +75,14 @@ struct _TotemObject {
GtkWidget *win;
GtkWidget *stack;
BaconVideoWidget *bvw;
+ GtkWidget *bvw_grid;
GtkWidget *prefs;
GtkWindow *shortcuts_win;
+ GtkWidget *spinner;
GtkWidget *grilo;
- GObject *controls;
+ GtkBuilder *controls;
GtkWidget *play_button;
BaconTimeLabel *time_label;
BaconTimeLabel *time_rem_label;
@@ -112,6 +114,9 @@ struct _TotemObject {
/* controls management */
ControlsVisibility controls_visibility;
+ gboolean reveal_controls;
+ guint transition_timeout_id;
+ GHashTable *busy_popup_ht; /* key=reason string, value=gboolean */
/* Stream info */
gint64 stream_length;