Blame SOURCES/0001-screencast-Stop-recording-when-screen-size-or-resour.patch

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