Add screencast stream restoration support

Resolves: RHEL-4526
This commit is contained in:
Jan Grulich 2024-01-09 15:24:07 +01:00
parent 08f1f9377b
commit 6e8c012b33
15 changed files with 3679 additions and 1 deletions

View File

@ -0,0 +1,638 @@
From d9c897c8b91165f95f011d44f2fea731b4b7eb16 Mon Sep 17 00:00:00 2001
From: Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
Date: Wed, 10 Nov 2021 15:32:18 -0300
Subject: [PATCH] screencast: Trivial style cleanups
Move some code around, and cleanup some of the styling.
It's getting increasingly harder to follow these files,
so start this series of cleanups with them.
---
src/screencast.c | 30 ++--
src/screencastdialog.c | 62 +++----
src/screencastdialog.h | 2 +-
src/screencastwidget.c | 356 +++++++++++++++++++++--------------------
src/screencastwidget.h | 10 +-
5 files changed, 238 insertions(+), 222 deletions(-)
diff --git a/src/gnomescreencast.c b/src/gnomescreencast.c
index fd80ca7..abf5b53 100644
--- a/src/gnomescreencast.c
+++ b/src/gnomescreencast.c
@@ -473,6 +473,7 @@ gnome_screen_cast_session_record_selections (GnomeScreenCastSession *gnome_scree
select,
error))
return FALSE;
+ break;
}
}
diff --git a/src/screencast.c b/src/screencast.c
index 27d8946..38d1d05 100644
--- a/src/screencast.c
+++ b/src/screencast.c
@@ -572,21 +572,6 @@ on_gnome_screen_cast_disabled (GDBusConnection *connection,
}
}
-gboolean
-screen_cast_init (GDBusConnection *connection,
- GError **error)
-{
- impl_connection = connection;
- gnome_screen_cast = gnome_screen_cast_new (connection);
-
- g_signal_connect (gnome_screen_cast, "enabled",
- G_CALLBACK (on_gnome_screen_cast_enabled), NULL);
- g_signal_connect (gnome_screen_cast, "disabled",
- G_CALLBACK (on_gnome_screen_cast_disabled), NULL);
-
- return TRUE;
-}
-
static void
screen_cast_session_close (Session *session)
{
@@ -636,3 +621,18 @@ screen_cast_session_class_init (ScreenCastSessionClass *klass)
session_class = (SessionClass *)klass;
session_class->close = screen_cast_session_close;
}
+
+gboolean
+screen_cast_init (GDBusConnection *connection,
+ GError **error)
+{
+ impl_connection = connection;
+ gnome_screen_cast = gnome_screen_cast_new (connection);
+
+ g_signal_connect (gnome_screen_cast, "enabled",
+ G_CALLBACK (on_gnome_screen_cast_enabled), NULL);
+ g_signal_connect (gnome_screen_cast, "disabled",
+ G_CALLBACK (on_gnome_screen_cast_disabled), NULL);
+
+ return TRUE;
+}
diff --git a/src/screencastdialog.c b/src/screencastdialog.c
index 306992d..56d4d49 100644
--- a/src/screencastdialog.c
+++ b/src/screencastdialog.c
@@ -51,6 +51,10 @@ static guint signals[N_SIGNALS];
G_DEFINE_TYPE (ScreenCastDialog, screen_cast_dialog, GTK_TYPE_WINDOW)
+/*
+ * Callbacks
+ */
+
static void
button_clicked (GtkWidget *button,
ScreenCastDialog *dialog)
@@ -84,7 +88,7 @@ button_clicked (GtkWidget *button,
static void
on_has_selection_changed (ScreenCastWidget *screen_cast_widget,
- gboolean has_selection,
+ gboolean has_selection,
ScreenCastDialog *dialog)
{
if (has_selection)
@@ -93,32 +97,9 @@ on_has_selection_changed (ScreenCastWidget *screen_cast_widget,
gtk_widget_set_sensitive (dialog->accept_button, FALSE);
}
-ScreenCastDialog *
-screen_cast_dialog_new (const char *app_id,
- ScreenCastSelection *select)
-{
- ScreenCastDialog *dialog;
- ScreenCastWidget *screen_cast_widget;
-
- dialog = g_object_new (SCREEN_CAST_TYPE_DIALOG, NULL);
- screen_cast_widget = SCREEN_CAST_WIDGET (dialog->screen_cast_widget);
- screen_cast_widget_set_app_id (screen_cast_widget, 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);
-
- return dialog;
-}
-
-static void
-screen_cast_dialog_init (ScreenCastDialog *dialog)
-{
- gtk_widget_init_template (GTK_WIDGET (dialog));
-
- g_signal_connect (dialog->screen_cast_widget, "has-selection-changed",
- G_CALLBACK (on_has_selection_changed), dialog);
- gtk_widget_show (dialog->screen_cast_widget);
-}
+/*
+ * GtkWindow overrides
+ */
static gboolean
screen_cast_dialog_close_request (GtkWindow *dialog)
@@ -155,3 +136,30 @@ screen_cast_dialog_class_init (ScreenCastDialogClass *klass)
gtk_widget_class_bind_template_child (widget_class, ScreenCastDialog, screen_cast_widget);
gtk_widget_class_bind_template_callback (widget_class, button_clicked);
}
+
+static void
+screen_cast_dialog_init (ScreenCastDialog *dialog)
+{
+ gtk_widget_init_template (GTK_WIDGET (dialog));
+
+ g_signal_connect (dialog->screen_cast_widget, "has-selection-changed",
+ G_CALLBACK (on_has_selection_changed), dialog);
+ gtk_widget_show (dialog->screen_cast_widget);
+}
+
+ScreenCastDialog *
+screen_cast_dialog_new (const char *app_id,
+ ScreenCastSelection *select)
+{
+ ScreenCastDialog *dialog;
+ ScreenCastWidget *screen_cast_widget;
+
+ dialog = g_object_new (SCREEN_CAST_TYPE_DIALOG, NULL);
+ screen_cast_widget = SCREEN_CAST_WIDGET (dialog->screen_cast_widget);
+ screen_cast_widget_set_app_id (screen_cast_widget, 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);
+
+ return dialog;
+}
diff --git a/src/screencastdialog.h b/src/screencastdialog.h
index 247d93b..1fca470 100644
--- a/src/screencastdialog.h
+++ b/src/screencastdialog.h
@@ -26,5 +26,5 @@
G_DECLARE_FINAL_TYPE (ScreenCastDialog, screen_cast_dialog,
SCREEN_CAST, DIALOG, GtkWindow)
-ScreenCastDialog * screen_cast_dialog_new (const char *app_id,
+ScreenCastDialog * screen_cast_dialog_new (const char *app_id,
ScreenCastSelection *select);
diff --git a/src/screencastwidget.c b/src/screencastwidget.c
index cdd57dc..454c93e 100644
--- a/src/screencastwidget.c
+++ b/src/screencastwidget.c
@@ -65,6 +65,55 @@ static GQuark quark_window_widget_data;
G_DEFINE_TYPE (ScreenCastWidget, screen_cast_widget, GTK_TYPE_BOX)
+/*
+ * Auxiliary methods
+ */
+
+static gboolean
+add_selections (ScreenCastWidget *widget,
+ GVariantBuilder *source_selections_builder)
+{
+ GList *selected_monitor_rows;
+ GList *selected_window_rows;
+ GList *l;
+
+ 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 FALSE;
+
+ 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_variant_builder_add (source_selections_builder, "(us)",
+ SCREEN_CAST_SOURCE_TYPE_MONITOR,
+ monitor_get_connector (monitor));
+ }
+ g_list_free (selected_monitor_rows);
+ 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);
+
+ return TRUE;
+}
+
static GtkWidget *
create_window_widget (Window *window)
{
@@ -131,7 +180,7 @@ create_monitor_widget (LogicalMonitor *logical_monitor)
}
static gboolean
-should_skip_window (Window *window,
+should_skip_window (Window *window,
GtkWindow *toplevel)
{
g_autofree char *processed_app_id = NULL;
@@ -254,7 +303,7 @@ unselect_rows (GtkListBox *listbox)
}
static void
-on_windows_changed (ShellIntrospect *shell_introspect,
+on_windows_changed (ShellIntrospect *shell_introspect,
ScreenCastWidget *widget)
{
update_windows_list (widget);
@@ -283,9 +332,9 @@ disconnect_windows_changed_listener (ScreenCastWidget *widget)
}
static void
-on_stack_switch (GtkStack *stack,
+on_stack_switch (GtkStack *stack,
GParamSpec *pspec,
- gpointer *data)
+ gpointer *data)
{
ScreenCastWidget *widget = (ScreenCastWidget *)data;
GtkWidget *visible_child;
@@ -307,9 +356,9 @@ on_stack_switch (GtkStack *stack,
}
static void
-on_row_activated (GtkListBox *box,
+on_row_activated (GtkListBox *box,
GtkListBoxRow *row,
- gpointer *data)
+ gpointer *data)
{
if (!row)
return;
@@ -378,7 +427,7 @@ schedule_selection_change (ScreenCastWidget *widget)
}
static void
-on_selected_rows_changed (GtkListBox *box,
+on_selected_rows_changed (GtkListBox *box,
ScreenCastWidget *widget)
{
/* GtkListBox activates rows after selecting them, which prevents
@@ -403,59 +452,128 @@ update_list_box_header (GtkListBoxRow *row,
static void
on_monitors_changed (DisplayStateTracker *display_state_tracker,
- ScreenCastWidget *widget)
+ ScreenCastWidget *widget)
{
update_monitors_list (widget);
}
-static gboolean
-add_selections (ScreenCastWidget *widget,
- GVariantBuilder *source_selections_builder)
+/*
+ * GObject overrides
+ */
+
+static void
+screen_cast_widget_finalize (GObject *object)
{
- GList *selected_monitor_rows;
- GList *selected_window_rows;
- GList *l;
+ ScreenCastWidget *widget = SCREEN_CAST_WIDGET (object);
- 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 FALSE;
+ g_signal_handler_disconnect (widget->display_state_tracker,
+ widget->monitors_changed_handler_id);
- for (l = selected_monitor_rows; l; l = l->next)
+ if (widget->windows_changed_handler_id)
+ disconnect_windows_changed_listener (widget);
+
+ if (widget->selection_changed_timeout_id > 0)
{
- GtkWidget *monitor_widget = gtk_list_box_row_get_child (l->data);
- Monitor *monitor;
+ g_source_remove (widget->selection_changed_timeout_id);
+ widget->selection_changed_timeout_id = 0;
+ }
- monitor = g_object_get_qdata (G_OBJECT (monitor_widget),
- quark_monitor_widget_data);
+ G_OBJECT_CLASS (screen_cast_widget_parent_class)->finalize (object);
+}
- g_variant_builder_add (source_selections_builder, "(us)",
- SCREEN_CAST_SOURCE_TYPE_MONITOR,
- monitor_get_connector (monitor));
- }
- g_list_free (selected_monitor_rows);
- for (l = selected_window_rows; l; l = l->next)
- {
- GtkWidget *window_widget = gtk_list_box_row_get_child (l->data);
- Window *window;
+static void
+screen_cast_widget_class_init (ScreenCastWidgetClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
- window = g_object_get_qdata (G_OBJECT (window_widget),
- quark_window_widget_data);
+ object_class->finalize = screen_cast_widget_finalize;
- g_variant_builder_add (source_selections_builder, "(ut)",
- SCREEN_CAST_SOURCE_TYPE_WINDOW,
- window_get_id (window));
- }
- g_list_free (selected_window_rows);
+ signals[HAS_SELECTION_CHANGED] = g_signal_new ("has-selection-changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 1,
+ G_TYPE_BOOLEAN);
- return TRUE;
+ 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, 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);
+ gtk_widget_class_bind_template_child (widget_class, ScreenCastWidget, window_selection);
+ gtk_widget_class_bind_template_child (widget_class, ScreenCastWidget, monitor_heading);
+ gtk_widget_class_bind_template_child (widget_class, ScreenCastWidget, monitor_list);
+ gtk_widget_class_bind_template_child (widget_class, ScreenCastWidget, window_heading);
+ gtk_widget_class_bind_template_child (widget_class, ScreenCastWidget, window_list);
+ gtk_widget_class_bind_template_child (widget_class, ScreenCastWidget, window_list_scrolled);
+
+ quark_monitor_widget_data = g_quark_from_static_string ("-monitor-widget-connector-quark");
+ quark_window_widget_data = g_quark_from_static_string ("-window-widget-connector-quark");
+}
+
+static void
+screen_cast_widget_init (ScreenCastWidget *widget)
+{
+ GtkScrolledWindow *scrolled_window;
+ GtkAdjustment *vadjustment;
+
+ gtk_widget_init_template (GTK_WIDGET (widget));
+
+ screen_cast_widget_set_app_id (widget, NULL);
+ screen_cast_widget_set_allow_multiple (widget, FALSE);
+
+ gtk_list_box_set_header_func (GTK_LIST_BOX (widget->monitor_list),
+ update_list_box_header,
+ NULL, NULL);
+ gtk_list_box_set_header_func (GTK_LIST_BOX (widget->window_list),
+ update_list_box_header,
+ NULL, NULL);
+ scrolled_window = GTK_SCROLLED_WINDOW (widget->window_list_scrolled);
+ vadjustment = gtk_scrolled_window_get_vadjustment (scrolled_window);
+ gtk_list_box_set_adjustment (GTK_LIST_BOX (widget->window_list), vadjustment);
+
+ g_signal_connect (widget->source_type, "notify::visible-child",
+ G_CALLBACK (on_stack_switch),
+ widget);
+ g_signal_connect (widget->monitor_list, "row-activated",
+ G_CALLBACK (on_row_activated),
+ NULL);
+ g_signal_connect (widget->window_list, "row-activated",
+ G_CALLBACK (on_row_activated),
+ NULL);
+ g_signal_connect (widget->monitor_list, "selected-rows-changed",
+ G_CALLBACK (on_selected_rows_changed),
+ widget);
+ g_signal_connect (widget->window_list, "selected-rows-changed",
+ G_CALLBACK (on_selected_rows_changed),
+ widget);
+
+ widget->display_state_tracker = display_state_tracker_get ();
+ widget->monitors_changed_handler_id =
+ g_signal_connect (widget->display_state_tracker,
+ "monitors-changed",
+ G_CALLBACK (on_monitors_changed),
+ widget);
+ widget->shell_introspect = shell_introspect_get ();
+
+ update_monitors_list (widget);
+ update_windows_list (widget);
+
+ gtk_widget_show (widget->monitor_list);
+ gtk_widget_show (widget->window_list);
+}
+
+void
+init_screen_cast_widget (void)
+{
+ g_type_ensure (screen_cast_widget_get_type ());
}
void
screen_cast_widget_add_selections (ScreenCastWidget *widget,
- GVariantBuilder *selections_builder)
+ GVariantBuilder *selections_builder)
{
GVariantBuilder source_selections_builder;
@@ -474,7 +592,7 @@ screen_cast_widget_add_selections (ScreenCastWidget *widget,
void
screen_cast_widget_set_app_id (ScreenCastWidget *widget,
- const char *app_id)
+ const char *app_id)
{
g_autofree char *monitor_heading = NULL;
g_autofree char *window_heading = NULL;
@@ -508,7 +626,7 @@ screen_cast_widget_set_app_id (ScreenCastWidget *widget,
void
screen_cast_widget_set_allow_multiple (ScreenCastWidget *widget,
- gboolean multiple)
+ gboolean multiple)
{
gtk_list_box_set_selection_mode (GTK_LIST_BOX (widget->monitor_list),
multiple ? GTK_SELECTION_MULTIPLE
@@ -519,8 +637,8 @@ screen_cast_widget_set_allow_multiple (ScreenCastWidget *widget,
}
void
-screen_cast_widget_set_source_types (ScreenCastWidget *screen_cast_widget,
- ScreenCastSourceType source_types)
+screen_cast_widget_set_source_types (ScreenCastWidget *screen_cast_widget,
+ ScreenCastSourceType source_types)
{
if (source_types & SCREEN_CAST_SOURCE_TYPE_MONITOR)
gtk_widget_show (screen_cast_widget->monitor_selection);
@@ -531,113 +649,3 @@ screen_cast_widget_set_source_types (ScreenCastWidget *screen_cast_widget,
if (__builtin_popcount (source_types) > 1)
gtk_widget_show (screen_cast_widget->source_type_switcher);
}
-
-static void
-screen_cast_widget_finalize (GObject *object)
-{
- ScreenCastWidget *widget = SCREEN_CAST_WIDGET (object);
-
- g_signal_handler_disconnect (widget->display_state_tracker,
- widget->monitors_changed_handler_id);
-
- if (widget->windows_changed_handler_id)
- disconnect_windows_changed_listener (widget);
-
- if (widget->selection_changed_timeout_id > 0)
- {
- g_source_remove (widget->selection_changed_timeout_id);
- widget->selection_changed_timeout_id = 0;
- }
-
- G_OBJECT_CLASS (screen_cast_widget_parent_class)->finalize (object);
-}
-
-static void
-screen_cast_widget_init (ScreenCastWidget *widget)
-{
- GtkScrolledWindow *scrolled_window;
- GtkAdjustment *vadjustment;
-
- gtk_widget_init_template (GTK_WIDGET (widget));
-
- screen_cast_widget_set_app_id (widget, NULL);
- screen_cast_widget_set_allow_multiple (widget, FALSE);
-
- gtk_list_box_set_header_func (GTK_LIST_BOX (widget->monitor_list),
- update_list_box_header,
- NULL, NULL);
- gtk_list_box_set_header_func (GTK_LIST_BOX (widget->window_list),
- update_list_box_header,
- NULL, NULL);
- scrolled_window = GTK_SCROLLED_WINDOW (widget->window_list_scrolled);
- vadjustment = gtk_scrolled_window_get_vadjustment (scrolled_window);
- gtk_list_box_set_adjustment (GTK_LIST_BOX (widget->window_list), vadjustment);
-
- g_signal_connect (widget->source_type, "notify::visible-child",
- G_CALLBACK (on_stack_switch),
- widget);
- g_signal_connect (widget->monitor_list, "row-activated",
- G_CALLBACK (on_row_activated),
- NULL);
- g_signal_connect (widget->window_list, "row-activated",
- G_CALLBACK (on_row_activated),
- NULL);
- g_signal_connect (widget->monitor_list, "selected-rows-changed",
- G_CALLBACK (on_selected_rows_changed),
- widget);
- g_signal_connect (widget->window_list, "selected-rows-changed",
- G_CALLBACK (on_selected_rows_changed),
- widget);
-
- widget->display_state_tracker = display_state_tracker_get ();
- widget->monitors_changed_handler_id =
- g_signal_connect (widget->display_state_tracker,
- "monitors-changed",
- G_CALLBACK (on_monitors_changed),
- widget);
- widget->shell_introspect = shell_introspect_get ();
-
- update_monitors_list (widget);
- update_windows_list (widget);
-
- gtk_widget_show (widget->monitor_list);
- gtk_widget_show (widget->window_list);
-}
-
-static void
-screen_cast_widget_class_init (ScreenCastWidgetClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-
- object_class->finalize = screen_cast_widget_finalize;
-
- signals[HAS_SELECTION_CHANGED] = g_signal_new ("has-selection-changed",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL, NULL,
- NULL,
- G_TYPE_NONE, 1,
- 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, 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);
- gtk_widget_class_bind_template_child (widget_class, ScreenCastWidget, window_selection);
- gtk_widget_class_bind_template_child (widget_class, ScreenCastWidget, monitor_heading);
- gtk_widget_class_bind_template_child (widget_class, ScreenCastWidget, monitor_list);
- gtk_widget_class_bind_template_child (widget_class, ScreenCastWidget, window_heading);
- gtk_widget_class_bind_template_child (widget_class, ScreenCastWidget, window_list);
- gtk_widget_class_bind_template_child (widget_class, ScreenCastWidget, window_list_scrolled);
-
- quark_monitor_widget_data = g_quark_from_static_string ("-monitor-widget-connector-quark");
- quark_window_widget_data = g_quark_from_static_string ("-window-widget-connector-quark");
-}
-
-void
-init_screen_cast_widget (void)
-{
- g_type_ensure (screen_cast_widget_get_type ());
-}
diff --git a/src/screencastwidget.h b/src/screencastwidget.h
index 3a1ebd2..34360a3 100644
--- a/src/screencastwidget.h
+++ b/src/screencastwidget.h
@@ -31,13 +31,13 @@ G_DECLARE_FINAL_TYPE (ScreenCastWidget, screen_cast_widget,
void init_screen_cast_widget (void);
void screen_cast_widget_set_app_id (ScreenCastWidget *widget,
- const char *app_id);
+ const char *app_id);
void screen_cast_widget_set_allow_multiple (ScreenCastWidget *widget,
- gboolean multiple);
+ gboolean multiple);
-void screen_cast_widget_set_source_types (ScreenCastWidget *screen_cast_widget,
- ScreenCastSourceType source_types);
+void screen_cast_widget_set_source_types (ScreenCastWidget *screen_cast_widget,
+ ScreenCastSourceType source_types);
void screen_cast_widget_add_selections (ScreenCastWidget *widget,
- GVariantBuilder *selections_builder);
+ GVariantBuilder *selections_builder);
diff --git a/src/screencastwidget.ui b/src/screencastwidget.ui
index 2417ca5..fb83b94 100644
--- a/src/screencastwidget.ui
+++ b/src/screencastwidget.ui
@@ -19,6 +19,7 @@
<child>
<object class="GtkStack" id="source_type">
<property name="transition-type">crossfade</property>
+ <!-- Window selection page -->
<child>
<object class="GtkStackPage">
<property name="name">windows_page</property>
@@ -80,6 +81,8 @@
</property>
</object>
</child>
+
+ <!-- Physical monitor selection page -->
<child>
<object class="GtkStackPage">
<property name="name">monitors_page</property>

View File

@ -0,0 +1,223 @@
diff --git a/src/displaystatetracker.c b/src/displaystatetracker.c
index fc9109e..ebe1105 100644
--- a/src/displaystatetracker.c
+++ b/src/displaystatetracker.c
@@ -62,7 +62,7 @@ G_DEFINE_TYPE (DisplayStateTracker, display_state_tracker, G_TYPE_OBJECT)
static DisplayStateTracker *_display_state_tracker;
-static void
+void
monitor_free (Monitor *monitor)
{
g_free (monitor->connector);
@@ -71,6 +71,19 @@ monitor_free (Monitor *monitor)
g_free (monitor);
}
+Monitor *
+monitor_dup (Monitor *monitor)
+{
+ Monitor *new_monitor;
+
+ new_monitor = g_new0 (Monitor, 1);
+ new_monitor->connector = g_strdup (monitor->connector);
+ new_monitor->match_string = g_strdup (monitor->match_string);
+ new_monitor->display_name = g_strdup (monitor->display_name);
+
+ return new_monitor;
+}
+
const char *
monitor_get_connector (Monitor *monitor)
{
diff --git a/src/displaystatetracker.h b/src/displaystatetracker.h
index 1c3a7dc..e438dda 100644
--- a/src/displaystatetracker.h
+++ b/src/displaystatetracker.h
@@ -26,6 +26,10 @@ typedef struct _LogicalMonitor LogicalMonitor;
G_DECLARE_FINAL_TYPE (DisplayStateTracker, display_state_tracker,
DISPLAY, STATE_TRACKER, GObject)
+void monitor_free (Monitor *monitor);
+
+Monitor * monitor_dup (Monitor *monitor);
+
const char * monitor_get_connector (Monitor *monitor);
const char * monitor_get_match_string (Monitor *monitor);
diff --git a/src/screencast.c b/src/screencast.c
index 0a15033..724ffc9 100644
--- a/src/screencast.c
+++ b/src/screencast.c
@@ -469,6 +469,22 @@ find_best_window_by_app_id_and_title (const char *app_id,
return best_match;
}
+void
+screen_cast_stream_info_free (ScreenCastStreamInfo *info)
+{
+ switch (info->type)
+ {
+ case SCREEN_CAST_SOURCE_TYPE_MONITOR:
+ g_clear_pointer (&info->data.monitor, monitor_free);
+ break;
+ case SCREEN_CAST_SOURCE_TYPE_WINDOW:
+ g_clear_pointer (&info->data.window, window_free);
+ break;
+ }
+
+ g_free (info);
+}
+
static gboolean
restore_stream_from_data (ScreenCastSession *screen_cast_session)
@@ -486,7 +502,8 @@ restore_stream_from_data (ScreenCastSession *screen_cast_session)
if (!screen_cast_session->restored.data)
return FALSE;
- streams = g_ptr_array_new_with_free_func (g_free);
+ streams =
+ g_ptr_array_new_with_free_func ((GDestroyNotify) screen_cast_stream_info_free);
g_variant_get (screen_cast_session->restored.data,
RESTORE_VARIANT_TYPE,
@@ -512,7 +529,7 @@ restore_stream_from_data (ScreenCastSession *screen_cast_session)
info = g_new0 (ScreenCastStreamInfo, 1);
info->type = SCREEN_CAST_SOURCE_TYPE_MONITOR;
- info->data.monitor = monitor;
+ info->data.monitor = monitor_dup (monitor);
info->id = id;
g_ptr_array_add (streams, info);
}
@@ -537,7 +554,7 @@ restore_stream_from_data (ScreenCastSession *screen_cast_session)
info = g_new0 (ScreenCastStreamInfo, 1);
info->type = SCREEN_CAST_SOURCE_TYPE_WINDOW;
- info->data.window = window;
+ info->data.window = window_dup (window);
info->id = id;
g_ptr_array_add (streams, info);
}
diff --git a/src/screencast.h b/src/screencast.h
index 3d64b4a..ae8988d 100644
--- a/src/screencast.h
+++ b/src/screencast.h
@@ -64,3 +64,5 @@ typedef struct
gboolean screen_cast_init (GDBusConnection *connection,
GError **error);
+
+void screen_cast_stream_info_free (ScreenCastStreamInfo *info);
diff --git a/src/screencastwidget.c b/src/screencastwidget.c
index 11743f7..a40c824 100644
--- a/src/screencastwidget.c
+++ b/src/screencastwidget.c
@@ -101,9 +101,10 @@ create_window_widget (Window *window)
gtk_widget_set_margin_bottom (window_label, 12);
gtk_box_append (GTK_BOX (window_widget), window_label);
- g_object_set_qdata (G_OBJECT (window_widget),
- quark_window_widget_data,
- window);
+ g_object_set_qdata_full (G_OBJECT (window_widget),
+ quark_window_widget_data,
+ window_dup (window),
+ (GDestroyNotify) window_free);
return window_widget;
}
@@ -123,9 +124,12 @@ create_monitor_widget (LogicalMonitor *logical_monitor)
GtkWidget *monitor_label;
if (!l->prev)
- g_object_set_qdata (G_OBJECT (monitor_widget),
- quark_monitor_widget_data,
- monitor);
+ {
+ g_object_set_qdata_full (G_OBJECT (monitor_widget),
+ quark_monitor_widget_data,
+ monitor_dup (monitor),
+ (GDestroyNotify) monitor_free);
+ }
monitor_label = gtk_label_new (monitor_get_display_name (monitor));
gtk_widget_set_margin_top (monitor_label, 12);
@@ -599,7 +603,8 @@ screen_cast_widget_get_selected_streams (ScreenCastWidget *self)
uint32_t id = 0;
GList *l;
- streams = g_ptr_array_new_with_free_func (g_free);
+ streams =
+ g_ptr_array_new_with_free_func ((GDestroyNotify) screen_cast_stream_info_free);
selected_monitor_rows =
gtk_list_box_get_selected_rows (GTK_LIST_BOX (self->monitor_list));
@@ -619,7 +624,7 @@ screen_cast_widget_get_selected_streams (ScreenCastWidget *self)
info = g_new0 (ScreenCastStreamInfo, 1);
info->type = SCREEN_CAST_SOURCE_TYPE_MONITOR;
- info->data.monitor = monitor;
+ info->data.monitor = monitor_dup (monitor);
info->id = id++;
g_ptr_array_add (streams, info);
}
@@ -634,7 +639,7 @@ screen_cast_widget_get_selected_streams (ScreenCastWidget *self)
info = g_new0 (ScreenCastStreamInfo, 1);
info->type = SCREEN_CAST_SOURCE_TYPE_WINDOW;
- info->data.window = window;
+ info->data.window = window_dup (window);
info->id = id++;
g_ptr_array_add (streams, info);
}
diff --git a/src/shellintrospect.c b/src/shellintrospect.c
index 8a81086..d1bcc8c 100644
--- a/src/shellintrospect.c
+++ b/src/shellintrospect.c
@@ -62,7 +62,7 @@ static guint signals[N_SIGNALS];
static ShellIntrospect *_shell_introspect;
-static void
+void
window_free (Window *window)
{
g_free (window->title);
@@ -70,6 +70,19 @@ window_free (Window *window)
g_free (window);
}
+Window *
+window_dup (Window *window)
+{
+ Window *new_window;
+
+ new_window = g_new0 (Window, 1);
+ new_window->id = window->id;
+ new_window->title = g_strdup (window->title);
+ new_window->app_id = g_strdup (window->app_id);
+
+ return new_window;
+}
+
static void
get_windows_cb (GObject *source_object,
GAsyncResult *res,
diff --git a/src/shellintrospect.h b/src/shellintrospect.h
index f63ecee..ea4188f 100644
--- a/src/shellintrospect.h
+++ b/src/shellintrospect.h
@@ -34,6 +34,10 @@ void shell_introspect_ref_listeners (ShellIntrospect *shell_introspect);
void shell_introspect_unref_listeners (ShellIntrospect *shell_introspect);
+void window_free (Window *window);
+
+Window * window_dup (Window *window);
+
const char * window_get_app_id (Window *window);
const char * window_get_title (Window *window);

View File

@ -0,0 +1,23 @@
From a7c03eb9642a244f5623bf5bbe0e29f759554567 Mon Sep 17 00:00:00 2001
From: Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
Date: Wed, 10 Nov 2021 15:52:37 -0300
Subject: [PATCH] screencast: Cleanup unnecessary forward declaration
---
src/screencast.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/src/screencast.c b/src/screencast.c
index 38d1d05..98390ab 100644
--- a/src/screencast.c
+++ b/src/screencast.c
@@ -77,9 +77,6 @@ static GnomeScreenCast *gnome_screen_cast;
GType screen_cast_session_get_type (void);
G_DEFINE_TYPE (ScreenCastSession, screen_cast_session, session_get_type ())
-static void
-start_done (ScreenCastSession *session);
-
static gboolean
start_session (ScreenCastSession *session,
GVariant *selections,

View File

@ -0,0 +1,452 @@
From 367f05b980ab780ae3b3380164f2135ce4f487fa Mon Sep 17 00:00:00 2001
From: Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
Date: Wed, 10 Nov 2021 16:04:59 -0300
Subject: [PATCH] screencast: More code shuffling and cleanups
No funcional changes.
---
src/screencast.c | 350 +++++++++++++++++++++++------------------------
1 file changed, 168 insertions(+), 182 deletions(-)
diff --git a/src/screencast.c b/src/screencast.c
index 98390ab..4ba67aa 100644
--- a/src/screencast.c
+++ b/src/screencast.c
@@ -82,10 +82,6 @@ start_session (ScreenCastSession *session,
GVariant *selections,
GError **error);
-static void
-cancel_start_session (ScreenCastSession *session,
- int response);
-
static gboolean
is_screen_cast_session (Session *session)
{
@@ -108,10 +104,23 @@ screen_cast_dialog_handle_close (ScreenCastDialogHandle *dialog_handle)
screen_cast_dialog_handle_free (dialog_handle);
}
+static void
+cancel_start_session (ScreenCastSession *screen_cast_session,
+ int response)
+{
+ GVariantBuilder results_builder;
+
+ g_variant_builder_init (&results_builder, G_VARIANT_TYPE_VARDICT);
+ xdp_impl_screen_cast_complete_start (XDP_IMPL_SCREEN_CAST (impl),
+ screen_cast_session->start_invocation,
+ response,
+ g_variant_builder_end (&results_builder));
+}
+
static gboolean
-handle_close (XdpImplRequest *object,
- GDBusMethodInvocation *invocation,
- ScreenCastDialogHandle *dialog_handle)
+on_request_handle_close_cb (XdpImplRequest *object,
+ GDBusMethodInvocation *invocation,
+ ScreenCastDialogHandle *dialog_handle)
{
cancel_start_session (dialog_handle->session, 2);
@@ -121,10 +130,10 @@ handle_close (XdpImplRequest *object,
}
static void
-screen_cast_dialog_done (GtkWidget *widget,
- int dialog_response,
- GVariant *selections,
- ScreenCastDialogHandle *dialog_handle)
+on_screen_cast_dialog_done_cb (GtkWidget *widget,
+ int dialog_response,
+ GVariant *selections,
+ ScreenCastDialogHandle *dialog_handle)
{
int response;
@@ -165,10 +174,10 @@ screen_cast_dialog_done (GtkWidget *widget,
}
static ScreenCastDialogHandle *
-create_screen_cast_dialog (ScreenCastSession *session,
+create_screen_cast_dialog (ScreenCastSession *session,
GDBusMethodInvocation *invocation,
- Request *request,
- const char *parent_window)
+ Request *request,
+ const char *parent_window)
{
ScreenCastDialogHandle *dialog_handle;
ExternalWindow *external_parent;
@@ -210,10 +219,9 @@ create_screen_cast_dialog (ScreenCastSession *session,
dialog_handle->dialog = dialog;
g_signal_connect (request, "handle-close",
- G_CALLBACK (handle_close), dialog_handle);
-
+ G_CALLBACK (on_request_handle_close_cb), dialog_handle);
g_signal_connect (dialog, "done",
- G_CALLBACK (screen_cast_dialog_done), dialog_handle);
+ G_CALLBACK (on_screen_cast_dialog_done_cb), dialog_handle);
gtk_widget_realize (dialog);
@@ -226,145 +234,6 @@ create_screen_cast_dialog (ScreenCastSession *session,
return dialog_handle;
}
-static ScreenCastSession *
-screen_cast_session_new (const char *app_id,
- const char *session_handle)
-{
- ScreenCastSession *screen_cast_session;
-
- screen_cast_session = g_object_new (screen_cast_session_get_type (),
- "id", session_handle,
- NULL);
-
- return screen_cast_session;
-}
-
-static gboolean
-handle_create_session (XdpImplScreenCast *object,
- GDBusMethodInvocation *invocation,
- const char *arg_handle,
- const char *arg_session_handle,
- const char *arg_app_id,
- GVariant *arg_options)
-{
- g_autoptr(GError) error = NULL;
- int response;
- Session *session;
- GVariantBuilder results_builder;
-
- session = (Session *)screen_cast_session_new (arg_app_id,
- arg_session_handle);
-
- if (!session_export (session,
- g_dbus_method_invocation_get_connection (invocation),
- &error))
- {
- g_clear_object (&session);
- g_warning ("Failed to create screen cast session: %s", error->message);
- response = 2;
- goto out;
- }
-
- response = 0;
-
-out:
- g_variant_builder_init (&results_builder, G_VARIANT_TYPE_VARDICT);
- xdp_impl_screen_cast_complete_create_session (object,
- invocation,
- response,
- g_variant_builder_end (&results_builder));
-
- return TRUE;
-}
-
-static gboolean
-handle_select_sources (XdpImplScreenCast *object,
- GDBusMethodInvocation *invocation,
- const char *arg_handle,
- const char *arg_session_handle,
- const char *arg_app_id,
- GVariant *arg_options)
-{
- Session *session;
- int response;
- uint32_t types;
- gboolean multiple;
- ScreenCastCursorMode cursor_mode;
- ScreenCastSelection select;
- GVariantBuilder results_builder;
- GVariant *results;
-
- session = lookup_session (arg_session_handle);
- if (!session)
- {
- g_warning ("Tried to select sources on non-existing %s", arg_session_handle);
- response = 2;
- goto out;
- }
-
- if (!g_variant_lookup (arg_options, "multiple", "b", &multiple))
- multiple = FALSE;
-
- if (!g_variant_lookup (arg_options, "types", "u", &types))
- types = SCREEN_CAST_SOURCE_TYPE_MONITOR;
-
- if (!(types & (SCREEN_CAST_SOURCE_TYPE_MONITOR |
- SCREEN_CAST_SOURCE_TYPE_WINDOW)))
- {
- g_warning ("Unknown screen cast source type");
- response = 2;
- goto out;
- }
-
- if (!g_variant_lookup (arg_options, "cursor_mode", "u", &cursor_mode))
- cursor_mode = SCREEN_CAST_CURSOR_MODE_HIDDEN;
-
- switch (cursor_mode)
- {
- case SCREEN_CAST_CURSOR_MODE_HIDDEN:
- case SCREEN_CAST_CURSOR_MODE_EMBEDDED:
- case SCREEN_CAST_CURSOR_MODE_METADATA:
- break;
- default:
- g_warning ("Unknown screen cast cursor mode");
- response = 2;
- goto out;
- }
-
- select.multiple = multiple;
- select.source_types = types;
- select.cursor_mode = cursor_mode;
-
- if (is_screen_cast_session (session))
- {
- ScreenCastSession *screen_cast_session = (ScreenCastSession *)session;
-
- screen_cast_session->select = select;
- response = 0;
- }
- else if (is_remote_desktop_session (session))
- {
- RemoteDesktopSession *remote_desktop_session =
- (RemoteDesktopSession *)session;
-
- remote_desktop_session_sources_selected (remote_desktop_session, &select);
- response = 0;
- }
- else
- {
- g_warning ("Tried to select sources on invalid session type");
- response = 2;
- }
-
-out:
- g_variant_builder_init (&results_builder, G_VARIANT_TYPE_VARDICT);
- results = g_variant_builder_end (&results_builder);
- xdp_impl_screen_cast_complete_select_sources (object, invocation,
- response, results);
-
- return TRUE;
-}
-
static void
start_done (ScreenCastSession *screen_cast_session)
{
@@ -391,14 +260,14 @@ start_done (ScreenCastSession *screen_cast_session)
static void
on_gnome_screen_cast_session_ready (GnomeScreenCastSession *gnome_screen_cast_session,
- ScreenCastSession *screen_cast_session)
+ ScreenCastSession *screen_cast_session)
{
start_done (screen_cast_session);
}
static void
on_gnome_screen_cast_session_closed (GnomeScreenCastSession *gnome_screen_cast_session,
- ScreenCastSession *screen_cast_session)
+ ScreenCastSession *screen_cast_session)
{
session_close ((Session *)screen_cast_session);
}
@@ -441,27 +310,14 @@ start_session (ScreenCastSession *screen_cast_session,
return TRUE;
}
-static void
-cancel_start_session (ScreenCastSession *screen_cast_session,
- int response)
-{
- GVariantBuilder results_builder;
-
- g_variant_builder_init (&results_builder, G_VARIANT_TYPE_VARDICT);
- xdp_impl_screen_cast_complete_start (XDP_IMPL_SCREEN_CAST (impl),
- screen_cast_session->start_invocation,
- response,
- g_variant_builder_end (&results_builder));
-}
-
static gboolean
-handle_start (XdpImplScreenCast *object,
+handle_start (XdpImplScreenCast *object,
GDBusMethodInvocation *invocation,
- const char *arg_handle,
- const char *arg_session_handle,
- const char *arg_app_id,
- const char *arg_parent_window,
- GVariant *arg_options)
+ const char *arg_handle,
+ const char *arg_session_handle,
+ const char *arg_app_id,
+ const char *arg_parent_window,
+ GVariant *arg_options)
{
const char *sender;
g_autoptr(Request) request = NULL;
@@ -507,6 +363,133 @@ err:
return TRUE;
}
+static gboolean
+handle_select_sources (XdpImplScreenCast *object,
+ GDBusMethodInvocation *invocation,
+ const char *arg_handle,
+ const char *arg_session_handle,
+ const char *arg_app_id,
+ GVariant *arg_options)
+{
+ Session *session;
+ int response;
+ uint32_t types;
+ gboolean multiple;
+ ScreenCastCursorMode cursor_mode;
+ ScreenCastSelection select;
+ GVariantBuilder results_builder;
+ GVariant *results;
+
+ session = lookup_session (arg_session_handle);
+ if (!session)
+ {
+ g_warning ("Tried to select sources on non-existing %s", arg_session_handle);
+ response = 2;
+ goto out;
+ }
+
+ if (!g_variant_lookup (arg_options, "multiple", "b", &multiple))
+ multiple = FALSE;
+
+ if (!g_variant_lookup (arg_options, "types", "u", &types))
+ types = SCREEN_CAST_SOURCE_TYPE_MONITOR;
+
+ if (!(types & (SCREEN_CAST_SOURCE_TYPE_MONITOR |
+ SCREEN_CAST_SOURCE_TYPE_WINDOW)))
+ {
+ g_warning ("Unknown screen cast source type");
+ response = 2;
+ goto out;
+ }
+
+ if (!g_variant_lookup (arg_options, "cursor_mode", "u", &cursor_mode))
+ cursor_mode = SCREEN_CAST_CURSOR_MODE_HIDDEN;
+
+ switch (cursor_mode)
+ {
+ case SCREEN_CAST_CURSOR_MODE_HIDDEN:
+ case SCREEN_CAST_CURSOR_MODE_EMBEDDED:
+ case SCREEN_CAST_CURSOR_MODE_METADATA:
+ break;
+ default:
+ g_warning ("Unknown screen cast cursor mode");
+ response = 2;
+ goto out;
+ }
+
+ select.multiple = multiple;
+ select.source_types = types;
+ select.cursor_mode = cursor_mode;
+
+ if (is_screen_cast_session (session))
+ {
+ ScreenCastSession *screen_cast_session = (ScreenCastSession *)session;
+
+ screen_cast_session->select = select;
+ response = 0;
+ }
+ else if (is_remote_desktop_session (session))
+ {
+ RemoteDesktopSession *remote_desktop_session =
+ (RemoteDesktopSession *)session;
+
+ remote_desktop_session_sources_selected (remote_desktop_session, &select);
+ response = 0;
+ }
+ else
+ {
+ g_warning ("Tried to select sources on invalid session type");
+ response = 2;
+ }
+
+out:
+ g_variant_builder_init (&results_builder, G_VARIANT_TYPE_VARDICT);
+ results = g_variant_builder_end (&results_builder);
+ xdp_impl_screen_cast_complete_select_sources (object, invocation,
+ response, results);
+
+ return TRUE;
+}
+
+static gboolean
+handle_create_session (XdpImplScreenCast *object,
+ GDBusMethodInvocation *invocation,
+ const char *arg_handle,
+ const char *arg_session_handle,
+ const char *arg_app_id,
+ GVariant *arg_options)
+{
+ g_autoptr(GError) error = NULL;
+ int response;
+ Session *session;
+ GVariantBuilder results_builder;
+
+ session = g_object_new (screen_cast_session_get_type (),
+ "id", arg_session_handle,
+ NULL);
+
+ if (!session_export (session,
+ g_dbus_method_invocation_get_connection (invocation),
+ &error))
+ {
+ g_clear_object (&session);
+ g_warning ("Failed to create screen cast session: %s", error->message);
+ response = 2;
+ goto out;
+ }
+
+ response = 0;
+
+out:
+ g_variant_builder_init (&results_builder, G_VARIANT_TYPE_VARDICT);
+ xdp_impl_screen_cast_complete_create_session (object,
+ invocation,
+ response,
+ g_variant_builder_end (&results_builder));
+
+ return TRUE;
+}
+
static void
on_gnome_screen_cast_enabled (GnomeScreenCast *gnome_screen_cast)
{
@@ -535,9 +518,12 @@ on_gnome_screen_cast_enabled (GnomeScreenCast *gnome_screen_cast)
available_cursor_modes = SCREEN_CAST_CURSOR_MODE_NONE;
if (gnome_api_version >= 2)
- available_cursor_modes |= (SCREEN_CAST_CURSOR_MODE_HIDDEN |
- SCREEN_CAST_CURSOR_MODE_EMBEDDED |
- SCREEN_CAST_CURSOR_MODE_METADATA);
+ {
+ available_cursor_modes |= SCREEN_CAST_CURSOR_MODE_HIDDEN |
+ SCREEN_CAST_CURSOR_MODE_EMBEDDED |
+ SCREEN_CAST_CURSOR_MODE_METADATA;
+ }
+
g_object_set (G_OBJECT (impl),
"available-cursor-modes", available_cursor_modes,
NULL);
@@ -620,8 +606,8 @@ screen_cast_session_class_init (ScreenCastSessionClass *klass)
}
gboolean
-screen_cast_init (GDBusConnection *connection,
- GError **error)
+screen_cast_init (GDBusConnection *connection,
+ GError **error)
{
impl_connection = connection;
gnome_screen_cast = gnome_screen_cast_new (connection);

View File

@ -0,0 +1,744 @@
From 0f6957254e32ab6dc1c132c0f7623bbac31309f6 Mon Sep 17 00:00:00 2001
From: Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
Date: Wed, 10 Nov 2021 19:54:39 -0300
Subject: [PATCH] screencastwidget: Rework selection APIs
Instead of passing data around using GVariants, add
properly types variables and structures all around.
This will vastly simplify future commits introducing
screencast stream restore.
---
src/gnomescreencast.c | 51 ++++++-------
src/gnomescreencast.h | 8 +-
src/remotedesktop.c | 40 +++++-----
src/remotedesktopdialog.c | 35 ++++-----
src/screencast.c | 151 +++++++++++++++++---------------------
src/screencast.h | 12 +++
src/screencastdialog.c | 15 ++--
src/screencastwidget.c | 132 +++++++++++++++------------------
src/screencastwidget.h | 3 +-
9 files changed, 203 insertions(+), 244 deletions(-)
diff --git a/src/gnomescreencast.c b/src/gnomescreencast.c
index abf5b53..3f8539c 100644
--- a/src/gnomescreencast.c
+++ b/src/gnomescreencast.c
@@ -274,10 +274,10 @@ cursor_mode_to_gnome_cursor_mode (ScreenCastCursorMode cursor_mode)
}
static gboolean
-gnome_screen_cast_session_record_window (GnomeScreenCastSession *gnome_screen_cast_session,
- const guint64 id,
- ScreenCastSelection *select,
- GError **error)
+gnome_screen_cast_session_record_window (GnomeScreenCastSession *gnome_screen_cast_session,
+ Window *window,
+ ScreenCastSelection *select,
+ GError **error)
{
OrgGnomeMutterScreenCastSession *session_proxy =
gnome_screen_cast_session->proxy;
@@ -292,7 +292,7 @@ gnome_screen_cast_session_record_window (GnomeScreenCastSession *gnome_screen_ca
g_variant_builder_init (&properties_builder, G_VARIANT_TYPE_VARDICT);
g_variant_builder_add (&properties_builder, "{sv}",
"window-id",
- g_variant_new_uint64 (id));
+ g_variant_new_uint64 (window_get_id (window)));
if (select->cursor_mode)
{
uint32_t gnome_cursor_mode;
@@ -356,10 +356,10 @@ gnome_screen_cast_session_record_window (GnomeScreenCastSession *gnome_screen_ca
}
static gboolean
-gnome_screen_cast_session_record_monitor (GnomeScreenCastSession *gnome_screen_cast_session,
- const char *connector,
- ScreenCastSelection *select,
- GError **error)
+gnome_screen_cast_session_record_monitor (GnomeScreenCastSession *gnome_screen_cast_session,
+ Monitor *monitor,
+ ScreenCastSelection *select,
+ GError **error)
{
OrgGnomeMutterScreenCastSession *session_proxy =
gnome_screen_cast_session->proxy;
@@ -370,6 +370,7 @@ gnome_screen_cast_session_record_monitor (GnomeScreenCastSession *gnome_screen_c
OrgGnomeMutterScreenCastStream *stream_proxy;
GnomeScreenCastStream *stream;
GVariant *parameters;
+ const char *connector;
g_variant_builder_init (&properties_builder, G_VARIANT_TYPE_VARDICT);
if (select->cursor_mode)
@@ -383,6 +384,7 @@ gnome_screen_cast_session_record_monitor (GnomeScreenCastSession *gnome_screen_c
}
properties = g_variant_builder_end (&properties_builder);
+ connector = monitor_get_connector (monitor);
if (!org_gnome_mutter_screen_cast_session_call_record_monitor_sync (session_proxy,
connector,
properties,
@@ -436,40 +438,29 @@ gnome_screen_cast_session_record_monitor (GnomeScreenCastSession *gnome_screen_c
}
gboolean
-gnome_screen_cast_session_record_selections (GnomeScreenCastSession *gnome_screen_cast_session,
- GVariant *selections,
- ScreenCastSelection *select,
- GError **error)
+gnome_screen_cast_session_record_selections (GnomeScreenCastSession *gnome_screen_cast_session,
+ GPtrArray *streams,
+ ScreenCastSelection *select,
+ GError **error)
{
- GVariantIter selections_iter;
- GVariant *selection;
+ guint i;
- g_variant_iter_init (&selections_iter, selections);
- while ((selection = g_variant_iter_next_value (&selections_iter)))
+ for (i = 0; i < streams->len; i++)
{
- ScreenCastSourceType source_type;
- g_autofree char *key = NULL;
- g_autoptr(GVariant) variant = NULL;
- guint64 id;
+ ScreenCastStreamInfo *info = g_ptr_array_index (streams, i);
- g_variant_get (selection, "(u?)",
- &source_type,
- &variant);
-
- switch (source_type)
+ switch (info->type)
{
case SCREEN_CAST_SOURCE_TYPE_MONITOR:
- key = g_variant_dup_string (variant, NULL);
if (!gnome_screen_cast_session_record_monitor (gnome_screen_cast_session,
- key,
+ info->data.monitor,
select,
error))
return FALSE;
break;
case SCREEN_CAST_SOURCE_TYPE_WINDOW:
- id = g_variant_get_uint64 (variant);
if (!gnome_screen_cast_session_record_window (gnome_screen_cast_session,
- id,
+ info->data.window,
select,
error))
return FALSE;
diff --git a/src/gnomescreencast.h b/src/gnomescreencast.h
index 06e4e1e..748cf7d 100644
--- a/src/gnomescreencast.h
+++ b/src/gnomescreencast.h
@@ -34,10 +34,10 @@ const char * gnome_screen_cast_session_get_stream_path_from_id (GnomeScreenCastS
void gnome_screen_cast_session_add_stream_properties (GnomeScreenCastSession *gnome_screen_cast_session,
GVariantBuilder *streams_builder);
-gboolean gnome_screen_cast_session_record_selections (GnomeScreenCastSession *gnome_screen_cast_session,
- GVariant *selections,
- ScreenCastSelection *select,
- GError **error);
+gboolean gnome_screen_cast_session_record_selections (GnomeScreenCastSession *gnome_screen_cast_session,
+ GPtrArray *streams,
+ ScreenCastSelection *select,
+ GError **error);
gboolean gnome_screen_cast_session_stop (GnomeScreenCastSession *gnome_screen_cast_session,
GError **error);
diff --git a/src/remotedesktop.c b/src/remotedesktop.c
index a1c688a..46d1dcc 100644
--- a/src/remotedesktop.c
+++ b/src/remotedesktop.c
@@ -104,9 +104,10 @@ static void
start_done (RemoteDesktopSession *session);
static gboolean
-start_session (RemoteDesktopSession *session,
- GVariant *selections,
- GError **error);
+start_session (RemoteDesktopSession *session,
+ RemoteDesktopDeviceType device_types,
+ GPtrArray *streams,
+ GError **error);
static void
cancel_start_session (RemoteDesktopSession *session,
@@ -155,9 +156,10 @@ handle_close (XdpImplRequest *object,
}
static void
-remote_desktop_dialog_done (GtkWidget *widget,
- int dialog_response,
- GVariant *selections,
+remote_desktop_dialog_done (GtkWidget *widget,
+ int dialog_response,
+ RemoteDesktopDeviceType device_types,
+ GPtrArray *streams,
RemoteDesktopDialogHandle *dialog_handle)
{
int response;
@@ -184,7 +186,7 @@ remote_desktop_dialog_done (GtkWidget *widget,
{
g_autoptr(GError) error = NULL;
- if (!start_session (dialog_handle->session, selections, &error))
+ if (!start_session (dialog_handle->session, device_types, streams, &error))
{
g_warning ("Failed to start session: %s", error->message);
response = 2;
@@ -453,9 +455,9 @@ on_gnome_screen_cast_session_ready (GnomeScreenCastSession *gnome_screen_cast_se
}
static gboolean
-open_screen_cast_session (RemoteDesktopSession *remote_desktop_session,
- GVariant *source_selections,
- GError **error)
+open_screen_cast_session (RemoteDesktopSession *remote_desktop_session,
+ GPtrArray *streams,
+ GError **error)
{
OrgGnomeMutterRemoteDesktopSession *session_proxy =
remote_desktop_session->mutter_session_proxy;
@@ -478,7 +480,7 @@ open_screen_cast_session (RemoteDesktopSession *remote_desktop_session,
remote_desktop_session);
if (!gnome_screen_cast_session_record_selections (gnome_screen_cast_session,
- source_selections,
+ streams,
&remote_desktop_session->select.screen_cast,
error))
return FALSE;
@@ -487,23 +489,19 @@ open_screen_cast_session (RemoteDesktopSession *remote_desktop_session,
}
static gboolean
-start_session (RemoteDesktopSession *remote_desktop_session,
- GVariant *selections,
- GError **error)
+start_session (RemoteDesktopSession *remote_desktop_session,
+ RemoteDesktopDeviceType device_types,
+ GPtrArray *streams,
+ GError **error)
{
OrgGnomeMutterRemoteDesktopSession *session_proxy;
- RemoteDesktopDeviceType device_types = 0;
- g_autoptr(GVariant) source_selections = NULL;
gboolean need_streams;
- g_variant_lookup (selections, "selected_device_types", "u", &device_types);
remote_desktop_session->shared.device_types = device_types;
- if (g_variant_lookup (selections, "selected_screen_cast_sources", "@a(us)",
- &source_selections))
+ if (streams)
{
- if (!open_screen_cast_session (remote_desktop_session,
- source_selections, error))
+ if (!open_screen_cast_session (remote_desktop_session, streams, error))
return FALSE;
need_streams = TRUE;
diff --git a/src/remotedesktopdialog.c b/src/remotedesktopdialog.c
index a21b008..bae7678 100644
--- a/src/remotedesktopdialog.c
+++ b/src/remotedesktopdialog.c
@@ -61,9 +61,8 @@ static GQuark quark_device_widget_data;
G_DEFINE_TYPE (RemoteDesktopDialog, remote_desktop_dialog, GTK_TYPE_WINDOW)
-static void
-add_device_type_selections (RemoteDesktopDialog *dialog,
- GVariantBuilder *selections_builder)
+static RemoteDesktopDeviceType
+get_selected_device_types (RemoteDesktopDialog *dialog)
{
GList *selected_rows;
GList *l;
@@ -81,43 +80,36 @@ add_device_type_selections (RemoteDesktopDialog *dialog,
}
g_list_free (selected_rows);
- g_variant_builder_add (selections_builder, "{sv}",
- "selected_device_types",
- g_variant_new_uint32 (selected_device_types));
+ return selected_device_types;
}
static void
button_clicked (GtkWidget *button,
RemoteDesktopDialog *dialog)
{
+ RemoteDesktopDeviceType device_types = 0;
+ g_autoptr(GPtrArray) streams = NULL;
int response;
- GVariant *selections;
gtk_widget_hide (GTK_WIDGET (dialog));
if (button == dialog->accept_button)
{
- GVariantBuilder selections_builder;
ScreenCastWidget *screen_cast_widget =
SCREEN_CAST_WIDGET (dialog->screen_cast_widget);
response = GTK_RESPONSE_OK;
-
- g_variant_builder_init (&selections_builder, G_VARIANT_TYPE_VARDICT);
-
- add_device_type_selections (dialog, &selections_builder);
- if (dialog->screen_cast_enable)
- screen_cast_widget_add_selections (screen_cast_widget,
- &selections_builder);
- selections = g_variant_builder_end (&selections_builder);
+ device_types = get_selected_device_types (dialog);
+ streams = screen_cast_widget_get_selected_streams (screen_cast_widget);
}
else
{
response = GTK_RESPONSE_CANCEL;
- selections = NULL;
+ device_types = 0;
+ streams = NULL;
}
- g_signal_emit (dialog, signals[DONE], 0, response, selections);
+ g_signal_emit (dialog, signals[DONE], 0, response, device_types, streams);
}
static void
@@ -356,7 +348,7 @@ remote_desktop_dialog_close_request (GtkWindow *dialog)
{
gtk_widget_hide (GTK_WIDGET (dialog));
- g_signal_emit (dialog, signals[DONE], 0, GTK_RESPONSE_CANCEL, NULL);
+ g_signal_emit (dialog, signals[DONE], 0, GTK_RESPONSE_CANCEL, 0, NULL);
return TRUE;
}
@@ -375,9 +367,10 @@ remote_desktop_dialog_class_init (RemoteDesktopDialogClass *klass)
0,
NULL, NULL,
NULL,
- G_TYPE_NONE, 2,
+ G_TYPE_NONE, 3,
+ G_TYPE_INT,
G_TYPE_INT,
- G_TYPE_VARIANT);
+ G_TYPE_PTR_ARRAY);
init_screen_cast_widget ();
diff --git a/src/screencast.c b/src/screencast.c
index 4ba67aa..2713d26 100644
--- a/src/screencast.c
+++ b/src/screencast.c
@@ -77,11 +77,6 @@ static GnomeScreenCast *gnome_screen_cast;
GType screen_cast_session_get_type (void);
G_DEFINE_TYPE (ScreenCastSession, screen_cast_session, session_get_type ())
-static gboolean
-start_session (ScreenCastSession *session,
- GVariant *selections,
- GError **error);
-
static gboolean
is_screen_cast_session (Session *session)
{
@@ -129,10 +124,76 @@ on_request_handle_close_cb (XdpImplRequest *object,
return FALSE;
}
+static void
+on_gnome_screen_cast_session_ready (GnomeScreenCastSession *gnome_screen_cast_session,
+ ScreenCastSession *screen_cast_session)
+{
+ GVariantBuilder streams_builder;
+ GVariantBuilder results_builder;
+
+ g_variant_builder_init (&results_builder, G_VARIANT_TYPE_VARDICT);
+ g_variant_builder_init (&streams_builder, G_VARIANT_TYPE ("a(ua{sv})"));
+
+ gnome_screen_cast_session = screen_cast_session->gnome_screen_cast_session;
+ gnome_screen_cast_session_add_stream_properties (gnome_screen_cast_session,
+ &streams_builder);
+
+ g_variant_builder_add (&results_builder, "{sv}",
+ "streams",
+ g_variant_builder_end (&streams_builder));
+
+ xdp_impl_screen_cast_complete_start (XDP_IMPL_SCREEN_CAST (impl),
+ screen_cast_session->start_invocation, 0,
+ g_variant_builder_end (&results_builder));
+ screen_cast_session->start_invocation = NULL;
+}
+
+static void
+on_gnome_screen_cast_session_closed (GnomeScreenCastSession *gnome_screen_cast_session,
+ ScreenCastSession *screen_cast_session)
+{
+ session_close ((Session *)screen_cast_session);
+}
+
+static gboolean
+start_session (ScreenCastSession *screen_cast_session,
+ GPtrArray *streams,
+ GError **error)
+{
+ GnomeScreenCastSession *gnome_screen_cast_session;
+
+ gnome_screen_cast_session =
+ gnome_screen_cast_create_session (gnome_screen_cast, NULL, error);
+ if (!gnome_screen_cast_session)
+ return FALSE;
+
+ screen_cast_session->gnome_screen_cast_session = gnome_screen_cast_session;
+
+ screen_cast_session->session_ready_handler_id =
+ g_signal_connect (gnome_screen_cast_session, "ready",
+ G_CALLBACK (on_gnome_screen_cast_session_ready),
+ screen_cast_session);
+ screen_cast_session->session_closed_handler_id =
+ g_signal_connect (gnome_screen_cast_session, "closed",
+ G_CALLBACK (on_gnome_screen_cast_session_closed),
+ screen_cast_session);
+
+ if (!gnome_screen_cast_session_record_selections (gnome_screen_cast_session,
+ streams,
+ &screen_cast_session->select,
+ error))
+ return FALSE;
+
+ if (!gnome_screen_cast_session_start (gnome_screen_cast_session, error))
+ return FALSE;
+
+ return TRUE;
+}
+
static void
on_screen_cast_dialog_done_cb (GtkWidget *widget,
int dialog_response,
- GVariant *selections,
+ GPtrArray *streams,
ScreenCastDialogHandle *dialog_handle)
{
int response;
@@ -159,7 +220,7 @@ on_screen_cast_dialog_done_cb (GtkWidget *widget,
{
g_autoptr(GError) error = NULL;
- if (!start_session (dialog_handle->session, selections, &error))
+ if (!start_session (dialog_handle->session, streams, &error))
{
g_warning ("Failed to start session: %s", error->message);
response = 2;
@@ -234,82 +295,6 @@ create_screen_cast_dialog (ScreenCastSession *session,
return dialog_handle;
}
-static void
-start_done (ScreenCastSession *screen_cast_session)
-{
- GnomeScreenCastSession *gnome_screen_cast_session;
- GVariantBuilder streams_builder;
- GVariantBuilder results_builder;
-
- g_variant_builder_init (&results_builder, G_VARIANT_TYPE_VARDICT);
- g_variant_builder_init (&streams_builder, G_VARIANT_TYPE ("a(ua{sv})"));
-
- gnome_screen_cast_session = screen_cast_session->gnome_screen_cast_session;
- gnome_screen_cast_session_add_stream_properties (gnome_screen_cast_session,
- &streams_builder);
-
- g_variant_builder_add (&results_builder, "{sv}",
- "streams",
- g_variant_builder_end (&streams_builder));
-
- xdp_impl_screen_cast_complete_start (XDP_IMPL_SCREEN_CAST (impl),
- screen_cast_session->start_invocation, 0,
- g_variant_builder_end (&results_builder));
- screen_cast_session->start_invocation = NULL;
-}
-
-static void
-on_gnome_screen_cast_session_ready (GnomeScreenCastSession *gnome_screen_cast_session,
- ScreenCastSession *screen_cast_session)
-{
- start_done (screen_cast_session);
-}
-
-static void
-on_gnome_screen_cast_session_closed (GnomeScreenCastSession *gnome_screen_cast_session,
- ScreenCastSession *screen_cast_session)
-{
- session_close ((Session *)screen_cast_session);
-}
-
-static gboolean
-start_session (ScreenCastSession *screen_cast_session,
- GVariant *selections,
- GError **error)
-{
- GnomeScreenCastSession *gnome_screen_cast_session;
- g_autoptr(GVariant) source_selections = NULL;
-
- gnome_screen_cast_session =
- gnome_screen_cast_create_session (gnome_screen_cast, NULL, error);
- if (!gnome_screen_cast_session)
- return FALSE;
-
- screen_cast_session->gnome_screen_cast_session = gnome_screen_cast_session;
-
- screen_cast_session->session_ready_handler_id =
- g_signal_connect (gnome_screen_cast_session, "ready",
- G_CALLBACK (on_gnome_screen_cast_session_ready),
- screen_cast_session);
- screen_cast_session->session_closed_handler_id =
- g_signal_connect (gnome_screen_cast_session, "closed",
- G_CALLBACK (on_gnome_screen_cast_session_closed),
- screen_cast_session);
-
- g_variant_lookup (selections, "selected_screen_cast_sources", "@a(u?)",
- &source_selections);
- if (!gnome_screen_cast_session_record_selections (gnome_screen_cast_session,
- source_selections,
- &screen_cast_session->select,
- error))
- return FALSE;
-
- if (!gnome_screen_cast_session_start (gnome_screen_cast_session, error))
- return FALSE;
-
- return TRUE;
-}
-
static gboolean
handle_start (XdpImplScreenCast *object,
GDBusMethodInvocation *invocation,
diff --git a/src/screencast.h b/src/screencast.h
index f5033b2..a9be16b 100644
--- a/src/screencast.h
+++ b/src/screencast.h
@@ -21,6 +21,9 @@
#include <glib.h>
#include <gio/gio.h>
+#include "displaystatetracker.h"
+#include "shellintrospect.h"
+
typedef enum _ScreenCastSourceType
{
SCREEN_CAST_SOURCE_TYPE_MONITOR = 1,
@@ -42,5 +45,14 @@ typedef struct _ScreenCastSelection
ScreenCastCursorMode cursor_mode;
} ScreenCastSelection;
+typedef struct
+{
+ ScreenCastSourceType type;
+ union {
+ Monitor *monitor;
+ Window *window;
+ } data;
+} ScreenCastStreamInfo;
+
gboolean screen_cast_init (GDBusConnection *connection,
GError **error);
diff --git a/src/screencastdialog.c b/src/screencastdialog.c
index 56d4d49..3e3b064 100644
--- a/src/screencastdialog.c
+++ b/src/screencastdialog.c
@@ -59,8 +59,8 @@ static void
button_clicked (GtkWidget *button,
ScreenCastDialog *dialog)
{
+ g_autoptr(GPtrArray) streams = NULL;
int response;
- GVariant *selections;
gtk_widget_hide (GTK_WIDGET (dialog));
@@ -68,22 +68,17 @@ button_clicked (GtkWidget *button,
{
ScreenCastWidget *screen_cast_widget =
SCREEN_CAST_WIDGET (dialog->screen_cast_widget);
- GVariantBuilder selections_builder;
response = GTK_RESPONSE_OK;
-
- g_variant_builder_init (&selections_builder, G_VARIANT_TYPE ("a{sv}"));
- screen_cast_widget_add_selections (screen_cast_widget,
- &selections_builder);
- selections = g_variant_builder_end (&selections_builder);
+ streams = screen_cast_widget_get_selected_streams (screen_cast_widget);
}
else
{
response = GTK_RESPONSE_CANCEL;
- selections = NULL;
+ streams = NULL;
}
- g_signal_emit (dialog, signals[DONE], 0, response, selections);
+ g_signal_emit (dialog, signals[DONE], 0, response, streams);
}
static void
@@ -127,7 +122,7 @@ screen_cast_dialog_class_init (ScreenCastDialogClass *klass)
NULL,
G_TYPE_NONE, 2,
G_TYPE_INT,
- G_TYPE_VARIANT);
+ G_TYPE_PTR_ARRAY);
init_screen_cast_widget ();
diff --git a/src/screencastwidget.c b/src/screencastwidget.c
index 454c93e..3119245 100644
--- a/src/screencastwidget.c
+++ b/src/screencastwidget.c
@@ -69,51 +69,6 @@ G_DEFINE_TYPE (ScreenCastWidget, screen_cast_widget, GTK_TYPE_BOX)
* Auxiliary methods
*/
-static gboolean
-add_selections (ScreenCastWidget *widget,
- GVariantBuilder *source_selections_builder)
-{
- GList *selected_monitor_rows;
- GList *selected_window_rows;
- GList *l;
-
- 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 FALSE;
-
- 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_variant_builder_add (source_selections_builder, "(us)",
- SCREEN_CAST_SOURCE_TYPE_MONITOR,
- monitor_get_connector (monitor));
- }
- g_list_free (selected_monitor_rows);
- 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);
-
- return TRUE;
-}
-
static GtkWidget *
create_window_widget (Window *window)
{
@@ -571,25 +526,6 @@ init_screen_cast_widget (void)
g_type_ensure (screen_cast_widget_get_type ());
}
-void
-screen_cast_widget_add_selections (ScreenCastWidget *widget,
- GVariantBuilder *selections_builder)
-{
- GVariantBuilder source_selections_builder;
-
- g_variant_builder_init (&source_selections_builder, G_VARIANT_TYPE ("a(u?)"));
- if (!add_selections (widget, &source_selections_builder))
- {
- g_variant_builder_clear (&source_selections_builder);
- }
- else
- {
- g_variant_builder_add (selections_builder, "{sv}",
- "selected_screen_cast_sources",
- g_variant_builder_end (&source_selections_builder));
- }
-}
-
void
screen_cast_widget_set_app_id (ScreenCastWidget *widget,
const char *app_id)
@@ -649,3 +585,53 @@ screen_cast_widget_set_source_types (ScreenCastWidget *screen_cast_widget,
if (__builtin_popcount (source_types) > 1)
gtk_widget_show (screen_cast_widget->source_type_switcher);
}
+
+GPtrArray *
+screen_cast_widget_get_selected_streams (ScreenCastWidget *self)
+{
+ ScreenCastStreamInfo *info;
+ g_autoptr(GPtrArray) streams = NULL;
+ g_autoptr(GList) selected_monitor_rows = NULL;
+ g_autoptr(GList) selected_window_rows = NULL;
+ GList *l;
+
+ streams = g_ptr_array_new_with_free_func (g_free);
+
+ selected_monitor_rows =
+ gtk_list_box_get_selected_rows (GTK_LIST_BOX (self->monitor_list));
+ selected_window_rows =
+ gtk_list_box_get_selected_rows (GTK_LIST_BOX (self->window_list));
+
+ if (!selected_monitor_rows && !selected_window_rows)
+ return g_steal_pointer (&streams);
+
+ 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);
+
+ info = g_new0 (ScreenCastStreamInfo, 1);
+ info->type = SCREEN_CAST_SOURCE_TYPE_MONITOR;
+ info->data.monitor = monitor;
+ g_ptr_array_add (streams, info);
+ }
+
+ 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);
+
+ info = g_new0 (ScreenCastStreamInfo, 1);
+ info->type = SCREEN_CAST_SOURCE_TYPE_WINDOW;
+ info->data.window = window;
+ g_ptr_array_add (streams, info);
+ }
+
+ return g_steal_pointer (&streams);
+}
diff --git a/src/screencastwidget.h b/src/screencastwidget.h
index 34360a3..ad95903 100644
--- a/src/screencastwidget.h
+++ b/src/screencastwidget.h
@@ -39,5 +39,4 @@ 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_add_selections (ScreenCastWidget *widget,
- GVariantBuilder *selections_builder);
+GPtrArray *screen_cast_widget_get_selected_streams (ScreenCastWidget *self);

View File

@ -0,0 +1,90 @@
From 36594e191980d84ca77ba09faddf3f160a9839cf Mon Sep 17 00:00:00 2001
From: Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
Date: Tue, 28 Sep 2021 21:00:35 -0300
Subject: [PATCH] displaystatetracker: Add match string
The monitor's match string is a unique string that can be used to compare
monitors and check for equality. It's composed of the product, vendor, and
serial numbers. It'll be used by the next commit to restore sessions.
---
src/displaystatetracker.c | 18 +++++++++++++++---
src/displaystatetracker.h | 2 ++
2 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/src/displaystatetracker.c b/src/displaystatetracker.c
index 6affd8a..fc9109e 100644
--- a/src/displaystatetracker.c
+++ b/src/displaystatetracker.c
@@ -35,6 +35,7 @@ static guint signals[N_SIGNALS];
typedef struct _Monitor
{
char *connector;
+ char *match_string;
char *display_name;
} Monitor;
@@ -65,6 +66,7 @@ static void
monitor_free (Monitor *monitor)
{
g_free (monitor->connector);
+ g_free (monitor->match_string);
g_free (monitor->display_name);
g_free (monitor);
}
@@ -75,6 +77,12 @@ monitor_get_connector (Monitor *monitor)
return monitor->connector;
}
+const char *
+monitor_get_match_string (Monitor *monitor)
+{
+ return monitor->match_string;
+}
+
const char *
monitor_get_display_name (Monitor *monitor)
{
@@ -109,6 +117,9 @@ generate_monitors (DisplayStateTracker *tracker,
g_variant_iter_init (&monitors_iter, monitors);
while ((monitor_variant = g_variant_iter_next_value (&monitors_iter)))
{
+ g_autofree char *vendor = NULL;
+ g_autofree char *product = NULL;
+ g_autofree char *serial = NULL;
Monitor *monitor;
char *connector;
char *display_name;
@@ -116,9 +127,9 @@ generate_monitors (DisplayStateTracker *tracker,
g_variant_get (monitor_variant, "((ssss)a(siiddada{sv})@a{sv})",
&connector,
- NULL /* vendor */,
- NULL /* product */,
- NULL /* serial */,
+ &vendor,
+ &product,
+ &serial,
NULL /* modes */,
&properties);
@@ -128,6 +139,7 @@ generate_monitors (DisplayStateTracker *tracker,
monitor = g_new0 (Monitor, 1);
*monitor = (Monitor) {
.connector = connector,
+ .match_string = g_strdup_printf ("%s:%s:%s", vendor, product, serial),
.display_name = display_name
};
diff --git a/src/displaystatetracker.h b/src/displaystatetracker.h
index 54c63fa..1c3a7dc 100644
--- a/src/displaystatetracker.h
+++ b/src/displaystatetracker.h
@@ -28,6 +28,8 @@ G_DECLARE_FINAL_TYPE (DisplayStateTracker, display_state_tracker,
const char * monitor_get_connector (Monitor *monitor);
+const char * monitor_get_match_string (Monitor *monitor);
+
const char * monitor_get_display_name (Monitor *monitor);
GList * logical_monitor_get_monitors (LogicalMonitor *logical_monitor);

View File

@ -0,0 +1,724 @@
From af25561e0f4e5aa2c3460ce7448b0c580f28532a Mon Sep 17 00:00:00 2001
From: Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
Date: Tue, 28 Sep 2021 21:04:28 -0300
Subject: [PATCH] Implement screencast stream restoration
Handle receiving 'restore_data' and 'persist_mode'.
For monitors, use the match string introduced by the previous
commit to identify individual monitors. For windows, do a strict
check on the app id, and a best-match approach to window titles.
Virtual monitors don't have any particular data attached to them,
so they are merely stored as "virtual" and restored.
---
src/screencast.c | 327 +++++++++++++++++++++++++++++++++++++++-
src/screencast.h | 7 +
src/screencastdialog.c | 14 +-
src/screencastdialog.h | 5 +-
src/screencastwidget.c | 23 +++
src/screencastwidget.h | 6 +
src/screencastwidget.ui | 8 +
src/utils.c | 77 ++++++++++
src/utils.h | 3 +
9 files changed, 456 insertions(+), 14 deletions(-)
diff --git a/src/screencast.c b/src/screencast.c
index 2713d26..55a3e5c 100644
--- a/src/screencast.c
+++ b/src/screencast.c
@@ -33,8 +33,15 @@
#include "externalwindow.h"
#include "request.h"
#include "session.h"
+#include "shellintrospect.h"
#include "utils.h"
+#define RESTORE_FORMAT_VERSION 1
+#define RESTORE_VARIANT_TYPE "(xxa(uuv))"
+#define MONITOR_TYPE "s"
+#define WINDOW_TYPE "(ss)"
+#define VIRTUAL_TYPE "b"
+
typedef struct _ScreenCastDialogHandle ScreenCastDialogHandle;
typedef struct _ScreenCastSession
@@ -49,6 +56,13 @@ typedef struct _ScreenCastSession
ScreenCastSelection select;
+ ScreenCastPersistMode persist_mode;
+ GPtrArray *streams_to_restore;
+ struct {
+ GVariant *data;
+ int64_t creation_time;
+ } restored;
+
GDBusMethodInvocation *start_invocation;
ScreenCastDialogHandle *dialog_handle;
} ScreenCastSession;
@@ -99,6 +113,68 @@ screen_cast_dialog_handle_close (ScreenCastDialogHandle *dialog_handle)
screen_cast_dialog_handle_free (dialog_handle);
}
+static GVariant *
+serialize_streams_as_restore_data (ScreenCastSession *screen_cast_session,
+ GPtrArray *streams)
+{
+ GVariantBuilder restore_data_builder;
+ GVariantBuilder impl_builder;
+ int64_t creation_time;
+ int64_t last_used_time;
+ guint i;
+
+ if (!streams || streams->len == 0)
+ return NULL;
+
+ last_used_time = g_get_real_time ();
+ if (screen_cast_session->restored.creation_time != -1)
+ creation_time = screen_cast_session->restored.creation_time;
+ else
+ creation_time = g_get_real_time ();
+
+ g_variant_builder_init (&impl_builder, G_VARIANT_TYPE (RESTORE_VARIANT_TYPE));
+ g_variant_builder_add (&impl_builder, "x", creation_time);
+ g_variant_builder_add (&impl_builder, "x", last_used_time);
+
+ g_variant_builder_open (&impl_builder, G_VARIANT_TYPE ("a(uuv)"));
+ for (i = 0; i < streams->len; i++)
+ {
+ ScreenCastStreamInfo *info = g_ptr_array_index (streams, i);
+ GVariant *stream_variant;
+ Monitor *monitor;
+ Window *window;
+
+ switch (info->type)
+ {
+ case SCREEN_CAST_SOURCE_TYPE_MONITOR:
+ monitor = info->data.monitor;
+ stream_variant = g_variant_new (MONITOR_TYPE,
+ monitor_get_match_string (monitor));
+ break;
+
+ case SCREEN_CAST_SOURCE_TYPE_WINDOW:
+ window = info->data.window;
+ stream_variant = g_variant_new (WINDOW_TYPE,
+ window_get_app_id (window),
+ window_get_title (window));
+ break;
+ }
+
+ g_variant_builder_add (&impl_builder,
+ "(uuv)",
+ i,
+ info->type,
+ stream_variant);
+ }
+ g_variant_builder_close (&impl_builder);
+
+ g_variant_builder_init (&restore_data_builder, G_VARIANT_TYPE ("(suv)"));
+ g_variant_builder_add (&restore_data_builder, "s", "GNOME");
+ g_variant_builder_add (&restore_data_builder, "u", RESTORE_FORMAT_VERSION);
+ g_variant_builder_add (&restore_data_builder, "v", g_variant_builder_end (&impl_builder));
+ return g_variant_builder_end (&restore_data_builder);
+}
+
static void
cancel_start_session (ScreenCastSession *screen_cast_session,
int response)
@@ -142,6 +218,22 @@ on_gnome_screen_cast_session_ready (GnomeScreenCastSession *gnome_screen_cast_se
"streams",
g_variant_builder_end (&streams_builder));
+ if (screen_cast_session->persist_mode != SCREEN_CAST_PERSIST_MODE_NONE)
+ {
+ g_autoptr(GPtrArray) streams = g_steal_pointer (&screen_cast_session->streams_to_restore);
+ GVariant *restore_data;
+
+ restore_data = serialize_streams_as_restore_data (screen_cast_session, streams);
+
+ if (restore_data)
+ {
+ g_variant_builder_add (&results_builder, "{sv}", "persist_mode",
+ g_variant_new_uint32 (screen_cast_session->persist_mode));
+ g_variant_builder_add (&results_builder, "{sv}", "restore_data",
+ g_variant_new_variant (restore_data));
+ }
+ }
+
xdp_impl_screen_cast_complete_start (XDP_IMPL_SCREEN_CAST (impl),
screen_cast_session->start_invocation, 0,
g_variant_builder_end (&results_builder));
@@ -178,6 +270,9 @@ start_session (ScreenCastSession *screen_cast_session,
G_CALLBACK (on_gnome_screen_cast_session_closed),
screen_cast_session);
+ if (screen_cast_session->persist_mode != SCREEN_CAST_PERSIST_MODE_NONE)
+ screen_cast_session->streams_to_restore = g_ptr_array_ref (streams);
+
if (!gnome_screen_cast_session_record_selections (gnome_screen_cast_session,
streams,
&screen_cast_session->select,
@@ -193,6 +288,7 @@ start_session (ScreenCastSession *screen_cast_session,
static void
on_screen_cast_dialog_done_cb (GtkWidget *widget,
int dialog_response,
+ ScreenCastPersistMode persist_mode,
GPtrArray *streams,
ScreenCastDialogHandle *dialog_handle)
{
@@ -218,8 +314,12 @@ on_screen_cast_dialog_done_cb (GtkWidget *widget,
if (response == 0)
{
+ ScreenCastSession *screen_cast_session = dialog_handle->session;
g_autoptr(GError) error = NULL;
+ screen_cast_session->persist_mode = MIN (screen_cast_session->persist_mode,
+ persist_mode);
+
if (!start_session (dialog_handle->session, streams, &error))
{
g_warning ("Failed to start session: %s", error->message);
@@ -269,7 +369,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);
@@ -295,6 +396,161 @@ create_screen_cast_dialog (ScreenCastSession *session,
return dialog_handle;
}
+static Monitor *
+find_monitor_by_string (const char *monitor_string)
+{
+ DisplayStateTracker *display_state_tracker = display_state_tracker_get ();
+ GList *l;
+
+ for (l = display_state_tracker_get_logical_monitors (display_state_tracker);
+ l;
+ l = l->next)
+ {
+ LogicalMonitor *logical_monitor = l->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 Window *
+find_best_window_by_app_id_and_title (const char *app_id,
+ const char *title)
+{
+ ShellIntrospect *shell_introspect = shell_introspect_get ();
+ Window *best_match;
+ glong best_match_distance;
+ GList *l;
+
+ best_match = NULL;
+ best_match_distance = G_MAXLONG;
+
+ for (l = shell_introspect_get_windows (shell_introspect); l; l = l->next)
+ {
+ Window *window = l->data;
+ glong distance;
+
+ if (g_strcmp0 (window_get_app_id (window), app_id) != 0)
+ continue;
+
+ distance = str_distance (window_get_title (window), title);
+
+ if (distance == 0)
+ return window;
+
+ if (distance < best_match_distance)
+ {
+ best_match = window;
+ best_match_distance = distance;
+ }
+ }
+
+ return best_match;
+}
+
+static gboolean
+restore_stream_from_data (ScreenCastSession *screen_cast_session)
+
+{
+ ScreenCastStreamInfo *info;
+ g_autoptr(GVariantIter) array_iter = NULL;
+ g_autoptr(GPtrArray) streams = NULL;
+ g_autoptr(GError) error = NULL;
+ ScreenCastSourceType source_type;
+ GVariant *data;
+ uint32_t id;
+ int64_t creation_time;
+ int64_t last_used_time;
+
+ if (!screen_cast_session->restored.data)
+ return FALSE;
+
+ streams = g_ptr_array_new_with_free_func (g_free);
+
+ g_variant_get (screen_cast_session->restored.data,
+ RESTORE_VARIANT_TYPE,
+ &creation_time,
+ &last_used_time,
+ &array_iter);
+
+ while (g_variant_iter_next (array_iter, "(uuv)", &id, &source_type, &data))
+ {
+ switch (source_type)
+ {
+ case SCREEN_CAST_SOURCE_TYPE_MONITOR:
+ {
+ if (!(screen_cast_session->select.source_types & SCREEN_CAST_SOURCE_TYPE_MONITOR) ||
+ !g_variant_check_format_string (data, MONITOR_TYPE, FALSE))
+ goto fail;
+
+ const char *match_string = g_variant_get_string (data, NULL);
+ Monitor *monitor = find_monitor_by_string (match_string);
+
+ if (!monitor)
+ goto fail;
+
+ info = g_new0 (ScreenCastStreamInfo, 1);
+ info->type = SCREEN_CAST_SOURCE_TYPE_MONITOR;
+ info->data.monitor = monitor;
+ g_ptr_array_add (streams, info);
+ }
+ break;
+
+ case SCREEN_CAST_SOURCE_TYPE_WINDOW:
+ {
+ if (!(screen_cast_session->select.source_types & SCREEN_CAST_SOURCE_TYPE_WINDOW) ||
+ !g_variant_check_format_string (data, WINDOW_TYPE, FALSE))
+ goto fail;
+
+ const char *app_id = NULL;
+ const char *title = NULL;
+ Window *window;
+
+ g_variant_get (data, "(&s&s)", &app_id, &title);
+
+ window = find_best_window_by_app_id_and_title (app_id, title);
+
+ if (!window)
+ goto fail;
+
+ info = g_new0 (ScreenCastStreamInfo, 1);
+ info->type = SCREEN_CAST_SOURCE_TYPE_WINDOW;
+ info->data.window = window;
+ g_ptr_array_add (streams, info);
+ }
+ break;
+
+ default:
+ goto fail;
+ }
+ }
+
+ screen_cast_session->restored.creation_time = creation_time;
+
+ start_session (screen_cast_session, streams, &error);
+
+ if (error)
+ {
+ g_warning ("Error restoring stream from session: %s", error->message);
+ return FALSE;
+ }
+
+ return TRUE;
+
+fail:
+ return FALSE;
+}
+
static gboolean
handle_start (XdpImplScreenCast *object,
GDBusMethodInvocation *invocation,
@@ -307,7 +563,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);
@@ -329,14 +584,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;
- screen_cast_session->start_invocation = invocation;
- screen_cast_session->dialog_handle = dialog_handle;
+ dialog_handle = create_screen_cast_dialog (screen_cast_session,
+ invocation,
+ request,
+ arg_parent_window);
+
+ screen_cast_session->dialog_handle = dialog_handle;
+ }
return TRUE;
@@ -356,6 +616,9 @@ handle_select_sources (XdpImplScreenCast *object,
const char *arg_app_id,
GVariant *arg_options)
{
+ g_autofree gchar *provider = NULL;
+ g_autoptr(GVariant) restore_data = NULL;
+ ScreenCastSession *screen_cast_session;
Session *session;
int response;
uint32_t types;
@@ -364,6 +627,7 @@ handle_select_sources (XdpImplScreenCast *object,
ScreenCastSelection select;
GVariantBuilder results_builder;
GVariant *results;
+ uint32_t version;
session = lookup_session (arg_session_handle);
if (!session)
@@ -427,6 +691,21 @@ 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);
+
+ if (g_variant_lookup (arg_options, "restore_data", "(suv)", &provider, &version, &restore_data))
+ {
+ if (!g_variant_check_format_string (restore_data, "(suv)", FALSE))
+ {
+ g_warning ("Cannot parse restore data, ignoring");
+ goto out;
+ }
+
+ if (g_strcmp0 (provider, "GNOME") == 0 && version == RESTORE_FORMAT_VERSION)
+ screen_cast_session->restored.data = g_variant_ref (restore_data);
+ }
+
out:
g_variant_builder_init (&results_builder, G_VARIANT_TYPE_VARDICT);
results = g_variant_builder_end (&results_builder);
@@ -567,6 +846,8 @@ screen_cast_session_finalize (GObject *object)
{
ScreenCastSession *screen_cast_session = (ScreenCastSession *)object;
+ g_clear_pointer (&screen_cast_session->streams_to_restore, g_ptr_array_unref);
+ g_clear_pointer (&screen_cast_session->restored.data, g_variant_unref);
g_clear_object (&screen_cast_session->gnome_screen_cast_session);
G_OBJECT_CLASS (screen_cast_session_parent_class)->finalize (object);
@@ -575,6 +856,8 @@ screen_cast_session_finalize (GObject *object)
static void
screen_cast_session_init (ScreenCastSession *screen_cast_session)
{
+ screen_cast_session->persist_mode = SCREEN_CAST_PERSIST_MODE_NONE;
+ screen_cast_session->restored.creation_time = -1;
}
static void
@@ -594,6 +877,14 @@ gboolean
screen_cast_init (GDBusConnection *connection,
GError **error)
{
+ /*
+ * Ensure ShellIntrospect and DisplayStateTracker are initialized before
+ * any screencast session is created to avoid race conditions when restoring
+ * previous streams.
+ */
+ display_state_tracker_get ();
+ shell_introspect_get ();
+
impl_connection = connection;
gnome_screen_cast = gnome_screen_cast_new (connection);
diff --git a/src/screencast.h b/src/screencast.h
index a9be16b..d78066e 100644
--- a/src/screencast.h
+++ b/src/screencast.h
@@ -38,6 +38,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 3e3b064..d80329e 100644
--- a/src/screencastdialog.c
+++ b/src/screencastdialog.c
@@ -59,6 +59,7 @@ static void
button_clicked (GtkWidget *button,
ScreenCastDialog *dialog)
{
+ ScreenCastPersistMode persist_mode;
g_autoptr(GPtrArray) streams = NULL;
int response;
@@ -71,14 +72,16 @@ button_clicked (GtkWidget *button,
response = GTK_RESPONSE_OK;
streams = screen_cast_widget_get_selected_streams (screen_cast_widget);
+ persist_mode = screen_cast_widget_get_persist_mode (screen_cast_widget);
}
else
{
response = GTK_RESPONSE_CANCEL;
+ persist_mode = SCREEN_CAST_PERSIST_MODE_NONE;
streams = NULL;
}
- g_signal_emit (dialog, signals[DONE], 0, response, streams);
+ g_signal_emit (dialog, signals[DONE], 0, response, persist_mode, streams);
}
static void
@@ -120,7 +123,8 @@ screen_cast_dialog_class_init (ScreenCastDialogClass *klass)
0,
NULL, NULL,
NULL,
- G_TYPE_NONE, 2,
+ G_TYPE_NONE, 3,
+ G_TYPE_INT,
G_TYPE_INT,
G_TYPE_PTR_ARRAY);
@@ -143,8 +147,9 @@ screen_cast_dialog_init (ScreenCastDialog *dialog)
}
ScreenCastDialog *
-screen_cast_dialog_new (const char *app_id,
- ScreenCastSelection *select)
+screen_cast_dialog_new (const char *app_id,
+ ScreenCastSelection *select,
+ ScreenCastPersistMode persist_mode)
{
ScreenCastDialog *dialog;
ScreenCastWidget *screen_cast_widget;
@@ -155,6 +160,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;
}
diff --git a/src/screencastdialog.h b/src/screencastdialog.h
index 1fca470..c132ecf 100644
--- a/src/screencastdialog.h
+++ b/src/screencastdialog.h
@@ -26,5 +26,6 @@
G_DECLARE_FINAL_TYPE (ScreenCastDialog, screen_cast_dialog,
SCREEN_CAST, DIALOG, GtkWindow)
-ScreenCastDialog * screen_cast_dialog_new (const char *app_id,
- ScreenCastSelection *select);
+ScreenCastDialog * screen_cast_dialog_new (const char *app_id,
+ ScreenCastSelection *select,
+ ScreenCastPersistMode persist_mode);
diff --git a/src/screencastwidget.c b/src/screencastwidget.c
index 3119245..c100ad9 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;
@@ -454,6 +457,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);
@@ -635,3 +639,22 @@ screen_cast_widget_get_selected_streams (ScreenCastWidget *self)
return g_steal_pointer (&streams);
}
+
+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_NONE);
+}
+
+ScreenCastPersistMode
+screen_cast_widget_get_persist_mode (ScreenCastWidget *screen_cast_widget)
+{
+ if (!gtk_check_button_get_active (screen_cast_widget->persist_check))
+ return SCREEN_CAST_PERSIST_MODE_NONE;
+
+ return screen_cast_widget->persist_mode;
+}
diff --git a/src/screencastwidget.h b/src/screencastwidget.h
index ad95903..a963f99 100644
--- a/src/screencastwidget.h
+++ b/src/screencastwidget.h
@@ -40,3 +40,9 @@ void screen_cast_widget_set_source_types (ScreenCastWidget *screen_cast_widg
ScreenCastSourceType source_types);
GPtrArray *screen_cast_widget_get_selected_streams (ScreenCastWidget *self);
+
+void screen_cast_widget_set_persist_mode (ScreenCastWidget *screen_cast_widget,
+ ScreenCastPersistMode persist_mode);
+
+ScreenCastPersistMode
+screen_cast_widget_get_persist_mode (ScreenCastWidget *screen_cast_widget);
diff --git a/src/screencastwidget.ui b/src/screencastwidget.ui
index fb83b94..0a9028e 100644
--- a/src/screencastwidget.ui
+++ b/src/screencastwidget.ui
@@ -152,5 +152,13 @@
</child>
</object>
</child>
+
+ <!-- Persist permission -->
+ <child>
+ <object class="GtkCheckButton" id="persist_check">
+ <property name="active">True</property>
+ <property name="label" translatable="yes">Remember this selection</property>
+ </object>
+ </child>
</template>
</interface>
diff --git a/src/utils.c b/src/utils.c
index b7dd472..5e0485c 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -45,3 +45,80 @@ xdg_desktop_portal_error_quark (void)
G_N_ELEMENTS (xdg_desktop_portal_error_entries));
return (GQuark) quark_volatile;
}
+
+glong
+str_distance (const char *a,
+ const char *b)
+{
+ g_autofree gint *v0 = NULL;
+ g_autofree gint *v1 = NULL;
+ const gchar *s;
+ const gchar *t;
+ gunichar sc;
+ gunichar tc;
+ glong b_char_len;
+ glong cost;
+ glong i;
+ glong j;
+
+ /*
+ * Handle degenerate cases.
+ */
+ if (g_strcmp0 (a, b) == 0)
+ return 0;
+ else if (!*a)
+ return g_utf8_strlen (a, -1);
+ else if (!*b)
+ return g_utf8_strlen (a, -1);
+
+ b_char_len = g_utf8_strlen (b, -1);
+
+ /*
+ * Create two vectors to hold our states.
+ */
+
+ v0 = g_new0 (gint, b_char_len + 1);
+ v1 = g_new0 (gint, b_char_len + 1);
+
+ /*
+ * initialize v0 (the previous row of distances).
+ * this row is A[0][i]: edit distance for an empty a.
+ * the distance is just the number of characters to delete from b.
+ */
+ for (i = 0; i < b_char_len + 1; i++)
+ v0[i] = i;
+
+ for (i = 0, s = a; s && *s; i++, s = g_utf8_next_char(s))
+ {
+ /*
+ * Calculate v1 (current row distances) from the previous row v0.
+ */
+
+ sc = g_utf8_get_char(s);
+
+ /*
+ * first element of v1 is A[i+1][0]
+ *
+ * edit distance is delete (i+1) chars from a to match empty
+ * b.
+ */
+ v1[0] = i + 1;
+
+ /*
+ * use formula to fill in the rest of the row.
+ */
+ for (j = 0, t = b; t && *t; j++, t = g_utf8_next_char(t))
+ {
+ tc = g_utf8_get_char(t);
+ cost = (sc == tc) ? 0 : 1;
+ v1[j+1] = MIN (v1[j] + 1, MIN (v0[j+1] + 1, v0[j] + cost));
+ }
+
+ /*
+ * copy v1 (current row) to v0 (previous row) for next iteration.
+ */
+ memcpy (v0, v1, sizeof(gint) * b_char_len);
+ }
+
+ return v1[b_char_len];
+}
diff --git a/src/utils.h b/src/utils.h
index 5fdfda9..fa3f1b0 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -37,3 +37,6 @@ typedef enum {
#define XDG_DESKTOP_PORTAL_ERROR xdg_desktop_portal_error_quark ()
GQuark xdg_desktop_portal_error_quark (void);
+
+glong str_distance (const char *a,
+ const char *b);

View File

@ -0,0 +1,166 @@
From c865ffdb24d1a945f36a1bf873fe0900cbbade14 Mon Sep 17 00:00:00 2001
From: Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
Date: Thu, 11 Nov 2021 00:05:27 -0300
Subject: [PATCH] screencast: Pass stream ids
The stream id is any string that can uniquely
identify a stream within a screencast session.
Add that to the list of stream properties.
For now, only use a simple positional integer
as id.
---
src/gnomescreencast.c | 21 ++++++++++++++++++---
src/screencast.c | 5 ++++-
src/screencast.h | 1 +
src/screencastwidget.c | 4 ++++
4 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/src/gnomescreencast.c b/src/gnomescreencast.c
index 3f8539c..482fcd0 100644
--- a/src/gnomescreencast.c
+++ b/src/gnomescreencast.c
@@ -59,6 +59,7 @@ typedef struct _GnomeScreenCastStream
ScreenCastSourceType source_type;
+ uint32_t id;
char *path;
OrgGnomeMutterScreenCastStream *proxy;
@@ -219,6 +220,7 @@ void
gnome_screen_cast_session_add_stream_properties (GnomeScreenCastSession *gnome_screen_cast_session,
GVariantBuilder *streams_builder)
{
+ char id[64] = { 0, };
GList *streams;
GList *l;
@@ -234,6 +236,10 @@ gnome_screen_cast_session_add_stream_properties (GnomeScreenCastSession *gnome_s
g_variant_builder_init (&stream_properties_builder, G_VARIANT_TYPE_VARDICT);
+ g_snprintf (id, G_N_ELEMENTS (id), "%u", stream->id);
+ g_variant_builder_add (&stream_properties_builder, "{sv}",
+ "id",
+ g_variant_new ("s", id));
g_variant_builder_add (&stream_properties_builder, "{sv}",
"source_type",
g_variant_new ("u", stream->source_type));
@@ -275,6 +281,7 @@ cursor_mode_to_gnome_cursor_mode (ScreenCastCursorMode cursor_mode)
static gboolean
gnome_screen_cast_session_record_window (GnomeScreenCastSession *gnome_screen_cast_session,
+ uint32_t id,
Window *window,
ScreenCastSelection *select,
GError **error)
@@ -327,6 +334,7 @@ gnome_screen_cast_session_record_window (GnomeScreenCastSession *gnome_screen_c
stream->session = gnome_screen_cast_session;
stream->path = g_strdup (stream_path);
stream->proxy = stream_proxy;
+ stream->id = id;
parameters = org_gnome_mutter_screen_cast_stream_get_parameters (stream->proxy);
if (parameters)
@@ -357,6 +365,7 @@ gnome_screen_cast_session_record_window (GnomeScreenCastSession *gnome_screen_c
static gboolean
gnome_screen_cast_session_record_monitor (GnomeScreenCastSession *gnome_screen_cast_session,
+ uint32_t id,
Monitor *monitor,
ScreenCastSelection *select,
GError **error)
@@ -409,6 +418,7 @@ gnome_screen_cast_session_record_monitor (GnomeScreenCastSession *gnome_screen_
stream->session = gnome_screen_cast_session;
stream->path = g_strdup (stream_path);
stream->proxy = stream_proxy;
+ stream->id = id;
parameters = org_gnome_mutter_screen_cast_stream_get_parameters (stream->proxy);
if (parameters)
@@ -453,6 +463,7 @@ gnome_screen_cast_session_record_selections (GnomeScreenCastSession *gnome_scre
{
case SCREEN_CAST_SOURCE_TYPE_MONITOR:
if (!gnome_screen_cast_session_record_monitor (gnome_screen_cast_session,
+ info->id,
info->data.monitor,
select,
error))
@@ -460,6 +471,7 @@ gnome_screen_cast_session_record_selections (GnomeScreenCastSession *gnome_scre
break;
case SCREEN_CAST_SOURCE_TYPE_WINDOW:
if (!gnome_screen_cast_session_record_window (gnome_screen_cast_session,
+ info->id,
info->data.window,
select,
error))
diff --git a/src/screencast.c b/src/screencast.c
index 55a3e5c..3be8337 100644
--- a/src/screencast.c
+++ b/src/screencast.c
@@ -162,7 +162,7 @@ serialize_streams_as_restore_data (ScreenCastSession *screen_cast_session,
g_variant_builder_add (&impl_builder,
"(uuv)",
- i,
+ info->id,
info->type,
stream_variant);
}
@@ -502,6 +502,7 @@ restore_stream_from_data (ScreenCastSession *screen_cast_session)
info = g_new0 (ScreenCastStreamInfo, 1);
info->type = SCREEN_CAST_SOURCE_TYPE_MONITOR;
info->data.monitor = monitor;
+ info->id = id;
g_ptr_array_add (streams, info);
}
break;
@@ -526,6 +527,7 @@ restore_stream_from_data (ScreenCastSession *screen_cast_session)
info = g_new0 (ScreenCastStreamInfo, 1);
info->type = SCREEN_CAST_SOURCE_TYPE_WINDOW;
info->data.window = window;
+ info->id = id;
g_ptr_array_add (streams, info);
}
break;
diff --git a/src/screencast.h b/src/screencast.h
index d78066e..3d64b4a 100644
--- a/src/screencast.h
+++ b/src/screencast.h
@@ -55,6 +55,7 @@ typedef struct _ScreenCastSelection
typedef struct
{
ScreenCastSourceType type;
+ uint32_t id;
union {
Monitor *monitor;
Window *window;
diff --git a/src/screencastwidget.c b/src/screencastwidget.c
index c100ad9..20df194 100644
--- a/src/screencastwidget.c
+++ b/src/screencastwidget.c
@@ -597,6 +597,7 @@ screen_cast_widget_get_selected_streams (ScreenCastWidget *self)
g_autoptr(GPtrArray) streams = NULL;
g_autoptr(GList) selected_monitor_rows = NULL;
g_autoptr(GList) selected_window_rows = NULL;
+ uint32_t id = 0;
GList *l;
streams = g_ptr_array_new_with_free_func (g_free);
@@ -620,6 +621,7 @@ screen_cast_widget_get_selected_streams (ScreenCastWidget *self)
info = g_new0 (ScreenCastStreamInfo, 1);
info->type = SCREEN_CAST_SOURCE_TYPE_MONITOR;
info->data.monitor = monitor;
+ info->id = id++;
g_ptr_array_add (streams, info);
}
@@ -634,6 +636,7 @@ screen_cast_widget_get_selected_streams (ScreenCastWidget *self)
info = g_new0 (ScreenCastStreamInfo, 1);
info->type = SCREEN_CAST_SOURCE_TYPE_WINDOW;
info->data.window = window;
+ info->id = id++;
g_ptr_array_add (streams, info);
}

View File

@ -0,0 +1,24 @@
From df8ddc91a6ab1254b22de8f092f07ce9aca4ea3c Mon Sep 17 00:00:00 2001
From: Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
Date: Thu, 25 Nov 2021 10:27:07 -0300
Subject: [PATCH] screencast: Fix variant type check
The restore data type is not the (suv) variant, but rather the
GNOME-specific variant format.
---
src/screencast.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/screencast.c b/src/screencast.c
index 3be8337..c46a4a8 100644
--- a/src/screencast.c
+++ b/src/screencast.c
@@ -698,7 +698,7 @@ handle_select_sources (XdpImplScreenCast *object,
if (g_variant_lookup (arg_options, "restore_data", "(suv)", &provider, &version, &restore_data))
{
- if (!g_variant_check_format_string (restore_data, "(suv)", FALSE))
+ if (!g_variant_check_format_string (restore_data, RESTORE_VARIANT_TYPE, FALSE))
{
g_warning ("Cannot parse restore data, ignoring");
goto out;

View File

@ -0,0 +1,30 @@
From 4251d584b010c130f278ba22869d4c9a9d19ebdb Mon Sep 17 00:00:00 2001
From: Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
Date: Fri, 18 Mar 2022 13:32:11 -0300
Subject: [PATCH] screencast: Don't restore windows with too different titles
If the title is too different, don't restore it. The "too
different" part is arbitrarily chosen to be half of the
title's length. If this is too strict, we can review it
later.
---
src/screencast.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/screencast.c b/src/screencast.c
index c46a4a8..5f9a738 100644
--- a/src/screencast.c
+++ b/src/screencast.c
@@ -455,6 +455,12 @@ find_best_window_by_app_id_and_title (const char *app_id,
}
}
+ /* If even the best match's window title is too different, don't
+ * restore it.
+ */
+ if (best_match_distance > strlen (title) / 2)
+ return NULL;
+
return best_match;
}

View File

@ -0,0 +1,29 @@
From 6d293e77e4470d0e5df57c29eeb6e1ed5cb619e8 Mon Sep 17 00:00:00 2001
From: Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
Date: Fri, 18 Mar 2022 13:36:37 -0300
Subject: [PATCH] screencast: Don't wrap restore data in another variant
We were sending a variant with the wrong type. This was a
fallout from the evolution of the xdg-desktop-portal work,
which originally started as a 'v' variant, but then changed
to '(suv)', and we didn't adapt properly
See https://github.com/flatpak/xdg-desktop-portal/pull/730
---
src/screencast.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/screencast.c b/src/screencast.c
index 5f9a738..6b0014a 100644
--- a/src/screencast.c
+++ b/src/screencast.c
@@ -229,8 +229,7 @@ on_gnome_screen_cast_session_ready (GnomeScreenCastSession *gnome_screen_cast_se
{
g_variant_builder_add (&results_builder, "{sv}", "persist_mode",
g_variant_new_uint32 (screen_cast_session->persist_mode));
- g_variant_builder_add (&results_builder, "{sv}", "restore_data",
- g_variant_new_variant (restore_data));
+ g_variant_builder_add (&results_builder, "{sv}", "restore_data", restore_data);
}
}

View File

@ -0,0 +1,390 @@
diff --git a/src/screencast.c b/src/screencast.c
index 6b0014a..15f6a80 100644
--- a/src/screencast.c
+++ b/src/screencast.c
@@ -427,16 +427,20 @@ find_best_window_by_app_id_and_title (const char *app_id,
const char *title)
{
ShellIntrospect *shell_introspect = shell_introspect_get ();
+ GPtrArray *windows;
Window *best_match;
glong best_match_distance;
- GList *l;
best_match = NULL;
best_match_distance = G_MAXLONG;
- for (l = shell_introspect_get_windows (shell_introspect); l; l = l->next)
+ shell_introspect_ref_listeners (shell_introspect);
+ shell_introspect_wait_for_windows (shell_introspect);
+
+ windows = shell_introspect_get_windows (shell_introspect);
+ for (size_t i = 0; windows && i < windows->len; i++)
{
- Window *window = l->data;
+ Window *window = g_ptr_array_index (windows, i);
glong distance;
if (g_strcmp0 (window_get_app_id (window), app_id) != 0)
@@ -454,6 +458,8 @@ find_best_window_by_app_id_and_title (const char *app_id,
}
}
+ shell_introspect_unref_listeners (shell_introspect);
+
/* If even the best match's window title is too different, don't
* restore it.
*/
diff --git a/src/screencastwidget.c b/src/screencastwidget.c
index 9b30f2d..e95fee2 100644
--- a/src/screencastwidget.c
+++ b/src/screencastwidget.c
@@ -164,8 +164,7 @@ update_windows_list (ScreenCastWidget *widget)
GtkListBox *window_list = GTK_LIST_BOX (widget->window_list);
GtkWidget *toplevel;
GtkWidget *child;
- GList *windows;
- GList *l;
+ GPtrArray *windows;
child = gtk_widget_get_first_child (GTK_WIDGET (window_list));
while (child)
@@ -181,9 +180,9 @@ update_windows_list (ScreenCastWidget *widget)
return;
windows = shell_introspect_get_windows (widget->shell_introspect);
- for (l = windows; l; l = l->next)
+ for (size_t i = 0; windows && i < windows->len; i++)
{
- Window *window = l->data;
+ Window *window = g_ptr_array_index (windows, i);
GtkWidget *window_widget;
if (should_skip_window (window, GTK_WINDOW (toplevel)))
diff --git a/src/shellintrospect.c b/src/shellintrospect.c
index 1fa8b93..c2b288d 100644
--- a/src/shellintrospect.c
+++ b/src/shellintrospect.c
@@ -22,16 +22,6 @@
#include "shell-dbus.h"
#include "shellintrospect.h"
-enum
-{
- WINDOWS_CHANGED,
- ANIMATIONS_ENABLED_CHANGED,
-
- N_SIGNALS
-};
-
-static guint signals[N_SIGNALS];
-
struct _Window
{
uint64_t id;
@@ -50,7 +40,7 @@ struct _ShellIntrospect
unsigned int version;
- GList *windows;
+ GPtrArray *windows;
int num_listeners;
@@ -60,6 +50,16 @@ struct _ShellIntrospect
G_DEFINE_TYPE (ShellIntrospect, shell_introspect, G_TYPE_OBJECT)
+enum
+{
+ WINDOWS_CHANGED,
+ ANIMATIONS_ENABLED_CHANGED,
+
+ N_SIGNALS
+};
+
+static guint signals[N_SIGNALS];
+
static ShellIntrospect *_shell_introspect;
static void
@@ -70,50 +70,36 @@ window_free (Window *window)
g_free (window);
}
-const char *
-window_get_title (Window *window)
-{
- return window->title;
-}
-
-const char *
-window_get_app_id (Window *window)
-{
- return window->app_id;
-}
-
-const uint64_t
-window_get_id (Window *window)
-{
- return window->id;
-}
-
static void
get_windows_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
ShellIntrospect *shell_introspect = user_data;
+ g_autoptr(GPtrArray) windows = NULL;
g_autoptr(GVariant) windows_variant = NULL;
g_autoptr(GError) error = NULL;
GVariantIter iter;
uint64_t id;
GVariant *params = NULL;
- GList *windows = NULL;
- g_list_free_full (shell_introspect->windows, (GDestroyNotify) window_free);
- shell_introspect->windows = NULL;
+ g_clear_object (&shell_introspect->cancellable);
if (!org_gnome_shell_introspect_call_get_windows_finish (shell_introspect->proxy,
&windows_variant,
res,
&error))
{
- g_warning ("Failed to get window list: %s", error->message);
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning ("Failed to get window list: %s", error->message);
return;
}
g_variant_iter_init (&iter, windows_variant);
+
+ windows = g_ptr_array_new_full (g_variant_iter_n_children (&iter),
+ (GDestroyNotify) window_free);
+
while (g_variant_iter_loop (&iter, "{t@a{sv}}", &id, &params))
{
char *app_id = NULL;
@@ -131,64 +117,30 @@ get_windows_cb (GObject *source_object,
.title = title,
.app_id = app_id
};
- windows = g_list_prepend (windows, window);
+ g_ptr_array_add (windows, window);
g_clear_pointer (&params, g_variant_unref);
}
- shell_introspect->windows = windows;
+ shell_introspect->windows = g_steal_pointer (&windows);
g_signal_emit (shell_introspect, signals[WINDOWS_CHANGED], 0);
}
static void
sync_state (ShellIntrospect *shell_introspect)
{
+ g_clear_pointer (&shell_introspect->windows, g_ptr_array_unref);
+
+ g_cancellable_cancel (shell_introspect->cancellable);
+ g_clear_object (&shell_introspect->cancellable);
+ shell_introspect->cancellable = g_cancellable_new ();
+
org_gnome_shell_introspect_call_get_windows (shell_introspect->proxy,
shell_introspect->cancellable,
get_windows_cb,
shell_introspect);
}
-GList *
-shell_introspect_get_windows (ShellIntrospect *shell_introspect)
-{
- return shell_introspect->windows;
-}
-
-void
-shell_introspect_ref_listeners (ShellIntrospect *shell_introspect)
-{
- shell_introspect->num_listeners++;
-
- if (shell_introspect->proxy)
- sync_state (shell_introspect);
-}
-
-void
-shell_introspect_unref_listeners (ShellIntrospect *shell_introspect)
-{
- g_return_if_fail (shell_introspect->num_listeners > 0);
-
- shell_introspect->num_listeners--;
- if (shell_introspect->num_listeners == 0)
- {
- g_list_free_full (shell_introspect->windows,
- (GDestroyNotify) window_free);
- shell_introspect->windows = NULL;
- }
-}
-
-gboolean
-shell_introspect_are_animations_enabled (ShellIntrospect *shell_introspect,
- gboolean *out_animations_enabled)
-{
- if (!shell_introspect->animations_enabled_valid)
- return FALSE;
-
- *out_animations_enabled = shell_introspect->animations_enabled;
- return TRUE;
-}
-
static void
on_windows_changed_cb (GDBusProxy *proxy,
ShellIntrospect *shell_introspect)
@@ -291,6 +243,29 @@ on_shell_introspect_name_vanished (GDBusConnection *connection,
}
}
+static void
+shell_introspect_class_init (ShellIntrospectClass *klass)
+{
+ signals[WINDOWS_CHANGED] = g_signal_new ("windows-changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
+ signals[ANIMATIONS_ENABLED_CHANGED] =
+ g_signal_new ("animations-enabled-changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
+}
+
+static void
+shell_introspect_init (ShellIntrospect *shell_introspect)
+{
+}
+
ShellIntrospect *
shell_introspect_get (void)
{
@@ -311,25 +286,67 @@ shell_introspect_get (void)
return shell_introspect;
}
-static void
-shell_introspect_init (ShellIntrospect *shell_introspect)
+GPtrArray *
+shell_introspect_get_windows (ShellIntrospect *shell_introspect)
{
+ return shell_introspect->windows;
}
-static void
-shell_introspect_class_init (ShellIntrospectClass *klass)
+void
+shell_introspect_ref_listeners (ShellIntrospect *shell_introspect)
{
- signals[WINDOWS_CHANGED] = g_signal_new ("windows-changed",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL, NULL, NULL,
- G_TYPE_NONE, 0);
- signals[ANIMATIONS_ENABLED_CHANGED] =
- g_signal_new ("animations-enabled-changed",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL, NULL, NULL,
- G_TYPE_NONE, 0);
+ shell_introspect->num_listeners++;
+
+ if (shell_introspect->proxy)
+ sync_state (shell_introspect);
+}
+
+void
+shell_introspect_unref_listeners (ShellIntrospect *shell_introspect)
+{
+ g_return_if_fail (shell_introspect->num_listeners > 0);
+
+ shell_introspect->num_listeners--;
+ if (shell_introspect->num_listeners == 0)
+ g_clear_pointer (&shell_introspect->windows, g_ptr_array_unref);
+}
+
+const char *
+window_get_title (Window *window)
+{
+ return window->title;
+}
+
+const char *
+window_get_app_id (Window *window)
+{
+ return window->app_id;
+}
+
+const uint64_t
+window_get_id (Window *window)
+{
+ return window->id;
+}
+
+gboolean
+shell_introspect_are_animations_enabled (ShellIntrospect *shell_introspect,
+ gboolean *out_animations_enabled)
+{
+ if (!shell_introspect->animations_enabled_valid)
+ return FALSE;
+
+ *out_animations_enabled = shell_introspect->animations_enabled;
+ return TRUE;
+}
+
+void
+shell_introspect_wait_for_windows (ShellIntrospect *shell_introspect)
+{
+ g_assert (shell_introspect->num_listeners > 0);
+
+ sync_state (shell_introspect);
+
+ while (!shell_introspect->windows)
+ g_main_context_iteration (NULL, TRUE);
}
diff --git a/src/shellintrospect.h b/src/shellintrospect.h
index b187c4d..f63ecee 100644
--- a/src/shellintrospect.h
+++ b/src/shellintrospect.h
@@ -28,19 +28,21 @@ typedef struct _Window Window;
G_DECLARE_FINAL_TYPE (ShellIntrospect, shell_introspect,
SHELL, INTROSPECT, GObject)
+ShellIntrospect * shell_introspect_get (void);
+
+void shell_introspect_ref_listeners (ShellIntrospect *shell_introspect);
+
+void shell_introspect_unref_listeners (ShellIntrospect *shell_introspect);
+
const char * window_get_app_id (Window *window);
const char * window_get_title (Window *window);
const uint64_t window_get_id (Window *window);
-GList * shell_introspect_get_windows (ShellIntrospect *shell_introspect);
+GPtrArray * shell_introspect_get_windows (ShellIntrospect *shell_introspect);
-gboolean shell_introspect_are_animations_enabled (ShellIntrospect *introspect,
+gboolean shell_introspect_are_animations_enabled (ShellIntrospect *shell_introspect,
gboolean *enable_animations);
-void shell_introspect_ref_listeners (ShellIntrospect *shell_introspect);
-
-void shell_introspect_unref_listeners (ShellIntrospect *shell_introspect);
-
-ShellIntrospect * shell_introspect_get (void);
+void shell_introspect_wait_for_windows (ShellIntrospect *shell_introspect);

View File

@ -0,0 +1,27 @@
From 5450d65d61ea927752c001dff9f94cb9fd7baf7a Mon Sep 17 00:00:00 2001
From: Jan Grulich <jgrulich@redhat.com>
Date: Tue, 14 Jun 2022 15:39:26 +0200
Subject: [PATCH] ScreenCast: close screencast dialog when the session is
closed from the client side
When the session is closed, for example trying to share a screen in Chrome and closing
the web page while having the portal dialog still open, it will not take down the dialog
and instead it just gets hidden below Chrome's window.
---
src/screencast.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/screencast.c b/src/screencast.c
index 15f6a80..729d668 100644
--- a/src/screencast.c
+++ b/src/screencast.c
@@ -852,6 +852,9 @@ screen_cast_session_close (Session *session)
error->message);
g_clear_object (&screen_cast_session->gnome_screen_cast_session);
}
+
+ g_clear_pointer (&screen_cast_session->dialog_handle,
+ screen_cast_dialog_handle_close);
}
static void

View File

@ -0,0 +1,87 @@
From b33d02e04877bfeeaa43671d3b1b48e0680fc12d Mon Sep 17 00:00:00 2001
From: Peter Hutterer <peter.hutterer@who-t.net>
Date: Mon, 22 Aug 2022 18:45:46 +1000
Subject: [PATCH] session: emit the Closed signal when we're closing on our own
account
If a RemoteDesktop/ScreenCast session is closed by mutter, send out the
Closed signal on our impl.portal.Session to notify the
xdg-desktop-portal that we're done.
Related: https://github.com/flatpak/xdg-desktop-portal/issues/508
---
src/remotedesktop.c | 2 +-
src/screencast.c | 2 +-
src/session.c | 11 +++++++++--
src/session.h | 2 +-
4 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/src/remotedesktop.c b/src/remotedesktop.c
index 46d1dcc..0298f68 100644
--- a/src/remotedesktop.c
+++ b/src/remotedesktop.c
@@ -266,7 +266,7 @@ static void
on_mutter_session_closed (OrgGnomeMutterRemoteDesktopSession *mutter_session_proxy,
RemoteDesktopSession *remote_desktop_session)
{
- session_close ((Session *)remote_desktop_session);
+ session_close ((Session *)remote_desktop_session, TRUE);
}
static RemoteDesktopSession *
diff --git a/src/screencast.c b/src/screencast.c
index 15f6a80..0a15033 100644
--- a/src/screencast.c
+++ b/src/screencast.c
@@ -243,7 +243,7 @@ static void
on_gnome_screen_cast_session_closed (GnomeScreenCastSession *gnome_screen_cast_session,
ScreenCastSession *screen_cast_session)
{
- session_close ((Session *)screen_cast_session);
+ session_close ((Session *)screen_cast_session, TRUE);
}
static gboolean
diff --git a/src/session.c b/src/session.c
index 5ebe13f..b428ef8 100644
--- a/src/session.c
+++ b/src/session.c
@@ -73,8 +73,15 @@ session_unexport (Session *session)
}
void
-session_close (Session *session)
+session_close (Session *session, gboolean notify)
{
+ if (notify)
+ {
+ GVariantBuilder details_builder;
+ g_variant_builder_init (&details_builder, G_VARIANT_TYPE_VARDICT);
+ g_signal_emit_by_name (session, "closed", g_variant_builder_end (&details_builder));
+ }
+
if (session->exported)
session_unexport (session);
@@ -92,7 +99,7 @@ handle_close (XdpImplSession *object,
Session *session = (Session *)object;
if (!session->closed)
- session_close (session);
+ session_close (session, FALSE);
xdp_impl_session_complete_close (object, invocation);
diff --git a/src/session.h b/src/session.h
index 4a1173a..7594bd8 100644
--- a/src/session.h
+++ b/src/session.h
@@ -47,7 +47,7 @@ Session *lookup_session (const char *id);
Session *session_new (const char *id);
-void session_close (Session *session);
+void session_close (Session *session, gboolean notify);
gboolean session_export (Session *session,
GDBusConnection *connection,

View File

@ -5,7 +5,7 @@
Name: xdg-desktop-portal-gnome Name: xdg-desktop-portal-gnome
Version: 41.2 Version: 41.2
Release: 2%{?dist} Release: 3%{?dist}
Summary: Backend implementation for xdg-desktop-portal using GNOME Summary: Backend implementation for xdg-desktop-portal using GNOME
License: LGPLv2+ License: LGPLv2+
@ -14,6 +14,33 @@ Source0: https://download.gnome.org/sources/%{name}/41/%{name}-%{tarball_
Patch0: windows-changed-signal.patch Patch0: windows-changed-signal.patch
## Screencast: stream restoration support
# Code cleanups/shuffling
# https://gitlab.gnome.org/GNOME/xdg-desktop-portal-gnome/-/merge_requests/18
Patch11: 0001-screencast-trivial-style-cleanups.patch
Patch12: 0002-screencast-cleanup-unnecessary-forward-declaration.patch
Patch13: 0003-screencast-more-code-shuffling-and-cleanups.patch
Patch14: 0004-screencastwidget-rework-selection-api.patch
# Stream restoration support
# https://gitlab.gnome.org/GNOME/xdg-desktop-portal-gnome/-/merge_requests/14
Patch15: 0005-displaystatetracker-add-match-string.patch
Patch16: 0006-implement-screencast-stream-restoration.patch
Patch17: 0007-screencast-pass-stream-ids.patch
# Followup fixes
Patch18: 0008-screencast-fix-variant-type-check.patch
Patch19: 0009-screencast-dont-restore-windows-with-too-different-titles.patch
Patch20: 0010-screencast-dont-wrap-restore-data-in-another-variant.patch
# https://gitlab.gnome.org/GNOME/xdg-desktop-portal-gnome/-/merge_requests/49
Patch21: 0011-fix-window-screencast-stream-restore.patch
# Closely related screencast fixes
# https://gitlab.gnome.org/GNOME/xdg-desktop-portal-gnome/-/merge_requests/40
# https://gitlab.gnome.org/GNOME/xdg-desktop-portal-gnome/-/merge_requests/41
Patch22: 0012-screencast-close-screencast-dialog-when-the-session-is-closed-from-client-side.patch
# https://gitlab.gnome.org/GNOME/xdg-desktop-portal-gnome/-/merge_requests/52
Patch23: 0013-session-emit-closed-signal-when-we-are-closing-our-own-account.patch
# https://gitlab.gnome.org/GNOME/xdg-desktop-portal-gnome/-/merge_requests/86
Patch24: 00014-screencasts-duplicate-monitor-and-window-stream-info.patch
BuildRequires: desktop-file-utils BuildRequires: desktop-file-utils
BuildRequires: gcc BuildRequires: gcc
BuildRequires: gettext BuildRequires: gettext
@ -68,6 +95,10 @@ desktop-file-validate %{buildroot}/%{_datadir}/applications/%{name}.desktop
%changelog %changelog
* Tue Jan 09 2024 Jan Grulich <jgrulich@redhat.com> - 41.2-3
- Add screencast stream restoration support
Resolves: RHEL-4526
* Tue Dec 13 2022 Jonas Ådahl <jadahl@redhat.com> - 41.2-2 * Tue Dec 13 2022 Jonas Ådahl <jadahl@redhat.com> - 41.2-2
- Keep screen share window list up to date - Keep screen share window list up to date
Resolves: #2148362 Resolves: #2148362