Expose screencast functionality via DBus
Like screenshots, the screen recorder can be a useful tool in other cases than being triggered by a keyboard shortcut. To account for that, export a Screencast DBus API similar to the existing Screenshot interface. https://bugzilla.gnome.org/show_bug.cgi?id=696247
This commit is contained in:
parent
d44d00f0f4
commit
24c530611f
@ -15,6 +15,7 @@ desktop_DATA = gnome-shell.desktop gnome-shell-extension-prefs.desktop
|
|||||||
|
|
||||||
introspectiondir = $(datadir)/dbus-1/interfaces
|
introspectiondir = $(datadir)/dbus-1/interfaces
|
||||||
introspection_DATA = \
|
introspection_DATA = \
|
||||||
|
org.gnome.Shell.Screencast.xml \
|
||||||
org.gnome.Shell.Screenshot.xml \
|
org.gnome.Shell.Screenshot.xml \
|
||||||
org.gnome.ShellSearchProvider.xml \
|
org.gnome.ShellSearchProvider.xml \
|
||||||
org.gnome.ShellSearchProvider2.xml
|
org.gnome.ShellSearchProvider2.xml
|
||||||
|
96
data/org.gnome.Shell.Screencast.xml
Normal file
96
data/org.gnome.Shell.Screencast.xml
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
<!DOCTYPE node PUBLIC
|
||||||
|
'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
|
||||||
|
'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
|
||||||
|
<node>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
org.gnome.Shell.Screencast:
|
||||||
|
@short_description: Screencast interface
|
||||||
|
|
||||||
|
The interface used to record screen contents.
|
||||||
|
-->
|
||||||
|
<interface name="org.gnome.Shell.Screencast">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Screencast:
|
||||||
|
@file_template: the template for the filename to use
|
||||||
|
@options: a dictionary of optional parameters
|
||||||
|
@success: whether the screencast was started successfully
|
||||||
|
@filename_used: the file where the screencast is being saved
|
||||||
|
|
||||||
|
Records a screencast of the whole screen and saves it
|
||||||
|
(by default) as webm video under a filename derived from
|
||||||
|
@file_template. The template is either a relative or absolute
|
||||||
|
filename which may contain some escape sequences - %d and %t
|
||||||
|
will be replaced by the start date and time of the recording.
|
||||||
|
If a relative name is used, the screencast will be saved in the
|
||||||
|
$XDG_VIDEOS_DIR if it exists, or the home directory otherwise.
|
||||||
|
The actual filename of the saved video is returned in @filename_used.
|
||||||
|
The set of optional parameters in @options currently consists of:
|
||||||
|
'draw-cursor'(b): whether the cursor should be included in the
|
||||||
|
recording (true)
|
||||||
|
'framerate'(i): the number of frames per second that should be
|
||||||
|
recorded if possible (30)
|
||||||
|
'pipeline'(s): the GStreamer pipeline used to encode recordings
|
||||||
|
in gst-launch format; if not specified, the
|
||||||
|
recorder will produce vp8 (webm) video (unset)
|
||||||
|
-->
|
||||||
|
<method name="Screencast">
|
||||||
|
<arg type="s" direction="in" name="file_template"/>
|
||||||
|
<arg type="a{sv}" direction="in" name="options"/>
|
||||||
|
<arg type="b" direction="in" name="flash"/>
|
||||||
|
<arg type="b" direction="out" name="success"/>
|
||||||
|
<arg type="s" direction="out" name="filename_used"/>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
ScreencastArea:
|
||||||
|
@x: the X coordinate of the area to capture
|
||||||
|
@y: the Y coordinate of the area to capture
|
||||||
|
@width: the width of the area to capture
|
||||||
|
@height: the height of the area to capture
|
||||||
|
@file_template: the template for the filename to use
|
||||||
|
@options: a dictionary of optional parameters
|
||||||
|
@success: whether the screencast was started successfully
|
||||||
|
@filename_used: the file where the screencast is being saved
|
||||||
|
|
||||||
|
Records a screencast of the passed in area and saves it
|
||||||
|
(by default) as webm video under a filename derived from
|
||||||
|
@file_template. The template is either a relative or absolute
|
||||||
|
filename which may contain some escape sequences - %d and %t
|
||||||
|
will be replaced by the start date and time of the recording.
|
||||||
|
If a relative name is used, the screencast will be saved in the
|
||||||
|
$XDG_VIDEOS_DIR if it exists, or the home directory otherwise.
|
||||||
|
The actual filename of the saved video is returned in @filename_used.
|
||||||
|
The set of optional parameters in @options currently consists of:
|
||||||
|
'draw-cursor'(b): whether the cursor should be included in the
|
||||||
|
recording (true)
|
||||||
|
'framerate'(i): the number of frames per second that should be
|
||||||
|
recorded if possible (30)
|
||||||
|
'pipeline'(s): the GStreamer pipeline used to encode recordings
|
||||||
|
in gst-launch format; if not specified, the
|
||||||
|
recorder will produce vp8 (webm) video (unset)
|
||||||
|
-->
|
||||||
|
<method name="ScreencastArea">
|
||||||
|
<arg type="i" direction="in" name="x"/>
|
||||||
|
<arg type="i" direction="in" name="y"/>
|
||||||
|
<arg type="i" direction="in" name="width"/>
|
||||||
|
<arg type="i" direction="in" name="height"/>
|
||||||
|
<arg type="s" direction="in" name="file_template"/>
|
||||||
|
<arg type="a{sv}" direction="in" name="options"/>
|
||||||
|
<arg type="b" direction="out" name="success"/>
|
||||||
|
<arg type="s" direction="out" name="filename_used"/>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
StopScreencast:
|
||||||
|
@success: whether stopping the recording was successful
|
||||||
|
|
||||||
|
Stop the recording started by either Screencast or ScreencastArea.
|
||||||
|
-->
|
||||||
|
<method name="StopScreencasta">
|
||||||
|
<arg type="b" direction="out" name="success"/>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
</interface>
|
||||||
|
</node>
|
@ -78,6 +78,7 @@ nobase_dist_js_DATA = \
|
|||||||
ui/popupMenu.js \
|
ui/popupMenu.js \
|
||||||
ui/remoteSearch.js \
|
ui/remoteSearch.js \
|
||||||
ui/runDialog.js \
|
ui/runDialog.js \
|
||||||
|
ui/screencast.js \
|
||||||
ui/screenshot.js \
|
ui/screenshot.js \
|
||||||
ui/screenShield.js \
|
ui/screenShield.js \
|
||||||
ui/scripting.js \
|
ui/scripting.js \
|
||||||
|
138
js/ui/screencast.js
Normal file
138
js/ui/screencast.js
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
|
const GLib = imports.gi.GLib;
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const Shell = imports.gi.Shell;
|
||||||
|
|
||||||
|
const Hash = imports.misc.hash;
|
||||||
|
const Main = imports.ui.main;
|
||||||
|
|
||||||
|
const ScreencastIface = <interface name="org.gnome.Shell.Screencast">
|
||||||
|
<method name="Screencast">
|
||||||
|
<arg type="s" direction="in" name="file_template"/>
|
||||||
|
<arg type="a{sv}" direction="in" name="options"/>
|
||||||
|
<arg type="b" direction="out" name="success"/>
|
||||||
|
<arg type="s" direction="out" name="filename_used"/>
|
||||||
|
</method>
|
||||||
|
<method name="ScreencastArea">
|
||||||
|
<arg type="i" direction="in" name="x"/>
|
||||||
|
<arg type="i" direction="in" name="y"/>
|
||||||
|
<arg type="i" direction="in" name="width"/>
|
||||||
|
<arg type="i" direction="in" name="height"/>
|
||||||
|
<arg type="s" direction="in" name="file_template"/>
|
||||||
|
<arg type="a{sv}" direction="in" name="options"/>
|
||||||
|
<arg type="b" direction="out" name="success"/>
|
||||||
|
<arg type="s" direction="out" name="filename_used"/>
|
||||||
|
</method>
|
||||||
|
<method name="StopScreencast">
|
||||||
|
<arg type="b" direction="out" name="success"/>
|
||||||
|
</method>
|
||||||
|
</interface>;
|
||||||
|
|
||||||
|
const ScreencastService = new Lang.Class({
|
||||||
|
Name: 'ScreencastService',
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ScreencastIface, this);
|
||||||
|
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell/Screencast');
|
||||||
|
|
||||||
|
Gio.DBus.session.own_name('org.gnome.Shell.Screencast', Gio.BusNameOwnerFlags.REPLACE, null, null);
|
||||||
|
|
||||||
|
this._recorders = new Hash.Map();
|
||||||
|
|
||||||
|
Main.sessionMode.connect('updated',
|
||||||
|
Lang.bind(this, this._sessionModeChanged));
|
||||||
|
},
|
||||||
|
|
||||||
|
_ensureRecorderForSender: function(sender) {
|
||||||
|
let recorder = this._recorders.get(sender);
|
||||||
|
if (!recorder) {
|
||||||
|
recorder = new Shell.Recorder({ stage: global.stage });
|
||||||
|
recorder._watchNameId =
|
||||||
|
Gio.bus_watch_name(Gio.BusType.SESSION, sender, 0, null,
|
||||||
|
Lang.bind(this, this._onNameVanished));
|
||||||
|
this._recorders.set(sender, recorder);
|
||||||
|
}
|
||||||
|
return recorder;
|
||||||
|
},
|
||||||
|
|
||||||
|
_sessionModeChanged: function() {
|
||||||
|
if (Main.sessionMode.allowScreencast)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (let sender in this._recorders.keys())
|
||||||
|
this._recorders.delete(sender);
|
||||||
|
},
|
||||||
|
|
||||||
|
_onNameVanished: function(connection, name) {
|
||||||
|
this._stopRecordingForSender(name);
|
||||||
|
},
|
||||||
|
|
||||||
|
_stopRecordingForSender: function(sender) {
|
||||||
|
let recorder = this._recorders.get(sender);
|
||||||
|
if (!recorder)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Gio.bus_unwatch_name(recorder._watchNameId);
|
||||||
|
recorder.close();
|
||||||
|
this._recorders.delete(sender);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
_applyOptionalParameters: function(recorder, options) {
|
||||||
|
for (let option in options)
|
||||||
|
options[option] = options[option].deep_unpack();
|
||||||
|
|
||||||
|
if (options['pipeline'])
|
||||||
|
recorder.set_pipeline(options['pipeline']);
|
||||||
|
if (options['framerate'])
|
||||||
|
recorder.set_framerate(options['framerate']);
|
||||||
|
if (options['draw-cursor'])
|
||||||
|
recorder.set_draw_cursor(options['draw-cursor']);
|
||||||
|
},
|
||||||
|
|
||||||
|
ScreencastAsync: function(params, invocation) {
|
||||||
|
let returnValue = [false, ''];
|
||||||
|
if (!Main.sessionMode.allowScreencast)
|
||||||
|
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
|
||||||
|
|
||||||
|
let sender = invocation.get_sender();
|
||||||
|
let recorder = this._ensureRecorderForSender(sender);
|
||||||
|
if (!recorder.is_recording()) {
|
||||||
|
let [fileTemplate, options] = params;
|
||||||
|
|
||||||
|
recorder.set_file_template(fileTemplate);
|
||||||
|
this._applyOptionalParameters(recorder, options);
|
||||||
|
returnValue = recorder.record();
|
||||||
|
}
|
||||||
|
|
||||||
|
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
|
||||||
|
},
|
||||||
|
|
||||||
|
ScreencastAreaAsync: function(params, invocation) {
|
||||||
|
let returnValue = [false, ''];
|
||||||
|
if (!Main.sessionMode.allowScreencast)
|
||||||
|
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
|
||||||
|
|
||||||
|
let sender = invocation.get_sender();
|
||||||
|
let recorder = this._ensureRecorderForSender(sender);
|
||||||
|
|
||||||
|
if (!recorder.is_recording()) {
|
||||||
|
let [x, y, width, height, fileTemplate, options] = params;
|
||||||
|
|
||||||
|
recorder.set_file_template(fileTemplate);
|
||||||
|
recorder.set_area(x, y, width, height);
|
||||||
|
this._applyOptionalParameters(recorder, options);
|
||||||
|
returnValue = recorder.record();
|
||||||
|
}
|
||||||
|
|
||||||
|
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
|
||||||
|
},
|
||||||
|
|
||||||
|
StopScreencastAsync: function(params, invocation) {
|
||||||
|
let success = this._stopRecordingForSender(invocation.get_sender());
|
||||||
|
invocation.return_value(GLib.Variant.new('(b)', [success]));
|
||||||
|
}
|
||||||
|
});
|
@ -12,6 +12,7 @@ const ExtensionDownloader = imports.ui.extensionDownloader;
|
|||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
const ExtensionUtils = imports.misc.extensionUtils;
|
||||||
const Hash = imports.misc.hash;
|
const Hash = imports.misc.hash;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
|
const Screencast = imports.ui.screencast;
|
||||||
const Screenshot = imports.ui.screenshot;
|
const Screenshot = imports.ui.screenshot;
|
||||||
|
|
||||||
const GnomeShellIface = <interface name="org.gnome.Shell">
|
const GnomeShellIface = <interface name="org.gnome.Shell">
|
||||||
@ -70,6 +71,7 @@ const GnomeShell = new Lang.Class({
|
|||||||
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell');
|
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell');
|
||||||
|
|
||||||
this._extensionsService = new GnomeShellExtensions();
|
this._extensionsService = new GnomeShellExtensions();
|
||||||
|
this._screencastService = new Screencast.ScreencastService();
|
||||||
this._screenshotService = new Screenshot.ScreenshotService();
|
this._screenshotService = new Screenshot.ScreenshotService();
|
||||||
|
|
||||||
this._grabbedAccelerators = new Hash.Map();
|
this._grabbedAccelerators = new Hash.Map();
|
||||||
|
Loading…
Reference in New Issue
Block a user