[totem] missing plugins: Ask the user before spawning a plugin search



commit dd42ebd45cf39bbdd8b1d5dd0fb0682c00d46b41
Author: Kalev Lember <kalevlember gmail com>
Date:   Fri Feb 13 16:30:13 2015 +0100

    missing plugins: Ask the user before spawning a plugin search
    
    Previously, the PackageKit session service implementation would use
    Totem's window xid to attach its own dialogs. This however no longer
    works in Wayland world.
    
    Instead of attaching a dialog to Totem's window, gnome-software by
    default now pops up a Shell notification asking for confirmation before
    launching the codec search. This is however just a fallback and the
    preferred way is for an app to pop up its own dialog / in-app
    notification before starting the codec installation.
    
    This commit implements the confirmation dialog within Totem and passes
    down necessary flags to supress the Shell notification in that case.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=744610

 .../bacon-video-widget-gst-missing-plugins.c       |  156 +++++++++++++++++++-
 src/backend/bacon-video-widget.c                   |   14 ++
 2 files changed, 164 insertions(+), 6 deletions(-)
---
diff --git a/src/backend/bacon-video-widget-gst-missing-plugins.c 
b/src/backend/bacon-video-widget-gst-missing-plugins.c
index 6ceead3..c717566 100644
--- a/src/backend/bacon-video-widget-gst-missing-plugins.c
+++ b/src/backend/bacon-video-widget-gst-missing-plugins.c
@@ -34,6 +34,8 @@
 #include <gst/pbutils/pbutils.h>
 #include <gst/pbutils/install-plugins.h>
 
+#include <gio/gdesktopappinfo.h>
+#include <glib/gi18n.h>
 #include <gtk/gtk.h>
 
 #ifdef GDK_WINDOWING_X11
@@ -236,8 +238,25 @@ on_plugin_installation_done (GstInstallPluginsReturn res, gpointer user_data)
        bacon_video_widget_gst_codec_install_context_free (ctx);
 }
 
+#ifdef GDK_WINDOWING_X11
+#if GST_CHECK_VERSION (1, 5, 0)
+static gchar *
+set_startup_notification_id (GstInstallPluginsContext *install_ctx)
+{
+       gchar *startup_id;
+       guint32 timestamp;
+
+       timestamp = gtk_get_current_event_time ();
+       startup_id = g_strdup_printf ("_TIME%u", timestamp);
+       gst_install_plugins_context_set_startup_notification_id (install_ctx, startup_id);
+       g_free (startup_id);
+}
+#endif
+#endif
+
 static gboolean
-bacon_video_widget_start_plugin_installation (TotemCodecInstallContext *ctx)
+bacon_video_widget_start_plugin_installation (TotemCodecInstallContext *ctx,
+                                              gboolean                  confirm_search)
 {
        GstInstallPluginsContext *install_ctx;
        GstInstallPluginsReturn status;
@@ -248,6 +267,7 @@ bacon_video_widget_start_plugin_installation (TotemCodecInstallContext *ctx)
        install_ctx = gst_install_plugins_context_new ();
 #if GST_CHECK_VERSION (1, 5, 0)
        gst_install_plugins_context_set_desktop_id (install_ctx, "org.gnome.Totem.desktop");
+       gst_install_plugins_context_set_confirm_search (install_ctx, confirm_search);
 #endif
 
 #ifdef GDK_WINDOWING_X11
@@ -259,6 +279,10 @@ bacon_video_widget_start_plugin_installation (TotemCodecInstallContext *ctx)
        {
                gulong xid = 0;
 
+#if GST_CHECK_VERSION (1, 5, 0)
+               set_startup_notification_id (install_ctx);
+#endif
+
                xid = bacon_video_widget_gst_get_toplevel (GTK_WIDGET (ctx->bvw));
                gst_install_plugins_context_set_xid (install_ctx, xid);
        }
@@ -289,10 +313,121 @@ bacon_video_widget_start_plugin_installation (TotemCodecInstallContext *ctx)
        return TRUE;
 }
 
+#if GST_CHECK_VERSION (1, 5, 0)
+static void
+codec_confirmation_dialog_response_cb (GtkDialog       *dialog,
+                                       GtkResponseType  response_type,
+                                       gpointer         user_data)
+{
+       TotemCodecInstallContext *ctx = user_data;
+
+       switch (response_type) {
+       case GTK_RESPONSE_ACCEPT:
+               bacon_video_widget_start_plugin_installation (ctx, FALSE);
+               break;
+       case GTK_RESPONSE_CANCEL:
+       case GTK_RESPONSE_DELETE_EVENT:
+               break;
+       default:
+               g_assert_not_reached ();
+       }
+       gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+static void
+show_codec_confirmation_dialog (TotemCodecInstallContext *ctx,
+                                const gchar              *install_helper_display_name)
+{
+       GtkWidget *button;
+       GtkWidget *dialog;
+       GtkWidget *toplevel;
+       gchar *button_text;
+       gchar *descriptions_text;
+       gchar *message_text;
+
+       toplevel = gtk_widget_get_toplevel (GTK_WIDGET (ctx->bvw));
+
+       dialog = gtk_message_dialog_new (GTK_WINDOW (toplevel),
+                                        GTK_DIALOG_MODAL |
+                                        GTK_DIALOG_DESTROY_WITH_PARENT,
+                                        GTK_MESSAGE_ERROR,
+                                        GTK_BUTTONS_CANCEL,
+                                        _("Unable to play the file"));
+
+       descriptions_text = g_strjoinv (", ", ctx->descriptions);
+       message_text = g_strdup_printf (ngettext ("%s is required to play the file, but is not installed.",
+                                                 "%s are required to play the file, but are not installed.",
+                                                 g_strv_length (ctx->descriptions)),
+                                       descriptions_text);
+
+       /* TRANSLATORS: this is a button to launch a codec installer.
+        * %s will be replaced with the software installer's name, e.g.
+        * 'Software' in case of gnome-software. */
+       button_text = g_strdup_printf ("_Find in %s", install_helper_display_name);
+       gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", message_text);
+       button = gtk_dialog_add_button (GTK_DIALOG (dialog),
+                                       button_text,
+                                       GTK_RESPONSE_ACCEPT);
+       gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
+       gtk_style_context_add_class (gtk_widget_get_style_context (button), "suggested-action");
+       g_signal_connect (dialog, "response",
+                         G_CALLBACK (codec_confirmation_dialog_response_cb),
+                         ctx);
+
+       gtk_window_present (GTK_WINDOW (dialog));
+
+       g_free (button_text);
+       g_free (descriptions_text);
+       g_free (message_text);
+}
+#endif
+
+static void
+on_packagekit_proxy_ready (GObject      *source_object,
+                           GAsyncResult *res,
+                           gpointer      user_data)
+{
+       TotemCodecInstallContext *ctx = (TotemCodecInstallContext *) user_data;
+       GDBusProxy *packagekit_proxy = NULL;
+       GVariant *property = NULL;
+       GError *error = NULL;
+
+       packagekit_proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
+       if (packagekit_proxy == NULL &&
+           g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+               goto out;
+       }
+
+#if GST_CHECK_VERSION (1, 5, 0)
+       if (packagekit_proxy != NULL) {
+               property = g_dbus_proxy_get_cached_property (packagekit_proxy, "DisplayName");
+               if (property != NULL) {
+                       const gchar *display_name;
+
+                       display_name = g_variant_get_string (property, NULL);
+                       if (display_name != NULL && display_name[0] != '\0') {
+                               show_codec_confirmation_dialog (ctx, display_name);
+                               goto out;
+                       }
+               }
+       }
+#endif
+
+       /* If the above failed, fall back to immediately starting the codec installation */
+       bacon_video_widget_start_plugin_installation (ctx, TRUE);
+
+out:
+       g_clear_error (&error);
+       g_clear_pointer (&property, g_variant_unref);
+       g_clear_object (&packagekit_proxy);
+}
+
 static gboolean
-bacon_video_widget_gst_on_missing_plugins_event (BaconVideoWidget *bvw, char **details,
-                                                char **descriptions, gboolean playing,
-                                                gpointer user_data)
+bacon_video_widget_gst_on_missing_plugins_event (BaconVideoWidget  *bvw,
+                                                 char             **details,
+                                                 char             **descriptions,
+                                                 gboolean           playing,
+                                                 gpointer           user_data)
 {
        TotemCodecInstallContext *ctx;
        guint i, num;
@@ -331,8 +466,17 @@ bacon_video_widget_gst_on_missing_plugins_event (BaconVideoWidget *bvw, char **d
                return FALSE;
        }
 
-       if (!bacon_video_widget_start_plugin_installation (ctx))
-               return FALSE;
+       /* Get the PackageKit session interface proxy and continue with the
+        * codec installation in the callback */
+       g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
+                                 G_DBUS_PROXY_FLAGS_NONE,
+                                 NULL, /* g-interface-info */
+                                 "org.freedesktop.PackageKit",
+                                 "/org/freedesktop/PackageKit",
+                                 "org.freedesktop.PackageKit.Modify2",
+                                 g_object_get_data (G_OBJECT (bvw), "missing-plugins-cancellable"),
+                                 on_packagekit_proxy_ready,
+                                 ctx);
 
        /* if we managed to start playing, pause playback, since some install
         * wizard should now take over in a second anyway and the user might not
diff --git a/src/backend/bacon-video-widget.c b/src/backend/bacon-video-widget.c
index e757d0c..3e1f7b8 100644
--- a/src/backend/bacon-video-widget.c
+++ b/src/backend/bacon-video-widget.c
@@ -269,6 +269,7 @@ struct BaconVideoWidgetPrivate
   /* for easy codec installation */
   GList                       *missing_plugins;   /* GList of GstMessages */
   gboolean                     plugin_install_in_progress;
+  GCancellable                *missing_plugins_cancellable;
 
   /* for mounting locations if necessary */
   GCancellable                *mount_cancellable;
@@ -639,10 +640,22 @@ bacon_video_widget_realize (GtkWidget * widget)
   g_signal_connect (G_OBJECT (toplevel), "leave-notify-event",
                    G_CALLBACK (leave_notify_cb), bvw);
 
+  bvw->priv->missing_plugins_cancellable = g_cancellable_new ();
+  g_object_set_data (G_OBJECT (bvw), "missing-plugins-cancellable",
+                    bvw->priv->missing_plugins_cancellable);
   bacon_video_widget_gst_missing_plugins_setup (bvw);
 }
 
 static void
+bacon_video_widget_unrealize (GtkWidget *widget)
+{
+  BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
+
+  g_cancellable_cancel (bvw->priv->missing_plugins_cancellable);
+  g_clear_object (&bvw->priv->missing_plugins_cancellable);
+}
+
+static void
 size_changed_cb (GdkScreen *screen, BaconVideoWidget *bvw)
 {
   bvw_check_for_cover_pixbuf (bvw);
@@ -1022,6 +1035,7 @@ bacon_video_widget_class_init (BaconVideoWidgetClass * klass)
   widget_class->get_preferred_width = bacon_video_widget_get_preferred_width;
   widget_class->get_preferred_height = bacon_video_widget_get_preferred_height;
   widget_class->realize = bacon_video_widget_realize;
+  widget_class->unrealize = bacon_video_widget_unrealize;
 
   widget_class->motion_notify_event = bacon_video_widget_motion_notify;
   widget_class->button_press_event = bacon_video_widget_button_press_or_release;


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