status/remote-access: Split out screen sharing indicator
The latest mockups move the screen sharing indicator into a separate control, similar to the existing indicator for built-in screen recordings. As this removes the submenu and only keeps the top bar icon (for external screen recordings), this will smooth the transition to quick settings. Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2391>
This commit is contained in:
parent
4f155d3757
commit
7ab7df739a
@ -40,7 +40,14 @@ $panel_transition_duration: 250ms; // same as the overview transition duration
|
||||
|
||||
&.screen-recording-indicator {
|
||||
box-shadow: inset 0 0 0 100px $screenshot_ui_button_red;
|
||||
}
|
||||
&.screen-sharing-indicator {
|
||||
box-shadow: inset 0 0 0 100px $warning_color;
|
||||
StBoxLayout { margin: 0 $base_padding; }
|
||||
}
|
||||
|
||||
&.screen-recording-indicator,
|
||||
&.screen-sharing-indicator {
|
||||
StBoxLayout {
|
||||
spacing: $base_padding;
|
||||
}
|
||||
@ -66,6 +73,9 @@ $panel_transition_duration: 250ms; // same as the overview transition duration
|
||||
&.screen-recording-indicator {
|
||||
box-shadow: inset 0 0 0 100px transparentize($screenshot_ui_button_red, 0.15);
|
||||
}
|
||||
&.screen-sharing-indicator {
|
||||
box-shadow: inset 0 0 0 100px transparentize($warning_color, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@ -80,6 +90,9 @@ $panel_transition_duration: 250ms; // same as the overview transition duration
|
||||
&.screen-recording-indicator {
|
||||
box-shadow: inset 0 0 0 100px transparentize($screenshot_ui_button_red, 0.1);
|
||||
}
|
||||
&.screen-sharing-indicator {
|
||||
box-shadow: inset 0 0 0 100px transparentize($warning_color, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
&:active:hover, &:overview:hover, &:focus:hover, &:checked:hover {
|
||||
@ -94,6 +107,9 @@ $panel_transition_duration: 250ms; // same as the overview transition duration
|
||||
&.screen-recording-indicator {
|
||||
box-shadow: inset 0 0 0 100px transparentize($screenshot_ui_button_red, 0.2);
|
||||
}
|
||||
&.screen-sharing-indicator {
|
||||
box-shadow: inset 0 0 0 100px transparentize($warning_color, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
// status area icons
|
||||
@ -137,6 +153,9 @@ $panel_transition_duration: 250ms; // same as the overview transition duration
|
||||
&.screen-recording-indicator {
|
||||
box-shadow: inset 0 0 0 100px transparentize($screenshot_ui_button_red, 0.15);
|
||||
}
|
||||
&.screen-sharing-indicator {
|
||||
box-shadow: inset 0 0 0 100px transparentize($warning_color, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@ -151,6 +170,9 @@ $panel_transition_duration: 250ms; // same as the overview transition duration
|
||||
&.screen-recording-indicator {
|
||||
box-shadow: inset 0 0 0 100px transparentize($screenshot_ui_button_red, 0.1);
|
||||
}
|
||||
&.screen-sharing-indicator {
|
||||
box-shadow: inset 0 0 0 100px transparentize($warning_color, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
&:active:hover, &:overview:hover, &:focus:hover, &:checked:hover {
|
||||
@ -165,6 +187,9 @@ $panel_transition_duration: 250ms; // same as the overview transition duration
|
||||
&.screen-recording-indicator {
|
||||
box-shadow: inset 0 0 0 100px transparentize($screenshot_ui_button_red, 0.2);
|
||||
}
|
||||
&.screen-sharing-indicator {
|
||||
box-shadow: inset 0 0 0 100px transparentize($warning_color, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -441,6 +441,7 @@ const PANEL_ITEM_IMPLEMENTATIONS = {
|
||||
'keyboard': imports.ui.status.keyboard.InputSourceIndicator,
|
||||
'dwellClick': imports.ui.status.dwellClick.DwellClickIndicator,
|
||||
'screenRecording': imports.ui.status.remoteAccess.ScreenRecordingIndicator,
|
||||
'screenSharing': imports.ui.status.remoteAccess.ScreenSharingIndicator,
|
||||
};
|
||||
|
||||
var Panel = GObject.registerClass(
|
||||
|
@ -94,7 +94,7 @@ const _modes = {
|
||||
panel: {
|
||||
left: ['activities', 'appMenu'],
|
||||
center: ['dateMenu'],
|
||||
right: ['screenRecording', 'dwellClick', 'a11y', 'keyboard', 'aggregateMenu'],
|
||||
right: ['screenRecording', 'screenSharing', 'dwellClick', 'a11y', 'keyboard', 'aggregateMenu'],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -1,11 +1,10 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported RemoteAccessApplet, ScreenRecordingIndicator */
|
||||
/* exported RemoteAccessApplet, ScreenRecordingIndicator, ScreenSharingIndicator */
|
||||
|
||||
const { Atk, Clutter, GLib, GObject, Meta, St } = imports.gi;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
|
||||
// Minimum amount of time the shared indicator is visible (in micro seconds)
|
||||
const MIN_SHARED_INDICATOR_VISIBLE_TIME_US = 5 * GLib.TIME_SPAN_SECOND;
|
||||
@ -21,97 +20,30 @@ class RemoteAccessApplet extends PanelMenu.SystemIndicator {
|
||||
return;
|
||||
|
||||
this._handles = new Set();
|
||||
this._sharedIndicator = null;
|
||||
this._recordingIndicator = null;
|
||||
this._menuSection = null;
|
||||
|
||||
this._indicator = this._addIndicator();
|
||||
this._indicator.set({
|
||||
style_class: 'screencast-indicator',
|
||||
icon_name: 'media-record-symbolic',
|
||||
});
|
||||
|
||||
controller.connect('new-handle', (o, handle) => {
|
||||
this._onNewHandle(handle);
|
||||
});
|
||||
}
|
||||
|
||||
_ensureControls() {
|
||||
if (this._sharedIndicator && this._recordingIndicator)
|
||||
return;
|
||||
|
||||
this._sharedIndicator = this._addIndicator();
|
||||
this._sharedIndicator.visible = false;
|
||||
this._sharedIndicator.icon_name = 'screen-shared-symbolic';
|
||||
this._sharedIndicator.add_style_class_name('remote-access-indicator');
|
||||
|
||||
this._sharedItem =
|
||||
new PopupMenu.PopupSubMenuMenuItem(_("Screen is Being Shared"),
|
||||
true);
|
||||
this._sharedItem.menu.addAction(_("Turn off"),
|
||||
() => {
|
||||
for (let handle of this._handles) {
|
||||
if (!handle.is_recording)
|
||||
handle.stop();
|
||||
}
|
||||
});
|
||||
this._sharedItem.icon.icon_name = 'screen-shared-symbolic';
|
||||
this.menu.addMenuItem(this._sharedItem);
|
||||
|
||||
this._recordingIndicator = this._addIndicator();
|
||||
this._recordingIndicator.icon_name = 'media-record-symbolic';
|
||||
this._recordingIndicator.add_style_class_name('screencast-indicator');
|
||||
}
|
||||
|
||||
_isScreenShared() {
|
||||
return [...this._handles].some(handle => !handle.is_recording);
|
||||
this._sync();
|
||||
}
|
||||
|
||||
_isRecording() {
|
||||
const recordingHandles =
|
||||
[...this._handles].filter(handle => handle.is_recording);
|
||||
|
||||
// Screenshot UI screencasts have their own panel, so don't show this
|
||||
// indicator if there's only a screenshot UI screencast.
|
||||
if (Main.screenshotUI.screencast_in_progress)
|
||||
return recordingHandles.length > 1;
|
||||
return this._handles.size > 1;
|
||||
|
||||
return recordingHandles.length > 0;
|
||||
}
|
||||
|
||||
_hideSharedIndicator() {
|
||||
this._sharedIndicator.visible = false;
|
||||
delete this._hideSharedIndicatorId;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return this._handles.size > 0;
|
||||
}
|
||||
|
||||
_sync() {
|
||||
if (this._hideSharedIndicatorId) {
|
||||
GLib.source_remove(this._hideSharedIndicatorId);
|
||||
delete this._hideSharedIndicatorId;
|
||||
}
|
||||
|
||||
if (this._isScreenShared()) {
|
||||
if (!this._sharedIndicator.visible)
|
||||
this._visibleTimeUs = GLib.get_monotonic_time();
|
||||
this._sharedIndicator.visible = true;
|
||||
this._sharedItem.visible = true;
|
||||
} else {
|
||||
if (this._sharedIndicator.visible) {
|
||||
const currentTimeUs = GLib.get_monotonic_time();
|
||||
const timeSinceVisibleUs = currentTimeUs - this._visibleTimeUs;
|
||||
|
||||
if (timeSinceVisibleUs >= MIN_SHARED_INDICATOR_VISIBLE_TIME_US) {
|
||||
this._hideSharedIndicator();
|
||||
} else {
|
||||
const timeUntilHideUs =
|
||||
MIN_SHARED_INDICATOR_VISIBLE_TIME_US - timeSinceVisibleUs;
|
||||
this._hideSharedIndicatorId =
|
||||
GLib.timeout_add(
|
||||
GLib.PRIORITY_DEFAULT,
|
||||
timeUntilHideUs / GLib.TIME_SPAN_MILLISECOND,
|
||||
this._hideSharedIndicator.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
this._sharedItem.visible = false;
|
||||
}
|
||||
|
||||
this._recordingIndicator.visible = this._isRecording();
|
||||
this._indicator.visible = this._isRecording();
|
||||
}
|
||||
|
||||
_onStopped(handle) {
|
||||
@ -120,20 +52,12 @@ class RemoteAccessApplet extends PanelMenu.SystemIndicator {
|
||||
}
|
||||
|
||||
_onNewHandle(handle) {
|
||||
// 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.
|
||||
//
|
||||
// We still want to show screen recordings though, to indicate when
|
||||
// the built in screen recorder is active, no matter the session type.
|
||||
if (!Meta.is_wayland_compositor() && !handle.is_recording)
|
||||
if (!handle.is_recording)
|
||||
return;
|
||||
|
||||
this._handles.add(handle);
|
||||
handle.connect('stopped', this._onStopped.bind(this));
|
||||
|
||||
this._ensureControls();
|
||||
this._sync();
|
||||
}
|
||||
});
|
||||
@ -207,3 +131,101 @@ var ScreenRecordingIndicator = GObject.registerClass({
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var ScreenSharingIndicator = GObject.registerClass({
|
||||
Signals: {'menu-set': {}},
|
||||
}, class ScreenSharingIndicator extends PanelMenu.ButtonBox {
|
||||
_init() {
|
||||
super._init({
|
||||
reactive: true,
|
||||
can_focus: true,
|
||||
track_hover: true,
|
||||
accessible_name: _('Stop Screen Sharing'),
|
||||
accessible_role: Atk.Role.PUSH_BUTTON,
|
||||
});
|
||||
this.add_style_class_name('screen-sharing-indicator');
|
||||
|
||||
this._box = new St.BoxLayout();
|
||||
this.add_child(this._box);
|
||||
|
||||
let icon = new St.Icon({icon_name: 'screen-shared-symbolic'});
|
||||
this._box.add_child(icon);
|
||||
|
||||
icon = new St.Icon({icon_name: 'window-close-symbolic'});
|
||||
this._box.add_child(icon);
|
||||
|
||||
this._controller = global.backend.get_remote_access_controller();
|
||||
|
||||
this._handles = new Set();
|
||||
|
||||
this._controller?.connect('new-handle',
|
||||
(o, handle) => this._onNewHandle(handle));
|
||||
|
||||
this._sync();
|
||||
}
|
||||
|
||||
_onNewHandle(handle) {
|
||||
// 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;
|
||||
|
||||
if (handle.isRecording)
|
||||
return;
|
||||
|
||||
this._handles.add(handle);
|
||||
handle.connect('stopped', () => {
|
||||
this._handles.delete(handle);
|
||||
this._sync();
|
||||
});
|
||||
this._sync();
|
||||
}
|
||||
|
||||
vfunc_event(event) {
|
||||
if (event.type() === Clutter.EventType.TOUCH_BEGIN ||
|
||||
event.type() === Clutter.EventType.BUTTON_PRESS)
|
||||
this._stopSharing();
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
}
|
||||
|
||||
_stopSharing() {
|
||||
for (const handle of this._handles)
|
||||
handle.stop();
|
||||
}
|
||||
|
||||
_hideIndicator() {
|
||||
this.hide();
|
||||
delete this._hideIndicatorId;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
_sync() {
|
||||
if (this._hideIndicatorId) {
|
||||
GLib.source_remove(this._hideIndicatorId);
|
||||
delete this._hideIndicatorId;
|
||||
}
|
||||
|
||||
if (this._handles.size > 0) {
|
||||
if (!this.visible)
|
||||
this._visibleTimeUs = GLib.get_monotonic_time();
|
||||
this.show();
|
||||
} else if (this.visible) {
|
||||
const currentTimeUs = GLib.get_monotonic_time();
|
||||
const timeSinceVisibleUs = currentTimeUs - this._visibleTimeUs;
|
||||
|
||||
if (timeSinceVisibleUs >= MIN_SHARED_INDICATOR_VISIBLE_TIME_US) {
|
||||
this._hideIndicator();
|
||||
} else {
|
||||
const timeUntilHideUs =
|
||||
MIN_SHARED_INDICATOR_VISIBLE_TIME_US - timeSinceVisibleUs;
|
||||
this._hideIndicatorId =
|
||||
GLib.timeout_add(GLib.PRIORITY_DEFAULT,
|
||||
timeUntilHideUs / GLib.TIME_SPAN_MILLISECOND,
|
||||
() => this._hideIndicator());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user