[totem/wip/hadess/glsink: 12/13] reimplement popup showing/hiding




commit 4a89341575cba977d5738dc8045a7ffaaed1db66
Author: Bastien Nocera <hadess hadess net>
Date:   Fri Jan 28 16:50:37 2022 +0100

    reimplement popup showing/hiding

 src/backend/bacon-video-widget.c | 332 +++++++++------------------------------
 src/backend/bacon-video-widget.h |   9 +-
 src/totem-object.c               | 207 +++++++++++++++++++++---
 src/totem-private.h              |   4 +
 4 files changed, 259 insertions(+), 293 deletions(-)
---
diff --git a/src/backend/bacon-video-widget.c b/src/backend/bacon-video-widget.c
index d08225dd4..f4c38d9ca 100644
--- a/src/backend/bacon-video-widget.c
+++ b/src/backend/bacon-video-widget.c
@@ -87,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
@@ -119,6 +118,7 @@ enum
   SIGNAL_BUFFERING,
   SIGNAL_MISSING_PLUGINS,
   SIGNAL_DOWNLOAD_BUFFERING,
+  SIGNAL_PLAY_STARTING,
   LAST_SIGNAL
 };
 
@@ -142,7 +142,7 @@ enum
   PROP_HUE,
   PROP_AUDIO_OUTPUT_TYPE,
   PROP_AV_OFFSET,
-  PROP_REVEAL_CONTROLS
+  PROP_SHOW_CURSOR,
 };
 
 static const gchar *video_props_str[4] = {
@@ -191,11 +191,6 @@ struct _BaconVideoWidget
 
   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;
@@ -280,9 +275,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;
@@ -376,36 +368,6 @@ bvw_check_if_video_decoder_is_missing (BaconVideoWidget * bvw)
   }
 }
 
-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
 bacon_video_widget_realize (GtkWidget * widget)
 {
@@ -417,11 +379,6 @@ bacon_video_widget_realize (GtkWidget * widget)
   gtk_widget_set_realized (widget, TRUE);
 
   /* 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);
@@ -438,10 +395,6 @@ bacon_video_widget_unrealize (GtkWidget *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);
@@ -458,90 +411,6 @@ set_current_actor (BaconVideoWidget *bvw)
                                    draw_logo ? "logo" : "video");
 }
 
-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)
-{
-#if 0
-  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");
-#endif
-}
-
 static void
 translate_coords (GtkWidget   *widget,
                  GdkWindow   *window,
@@ -561,23 +430,6 @@ translate_coords (GtkWidget   *widget,
   }
 }
 
-static gboolean
-ignore_event (BaconVideoWidget *bvw,
-             int               x,
-             int               y)
-{
-#if 0
-  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;
-#endif
-  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 */
@@ -599,20 +451,6 @@ bacon_video_widget_motion_notify (GtkWidget *widget, GdkEventMotion *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;
 }
 
@@ -621,7 +459,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);
@@ -630,10 +467,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;
@@ -641,8 +474,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);
 
@@ -888,14 +723,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 */
@@ -1052,6 +887,25 @@ bacon_video_widget_class_init (BaconVideoWidgetClass * klass)
                   0,
                   NULL, NULL,
                   g_cclosure_marshal_VOID__DOUBLE, G_TYPE_NONE, 1, G_TYPE_DOUBLE);
+
+  /**
+   * BaconVideoWidget::play-starting:
+   * @bvw: the #BaconVideoWidget which received the signal
+   *
+   * Emitted when a movie will start playing, meaning it's not buffering, pausing
+   *  waiting for plugins to be installed, drives to be mounted or authentication
+   *  to succeed.
+   *
+   * This usually means that popups showing state 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
@@ -1088,8 +942,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 ();
 }
 
@@ -2521,8 +2373,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) */
@@ -2538,7 +2388,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);
 
@@ -2620,6 +2469,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;
@@ -2680,8 +2532,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);
@@ -3272,81 +3124,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)
-{
-#if 0
-  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);
-  }
-#endif
-}
-
 /* =========================================== */
 /*                                             */
 /*               Play/Pause, Stop              */
@@ -3621,8 +3398,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);
@@ -3687,7 +3462,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);
@@ -4361,6 +4136,43 @@ bacon_video_widget_get_volume (BaconVideoWidget * bvw)
   return bvw->volume;
 }
 
+/**
+ * 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
diff --git a/src/backend/bacon-video-widget.h b/src/backend/bacon-video-widget.h
index 4b90bf0cc..4221b608b 100644
--- a/src/backend/bacon-video-widget.h
+++ b/src/backend/bacon-video-widget.h
@@ -142,6 +142,8 @@ 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 */
 /**
@@ -411,10 +413,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);
diff --git a/src/totem-object.c b/src/totem-object.c
index 77b26f161..a98c0897b 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 */
@@ -527,6 +530,8 @@ totem_object_init (TotemObject *totem)
        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);
 }
 
@@ -535,6 +540,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);
@@ -997,6 +1003,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
+totem_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)
@@ -1034,7 +1075,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);
+               totem_show_popup (totem);
        } else if (g_strcmp0 (page_id, "grilo") == 0) {
                totem_grilo_start (TOTEM_GRILO (totem->grilo));
                g_object_set (totem->header,
@@ -1239,6 +1280,10 @@ totem_remote_setting_get_type (void)
        return etype;
 }
 
+static void
+bacon_video_widget_unmark_popup_busy (TotemObject      *totem,
+                                   const char       *reason);
+
 static void
 reset_seek_status (TotemObject *totem)
 {
@@ -1247,7 +1292,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");
+               bacon_video_widget_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);
@@ -1825,6 +1870,91 @@ totem_object_set_next_subtitle (TotemObject *totem,
        totem->next_subtitle = g_strdup (subtitle);
 }
 
+static void
+set_controls_visibility (TotemObject      *totem,
+                        gboolean          visible,
+                        gboolean          animate)
+{
+  double opacity = visible ? OVERLAY_OPACITY : 0;
+#if 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);
+#endif
+  gtk_widget_set_opacity (GTK_WIDGET (gtk_builder_get_object (totem->controls, "toolbar")), opacity);
+  //FIXME
+  bacon_video_widget_set_show_cursor (totem->bvw, visible);
+  if (visible && animate)
+    schedule_hiding_popup (totem);
+  totem->reveal_controls = visible;
+}
+
+/**
+ * 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
+ */
+static void
+bacon_video_widget_mark_popup_busy (TotemObject      *totem,
+                                   const char       *reason)
+{
+  g_hash_table_insert (totem->busy_popup_ht,
+                      g_strdup (reason),
+                      GINT_TO_POINTER (1));
+
+  set_controls_visibility (totem, TRUE, FALSE);
+
+  g_debug ("Adding popup busy for reason %s", reason);
+
+  unschedule_hiding_popup (totem);
+}
+
+/**
+ * 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 (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
@@ -1892,6 +2022,7 @@ totem_object_set_mrl (TotemObject *totem,
 
                g_application_mark_busy (G_APPLICATION (totem));
                bacon_video_widget_open (totem->bvw, mrl);
+               bacon_video_widget_mark_popup_busy (totem, "opening file");
                if (subtitle) {
                        bacon_video_widget_set_text_subtitle (totem->bvw, subtitle);
                } else if (autoload_sub) {
@@ -2523,6 +2654,34 @@ on_download_buffering_event (BaconVideoWidget *bvw, gdouble level, TotemObject *
        update_fill (totem, level);
 }
 
+static void
+play_starting_cb (BaconVideoWidget *bvw,
+                 TotemObject      *totem)
+{
+       bacon_video_widget_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);
+
+  //translate_coords (widget, event->window, event->x, event->y, &x, &y);
+#if 0
+  if (ignore_event (bvw, x, y)) {
+         /* Is the mouse on the popups? */
+         unschedule_hiding_popup (bvw);
+  } else {
+#endif
+         schedule_hiding_popup (totem);
+//  }
+
+  return GDK_EVENT_PROPAGATE;
+}
+
 static void
 update_fill (TotemObject *totem, gdouble level)
 {
@@ -2684,7 +2843,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");
+       bacon_video_widget_mark_popup_busy (totem, "seek started");
 
        return FALSE;
 }
@@ -2722,7 +2881,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");
+       bacon_video_widget_unmark_popup_busy (totem, "seek started");
 
        /* sync both adjustments */
        adj = gtk_range_get_adjustment (GTK_RANGE (widget));
@@ -3361,7 +3520,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);
+               totem_show_popup (totem);
                break;
        case GDK_KEY_C:
        case GDK_KEY_c:
@@ -3403,7 +3562,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);
+               totem_show_popup (totem);
                break;
        case GDK_KEY_OpenURL:
                totem_object_set_fullscreen (totem, FALSE);
@@ -3508,7 +3667,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);
+                               totem_show_popup (totem);
                        }
                } else {
                        if (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_Page_Down)
@@ -3519,7 +3678,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);
+               totem_show_popup (totem);
                break;
        case GDK_KEY_Up:
                if (bacon_video_widget_has_menus (totem->bvw) != FALSE)
@@ -3547,7 +3706,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);
+               totem_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)));
@@ -3557,7 +3716,7 @@ totem_object_handle_key_press (TotemObject *totem, GdkEventKey *event)
                }
                break;
        case GDK_KEY_Time:
-               bacon_video_widget_show_popup (totem->bvw);
+               totem_show_popup (totem);
                break;
        case GDK_KEY_equal:
                if (mask == GDK_CONTROL_MASK)
@@ -3571,7 +3730,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);
+                       totem_show_popup (totem);
                } else {
                        totem_object_set_zoom (totem, TRUE);
                }
@@ -3580,7 +3739,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);
+                       totem_show_popup (totem);
                } else {
                        totem_object_set_zoom (totem, FALSE);
                }
@@ -3616,14 +3775,6 @@ totem_object_handle_key_press (TotemObject *totem, GdkEventKey *event)
        return retval;
 }
 
-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);
-}
-
 gboolean
 window_key_press_event_cb (GtkWidget *win, GdkEventKey *event, TotemObject *totem)
 {
@@ -3839,9 +3990,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");
+               bacon_video_widget_mark_popup_busy (totem, "toolbar/go menu visible");
        else
-               bacon_video_widget_unmark_popup_busy (totem->bvw, "toolbar/go menu visible");
+               bacon_video_widget_unmark_popup_busy (totem, "toolbar/go menu visible");
 }
 
 static void
@@ -3850,9 +4001,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");
+               bacon_video_widget_mark_popup_busy (totem, "volume menu visible");
        else
-               bacon_video_widget_unmark_popup_busy (totem->bvw, "volume menu visible");
+               bacon_video_widget_unmark_popup_busy (totem, "volume menu visible");
 }
 
 static void
@@ -4215,13 +4366,17 @@ video_widget_create (TotemObject *totem)
                        G_CALLBACK (on_error_event),
                        totem);
        g_signal_connect (G_OBJECT (totem->bvw),
-                         "track-skip-requested",
-                         G_CALLBACK (on_track_skip_requested_event),
+                         "play-starting",
+                         G_CALLBACK (play_starting_cb),
                          totem);
        g_signal_connect (G_OBJECT (totem->bvw),
                          "scroll-event",
                          G_CALLBACK (seek_slider_scroll_event_cb),
                          totem);
+       g_signal_connect (G_OBJECT (totem->bvw),
+                         "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,
diff --git a/src/totem-private.h b/src/totem-private.h
index 867ba3757..802976c5e 100644
--- a/src/totem-private.h
+++ b/src/totem-private.h
@@ -115,6 +115,10 @@ 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;
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]