[gnome-shell-extensions/wip/rstrode/heads-up-display: 24/62] window-list: Add window picker button
- From: Ray Strode <halfline src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell-extensions/wip/rstrode/heads-up-display: 24/62] window-list: Add window picker button
- Date: Thu, 26 Aug 2021 19:31:31 +0000 (UTC)
commit ff53c967fe7fa15858a708804d654f49d4785a6f
Author: Florian Müllner <fmuellner gnome org>
Date: Tue May 14 19:51:22 2019 +0200
window-list: Add window picker button
With the latest changes, GNOME Classic has become so classic that it
is bordering dull. Salvage at least a tiny piece of GNOME 3 in form
of a window-pick button which toggles an exposé-like reduced overview.
https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/73
extensions/window-list/classic.css | 20 ++-
extensions/window-list/extension.js | 36 ++++-
extensions/window-list/meson.build | 2 +-
extensions/window-list/stylesheet.css | 27 +++-
extensions/window-list/windowPicker.js | 260 +++++++++++++++++++++++++++++++++
5 files changed, 332 insertions(+), 13 deletions(-)
---
diff --git a/extensions/window-list/classic.css b/extensions/window-list/classic.css
index f3c44a3..c506bea 100644
--- a/extensions/window-list/classic.css
+++ b/extensions/window-list/classic.css
@@ -6,14 +6,13 @@
height: 2.25em ;
}
- .bottom-panel .window-button > StWidget {
+ .bottom-panel .window-button > StWidget,
+ .bottom-panel .window-picker-toggle > StWidget {
background-gradient-drection: vertical;
background-color: #fff;
background-gradient-start: #fff;
background-gradient-end: #eee;
color: #000;
- -st-natural-width: 18.7em;
- max-width: 18.75em;
color: #2e3436;
background-color: #eee;
border-radius: 2px;
@@ -22,7 +21,17 @@
text-shadow: 0 0 transparent;
}
- .bottom-panel .window-button:hover > StWidget {
+ .bottom-panel .window-button > StWidget {
+ -st-natural-width: 18.7em;
+ max-width: 18.75em;
+ }
+
+ .bottom-panel .window-picker-toggle > StWidet {
+ border: 1px solid rgba(0,0,0,0.3);
+ }
+
+ .bottom-panel .window-button:hover > StWidget,
+ .bottom-panel .window-picker-toggle:hover > StWidget {
background-color: #f9f9f9;
}
@@ -31,7 +40,8 @@
box-shadow: inset 1px 1px 2px rgba(0,0,0,0.5);
}
- .bottom-panel .window-button.focused > StWidget {
+ .bottom-panel .window-button.focused > StWidget,
+ .bottom-panel .window-picker-toggle:checked > StWidget {
background-color: #ddd;
box-shadow: inset 1px 1px 1px rgba(0,0,0,0.5);
}
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index e1ea742..b2784b4 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -3,11 +3,14 @@ const { Clutter, Gio, GLib, GObject, Gtk, Meta, Shell, St } = imports.gi;
const DND = imports.ui.dnd;
const Main = imports.ui.main;
+const Overview = imports.ui.overview;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
+const Tweener = imports.ui.tweener;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
+const { WindowPicker, WindowPickerToggle } = Me.imports.windowPicker;
const Gettext = imports.gettext.domain('gnome-shell-extensions');
const _ = Gettext.gettext;
@@ -787,6 +790,12 @@ class WindowList {
let box = new St.BoxLayout({ x_expand: true, y_expand: true });
this.actor.add_actor(box);
+ let toggle = new WindowPickerToggle();
+ box.add_actor(toggle);
+
+ toggle.connect('notify::checked',
+ this._updateWindowListVisibility.bind(this));
+
let layout = new Clutter.BoxLayout({ homogeneous: true });
this._windowList = new St.Widget({
style_class: 'window-list',
@@ -936,6 +945,19 @@ class WindowList {
this._workspaceIndicator.actor.visible = hasWorkspaces && workspacesOnMonitor;
}
+ _updateWindowListVisibility() {
+ let visible = !Main.windowPicker.visible;
+
+ Tweener.addTween(this._windowList, {
+ opacity: visible ? 255 : 0,
+ transition: 'ease-out-quad',
+ time: Overview.ANIMATION_TIME
+ });
+
+ this._windowList.reactive = visible;
+ this._windowList.get_children().forEach(c => c.reactive = visible);
+ }
+
_getPreferredUngroupedWindowListWidth() {
if (this._windowList.get_n_children() == 0)
return this._windowList.get_preferred_width(-1)[1];
@@ -1206,7 +1228,7 @@ class WindowList {
class Extension {
constructor() {
this._windowLists = null;
- this._injections = {};
+ this._hideOverviewOrig = Main.overview.hide;
}
enable() {
@@ -1221,6 +1243,13 @@ class Extension {
Main.layoutManager.connect('monitors-changed',
this._buildWindowLists.bind(this));
+ Main.windowPicker = new WindowPicker();
+
+ Main.overview.hide = () => {
+ Main.windowPicker.close();
+ this._hideOverviewOrig.call(Main.overview);
+ };
+
this._buildWindowLists();
}
@@ -1251,6 +1280,11 @@ class Extension {
windowList.actor.destroy();
});
this._windowLists = null;
+
+ Main.windowPicker.actor.destroy();
+ delete Main.windowPicker;
+
+ Main.overview.hide = this._hideOverviewOrig;
}
someWindowListContains(actor) {
diff --git a/extensions/window-list/meson.build b/extensions/window-list/meson.build
index b4aa4db..5b1f5f5 100644
--- a/extensions/window-list/meson.build
+++ b/extensions/window-list/meson.build
@@ -4,7 +4,7 @@ extension_data += configure_file(
configuration: metadata_conf
)
-extension_sources += files('prefs.js')
+extension_sources += files('prefs.js', 'windowPicker.js')
extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml')
if classic_mode_enabled
diff --git a/extensions/window-list/stylesheet.css b/extensions/window-list/stylesheet.css
index f5285cb..91383ab 100644
--- a/extensions/window-list/stylesheet.css
+++ b/extensions/window-list/stylesheet.css
@@ -26,9 +26,8 @@
spacing: 4px;
}
-.window-button > StWidget {
- -st-natural-width: 18.75em;
- max-width: 18.75em;
+.window-button > StWidget,
+.window-picker-toggle > StWidget {
color: #bbb;
background-color: black;
border-radius: 4px;
@@ -37,7 +36,21 @@
text-shadow: 1px 1px 4px rgba(0,0,0,0.8);
}
-.window-button:hover > StWidget {
+.window-picker-toggle {
+ padding: 3px;
+}
+
+.window-picker-toggle > StWidet {
+ border: 1px solid rgba(255,255,255,0.3);
+}
+
+.window-button > StWidget {
+ -st-natural-width: 18.75em;
+ max-width: 18.75em;
+}
+
+.window-button:hover > StWidget,
+.window-picker-toggle:hover > StWidget {
color: white;
background-color: #1f1f1f;
}
@@ -47,12 +60,14 @@
box-shadow: inset 2px 2px 4px rgba(255,255,255,0.5);
}
-.window-button.focused > StWidget {
+.window-button.focused > StWidget,
+.window-picker-toggle:checked > StWidget {
color: white;
box-shadow: inset 1px 1px 4px rgba(255,255,255,0.7);
}
-.window-button.focused:active > StWidget {
+.window-button.focused:active > StWidget,
+.window-picker-toggle:checked:active > StWidget {
box-shadow: inset 2px 2px 4px rgba(255,255,255,0.7);
}
diff --git a/extensions/window-list/windowPicker.js b/extensions/window-list/windowPicker.js
new file mode 100644
index 0000000..024fd80
--- /dev/null
+++ b/extensions/window-list/windowPicker.js
@@ -0,0 +1,260 @@
+/* exported WindowPicker, WindowPickerToggle */
+const { Clutter, GLib, GObject, Meta, Shell, St } = imports.gi;
+const Signals = imports.signals;
+
+const Layout = imports.ui.layout;
+const Main = imports.ui.main;
+const Overview = imports.ui.overview;
+const { WorkspacesDisplay } = imports.ui.workspacesView;
+
+let MyWorkspacesDisplay = class extends WorkspacesDisplay {
+ constructor() {
+ super();
+
+ this.actor.add_constraint(
+ new Layout.MonitorConstraint({
+ primary: true,
+ work_area: true
+ }));
+
+ this.actor.connect('destroy', this._onDestroy.bind(this));
+
+ this._workareasChangedId = global.display.connect('workareas-changed',
+ this._onWorkAreasChanged.bind(this));
+ this._onWorkAreasChanged();
+ }
+
+ show(...args) {
+ if (this._scrollEventId == 0)
+ this._scrollEventId = Main.windowPicker.connect('scroll-event',
+ this._onScrollEvent.bind(this));
+
+ super.show(...args);
+ }
+
+ hide(...args) {
+ if (this._scrollEventId > 0)
+ Main.windowPicker.disconnect(this._scrollEventId);
+ this._scrollEventId = 0;
+
+ super.hide(...args);
+ }
+
+ _onWorkAreasChanged() {
+ let { primaryIndex } = Main.layoutManager;
+ let workarea = Main.layoutManager.getWorkAreaForMonitor(primaryIndex);
+ this.setWorkspacesFullGeometry(workarea);
+ }
+
+ _updateWorkspacesViews() {
+ super._updateWorkspacesViews();
+
+ this._workspacesViews.forEach(v => {
+ Main.layoutManager.overviewGroup.remove_actor(v.actor);
+ Main.windowPicker.actor.add_actor(v.actor);
+ });
+ }
+
+ _onDestroy() {
+ if (this._workareasChangedId)
+ global.display.disconnect(this._workareasChangedId);
+ this._workareasChangedId = 0;
+ }
+};
+
+var WindowPicker = class {
+ constructor() {
+ this._visible = false;
+ this._modal = false;
+
+ this.actor = new Clutter.Actor();
+
+ this.actor.connect('destroy', this._onDestroy.bind(this));
+
+ global.bind_property('screen-width',
+ this.actor, 'width',
+ GObject.BindingFlags.SYNC_CREATE);
+ global.bind_property('screen-height',
+ this.actor, 'height',
+ GObject.BindingFlags.SYNC_CREATE);
+
+ this._backgroundGroup = new Meta.BackgroundGroup({ reactive: true });
+ this.actor.add_child(this._backgroundGroup);
+
+ this._backgroundGroup.connect('scroll-event', (a, ev) => {
+ this.emit('scroll-event', ev);
+ });
+
+ // Trick WorkspacesDisplay constructor into adding actions here
+ let addActionOrig = Main.overview.addAction;
+ Main.overview.addAction = a => this._backgroundGroup.add_action(a);
+
+ this._workspacesDisplay = new MyWorkspacesDisplay();
+ this.actor.add_child(this._workspacesDisplay.actor);
+
+ Main.overview.addAction = addActionOrig;
+
+ this._bgManagers = [];
+
+ this._monitorsChangedId = Main.layoutManager.connect('monitors-changed',
+ this._updateBackgrounds.bind(this));
+ this._updateBackgrounds();
+
+ Main.uiGroup.insert_child_below(this.actor, global.window_group);
+ }
+
+ get visible() {
+ return this._visible;
+ }
+
+ open() {
+ if (this._visible)
+ return;
+
+ this._visible = true;
+
+ if (!this._syncGrab())
+ return;
+
+ this._fakeOverviewVisible(true);
+ this._shadeBackgrounds();
+ this._fakeOverviewAnimation();
+ this._workspacesDisplay.show(false);
+
+ this.emit('open-state-changed', this._visible);
+ }
+
+ close() {
+ if (!this._visible)
+ return;
+
+ this._visible = false;
+
+ if (!this._syncGrab())
+ return;
+
+ this._workspacesDisplay.animateFromOverview(false);
+ this._unshadeBackgrounds();
+ this._fakeOverviewAnimation(() => {
+ this._workspacesDisplay.hide();
+ this._fakeOverviewVisible(false);
+ });
+
+ this.emit('open-state-changed', this._visible);
+ }
+
+ _fakeOverviewAnimation(onComplete) {
+ Main.overview.animationInProgress = true;
+ GLib.timeout_add(
+ GLib.PRIORITY_DEFAULT,
+ Overview.ANIMATION_TIME * 1000,
+ () => {
+ Main.overview.animationInProgress = false;
+ if (onComplete)
+ onComplete();
+ });
+ }
+
+ _fakeOverviewVisible(visible) {
+ // Fake overview state for WorkspacesDisplay
+ Main.overview.visible = visible;
+
+ // Hide real windows
+ Main.layoutManager._inOverview = visible;
+ Main.layoutManager._updateVisibility();
+ }
+
+ _syncGrab() {
+ if (this._visible) {
+ if (this._modal)
+ return true;
+
+ this._modal = Main.pushModal(this.actor, {
+ actionMode: Shell.ActionMode.OVERVIEW
+ });
+
+ if (!this._modal) {
+ this.hide();
+ return false;
+ }
+ } else if (this._modal) {
+ Main.popModal(this.actor);
+ this._modal = false;
+ }
+ return true;
+ }
+
+ _onDestroy() {
+ if (this._monitorsChangedId)
+ Main.layoutManager.disconnect(this._monitorsChangedId);
+ this._monitorsChangedId = 0;
+ }
+
+ _updateBackgrounds() {
+ Main.overview._updateBackgrounds.call(this);
+ }
+
+ _shadeBackgrounds() {
+ Main.overview._shadeBackgrounds.call(this);
+ }
+
+ _unshadeBackgrounds() {
+ Main.overview._unshadeBackgrounds.call(this);
+ }
+};
+Signals.addSignalMethods(WindowPicker.prototype);
+
+var WindowPickerToggle = GObject.registerClass(
+class WindowPickerToggle extends St.Button {
+ _init() {
+ let iconBin = new St.Widget({
+ layout_manager: new Clutter.BinLayout()
+ });
+ iconBin.add_child(new St.Icon({
+ icon_name: 'focus-windows-symbolic',
+ icon_size: 16,
+ x_expand: true,
+ y_expand: true,
+ x_align: Clutter.ActorAlign.CENTER,
+ y_align: Clutter.ActorAlign.CENTER
+ }));
+ super._init({
+ style_class: 'window-picker-toggle',
+ child: iconBin,
+ visible: !Main.sessionMode.hasOverview,
+ x_fill: true,
+ y_fill: true,
+ toggle_mode: true
+ });
+
+ this._overlayKeyId = 0;
+
+ this.connect('destroy', this._onDestroy.bind(this));
+
+ this.connect('notify::checked', () => {
+ if (this.checked)
+ Main.windowPicker.open();
+ else
+ Main.windowPicker.close();
+ });
+
+ if (!Main.sessionMode.hasOverview) {
+ this._overlayKeyId = global.display.connect('overlay-key', () => {
+ if (!Main.windowPicker.visible)
+ Main.windowPicker.open();
+ else
+ Main.windowPicker.close();
+ });
+ }
+
+ Main.windowPicker.connect('open-state-changed', () => {
+ this.checked = Main.windowPicker.visible;
+ });
+ }
+
+ _onDestroy() {
+ if (this._overlayKeyId)
+ global.display.disconnect(this._overlayKeyId);
+ this._overlayKeyId == 0;
+ }
+});
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]