169 lines
4.8 KiB
JavaScript
169 lines
4.8 KiB
JavaScript
|
/* ========================================================================================================
|
||
|
* myPressureBarrier.js
|
||
|
* --------------------------------------------------------------------------------------------------------
|
||
|
* CREDITS: Part of this code was copied from gnome-shell Layout.js
|
||
|
* ========================================================================================================
|
||
|
*/
|
||
|
|
||
|
|
||
|
const Clutter = imports.gi.Clutter;
|
||
|
const GLib = imports.gi.GLib;
|
||
|
const GObject = imports.gi.GObject;
|
||
|
const Lang = imports.lang;
|
||
|
const Meta = imports.gi.Meta;
|
||
|
const Shell = imports.gi.Shell;
|
||
|
const Signals = imports.signals;
|
||
|
const St = imports.gi.St;
|
||
|
|
||
|
const Main = imports.ui.main;
|
||
|
|
||
|
var MyPressureBarrier = class WorkspacesToDock_MyPressureBarrier {
|
||
|
constructor(threshold, speedLimit, timeout, actionMode) {
|
||
|
this._threshold = threshold;
|
||
|
this._speedLimit = speedLimit;
|
||
|
this._timeout = timeout;
|
||
|
this._actionMode = actionMode;
|
||
|
this._barriers = [];
|
||
|
this._eventFilter = null;
|
||
|
|
||
|
this._isTriggered = false;
|
||
|
this._reset();
|
||
|
}
|
||
|
|
||
|
addBarrier(barrier) {
|
||
|
barrier._pressureHitId = barrier.connect('hit', this._onBarrierHit.bind(this));
|
||
|
barrier._pressureLeftId = barrier.connect('left', this._onBarrierLeft.bind(this));
|
||
|
|
||
|
this._barriers.push(barrier);
|
||
|
}
|
||
|
|
||
|
_disconnectBarrier(barrier) {
|
||
|
barrier.disconnect(barrier._pressureHitId);
|
||
|
barrier.disconnect(barrier._pressureLeftId);
|
||
|
}
|
||
|
|
||
|
removeBarrier(barrier) {
|
||
|
this._disconnectBarrier(barrier);
|
||
|
this._barriers.splice(this._barriers.indexOf(barrier), 1);
|
||
|
}
|
||
|
|
||
|
destroy() {
|
||
|
this._barriers.forEach(this._disconnectBarrier.bind(this));
|
||
|
this._barriers = [];
|
||
|
}
|
||
|
|
||
|
setEventFilter(filter) {
|
||
|
this._eventFilter = filter;
|
||
|
}
|
||
|
|
||
|
_reset() {
|
||
|
this._barrierEvents = [];
|
||
|
this._currentPressure = 0;
|
||
|
this._lastTime = 0;
|
||
|
}
|
||
|
|
||
|
_isHorizontal(barrier) {
|
||
|
return barrier.y1 == barrier.y2;
|
||
|
}
|
||
|
|
||
|
_getDistanceAcrossBarrier(barrier, event) {
|
||
|
if (this._isHorizontal(barrier))
|
||
|
return Math.abs(event.dy);
|
||
|
else
|
||
|
return Math.abs(event.dx);
|
||
|
}
|
||
|
|
||
|
_getDistanceAlongBarrier(barrier, event) {
|
||
|
if (this._isHorizontal(barrier))
|
||
|
return Math.abs(event.dx);
|
||
|
else
|
||
|
return Math.abs(event.dy);
|
||
|
}
|
||
|
|
||
|
_trimBarrierEvents() {
|
||
|
// Events are guaranteed to be sorted in time order from
|
||
|
// oldest to newest, so just look for the first old event,
|
||
|
// and then chop events after that off.
|
||
|
let i = 0;
|
||
|
let threshold = this._lastTime - this._timeout;
|
||
|
|
||
|
while (i < this._barrierEvents.length) {
|
||
|
let [time, distance] = this._barrierEvents[i];
|
||
|
if (time >= threshold)
|
||
|
break;
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
let firstNewEvent = i;
|
||
|
|
||
|
for (i = 0; i < firstNewEvent; i++) {
|
||
|
let [time, distance] = this._barrierEvents[i];
|
||
|
this._currentPressure -= distance;
|
||
|
}
|
||
|
|
||
|
this._barrierEvents = this._barrierEvents.slice(firstNewEvent);
|
||
|
}
|
||
|
|
||
|
_onBarrierLeft(barrier, event) {
|
||
|
barrier._isHit = false;
|
||
|
if (this._barriers.every(function(b) { return !b._isHit; })) {
|
||
|
this._reset();
|
||
|
this._isTriggered = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_trigger() {
|
||
|
this._isTriggered = true;
|
||
|
this.emit('trigger');
|
||
|
this._reset();
|
||
|
}
|
||
|
|
||
|
_onBarrierHit(barrier, event) {
|
||
|
barrier._isHit = true;
|
||
|
|
||
|
// If we've triggered the barrier, wait until the pointer has the
|
||
|
// left the barrier hitbox until we trigger it again.
|
||
|
if (this._isTriggered)
|
||
|
return;
|
||
|
|
||
|
if (this._eventFilter && this._eventFilter(event))
|
||
|
return;
|
||
|
|
||
|
// Throw out all events not in the proper keybinding mode
|
||
|
if (!(this._actionMode & Main.actionMode))
|
||
|
return;
|
||
|
|
||
|
let slide = this._getDistanceAlongBarrier(barrier, event);
|
||
|
let distance = this._getDistanceAcrossBarrier(barrier, event);
|
||
|
|
||
|
if (this._speedLimit && distance >= this._speedLimit) {
|
||
|
this.emit('speed-exceeded');
|
||
|
this._reset();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (distance >= this._threshold) {
|
||
|
this._trigger();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Throw out events where the cursor is move more
|
||
|
// along the axis of the barrier than moving with
|
||
|
// the barrier.
|
||
|
if (slide > distance)
|
||
|
return;
|
||
|
|
||
|
this._lastTime = event.time;
|
||
|
|
||
|
this._trimBarrierEvents();
|
||
|
distance = Math.min(15, distance);
|
||
|
|
||
|
this._barrierEvents.push([event.time, distance]);
|
||
|
this._currentPressure += distance;
|
||
|
|
||
|
if (this._currentPressure >= this._threshold)
|
||
|
this._trigger();
|
||
|
}
|
||
|
};
|
||
|
Signals.addSignalMethods(MyPressureBarrier.prototype);
|