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.
|
The interface used to record screen contents.
|
||||||
-->
|
-->
|
||||||
<interface name="org.gnome.Shell.Screencast">
|
<interface name="org.gnome.Shell.Screencast">
|
||||||
|
<property name="ScreencastSupported" type="b" access="read"/>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Screencast:
|
Screencast:
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
/* exported main */
|
/* exported main */
|
||||||
|
|
||||||
const Config = imports.misc.config;
|
const {DBusService} = imports.dbusService;
|
||||||
const { DBusService } = imports.dbusService;
|
|
||||||
|
|
||||||
function main() {
|
function main() {
|
||||||
if (!Config.HAVE_RECORDER)
|
const {ScreencastService} = imports.screencastService;
|
||||||
|
if (!ScreencastService.canScreencast())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const { ScreencastService } = imports.screencastService;
|
|
||||||
const service = new DBusService(
|
const service = new DBusService(
|
||||||
'org.gnome.Shell.Screencast',
|
'org.gnome.Shell.Screencast',
|
||||||
new ScreencastService());
|
new ScreencastService());
|
||||||
|
@ -258,9 +258,17 @@ var Recorder = class {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var ScreencastService = class extends ServiceImplementation {
|
var ScreencastService = class extends ServiceImplementation {
|
||||||
|
static canScreencast() {
|
||||||
|
return Gst.init_check(null) &&
|
||||||
|
Gst.ElementFactory.find('pipewiresrc') &&
|
||||||
|
Gst.ElementFactory.find('filesink');
|
||||||
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(ScreencastIface, '/org/gnome/Shell/Screencast');
|
super(ScreencastIface, '/org/gnome/Shell/Screencast');
|
||||||
|
|
||||||
|
this._canScreencast = ScreencastService.canScreencast();
|
||||||
|
|
||||||
Gst.init(null);
|
Gst.init(null);
|
||||||
Gtk.init();
|
Gtk.init();
|
||||||
|
|
||||||
@ -280,6 +288,10 @@ var ScreencastService = class extends ServiceImplementation {
|
|||||||
'/org/gnome/Shell/Introspect');
|
'/org/gnome/Shell/Introspect');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get ScreencastSupported() {
|
||||||
|
return this._canScreencast;
|
||||||
|
}
|
||||||
|
|
||||||
_removeRecorder(sender) {
|
_removeRecorder(sender) {
|
||||||
this._recorders.delete(sender);
|
this._recorders.delete(sender);
|
||||||
if (this._recorders.size === 0)
|
if (this._recorders.size === 0)
|
||||||
|
@ -21,8 +21,3 @@ var LIBMUTTER_API_VERSION = '@LIBMUTTER_API_VERSION@'
|
|||||||
|
|
||||||
var HAVE_BLUETOOTH = pkg.checkSymbol('GnomeBluetooth', '3.0',
|
var HAVE_BLUETOOTH = pkg.checkSymbol('GnomeBluetooth', '3.0',
|
||||||
'Client.default_adapter_state')
|
'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 { Clutter, Cogl, Gio, GObject, GLib, Graphene, Gtk, Meta, Shell, St } = imports.gi;
|
||||||
|
|
||||||
const Config = imports.misc.config;
|
|
||||||
const GrabHelper = imports.ui.grabHelper;
|
const GrabHelper = imports.ui.grabHelper;
|
||||||
const Layout = imports.ui.layout;
|
const Layout = imports.ui.layout;
|
||||||
const Lightbox = imports.ui.lightbox;
|
const Lightbox = imports.ui.lightbox;
|
||||||
@ -1019,6 +1018,19 @@ var ScreenshotUI = GObject.registerClass({
|
|||||||
|
|
||||||
this._screencastInProgress = false;
|
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' });
|
this._lockdownSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.lockdown' });
|
||||||
|
|
||||||
// The full-screen screenshot has a separate container so that we can
|
// 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',
|
style_class: 'screenshot-ui-shot-cast-button',
|
||||||
icon_name: 'camera-web-symbolic',
|
icon_name: 'camera-web-symbolic',
|
||||||
toggle_mode: true,
|
toggle_mode: true,
|
||||||
visible: Config.HAVE_RECORDER,
|
visible: false,
|
||||||
});
|
});
|
||||||
this._castButton.connect('notify::checked',
|
this._castButton.connect('notify::checked',
|
||||||
this._onCastButtonToggled.bind(this));
|
this._onCastButtonToggled.bind(this));
|
||||||
@ -1438,7 +1450,7 @@ var ScreenshotUI = GObject.registerClass({
|
|||||||
if (this._screencastInProgress)
|
if (this._screencastInProgress)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (mode === UIMode.SCREENCAST && !Config.HAVE_RECORDER)
|
if (mode === UIMode.SCREENCAST && !this._screencastProxy.ScreencastSupported)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._castButton.checked = mode === UIMode.SCREENCAST;
|
this._castButton.checked = mode === UIMode.SCREENCAST;
|
||||||
@ -1809,7 +1821,7 @@ var ScreenshotUI = GObject.registerClass({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_startScreencast() {
|
async _startScreencast() {
|
||||||
if (this._windowButton.checked)
|
if (this._windowButton.checked)
|
||||||
return; // TODO
|
return; // TODO
|
||||||
|
|
||||||
@ -1833,61 +1845,40 @@ var ScreenshotUI = GObject.registerClass({
|
|||||||
this.close(true);
|
this.close(true);
|
||||||
|
|
||||||
// This is a bit awkward because creating a proxy synchronously hangs Shell.
|
// This is a bit awkward because creating a proxy synchronously hangs Shell.
|
||||||
const doStartScreencast = async () => {
|
let method =
|
||||||
let method =
|
this._screencastProxy.ScreencastAsync.bind(this._screencastProxy);
|
||||||
this._screencastProxy.ScreencastAsync.bind(this._screencastProxy);
|
if (w !== -1) {
|
||||||
if (w !== -1) {
|
method = this._screencastProxy.ScreencastAreaAsync.bind(
|
||||||
method = this._screencastProxy.ScreencastAreaAsync.bind(
|
this._screencastProxy, x, y, w, h);
|
||||||
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');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set this before calling the method as the screen recording indicator
|
// Set this before calling the method as the screen recording indicator
|
||||||
// will check it before the success callback fires.
|
// will check it before the success callback fires.
|
||||||
this._setScreencastInProgress(true);
|
this._setScreencastInProgress(true);
|
||||||
|
|
||||||
if (this._screencastProxy) {
|
try {
|
||||||
doStartScreencast();
|
const [success, path] = await method(
|
||||||
} else {
|
GLib.build_filenamev([
|
||||||
new ScreencastProxy(
|
/* Translators: this is the folder where recorded
|
||||||
Gio.DBus.session,
|
screencasts are stored. */
|
||||||
'org.gnome.Shell.Screencast',
|
_('Screencasts'),
|
||||||
'/org/gnome/Shell/Screencast',
|
/* Translators: this is a filename used for screencast
|
||||||
(object, error) => {
|
* recording, where "%d" and "%t" date and time, e.g.
|
||||||
if (error !== null) {
|
* "Screencast from 07-17-2013 10:00:46 PM.webm" */
|
||||||
log('Error connecting to the screencast service');
|
/* xgettext:no-c-format */
|
||||||
return;
|
_('Screencast from %d %t.webm'),
|
||||||
}
|
]),
|
||||||
|
{'draw-cursor': new GLib.Variant('b', drawCursor)});
|
||||||
this._screencastProxy = object;
|
if (!success)
|
||||||
doStartScreencast();
|
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