[gnome-software/1843-gs-screenshot-support-videos-as-screenshot] gs-screenshot-image: Show also 'video' screenshots



commit bea2adf8d86bc83348b586f71d1a63e7edad5a1b
Author: Milan Crha <mcrha redhat com>
Date:   Tue Aug 9 15:55:09 2022 +0200

    gs-screenshot-image: Show also 'video' screenshots
    
    This allows to show also video screenshots, not only static images.
    
    Closes https://gitlab.gnome.org/GNOME/gnome-software/-/merge_requests/1451

 src/gs-screenshot-image.c  | 190 +++++++++++++++++++++++++++++++++------------
 src/gs-screenshot-image.ui |  13 ++++
 2 files changed, 153 insertions(+), 50 deletions(-)
---
diff --git a/src/gs-screenshot-image.c b/src/gs-screenshot-image.c
index 946ab0984..2a36ae403 100644
--- a/src/gs-screenshot-image.c
+++ b/src/gs-screenshot-image.c
@@ -27,13 +27,12 @@ struct _GsScreenshotImage
        GtkWidget       *box_error;
        GtkWidget       *image1;
        GtkWidget       *image2;
+       GtkWidget       *video;
        GtkWidget       *label_error;
        GSettings       *settings;
        SoupSession     *session;
        SoupMessage     *message;
-#if SOUP_CHECK_VERSION(3, 0, 0)
        GCancellable    *cancellable;
-#endif
        gchar           *filename;
        const gchar     *current_image;
        guint            width;
@@ -104,32 +103,38 @@ gs_screenshot_image_set_error (GsScreenshotImage *ssimg, const gchar *message)
 static void
 as_screenshot_show_image (GsScreenshotImage *ssimg)
 {
-       g_autoptr(GdkPixbuf) pixbuf = NULL;
-
-       /* no need to composite */
-       if (ssimg->width == G_MAXUINT || ssimg->height == G_MAXUINT) {
-               pixbuf = gdk_pixbuf_new_from_file (ssimg->filename, NULL);
+       if (as_screenshot_get_media_kind (ssimg->screenshot) == AS_SCREENSHOT_MEDIA_KIND_VIDEO) {
+               gtk_video_set_filename (GTK_VIDEO (ssimg->video), ssimg->filename);
+               ssimg->current_image = "video";
+               gtk_stack_set_visible_child_name (GTK_STACK (ssimg->stack), ssimg->current_image);
        } else {
-               /* this is always going to have alpha */
-               pixbuf = gdk_pixbuf_new_from_file_at_scale (ssimg->filename,
-                                                           (gint) (ssimg->width * ssimg->scale),
-                                                           (gint) (ssimg->height * ssimg->scale),
-                                                           FALSE, NULL);
-       }
-
-       /* show icon */
-       if (g_strcmp0 (ssimg->current_image, "image1") == 0) {
-               if (pixbuf != NULL) {
-                       gtk_picture_set_pixbuf (GTK_PICTURE (ssimg->image2), pixbuf);
+               g_autoptr(GdkPixbuf) pixbuf = NULL;
+
+               /* no need to composite */
+               if (ssimg->width == G_MAXUINT || ssimg->height == G_MAXUINT) {
+                       pixbuf = gdk_pixbuf_new_from_file (ssimg->filename, NULL);
+               } else {
+                       /* this is always going to have alpha */
+                       pixbuf = gdk_pixbuf_new_from_file_at_scale (ssimg->filename,
+                                                                   (gint) (ssimg->width * ssimg->scale),
+                                                                   (gint) (ssimg->height * ssimg->scale),
+                                                                   FALSE, NULL);
                }
-               gtk_stack_set_visible_child_name (GTK_STACK (ssimg->stack), "image2");
-               ssimg->current_image = "image2";
-       } else {
-               if (pixbuf != NULL) {
-                       gtk_picture_set_pixbuf (GTK_PICTURE (ssimg->image1), pixbuf);
+
+               /* show icon */
+               if (g_strcmp0 (ssimg->current_image, "image1") == 0) {
+                       if (pixbuf != NULL) {
+                               gtk_picture_set_pixbuf (GTK_PICTURE (ssimg->image2), pixbuf);
+                       }
+                       gtk_stack_set_visible_child_name (GTK_STACK (ssimg->stack), "image2");
+                       ssimg->current_image = "image2";
+               } else {
+                       if (pixbuf != NULL) {
+                               gtk_picture_set_pixbuf (GTK_PICTURE (ssimg->image1), pixbuf);
+                       }
+                       gtk_stack_set_visible_child_name (GTK_STACK (ssimg->stack), "image1");
+                       ssimg->current_image = "image1";
                }
-               gtk_stack_set_visible_child_name (GTK_STACK (ssimg->stack), "image1");
-               ssimg->current_image = "image1";
        }
 
        gtk_widget_show (GTK_WIDGET (ssimg));
@@ -243,6 +248,11 @@ gs_screenshot_image_show_blurred (GsScreenshotImage *ssimg,
        if (pb == NULL)
                return;
 
+       if (g_strcmp0 (ssimg->current_image, "video") == 0) {
+               ssimg->current_image = "image1";
+               gtk_stack_set_visible_child_name (GTK_STACK (ssimg->stack), ssimg->current_image);
+       }
+
        if (g_strcmp0 (ssimg->current_image, "image1") == 0) {
                gtk_picture_set_pixbuf (GTK_PICTURE (ssimg->image1), pb);
        } else {
@@ -542,11 +552,84 @@ gs_screenshot_show_spinner_cb (gpointer user_data)
        return FALSE;
 }
 
+static const gchar *
+gs_screenshot_image_get_url (GsScreenshotImage *ssimg)
+{
+       const gchar *url = NULL;
+
+       /* load an image according to the scale factor */
+       ssimg->scale = (guint) gtk_widget_get_scale_factor (GTK_WIDGET (ssimg));
+
+       if (as_screenshot_get_media_kind (ssimg->screenshot) == AS_SCREENSHOT_MEDIA_KIND_VIDEO) {
+               GPtrArray *videos;
+               AsVideo *best_video = NULL;
+               gint64 best_size = G_MAXINT64;
+               gint64 wh = (gint64) ssimg->width * ssimg->scale * ssimg->height * ssimg->scale;
+
+               videos = as_screenshot_get_videos (ssimg->screenshot);
+               for (guint i = 0; videos != NULL && i < videos->len; i++) {
+                       AsVideo *adept = g_ptr_array_index (videos, i);
+                       gint64 tmp;
+
+                       tmp = ABS (wh - (gint64) (as_video_get_width (adept) * as_video_get_height (adept)));
+                       if (tmp < best_size) {
+                               best_size = tmp;
+                               best_video = adept;
+                               if (!tmp)
+                                       break;
+                       }
+               }
+
+               if (best_video)
+                       url = as_video_get_url (best_video);
+       } else if (as_screenshot_get_media_kind (ssimg->screenshot) == AS_SCREENSHOT_MEDIA_KIND_IMAGE) {
+               AsImage *im;
+
+               im = as_screenshot_get_image (ssimg->screenshot,
+                                             ssimg->width * ssimg->scale,
+                                             ssimg->height * ssimg->scale);
+
+               /* if we've failed to load a HiDPI image, fallback to LoDPI */
+               if (im == NULL && ssimg->scale > 1) {
+                       ssimg->scale = 1;
+                       im = as_screenshot_get_image (ssimg->screenshot,
+                                                     ssimg->width,
+                                                     ssimg->height);
+               }
+
+               if (im)
+                       url = as_image_get_url (im);
+       }
+
+       return url;
+}
+
+static void
+gs_screenshot_video_downloaded_cb (GObject *source_object,
+                                  GAsyncResult *result,
+                                  gpointer user_data)
+{
+       g_autoptr(GsScreenshotImage) ssimg = user_data;
+       g_autoptr(GError) error = NULL;
+
+       if (gs_download_file_finish (ssimg->session, result, &error)) {
+               gs_screenshot_image_stop_spinner (ssimg);
+               as_screenshot_show_image (ssimg);
+
+               g_clear_object (&ssimg->cancellable);
+       } else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+               g_debug ("Failed to download screenshot video: %s", error->message);
+               /* Reset the width request, thus the image shrinks when the window width is small */
+               gtk_widget_set_size_request (ssimg->stack, -1, (gint) ssimg->height);
+               gs_screenshot_image_stop_spinner (ssimg);
+               gs_screenshot_image_set_error (ssimg, _("Screenshot not found"));
+       }
+}
+
 void
 gs_screenshot_image_load_async (GsScreenshotImage *ssimg,
                                GCancellable *cancellable)
 {
-       AsImage *im = NULL;
        const gchar *url;
        g_autofree gchar *basename = NULL;
        g_autofree gchar *cache_kind = NULL;
@@ -563,20 +646,8 @@ gs_screenshot_image_load_async (GsScreenshotImage *ssimg,
        /* Reset the width request, thus the image shrinks when the window width is small */
        gtk_widget_set_size_request (ssimg->stack, -1, (gint) ssimg->height);
 
-       /* load an image according to the scale factor */
-       ssimg->scale = (guint) gtk_widget_get_scale_factor (GTK_WIDGET (ssimg));
-       im = as_screenshot_get_image (ssimg->screenshot,
-                                     ssimg->width * ssimg->scale,
-                                     ssimg->height * ssimg->scale);
-
-       /* if we've failed to load a HiDPI image, fallback to LoDPI */
-       if (im == NULL && ssimg->scale > 1) {
-               ssimg->scale = 1;
-               im = as_screenshot_get_image (ssimg->screenshot,
-                                             ssimg->width,
-                                             ssimg->height);
-       }
-       if (im == NULL) {
+       url = gs_screenshot_image_get_url (ssimg);
+       if (url == NULL) {
                /* TRANSLATORS: this is when we request a screenshot size that
                 * the generator did not create or the parser did not add */
                gs_screenshot_image_set_error (ssimg, _("Screenshot size not found"));
@@ -584,7 +655,6 @@ gs_screenshot_image_load_async (GsScreenshotImage *ssimg,
        }
 
        /* check if the URL points to a local file */
-       url = as_image_get_url (im);
        if (g_str_has_prefix (url, "file://")) {
                g_free (ssimg->filename);
                ssimg->filename = g_strdup (url + 7);
@@ -629,11 +699,13 @@ gs_screenshot_image_load_async (GsScreenshotImage *ssimg,
        /* if we're not showing a full-size image, we try loading a blurred
         * smaller version of it straight away */
        if (!ssimg->showing_image &&
+           as_screenshot_get_media_kind (ssimg->screenshot) == AS_SCREENSHOT_MEDIA_KIND_IMAGE &&
            ssimg->width > AS_IMAGE_THUMBNAIL_WIDTH &&
            ssimg->height > AS_IMAGE_THUMBNAIL_HEIGHT) {
                const gchar *url_thumb;
                g_autofree gchar *basename_thumb = NULL;
                g_autofree gchar *cache_kind_thumb = NULL;
+               AsImage *im;
                im = as_screenshot_get_image (ssimg->screenshot,
                                              AS_IMAGE_THUMBNAIL_WIDTH * ssimg->scale,
                                              AS_IMAGE_THUMBNAIL_HEIGHT * ssimg->scale);
@@ -684,11 +756,13 @@ gs_screenshot_image_load_async (GsScreenshotImage *ssimg,
        }
 
        /* cancel any previous messages */
-       if (ssimg->message != NULL) {
-#if SOUP_CHECK_VERSION(3, 0, 0)
+       if (ssimg->cancellable != NULL) {
                g_cancellable_cancel (ssimg->cancellable);
                g_clear_object (&ssimg->cancellable);
-#else
+       }
+
+       if (ssimg->message != NULL) {
+#if !SOUP_CHECK_VERSION(3, 0, 0)
                soup_session_cancel_message (ssimg->session,
                                             ssimg->message,
                                             SOUP_STATUS_CANCELLED);
@@ -696,6 +770,22 @@ gs_screenshot_image_load_async (GsScreenshotImage *ssimg,
                g_clear_object (&ssimg->message);
        }
 
+       if (as_screenshot_get_media_kind (ssimg->screenshot) == AS_SCREENSHOT_MEDIA_KIND_VIDEO) {
+               g_autofree gchar *uri_str = g_uri_to_string (base_uri);
+               g_autoptr(GFile) output_file = NULL;
+
+               ssimg->cancellable = g_cancellable_new ();
+               output_file = g_file_new_for_path (ssimg->filename);
+
+               /* Make sure the spinner takes approximately the size the screenshot will use */
+               gtk_widget_set_size_request (ssimg->stack, (gint) ssimg->width, (gint) ssimg->height);
+
+               gs_download_file_async (ssimg->session, uri_str, output_file, G_PRIORITY_DEFAULT, NULL, NULL,
+                                       ssimg->cancellable, gs_screenshot_video_downloaded_cb, g_object_ref 
(ssimg));
+
+               return;
+       }
+
 #if SOUP_CHECK_VERSION(3, 0, 0)
        ssimg->message = soup_message_new_from_uri (SOUP_METHOD_GET, base_uri);
 #else
@@ -717,9 +807,6 @@ gs_screenshot_image_load_async (GsScreenshotImage *ssimg,
                gs_screenshot_soup_msg_set_modified_request (ssimg->message, file);
        }
 
-       /* Make sure the spinner takes approximately the size the screenshot will use */
-       gtk_widget_set_size_request (ssimg->stack, (gint) ssimg->width, (gint) ssimg->height);
-
        ssimg->load_timeout_id = g_timeout_add_seconds (SPINNER_TIMEOUT_SECS,
                gs_screenshot_show_spinner_cb, ssimg);
 
@@ -764,11 +851,13 @@ gs_screenshot_image_dispose (GObject *object)
                ssimg->load_timeout_id = 0;
        }
 
-       if (ssimg->message != NULL) {
-#if SOUP_CHECK_VERSION(3, 0, 0)
+       if (ssimg->cancellable != NULL) {
                g_cancellable_cancel (ssimg->cancellable);
                g_clear_object (&ssimg->cancellable);
-#else
+       }
+
+       if (ssimg->message != NULL) {
+#if !SOUP_CHECK_VERSION(3, 0, 0)
                soup_session_cancel_message (ssimg->session,
                                             ssimg->message,
                                             SOUP_STATUS_CANCELLED);
@@ -836,6 +925,7 @@ gs_screenshot_image_class_init (GsScreenshotImageClass *klass)
        gtk_widget_class_bind_template_child (widget_class, GsScreenshotImage, stack);
        gtk_widget_class_bind_template_child (widget_class, GsScreenshotImage, image1);
        gtk_widget_class_bind_template_child (widget_class, GsScreenshotImage, image2);
+       gtk_widget_class_bind_template_child (widget_class, GsScreenshotImage, video);
        gtk_widget_class_bind_template_child (widget_class, GsScreenshotImage, box_error);
        gtk_widget_class_bind_template_child (widget_class, GsScreenshotImage, label_error);
 
diff --git a/src/gs-screenshot-image.ui b/src/gs-screenshot-image.ui
index 2606be51d..a108ba77e 100644
--- a/src/gs-screenshot-image.ui
+++ b/src/gs-screenshot-image.ui
@@ -55,6 +55,19 @@
               </object>
             </child>
 
+            <child>
+              <object class="GtkStackPage">
+                <property name="name">video</property>
+                <property name="child">
+                  <object class="GtkVideo" id="video">
+                    <style>
+                      <class name="video"/>
+                    </style>
+                  </object>
+                </property>
+              </object>
+            </child>
+
             <child>
               <object class="GtkStackPage">
                 <property name="name">error</property>


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