[xdg-desktop-portal-gnome/gbsneto/screencast-session-restore] WIP: Implement stream restoration
- From: Georges Basile Stavracas Neto <gbsneto src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [xdg-desktop-portal-gnome/gbsneto/screencast-session-restore] WIP: Implement stream restoration
- Date: Tue, 9 Nov 2021 18:13:22 +0000 (UTC)
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]