[gnome-shell/wip/rstrode/login-screen-extensions: 122/134] screencast: Stop recording when screen size or resource scale change
- From: Ray Strode <halfline src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell/wip/rstrode/login-screen-extensions: 122/134] screencast: Stop recording when screen size or resource scale change
- Date: Thu, 26 Aug 2021 19:31:02 +0000 (UTC)
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]