workspacesView: Properly allocate workspaces

So far we've been allocating workspaces in a stack, and relied on
translation to move them to the right position. And as the position
depends on both the workspace's index and the view's viewport, some
care is needed to prevent gestures/scrolling from interfering with
layout updates.

Clean that up by properly allocating workspaces in a row or column,
and use a translation to reflect the current scroll position.

https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1345
This commit is contained in:
Florian Müllner 2020-06-26 16:04:44 +02:00
parent d66cd0d206
commit 96f63b08c2

View File

@ -80,9 +80,8 @@ class WorkspacesView extends WorkspacesViewBase {
this._gestureActive = false; // touch(pad) gestures this._gestureActive = false; // touch(pad) gestures
this._scrollAdjustment = scrollAdjustment; this._scrollAdjustment = scrollAdjustment;
this._onScrollId = this._onScrollId = this._scrollAdjustment.connect('notify::value',
this._scrollAdjustment.connect('notify::value', this._updateScrollPosition.bind(this));
this._onScroll.bind(this));
this._workspaces = []; this._workspaces = [];
this._updateWorkspaces(); this._updateWorkspaces();
@ -94,7 +93,8 @@ class WorkspacesView extends WorkspacesViewBase {
this._workspaces.sort((a, b) => { this._workspaces.sort((a, b) => {
return a.metaWorkspace.index() - b.metaWorkspace.index(); return a.metaWorkspace.index() - b.metaWorkspace.index();
}); });
this._updateWorkspaceActors(false); this._workspaces.forEach(
(ws, i) => this.set_child_at_index(ws, i));
}); });
this._overviewShownId = Main.overview.connect('shown', () => { this._overviewShownId = Main.overview.connect('shown', () => {
@ -106,6 +106,31 @@ class WorkspacesView extends WorkspacesViewBase {
this._activeWorkspaceChanged.bind(this)); this._activeWorkspaceChanged.bind(this));
} }
vfunc_allocate(box) {
this.set_allocation(box);
if (this.get_n_children() === 0)
return;
const { workspaceManager } = global;
const { nWorkspaces } = workspaceManager;
const vertical = workspaceManager.layout_rows === -1;
const rtl = this.text_direction === Clutter.TextDirection.RTL;
this._workspaces.forEach((child, index) => {
if (rtl && !vertical)
index = nWorkspaces - index - 1;
const x = vertical ? 0 : index * this.width;
const y = vertical ? index * this.height : 0;
child.allocate_available_size(x, y, box.get_width(), box.get_height());
});
this._updateScrollPosition();
}
_setReservedSlot(window) { _setReservedSlot(window) {
for (let i = 0; i < this._workspaces.length; i++) for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].setReservedSlot(window); this._workspaces[i].setReservedSlot(window);
@ -124,7 +149,7 @@ class WorkspacesView extends WorkspacesViewBase {
else else
this._workspaces[w].fadeToOverview(); this._workspaces[w].fadeToOverview();
} }
this._updateWorkspaceActors(false); this._updateScrollPosition();
} }
animateFromOverview(animationType) { animateFromOverview(animationType) {
@ -143,49 +168,22 @@ class WorkspacesView extends WorkspacesViewBase {
this._workspaces[i].syncStacking(stackIndices); this._workspaces[i].syncStacking(stackIndices);
} }
// Update workspace actors parameters _scrollToActive() {
// @showAnimation: iff %true, transition between states const { workspaceManager } = global;
_updateWorkspaceActors(showAnimation) { const active = workspaceManager.get_active_workspace_index();
let workspaceManager = global.workspace_manager;
let active = workspaceManager.get_active_workspace_index();
this._animating = showAnimation; this._animating = true;
this._updateVisibility();
for (let w = 0; w < this._workspaces.length; w++) { this._scrollAdjustment.remove_transition('value');
let workspace = this._workspaces[w]; this._scrollAdjustment.ease(active, {
workspace.remove_all_transitions();
let params = {};
if (workspaceManager.layout_rows == -1)
params.translation_y = (w - active) * this.height;
else if (this.text_direction == Clutter.TextDirection.RTL)
params.translation_x = (active - w) * this.width;
else
params.translation_x = (w - active) * this.width;
if (showAnimation) {
let easeParams = Object.assign(params, {
duration: WORKSPACE_SWITCH_TIME, duration: WORKSPACE_SWITCH_TIME,
mode: Clutter.AnimationMode.EASE_OUT_CUBIC, mode: Clutter.AnimationMode.EASE_OUT_CUBIC,
}); onComplete: () => {
// we have to call _updateVisibility() once before the
// animation and once afterwards - it does not really
// matter which tween we use, so we pick the first one ...
if (w == 0) {
this._updateVisibility();
easeParams.onComplete = () => {
this._animating = false; this._animating = false;
this._updateVisibility(); this._updateVisibility();
}; },
} });
workspace.ease(easeParams);
} else {
workspace.set(params);
if (w == 0)
this._updateVisibility();
}
}
} }
_updateVisibility() { _updateVisibility() {
@ -226,14 +224,14 @@ class WorkspacesView extends WorkspacesViewBase {
} }
} }
this._updateWorkspaceActors(false); this._updateScrollPosition();
} }
_activeWorkspaceChanged(_wm, _from, _to, _direction) { _activeWorkspaceChanged(_wm, _from, _to, _direction) {
if (this._scrolling) if (this._scrolling)
return; return;
this._updateWorkspaceActors(true); this._scrollToActive();
} }
_onDestroy() { _onDestroy() {
@ -255,21 +253,25 @@ class WorkspacesView extends WorkspacesViewBase {
this._gestureActive = false; this._gestureActive = false;
// Make sure title captions etc are shown as necessary // Make sure title captions etc are shown as necessary
this._updateWorkspaceActors(true); this._scrollToActive();
this._updateVisibility(); this._updateVisibility();
} }
// sync the workspaces' positions to the value of the scroll adjustment // sync the workspaces' positions to the value of the scroll adjustment
// and change the active workspace if appropriate // and change the active workspace if appropriate
_onScroll(adj) { _updateScrollPosition() {
if (adj.get_transition('value') !== null && !this._gestureActive) if (!this.has_allocation())
return; return;
const adj = this._scrollAdjustment;
const allowSwitch =
adj.get_transition('value') === null && !this._gestureActive;
let workspaceManager = global.workspace_manager; let workspaceManager = global.workspace_manager;
let active = workspaceManager.get_active_workspace_index(); let active = workspaceManager.get_active_workspace_index();
let current = Math.round(adj.value); let current = Math.round(adj.value);
if (active != current && !this._gestureActive) { if (allowSwitch && active !== current) {
if (!this._workspaces[current]) { if (!this._workspaces[current]) {
// The current workspace was destroyed. This could happen // The current workspace was destroyed. This could happen
// when you are on the last empty workspace, and consolidate // when you are on the last empty workspace, and consolidate
@ -286,36 +288,16 @@ class WorkspacesView extends WorkspacesViewBase {
if (adj.upper == 1) if (adj.upper == 1)
return; return;
let last = this._workspaces.length - 1; const vertical = workspaceManager.layout_rows === -1;
const rtl = this.text_direction === Clutter.TextDirection.RTL;
const progress = vertical || !rtl
? adj.value : adj.upper - adj.value;
if (workspaceManager.layout_rows == -1) { for (const ws of this._workspaces) {
let firstWorkspaceY = this._workspaces[0].translation_y; if (vertical)
let lastWorkspaceY = this._workspaces[last].translation_y; ws.translation_y = -progress * this.height;
let workspacesHeight = lastWorkspaceY - firstWorkspaceY; else
ws.translation_x = -progress * this.width;
let currentY = firstWorkspaceY;
let newY = -Math.round(adj.value / (adj.upper - 1) * workspacesHeight);
let dy = newY - currentY;
for (let i = 0; i < this._workspaces.length; i++) {
this._workspaces[i].visible = Math.abs(i - adj.value) <= 1;
this._workspaces[i].translation_y += dy;
}
} else {
let firstWorkspaceX = this._workspaces[0].translation_x;
let lastWorkspaceX = this._workspaces[last].translation_x;
let workspacesWidth = lastWorkspaceX - firstWorkspaceX;
let currentX = firstWorkspaceX;
let newX = -Math.round(adj.value / (adj.upper - 1) * workspacesWidth);
let dx = newX - currentX;
for (let i = 0; i < this._workspaces.length; i++) {
this._workspaces[i].visible = Math.abs(i - adj.value) <= 1;
this._workspaces[i].translation_x += dx;
}
} }
} }
}); });