Scale thumbnails to fit in the vertical space
When we have more thumbnails than can fit in the vertical space, scale them down. This is implemented by using a generic container so we can compute positions and sizes on the fly and do the appropriate width-for-height behavior. The usage of clutter constraints to position the indicator is droppped since it less complicated to just position the indicator in the right place ourselves. https://bugzilla.gnome.org/show_bug.cgi?id=641879
This commit is contained in:
parent
fb8f3f19f7
commit
0ef3f999d2
@ -13,8 +13,8 @@ const Tweener = imports.ui.tweener;
|
|||||||
const Workspace = imports.ui.workspace;
|
const Workspace = imports.ui.workspace;
|
||||||
const WorkspacesView = imports.ui.workspacesView;
|
const WorkspacesView = imports.ui.workspacesView;
|
||||||
|
|
||||||
// Fraction of original screen size for thumbnails
|
// The maximum size of a thumbnail is 1/8 the width and height of the screen
|
||||||
let THUMBNAIL_SCALE = 1/8.;
|
let MAX_THUMBNAIL_SCALE = 1/8.;
|
||||||
|
|
||||||
function WindowClone(realWindow) {
|
function WindowClone(realWindow) {
|
||||||
this._init(realWindow);
|
this._init(realWindow);
|
||||||
@ -153,9 +153,7 @@ WorkspaceThumbnail.prototype = {
|
|||||||
|
|
||||||
this._background = new Clutter.Clone({ source: global.background_actor });
|
this._background = new Clutter.Clone({ source: global.background_actor });
|
||||||
this._group.add_actor(this._background);
|
this._group.add_actor(this._background);
|
||||||
|
this._group.set_size(global.screen_width, global.screen_height);
|
||||||
this._group.set_size(THUMBNAIL_SCALE * global.screen_width, THUMBNAIL_SCALE * global.screen_height);
|
|
||||||
this._group.set_scale(THUMBNAIL_SCALE, THUMBNAIL_SCALE);
|
|
||||||
|
|
||||||
let windows = global.get_window_actors().filter(this._isMyWindow, this);
|
let windows = global.get_window_actors().filter(this._isMyWindow, this);
|
||||||
|
|
||||||
@ -329,8 +327,11 @@ function ThumbnailsBox() {
|
|||||||
|
|
||||||
ThumbnailsBox.prototype = {
|
ThumbnailsBox.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.actor = new St.BoxLayout({ vertical: true,
|
this.actor = new Shell.GenericContainer({ style_class: 'workspace-thumbnails',
|
||||||
style_class: 'workspace-thumbnails' });
|
request_mode: Clutter.RequestMode.WIDTH_FOR_HEIGHT });
|
||||||
|
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||||
|
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||||
|
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
||||||
|
|
||||||
let indicator = new St.Bin({ style_class: 'workspace-thumbnail-indicator',
|
let indicator = new St.Bin({ style_class: 'workspace-thumbnail-indicator',
|
||||||
fixed_position_set: true });
|
fixed_position_set: true });
|
||||||
@ -339,13 +340,8 @@ ThumbnailsBox.prototype = {
|
|||||||
Shell.util_set_hidden_from_pick(indicator, true);
|
Shell.util_set_hidden_from_pick(indicator, true);
|
||||||
|
|
||||||
this._indicator = indicator;
|
this._indicator = indicator;
|
||||||
this.actor.add(indicator);
|
this.actor.add_actor(indicator);
|
||||||
this._indicatorConstraints = [];
|
this._indicatorConstrained = false;
|
||||||
this._indicatorConstraints.push(new Clutter.BindConstraint({ coordinate: Clutter.BindCoordinate.POSITION }));
|
|
||||||
this._indicatorConstraints.push(new Clutter.BindConstraint({ coordinate: Clutter.BindCoordinate.SIZE }));
|
|
||||||
this._indicatorConstraints.forEach(function(constraint) {
|
|
||||||
indicator.add_constraint(constraint);
|
|
||||||
});
|
|
||||||
|
|
||||||
this._thumbnails = [];
|
this._thumbnails = [];
|
||||||
},
|
},
|
||||||
@ -377,13 +373,10 @@ ThumbnailsBox.prototype = {
|
|||||||
let metaWorkspace = global.screen.get_workspace_by_index(k);
|
let metaWorkspace = global.screen.get_workspace_by_index(k);
|
||||||
let thumbnail = new WorkspaceThumbnail(metaWorkspace);
|
let thumbnail = new WorkspaceThumbnail(metaWorkspace);
|
||||||
this._thumbnails[k] = thumbnail;
|
this._thumbnails[k] = thumbnail;
|
||||||
this.actor.add(thumbnail.actor);
|
this.actor.add_actor(thumbnail.actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The thumbnails indicator actually needs to be on top of the thumbnails, but
|
// The thumbnails indicator actually needs to be on top of the thumbnails
|
||||||
// there is also something more subtle going on as well - actors in a StBoxLayout
|
|
||||||
// are allocated from bottom to top (start to end), and we need the
|
|
||||||
// thumnail indicator to be allocated after the actors it is constrained to.
|
|
||||||
this._indicator.raise_top();
|
this._indicator.raise_top();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -407,20 +400,99 @@ ThumbnailsBox.prototype = {
|
|||||||
this._thumbnails[i].syncStacking(stackIndices);
|
this._thumbnails[i].syncStacking(stackIndices);
|
||||||
},
|
},
|
||||||
|
|
||||||
_constrainThumbnailIndicator: function() {
|
_getPreferredHeight: function(actor, forWidth, alloc) {
|
||||||
let active = global.screen.get_active_workspace_index();
|
// Note that for getPreferredWidth/Height we cheat a bit and skip propagating
|
||||||
let thumbnail = this._thumbnails[active];
|
// 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.
|
||||||
|
|
||||||
this._indicatorConstraints.forEach(function(constraint) {
|
if (this._thumbnails.length == 0)
|
||||||
constraint.set_source(thumbnail.actor);
|
return;
|
||||||
constraint.set_enabled(true);
|
|
||||||
});
|
let spacing = this.actor.get_theme_node().get_length('spacing');
|
||||||
|
let totalSpacing = (this._thumbnails.length - 1) * spacing;
|
||||||
|
|
||||||
|
alloc.min_size = totalSpacing;
|
||||||
|
alloc.natural_size = totalSpacing + this._thumbnails.length * global.screen_height * MAX_THUMBNAIL_SCALE;
|
||||||
|
},
|
||||||
|
|
||||||
|
_getPreferredWidth: function(actor, forHeight, alloc) {
|
||||||
|
if (this._thumbnails.length == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let spacing = this.actor.get_theme_node().get_length('spacing');
|
||||||
|
let totalSpacing = (this._thumbnails.length - 1) * spacing;
|
||||||
|
let avail = forHeight - totalSpacing;
|
||||||
|
|
||||||
|
let scale = (avail / this._thumbnails.length) / global.screen_height;
|
||||||
|
scale = Math.min(scale, MAX_THUMBNAIL_SCALE);
|
||||||
|
|
||||||
|
alloc.min_size = alloc.natural_size = Math.round(global.screen_width * scale);
|
||||||
|
},
|
||||||
|
|
||||||
|
_allocate: function(actor, box, flags) {
|
||||||
|
let screenHeight = global.screen_height;
|
||||||
|
|
||||||
|
let spacing = this.actor.get_theme_node().get_length('spacing');
|
||||||
|
let totalSpacing = (this._thumbnails.length - 1) * spacing;
|
||||||
|
let avail = (box.y2 - box.y1) - totalSpacing;
|
||||||
|
|
||||||
|
let scale = (avail / this._thumbnails.length) / screenHeight;
|
||||||
|
scale = Math.min(scale, MAX_THUMBNAIL_SCALE);
|
||||||
|
|
||||||
|
let thumbnailHeight = screenHeight * scale;
|
||||||
|
|
||||||
|
let childBox = new Clutter.ActorBox();
|
||||||
|
|
||||||
|
let indicatorWorkspace = this._indicatorConstrained ? global.screen.get_active_workspace() : null;
|
||||||
|
let indicatorBox;
|
||||||
|
|
||||||
|
// 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 = box.x1;
|
||||||
|
childBox.x2 = childBox.x1 + global.screen_width;
|
||||||
|
|
||||||
|
let y = box.y1;
|
||||||
|
|
||||||
|
for (let i = 0; i < this._thumbnails.length; i++) {
|
||||||
|
if (i > 0)
|
||||||
|
y += spacing + thumbnailHeight;
|
||||||
|
|
||||||
|
// 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 compute an actual scale separately for each thumbnail.
|
||||||
|
let y1 = Math.round(y);
|
||||||
|
let y2 = Math.round(y + thumbnailHeight);
|
||||||
|
let roundedScale = (y2 - y1) / screenHeight;
|
||||||
|
|
||||||
|
if (this._thumbnails[i].metaWorkspace == indicatorWorkspace) {
|
||||||
|
let indicatorBox = new Clutter.ActorBox();
|
||||||
|
indicatorBox.x1 = box.x1;
|
||||||
|
indicatorBox.x2 = box.x2;
|
||||||
|
indicatorBox.y1 = y1;
|
||||||
|
indicatorBox.y2 = y2;
|
||||||
|
|
||||||
|
this._indicator.allocate(indicatorBox, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
childBox.y1 = y1;
|
||||||
|
childBox.y2 = childBox.y1 + screenHeight;
|
||||||
|
|
||||||
|
this._thumbnails[i].actor.set_scale(roundedScale, roundedScale);
|
||||||
|
this._thumbnails[i].actor.allocate(childBox, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (indicatorWorkspace == null)
|
||||||
|
this._indicator.allocate_preferred_size(flags);
|
||||||
|
},
|
||||||
|
|
||||||
|
_constrainThumbnailIndicator: function() {
|
||||||
|
this._indicatorConstrained = true;
|
||||||
|
this.actor.queue_relayout();
|
||||||
},
|
},
|
||||||
|
|
||||||
_unconstrainThumbnailIndicator: function() {
|
_unconstrainThumbnailIndicator: function() {
|
||||||
this._indicatorConstraints.forEach(function(constraint) {
|
this._indicatorConstrained = false;
|
||||||
constraint.set_enabled(false);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_activeWorkspaceChanged: function(wm, from, to, direction) {
|
_activeWorkspaceChanged: function(wm, from, to, direction) {
|
||||||
|
Loading…
Reference in New Issue
Block a user