[xdg-desktop-portal-gnome/gbsneto/screencast-session-restore] WIP: Implement stream restoration




commit 74ea75d1a3d3fccf9b087d511f2bba50e8e025fa
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Tue Sep 28 21:04:28 2021 -0300

    WIP: Implement stream restoration
    
    Still not fully ready, but this is enough to
    get going

 src/screencast.c        | 158 +++++++++++++++++++++++++++++++++++++++++++++---
 src/screencast.h        |   7 +++
 src/screencastdialog.c  |  25 ++++++--
 src/screencastdialog.h  |   3 +-
 src/screencastwidget.c  |  76 +++++++++++++++++++++++
 src/screencastwidget.h  |   6 ++
 src/screencastwidget.ui |   7 +++
 7 files changed, 269 insertions(+), 13 deletions(-)
---
diff --git a/src/screencast.c b/src/screencast.c
index 27d8946..a145abe 100644
--- a/src/screencast.c
+++ b/src/screencast.c
@@ -49,6 +49,9 @@ typedef struct _ScreenCastSession
 
   ScreenCastSelection select;
 
+  ScreenCastPersistMode persist_mode;
+  char **restore_data;
+
   GDBusMethodInvocation *start_invocation;
   ScreenCastDialogHandle *dialog_handle;
 } ScreenCastSession;
@@ -127,6 +130,8 @@ static void
 screen_cast_dialog_done (GtkWidget *widget,
                          int dialog_response,
                          GVariant *selections,
+                         GStrv restore_data,
+                         ScreenCastPersistMode persist_mode,
                          ScreenCastDialogHandle *dialog_handle)
 {
   int response;
@@ -151,8 +156,16 @@ screen_cast_dialog_done (GtkWidget *widget,
 
   if (response == 0)
     {
+      ScreenCastSession *session = dialog_handle->session;
       g_autoptr(GError) error = NULL;
 
+      if (session->persist_mode != SCREEN_CAST_PERSIST_MODE_NONE && restore_data)
+        {
+          g_clear_pointer (&session->restore_data, g_strfreev);
+          session->restore_data = g_strdupv (restore_data);
+          session->persist_mode = MIN (session->persist_mode, persist_mode);
+        }
+
       if (!start_session (dialog_handle->session, selections, &error))
         {
           g_warning ("Failed to start session: %s", error->message);
@@ -202,7 +215,8 @@ create_screen_cast_dialog (ScreenCastSession *session,
   g_object_ref_sink (fake_parent);
 
   dialog = GTK_WIDGET (screen_cast_dialog_new (request->app_id,
-                                               &session->select));
+                                               &session->select,
+                                               session->persist_mode));
   gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (fake_parent));
   gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
 
@@ -288,6 +302,8 @@ handle_select_sources (XdpImplScreenCast *object,
                        const char *arg_app_id,
                        GVariant *arg_options)
 {
+  g_autoptr(GVariant) restore_data = NULL;
+  ScreenCastSession *screen_cast_session;
   Session *session;
   int response;
   uint32_t types;
@@ -359,6 +375,25 @@ handle_select_sources (XdpImplScreenCast *object,
       response = 2;
     }
 
+  screen_cast_session = (ScreenCastSession *)session;
+  g_variant_lookup (arg_options, "persist_mode", "u", &screen_cast_session->persist_mode);
+  g_variant_lookup (arg_options, "restore_data", "v", &restore_data);
+
+  if (restore_data)
+    {
+      if (g_variant_check_format_string (restore_data, "^a&s", FALSE))
+        {
+          g_autofree gchar **restore_data_strv = NULL;
+
+          g_variant_get (restore_data,  "^a&s", &restore_data_strv);
+          screen_cast_session->restore_data = g_strdupv (restore_data_strv);
+        }
+      else
+        {
+          g_warning ("Cannot parse restore data, ignoring");
+        }
+    }
+
 out:
   g_variant_builder_init (&results_builder, G_VARIANT_TYPE_VARDICT);
   results = g_variant_builder_end (&results_builder);
@@ -386,6 +421,18 @@ start_done (ScreenCastSession *screen_cast_session)
                          "streams",
                          g_variant_builder_end (&streams_builder));
 
+  if (screen_cast_session->persist_mode != SCREEN_CAST_PERSIST_MODE_NONE &&
+      screen_cast_session->restore_data)
+    {
+      GVariant *restore_data =
+        g_variant_new_strv ((const char * const*)screen_cast_session->restore_data, -1);
+
+      g_variant_builder_add (&results_builder, "{sv}", "restore_data",
+                             g_variant_new_variant (restore_data));
+      g_variant_builder_add (&results_builder, "{sv}", "persist_mode",
+                             g_variant_new_uint32 (screen_cast_session->persist_mode));
+    }
+
   xdp_impl_screen_cast_complete_start (XDP_IMPL_SCREEN_CAST (impl),
                                        screen_cast_session->start_invocation, 0,
                                        g_variant_builder_end (&results_builder));
@@ -457,6 +504,95 @@ cancel_start_session (ScreenCastSession *screen_cast_session,
                                        g_variant_builder_end (&results_builder));
 }
 
+static Monitor *
+find_monitor_by_string (const char *monitor_string)
+{
+  DisplayStateTracker *display_state_tracker = display_state_tracker_get ();
+  GList *logical_monitors;
+
+  for (logical_monitors = display_state_tracker_get_logical_monitors (display_state_tracker);
+       logical_monitors;
+       logical_monitors = logical_monitors->next)
+    {
+      LogicalMonitor *logical_monitor = logical_monitors->data;
+      GList *monitors;
+
+      for (monitors = logical_monitor_get_monitors (logical_monitor);
+           monitors;
+           monitors = monitors->next)
+        {
+          Monitor *monitor = monitors->data;
+
+          if (g_strcmp0 (monitor_get_match_string (monitor), monitor_string) == 0)
+            return monitor;
+        }
+    }
+
+  return NULL;
+}
+
+static gboolean
+restore_stream_from_data (ScreenCastSession *screen_cast_session)
+
+{
+  g_autoptr(GError) error = NULL;
+  GVariantBuilder selections_builder;
+  GVariantBuilder sources_builder;
+  gsize i;
+
+  if (!screen_cast_session->restore_data)
+    return FALSE;
+
+  g_variant_builder_init (&sources_builder, G_VARIANT_TYPE ("a(u?)"));
+  for (i = 0; screen_cast_session->restore_data[i] != NULL; i++)
+    {
+      const char *to_restore = screen_cast_session->restore_data[i];
+
+      if (g_str_has_prefix (to_restore, "monitor::"))
+        {
+          Monitor *monitor = find_monitor_by_string (to_restore + strlen ("monitor::"));
+
+          if (!monitor)
+            goto fail;
+
+          g_variant_builder_add (&sources_builder, "(us)",
+                                 SCREEN_CAST_SOURCE_TYPE_MONITOR,
+                                 monitor_get_connector (monitor));
+        }
+      else if (g_str_has_prefix (to_restore, "window::"))
+        {
+          // TODO: find window
+          goto fail;
+        }
+      else
+        {
+          goto fail;
+        }
+    }
+
+  g_variant_builder_init (&selections_builder, G_VARIANT_TYPE ("a{sv}"));
+  g_variant_builder_add (&selections_builder, "{sv}",
+                         "selected_screen_cast_sources",
+                         g_variant_builder_end (&sources_builder));
+
+  start_session (screen_cast_session,
+                 g_variant_builder_end (&selections_builder),
+                 &error);
+
+  if (error)
+    {
+      g_warning ("Error restoring stream from session: %s", error->message);
+      return FALSE;
+    }
+
+  return TRUE;
+
+fail:
+  g_variant_builder_clear (&selections_builder);
+  g_variant_builder_clear (&sources_builder);
+  return FALSE;
+}
+
 static gboolean
 handle_start (XdpImplScreenCast *object,
               GDBusMethodInvocation *invocation,
@@ -469,7 +605,6 @@ handle_start (XdpImplScreenCast *object,
   const char *sender;
   g_autoptr(Request) request = NULL;
   ScreenCastSession *screen_cast_session;
-  ScreenCastDialogHandle *dialog_handle;
   GVariantBuilder results_builder;
 
   sender = g_dbus_method_invocation_get_sender (invocation);
@@ -491,14 +626,19 @@ handle_start (XdpImplScreenCast *object,
       goto err;
     }
 
-  dialog_handle = create_screen_cast_dialog (screen_cast_session,
-                                             invocation,
-                                             request,
-                                             arg_parent_window);
+  screen_cast_session->start_invocation = invocation;
+
+  if (!restore_stream_from_data (screen_cast_session))
+    {
+      ScreenCastDialogHandle *dialog_handle;
 
+      dialog_handle = create_screen_cast_dialog (screen_cast_session,
+                                                 invocation,
+                                                 request,
+                                                 arg_parent_window);
 
-  screen_cast_session->start_invocation = invocation;
-  screen_cast_session->dialog_handle = dialog_handle;
+      screen_cast_session->dialog_handle = dialog_handle;
+    }
 
   return TRUE;
 
@@ -622,6 +762,8 @@ screen_cast_session_finalize (GObject *object)
 static void
 screen_cast_session_init (ScreenCastSession *screen_cast_session)
 {
+  display_state_tracker_get ();
+  screen_cast_session->persist_mode = SCREEN_CAST_PERSIST_MODE_NONE;
 }
 
 static void
diff --git a/src/screencast.h b/src/screencast.h
index f5033b2..42b5a57 100644
--- a/src/screencast.h
+++ b/src/screencast.h
@@ -35,6 +35,13 @@ typedef enum _ScreenCastCursorMode
   SCREEN_CAST_CURSOR_MODE_METADATA = 4,
 } ScreenCastCursorMode;
 
+typedef enum _ScreenCastPersistMode
+{
+  SCREEN_CAST_PERSIST_MODE_NONE = 0,
+  SCREEN_CAST_PERSIST_MODE_TRANSIENT = 1,
+  SCREEN_CAST_PERSIST_MODE_PERSISTENT = 2,
+} ScreenCastPersistMode;
+
 typedef struct _ScreenCastSelection
 {
   gboolean multiple;
diff --git a/src/screencastdialog.c b/src/screencastdialog.c
index 306992d..1bfd841 100644
--- a/src/screencastdialog.c
+++ b/src/screencastdialog.c
@@ -55,8 +55,10 @@ static void
 button_clicked (GtkWidget *button,
                 ScreenCastDialog *dialog)
 {
+  ScreenCastPersistMode persist_mode;
   int response;
   GVariant *selections;
+  GStrv restore_data;
 
   gtk_widget_hide (GTK_WIDGET (dialog));
 
@@ -72,14 +74,25 @@ button_clicked (GtkWidget *button,
       screen_cast_widget_add_selections (screen_cast_widget,
                                          &selections_builder);
       selections = g_variant_builder_end (&selections_builder);
+
+      restore_data = screen_cast_widget_get_restore_data (screen_cast_widget,
+                                                          &persist_mode);
     }
   else
     {
       response = GTK_RESPONSE_CANCEL;
       selections = NULL;
+      restore_data = NULL;
+      persist_mode = SCREEN_CAST_PERSIST_MODE_NONE;
     }
 
-  g_signal_emit (dialog, signals[DONE], 0, response, selections);
+  g_signal_emit (dialog,
+                 signals[DONE],
+                 0,
+                 response,
+                 selections,
+                 restore_data,
+                 persist_mode);
 }
 
 static void
@@ -95,7 +108,8 @@ on_has_selection_changed (ScreenCastWidget *screen_cast_widget,
 
 ScreenCastDialog *
 screen_cast_dialog_new (const char *app_id,
-                        ScreenCastSelection *select)
+                        ScreenCastSelection *select,
+                        ScreenCastPersistMode persist_mode)
 {
   ScreenCastDialog *dialog;
   ScreenCastWidget *screen_cast_widget;
@@ -106,6 +120,7 @@ screen_cast_dialog_new (const char *app_id,
   screen_cast_widget_set_allow_multiple (screen_cast_widget, select->multiple);
   screen_cast_widget_set_source_types (screen_cast_widget,
                                        select->source_types);
+  screen_cast_widget_set_persist_mode (screen_cast_widget, persist_mode);
 
   return dialog;
 }
@@ -144,9 +159,11 @@ screen_cast_dialog_class_init (ScreenCastDialogClass *klass)
                                 0,
                                 NULL, NULL,
                                 NULL,
-                                G_TYPE_NONE, 2,
+                                G_TYPE_NONE, 4,
                                 G_TYPE_INT,
-                                G_TYPE_VARIANT);
+                                G_TYPE_VARIANT,
+                                G_TYPE_STRV,
+                                G_TYPE_INT);
 
   init_screen_cast_widget ();
 
diff --git a/src/screencastdialog.h b/src/screencastdialog.h
index 247d93b..f116dd3 100644
--- a/src/screencastdialog.h
+++ b/src/screencastdialog.h
@@ -27,4 +27,5 @@ G_DECLARE_FINAL_TYPE (ScreenCastDialog, screen_cast_dialog,
                       SCREEN_CAST, DIALOG, GtkWindow)
 
 ScreenCastDialog * screen_cast_dialog_new (const char *app_id,
-                                           ScreenCastSelection *select);
+                                           ScreenCastSelection *select,
+                                           ScreenCastPersistMode persist_mode);
diff --git a/src/screencastwidget.c b/src/screencastwidget.c
index cdd57dc..6374abb 100644
--- a/src/screencastwidget.c
+++ b/src/screencastwidget.c
@@ -51,6 +51,9 @@ struct _ScreenCastWidget
   GtkWidget *window_list;
   GtkWidget *window_list_scrolled;
 
+  GtkCheckButton *persist_check;
+  ScreenCastPersistMode persist_mode;
+
   DisplayStateTracker *display_state_tracker;
   gulong monitors_changed_handler_id;
 
@@ -472,6 +475,69 @@ screen_cast_widget_add_selections (ScreenCastWidget *widget,
     }
 }
 
+GStrv
+screen_cast_widget_get_restore_data (ScreenCastWidget      *widget,
+                                     ScreenCastPersistMode *out_persist_mode)
+{
+  GPtrArray *array;
+  GList *selected_monitor_rows;
+  GList *selected_window_rows;
+  GList *l;
+
+  if (widget->persist_mode == SCREEN_CAST_PERSIST_MODE_NONE ||
+      (widget->persist_mode == SCREEN_CAST_PERSIST_MODE_PERSISTENT &&
+       !gtk_check_button_get_active (widget->persist_check)))
+    {
+      *out_persist_mode = SCREEN_CAST_PERSIST_MODE_NONE;
+      return NULL;
+    }
+
+  selected_monitor_rows =
+    gtk_list_box_get_selected_rows (GTK_LIST_BOX (widget->monitor_list));
+  selected_window_rows =
+    gtk_list_box_get_selected_rows (GTK_LIST_BOX (widget->window_list));
+  if (!selected_monitor_rows && !selected_window_rows)
+    return NULL;
+
+  array = g_ptr_array_new ();
+
+  for (l = selected_monitor_rows; l; l = l->next)
+    {
+      GtkWidget *monitor_widget = gtk_list_box_row_get_child (l->data);
+      Monitor *monitor;
+
+      monitor = g_object_get_qdata (G_OBJECT (monitor_widget),
+                                    quark_monitor_widget_data);
+
+      g_message ("  Adding monitor %s to restore data", monitor_get_match_string (monitor));
+      g_ptr_array_add (array, g_strdup_printf ("monitor::%s", monitor_get_match_string (monitor)));
+    }
+  g_list_free (selected_monitor_rows);
+
+  // TODO: windows
+  /*
+  for (l = selected_window_rows; l; l = l->next)
+    {
+      GtkWidget *window_widget = gtk_list_box_row_get_child (l->data);
+      Window *window;
+
+      window = g_object_get_qdata (G_OBJECT (window_widget),
+                                    quark_window_widget_data);
+
+      g_variant_builder_add (source_selections_builder, "(ut)",
+                             SCREEN_CAST_SOURCE_TYPE_WINDOW,
+                             window_get_id (window));
+    }
+  g_list_free (selected_window_rows);
+   */
+
+  g_ptr_array_add (array, NULL);
+
+  *out_persist_mode = widget->persist_mode;
+
+  return (GStrv) g_ptr_array_free (array, FALSE);
+}
+
 void
 screen_cast_widget_set_app_id (ScreenCastWidget *widget,
                                const char *app_id)
@@ -532,6 +598,15 @@ screen_cast_widget_set_source_types (ScreenCastWidget *screen_cast_widget,
     gtk_widget_show (screen_cast_widget->source_type_switcher);
 }
 
+void
+screen_cast_widget_set_persist_mode (ScreenCastWidget      *screen_cast_widget,
+                                     ScreenCastPersistMode  persist_mode)
+{
+  screen_cast_widget->persist_mode = persist_mode;
+  gtk_widget_set_visible (GTK_WIDGET (screen_cast_widget->persist_check),
+                                      persist_mode == SCREEN_CAST_PERSIST_MODE_PERSISTENT);
+}
+
 static void
 screen_cast_widget_finalize (GObject *object)
 {
@@ -622,6 +697,7 @@ screen_cast_widget_class_init (ScreenCastWidgetClass *klass)
                                                  G_TYPE_BOOLEAN);
 
   gtk_widget_class_set_template_from_resource (widget_class, 
"/org/freedesktop/portal/desktop/gnome/screencastwidget.ui");
+  gtk_widget_class_bind_template_child (widget_class, ScreenCastWidget, persist_check);
   gtk_widget_class_bind_template_child (widget_class, ScreenCastWidget, source_type_switcher);
   gtk_widget_class_bind_template_child (widget_class, ScreenCastWidget, source_type);
   gtk_widget_class_bind_template_child (widget_class, ScreenCastWidget, monitor_selection);
diff --git a/src/screencastwidget.h b/src/screencastwidget.h
index 3a1ebd2..0b80274 100644
--- a/src/screencastwidget.h
+++ b/src/screencastwidget.h
@@ -39,5 +39,11 @@ void screen_cast_widget_set_allow_multiple (ScreenCastWidget *widget,
 void screen_cast_widget_set_source_types (ScreenCastWidget *screen_cast_widget,
                                           ScreenCastSourceType source_types);
 
+void screen_cast_widget_set_persist_mode (ScreenCastWidget *screen_cast_widget,
+                                          ScreenCastPersistMode persist_mode);
+
 void screen_cast_widget_add_selections (ScreenCastWidget *widget,
                                         GVariantBuilder *selections_builder);
+
+GStrv screen_cast_widget_get_restore_data (ScreenCastWidget      *widget,
+                                           ScreenCastPersistMode *out_persist_mode);
diff --git a/src/screencastwidget.ui b/src/screencastwidget.ui
index 2417ca5..d727c72 100644
--- a/src/screencastwidget.ui
+++ b/src/screencastwidget.ui
@@ -149,5 +149,12 @@
         </child>
       </object>
     </child>
+
+    <!-- Persist permission -->
+    <child>
+      <object class="GtkCheckButton" id="persist_check">
+        <property name="label" translatable="yes">Remember this decision</property>
+      </object>
+    </child>
   </template>
 </interface>


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