diff --git a/js/js-resources.gresource.xml b/js/js-resources.gresource.xml index 58035d303..22ba047d8 100644 --- a/js/js-resources.gresource.xml +++ b/js/js-resources.gresource.xml @@ -131,6 +131,7 @@ ui/status/rfkill.js ui/status/volume.js ui/status/bluetooth.js + ui/status/remoteAccess.js ui/status/screencast.js ui/status/system.js ui/status/thunderbolt.js diff --git a/js/ui/panel.js b/js/ui/panel.js index d1a572503..7a136fec5 100644 --- a/js/ui/panel.js +++ b/js/ui/panel.js @@ -716,6 +716,7 @@ var AggregateMenu = new Lang.Class({ this._bluetooth = null; } + this._remoteAccess = new imports.ui.status.remoteAccess.RemoteAccessApplet(); this._power = new imports.ui.status.power.Indicator(); this._rfkill = new imports.ui.status.rfkill.Indicator(); this._volume = new imports.ui.status.volume.Indicator(); @@ -736,6 +737,7 @@ var AggregateMenu = new Lang.Class({ if (this._bluetooth) { this._indicators.add_child(this._bluetooth.indicators); } + this._indicators.add_child(this._remoteAccess.indicators); this._indicators.add_child(this._rfkill.indicators); this._indicators.add_child(this._volume.indicators); this._indicators.add_child(this._power.indicators); @@ -750,6 +752,7 @@ var AggregateMenu = new Lang.Class({ if (this._bluetooth) { this.menu.addMenuItem(this._bluetooth.menu); } + this.menu.addMenuItem(this._remoteAccess.menu); this.menu.addMenuItem(this._location.menu); this.menu.addMenuItem(this._rfkill.menu); this.menu.addMenuItem(this._power.menu); diff --git a/js/ui/status/remoteAccess.js b/js/ui/status/remoteAccess.js new file mode 100644 index 000000000..ffa334001 --- /dev/null +++ b/js/ui/status/remoteAccess.js @@ -0,0 +1,80 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const Lang = imports.lang; +const Meta = imports.gi.Meta; + +const PanelMenu = imports.ui.panelMenu; +const PopupMenu = imports.ui.popupMenu; + +var RemoteAccessApplet = new Lang.Class({ + Name: 'RemoteAccessApplet', + Extends: PanelMenu.SystemIndicator, + + _init() { + this.parent(); + + let backend = Meta.get_backend(); + let controller = backend.get_remote_access_controller(); + + if (!controller) + return; + + // We can't possibly know about all types of screen sharing on X11, so + // showing these controls on X11 might give a false sense of security. + // Thus, only enable these controls when using Wayland, where we are + // in control of sharing. + if (!Meta.is_wayland_compositor()) + return; + + this._handles = new Set(); + this._indicator = null; + this._menuSection = null; + + controller.connect('new-handle', (controller, handle) => { + this._onNewHandle(handle); + }); + }, + + _ensureControls() { + if (this._indicator) + return; + + this._indicator = this._addIndicator(); + this._indicator.icon_name = 'screen-shared-symbolic'; + this._item = + new PopupMenu.PopupSubMenuMenuItem(_("Screen is Being Shared"), + true); + this._item.menu.addAction(_("Turn off"), + () => { + for (let handle of this._handles) + handle.stop(); + }); + this._item.icon.icon_name = 'screen-shared-symbolic'; + this.menu.addMenuItem(this._item); + }, + + _sync() { + if (this._handles.size == 0) { + this._indicator.visible = false; + this._item.actor.visible = false; + } else { + this._indicator.visible = true; + this._item.actor.visible = true; + } + }, + + _onStopped(handle) { + this._handles.delete(handle); + this._sync(); + }, + + _onNewHandle(handle) { + this._handles.add(handle); + handle.connect('stopped', this._onStopped.bind(this)); + + if (this._handles.size == 1) { + this._ensureControls(); + this._sync(); + } + }, +});