[xdg-desktop-portal-gnome] screencast: Add support for 'VIRTUAL' source type



commit 340533035b897d40a2c4e36ccb41ab9cc060d0bc
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Thu Jun 17 09:54:05 2021 +0200

    screencast: Add support for 'VIRTUAL' source type
    
    This maps to the 'RecordVirtual' D-Bus method on the mutter screen cast
    API.

 src/gnomescreencast.c   | 85 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/screencast.h        |  1 +
 src/screencastwidget.c  | 44 +++++++++++++++++++++++--
 src/screencastwidget.ui | 61 +++++++++++++++++++++++++++++++++++
 4 files changed, 189 insertions(+), 2 deletions(-)
---
diff --git a/src/gnomescreencast.c b/src/gnomescreencast.c
index fd80ca7..70938cc 100644
--- a/src/gnomescreencast.c
+++ b/src/gnomescreencast.c
@@ -435,6 +435,84 @@ gnome_screen_cast_session_record_monitor (GnomeScreenCastSession *gnome_screen_c
   return TRUE;
 }
 
+static gboolean
+gnome_screen_cast_session_record_virtual (GnomeScreenCastSession *gnome_screen_cast_session,
+                                          ScreenCastSelection *select,
+                                          GError **error)
+{
+  OrgGnomeMutterScreenCastSession *session_proxy =
+    gnome_screen_cast_session->proxy;
+  GVariantBuilder properties_builder;
+  GVariant *properties;
+  g_autofree char *stream_path = NULL;
+  GDBusConnection *connection;
+  OrgGnomeMutterScreenCastStream *stream_proxy;
+  GnomeScreenCastStream *stream;
+  GVariant *parameters;
+
+  g_variant_builder_init (&properties_builder, G_VARIANT_TYPE_VARDICT);
+  if (select->cursor_mode)
+    {
+      uint32_t gnome_cursor_mode;
+
+      gnome_cursor_mode = cursor_mode_to_gnome_cursor_mode (select->cursor_mode);
+      g_variant_builder_add (&properties_builder, "{sv}",
+                             "cursor-mode",
+                             g_variant_new_uint32 (gnome_cursor_mode));
+    }
+  properties = g_variant_builder_end (&properties_builder);
+
+  if (!org_gnome_mutter_screen_cast_session_call_record_virtual_sync (session_proxy,
+                                                                      properties,
+                                                                      &stream_path,
+                                                                      NULL,
+                                                                      error))
+    return FALSE;
+
+  connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (session_proxy));
+  stream_proxy =
+    org_gnome_mutter_screen_cast_stream_proxy_new_sync (connection,
+                                                        G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
+                                                        "org.gnome.Mutter.ScreenCast",
+                                                        stream_path,
+                                                        NULL,
+                                                        error);
+  if (!stream_proxy)
+    return FALSE;
+
+  stream = g_object_new (gnome_screen_cast_stream_get_type (), NULL);
+  stream->source_type = SCREEN_CAST_SOURCE_TYPE_VIRTUAL;
+  stream->session = gnome_screen_cast_session;
+  stream->path = g_strdup (stream_path);
+  stream->proxy = stream_proxy;
+
+  parameters = org_gnome_mutter_screen_cast_stream_get_parameters (stream->proxy);
+  if (parameters)
+    {
+      if (g_variant_lookup (parameters, "position", "(ii)",
+                            &stream->x, &stream->y))
+        stream->has_position = TRUE;
+      if (g_variant_lookup (parameters, "size", "(ii)",
+                            &stream->width, &stream->height))
+        stream->has_size = TRUE;
+    }
+  else
+    {
+      g_warning ("Screen cast stream %s missing parameters",
+                 stream->path);
+    }
+
+  g_signal_connect (stream_proxy, "pipewire-stream-added",
+                    G_CALLBACK (on_pipewire_stream_added),
+                    stream);
+
+  gnome_screen_cast_session->streams =
+    g_list_prepend (gnome_screen_cast_session->streams, stream);
+  gnome_screen_cast_session->n_needed_stream_node_ids++;
+
+  return TRUE;
+}
+
 gboolean
 gnome_screen_cast_session_record_selections (GnomeScreenCastSession *gnome_screen_cast_session,
                                              GVariant *selections,
@@ -473,6 +551,13 @@ gnome_screen_cast_session_record_selections (GnomeScreenCastSession *gnome_scree
                                                         select,
                                                         error))
             return FALSE;
+          break;
+        case SCREEN_CAST_SOURCE_TYPE_VIRTUAL:
+          if (!gnome_screen_cast_session_record_virtual (gnome_screen_cast_session,
+                                                         select,
+                                                         error))
+            return FALSE;
+          break;
         }
     }
 
diff --git a/src/screencast.h b/src/screencast.h
index f5033b2..00f939c 100644
--- a/src/screencast.h
+++ b/src/screencast.h
@@ -25,6 +25,7 @@ typedef enum _ScreenCastSourceType
 {
   SCREEN_CAST_SOURCE_TYPE_MONITOR = 1,
   SCREEN_CAST_SOURCE_TYPE_WINDOW = 2,
+  SCREEN_CAST_SOURCE_TYPE_VIRTUAL = 4,
 } ScreenCastSourceType;
 
 typedef enum _ScreenCastCursorMode
diff --git a/src/screencastwidget.c b/src/screencastwidget.c
index cdd57dc..64a43b5 100644
--- a/src/screencastwidget.c
+++ b/src/screencastwidget.c
@@ -43,6 +43,7 @@ struct _ScreenCastWidget
   GtkWidget *source_type;
   GtkWidget *window_selection;
   GtkWidget *monitor_selection;
+  GtkWidget *virtual_selection;
 
   GtkWidget *monitor_heading;
   GtkWidget *monitor_list;
@@ -51,6 +52,10 @@ struct _ScreenCastWidget
   GtkWidget *window_list;
   GtkWidget *window_list_scrolled;
 
+  GtkWidget *virtual_heading;
+  GtkWidget *virtual_switch;
+  GtkWidget *virtual_switch_label;
+
   DisplayStateTracker *display_state_tracker;
   gulong monitors_changed_handler_id;
 
@@ -351,6 +356,7 @@ emit_selection_change_in_idle_cb (gpointer data)
   ScreenCastWidget *widget = (ScreenCastWidget *)data;
   GList *selected_monitor_rows;
   GList *selected_window_rows;
+  gboolean selected_virtual;
 
   /* Update the selected rows */
   update_selected_rows (GTK_LIST_BOX (widget->monitor_list));
@@ -358,8 +364,9 @@ emit_selection_change_in_idle_cb (gpointer data)
 
   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));
+  selected_virtual = gtk_switch_get_state (GTK_SWITCH (widget->virtual_switch));
   g_signal_emit (widget, signals[HAS_SELECTION_CHANGED], 0,
-                 !!selected_monitor_rows || !!selected_window_rows);
+                 !!selected_monitor_rows || !!selected_window_rows || selected_virtual);
   g_list_free (selected_monitor_rows);
   g_list_free (selected_window_rows);
 
@@ -386,6 +393,15 @@ on_selected_rows_changed (GtkListBox *box,
   schedule_selection_change (widget);
 }
 
+static gboolean
+on_virtual_switch_state_set (GtkSwitch *virtual_switch,
+                             gboolean state,
+                             ScreenCastWidget *widget)
+{
+  schedule_selection_change (widget);
+  return FALSE;
+}
+
 static void
 update_list_box_header (GtkListBoxRow *row,
                         GtkListBoxRow *before,
@@ -414,13 +430,15 @@ add_selections (ScreenCastWidget *widget,
 {
   GList *selected_monitor_rows;
   GList *selected_window_rows;
+  gboolean selected_virtual;
   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)
+  selected_virtual = gtk_switch_get_state (GTK_SWITCH (widget->virtual_switch));
+  if (!selected_monitor_rows && !selected_window_rows && !selected_virtual)
     return FALSE;
 
   for (l = selected_monitor_rows; l; l = l->next)
@@ -450,6 +468,13 @@ add_selections (ScreenCastWidget *widget,
     }
   g_list_free (selected_window_rows);
 
+  if (selected_virtual)
+    {
+      g_variant_builder_add (source_selections_builder, "(ud)",
+                             SCREEN_CAST_SOURCE_TYPE_VIRTUAL,
+                             1);
+    }
+
   return TRUE;
 }
 
@@ -478,6 +503,7 @@ screen_cast_widget_set_app_id (ScreenCastWidget *widget,
 {
   g_autofree char *monitor_heading = NULL;
   g_autofree char *window_heading = NULL;
+  g_autofree char *virtual_heading = NULL;
 
   if (app_id && strcmp (app_id, "") != 0)
     {
@@ -495,15 +521,19 @@ screen_cast_widget_set_app_id (ScreenCastWidget *widget,
                                          display_name);
       window_heading = g_strdup_printf (_("Select window to share with %s"),
                                         display_name);
+      virtual_heading = g_strdup_printf (_("Select whether to create a vitrual monitor for %s"),
+                                        display_name);
     }
   else
     {
       monitor_heading = g_strdup (_("Select monitor to share with the requesting application"));
       window_heading = g_strdup (_("Select window to share with the requesting application"));
+      virtual_heading = g_strdup (_("Select whether to create a virtual monitor for the requesting 
application"));
     }
 
   gtk_label_set_label (GTK_LABEL (widget->monitor_heading), monitor_heading);
   gtk_label_set_label (GTK_LABEL (widget->window_heading), window_heading);
+  gtk_label_set_label (GTK_LABEL (widget->virtual_heading), virtual_heading);
 }
 
 void
@@ -528,6 +558,9 @@ screen_cast_widget_set_source_types (ScreenCastWidget *screen_cast_widget,
   if (source_types & SCREEN_CAST_SOURCE_TYPE_WINDOW)
     gtk_widget_show (screen_cast_widget->window_selection);
 
+  if (source_types & SCREEN_CAST_SOURCE_TYPE_VIRTUAL)
+    gtk_widget_show (screen_cast_widget->virtual_selection);
+
   if (__builtin_popcount (source_types) > 1)
     gtk_widget_show (screen_cast_widget->source_type_switcher);
 }
@@ -588,6 +621,9 @@ screen_cast_widget_init (ScreenCastWidget *widget)
   g_signal_connect (widget->window_list, "selected-rows-changed",
                     G_CALLBACK (on_selected_rows_changed),
                     widget);
+  g_signal_connect (widget->virtual_switch, "state-set",
+                    G_CALLBACK (on_virtual_switch_state_set),
+                    widget);
 
   widget->display_state_tracker = display_state_tracker_get ();
   widget->monitors_changed_handler_id =
@@ -602,6 +638,7 @@ screen_cast_widget_init (ScreenCastWidget *widget)
 
   gtk_widget_show (widget->monitor_list);
   gtk_widget_show (widget->window_list);
+  gtk_widget_show (widget->virtual_switch);
 }
 
 static void
@@ -626,11 +663,14 @@ screen_cast_widget_class_init (ScreenCastWidgetClass *klass)
   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, virtual_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);
+  gtk_widget_class_bind_template_child (widget_class, ScreenCastWidget, virtual_heading);
+  gtk_widget_class_bind_template_child (widget_class, ScreenCastWidget, virtual_switch);
 
   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");
diff --git a/src/screencastwidget.ui b/src/screencastwidget.ui
index 2417ca5..fbabfa7 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>
@@ -141,6 +144,64 @@
                 </property>
               </object>
             </child>
+
+            <!-- Virtual monitor selection page -->
+            <child>
+              <object class="GtkStackPage">
+                <property name="name">virtual_page</property>
+                <property name="title" translatable="yes">Virtual monitor</property>
+                <property name="child">
+                  <object class="GtkBox" id="virtual_selection">
+                    <property name="orientation">vertical</property>
+                    <property name="visible">0</property>
+                    <property name="margin_top">12</property>
+
+                    <!-- Virtual monitor selection label -->
+                    <child>
+                      <object class="GtkBox">
+                        <property name="hexpand">True</property>
+                        <property name="halign">start</property>
+                        <child>
+                          <object class="GtkLabel" id="virtual_heading">
+                            <property name="label"/>
+                            <property name="xalign">0.0</property>
+                            <property name="margin_bottom">12</property>
+                            <attributes>
+                              <attribute name="weight" value="bold"/>
+                            </attributes>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+
+                    <!-- Virtual monitor switch view -->
+                    <child>
+                      <object class="GtkBox">
+                        <property name="can_focus">False</property>
+                        <property name="orientation">horizontal</property>
+                        <child>
+                          <object class="GtkLabel">
+                            <property name="label" translatable="yes">
+                              Create virtual monitor?
+                            </property>
+                            <property name="hexpand">True</property>
+                            <property name="vexpand">False</property>
+                          </object>
+                        </child>
+                        <child>
+                          <object class="GtkSwitch" id="virtual_switch">
+                            <property name="can_focus">True</property>
+                            <property name="hexpand">False</property>
+                            <property name="vexpand">False</property>
+                            <property name="valign">center</property>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </property>
+              </object>
+            </child>
             <layout>
               <property name="column">0</property>
               <property name="row">1</property>


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