[gnome-shell] workspaceThumbnail: Make it horizontal
- From: Marge Bot <marge-bot src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] workspaceThumbnail: Make it horizontal
- Date: Fri, 29 Jan 2021 15:04:20 +0000 (UTC)
commit 3ad7b85e259dffd6958816361a866a31310a9382
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date: Mon Jan 25 20:52:17 2021 -0300
workspaceThumbnail: Make it horizontal
Allocate workspace thumbnails horizontally. This requires introducing code
to handle the RTL direction. Do a small rewrite of the DnD hover method to
be simultaneously simpler and easier to follow, and work correctly on RTL.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1593>
js/ui/workspaceThumbnail.js | 285 +++++++++++++++++++++++++-------------------
1 file changed, 162 insertions(+), 123 deletions(-)
---
diff --git a/js/ui/workspaceThumbnail.js b/js/ui/workspaceThumbnail.js
index 431f46eb60..a30cc0a73b 100644
--- a/js/ui/workspaceThumbnail.js
+++ b/js/ui/workspaceThumbnail.js
@@ -627,9 +627,11 @@ var ThumbnailsBox = GObject.registerClass({
},
}, class ThumbnailsBox extends St.Widget {
_init(scrollAdjustment) {
- super._init({ reactive: true,
- style_class: 'workspace-thumbnails',
- request_mode: Clutter.RequestMode.WIDTH_FOR_HEIGHT });
+ super._init({
+ style_class: 'workspace-thumbnails',
+ reactive: true,
+ x_align: Clutter.ActorAlign.CENTER,
+ });
this._delegate = this;
@@ -723,11 +725,11 @@ var ThumbnailsBox = GObject.registerClass({
}
_activateThumbnailAtPoint(stageX, stageY, time) {
- let [r_, x_, y] = this.transform_stage_point(stageX, stageY);
+ const [r_, x] = this.transform_stage_point(stageX, stageY);
- let thumbnail = this._thumbnails.find(t => {
- let [, h] = t.get_transformed_size();
- return y >= t.y && y <= t.y + h;
+ const thumbnail = this._thumbnails.find(t => {
+ const [w] = t.get_transformed_size();
+ return x >= t.x && x <= t.x + w;
});
if (thumbnail)
thumbnail.activate(time);
@@ -792,6 +794,57 @@ var ThumbnailsBox = GObject.registerClass({
this.queue_relayout();
}
+ _getPlaceholderTarget(index, spacing, rtl) {
+ const workspace = this._thumbnails[index];
+
+ let targetX1;
+ let targetX2;
+
+ if (rtl) {
+ const [r_, w] = workspace.get_transformed_size();
+ const baseX = workspace.x + w;
+ targetX1 = baseX - WORKSPACE_CUT_SIZE;
+ targetX2 = baseX + spacing + WORKSPACE_CUT_SIZE;
+ } else {
+ targetX1 = workspace.x - spacing - WORKSPACE_CUT_SIZE;
+ targetX2 = workspace.x + WORKSPACE_CUT_SIZE;
+ }
+
+ if (index === 0) {
+ if (rtl)
+ targetX2 -= spacing + WORKSPACE_CUT_SIZE;
+ else
+ targetX1 += spacing + WORKSPACE_CUT_SIZE;
+ }
+
+ if (index === this._dropPlaceholderPos) {
+ const placeholderWidth = this._dropPlaceholder.get_width() + spacing;
+ if (rtl)
+ targetX2 += placeholderWidth;
+ else
+ targetX1 -= placeholderWidth;
+ }
+
+ return [targetX1, targetX2];
+ }
+
+ _withinWorkspace(x, index, rtl) {
+ const length = this._thumbnails.length;
+ const workspace = this._thumbnails[index];
+
+ let workspaceX1 = workspace.x + WORKSPACE_CUT_SIZE;
+ let workspaceX2 = workspace.x + workspace.width - WORKSPACE_CUT_SIZE;
+
+ if (index === length - 1) {
+ if (rtl)
+ workspaceX1 -= WORKSPACE_CUT_SIZE;
+ else
+ workspaceX2 += WORKSPACE_CUT_SIZE;
+ }
+
+ return x > workspaceX1 && x <= workspaceX2;
+ }
+
// Draggable target interface
handleDragOver(source, actor, x, y, time) {
if (!source.metaWindow &&
@@ -800,41 +853,30 @@ var ThumbnailsBox = GObject.registerClass({
source != Main.xdndHandler)
return DND.DragMotionResult.CONTINUE;
+ const rtl = Clutter.get_default_text_direction() === Clutter.TextDirection.RTL;
let canCreateWorkspaces = Meta.prefs_get_dynamic_workspaces();
let spacing = this.get_theme_node().get_length('spacing');
this._dropWorkspace = -1;
let placeholderPos = -1;
- let targetBase;
- if (this._dropPlaceholderPos == 0)
- targetBase = this._dropPlaceholder.y;
- else
- targetBase = this._thumbnails[0].y;
- let targetTop = targetBase - spacing - WORKSPACE_CUT_SIZE;
let length = this._thumbnails.length;
for (let i = 0; i < length; i++) {
- // Allow the reorder target to have a 10px "cut" into
- // each side of the thumbnail, to make dragging onto the
- // placeholder easier
- let [, h] = this._thumbnails[i].get_transformed_size();
- let targetBottom = targetBase + WORKSPACE_CUT_SIZE;
- let nextTargetBase = targetBase + h + spacing;
- let nextTargetTop = nextTargetBase - spacing - (i == length - 1 ? 0 : WORKSPACE_CUT_SIZE);
-
- // Expand the target to include the placeholder, if it exists.
- if (i == this._dropPlaceholderPos)
- targetBottom += this._dropPlaceholder.get_height();
-
- if (y > targetTop && y <= targetBottom && source != Main.xdndHandler && canCreateWorkspaces) {
- placeholderPos = i;
- break;
- } else if (y > targetBottom && y <= nextTargetTop) {
- this._dropWorkspace = i;
- break;
+ const index = rtl ? length - i - 1 : i;
+
+ if (canCreateWorkspaces && source !== Main.xdndHandler) {
+ const [targetStart, targetEnd] =
+ this._getPlaceholderTarget(index, spacing, rtl);
+
+ if (x > targetStart && x <= targetEnd) {
+ placeholderPos = index;
+ break;
+ }
}
- targetBase = nextTargetBase;
- targetTop = nextTargetTop;
+ if (this._withinWorkspace(x, index, rtl)) {
+ this._dropWorkspace = index;
+ break;
+ }
}
if (this._dropPlaceholderPos != placeholderPos) {
@@ -1156,40 +1198,39 @@ var ThumbnailsBox = GObject.registerClass({
this._stateUpdateQueued = true;
}
- vfunc_get_preferred_height(_forWidth) {
- // Note that for getPreferredWidth/Height we cheat a bit and skip propagating
- // the size request to our children because we know how big they are and know
- // that the actors aren't depending on the virtual functions being called.
+ vfunc_get_preferred_height(forWidth) {
let workspaceManager = global.workspace_manager;
let themeNode = this.get_theme_node();
+ forWidth = themeNode.adjust_for_width(forWidth);
+
let spacing = themeNode.get_length('spacing');
let nWorkspaces = workspaceManager.n_workspaces;
let totalSpacing = (nWorkspaces - 1) * spacing;
- let naturalHeight = totalSpacing + nWorkspaces * this._porthole.height * MAX_THUMBNAIL_SCALE;
+ const avail = forWidth - totalSpacing;
+
+ let scale = (avail / nWorkspaces) / this._porthole.width;
+ scale = Math.min(scale, MAX_THUMBNAIL_SCALE);
- return themeNode.adjust_preferred_height(totalSpacing, naturalHeight);
+ const height = Math.round(this._porthole.height * scale);
+ return themeNode.adjust_preferred_height(height, height);
}
- vfunc_get_preferred_width(forHeight) {
+ vfunc_get_preferred_width(_forHeight) {
+ // Note that for getPreferredHeight/Width we cheat a bit and skip propagating
+ // the size request to our children because we know how big they are and know
+ // that the actors aren't depending on the virtual functions being called.
let workspaceManager = global.workspace_manager;
let themeNode = this.get_theme_node();
- forHeight = themeNode.adjust_for_height(forHeight);
-
let spacing = themeNode.get_length('spacing');
let nWorkspaces = workspaceManager.n_workspaces;
let totalSpacing = (nWorkspaces - 1) * spacing;
- let avail = forHeight - totalSpacing;
-
- let scale = (avail / nWorkspaces) / this._porthole.height;
- scale = Math.min(scale, MAX_THUMBNAIL_SCALE);
-
- let width = Math.round(this._porthole.width * scale);
-
- return themeNode.adjust_preferred_width(width, width);
+ const naturalWidth =
+ totalSpacing + nWorkspaces * this._porthole.width * MAX_THUMBNAIL_SCALE;
+ return themeNode.adjust_preferred_width(totalSpacing, naturalWidth);
}
_updatePorthole() {
@@ -1216,17 +1257,18 @@ var ThumbnailsBox = GObject.registerClass({
box = themeNode.get_content_box(box);
- let portholeWidth = this._porthole.width;
- let portholeHeight = this._porthole.height;
- let spacing = themeNode.get_length('spacing');
+ const portholeWidth = this._porthole.width;
+ const portholeHeight = this._porthole.height;
+ const spacing = themeNode.get_length('spacing');
// Compute the scale we'll need once everything is updated
let nWorkspaces = workspaceManager.n_workspaces;
let totalSpacing = (nWorkspaces - 1) * spacing;
- let avail = (box.y2 - box.y1) - totalSpacing;
+ const availableWidth = (box.get_width() - totalSpacing) / nWorkspaces;
- let newScale = (avail / nWorkspaces) / portholeHeight;
- newScale = Math.min(newScale, MAX_THUMBNAIL_SCALE);
+ const hScale = availableWidth / portholeWidth;
+ const vScale = box.get_height() / portholeHeight;
+ const newScale = Math.min(hScale, vScale);
if (newScale != this._targetScale) {
if (this._targetScale > 0) {
@@ -1242,24 +1284,19 @@ var ThumbnailsBox = GObject.registerClass({
this._queueUpdateStates();
}
- let thumbnailHeight = portholeHeight * this._scale;
- let thumbnailWidth = Math.round(portholeWidth * this._scale);
- let roundedHScale = thumbnailWidth / portholeWidth;
-
- let slideOffset; // X offset when thumbnail is fully slid offscreen
- if (rtl)
- slideOffset = -(thumbnailWidth + themeNode.get_padding(St.Side.LEFT));
- else
- slideOffset = thumbnailWidth + themeNode.get_padding(St.Side.RIGHT);
+ const ratio = portholeWidth / portholeHeight;
+ const thumbnailHeight = Math.round(portholeHeight * this._scale);
+ const thumbnailWidth = Math.round(thumbnailHeight * ratio);
+ const roundedVScale = thumbnailHeight / portholeHeight;
let indicatorValue = this._scrollAdjustment.value;
let indicatorUpperWs = Math.ceil(indicatorValue);
let indicatorLowerWs = Math.floor(indicatorValue);
- let indicatorLowerY1 = 0;
- let indicatorLowerY2 = 0;
- let indicatorUpperY1 = 0;
- let indicatorUpperY2 = 0;
+ let indicatorLowerX1 = 0;
+ let indicatorLowerX2 = 0;
+ let indicatorUpperX1 = 0;
+ let indicatorUpperX2 = 0;
let indicatorThemeNode = this._indicator.get_theme_node();
let indicatorTopFullBorder = indicatorThemeNode.get_padding(St.Side.TOP) +
indicatorThemeNode.get_border_width(St.Side.TOP);
@@ -1267,7 +1304,7 @@ var ThumbnailsBox = GObject.registerClass({
let indicatorLeftFullBorder = indicatorThemeNode.get_padding(St.Side.LEFT) +
indicatorThemeNode.get_border_width(St.Side.LEFT);
let indicatorRightFullBorder = indicatorThemeNode.get_padding(St.Side.RIGHT) +
indicatorThemeNode.get_border_width(St.Side.RIGHT);
- let y = box.y1;
+ let x = box.x1;
if (this._dropPlaceholderPos == -1) {
this._dropPlaceholder.allocate_preferred_size(
@@ -1281,82 +1318,84 @@ var ThumbnailsBox = GObject.registerClass({
let childBox = new Clutter.ActorBox();
for (let i = 0; i < this._thumbnails.length; i++) {
- let thumbnail = this._thumbnails[i];
-
+ const thumbnail = this._thumbnails[i];
if (i > 0)
- y += spacing - Math.round(thumbnail.collapse_fraction * spacing);
-
- let x1, x2;
- if (rtl) {
- x1 = box.x1 + slideOffset * thumbnail.slide_position;
- x2 = x1 + thumbnailWidth;
- } else {
- x1 = box.x2 - thumbnailWidth + slideOffset * thumbnail.slide_position;
- x2 = x1 + thumbnailWidth;
- }
+ x += spacing - Math.round(thumbnail.collapse_fraction * spacing);
+
+ const y1 = box.y1;
+ const y2 = y1 + thumbnailHeight;
+
+ if (i === this._dropPlaceholderPos) {
+ const [, placeholderWidth] = this._dropPlaceholder.get_preferred_width(-1);
+ childBox.y1 = y1;
+ childBox.y2 = y2;
+
+ if (rtl) {
+ childBox.x2 = box.x2 - Math.round(x);
+ childBox.x1 = box.x2 - Math.round(x + placeholderWidth);
+ } else {
+ childBox.x1 = Math.round(x);
+ childBox.x2 = Math.round(x + placeholderWidth);
+ }
- if (i == this._dropPlaceholderPos) {
- let [, placeholderHeight] = this._dropPlaceholder.get_preferred_height(-1);
- childBox.x1 = x1;
- childBox.x2 = x2;
- childBox.y1 = Math.round(y);
- childBox.y2 = Math.round(y + placeholderHeight);
this._dropPlaceholder.allocate(childBox);
+
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
this._dropPlaceholder.show();
});
- y += placeholderHeight + spacing;
+ x += placeholderWidth + spacing;
}
- // We might end up with thumbnailHeight being something like 99.33
- // pixels. To make this work and not end up with a gap at the bottom,
- // we need some thumbnails to be 99 pixels and some 100 pixels height;
+ // We might end up with thumbnailWidth being something like 99.33
+ // pixels. To make this work and not end up with a gap at the end,
+ // we need some thumbnails to be 99 pixels and some 100 pixels width;
// we compute an actual scale separately for each thumbnail.
- let y1 = Math.round(y);
- let y2 = Math.round(y + thumbnailHeight);
- let roundedVScale = (y2 - y1) / portholeHeight;
-
- if (i === indicatorUpperWs) {
- indicatorUpperY1 = y1;
- indicatorUpperY2 = y2;
- }
- if (i === indicatorLowerWs) {
- indicatorLowerY1 = y1;
- indicatorLowerY2 = y2;
- }
+ const x1 = Math.round(x);
+ const x2 = Math.round(x + thumbnailWidth);
+ const roundedHScale = (x2 - x1) / portholeWidth;
// Allocating a scaled actor is funny - x1/y1 correspond to the origin
// of the actor, but x2/y2 are increased by the *unscaled* size.
- childBox.x1 = x1;
- childBox.x2 = x1 + portholeWidth;
+ if (rtl) {
+ childBox.x2 = box.x2 - x1;
+ childBox.x1 = box.x2 - (x1 + portholeWidth);
+ } else {
+ childBox.x1 = x1;
+ childBox.x2 = x1 + portholeWidth;
+ }
childBox.y1 = y1;
childBox.y2 = y1 + portholeHeight;
thumbnail.set_scale(roundedHScale, roundedVScale);
thumbnail.allocate(childBox);
+ if (i === indicatorUpperWs) {
+ indicatorUpperX1 = childBox.x1;
+ indicatorUpperX2 = childBox.x2;
+ }
+ if (i === indicatorLowerWs) {
+ indicatorLowerX1 = childBox.x1;
+ indicatorLowerX2 = childBox.x2;
+ }
+
// We round the collapsing portion so that we don't get thumbnails resizing
// during an animation due to differences in rounded, but leave the uncollapsed
// portion unrounded so that non-animating we end up with the right total
- y += thumbnailHeight - Math.round(thumbnailHeight * thumbnail.collapse_fraction);
+ x += thumbnailWidth - Math.round(thumbnailWidth * thumbnail.collapse_fraction);
}
- if (rtl) {
- childBox.x1 = box.x1;
- childBox.x2 = box.x1 + thumbnailWidth;
- } else {
- childBox.x1 = box.x2 - thumbnailWidth;
- childBox.x2 = box.x2;
- }
- let indicatorY1 = indicatorLowerY1 +
- (indicatorUpperY1 - indicatorLowerY1) * (indicatorValue % 1);
- let indicatorY2 = indicatorLowerY2 +
- (indicatorUpperY2 - indicatorLowerY2) * (indicatorValue % 1);
-
- childBox.x1 -= indicatorLeftFullBorder;
- childBox.x2 += indicatorRightFullBorder;
- childBox.y1 = indicatorY1 - indicatorTopFullBorder;
- childBox.y2 = indicatorY2 + indicatorBottomFullBorder;
+ childBox.y1 = box.y1;
+ childBox.y2 = box.y1 + thumbnailHeight;
+
+ const indicatorX1 = indicatorLowerX1 +
+ (indicatorUpperX1 - indicatorLowerX1) * (indicatorValue % 1);
+ const indicatorX2 = indicatorLowerX2 +
+ (indicatorUpperX2 - indicatorLowerX2) * (indicatorValue % 1);
+
+ childBox.x1 = indicatorX1 - indicatorLeftFullBorder;
+ childBox.x2 = indicatorX2 + indicatorRightFullBorder;
+ childBox.y1 -= indicatorTopFullBorder;
+ childBox.y2 += indicatorBottomFullBorder;
this._indicator.allocate(childBox);
}
});
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]