[totem] backend: Rework popup visibility



commit cc880bfbccfc7edfe0ed4aa8235ee29035733a71
Author: Bastien Nocera <hadess hadess net>
Date:   Tue Feb 4 09:56:55 2014 +0100

    backend: Rework popup visibility
    
    When using the mouse, show the popup on motion, and hide it
    after 3 seconds (unless it's on our popup).
    When using a touchscreen, show/hide the popup on tap.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=697897

 src/backend/bacon-video-widget.c |  134 +++++++++++++++++++++++++++++--------
 src/backend/bacon-video-widget.h |    1 +
 2 files changed, 106 insertions(+), 29 deletions(-)
---
diff --git a/src/backend/bacon-video-widget.c b/src/backend/bacon-video-widget.c
index bbe8eae..9a92fd3 100644
--- a/src/backend/bacon-video-widget.c
+++ b/src/backend/bacon-video-widget.c
@@ -100,6 +100,7 @@
 #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 5
 
 #define MAX_NETWORK_SPEED 10752
 #define BUFFERING_LEFT_RATIO 1.1
@@ -162,7 +163,8 @@ enum
   PROP_HUE,
   PROP_AUDIO_OUTPUT_TYPE,
   PROP_AV_OFFSET,
-  PROP_SHOW_CURSOR
+  PROP_SHOW_CURSOR,
+  PROP_REVEAL_CONTROLS
 };
 
 static const gchar *video_props_str[4] = {
@@ -219,6 +221,10 @@ struct BaconVideoWidgetPrivate
 
   GdkCursor                   *cursor;
 
+  /* Controls */
+  gboolean                     reveal_controls;
+  guint                        transition_timeout_id;
+
   /* Visual effects */
   GList                       *vis_plugins_list;
   GHashTable                  *vis_plugins_ht;
@@ -315,7 +321,8 @@ static gboolean bacon_video_widget_seek_time_no_lock (BaconVideoWidget *bvw,
                                                      GstSeekFlags flag,
                                                      GError **error);
 static void set_controls_visibility (BaconVideoWidget *bvw,
-                                    gboolean          visible);
+                                    gboolean          visible,
+                                    gboolean          animate);
 
 typedef struct {
   GstTagList *tags;
@@ -627,7 +634,6 @@ bacon_video_widget_realize (GtkWidget * widget)
     gtk_window_set_geometry_hints (GTK_WINDOW (toplevel), widget, NULL, 0);
   } else {
     bvw->priv->embedded = TRUE;
-    set_controls_visibility (bvw, FALSE);
   }
 
   bacon_video_widget_gst_missing_plugins_setup (bvw);
@@ -683,48 +689,48 @@ set_current_actor (BaconVideoWidget *bvw)
   clutter_actor_hide (CLUTTER_ACTOR (bvw->priv->logo_frame));
 }
 
-/* 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 */
+static void
+unschedule_hiding_popup (BaconVideoWidget *bvw)
+{
+  if (bvw->priv->transition_timeout_id > 0)
+    g_source_remove (bvw->priv->transition_timeout_id);
+  bvw->priv->transition_timeout_id = 0;
+}
 
 static gboolean
-bacon_video_widget_motion_notify (GtkWidget *widget, GdkEventMotion *event)
+hide_popup_timeout_cb (BaconVideoWidget *bvw)
 {
-  gboolean res = FALSE;
-  BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
-
-  g_return_val_if_fail (bvw->priv->play != NULL, FALSE);
-
-  if (bvw->priv->navigation && !bvw->priv->logo_mode)
-    gst_navigation_send_mouse_event (bvw->priv->navigation, "mouse-move", 0, event->x, event->y);
-
-  if (GTK_WIDGET_CLASS (parent_class)->motion_notify_event)
-    res |= GTK_WIDGET_CLASS (parent_class)->motion_notify_event (widget, event);
+  set_controls_visibility (bvw, FALSE, TRUE);
+  unschedule_hiding_popup (bvw);
+  return G_SOURCE_REMOVE;
+}
 
-  return res;
+static void
+schedule_hiding_popup (BaconVideoWidget *bvw)
+{
+  unschedule_hiding_popup (bvw);
+  bvw->priv->transition_timeout_id = g_timeout_add_seconds (POPUP_HIDING_TIMEOUT, (GSourceFunc) 
hide_popup_timeout_cb, bvw);
 }
 
 static void
 set_controls_visibility (BaconVideoWidget *bvw,
-                        gboolean          visible)
+                        gboolean          visible,
+                        gboolean          animate)
 {
   guint8 opacity = visible ? OVERLAY_OPACITY : 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->priv->controls, animate ? 250 : 0);
   clutter_actor_set_opacity (bvw->priv->controls, opacity);
-}
 
-static void
-toggle_controls (BaconVideoWidget *bvw)
-{
-  gboolean value = TRUE;
+  bacon_video_widget_set_show_cursor (bvw, visible);
+  if (animate)
+    schedule_hiding_popup (bvw);
 
-  if (clutter_actor_get_opacity (bvw->priv->controls) != 0)
-    value = FALSE;
-  set_controls_visibility (bvw, value);
-  bacon_video_widget_set_show_cursor (bvw, value);
+  bvw->priv->reveal_controls = visible;
+  g_object_notify (G_OBJECT (bvw), "reveal-controls");
 }
 
 static void
@@ -762,6 +768,45 @@ ignore_event (BaconVideoWidget *bvw,
   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 */
+
+static gboolean
+bacon_video_widget_motion_notify (GtkWidget *widget, GdkEventMotion *event)
+{
+  gboolean res = FALSE;
+  BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
+  GdkDevice *device;
+  int x, y;
+
+  g_return_val_if_fail (bvw->priv->play != NULL, FALSE);
+
+  if (bvw->priv->navigation && !bvw->priv->logo_mode)
+    gst_navigation_send_mouse_event (bvw->priv->navigation, "mouse-move", 0, event->x, event->y);
+
+  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->priv->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;
+}
+
 static gboolean
 bacon_video_widget_button_press_or_release (GtkWidget *widget, GdkEventButton *event)
 {
@@ -792,7 +837,11 @@ bacon_video_widget_button_press_or_release (GtkWidget *widget, GdkEventButton *e
      * the button press
      res = TRUE; */
   } else if (event->type == GDK_BUTTON_RELEASE) {
-    toggle_controls (bvw);
+    gboolean value = TRUE;
+
+    if (clutter_actor_get_opacity (bvw->priv->controls) != 0)
+      value = FALSE;
+    set_controls_visibility (bvw, value, FALSE);
   }
 
 bail:
@@ -1110,6 +1159,17 @@ bacon_video_widget_class_init (BaconVideoWidgetClass * klass)
                                                          G_PARAM_READWRITE |
                                                          G_PARAM_STATIC_STRINGS));
 
+  /**
+   * BaconVideoWidget:reveal-controls:
+   *
+   * Whether to show or hide the controls.
+   **/
+  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_PARAM_STATIC_STRINGS));
+
   /* Signals */
   /**
    * BaconVideoWidget::error:
@@ -2722,6 +2782,8 @@ 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->priv->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) */
@@ -2903,6 +2965,9 @@ bacon_video_widget_get_property (GObject * object, guint property_id,
     case PROP_SHOW_CURSOR:
       g_value_set_boolean (value, bvw->priv->cursor_shown);
       break;
+    case PROP_REVEAL_CONTROLS:
+      g_value_set_boolean (value, bvw->priv->reveal_controls);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -3486,6 +3551,15 @@ bacon_video_widget_popup_osd (BaconVideoWidget *bvw,
   bacon_video_osd_actor_show_and_fade (BACON_VIDEO_OSD_ACTOR (bvw->priv->osd));
 }
 
+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);
+}
+
 GObject *
 bacon_video_widget_get_controls_object (BaconVideoWidget *bvw)
 {
@@ -6184,6 +6258,8 @@ bacon_video_widget_initable_init (GInitable     *initable,
                                         layout,
                                         bvw->priv->logo_frame);
 
+  clutter_actor_set_opacity (bvw->priv->controls, 0);
+
   /* And tell playbin */
   g_object_set (bvw->priv->play, "video-sink", video_sink, NULL);
 
diff --git a/src/backend/bacon-video-widget.h b/src/backend/bacon-video-widget.h
index 8ae53e1..c4679f8 100644
--- a/src/backend/bacon-video-widget.h
+++ b/src/backend/bacon-video-widget.h
@@ -455,6 +455,7 @@ 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_popup_osd                 (BaconVideoWidget *bvw,
                                                   const char       *icon_name);
 


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