screenshot: Move HAVE_RECORDER check into screencast service
Some gstreamer plugins require a connection to the display server, so if we end up initializing gstreamer before we are ourselves fully initialized, we may end up with a locked compositor. Avoid this by moving the runtime recorder check into the screencast D-Bus service, so that all gstreamer calls happen out of process. https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/5710 Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2519>
This commit is contained in:
parent
cff56d4b03
commit
f266c2ca15
@ -10,6 +10,7 @@
|
||||
The interface used to record screen contents.
|
||||
-->
|
||||
<interface name="org.gnome.Shell.Screencast">
|
||||
<property name="ScreencastSupported" type="b" access="read"/>
|
||||
|
||||
<!--
|
||||
Screencast:
|
||||
|
@ -1,13 +1,12 @@
|
||||
/* exported main */
|
||||
|
||||
const Config = imports.misc.config;
|
||||
const { DBusService } = imports.dbusService;
|
||||
const {DBusService} = imports.dbusService;
|
||||
|
||||
function main() {
|
||||
if (!Config.HAVE_RECORDER)
|
||||
const {ScreencastService} = imports.screencastService;
|
||||
if (!ScreencastService.canScreencast())
|
||||
return;
|
||||
|
||||
const { ScreencastService } = imports.screencastService;
|
||||
const service = new DBusService(
|
||||
'org.gnome.Shell.Screencast',
|
||||
new ScreencastService());
|
||||
|
@ -258,9 +258,17 @@ var Recorder = class {
|
||||
};
|
||||
|
||||
var ScreencastService = class extends ServiceImplementation {
|
||||
static canScreencast() {
|
||||
return Gst.init_check(null) &&
|
||||
Gst.ElementFactory.find('pipewiresrc') &&
|
||||
Gst.ElementFactory.find('filesink');
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super(ScreencastIface, '/org/gnome/Shell/Screencast');
|
||||
|
||||
this._canScreencast = ScreencastService.canScreencast();
|
||||
|
||||
Gst.init(null);
|
||||
Gtk.init();
|
||||
|
||||
@ -280,6 +288,10 @@ var ScreencastService = class extends ServiceImplementation {
|
||||
'/org/gnome/Shell/Introspect');
|
||||
}
|
||||
|
||||
get ScreencastSupported() {
|
||||
return this._canScreencast;
|
||||
}
|
||||
|
||||
_removeRecorder(sender) {
|
||||
this._recorders.delete(sender);
|
||||
if (this._recorders.size === 0)
|
||||
|
@ -21,8 +21,3 @@ var LIBMUTTER_API_VERSION = '@LIBMUTTER_API_VERSION@'
|
||||
|
||||
var HAVE_BLUETOOTH = pkg.checkSymbol('GnomeBluetooth', '3.0',
|
||||
'Client.default_adapter_state')
|
||||
var HAVE_RECORDER =
|
||||
pkg.checkSymbol('Gst', '1.0') &&
|
||||
imports.gi.Gst.init_check(null) &&
|
||||
imports.gi.Gst.ElementFactory.find('pipewiresrc') &&
|
||||
imports.gi.Gst.ElementFactory.find('filesink');
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
const { Clutter, Cogl, Gio, GObject, GLib, Graphene, Gtk, Meta, Shell, St } = imports.gi;
|
||||
|
||||
const Config = imports.misc.config;
|
||||
const GrabHelper = imports.ui.grabHelper;
|
||||
const Layout = imports.ui.layout;
|
||||
const Lightbox = imports.ui.lightbox;
|
||||
@ -1019,6 +1018,19 @@ var ScreenshotUI = GObject.registerClass({
|
||||
|
||||
this._screencastInProgress = false;
|
||||
|
||||
this._screencastProxy = new ScreencastProxy(
|
||||
Gio.DBus.session,
|
||||
'org.gnome.Shell.Screencast',
|
||||
'/org/gnome/Shell/Screencast',
|
||||
(object, error) => {
|
||||
if (error !== null) {
|
||||
log('Error connecting to the screencast service');
|
||||
return;
|
||||
}
|
||||
|
||||
this._castButton.visible = this._screencastProxy.ScreencastSupported;
|
||||
});
|
||||
|
||||
this._lockdownSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.lockdown' });
|
||||
|
||||
// The full-screen screenshot has a separate container so that we can
|
||||
@ -1212,7 +1224,7 @@ var ScreenshotUI = GObject.registerClass({
|
||||
style_class: 'screenshot-ui-shot-cast-button',
|
||||
icon_name: 'camera-web-symbolic',
|
||||
toggle_mode: true,
|
||||
visible: Config.HAVE_RECORDER,
|
||||
visible: false,
|
||||
});
|
||||
this._castButton.connect('notify::checked',
|
||||
this._onCastButtonToggled.bind(this));
|
||||
@ -1438,7 +1450,7 @@ var ScreenshotUI = GObject.registerClass({
|
||||
if (this._screencastInProgress)
|
||||
return;
|
||||
|
||||
if (mode === UIMode.SCREENCAST && !Config.HAVE_RECORDER)
|
||||
if (mode === UIMode.SCREENCAST && !this._screencastProxy.ScreencastSupported)
|
||||
return;
|
||||
|
||||
this._castButton.checked = mode === UIMode.SCREENCAST;
|
||||
@ -1809,7 +1821,7 @@ var ScreenshotUI = GObject.registerClass({
|
||||
}
|
||||
}
|
||||
|
||||
_startScreencast() {
|
||||
async _startScreencast() {
|
||||
if (this._windowButton.checked)
|
||||
return; // TODO
|
||||
|
||||
@ -1833,61 +1845,40 @@ var ScreenshotUI = GObject.registerClass({
|
||||
this.close(true);
|
||||
|
||||
// This is a bit awkward because creating a proxy synchronously hangs Shell.
|
||||
const doStartScreencast = async () => {
|
||||
let method =
|
||||
this._screencastProxy.ScreencastAsync.bind(this._screencastProxy);
|
||||
if (w !== -1) {
|
||||
method = this._screencastProxy.ScreencastAreaAsync.bind(
|
||||
this._screencastProxy, x, y, w, h);
|
||||
}
|
||||
|
||||
try {
|
||||
const [success, path] = await method(
|
||||
GLib.build_filenamev([
|
||||
/* Translators: this is the folder where recorded
|
||||
screencasts are stored. */
|
||||
_('Screencasts'),
|
||||
/* Translators: this is a filename used for screencast
|
||||
* recording, where "%d" and "%t" date and time, e.g.
|
||||
* "Screencast from 07-17-2013 10:00:46 PM.webm" */
|
||||
/* xgettext:no-c-format */
|
||||
_('Screencast from %d %t.webm'),
|
||||
]),
|
||||
{'draw-cursor': new GLib.Variant('b', drawCursor)});
|
||||
if (!success)
|
||||
throw new Error();
|
||||
this._screencastPath = path;
|
||||
} catch (error) {
|
||||
this._setScreencastInProgress(false);
|
||||
const {message} = error;
|
||||
if (message)
|
||||
log(`Error starting screencast: ${message}`);
|
||||
else
|
||||
log('Error starting screencast');
|
||||
}
|
||||
};
|
||||
let method =
|
||||
this._screencastProxy.ScreencastAsync.bind(this._screencastProxy);
|
||||
if (w !== -1) {
|
||||
method = this._screencastProxy.ScreencastAreaAsync.bind(
|
||||
this._screencastProxy, x, y, w, h);
|
||||
}
|
||||
|
||||
// Set this before calling the method as the screen recording indicator
|
||||
// will check it before the success callback fires.
|
||||
this._setScreencastInProgress(true);
|
||||
|
||||
if (this._screencastProxy) {
|
||||
doStartScreencast();
|
||||
} else {
|
||||
new ScreencastProxy(
|
||||
Gio.DBus.session,
|
||||
'org.gnome.Shell.Screencast',
|
||||
'/org/gnome/Shell/Screencast',
|
||||
(object, error) => {
|
||||
if (error !== null) {
|
||||
log('Error connecting to the screencast service');
|
||||
return;
|
||||
}
|
||||
|
||||
this._screencastProxy = object;
|
||||
doStartScreencast();
|
||||
}
|
||||
);
|
||||
try {
|
||||
const [success, path] = await method(
|
||||
GLib.build_filenamev([
|
||||
/* Translators: this is the folder where recorded
|
||||
screencasts are stored. */
|
||||
_('Screencasts'),
|
||||
/* Translators: this is a filename used for screencast
|
||||
* recording, where "%d" and "%t" date and time, e.g.
|
||||
* "Screencast from 07-17-2013 10:00:46 PM.webm" */
|
||||
/* xgettext:no-c-format */
|
||||
_('Screencast from %d %t.webm'),
|
||||
]),
|
||||
{'draw-cursor': new GLib.Variant('b', drawCursor)});
|
||||
if (!success)
|
||||
throw new Error();
|
||||
this._screencastPath = path;
|
||||
} catch (error) {
|
||||
this._setScreencastInProgress(false);
|
||||
const {message} = error;
|
||||
if (message)
|
||||
log(`Error starting screencast: ${message}`);
|
||||
else
|
||||
log('Error starting screencast');
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user