[gnome-shell] Factor out hot corner handling into a class
- From: Alexander Larsson <alexl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] Factor out hot corner handling into a class
- Date: Wed, 23 Feb 2011 19:18:18 +0000 (UTC)
commit 196d10454a7b2bd139414d1e8e41ceb00d062105
Author: Alexander Larsson <alexl redhat com>
Date: Wed Feb 23 11:22:49 2011 +0100
Factor out hot corner handling into a class
This is needed so that we can have several instances, one per
monitor.
This also makes the hot corner environments a container which
contains the corner.
https://bugzilla.gnome.org/show_bug.cgi?id=642881
js/ui/panel.js | 304 +++++++++++++++++++++++++++++---------------------------
1 files changed, 159 insertions(+), 145 deletions(-)
---
diff --git a/js/ui/panel.js b/js/ui/panel.js
index b6fbc62..9efe551 100644
--- a/js/ui/panel.js
+++ b/js/ui/panel.js
@@ -640,6 +640,158 @@ PanelCorner.prototype = {
}
};
+/**
+ * HotCorner:
+ *
+ * This class manages the "hot corner" that can toggle switching to
+ * overview.
+ */
+function HotCorner() {
+ this._init();
+}
+
+HotCorner.prototype = {
+ _init : function() {
+ // We use this flag to mark the case where the user has entered the
+ // hot corner and has not left both the hot corner and a surrounding
+ // guard area (the "environs"). This avoids triggering the hot corner
+ // multiple times due to an accidental jitter.
+ this._entered = false;
+
+ this.actor = new Clutter.Group({ width: 3,
+ height: 3,
+ reactive: true });
+
+ this._corner = new Clutter.Rectangle({ width: 1,
+ height: 1,
+ opacity: 0,
+ reactive: true });
+
+ this.actor.add_actor(this._corner);
+
+ if (St.Widget.get_default_direction() == St.TextDirection.RTL) {
+ this._corner.set_position(this.actor.width - this._corner.width, 0);
+ this.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
+ } else {
+ this._corner.set_position(0, 0);
+ }
+
+ this._activationTime = 0;
+
+ this.actor.connect('leave-event',
+ Lang.bind(this, this._onEnvironsLeft));
+ // Clicking on the hot corner environs should result in the same bahavior
+ // as clicking on the hot corner.
+ this.actor.connect('button-release-event',
+ Lang.bind(this, this._onCornerClicked));
+
+ // In addition to being triggered by the mouse enter event, the hot corner
+ // can be triggered by clicking on it. This is useful if the user wants to
+ // undo the effect of triggering the hot corner once in the hot corner.
+ this._corner.connect('enter-event',
+ Lang.bind(this, this._onCornerEntered));
+ this._corner.connect('button-release-event',
+ Lang.bind(this, this._onCornerClicked));
+ this._corner.connect('leave-event',
+ Lang.bind(this, this._onCornerLeft));
+
+ this._corner._delegate = this._corner;
+ this._corner.handleDragOver = Lang.bind(this,
+ function(source, actor, x, y, time) {
+ if (source == Main.xdndHandler) {
+ if(!Main.overview.visible && !Main.overview.animationInProgress) {
+ this.rippleAnimation();
+ Main.overview.showTemporarily();
+ Main.overview.beginItemDrag(actor);
+ }
+ }
+ });
+ },
+
+ destroy: function() {
+ this.actor.destroy();
+ },
+
+ _addRipple : function(delay, time, startScale, startOpacity, finalScale, finalOpacity) {
+ // We draw a ripple by using a source image and animating it scaling
+ // outwards and fading away. We want the ripples to move linearly
+ // or it looks unrealistic, but if the opacity of the ripple goes
+ // linearly to zero it fades away too quickly, so we use Tweener's
+ // 'onUpdate' to give a non-linear curve to the fade-away and make
+ // it more visible in the middle section.
+
+ let [x, y] = this._corner.get_transformed_position();
+ let ripple = new St.BoxLayout({ style_class: 'ripple-box',
+ opacity: 255 * Math.sqrt(startOpacity),
+ scale_x: startScale,
+ scale_y: startScale,
+ x: x,
+ y: y });
+ ripple._opacity = startOpacity;
+ Tweener.addTween(ripple, { _opacity: finalOpacity,
+ scale_x: finalScale,
+ scale_y: finalScale,
+ delay: delay,
+ time: time,
+ transition: 'linear',
+ onUpdate: function() { ripple.opacity = 255 * Math.sqrt(ripple._opacity); },
+ onComplete: function() { ripple.destroy(); } });
+ Main.uiGroup.add_actor(ripple);
+ },
+
+ rippleAnimation: function() {
+ // Show three concentric ripples expanding outwards; the exact
+ // parameters were found by trial and error, so don't look
+ // for them to make perfect sense mathematically
+
+ // delay time scale opacity => scale opacity
+ this._addRipple(0.0, 0.83, 0.25, 1.0, 1.5, 0.0);
+ this._addRipple(0.05, 1.0, 0.0, 0.7, 1.25, 0.0);
+ this._addRipple(0.35, 1.0, 0.0, 0.3, 1, 0.0);
+ },
+
+ _onCornerEntered : function() {
+ if (!this._entered) {
+ this._entered = true;
+ if (!Main.overview.animationInProgress) {
+ this._activationTime = Date.now() / 1000;
+
+ this.rippleAnimation();
+ Main.overview.toggle();
+ }
+ }
+ return false;
+ },
+
+ _onCornerClicked : function() {
+ if (!Main.overview.animationInProgress)
+ this.maybeToggleOverviewOnClick();
+ return false;
+ },
+
+ _onCornerLeft : function(actor, event) {
+ if (event.get_related() != this.actor)
+ this._entered = false;
+ // Consume event, otherwise this will confuse onEnvironsLeft
+ return true;
+ },
+
+ _onEnvironsLeft : function(actor, event) {
+ if (event.get_related() != this._corner)
+ this._entered = false;
+ return false;
+ },
+
+ // Toggles the overview unless this is the first click on the Activities button within the HOT_CORNER_ACTIVATION_TIMEOUT time
+ // of the hot corner being triggered. This check avoids opening and closing the overview if the user both triggered the hot corner
+ // and clicked the Activities button.
+ maybeToggleOverviewOnClick: function() {
+ if (this._activationTime == 0 || Date.now() / 1000 - this._activationTime > HOT_CORNER_ACTIVATION_TIMEOUT)
+ Main.overview.toggle();
+ this._activationTime = 0;
+ }
+}
+
function Panel() {
this._init();
@@ -712,27 +864,16 @@ Panel.prototype = {
sideWidth = (allocWidth - centerWidth) / 2;
let childBox = new Clutter.ActorBox();
- childBox.y1 = 0;
- childBox.y2 = this._hotCornerEnvirons.height;
- if (this.actor.get_direction() == St.TextDirection.RTL) {
- childBox.x1 = allocWidth - this._hotCornerEnvirons.width;
- childBox.x2 = allocWidth;
- } else {
- childBox.x1 = 0;
- childBox.x2 = this._hotCornerEnvirons.width;
- }
- this._hotCornerEnvirons.allocate(childBox, flags);
childBox.y1 = 0;
- childBox.y2 = this._hotCorner.height;
+ childBox.y2 = this._hotCorner.actor.height;
if (this.actor.get_direction() == St.TextDirection.RTL) {
- childBox.x1 = allocWidth - this._hotCorner.width;
- childBox.x2 = allocWidth;
+ childBox.x1 = allocWidth;
} else {
childBox.x1 = 0;
- childBox.x2 = this._hotCorner.width;
}
- this._hotCorner.allocate(childBox, flags);
+ childBox.x2 = childBox.x1 + this._hotCorner.actor.width;
+ this._hotCorner.actor.allocate(childBox, flags);
childBox.y1 = 0;
childBox.y2 = allocHeight;
@@ -800,55 +941,8 @@ Panel.prototype = {
corner.actor.set_style_pseudo_class(pseudoClass);
}));
- // We use this flag to mark the case where the user has entered the
- // hot corner and has not left both the hot corner and a surrounding
- // guard area (the "environs"). This avoids triggering the hot corner
- // multiple times due to an accidental jitter.
- this._hotCornerEntered = false;
-
- this._hotCornerEnvirons = new Clutter.Rectangle({ width: 3,
- height: 3,
- opacity: 0,
- reactive: true });
-
- this._hotCorner = new Clutter.Rectangle({ width: 1,
- height: 1,
- opacity: 0,
- reactive: true });
-
- this._hotCornerActivationTime = 0;
-
- this._hotCornerEnvirons.connect('leave-event',
- Lang.bind(this, this._onHotCornerEnvironsLeft));
- // Clicking on the hot corner environs should result in the same bahavior
- // as clicking on the hot corner.
- this._hotCornerEnvirons.connect('button-release-event',
- Lang.bind(this, this._onHotCornerClicked));
-
- // In addition to being triggered by the mouse enter event, the hot corner
- // can be triggered by clicking on it. This is useful if the user wants to
- // undo the effect of triggering the hot corner once in the hot corner.
- this._hotCorner.connect('enter-event',
- Lang.bind(this, this._onHotCornerEntered));
- this._hotCorner.connect('button-release-event',
- Lang.bind(this, this._onHotCornerClicked));
- this._hotCorner.connect('leave-event',
- Lang.bind(this, this._onHotCornerLeft));
-
- this._hotCorner._delegate = this._hotCorner;
- this._hotCorner.handleDragOver = Lang.bind(this,
- function(source, actor, x, y, time) {
- if (source == Main.xdndHandler) {
- if(!Main.overview.visible && !Main.overview.animationInProgress) {
- this.rippleAnimation();
- Main.overview.showTemporarily();
- Main.overview.beginItemDrag(actor);
- }
- }
- });
-
- this._boxContainer.add_actor(this._hotCornerEnvirons);
- this._boxContainer.add_actor(this._hotCorner);
+ this._hotCorner = new HotCorner();
+ this._boxContainer.add_actor(this._hotCorner.actor);
let appMenuButton = new AppMenuButton();
this._leftBox.add(appMenuButton.actor);
@@ -894,7 +988,7 @@ Panel.prototype = {
// to switch to.
this.button.connect('clicked', Lang.bind(this, function(b) {
if (!Main.overview.animationInProgress) {
- this._maybeToggleOverviewOnClick();
+ this._hotCorner.maybeToggleOverviewOnClick();
return true;
} else {
return false;
@@ -1001,84 +1095,4 @@ Panel.prototype = {
this._trayBox.remove_actor(icon);
},
- _addRipple : function(delay, time, startScale, startOpacity, finalScale, finalOpacity) {
- // We draw a ripple by using a source image and animating it scaling
- // outwards and fading away. We want the ripples to move linearly
- // or it looks unrealistic, but if the opacity of the ripple goes
- // linearly to zero it fades away too quickly, so we use Tweener's
- // 'onUpdate' to give a non-linear curve to the fade-away and make
- // it more visible in the middle section.
-
- let [x, y] = this._hotCorner.get_transformed_position();
- let ripple = new St.BoxLayout({ style_class: 'ripple-box',
- opacity: 255 * Math.sqrt(startOpacity),
- scale_x: startScale,
- scale_y: startScale,
- x: x,
- y: y });
- ripple._opacity = startOpacity;
- Tweener.addTween(ripple, { _opacity: finalOpacity,
- scale_x: finalScale,
- scale_y: finalScale,
- delay: delay,
- time: time,
- transition: 'linear',
- onUpdate: function() { ripple.opacity = 255 * Math.sqrt(ripple._opacity); },
- onComplete: function() { ripple.destroy(); } });
- Main.uiGroup.add_actor(ripple);
- },
-
- rippleAnimation: function() {
- // Show three concentric ripples expanding outwards; the exact
- // parameters were found by trial and error, so don't look
- // for them to make perfect sense mathematically
-
- // delay time scale opacity => scale opacity
- this._addRipple(0.0, 0.83, 0.25, 1.0, 1.5, 0.0);
- this._addRipple(0.05, 1.0, 0.0, 0.7, 1.25, 0.0);
- this._addRipple(0.35, 1.0, 0.0, 0.3, 1, 0.0);
- },
-
- _onHotCornerEntered : function() {
- if (!this._hotCornerEntered) {
- this._hotCornerEntered = true;
- if (!Main.overview.animationInProgress) {
- this._hotCornerActivationTime = Date.now() / 1000;
-
- this.rippleAnimation();
- Main.overview.toggle();
- }
- }
- return false;
- },
-
- _onHotCornerClicked : function() {
- if (!Main.overview.animationInProgress) {
- this._maybeToggleOverviewOnClick();
- }
- return false;
- },
-
- _onHotCornerLeft : function(actor, event) {
- if (event.get_related() != this._hotCornerEnvirons) {
- this._hotCornerEntered = false;
- }
- return false;
- },
-
- _onHotCornerEnvironsLeft : function(actor, event) {
- if (event.get_related() != this._hotCorner) {
- this._hotCornerEntered = false;
- }
- return false;
- },
-
- // Toggles the overview unless this is the first click on the Activities button within the HOT_CORNER_ACTIVATION_TIMEOUT time
- // of the hot corner being triggered. This check avoids opening and closing the overview if the user both triggered the hot corner
- // and clicked the Activities button.
- _maybeToggleOverviewOnClick: function() {
- if (this._hotCornerActivationTime == 0 || Date.now() / 1000 - this._hotCornerActivationTime > HOT_CORNER_ACTIVATION_TIMEOUT)
- Main.overview.toggle();
- this._hotCornerActivationTime = 0;
- }
};
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]