[gnome-shell-extensions] window-list: Show previews in workspace switcher
- From: Florian Müllner <fmuellner src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell-extensions] window-list: Show previews in workspace switcher
- Date: Fri, 19 Jul 2019 11:23:45 +0000 (UTC)
commit 5b07dfded9842c75dc5b7ef80d5c30f6abd65029
Author: Florian Müllner <fmuellner gnome org>
Date: Wed Jun 26 23:55:58 2019 +0000
window-list: Show previews in workspace switcher
Currently the new horizontal workspace switcher only shows a series of
buttons, with no indication of the workspaces' contents. Go full GNOME 2
and add tiny draggable preview rectangles that represent the windows
on a particular workspace.
https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/74
extensions/window-list/classic.css | 10 ++
extensions/window-list/stylesheet.css | 10 ++
extensions/window-list/workspaceIndicator.js | 154 ++++++++++++++++++++++++++-
3 files changed, 173 insertions(+), 1 deletion(-)
---
diff --git a/extensions/window-list/classic.css b/extensions/window-list/classic.css
index c533473..7079d3e 100644
--- a/extensions/window-list/classic.css
+++ b/extensions/window-list/classic.css
@@ -56,3 +56,13 @@
.window-list-workspace-indicator .workspace.active {
background-color: #ccc;
}
+
+.window-list-window-preview {
+ background-color: #ededed;
+ border: 1px solid #ccc;
+}
+
+.window-list-window-preview.active {
+ background-color: #f6f5f4;
+ border: 2px solid #888;
+}
diff --git a/extensions/window-list/stylesheet.css b/extensions/window-list/stylesheet.css
index ad5978a..79d56ba 100644
--- a/extensions/window-list/stylesheet.css
+++ b/extensions/window-list/stylesheet.css
@@ -121,6 +121,16 @@
background-color: rgba(200, 200, 200, .3);
}
+.window-list-window-preview {
+ background-color: #252525;
+ border: 1px solid #ccc;
+}
+
+.window-list-window-preview.active {
+ background-color: #353535;
+ border: 2px solid #ccc;
+}
+
.notification {
font-weight: normal;
}
diff --git a/extensions/window-list/workspaceIndicator.js b/extensions/window-list/workspaceIndicator.js
index d669507..84dccac 100644
--- a/extensions/window-list/workspaceIndicator.js
+++ b/extensions/window-list/workspaceIndicator.js
@@ -9,16 +9,131 @@ const PopupMenu = imports.ui.popupMenu;
const Gettext = imports.gettext.domain('gnome-shell-extensions');
const _ = Gettext.gettext;
+let WindowPreview = GObject.registerClass({
+ GTypeName: 'WindowListWindowPreview'
+}, class WindowPreview extends St.Button {
+ _init(window) {
+ super._init({
+ style_class: 'window-list-window-preview'
+ });
+
+ this._delegate = this;
+ DND.makeDraggable(this, { restoreOnSuccess: true });
+
+ this._window = window;
+
+ this.connect('destroy', this._onDestroy.bind(this));
+
+ this._sizeChangedId = this._window.connect('size-changed',
+ this._relayout.bind(this));
+ this._positionChangedId = this._window.connect('position-changed',
+ this._relayout.bind(this));
+ this._minimizedChangedId = this._window.connect('notify::minimized',
+ this._relayout.bind(this));
+ this._monitorEnteredId = global.display.connect('window-entered-monitor',
+ this._relayout.bind(this));
+ this._monitorLeftId = global.display.connect('window-left-monitor',
+ this._relayout.bind(this));
+
+ // Do initial layout when we get a parent
+ let id = this.connect('parent-set', () => {
+ this.disconnect(id);
+ if (!this.get_parent())
+ return;
+ this._laterId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
+ this._laterId = 0;
+ this._relayout();
+ return false;
+ });
+ });
+
+ this._focusChangedId = global.display.connect('notify::focus-window',
+ this._onFocusChanged.bind(this));
+ this._onFocusChanged();
+ }
+
+ // needed for DND
+ get realWindow() {
+ return this._window.get_compositor_private();
+ }
+
+ _onDestroy() {
+ this._window.disconnect(this._sizeChangedId);
+ this._window.disconnect(this._positionChangedId);
+ this._window.disconnect(this._minimizedChangedId);
+ global.display.disconnect(this._monitorEnteredId);
+ global.display.disconnect(this._monitorLeftId);
+ global.display.disconnect(this._focusChangedId);
+ if (this._laterId)
+ Meta.later_remove(this._laterId);
+ }
+
+ _onFocusChanged() {
+ if (global.display.focus_window == this._window)
+ this.add_style_class_name('active');
+ else
+ this.remove_style_class_name('active');
+ }
+
+ _relayout() {
+ let monitor = Main.layoutManager.findIndexForActor(this);
+ this.visible = monitor == this._window.get_monitor() &&
+ this._window.showing_on_its_workspace();
+
+ if (!this.visible)
+ return;
+
+ let workArea = Main.layoutManager.getWorkAreaForMonitor(monitor);
+ let hscale = this.get_parent().allocation.get_width() / workArea.width;
+ let vscale = this.get_parent().allocation.get_height() / workArea.height;
+
+ let frameRect = this._window.get_frame_rect();
+ this.set_size(
+ Math.round(Math.min(frameRect.width, workArea.width) * hscale),
+ Math.round(Math.min(frameRect.height, workArea.height) * vscale));
+ this.set_position(
+ Math.round(frameRect.x * hscale),
+ Math.round(frameRect.y * vscale));
+ }
+});
+
let WorkspaceThumbnail = GObject.registerClass({
GTypeName: 'WindowListWorkspaceThumbnail'
}, class WorkspaceThumbnail extends St.Button {
_init(index) {
super._init({
- style_class: 'workspace'
+ style_class: 'workspace',
+ child: new Clutter.Actor({
+ layout_manager: new Clutter.BinLayout(),
+ clip_to_allocation: true
+ }),
+ x_fill: true,
+ y_fill: true
});
+ this.connect('destroy', this._onDestroy.bind(this));
+
this._index = index;
this._delegate = this; // needed for DND
+
+ this._windowPreviews = new Map();
+
+ let workspaceManager = global.workspace_manager;
+ this._workspace = workspaceManager.get_workspace_by_index(index);
+
+ this._windowAddedId = this._workspace.connect('window-added',
+ (ws, window) => {
+ this._addWindow(window);
+ });
+ this._windowRemovedId = this._workspace.connect('window-removed',
+ (ws, window) => {
+ this._removeWindow(window);
+ });
+ this._restackedId = global.display.connect('restacked',
+ this._onRestacked.bind(this));
+
+ this._workspace.list_windows().forEach(w => this._addWindow(w));
+ this._onRestacked();
}
acceptDrop(source) {
@@ -37,6 +152,37 @@ let WorkspaceThumbnail = GObject.registerClass({
return DND.DragMotionResult.CONTINUE;
}
+ _addWindow(window) {
+ if (this._windowPreviews.has(window))
+ return;
+
+ let preview = new WindowPreview(window);
+ preview.connect('clicked', (a, btn) => this.emit('clicked', btn));
+ this._windowPreviews.set(window, preview);
+ this.child.add_child(preview);
+ }
+
+ _removeWindow(window) {
+ let preview = this._windowPreviews.get(window);
+ if (!preview)
+ return;
+
+ this._windowPreviews.delete(window);
+ preview.destroy();
+ }
+
+ _onRestacked() {
+ let lastPreview = null;
+ let windows = global.get_window_actors().map(a => a.meta_window);
+ for (let i = 0; i < windows.length; i++) {
+ let preview = this._windowPreviews.get(windows[i]);
+ if (!preview)
+ continue;
+
+ this.child.set_child_above_sibling(preview, lastPreview);
+ lastPreview = preview;
+ }
+ }
_moveWindow(window) {
let monitorIndex = Main.layoutManager.findIndexForActor(this);
@@ -50,6 +196,12 @@ let WorkspaceThumbnail = GObject.registerClass({
if (ws)
ws.activate(global.get_current_time());
}
+
+ _onDestroy() {
+ this._workspace.disconnect(this._windowAddedId);
+ this._workspace.disconnect(this._windowRemovedId);
+ global.display.disconnect(this._restackedId);
+ }
});
var WorkspaceIndicator = GObject.registerClass({
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]