[gnome-shell/wip/rstrode/login-screen-extensions: 122/134] screencast: Stop recording when screen size or resource scale change




commit 178f797e7a2072f7c532f77e183dcdb7a57ef631
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Tue Jan 5 12:04:23 2021 +0100

    screencast: Stop recording when screen size or resource scale change
    
    Video encoders don't really handle changing the size of the video, and if
    we'd e.g. change resolution while recording, we would end up with a corrupt
    video file. Handle this more gracefully by stopping the recording if the
    conditions change.

 js/ui/screencast.js  | 92 +++++++++++++++++++++++++++++++++++++++++++++++++---
 src/shell-recorder.c | 50 ++++++++++++++--------------
 src/shell-recorder.h |  1 +
 3 files changed, 114 insertions(+), 29 deletions(-)
---
diff --git a/js/ui/screencast.js b/js/ui/screencast.js
index 0b0b14a8e3..54f8fb5ae0 100644
--- a/js/ui/screencast.js
+++ b/js/ui/screencast.js
@@ -1,6 +1,6 @@
 // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 
-const { Gio, GLib, Shell } = imports.gi;
+const { Gio, GLib, Meta, Shell } = imports.gi;
 const Signals = imports.signals;
 
 const Main = imports.ui.main;
@@ -53,16 +53,27 @@ var ScreencastService = class {
         this._stopRecordingForSender(name);
     }
 
-    _stopRecordingForSender(sender) {
+    _stopRecordingForSender(sender, closeNow=false) {
         let recorder = this._recorders.get(sender);
         if (!recorder)
             return false;
 
         Gio.bus_unwatch_name(recorder._watchNameId);
-        recorder.close();
+        if (closeNow)
+            recorder.close_now();
+        else
+            recorder.close();
         this._recorders.delete(sender);
         this.emit('updated');
 
+        let connection = this._dbusImpl.get_connection();
+        let info = this._dbusImpl.get_info();
+        connection.emit_signal(sender,
+            this._dbusImpl.get_object_path(),
+            info ? info.name : null,
+            'Stopped',
+            null);
+
         return true;
     }
 
@@ -78,6 +89,53 @@ var ScreencastService = class {
             recorder.set_draw_cursor(options['draw-cursor']);
     }
 
+    _ensureResourceScaleChangedHandler() {
+        if (this._resourceScaleChangedHandlerId)
+            return;
+
+        this._resourceScaleChangedHandlerId =
+            global.stage.connect('notify::resource-scale',
+                () => {
+                    for (let sender of this._recorders.keys()) {
+                        let recorder = this._recorders.get(sender);
+
+                        if (!recorder.is_recording())
+                            continue;
+
+                        this._stopRecordingForSender(sender, true);
+                    }
+                });
+    }
+
+    _ensureMonitorsChangedHandler() {
+        if (this._monitorsChangedHandlerId)
+            return;
+
+        this._monitorsChangedHandlerId = Main.layoutManager.connect('monitors-changed',
+            () => {
+                for (let sender of this._recorders.keys()) {
+                    let recorder = this._recorders.get(sender);
+
+                    if (!recorder.is_recording())
+                        continue;
+
+                    let geometry = recorder._geometry;
+                    let screenWidth = global.screen_width;
+                    let screenHeight = global.screen_height;
+
+                    if (recorder._isAreaScreecast) {
+                        if (geometry.x + geometry.width > screenWidth ||
+                            geometry.y + geometry.height > screenHeight)
+                            this._stopRecordingForSender(sender, true);
+                    } else {
+                        if (geometry.width != screenWidth ||
+                            geometry.height != screenHeight)
+                            this._stopRecordingForSender(sender, true);
+                    }
+                }
+            });
+    }
+
     ScreencastAsync(params, invocation) {
         let returnValue = [false, ''];
         if (!Main.sessionMode.allowScreencast ||
@@ -95,8 +153,20 @@ var ScreencastService = class {
             this._applyOptionalParameters(recorder, options);
             let [success, fileName] = recorder.record();
             returnValue = [success, fileName ? fileName : ''];
-            if (!success)
+            if (success) {
+                recorder._isAreaScreecast = false;
+                recorder._geometry =
+                    new Meta.Rectangle({
+                        x: 0,
+                        y: 0,
+                        width: global.screen_width,
+                        height: global.screen_height
+                    });
+                this._ensureResourceScaleChangedHandler();
+                this._ensureMonitorsChangedHandler();
+            } else {
                 this._stopRecordingForSender(sender);
+            }
         }
 
         invocation.return_value(GLib.Variant.new('(bs)', returnValue));
@@ -131,8 +201,20 @@ var ScreencastService = class {
             this._applyOptionalParameters(recorder, options);
             let [success, fileName] = recorder.record();
             returnValue = [success, fileName ? fileName : ''];
-            if (!success)
+            if (success) {
+                recorder._isAreaScreecast = true;
+                recorder._geometry =
+                    new Meta.Rectangle({
+                        x: x,
+                        y: y,
+                        width: width,
+                        height: height
+                    });
+                this._ensureResourceScaleChangedHandler();
+                this._ensureMonitorsChangedHandler();
+            } else {
                 this._stopRecordingForSender(sender);
+            }
         }
 
         invocation.return_value(GLib.Variant.new('(bs)', returnValue));
diff --git a/src/shell-recorder.c b/src/shell-recorder.c
index 0203ecf1c9..e561a0152f 100644
--- a/src/shell-recorder.c
+++ b/src/shell-recorder.c
@@ -511,21 +511,6 @@ recorder_update_size (ShellRecorder *recorder)
     }
 }
 
-static void
-recorder_on_stage_notify_size (GObject          *object,
-                               GParamSpec       *pspec,
-                               ShellRecorder    *recorder)
-{
-  recorder_update_size (recorder);
-
-  /* This breaks the recording but tweaking the GStreamer pipeline a bit
-   * might make it work, at least if the codec can handle a stream where
-   * the frame size changes in the middle.
-   */
-  if (recorder->current_pipeline)
-    recorder_pipeline_set_caps (recorder->current_pipeline);
-}
-
 static gboolean
 recorder_idle_redraw (gpointer data)
 {
@@ -622,12 +607,6 @@ recorder_connect_stage_callbacks (ShellRecorder *recorder)
                     G_CALLBACK (recorder_on_stage_destroy), recorder);
   g_signal_connect_after (recorder->stage, "paint",
                           G_CALLBACK (recorder_on_stage_paint), recorder);
-  g_signal_connect (recorder->stage, "notify::width",
-                    G_CALLBACK (recorder_on_stage_notify_size), recorder);
-  g_signal_connect (recorder->stage, "notify::height",
-                    G_CALLBACK (recorder_on_stage_notify_size), recorder);
-  g_signal_connect (recorder->stage, "notify::resource-scale",
-                    G_CALLBACK (recorder_on_stage_notify_size), recorder);
 }
 
 static void
@@ -639,9 +618,6 @@ recorder_disconnect_stage_callbacks (ShellRecorder *recorder)
   g_signal_handlers_disconnect_by_func (recorder->stage,
                                         (void *)recorder_on_stage_paint,
                                         recorder);
-  g_signal_handlers_disconnect_by_func (recorder->stage,
-                                        (void *)recorder_on_stage_notify_size,
-                                        recorder);
 
   /* We don't don't deselect for cursor changes in case someone else just
    * happened to be selecting for cursor events on the same window; sending
@@ -1578,6 +1554,32 @@ shell_recorder_record (ShellRecorder  *recorder,
   return TRUE;
 }
 
+/**
+ * shell_recorder_close_now:
+ * @recorder: the #ShellRecorder
+ *
+ * Stops recording immediately. It's possible to call shell_recorder_record()
+ * again to reopen a new recording stream, but unless change the recording
+ * filename, this may result in the old recording being overwritten.
+ */
+void
+shell_recorder_close_now (ShellRecorder *recorder)
+{
+  g_return_if_fail (SHELL_IS_RECORDER (recorder));
+  g_return_if_fail (recorder->state != RECORDER_STATE_CLOSED);
+
+  recorder_remove_update_pointer_timeout (recorder);
+  recorder_close_pipeline (recorder);
+
+  recorder->state = RECORDER_STATE_CLOSED;
+
+  /* Reenable after the recording */
+  meta_enable_unredirect_for_display (shell_global_get_display (shell_global_get ()));
+
+  /* Release the refcount we took when we started recording */
+  g_object_unref (recorder);
+}
+
 /**
  * shell_recorder_close:
  * @recorder: the #ShellRecorder
diff --git a/src/shell-recorder.h b/src/shell-recorder.h
index c1e0e63683..1c3e6aab46 100644
--- a/src/shell-recorder.h
+++ b/src/shell-recorder.h
@@ -37,6 +37,7 @@ void               shell_recorder_set_area     (ShellRecorder *recorder,
 gboolean           shell_recorder_record       (ShellRecorder  *recorder,
                                                 char          **filename_used);
 void               shell_recorder_close        (ShellRecorder *recorder);
+void               shell_recorder_close_now    (ShellRecorder *recorder);
 void               shell_recorder_pause        (ShellRecorder *recorder);
 gboolean           shell_recorder_is_recording (ShellRecorder *recorder);
 


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