Workspace: Highlight window clone and caption when hovered

Windows in the overview should be highlighted when hovered, to indicate
they are an active target.

Based on a patch by Marc Plano-Lesay <marc.planolesay@gmail.com>

https://bugzilla.gnome.org/show_bug.cgi?id=665310
This commit is contained in:
Giovanni Campagna 2012-10-27 18:18:54 +02:00
parent 8a7c0313f6
commit a370697385
2 changed files with 88 additions and 15 deletions

View File

@ -615,6 +615,7 @@ StScrollBar StButton#vhandle:active {
border-radius: 8px; border-radius: 8px;
padding: 4px 12px; padding: 4px 12px;
-shell-caption-spacing: 12px; -shell-caption-spacing: 12px;
border: 2px solid rgba(0, 0, 0, 0);
} }
.window-close, .notification-close { .window-close, .notification-close {
@ -625,7 +626,16 @@ StScrollBar StButton#vhandle:active {
} }
.window-close { .window-close {
-shell-close-overlap: 20px; -shell-close-overlap: 16px;
}
.window-caption:hover {
border: 2px solid rgba(255, 255, 255, 0);
}
.window-clone-border {
border: 4px solid rgba(255, 255, 255, 0.5);
border-radius: 4px;
} }
.notification-close { .notification-close {

View File

@ -445,6 +445,9 @@ const WindowOverlay = new Lang.Class({
this._parentActor = parentActor; this._parentActor = parentActor;
this._hidden = false; this._hidden = false;
this.borderSize = 0;
this.border = new St.Bin({ style_class: 'window-clone-border' });
let title = new St.Label({ style_class: 'window-caption', let title = new St.Label({ style_class: 'window-caption',
text: metaWindow.title }); text: metaWindow.title });
title.clutter_text.ellipsize = Pango.EllipsizeMode.END; title.clutter_text.ellipsize = Pango.EllipsizeMode.END;
@ -482,11 +485,13 @@ const WindowOverlay = new Lang.Class({
this.closeButton = button; this.closeButton = button;
parentActor.add_actor(this.title); parentActor.add_actor(this.title);
parentActor.add_actor(this.border);
parentActor.add_actor(this.closeButton); parentActor.add_actor(this.closeButton);
title.connect('style-changed', title.connect('style-changed',
Lang.bind(this, this._onStyleChanged)); Lang.bind(this, this._onStyleChanged));
button.connect('style-changed', button.connect('style-changed',
Lang.bind(this, this._onStyleChanged)); Lang.bind(this, this._onStyleChanged));
this.border.connect('style-changed', Lang.bind(this, this._onStyleChanged));
// force a style change if we are already on a stage - otherwise // force a style change if we are already on a stage - otherwise
// the signal will be emitted normally when we are added // the signal will be emitted normally when we are added
if (parentActor.get_stage()) if (parentActor.get_stage())
@ -497,13 +502,17 @@ const WindowOverlay = new Lang.Class({
this._hidden = true; this._hidden = true;
this.closeButton.hide(); this.closeButton.hide();
this.title.hide(); this.title.hide();
this.title.remove_style_pseudo_class('hover');
this.border.hide();
}, },
show: function() { show: function() {
this._hidden = false; this._hidden = false;
if (this._windowClone.actor.has_pointer)
this.closeButton.show();
this.title.show(); this.title.show();
if (this._windowClone.actor.has_pointer)
this._animateVisible();
}, },
fadeIn: function() { fadeIn: function() {
@ -520,10 +529,14 @@ const WindowOverlay = new Lang.Class({
}, },
chromeHeights: function () { chromeHeights: function () {
return [this.closeButton.height - this.closeButton._overlap, return [Math.max(this.borderSize, this.closeButton.height - this.closeButton._overlap),
this.title.height + this.title._spacing]; this.title.height + this.title._spacing];
}, },
chromeWidths: function () {
return [this.borderSize, this.borderSize];
},
_repositionSelf: function() { _repositionSelf: function() {
let [cloneX, cloneY, cloneWidth, cloneHeight] = this._windowClone.slot; let [cloneX, cloneY, cloneWidth, cloneHeight] = this._windowClone.slot;
this.updatePositions(cloneX, cloneY, cloneWidth, cloneHeight, false); this.updatePositions(cloneX, cloneY, cloneWidth, cloneHeight, false);
@ -578,16 +591,32 @@ const WindowOverlay = new Lang.Class({
title.width = titleWidth; title.width = titleWidth;
title.set_position(Math.floor(titleX), Math.floor(titleY)); title.set_position(Math.floor(titleX), Math.floor(titleY));
} }
let borderX = cloneX - this.borderSize;
let borderY = cloneY - this.borderSize;
let borderWidth = cloneWidth + 2 * this.borderSize;
let borderHeight = cloneHeight + 2 * this.borderSize;
if (animate) {
this._animateOverlayActor(this.border, borderX, borderY,
borderWidth, borderHeight);
} else {
this.border.set_position(borderX, borderY);
this.border.set_size(borderWidth, borderHeight);
}
}, },
_animateOverlayActor: function(actor, x, y, width) { _animateOverlayActor: function(actor, x, y, width, height) {
Tweener.addTween(actor, let params = { x: x,
{ x: x,
y: y, y: y,
width: width, width: width,
time: Overview.ANIMATION_TIME, time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad' transition: 'easeOutQuad' };
});
if (height !== undefined)
params.height = height;
Tweener.addTween(actor, params);
}, },
_closeWindow: function(actor) { _closeWindow: function(actor) {
@ -630,6 +659,21 @@ const WindowOverlay = new Lang.Class({
this._windowClone.metaWindow.disconnect(this._updateCaptionId); this._windowClone.metaWindow.disconnect(this._updateCaptionId);
this.title.destroy(); this.title.destroy();
this.closeButton.destroy(); this.closeButton.destroy();
this.border.destroy();
},
_animateVisible: function() {
this._parentActor.raise_top();
this.closeButton.show();
this.border.show();
this.border.opacity = 0;
Tweener.addTween(this.border,
{ opacity: 255,
time: CLOSE_BUTTON_FADE_TIME,
transition: 'easeOutQuad' });
this.title.add_style_pseudo_class('hover');
}, },
_onEnter: function() { _onEnter: function() {
@ -639,8 +683,8 @@ const WindowOverlay = new Lang.Class({
// are shown again // are shown again
if (this._hidden) if (this._hidden)
return; return;
this._parentActor.raise_top();
this.closeButton.show(); this._animateVisible();
this.emit('show-close-button'); this.emit('show-close-button');
}, },
@ -652,9 +696,18 @@ const WindowOverlay = new Lang.Class({
_idleToggleCloseButton: function() { _idleToggleCloseButton: function() {
this._idleToggleCloseId = 0; this._idleToggleCloseId = 0;
if (!this._windowClone.actor.has_pointer && if (!this._windowClone.actor.has_pointer &&
!this.closeButton.has_pointer) !this.closeButton.has_pointer) {
this.closeButton.hide(); this.closeButton.hide();
this.border.opacity = 255;
Tweener.addTween(this.border,
{ opacity: 0,
time: CLOSE_BUTTON_FADE_TIME,
transition: 'easeInQuad' });
this.title.remove_style_pseudo_class('hover');
}
return false; return false;
}, },
@ -664,6 +717,8 @@ const WindowOverlay = new Lang.Class({
this._idleToggleCloseId = 0; this._idleToggleCloseId = 0;
} }
this.closeButton.hide(); this.closeButton.hide();
this.border.hide();
this.title.remove_style_pseudo_class('hover');
}, },
_onStyleChanged: function() { _onStyleChanged: function() {
@ -673,6 +728,9 @@ const WindowOverlay = new Lang.Class({
let closeNode = this.closeButton.get_theme_node(); let closeNode = this.closeButton.get_theme_node();
this.closeButton._overlap = closeNode.get_length('-shell-close-overlap'); this.closeButton._overlap = closeNode.get_length('-shell-close-overlap');
let borderNode = this.border.get_theme_node();
this.borderSize = borderNode.get_border_width(St.Side.TOP);
this._parentActor.queue_relayout(); this._parentActor.queue_relayout();
} }
}); });
@ -1623,20 +1681,25 @@ const Workspace = new Lang.Class({
return []; return [];
let closeButtonHeight, captionHeight; let closeButtonHeight, captionHeight;
let leftBorder, rightBorder;
if (this._windowOverlays.length) { if (this._windowOverlays.length) {
// All of the overlays have the same chrome sizes, // All of the overlays have the same chrome sizes,
// so just pick the first one. // so just pick the first one.
let overlay = this._windowOverlays[0]; let overlay = this._windowOverlays[0];
[closeButtonHeight, captionHeight] = overlay.chromeHeights(); [closeButtonHeight, captionHeight] = overlay.chromeHeights();
[leftBorder, rightBorder] = overlay.chromeWidths();
} else { } else {
[closeButtonHeight, captionHeight] = [0, 0]; [closeButtonHeight, captionHeight] = [0, 0];
} }
rowSpacing += captionHeight; rowSpacing += captionHeight;
columnSpacing += rightBorder;
let area = { x: this._x, y: this._y, width: this._width, height: this._height }; let area = { x: this._x, y: this._y, width: this._width, height: this._height };
area.y += closeButtonHeight; area.y += closeButtonHeight;
area.height -= closeButtonHeight; area.height -= closeButtonHeight;
area.x += leftBorder;
area.width -= leftBorder;
if (!this._currentLayout) if (!this._currentLayout)
this._currentLayout = this._computeLayout(windows, area, rowSpacing, columnSpacing, captionHeight); this._currentLayout = this._computeLayout(windows, area, rowSpacing, columnSpacing, captionHeight);