Blob Blame History Raw
From 8b916620e32ee0b42734dd7896fe5058c8591d81 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Fri, 20 Jul 2018 16:50:50 +0200
Subject: [PATCH 1/2] Add remote access indication and control

Add an indicator for when there is something access the display server
remotely. This could be 1) remote desktop, 2) screen cast or 3) remote
control, but all effectively applications using
org.freedesktop.portal.ScreenCast or org.gnome.portal.RemoteDesktop as
well as gnome-remote-desktop using the corresponding org.gnome.Mutter
APIs directly.

As it is now, it'll simply show a single icon for when anything is
having an active session, and a single action "Turn off" that'll close
every active session.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/160
---
 js/js-resources.gresource.xml |  1 +
 js/ui/panel.js                |  3 ++
 js/ui/status/remoteAccess.js  | 80 +++++++++++++++++++++++++++++++++++
 3 files changed, 84 insertions(+)
 create mode 100644 js/ui/status/remoteAccess.js

diff --git a/js/js-resources.gresource.xml b/js/js-resources.gresource.xml
index 883b62d66..cc1da4461 100644
--- a/js/js-resources.gresource.xml
+++ b/js/js-resources.gresource.xml
@@ -130,6 +130,7 @@
     <file>ui/status/rfkill.js</file>
     <file>ui/status/volume.js</file>
     <file>ui/status/bluetooth.js</file>
+    <file>ui/status/remoteAccess.js</file>
     <file>ui/status/screencast.js</file>
     <file>ui/status/system.js</file>
     <file>ui/status/thunderbolt.js</file>
diff --git a/js/ui/panel.js b/js/ui/panel.js
index d44ed9fec..53cc445f8 100644
--- a/js/ui/panel.js
+++ b/js/ui/panel.js
@@ -709,6 +709,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();
@@ -729,6 +730,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);
@@ -743,6 +745,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();
+        }
+    },
+});
-- 
2.17.1