2682 lines
94 KiB
JavaScript
2682 lines
94 KiB
JavaScript
|
/* extension.js
|
||
|
*
|
||
|
* This program is free software: you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation, either version 2 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*
|
||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||
|
*/
|
||
|
|
||
|
import Clutter from 'gi://Clutter';
|
||
|
import Meta from 'gi://Meta';
|
||
|
import St from 'gi://St';
|
||
|
import Shell from 'gi://Shell';
|
||
|
import Gio from 'gi://Gio';
|
||
|
|
||
|
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||
|
import { Extension } from 'resource:///org/gnome/shell/extensions/extension.js';
|
||
|
|
||
|
// Window edge action
|
||
|
const WindowEdgeAction = {
|
||
|
NONE: 0, // No action
|
||
|
WAIT_GESTURE: 0x01, // Wait for gesture flag
|
||
|
MOVE: 0x02, // Move flag
|
||
|
RESIZE: 0x04, // Resize flag
|
||
|
|
||
|
GESTURE_LEFT: 0x10, // Gesture Left
|
||
|
GESTURE_RIGHT: 0x20, // Gesture Right
|
||
|
GESTURE_UP: 0x40, // Gesture Up
|
||
|
GESTURE_DOWN: 0x80, // Gesture Down
|
||
|
|
||
|
GESTURE_UP_LEFT: 0x100, // Gesture Up Left
|
||
|
GESTURE_UP_RIGHT: 0x200, // Gesture Up Right
|
||
|
|
||
|
GESTURE_HORIZONTAL: 0x400, // Non-Window Gestures
|
||
|
GESTURE_VERTICAL: 0x800,
|
||
|
|
||
|
RESIZE_LEFT: 0x1000, // Resize Flags
|
||
|
RESIZE_RIGHT: 0x2000,
|
||
|
RESIZE_TOP: 0x4000,
|
||
|
RESIZE_BOTTOM: 0x8000,
|
||
|
|
||
|
MOVE_SNAP_TOP: 0x10000, // Snap Flags
|
||
|
MOVE_SNAP_LEFT: 0x20000,
|
||
|
MOVE_SNAP_RIGHT: 0x40000
|
||
|
|
||
|
};
|
||
|
|
||
|
// Window Blacklist Classes
|
||
|
const WindowClassBlacklist = [
|
||
|
"gjs"
|
||
|
];
|
||
|
|
||
|
// Manager Class
|
||
|
class Manager {
|
||
|
|
||
|
// Init Extension
|
||
|
constructor(ext) {
|
||
|
// Get settings
|
||
|
this._settings = ext.getSettings();
|
||
|
|
||
|
// Gestures are hooked by WGS
|
||
|
this._hooked = false;
|
||
|
|
||
|
// Create virtual devices
|
||
|
const seat = Clutter.get_default_backend().get_default_seat();
|
||
|
this._virtualTouchpad = seat.create_virtual_device(
|
||
|
Clutter.InputDeviceType.POINTER_DEVICE
|
||
|
);
|
||
|
this._virtualKeyboard = seat.create_virtual_device(
|
||
|
Clutter.InputDeviceType.KEYBOARD_DEVICE
|
||
|
);
|
||
|
|
||
|
// Init variables - keep enable() clean
|
||
|
this._clearVars();
|
||
|
|
||
|
// Capture Touchpad Event
|
||
|
this._gestureCallbackID = global.stage.connect(
|
||
|
'captured-event::touchpad',
|
||
|
this._touchpadEvent.bind(this)
|
||
|
);
|
||
|
|
||
|
// init 3 or 4 fingers config support
|
||
|
this._initFingerCountFlip();
|
||
|
|
||
|
// action widget holder
|
||
|
this._actionWidgets = {};
|
||
|
|
||
|
// Desktop Theme Setting
|
||
|
this._isettings = new Gio.Settings({
|
||
|
schema: 'org.gnome.desktop.interface'
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// Clear potentially running timeout/interval
|
||
|
destroyTimers() {
|
||
|
if (this._holdTo) {
|
||
|
// hold waiter
|
||
|
clearTimeout(this._holdTo);
|
||
|
this._holdTo = null;
|
||
|
}
|
||
|
if (this._actionWidgets.resetWinlist) {
|
||
|
// Alt+Tab timeout
|
||
|
clearTimeout(this._actionWidgets.resetWinlist);
|
||
|
this._actionWidgets.resetWinlist = null;
|
||
|
}
|
||
|
if (this._keyRepeatInterval) {
|
||
|
// Key repeat interval
|
||
|
clearInterval(this._keyRepeatInterval);
|
||
|
this._keyRepeatInterval = null;
|
||
|
}
|
||
|
if (this._flingInterval) {
|
||
|
// Kinetic interval
|
||
|
clearInterval(this._flingInterval);
|
||
|
this._flingInterval = null;
|
||
|
}
|
||
|
if (this._actionWidgets.tilerHider) {
|
||
|
clearTimeout(this._actionWidgets.tilerHider);
|
||
|
this._actionWidgets.tilerHider = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Cleanup Extension
|
||
|
destroy() {
|
||
|
// clear timers
|
||
|
this.destroyTimers();
|
||
|
|
||
|
// restore default GNOME 3 fingers gesture
|
||
|
this._restoreFingerCountFlip();
|
||
|
|
||
|
// Release Touchpad Event Capture
|
||
|
global.stage.disconnect(this._gestureCallbackID);
|
||
|
|
||
|
// Cleanup virtual devices
|
||
|
this._virtualTouchpad = null;
|
||
|
this._virtualKeyboard = null;
|
||
|
|
||
|
// Cleanup all variables
|
||
|
this._clearVars();
|
||
|
this._isettings = null;
|
||
|
this._settings = null;
|
||
|
this._ShaderClass = null;
|
||
|
}
|
||
|
|
||
|
// Initialize variables
|
||
|
_clearVars() {
|
||
|
// Target window to manage
|
||
|
this._targetWindow = null;
|
||
|
|
||
|
// Mouse start position
|
||
|
this._startPos = {
|
||
|
x: 0, y: 0
|
||
|
};
|
||
|
|
||
|
// Mouse start position
|
||
|
this._movePos = {
|
||
|
x: 0, y: 0
|
||
|
};
|
||
|
|
||
|
// Monitor Id
|
||
|
this._monitorId = 0;
|
||
|
|
||
|
// Monitor Workarea
|
||
|
this._monitorArea = null;
|
||
|
|
||
|
// Starting Window Area
|
||
|
this._startWinArea = null;
|
||
|
|
||
|
// Edge Action
|
||
|
this._edgeAction = WindowEdgeAction.NONE;
|
||
|
this._edgeGestured = 0;
|
||
|
this._swipeIsWin = false;
|
||
|
this._isActiveWin = false;
|
||
|
this._tapHold = 0;
|
||
|
this._tapHoldWin = null;
|
||
|
this._tapHoldTick = 0;
|
||
|
|
||
|
// Pinch
|
||
|
this._gesture = {
|
||
|
begin: false,
|
||
|
fingers: 0,
|
||
|
progress: 0,
|
||
|
|
||
|
velocity: null,
|
||
|
|
||
|
action: 0,
|
||
|
action_id: 0,
|
||
|
action_cmp: 0
|
||
|
};
|
||
|
|
||
|
// Clear window tile preview
|
||
|
// this._hidePreview();
|
||
|
}
|
||
|
|
||
|
// Init 3 or 4 finger count switch mode
|
||
|
_initFingerCountFlip() {
|
||
|
// Move 3-4 Finger Gesture
|
||
|
/*
|
||
|
* Original Hook Logic From (swap-finger-gestures):
|
||
|
* https://github.com/icedman/swap-finger-gestures-3-4
|
||
|
*
|
||
|
*/
|
||
|
this._swipeMods = [
|
||
|
Main.overview._swipeTracker._touchpadGesture,
|
||
|
Main.wm._workspaceAnimation._swipeTracker._touchpadGesture,
|
||
|
Main.overview._overview._controls
|
||
|
._workspacesDisplay._swipeTracker._touchpadGesture,
|
||
|
Main.overview._overview._controls
|
||
|
._appDisplay._swipeTracker._touchpadGesture
|
||
|
];
|
||
|
let me = this;
|
||
|
this._swipeMods.forEach((g) => {
|
||
|
g._newHandleEvent = (actor, event) => {
|
||
|
event._get_touchpad_gesture_finger_count =
|
||
|
event.get_touchpad_gesture_finger_count;
|
||
|
event.get_touchpad_gesture_finger_count = () => {
|
||
|
let real_count = event._get_touchpad_gesture_finger_count();
|
||
|
if (me._hooked || (real_count == me._gestureNumFinger())) {
|
||
|
return 0;
|
||
|
}
|
||
|
else if (real_count >= 3) {
|
||
|
return 3;
|
||
|
}
|
||
|
return 0;
|
||
|
};
|
||
|
if (me._hooked) {
|
||
|
return Clutter.EVENT_STOP;
|
||
|
}
|
||
|
return g._handleEvent(actor, event);
|
||
|
};
|
||
|
global.stage.disconnectObject(g);
|
||
|
global.stage.connectObject(
|
||
|
'captured-event::touchpad',
|
||
|
g._newHandleEvent.bind(g),
|
||
|
g
|
||
|
);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// Restore 3 or 4 finger count switch mode
|
||
|
_restoreFingerCountFlip() {
|
||
|
// Restore 3 finger gesture
|
||
|
this._swipeMods.forEach((g) => {
|
||
|
global.stage.disconnectObject(g);
|
||
|
global.stage.connectObject(
|
||
|
'captured-event::touchpad',
|
||
|
g._handleEvent.bind(g),
|
||
|
g
|
||
|
);
|
||
|
});
|
||
|
this._swipeMods = [];
|
||
|
}
|
||
|
|
||
|
// Is dark theme?
|
||
|
_isDarkTheme() {
|
||
|
let uit = this._settings.get_int('ui-theme');
|
||
|
if (uit == 0) {
|
||
|
return (this._isettings
|
||
|
.get_string('color-scheme') == 'prefer-dark');
|
||
|
}
|
||
|
return (uit == 2);
|
||
|
}
|
||
|
|
||
|
// Create UI Indicator
|
||
|
_createUi(ui_class, x, y, w, h, icon, parent) {
|
||
|
let ui = new St.Widget({ style_class: ui_class });
|
||
|
if (this._isDarkTheme()) {
|
||
|
ui.add_style_class_name("wgs-dark");
|
||
|
}
|
||
|
// ui.set_clip_to_allocation(true);
|
||
|
ui._icon = null;
|
||
|
ui._parent = parent ? parent : Main.layoutManager.uiGroup;
|
||
|
if (icon) {
|
||
|
ui._icon = new St.Icon({
|
||
|
icon_name: icon,
|
||
|
style_class: 'wgs-widget-icon'
|
||
|
});
|
||
|
ui.add_child(ui._icon);
|
||
|
}
|
||
|
ui.set_position(x, y);
|
||
|
ui.set_size(w, h);
|
||
|
ui.set_pivot_point(0.5, 0.5);
|
||
|
ui.viewShow = (prop, duration) => {
|
||
|
ui.show();
|
||
|
prop.mode = Clutter.AnimationMode.EASE_OUT_QUAD;
|
||
|
prop.duration = duration;
|
||
|
ui.ease(prop);
|
||
|
};
|
||
|
ui.viewHide = (prop) => {
|
||
|
prop.mode = Clutter.AnimationMode.EASE_OUT_QUAD;
|
||
|
prop.duration = duration;
|
||
|
prop.onStopped = () => {
|
||
|
ui.hide();
|
||
|
};
|
||
|
ui.ease(prop);
|
||
|
};
|
||
|
ui.aniRelease = (progress) => {
|
||
|
if (!progress) {
|
||
|
progress = 1.0;
|
||
|
}
|
||
|
if (progress > 0.2) {
|
||
|
ui.ease({
|
||
|
opacity: 0,
|
||
|
scale_x: 0,
|
||
|
scale_y: 0,
|
||
|
duration: Math.round(250 * progress),
|
||
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||
|
onStopped: () => {
|
||
|
ui.release();
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
else {
|
||
|
ui.release();
|
||
|
}
|
||
|
};
|
||
|
ui.release = () => {
|
||
|
// Cleanup
|
||
|
ui.hide();
|
||
|
ui._parent.remove_child(ui);
|
||
|
if (ui._icon) {
|
||
|
ui.remove_child(ui._icon);
|
||
|
ui._icon.destroy();
|
||
|
ui._icon = null;
|
||
|
}
|
||
|
ui.destroy();
|
||
|
ui = null;
|
||
|
};
|
||
|
ui._parent.add_child(ui);
|
||
|
return ui;
|
||
|
}
|
||
|
|
||
|
// Create Shader Effect
|
||
|
_createShader(type, actor, name) {
|
||
|
let fx = new Clutter.ShaderEffect(
|
||
|
{ shader_type: Clutter.ShaderType.FRAGMENT_SHADER }
|
||
|
);
|
||
|
let shader = '';
|
||
|
if (type == 'close') {
|
||
|
shader =
|
||
|
'color.g *= 1-(0.3*value); ' +
|
||
|
'color.b *= 1-(0.34*value); ';
|
||
|
}
|
||
|
else {
|
||
|
shader =
|
||
|
'color.rgb *= 1.0-value; ';
|
||
|
}
|
||
|
fx.set_shader_source(
|
||
|
'uniform sampler2D tex; ' +
|
||
|
'uniform float value; ' +
|
||
|
'void main() { ' +
|
||
|
'vec4 color=texture2D(tex,cogl_tex_coord_in[0].st);' +
|
||
|
shader +
|
||
|
'cogl_color_out = color * cogl_color_in;}'
|
||
|
);
|
||
|
fx.set_uniform_value('tex', 0);
|
||
|
fx.setValue = function (v) {
|
||
|
fx.set_uniform_value('value', v);
|
||
|
}
|
||
|
if (actor) {
|
||
|
fx._fxname = name;
|
||
|
actor.fx = fx;
|
||
|
if (actor.get_effect(name)) {
|
||
|
actor.remove_effect_by_name(name);
|
||
|
}
|
||
|
actor.add_effect_with_name(name, fx);
|
||
|
}
|
||
|
fx.release = () => {
|
||
|
if (actor) {
|
||
|
actor.remove_effect_by_name(actor.fx._fxname);
|
||
|
actor.fx = null;
|
||
|
actor = null;
|
||
|
}
|
||
|
fx = null;
|
||
|
};
|
||
|
return fx;
|
||
|
}
|
||
|
|
||
|
// Velocity functions
|
||
|
_velocityInit() {
|
||
|
let vel = {
|
||
|
data: [],
|
||
|
prev: 0
|
||
|
};
|
||
|
return vel;
|
||
|
}
|
||
|
_velocityTrim(vel) {
|
||
|
const thresholdTime = this._tick() - 150;
|
||
|
const index = vel.data.findIndex(r => r.time >= thresholdTime);
|
||
|
vel.data.splice(0, index);
|
||
|
}
|
||
|
_velocityAppend(vel, v) {
|
||
|
this._velocityTrim(vel);
|
||
|
let vb = Math.abs(v);
|
||
|
let d = vb - vel.prev;
|
||
|
vel.prev = vb;
|
||
|
vel.data.push({ time: this._tick(), delta: d });
|
||
|
}
|
||
|
_velocityCalc(vel) {
|
||
|
this._velocityTrim(vel);
|
||
|
if (vel.data.length < 2)
|
||
|
return 0;
|
||
|
const firstTime = vel.data[0].time;
|
||
|
const lastTime = vel.data[vel.data.length - 1].time;
|
||
|
if (firstTime === lastTime)
|
||
|
return 0;
|
||
|
const totalDelta = vel.data.slice(1).map(
|
||
|
a => a.delta).reduce((a, b) => a + b);
|
||
|
const period = lastTime - firstTime;
|
||
|
return totalDelta / period;
|
||
|
}
|
||
|
_velocityFlingHandler(me) {
|
||
|
if (me._velocityFlingQueue.length == 0) {
|
||
|
clearInterval(me._flingInterval);
|
||
|
me._flingInterval = 0;
|
||
|
return;
|
||
|
}
|
||
|
let now = me._velocityFlingQueue[0];
|
||
|
let clearIt = false;
|
||
|
now.target += now.v * 2;
|
||
|
now.v *= 0.98;
|
||
|
now.n++;
|
||
|
if (me._velocityFlingQueue.length != 1) {
|
||
|
// Another fling called
|
||
|
now.cb(1, target);
|
||
|
clearIt = true;
|
||
|
}
|
||
|
else if (now.target >= now.max || now.n >= now.maxframe) {
|
||
|
if (now.target >= now.max) {
|
||
|
now.target = now.max;
|
||
|
}
|
||
|
now.cb(1, now.target);
|
||
|
clearIt = true;
|
||
|
}
|
||
|
else {
|
||
|
now.cb(0, now.target);
|
||
|
}
|
||
|
if (clearIt) {
|
||
|
me._velocityFlingQueue.splice(0, 1);
|
||
|
}
|
||
|
}
|
||
|
_velocityFling(vel, curr, max, maxframe, cb) {
|
||
|
if (!this._velocityFlingQueue) {
|
||
|
this._velocityFlingQueue = [];
|
||
|
}
|
||
|
this._velocityFlingQueue.push({
|
||
|
target: curr,
|
||
|
v: vel,
|
||
|
max: max,
|
||
|
maxframe: maxframe,
|
||
|
cb: cb,
|
||
|
n: 0
|
||
|
});
|
||
|
if (!this._flingInterval) {
|
||
|
this._flingInterval = setInterval(
|
||
|
this._velocityFlingHandler, 4, this
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
_tick() {
|
||
|
return new Date().getTime();
|
||
|
}
|
||
|
|
||
|
_isWindowBlacklist(win) {
|
||
|
if (win) {
|
||
|
if (WindowClassBlacklist.indexOf(win.get_wm_class()) == -1 ||
|
||
|
win.get_window_type() === Meta.WindowType.DESKTOP) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// Get padding edge size
|
||
|
_edgeSize() {
|
||
|
return this._settings.get_int('edge-size');
|
||
|
}
|
||
|
|
||
|
// Get top padding edge size
|
||
|
_topEdgeSize() {
|
||
|
return this._settings.get_int('top-edge-size');
|
||
|
}
|
||
|
|
||
|
// Get gesture threshold
|
||
|
_gestureThreshold() {
|
||
|
return this._settings.get_int('gesture-threshold');
|
||
|
}
|
||
|
|
||
|
// Get acceleration
|
||
|
_getAcceleration() {
|
||
|
return (this._settings.get_int('gesture-acceleration') * 0.1);
|
||
|
}
|
||
|
|
||
|
// Get gesture threshold
|
||
|
_gestureCancelThreshold() {
|
||
|
return this._settings.get_int('gesture-cancel-threshold');
|
||
|
}
|
||
|
|
||
|
// Is 3 Finger
|
||
|
_gestureNumFinger() {
|
||
|
return this._settings.get_boolean("three-finger") ? 3 : 4;
|
||
|
}
|
||
|
|
||
|
// Functions Settings
|
||
|
_getUseActiveWindow() {
|
||
|
return this._settings.get_boolean("use-active-window");
|
||
|
}
|
||
|
_getEnableResize() {
|
||
|
return this._settings.get_boolean("fn-resize");
|
||
|
}
|
||
|
_getEnableMove() {
|
||
|
return this._settings.get_boolean("fn-move");
|
||
|
}
|
||
|
_getEnableMaxSnap() {
|
||
|
return this._settings.get_boolean("fn-maximized-snap");
|
||
|
}
|
||
|
_getEnableMoveSnap() {
|
||
|
return this._settings.get_boolean("fn-move-snap");
|
||
|
}
|
||
|
_getEnableFullscreen() {
|
||
|
return this._settings.get_boolean("fn-fullscreen");
|
||
|
}
|
||
|
_getPinchInScale() {
|
||
|
return this._settings.get_int('pinch-in-scale');
|
||
|
}
|
||
|
_getPinchOutScale() {
|
||
|
return this._settings.get_int('pinch-out-scale');
|
||
|
}
|
||
|
_getPinchEnabled() {
|
||
|
return this._settings.get_boolean("pinch-enable");
|
||
|
}
|
||
|
_getTapHoldMove() {
|
||
|
return this._settings.get_boolean("taphold-move");
|
||
|
}
|
||
|
|
||
|
// Is On Overview
|
||
|
_isOnOverview() {
|
||
|
return Main.overview._shown;
|
||
|
}
|
||
|
|
||
|
// Check edge flags
|
||
|
_isEdge(edge) {
|
||
|
return ((this._edgeAction & edge) == edge);
|
||
|
}
|
||
|
|
||
|
// Show Preview
|
||
|
_showPreview(rx, ry, rw, rh) {
|
||
|
if (global.display.get_focus_window() == null) {
|
||
|
return;
|
||
|
}
|
||
|
global.window_manager.emit("show-tile-preview",
|
||
|
global.display.get_focus_window(), new Meta.Rectangle(
|
||
|
{ x: rx, y: ry, width: rw, height: rh }
|
||
|
)
|
||
|
, this._monitorId
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// Find Target Window
|
||
|
_findPointerWindow() {
|
||
|
let target = null;
|
||
|
let [pointerX, pointerY, pointerZ] = global.get_pointer();
|
||
|
let currActor = global.stage.get_actor_at_pos(
|
||
|
Clutter.PickMode.REACTIVE, pointerX, pointerY
|
||
|
);
|
||
|
if (currActor) {
|
||
|
// Find root window for current actor
|
||
|
let currWindow = currActor.get_parent();
|
||
|
let i = 0;
|
||
|
while (currWindow && !currWindow.get_meta_window) {
|
||
|
currWindow = currWindow.get_parent();
|
||
|
if (!currWindow || (++i > 10)) {
|
||
|
currWindow = null;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
// Set meta window as target window to manage
|
||
|
target = currWindow?.get_meta_window();
|
||
|
}
|
||
|
return target;
|
||
|
}
|
||
|
|
||
|
// Get Alt Tabs List
|
||
|
_getWindowTabList() {
|
||
|
let wm = global.workspace_manager;
|
||
|
let workspace = wm.get_active_workspace();
|
||
|
let windows = global.display.get_tab_list(
|
||
|
Meta.TabList.NORMAL_ALL, workspace
|
||
|
);
|
||
|
return windows.map(w => {
|
||
|
return w.is_attached_dialog() ? w.get_transient_for() : w;
|
||
|
}).filter((w, i, a) => !w.skip_taskbar && a.indexOf(w) === i);
|
||
|
}
|
||
|
|
||
|
// Hide Preview
|
||
|
_hidePreview() {
|
||
|
global.window_manager.emit("hide-tile-preview");
|
||
|
}
|
||
|
|
||
|
// Simulate keypress (up -> down)
|
||
|
_sendKeyPress(combination) {
|
||
|
combination.forEach(key => this._virtualKeyboard.notify_keyval(
|
||
|
Clutter.get_current_event_time(), key, Clutter.KeyState.PRESSED)
|
||
|
);
|
||
|
combination.reverse().forEach(key =>
|
||
|
this._virtualKeyboard.notify_keyval(
|
||
|
Clutter.get_current_event_time(), key, Clutter.KeyState.RELEASED
|
||
|
));
|
||
|
}
|
||
|
|
||
|
// Move Mouse Pointer
|
||
|
_movePointer(x, y) {
|
||
|
if (!this._isActiveWin) {
|
||
|
// Move only if not use active window
|
||
|
this._virtualTouchpad.notify_relative_motion(
|
||
|
Meta.CURRENT_TIME, x, y
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// window management
|
||
|
_winmanWinApp(win) {
|
||
|
return Shell.WindowTracker.get_default()
|
||
|
.get_window_app(win);
|
||
|
// App.create_icon_texture;
|
||
|
}
|
||
|
|
||
|
// Snap Window
|
||
|
_setSnapWindow(snapRight) {
|
||
|
if (this._targetWindow == null) {
|
||
|
return;
|
||
|
}
|
||
|
// TODO: Using non key shortcut for snap left/right
|
||
|
if (snapRight) {
|
||
|
this._sendKeyPress([Clutter.KEY_Super_L, Clutter.KEY_Right]);
|
||
|
}
|
||
|
else {
|
||
|
this._sendKeyPress([Clutter.KEY_Super_L, Clutter.KEY_Left]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Move to Workspace
|
||
|
_moveWindowWorkspace(moveRight) {
|
||
|
if ((this._targetWindow == null) ||
|
||
|
!Meta.prefs_get_dynamic_workspaces()) {
|
||
|
return;
|
||
|
}
|
||
|
let wsid = this._targetWindow.get_workspace().index();
|
||
|
if (wsid == 0 && !moveRight) {
|
||
|
this._insertWorkspace(0, this._targetWindow);
|
||
|
return;
|
||
|
}
|
||
|
let tw = this._targetWindow.get_workspace()
|
||
|
.get_neighbor(moveRight ? Meta.MotionDirection.RIGHT :
|
||
|
Meta.MotionDirection.LEFT);
|
||
|
this._targetWindow.change_workspace(tw);
|
||
|
this._targetWindow.activate(Meta.CURRENT_TIME);
|
||
|
}
|
||
|
|
||
|
// Insert new workspace
|
||
|
_insertWorkspace(pos, chkwin) {
|
||
|
// Main.wm.insertWorkspace(0);
|
||
|
let wm = global.workspace_manager;
|
||
|
if (!Meta.prefs_get_dynamic_workspaces()) {
|
||
|
return -1;
|
||
|
}
|
||
|
wm.append_new_workspace(false, Meta.CURRENT_TIME);
|
||
|
let windows = global.get_window_actors().map(a => a.meta_window);
|
||
|
windows.forEach(window => {
|
||
|
if (chkwin && chkwin == window)
|
||
|
return -1;
|
||
|
if (window.get_transient_for() != null)
|
||
|
return -1;
|
||
|
if (window.is_override_redirect())
|
||
|
return -1;
|
||
|
if (window.on_all_workspaces)
|
||
|
return -1;
|
||
|
let index = window.get_workspace().index();
|
||
|
if (index < pos)
|
||
|
return -1;
|
||
|
window.change_workspace_by_index(index + 1, true);
|
||
|
});
|
||
|
if (chkwin) {
|
||
|
wm.get_workspace_by_index(pos + 1).activate(
|
||
|
Meta.CURRENT_TIME
|
||
|
);
|
||
|
chkwin.change_workspace_by_index(pos, true);
|
||
|
this._targetWindow.activate(Meta.CURRENT_TIME);
|
||
|
}
|
||
|
return pos;
|
||
|
}
|
||
|
_isDynamicWorkspace() {
|
||
|
return Meta.prefs_get_dynamic_workspaces();
|
||
|
}
|
||
|
|
||
|
// Have Left Workspace
|
||
|
_workspaceHavePrev() {
|
||
|
if (this._targetWindow == null) {
|
||
|
return false;
|
||
|
}
|
||
|
return (this._targetWindow.get_workspace().index() > 0);
|
||
|
}
|
||
|
|
||
|
_resetWinPos() {
|
||
|
if (this._targetWindow == null) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Reset
|
||
|
this._targetWindow.move_frame(
|
||
|
true,
|
||
|
this._startWinArea.x,
|
||
|
this._startWinArea.y
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// Activate Target Window
|
||
|
_activateWindow() {
|
||
|
if (this._targetWindow == null) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Activate window if not focused yet
|
||
|
if (!this._targetWindow.has_focus()) {
|
||
|
this._targetWindow.activate(
|
||
|
Meta.CURRENT_TIME
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Swipe window move handler
|
||
|
_swipeUpdateMove() {
|
||
|
this._activateWindow();
|
||
|
|
||
|
// gnome-shell-extension-tiling-assistant support
|
||
|
if (this._targetWindow.isTiled) {
|
||
|
let urct = this._targetWindow.untiledRect;
|
||
|
if (urct) {
|
||
|
let r = urct._rect;
|
||
|
this._startWinArea.x = r.x;
|
||
|
this._startWinArea.y = r.y;
|
||
|
this._startWinArea.width = r.width;
|
||
|
this._startWinArea.height = r.height;
|
||
|
// this._targetWindow.move_resize_frame(
|
||
|
// true,
|
||
|
// r.x, r.y, r.width, r.height
|
||
|
// );
|
||
|
this._sendKeyPress([Clutter.KEY_Super_L, Clutter.KEY_Down]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
let allowMoveSnap = this._getEnableMoveSnap();
|
||
|
// Move calculation
|
||
|
let mX = this._monitorArea.x;
|
||
|
let mY = this._monitorArea.y;
|
||
|
let mW = this._monitorArea.width;
|
||
|
let mR = mX + mW;
|
||
|
let winX = this._startWinArea.x + this._movePos.x;
|
||
|
let winY = this._startWinArea.y + this._movePos.y;
|
||
|
let winR = winX + this._startWinArea.width;
|
||
|
// Move action
|
||
|
this._targetWindow.move_frame(
|
||
|
true,
|
||
|
winX, winY
|
||
|
);
|
||
|
if (allowMoveSnap && winX < mX) {
|
||
|
this._showPreview(
|
||
|
this._monitorArea.x,
|
||
|
this._monitorArea.y,
|
||
|
this._monitorArea.width / 2,
|
||
|
this._monitorArea.height
|
||
|
);
|
||
|
this._edgeAction = WindowEdgeAction.MOVE
|
||
|
| WindowEdgeAction.MOVE_SNAP_LEFT;
|
||
|
}
|
||
|
else if (allowMoveSnap && winR > mR) {
|
||
|
this._showPreview(
|
||
|
this._monitorArea.x + (this._monitorArea.width / 2),
|
||
|
this._monitorArea.y,
|
||
|
this._monitorArea.width / 2,
|
||
|
this._monitorArea.height
|
||
|
);
|
||
|
this._edgeAction = WindowEdgeAction.MOVE
|
||
|
| WindowEdgeAction.MOVE_SNAP_RIGHT;
|
||
|
}
|
||
|
else if (allowMoveSnap && winY < mY) {
|
||
|
this._showPreview(
|
||
|
this._monitorArea.x,
|
||
|
this._monitorArea.y,
|
||
|
this._monitorArea.width,
|
||
|
this._monitorArea.height
|
||
|
);
|
||
|
this._edgeAction = WindowEdgeAction.MOVE
|
||
|
| WindowEdgeAction.MOVE_SNAP_TOP;
|
||
|
}
|
||
|
else {
|
||
|
this._edgeAction = WindowEdgeAction.MOVE;
|
||
|
this._hidePreview();
|
||
|
}
|
||
|
return Clutter.EVENT_STOP;
|
||
|
}
|
||
|
|
||
|
// Swipe window resize handler
|
||
|
_swipeUpdateResize(dx, dy) {
|
||
|
this._activateWindow();
|
||
|
// Move cursor pointer
|
||
|
this._movePointer(
|
||
|
(this._isEdge(WindowEdgeAction.RESIZE_LEFT) ||
|
||
|
this._isEdge(WindowEdgeAction.RESIZE_RIGHT)) ? dx : 0,
|
||
|
(this._isEdge(WindowEdgeAction.RESIZE_TOP) ||
|
||
|
this._isEdge(WindowEdgeAction.RESIZE_BOTTOM)) ? dy : 0
|
||
|
);
|
||
|
// Resize actions
|
||
|
let tX = this._startWinArea.x;
|
||
|
let tY = this._startWinArea.y;
|
||
|
let tW = this._startWinArea.width;
|
||
|
let tH = this._startWinArea.height;
|
||
|
if (this._isEdge(WindowEdgeAction.RESIZE_BOTTOM)) {
|
||
|
tH += this._movePos.y;
|
||
|
}
|
||
|
else if (this._isEdge(WindowEdgeAction.RESIZE_TOP)) {
|
||
|
tY += this._movePos.y;
|
||
|
tH -= this._movePos.y;
|
||
|
}
|
||
|
if (this._isEdge(WindowEdgeAction.RESIZE_RIGHT)) {
|
||
|
tW += this._movePos.x;
|
||
|
}
|
||
|
else if (this._isEdge(WindowEdgeAction.RESIZE_LEFT)) {
|
||
|
tX += this._movePos.x;
|
||
|
tW -= this._movePos.x;
|
||
|
}
|
||
|
let tR = tX + tW;
|
||
|
let tB = tY + tH;
|
||
|
let mX = this._monitorArea.x;
|
||
|
let mY = this._monitorArea.y;
|
||
|
let mW = this._monitorArea.width;
|
||
|
let mH = this._monitorArea.height;
|
||
|
let mR = mX + mW;
|
||
|
let mB = mY + mH;
|
||
|
// edge
|
||
|
if (tX < mX) {
|
||
|
tX = mX;
|
||
|
tW = tR - tX;
|
||
|
}
|
||
|
if (tY < mY) {
|
||
|
tY = mY;
|
||
|
tH = tB - tY;
|
||
|
}
|
||
|
if (tR > mR) {
|
||
|
tW = mR - tX;
|
||
|
}
|
||
|
if (tB > mB) {
|
||
|
tH = mB - tY;
|
||
|
}
|
||
|
// Resize Window
|
||
|
this._targetWindow.move_resize_frame(
|
||
|
true,
|
||
|
tX, tY, tW, tH
|
||
|
);
|
||
|
return Clutter.EVENT_STOP;
|
||
|
}
|
||
|
|
||
|
// Begin swipe gesture
|
||
|
_swipeBegin(numfingers) {
|
||
|
// Swipe Variables
|
||
|
this._swipeIsWin = (numfingers == this._gestureNumFinger());
|
||
|
|
||
|
// Workspace gesture only not on overview
|
||
|
if (this._isOnOverview() && !this._swipeIsWin) {
|
||
|
return Clutter.EVENT_PROPAGATE;
|
||
|
}
|
||
|
|
||
|
// Init gesture variables
|
||
|
this._gesture.begin = true;
|
||
|
this._gesture.fingers = numfingers;
|
||
|
this._gesture.progress = 0;
|
||
|
|
||
|
// Action Variables
|
||
|
this._gesture.action = 0;
|
||
|
this._gesture.action_cmp = 0;
|
||
|
this._gesture.action_id = 0;
|
||
|
|
||
|
// Velocity Variables
|
||
|
this._gesture.velocity = this._velocityInit();
|
||
|
this._velocityAppend(this._gesture.velocity, 0);
|
||
|
|
||
|
// Get current mouse position
|
||
|
let [pointerX, pointerY, pointerZ] = global.get_pointer();
|
||
|
this._startPos.x = pointerX;
|
||
|
this._startPos.y = pointerY;
|
||
|
this._movePos.x = this._movePos.y = 0;
|
||
|
|
||
|
// Configs
|
||
|
let allowResize = this._getEnableResize();
|
||
|
let allowMove = this._getEnableMove();
|
||
|
this._isActiveWin = false;
|
||
|
this._targetWindow = null;
|
||
|
let isTapHoldAction = false;
|
||
|
|
||
|
// Clear unswipe tap-hold
|
||
|
if ((this._tapHoldTick != 1) &&
|
||
|
(this._tapHoldTick < this._tick())) {
|
||
|
this._tapHold = this._tapHoldTick = 0;
|
||
|
this._tapHoldWin = null;
|
||
|
}
|
||
|
|
||
|
if (this._tapHoldWin) {
|
||
|
this._targetWindow = this._tapHoldWin;
|
||
|
this._tapHoldWin = null;
|
||
|
isTapHoldAction = true;
|
||
|
}
|
||
|
else if (!this._getUseActiveWindow() && !this._getTapHoldMove()) {
|
||
|
this._targetWindow = this._findPointerWindow();
|
||
|
}
|
||
|
if (!this._targetWindow) {
|
||
|
// Get Active Window
|
||
|
this._targetWindow = global.display.get_focus_window();
|
||
|
if (!this._targetWindow) {
|
||
|
return this._swipeIsWin ?
|
||
|
Clutter.EVENT_STOP : Clutter.EVENT_PROPAGATE;
|
||
|
}
|
||
|
allowResize = false;
|
||
|
this._isActiveWin = true;
|
||
|
}
|
||
|
|
||
|
// Set opener window as target if it was dialog
|
||
|
if (this._targetWindow.is_attached_dialog()) {
|
||
|
this._targetWindow = this._targetWindow.get_transient_for();
|
||
|
}
|
||
|
|
||
|
// Check blacklist window
|
||
|
if (this._isWindowBlacklist(this._targetWindow)) {
|
||
|
this._targetWindow = null;
|
||
|
return this._swipeIsWin ?
|
||
|
Clutter.EVENT_STOP : Clutter.EVENT_PROPAGATE;
|
||
|
}
|
||
|
|
||
|
// Get monitor area
|
||
|
this._monitorArea = this._targetWindow.get_work_area_current_monitor();
|
||
|
|
||
|
// Get monitor id
|
||
|
this._monitorId = global.display.get_monitor_index_for_rect(
|
||
|
this._monitorArea
|
||
|
);
|
||
|
|
||
|
// Get start frame rectangle
|
||
|
this._startWinArea = this._targetWindow.get_frame_rect();
|
||
|
|
||
|
// Window area as local value
|
||
|
let wLeft = this._startWinArea.x;
|
||
|
let wTop = this._startWinArea.y;
|
||
|
let wRight = wLeft + this._startWinArea.width;
|
||
|
let wBottom = wTop + this._startWinArea.height;
|
||
|
let wThirdX = wLeft + (this._startWinArea.width / 3);
|
||
|
let wThirdY = wTop + (this._startWinArea.height / 3);
|
||
|
let w34X = wLeft + ((this._startWinArea.width / 3) * 2);
|
||
|
let w34Y = wTop + ((this._startWinArea.height / 3) * 2);
|
||
|
|
||
|
// Detect window edge
|
||
|
let edge = this._edgeSize();
|
||
|
let topEdge = this._topEdgeSize();
|
||
|
|
||
|
// Default edge: need move event for more actions
|
||
|
this._edgeAction = WindowEdgeAction.NONE;
|
||
|
this._edgeGestured = 0;
|
||
|
|
||
|
// Check allow resize
|
||
|
if (this._swipeIsWin && !this._isActiveWin && allowResize &&
|
||
|
this._targetWindow.allows_resize() &&
|
||
|
this._targetWindow.allows_move() &&
|
||
|
!this._targetWindow.isTiled && !isTapHoldAction) {
|
||
|
// Edge cursor position detection
|
||
|
if (this._startPos.y >= wBottom - edge) {
|
||
|
if (this._startPos.y <= wBottom) {
|
||
|
// Cursor on bottom of window
|
||
|
this._edgeAction =
|
||
|
WindowEdgeAction.RESIZE |
|
||
|
WindowEdgeAction.RESIZE_BOTTOM;
|
||
|
|
||
|
// 1/3 from left|right
|
||
|
if (this._startPos.x <= wThirdX) {
|
||
|
this._edgeAction |= WindowEdgeAction.RESIZE_LEFT;
|
||
|
}
|
||
|
else if (this._startPos.x >= w34X) {
|
||
|
this._edgeAction |= WindowEdgeAction.RESIZE_RIGHT;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (this._startPos.x >= wLeft && this._startPos.x <= wRight) {
|
||
|
if (this._startPos.x <= wLeft + edge) {
|
||
|
// Cursor on left side of window
|
||
|
this._edgeAction =
|
||
|
WindowEdgeAction.RESIZE |
|
||
|
WindowEdgeAction.RESIZE_LEFT;
|
||
|
}
|
||
|
else if (this._startPos.x >= wRight - edge) {
|
||
|
// Cursor on right side of window
|
||
|
this._edgeAction =
|
||
|
WindowEdgeAction.RESIZE |
|
||
|
WindowEdgeAction.RESIZE_RIGHT;
|
||
|
}
|
||
|
if (this._isEdge(WindowEdgeAction.RESIZE)) {
|
||
|
// 1/3 from top|bottom
|
||
|
if (this._startPos.y <= wThirdY) {
|
||
|
this._edgeAction |= WindowEdgeAction.RESIZE_TOP;
|
||
|
}
|
||
|
else if (this._startPos.y >= w34Y) {
|
||
|
this._edgeAction |= WindowEdgeAction.RESIZE_BOTTOM;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (this._swipeIsWin && !this._isEdge(WindowEdgeAction.RESIZE)) {
|
||
|
let setmove = false;
|
||
|
if (this._getTapHoldMove()) {
|
||
|
if (this._tapHold == this._gestureNumFinger()) {
|
||
|
// Tap and hold
|
||
|
setmove = true;
|
||
|
}
|
||
|
}
|
||
|
else if (allowMove &&
|
||
|
this._startPos.x <= wRight &&
|
||
|
this._startPos.x >= wLeft &&
|
||
|
this._startPos.y >= wTop &&
|
||
|
this._startPos.y <= wTop + topEdge) {
|
||
|
// Mouse in top side of window
|
||
|
setmove = true;
|
||
|
}
|
||
|
if (setmove) {
|
||
|
if (this._targetWindow.allows_move() &&
|
||
|
!this._targetWindow.get_maximized()) {
|
||
|
this._edgeAction = WindowEdgeAction.MOVE;
|
||
|
}
|
||
|
}
|
||
|
} else if (this._tapHold > 2 &&
|
||
|
this._tapHold != this._gestureNumFinger()) {
|
||
|
this._edgeAction = WindowEdgeAction.GESTURE_DOWN;
|
||
|
this._movePos.y = (this._gestureThreshold() / 4) + 1;
|
||
|
}
|
||
|
|
||
|
return this._swipeIsWin ?
|
||
|
Clutter.EVENT_STOP : Clutter.EVENT_PROPAGATE;
|
||
|
}
|
||
|
|
||
|
_swipeUpdate(dx, dy) {
|
||
|
if (!this._gesture.begin) {
|
||
|
return Clutter.EVENT_PROPAGATE;
|
||
|
}
|
||
|
|
||
|
// Moving coordinate
|
||
|
this._movePos.x += dx;
|
||
|
this._movePos.y += dy;
|
||
|
|
||
|
// Move & Resize Handler
|
||
|
if (this._isEdge(WindowEdgeAction.MOVE)) {
|
||
|
return this._swipeUpdateMove();
|
||
|
}
|
||
|
else if (this._isEdge(WindowEdgeAction.RESIZE)) {
|
||
|
return this._swipeUpdateResize(dx, dy);
|
||
|
}
|
||
|
|
||
|
// Get threshold setting
|
||
|
let threshold = this._gestureThreshold();
|
||
|
let combineTrigger = this._gestureThreshold() * 2;
|
||
|
let trigger = (threshold / 4) + 1;
|
||
|
let target = 1.00 * (trigger + (threshold * 10));
|
||
|
let absX = Math.abs(this._movePos.x);
|
||
|
let absY = Math.abs(this._movePos.y);
|
||
|
|
||
|
// Find gesture directions
|
||
|
if (this._edgeAction == WindowEdgeAction.NONE) {
|
||
|
if (absX >= trigger || absY >= trigger) {
|
||
|
if (absX > absY) {
|
||
|
if (this._movePos.x <= 0 - trigger) {
|
||
|
this._edgeAction = WindowEdgeAction.GESTURE_LEFT;
|
||
|
}
|
||
|
else if (this._movePos.x >= trigger) {
|
||
|
this._edgeAction = WindowEdgeAction.GESTURE_RIGHT;
|
||
|
}
|
||
|
this._movePos.y = 0;
|
||
|
}
|
||
|
else {
|
||
|
if (this._movePos.y <= 0 - trigger) {
|
||
|
this._edgeAction = WindowEdgeAction.GESTURE_UP;
|
||
|
}
|
||
|
else if (this._movePos.y >= trigger) {
|
||
|
this._edgeAction = WindowEdgeAction.GESTURE_DOWN;
|
||
|
if (this._swipeIsWin) {
|
||
|
let allowMove = this._getEnableMove();
|
||
|
let holdMove = this._getTapHoldMove();
|
||
|
|
||
|
if (!allowMove || holdMove) {
|
||
|
if (!this._targetWindow.get_maximized() &&
|
||
|
!this._targetWindow.isTiled) {
|
||
|
this._edgeGestured = 1;
|
||
|
}
|
||
|
else {
|
||
|
this._edgeGestured = 0;
|
||
|
}
|
||
|
}
|
||
|
else if (
|
||
|
!this._edgeGestured &&
|
||
|
!this._targetWindow.is_fullscreen() &&
|
||
|
!this._targetWindow.get_maximized() &&
|
||
|
this._targetWindow.allows_move()) {
|
||
|
this._edgeAction = WindowEdgeAction.MOVE;
|
||
|
return this._swipeUpdateMove();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
this._movePos.x = 0;
|
||
|
}
|
||
|
this._edgeGestured = this._edgeGestured ? 2 : 1;
|
||
|
this._gesture.velocity = this._velocityInit();
|
||
|
this._velocityAppend(this._gesture.velocity, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
let prog = 0;
|
||
|
let vert = 0;
|
||
|
let horiz = 0;
|
||
|
if (this._isEdge(WindowEdgeAction.GESTURE_LEFT)) {
|
||
|
if (!this._swipeIsWin && !this._hooked) {
|
||
|
return Clutter.EVENT_PROPAGATE;
|
||
|
}
|
||
|
let xmove = this._movePos.x + trigger;
|
||
|
if (this._isEdge(WindowEdgeAction.GESTURE_UP) ||
|
||
|
this._isEdge(WindowEdgeAction.GESTURE_DOWN)) {
|
||
|
xmove = this._movePos.x + combineTrigger;
|
||
|
}
|
||
|
else if (!this._swipeIsWin) {
|
||
|
return Clutter.EVENT_PROPAGATE;
|
||
|
}
|
||
|
if (xmove < 0) {
|
||
|
prog = Math.abs(xmove) / target;
|
||
|
}
|
||
|
horiz = 1;
|
||
|
}
|
||
|
else if (this._isEdge(WindowEdgeAction.GESTURE_RIGHT)) {
|
||
|
if (!this._swipeIsWin && !this._hooked) {
|
||
|
return Clutter.EVENT_PROPAGATE;
|
||
|
}
|
||
|
let xmove = this._movePos.x - trigger;
|
||
|
if (this._isEdge(WindowEdgeAction.GESTURE_UP) ||
|
||
|
this._isEdge(WindowEdgeAction.GESTURE_DOWN)) {
|
||
|
xmove = this._movePos.x - combineTrigger;
|
||
|
}
|
||
|
else if (!this._swipeIsWin) {
|
||
|
return Clutter.EVENT_PROPAGATE;
|
||
|
}
|
||
|
if (xmove > 0) {
|
||
|
prog = xmove / target;
|
||
|
}
|
||
|
horiz = 2;
|
||
|
}
|
||
|
else if (this._isEdge(WindowEdgeAction.GESTURE_UP)) {
|
||
|
if (!this._swipeIsWin && !this._hooked) {
|
||
|
return Clutter.EVENT_PROPAGATE;
|
||
|
}
|
||
|
if (this._movePos.y < 0) {
|
||
|
prog = Math.abs(this._movePos.y) / target;
|
||
|
}
|
||
|
vert = 1;
|
||
|
}
|
||
|
else if (this._isEdge(WindowEdgeAction.GESTURE_DOWN)) {
|
||
|
if (!this._swipeIsWin && this._isOnOverview()) {
|
||
|
return Clutter.EVENT_PROPAGATE;
|
||
|
}
|
||
|
if (!this._swipeIsWin) {
|
||
|
this._hooked = true;
|
||
|
}
|
||
|
if (this._movePos.y > 0) {
|
||
|
let movey = this._movePos.y - (this._swipeIsWin ?
|
||
|
threshold : (threshold * 6));
|
||
|
if (movey < 0) {
|
||
|
movey = 0;
|
||
|
}
|
||
|
prog = movey / target;
|
||
|
}
|
||
|
vert = 2;
|
||
|
}
|
||
|
|
||
|
if (vert) {
|
||
|
if (absX >= trigger && ((vert == 1 && this._swipeIsWin) ||
|
||
|
(vert == 2 && !this._swipeIsWin))) {
|
||
|
if (vert == 1 || prog == 0) {
|
||
|
// Combination gesture (Down + Left/Right)
|
||
|
if (this._movePos.x <= 0 - combineTrigger) {
|
||
|
this._edgeAction |= WindowEdgeAction.GESTURE_LEFT;
|
||
|
this._gesture.velocity = this._velocityInit();
|
||
|
this._velocityAppend(this._gesture.velocity, 0);
|
||
|
this._movePos.x = 0 - combineTrigger;
|
||
|
return this._swipeUpdate(0, 0);
|
||
|
}
|
||
|
else if (this._movePos.x >= combineTrigger) {
|
||
|
this._edgeAction |= WindowEdgeAction.GESTURE_RIGHT;
|
||
|
this._gesture.velocity = this._velocityInit();
|
||
|
this._velocityAppend(this._gesture.velocity, 0);
|
||
|
this._movePos.x = combineTrigger;
|
||
|
return this._swipeUpdate(0, 0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (horiz) {
|
||
|
if (this._isEdge(WindowEdgeAction.GESTURE_UP)) {
|
||
|
vert = 1;
|
||
|
// Reset to single gesture
|
||
|
if (Math.abs(this._movePos.x) < combineTrigger) {
|
||
|
this._edgeAction = WindowEdgeAction.GESTURE_UP;
|
||
|
this._gesture.velocity = this._velocityInit();
|
||
|
this._velocityAppend(this._gesture.velocity, 0);
|
||
|
this._movePos.y = 0 - combineTrigger;
|
||
|
return this._swipeUpdate(0, 0);
|
||
|
}
|
||
|
}
|
||
|
else if (this._isEdge(WindowEdgeAction.GESTURE_DOWN)) {
|
||
|
vert = 2;
|
||
|
// Reset to single gesture
|
||
|
if (Math.abs(this._movePos.x) < combineTrigger) {
|
||
|
this._edgeAction = WindowEdgeAction.GESTURE_DOWN;
|
||
|
this._gesture.velocity = this._velocityInit();
|
||
|
this._velocityAppend(this._gesture.velocity, 0);
|
||
|
this._movePos.y = combineTrigger;
|
||
|
return this._swipeUpdate(0, 0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Switch gestures direction
|
||
|
if (
|
||
|
(vert == 1 && (this._movePos.y > 0 - trigger)) ||
|
||
|
(vert == 2 && (this._movePos.y < 0)) ||
|
||
|
(horiz == 1 && (this._movePos.x > 0 - trigger)) ||
|
||
|
(horiz == 2 && (this._movePos.x < 0))
|
||
|
) {
|
||
|
if (!(this._isEdge(WindowEdgeAction.GESTURE_DOWN) && horiz)) {
|
||
|
if (vert) {
|
||
|
this._movePos.x = 0;
|
||
|
}
|
||
|
if (horiz) {
|
||
|
this._movePos.y = 0;
|
||
|
}
|
||
|
this._edgeAction = WindowEdgeAction.NONE;
|
||
|
this._gesture.velocity = this._velocityInit();
|
||
|
this._velocityAppend(this._gesture.velocity, 0);
|
||
|
return this._swipeUpdate(0, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Limit progress
|
||
|
let oprog = prog;
|
||
|
if (prog >= 1) {
|
||
|
prog = 1.0;
|
||
|
}
|
||
|
this._gesture.action = 0;
|
||
|
|
||
|
// Set action
|
||
|
if (vert == 0) {
|
||
|
this._gesture.action = horiz; // left=1, right=2
|
||
|
}
|
||
|
else {
|
||
|
if (!this._swipeIsWin) {
|
||
|
if (horiz && vert == 2) {
|
||
|
// down + horiz
|
||
|
this._gesture.action = horiz + 4; // left=5, right=6
|
||
|
}
|
||
|
else {
|
||
|
// vert
|
||
|
this._gesture.action = (vert == 2) ? 4 : 7; // d=4, u=7
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (horiz && vert == 1) {
|
||
|
// up + horiz
|
||
|
this._gesture.action = horiz + 50; // left=51, right=52
|
||
|
}
|
||
|
else {
|
||
|
// vert
|
||
|
this._gesture.action = (vert == 2) ?
|
||
|
((this._edgeGestured == 1) ? 53 : 3) :
|
||
|
50; // up=50, dn=53, up+dn=3
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Cancel action
|
||
|
if (this._gesture.action_cmp &&
|
||
|
(this._gesture.action != this._gesture.action_cmp)) {
|
||
|
// Send Cancel State
|
||
|
let aid = this._actionIdGet(this._gesture.action_cmp);
|
||
|
if (aid) {
|
||
|
this._runAction(aid, 1, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Update progress & velocity
|
||
|
this._gesture.progress = prog;
|
||
|
this._velocityAppend(this._gesture.velocity,
|
||
|
this._gesture.progress);
|
||
|
|
||
|
if (this._gesture.action) {
|
||
|
let aid = this._actionIdGet(this._gesture.action);
|
||
|
if (aid) {
|
||
|
if (aid >= 50) {
|
||
|
this._activateWindow();
|
||
|
}
|
||
|
this._runAction(aid, 0, this._gesture.progress, oprog);
|
||
|
}
|
||
|
this._gesture.action_cmp = this._gesture.action;
|
||
|
}
|
||
|
|
||
|
return Clutter.EVENT_STOP;
|
||
|
}
|
||
|
|
||
|
_swipeEnd() {
|
||
|
// Check move snap
|
||
|
if (this._isEdge(WindowEdgeAction.MOVE)) {
|
||
|
this._hidePreview();
|
||
|
if (this._isEdge(WindowEdgeAction.MOVE_SNAP_TOP)) {
|
||
|
if (this._targetWindow.can_maximize()) {
|
||
|
this._resetWinPos();
|
||
|
this._targetWindow.maximize(Meta.MaximizeFlags.BOTH);
|
||
|
}
|
||
|
}
|
||
|
else if (this._isEdge(WindowEdgeAction.MOVE_SNAP_LEFT)) {
|
||
|
this._resetWinPos();
|
||
|
this._setSnapWindow(0);
|
||
|
}
|
||
|
else if (this._isEdge(WindowEdgeAction.MOVE_SNAP_RIGHT)) {
|
||
|
this._resetWinPos();
|
||
|
this._setSnapWindow(1);
|
||
|
}
|
||
|
this._hooked = false;
|
||
|
this._clearVars();
|
||
|
return Clutter.EVENT_STOP;
|
||
|
}
|
||
|
|
||
|
// Gesture Release
|
||
|
let retval = (!this._swipeIsWin && !this._hooked) ?
|
||
|
Clutter.EVENT_PROPAGATE : Clutter.EVENT_STOP;
|
||
|
this._hooked = false;
|
||
|
if (this._gesture.action) {
|
||
|
let aid = this._actionIdGet(this._gesture.action);
|
||
|
if (aid) {
|
||
|
let issnapaction = (aid == 51 || aid == 52);
|
||
|
if ((this._gesture.progress < 1.0) && !issnapaction) {
|
||
|
// Fling Velocity
|
||
|
let vel = this._velocityCalc(this._gesture.velocity);
|
||
|
if (vel > 0.001) {
|
||
|
let me = this;
|
||
|
this._velocityFling(vel,
|
||
|
this._gesture.progress,
|
||
|
1.0, 30,
|
||
|
function (state, prog) {
|
||
|
me._runAction(aid, state, prog);
|
||
|
}
|
||
|
);
|
||
|
this._clearVars();
|
||
|
return retval;
|
||
|
}
|
||
|
}
|
||
|
this._runAction(aid, 1, this._gesture.progress);
|
||
|
}
|
||
|
}
|
||
|
this._clearVars();
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
// Swipe Handler
|
||
|
_swipeEventHandler(actor, event) {
|
||
|
let numfingers = event.get_touchpad_gesture_finger_count();
|
||
|
if (numfingers != 3 && numfingers != 4) {
|
||
|
return Clutter.EVENT_PROPAGATE;
|
||
|
}
|
||
|
// Process gestures state
|
||
|
switch (event.get_gesture_phase()) {
|
||
|
case Clutter.TouchpadGesturePhase.BEGIN:
|
||
|
// Begin event
|
||
|
return this._swipeBegin(numfingers);
|
||
|
case Clutter.TouchpadGesturePhase.UPDATE:
|
||
|
// Update / move event
|
||
|
let [dx, dy] = event.get_gesture_motion_delta();
|
||
|
return this._swipeUpdate(
|
||
|
dx * this._getAcceleration(),
|
||
|
dy * this._getAcceleration()
|
||
|
);
|
||
|
}
|
||
|
return this._swipeEnd();
|
||
|
}
|
||
|
|
||
|
// Get Current Action Id
|
||
|
_pinchGetCurrentActionId() {
|
||
|
if (this._gesture.begin && this._gesture.action != 0) {
|
||
|
if (this._gesture.action != this._gesture.action_cmp) {
|
||
|
this._gesture.action_id = this._actionIdGet(
|
||
|
(this._gesture.fingers == 3) ?
|
||
|
this._gesture.action + 7 :
|
||
|
this._gesture.action + 9
|
||
|
);
|
||
|
this._gesture.action_cmp = this._gesture.action;
|
||
|
}
|
||
|
return this._gesture.action_id;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// Update Pinch
|
||
|
_pinchUpdate(pinch_scale) {
|
||
|
if (this._gesture.begin) {
|
||
|
let pIn = (this._getPinchInScale() / 100.0);
|
||
|
let pOut = (this._getPinchOutScale() / 100.0);
|
||
|
|
||
|
// Get prediction action & current progress position
|
||
|
if (pinch_scale < 1.0) {
|
||
|
if (pinch_scale < pIn) {
|
||
|
pinch_scale = pIn;
|
||
|
}
|
||
|
this._gesture.action = 1;
|
||
|
this._gesture.progress = (1.0 - pinch_scale) / (1.0 - pIn);
|
||
|
}
|
||
|
else if (pinch_scale > 1.0) {
|
||
|
if (pinch_scale > pOut) {
|
||
|
pinch_scale = pOut;
|
||
|
}
|
||
|
this._gesture.action = 2;
|
||
|
this._gesture.progress = (pinch_scale - 1.0) / (pOut - 1.0);
|
||
|
}
|
||
|
else {
|
||
|
this._gesture.action = 0;
|
||
|
this._gesture.progress = 0;
|
||
|
}
|
||
|
|
||
|
if (this._gesture.action_cmp &&
|
||
|
(this._gesture.action != this._gesture.action_cmp)) {
|
||
|
// Send Cancel State
|
||
|
let aid = this._actionIdGet(
|
||
|
(this._gesture.fingers == 3) ?
|
||
|
this._gesture.action_cmp + 7 :
|
||
|
this._gesture.action_cmp + 9
|
||
|
);
|
||
|
if (aid) {
|
||
|
this._runAction(aid, 1, 0);
|
||
|
}
|
||
|
|
||
|
// Reset velocity
|
||
|
this._gesture.velocity = this._velocityInit();
|
||
|
this._velocityAppend(this._gesture.velocity, 0);
|
||
|
}
|
||
|
this._velocityAppend(this._gesture.velocity,
|
||
|
this._gesture.progress);
|
||
|
|
||
|
let action_id = this._pinchGetCurrentActionId();
|
||
|
if (action_id) {
|
||
|
this._runAction(action_id, 0,
|
||
|
this._gesture.progress
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
return Clutter.EVENT_STOP;
|
||
|
}
|
||
|
|
||
|
// Pinch Begin
|
||
|
_pinchBegin(numfingers) {
|
||
|
// Pinch Variables
|
||
|
this._gesture.begin = true;
|
||
|
this._gesture.fingers = numfingers;
|
||
|
this._gesture.progress = 0;
|
||
|
|
||
|
// Action Variables
|
||
|
this._gesture.action = 0;
|
||
|
this._gesture.action_cmp = 0;
|
||
|
this._gesture.action_id = 0;
|
||
|
|
||
|
// Velocity Variables
|
||
|
this._gesture.velocity = this._velocityInit();
|
||
|
this._velocityAppend(this._gesture.velocity, 0);
|
||
|
return Clutter.EVENT_STOP;
|
||
|
}
|
||
|
|
||
|
// End Pinch
|
||
|
_pinchEnd() {
|
||
|
let action_id = this._pinchGetCurrentActionId();
|
||
|
if (action_id) {
|
||
|
if (this._gesture.progress < 1.0) {
|
||
|
// Fling Velocity
|
||
|
let vel = this._velocityCalc(this._gesture.velocity);
|
||
|
if (vel > 0.001) {
|
||
|
let me = this;
|
||
|
this._velocityFling(vel,
|
||
|
this._gesture.progress,
|
||
|
1.0, 30,
|
||
|
function (state, prog) {
|
||
|
me._runAction(action_id, state, prog);
|
||
|
}
|
||
|
);
|
||
|
this._clearVars();
|
||
|
return Clutter.EVENT_STOP;
|
||
|
}
|
||
|
}
|
||
|
this._runAction(action_id, 1, this._gesture.progress);
|
||
|
}
|
||
|
this._clearVars();
|
||
|
return Clutter.EVENT_STOP;
|
||
|
}
|
||
|
|
||
|
// Pinch Handler
|
||
|
_pinchEventHandler(actor, event) {
|
||
|
if (!this._getPinchEnabled()) {
|
||
|
return Clutter.EVENT_PROPAGATE;
|
||
|
}
|
||
|
let numfingers = event.get_touchpad_gesture_finger_count();
|
||
|
if (numfingers != 3 && numfingers != 4) {
|
||
|
return Clutter.EVENT_PROPAGATE;
|
||
|
}
|
||
|
const pinch_scale = event.get_gesture_pinch_scale();
|
||
|
|
||
|
// Process gestures state
|
||
|
switch (event.get_gesture_phase()) {
|
||
|
case Clutter.TouchpadGesturePhase.BEGIN:
|
||
|
return this._pinchBegin(numfingers);
|
||
|
case Clutter.TouchpadGesturePhase.UPDATE:
|
||
|
return this._pinchUpdate(pinch_scale);
|
||
|
}
|
||
|
return this._pinchEnd();
|
||
|
}
|
||
|
|
||
|
_tapHoldGesture(state, numfingers) {
|
||
|
let isWin = (numfingers == this._gestureNumFinger());
|
||
|
if (!isWin || this._getTapHoldMove()) {
|
||
|
if (state) {
|
||
|
let me = this;
|
||
|
this._holdTo = setTimeout(function () {
|
||
|
me._tapHold = 0;
|
||
|
let activeWin = null;
|
||
|
if (!me._getUseActiveWindow()) {
|
||
|
activeWin = me._findPointerWindow();
|
||
|
}
|
||
|
if (!activeWin) {
|
||
|
activeWin = global.display.get_focus_window();
|
||
|
}
|
||
|
if (activeWin && ((activeWin.allows_move() &&
|
||
|
!activeWin.get_maximized()) || !isWin)) {
|
||
|
activeWin.activate(
|
||
|
Meta.CURRENT_TIME
|
||
|
);
|
||
|
me._tapHold = numfingers;
|
||
|
me._tapHoldWin = activeWin;
|
||
|
me._tapHoldTick = 1;
|
||
|
activeWin.get_compositor_private()
|
||
|
.set_pivot_point(0.5, 0.5);
|
||
|
activeWin.get_compositor_private().ease({
|
||
|
duration: 100,
|
||
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||
|
scale_y: 1.05,
|
||
|
scale_x: 1.05,
|
||
|
onStopped: () => {
|
||
|
activeWin?.get_compositor_private().ease({
|
||
|
duration: 100,
|
||
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||
|
scale_y: 1,
|
||
|
scale_x: 1,
|
||
|
onStopped: () => {
|
||
|
activeWin?.get_compositor_private()
|
||
|
.set_pivot_point(0, 0);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
}, 100);
|
||
|
}
|
||
|
else {
|
||
|
if (this._holdTo) {
|
||
|
clearTimeout(this._holdTo);
|
||
|
}
|
||
|
this._tapHoldTick = this._tick() + 100;
|
||
|
this._holdTo = 0;
|
||
|
}
|
||
|
}
|
||
|
return Clutter.EVENT_PROPAGATE;
|
||
|
}
|
||
|
_tapHoldHandler(actor, event) {
|
||
|
// Process gestures state
|
||
|
let numfingers = event.get_touchpad_gesture_finger_count();
|
||
|
if (numfingers != 3 && numfingers != 4) {
|
||
|
return Clutter.EVENT_PROPAGATE;
|
||
|
}
|
||
|
if (event.get_gesture_phase() == Clutter.TouchpadGesturePhase.BEGIN) {
|
||
|
return this._tapHoldGesture(1, numfingers);
|
||
|
}
|
||
|
return this._tapHoldGesture(0, numfingers);
|
||
|
}
|
||
|
|
||
|
// Touch Event Handler
|
||
|
_touchpadEvent(actor, event) {
|
||
|
// log("_touchpadEvent = " + event.type());
|
||
|
// Process pinch
|
||
|
if (event.type() == Clutter.EventType.TOUCHPAD_PINCH)
|
||
|
return this._pinchEventHandler(actor, event);
|
||
|
|
||
|
// Process swipe
|
||
|
if (event.type() == Clutter.EventType.TOUCHPAD_SWIPE)
|
||
|
return this._swipeEventHandler(actor, event);
|
||
|
|
||
|
// Process tap hold
|
||
|
if (event.type() == Clutter.EventType.TOUCHPAD_HOLD)
|
||
|
return this._tapHoldHandler(actor, event);
|
||
|
|
||
|
return Clutter.EVENT_PROPAGATE;
|
||
|
}
|
||
|
|
||
|
// Get Action Id
|
||
|
_actionIdGet(type) {
|
||
|
let cfg_name = "";
|
||
|
switch (type) {
|
||
|
case 1: cfg_name = "swipe4-left"; break;
|
||
|
case 2: cfg_name = "swipe4-right"; break;
|
||
|
case 3: cfg_name = "swipe4-updown"; break;
|
||
|
case 4: cfg_name = "swipe3-down"; break;
|
||
|
case 5: cfg_name = "swipe3-left"; break;
|
||
|
case 6: cfg_name = "swipe3-right"; break;
|
||
|
case 7: cfg_name = "swipe3-downup"; break;
|
||
|
case 8: cfg_name = "pinch3-in"; break;
|
||
|
case 9: cfg_name = "pinch3-out"; break;
|
||
|
case 10: cfg_name = "pinch4-in"; break;
|
||
|
case 11: cfg_name = "pinch4-out"; break;
|
||
|
default:
|
||
|
if (type >= 50 && type <= 53) {
|
||
|
// Max & Snap
|
||
|
return type;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
return this._settings.get_int(cfg_name);
|
||
|
}
|
||
|
|
||
|
// Run Action
|
||
|
_runAction(id, state, progress, oprog) {
|
||
|
const _LCASE = 32;
|
||
|
if (id == 1) {
|
||
|
//
|
||
|
// MINIMIZE ACTION
|
||
|
//
|
||
|
if (this._isOnOverview()) {
|
||
|
return; // Ignore on overview
|
||
|
}
|
||
|
|
||
|
let activeWin = null;
|
||
|
let ui = this._actionWidgets.minimize;
|
||
|
|
||
|
// Init indicator
|
||
|
if (!ui) {
|
||
|
activeWin = global.display.get_focus_window();
|
||
|
if (this._isWindowBlacklist(activeWin)) {
|
||
|
activeWin = null;
|
||
|
}
|
||
|
if (activeWin && activeWin.can_minimize()) {
|
||
|
ui = activeWin.get_compositor_private();
|
||
|
this._actionWidgets.minimize = ui;
|
||
|
if (ui) {
|
||
|
ui.set_pivot_point(0.5, 1);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
this._actionWidgets.minimize = ui = -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Execute Progress
|
||
|
if (ui && ui != -1) {
|
||
|
if (!state) {
|
||
|
ui.set_pivot_point(0.5, 1);
|
||
|
ui.opacity = 255 - Math.round(100 * progress);
|
||
|
ui.scale_x = 1.0 - (0.2 * progress);
|
||
|
ui.scale_y = 1.0 - (0.2 * progress);
|
||
|
}
|
||
|
else {
|
||
|
// Action is executed
|
||
|
activeWin = null;
|
||
|
if (progress >= 1.0) {
|
||
|
activeWin = global.display.get_focus_window();
|
||
|
if (activeWin) {
|
||
|
if (!activeWin.can_minimize()) {
|
||
|
activeWin = null;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Restore
|
||
|
ui.ease({
|
||
|
duration: Math.round(250 * progress),
|
||
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||
|
opacity: activeWin ? 0 : 255,
|
||
|
scale_x: activeWin ? 0 : 1,
|
||
|
scale_y: activeWin ? 0 : 1,
|
||
|
onStopped: () => {
|
||
|
ui.set_pivot_point(0, 0);
|
||
|
if (activeWin) {
|
||
|
activeWin.minimize();
|
||
|
ui.opacity = 0;
|
||
|
ui.ease({
|
||
|
duration: 800,
|
||
|
opacity: 0,
|
||
|
onStopped: () => {
|
||
|
ui.opacity = 255;
|
||
|
ui.scale_x = 1;
|
||
|
ui.scale_y = 1;
|
||
|
ui = null;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
else {
|
||
|
ui = null;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
this._actionWidgets.minimize = null;
|
||
|
}
|
||
|
} else if (state) {
|
||
|
this._actionWidgets.minimize = ui = null;
|
||
|
}
|
||
|
}
|
||
|
else if (id == 2) {
|
||
|
//
|
||
|
// CLOSE WINDOW ACTION
|
||
|
//
|
||
|
if (this._isOnOverview()) {
|
||
|
return; // Ignore on overview
|
||
|
}
|
||
|
|
||
|
let activeWin = null;
|
||
|
let ui = this._actionWidgets.close;
|
||
|
|
||
|
// Init indicator
|
||
|
if (!ui) {
|
||
|
activeWin = global.display.get_focus_window();
|
||
|
if (this._isWindowBlacklist(activeWin)) {
|
||
|
activeWin = null;
|
||
|
}
|
||
|
if (activeWin) {
|
||
|
ui = activeWin.get_compositor_private();
|
||
|
this._actionWidgets.close = ui;
|
||
|
if (ui) {
|
||
|
ui.set_pivot_point(0.5, 0.5);
|
||
|
this._createShader('close', ui, 'closeindicator');
|
||
|
ui.fx?.setValue(0);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
this._actionWidgets.close = ui = -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Execute Progress
|
||
|
if (ui && ui != -1) {
|
||
|
if (!state) {
|
||
|
ui.set_pivot_point(0.5, 0.5);
|
||
|
ui.opacity = 255 - Math.round(40 * progress);
|
||
|
ui.scale_x = 1.0 - (progress * 0.08);
|
||
|
ui.scale_y = 1.0 - (progress * 0.08);
|
||
|
ui.fx?.setValue(progress * 0.99);
|
||
|
}
|
||
|
else {
|
||
|
activeWin = null;
|
||
|
|
||
|
// Action is executed
|
||
|
if (progress >= 1.0) {
|
||
|
activeWin = global.display.get_focus_window();
|
||
|
}
|
||
|
|
||
|
ui.fx?.release();
|
||
|
ui.set_pivot_point(0, 0);
|
||
|
ui.opacity = 255;
|
||
|
ui.scale_x = 1.0;
|
||
|
ui.scale_y = 1.0;
|
||
|
if (activeWin) {
|
||
|
activeWin.delete(
|
||
|
Meta.CURRENT_TIME
|
||
|
);
|
||
|
activeWin = null;
|
||
|
}
|
||
|
ui = null;
|
||
|
this._actionWidgets.close = null;
|
||
|
}
|
||
|
} else if (state) {
|
||
|
this._actionWidgets.close = ui = null;
|
||
|
}
|
||
|
}
|
||
|
else if (id == 3) {
|
||
|
//
|
||
|
// SHOW DESKTOP
|
||
|
//
|
||
|
if (this._isOnOverview()) { // Ignore on overview
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
let ui = this._actionWidgets.show_desktop;
|
||
|
|
||
|
// Init indicator
|
||
|
if (!ui) {
|
||
|
let monitorArea = global.display.list_all_windows();
|
||
|
if (monitorArea.length > 0) {
|
||
|
ui = [];
|
||
|
for (var i = 0; i < monitorArea.length; i++) {
|
||
|
if (!this._isWindowBlacklist(monitorArea[i])) {
|
||
|
let aui = monitorArea[i].get_compositor_private();
|
||
|
|
||
|
if (aui) {
|
||
|
ui.push(aui);
|
||
|
let mrect = monitorArea[i]
|
||
|
.get_work_area_current_monitor();
|
||
|
let wrect = monitorArea[i].get_frame_rect();
|
||
|
|
||
|
// black magic calc ;)
|
||
|
let wl = (mrect.width / 32);
|
||
|
aui._t_targetx = (mrect.width - wl) - wrect.x;
|
||
|
var nx = (0 - (wrect.width - wl)) - wrect.x;
|
||
|
aui.set_pivot_point(1.0, 0.5);
|
||
|
if (Math.abs(nx) < Math.abs(aui._t_targetx)) {
|
||
|
aui._t_targetx = nx;
|
||
|
aui.set_pivot_point(1, (i % 5) * 0.25);
|
||
|
}
|
||
|
else {
|
||
|
aui.set_pivot_point(0, (i % 5) * 0.25);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
this._actionWidgets.show_desktop = ui;
|
||
|
}
|
||
|
else {
|
||
|
this._actionWidgets.show_desktop = ui = -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Execute Progress
|
||
|
if (ui && ui != -1) {
|
||
|
if (!state) {
|
||
|
ui.forEach((aui) => {
|
||
|
aui.opacity = 255 - Math.round(180 * progress);
|
||
|
aui.scale_y =
|
||
|
aui.scale_x = 1.0 - (progress * 0.6);
|
||
|
aui.translation_x = (
|
||
|
(progress * progress) * aui._t_targetx
|
||
|
);
|
||
|
});
|
||
|
}
|
||
|
else {
|
||
|
// Action is executed
|
||
|
if (progress >= 1.0) {
|
||
|
// Show Desktop (Super+D) Clutter.KEY_D
|
||
|
this._sendKeyPress(
|
||
|
[Clutter.KEY_Super_L,
|
||
|
Clutter.KEY_D + _LCASE]
|
||
|
);
|
||
|
}
|
||
|
|
||
|
ui.forEach((aui) => {
|
||
|
aui.ease({
|
||
|
duration: Math.round(250 * progress),
|
||
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||
|
opacity: 255,
|
||
|
translation_x: 0,
|
||
|
scale_x: 1,
|
||
|
scale_y: 1,
|
||
|
onStopped: () => {
|
||
|
aui.set_pivot_point(0, 0);
|
||
|
delete aui._t_targetx;
|
||
|
delete aui._t_targety;
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
|
||
|
this._actionWidgets.show_desktop = ui = null;
|
||
|
}
|
||
|
} else if (state) {
|
||
|
this._actionWidgets.show_desktop = ui = null;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else if ((id == 4) || (id == 5)) {
|
||
|
//
|
||
|
// NEXT & PREVIOUS WINDOW SWITCHING
|
||
|
//
|
||
|
if (this._isOnOverview()) {
|
||
|
return; // Ignore on overview
|
||
|
}
|
||
|
|
||
|
let prv = (id == 5);
|
||
|
let wid = prv ? "switchwin_prev" : "switchwin_next";
|
||
|
let ui = this._actionWidgets[wid];
|
||
|
|
||
|
// Init indicator
|
||
|
if (!ui) {
|
||
|
ui = -1;
|
||
|
let wins = null;
|
||
|
let listActor = null;
|
||
|
|
||
|
// Cancel cache win timeout
|
||
|
if (this._actionWidgets.resetWinlist) {
|
||
|
clearTimeout(this._actionWidgets.resetWinlist);
|
||
|
this._actionWidgets.resetWinlist = 0;
|
||
|
}
|
||
|
// Get cached window list
|
||
|
if (this._actionWidgets.cacheWinTabList) {
|
||
|
wins = this._actionWidgets.cacheWinTabList?.wins;
|
||
|
listActor = this._actionWidgets.cacheWinTabList?.actor;
|
||
|
}
|
||
|
if (!wins) {
|
||
|
// No last cached
|
||
|
wins = this._getWindowTabList();
|
||
|
if (wins.length > 1) {
|
||
|
// Create UI
|
||
|
let gsize = Main.layoutManager.uiGroup.get_size();
|
||
|
let pad = 8;
|
||
|
let posCfg = this._settings.get_int(
|
||
|
'winswitch-position'
|
||
|
);
|
||
|
let lW = (pad * 2) + (wins.length * 48);
|
||
|
let lH = (pad * 2) + 32;
|
||
|
let lX = (gsize[0] - lW) / 2;
|
||
|
let lY = 64; // Top
|
||
|
let pivY = 0;
|
||
|
if (posCfg == 1) {
|
||
|
// Center
|
||
|
lY = (gsize[1] - lH) / 2;
|
||
|
pivY = 0.5;
|
||
|
}
|
||
|
else if (posCfg == 2) {
|
||
|
// Bottom
|
||
|
lY = gsize[1] - (lH + 64);
|
||
|
pivY = 1;
|
||
|
}
|
||
|
listActor = this._createUi(
|
||
|
"wgs-winswitch", lX, lY, lW, lH
|
||
|
);
|
||
|
listActor.set_pivot_point(0.5, pivY);
|
||
|
listActor.opacity = 0;
|
||
|
listActor.scale_x = 0.5;
|
||
|
listActor.scale_y = 0.5;
|
||
|
listActor._data = [];
|
||
|
for (var i = 0; i < wins.length; i++) {
|
||
|
let win = wins[i];
|
||
|
let app = this._winmanWinApp(win);
|
||
|
let ico = app.create_icon_texture(32);
|
||
|
ico.add_style_class_name("wgs-winswitch-ico");
|
||
|
// remove_style_class_name
|
||
|
listActor.add_child(ico);
|
||
|
ico.set_size(32, 32);
|
||
|
ico.set_position((pad * 2) + (48 * i), pad);
|
||
|
ico.set_pivot_point(0.5, 0.5);
|
||
|
listActor._data.push(
|
||
|
{
|
||
|
app: app,
|
||
|
win: win,
|
||
|
ico: ico
|
||
|
}
|
||
|
)
|
||
|
}
|
||
|
listActor.viewShow({
|
||
|
opacity: 255,
|
||
|
scale_x: 1,
|
||
|
scale_y: 1
|
||
|
}, 200);
|
||
|
|
||
|
// Reorder for next (below 1s) calls
|
||
|
this._actionWidgets.cacheWinTabList = {
|
||
|
sel: 0,
|
||
|
first: wins[0],
|
||
|
wins: wins,
|
||
|
actor: listActor
|
||
|
};
|
||
|
}
|
||
|
else {
|
||
|
this._actionWidgets.cacheWinTabList = null;
|
||
|
}
|
||
|
}
|
||
|
if (wins.length > 1) {
|
||
|
ui = { from: wins[0] };
|
||
|
if (prv) {
|
||
|
ui.into = wins[wins.length - 1];
|
||
|
ui.nsel = -1;
|
||
|
}
|
||
|
else {
|
||
|
ui.into = wins[1];
|
||
|
ui.nsel = 1;
|
||
|
}
|
||
|
ui.lstate = 0;
|
||
|
ui.from_actor = ui.from.get_compositor_private();
|
||
|
ui.into_actor = ui.into.get_compositor_private();
|
||
|
ui.from_actor.set_pivot_point(0.5, 1);
|
||
|
ui.into_actor.set_pivot_point(0.5, 1);
|
||
|
|
||
|
// Set selected target
|
||
|
for (var i = 0; i < listActor._data.length; i++) {
|
||
|
let d = listActor._data[i];
|
||
|
if (d.win == ui.from) {
|
||
|
d.ico.add_style_class_name("selected");
|
||
|
ui.from_ico = d.ico;
|
||
|
}
|
||
|
else if (d.win == ui.into) {
|
||
|
d.ico.remove_style_class_name("selected");
|
||
|
ui.into_ico = d.ico;
|
||
|
}
|
||
|
else {
|
||
|
d.ico.remove_style_class_name("selected");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
this._actionWidgets[wid] = ui;
|
||
|
}
|
||
|
if (ui && ui != -1) {
|
||
|
if (!state) {
|
||
|
try {
|
||
|
ui.from_actor.opacity = 255 - Math.round(80 * progress);
|
||
|
ui.from_actor.scale_y =
|
||
|
ui.from_actor.scale_x = 1.0 - (0.05 * progress);
|
||
|
ui.into_actor.scale_y =
|
||
|
ui.into_actor.scale_x = 1.0 + (0.05 * progress);
|
||
|
} catch (e) { }
|
||
|
if (progress > 0.8) {
|
||
|
if (!ui.lstate) {
|
||
|
try {
|
||
|
ui.into.raise();
|
||
|
} catch (e) { }
|
||
|
ui.lstate = 1;
|
||
|
ui.from_ico?.remove_style_class_name("selected");
|
||
|
ui.into_ico?.add_style_class_name("selected");
|
||
|
}
|
||
|
}
|
||
|
else if (ui.lstate) {
|
||
|
try {
|
||
|
ui.from.raise();
|
||
|
} catch (e) { }
|
||
|
ui.lstate = 0;
|
||
|
ui.from_ico?.add_style_class_name("selected");
|
||
|
ui.into_ico?.remove_style_class_name("selected");
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if ((progress > 0.8) || ui.lstate) {
|
||
|
try {
|
||
|
try {
|
||
|
this._actionWidgets
|
||
|
.cacheWinTabList.first.activate(
|
||
|
Meta.CURRENT_TIME
|
||
|
);
|
||
|
} catch (e) { }
|
||
|
try {
|
||
|
ui.from.raise();
|
||
|
} catch (e) { }
|
||
|
ui.into.activate(
|
||
|
Meta.CURRENT_TIME
|
||
|
);
|
||
|
} catch (e) { }
|
||
|
if (prv) {
|
||
|
this._actionWidgets.cacheWinTabList.wins.unshift(
|
||
|
this._actionWidgets.cacheWinTabList.wins.pop()
|
||
|
);
|
||
|
}
|
||
|
else {
|
||
|
this._actionWidgets.cacheWinTabList.wins.push(
|
||
|
this._actionWidgets.cacheWinTabList.wins.shift()
|
||
|
);
|
||
|
}
|
||
|
ui.from_ico?.remove_style_class_name("selected");
|
||
|
ui.into_ico?.add_style_class_name("selected");
|
||
|
}
|
||
|
else {
|
||
|
ui.from_ico?.add_style_class_name("selected");
|
||
|
ui.into_ico?.remove_style_class_name("selected");
|
||
|
}
|
||
|
ui.nclose = 0;
|
||
|
// Ease Restore
|
||
|
try {
|
||
|
ui.from_actor.ease({
|
||
|
duration: Math.round(200 * progress),
|
||
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||
|
opacity: 255,
|
||
|
scale_x: 1,
|
||
|
scale_y: 1,
|
||
|
onStopped: () => {
|
||
|
ui.from_actor.set_pivot_point(0, 0);
|
||
|
ui.from_actor = null;
|
||
|
ui.from = null;
|
||
|
if (++ui.nclose == 2) {
|
||
|
ui = null;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
} catch (e) { }
|
||
|
try {
|
||
|
ui.into_actor.ease({
|
||
|
duration: Math.round(200 * progress),
|
||
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||
|
opacity: 255,
|
||
|
scale_x: 1,
|
||
|
scale_y: 1,
|
||
|
onStopped: () => {
|
||
|
ui.into_actor.set_pivot_point(0, 0);
|
||
|
ui.into_actor = null;
|
||
|
ui.into = null;
|
||
|
if (++ui.nclose == 2) {
|
||
|
ui = null;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
} catch (e) { }
|
||
|
this._actionWidgets[wid] = null;
|
||
|
|
||
|
// Clear cache after timeout
|
||
|
let me = this;
|
||
|
this._actionWidgets.resetWinlist = setTimeout(
|
||
|
function () {
|
||
|
me._actionWidgets
|
||
|
.cacheWinTabList.actor.aniRelease();
|
||
|
me._actionWidgets.cacheWinTabList = null;
|
||
|
clearTimeout(me._actionWidgets.resetWinlist);
|
||
|
me._actionWidgets.resetWinlist = 0;
|
||
|
}, 500
|
||
|
);
|
||
|
}
|
||
|
} else if (state) {
|
||
|
this._actionWidgets[wid] = ui = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
else if ((id == 6) || (id == 7)) {
|
||
|
//
|
||
|
// SEND WINDOW LEFT/RIGHT WORKSPACE
|
||
|
//
|
||
|
if (this._isOnOverview()) {
|
||
|
return; // Ignore on overview
|
||
|
}
|
||
|
|
||
|
let prv = (id == 6);
|
||
|
let wid = prv ? "movewin_left" : "movewin_right";
|
||
|
let ui = this._actionWidgets[wid];
|
||
|
let activeWin = null;
|
||
|
|
||
|
// Init indicator
|
||
|
if (!ui) {
|
||
|
ui = -1;
|
||
|
let isDynamic = this._isDynamicWorkspace();
|
||
|
activeWin = global.display.get_focus_window();
|
||
|
let inserted = 0;
|
||
|
if (activeWin) {
|
||
|
let wsid = activeWin.get_workspace().index();
|
||
|
let tsid = wsid;
|
||
|
if (prv) {
|
||
|
if (isDynamic) {
|
||
|
if (wsid == 0) {
|
||
|
let wpl = activeWin.get_workspace().list_windows();
|
||
|
inserted = wpl.length;
|
||
|
if (inserted > 1) {
|
||
|
// Check for blacklisted windows
|
||
|
for (var i = 0; i < inserted; i++) {
|
||
|
if (this._isWindowBlacklist(wpl[i])) {
|
||
|
inserted--;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
wsid = tsid = 1;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (wsid == 0) {
|
||
|
inserted = 1;
|
||
|
}
|
||
|
}
|
||
|
tsid--;
|
||
|
}
|
||
|
else {
|
||
|
if (!isDynamic && (wsid >=
|
||
|
global.workspace_manager.get_n_workspaces() - 1)) {
|
||
|
inserted = 1;
|
||
|
}
|
||
|
tsid++;
|
||
|
}
|
||
|
// Make sure move left from left-most workspace only
|
||
|
// triggered if other window is available in
|
||
|
// current workspace
|
||
|
if (inserted !== 1) {
|
||
|
activeWin.stick();
|
||
|
if (inserted) {
|
||
|
this._insertWorkspace(0);
|
||
|
}
|
||
|
ui = {
|
||
|
confirmSwipe: () => { },
|
||
|
wm: Main.wm._workspaceAnimation,
|
||
|
win: activeWin,
|
||
|
wid: tsid,
|
||
|
sid: wsid,
|
||
|
ins: inserted
|
||
|
};
|
||
|
ui.wm._switchWorkspaceBegin(
|
||
|
ui,
|
||
|
global.display.get_primary_monitor()
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
this._actionWidgets[wid] = ui;
|
||
|
}
|
||
|
if (ui && ui != -1) {
|
||
|
if (!state) {
|
||
|
ui.wm._switchWorkspaceUpdate(
|
||
|
ui,
|
||
|
ui.sid + ((prv) ? 0 - progress : progress)
|
||
|
)
|
||
|
}
|
||
|
else {
|
||
|
ui.win.unstick();
|
||
|
ui.wm._switchWorkspaceEnd(
|
||
|
ui, 350,
|
||
|
ui.sid + ((prv) ? 0 - progress : progress)
|
||
|
);
|
||
|
if (progress > 0.5) {
|
||
|
ui.win.change_workspace_by_index(
|
||
|
ui.wid, true
|
||
|
);
|
||
|
global.workspace_manager.get_workspace_by_index(ui.wid)
|
||
|
.activate(
|
||
|
Meta.CURRENT_TIME
|
||
|
);
|
||
|
}
|
||
|
else if (ui.ins) {
|
||
|
// list_windows
|
||
|
if (ui.ins > 1) {
|
||
|
ui.win.change_workspace_by_index(
|
||
|
ui.sid, true
|
||
|
);
|
||
|
}
|
||
|
else {
|
||
|
ui.win.change_workspace_by_index(
|
||
|
ui.wid, true
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
ui.win.activate(Meta.CURRENT_TIME);
|
||
|
this._actionWidgets[wid] = ui = null;
|
||
|
}
|
||
|
} else if (state) {
|
||
|
this._actionWidgets[wid] = ui = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
else if (id >= 8 && id <= 9) {
|
||
|
//
|
||
|
// BACK / FORWARD
|
||
|
//
|
||
|
if (this._isOnOverview()) {
|
||
|
return; // Ignore on overview
|
||
|
}
|
||
|
|
||
|
const keyList = [
|
||
|
Clutter.KEY_Back,
|
||
|
Clutter.KEY_Forward
|
||
|
];
|
||
|
let kid = id - 8;
|
||
|
let activeWin = null;
|
||
|
let kidw = kid ? 'btnforward' : 'btnback';
|
||
|
let ui = this._actionWidgets[kidw];
|
||
|
|
||
|
// Init indicator
|
||
|
if (!ui) {
|
||
|
activeWin = global.display.get_focus_window();
|
||
|
if (this._isWindowBlacklist(activeWin)) {
|
||
|
activeWin = null;
|
||
|
}
|
||
|
if (activeWin) {
|
||
|
let uipar = activeWin.get_compositor_private();
|
||
|
if (uipar) {
|
||
|
let wrect = activeWin.get_frame_rect();
|
||
|
let uix = ((uipar.get_width() - wrect.width) / 2);
|
||
|
let uiy = (uipar.get_height() / 2) - 32;
|
||
|
if (kid) {
|
||
|
uix += wrect.width - 128;
|
||
|
}
|
||
|
else {
|
||
|
uix += 64;
|
||
|
}
|
||
|
ui = this._createUi(
|
||
|
'wgs-indicator-backforward',
|
||
|
uix,
|
||
|
uiy,
|
||
|
64, 64,
|
||
|
kid ? 'pan-end-symbolic.symbolic' :
|
||
|
'pan-start-symbolic.symbolic',
|
||
|
uipar
|
||
|
);
|
||
|
if (ui) {
|
||
|
ui.translation_x = kid ? -32 : 32;
|
||
|
ui.opacity = 0;
|
||
|
}
|
||
|
else {
|
||
|
ui = -1;
|
||
|
}
|
||
|
this._actionWidgets[kidw] = ui;
|
||
|
}
|
||
|
else {
|
||
|
this._actionWidgets[kidw] = -1;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
this._actionWidgets[kidw] = -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Execute Progress
|
||
|
if (ui && ui != -1) {
|
||
|
if (!state) {
|
||
|
if (kid) {
|
||
|
ui.translation_x = 32 - (32 * progress);
|
||
|
}
|
||
|
else {
|
||
|
ui.translation_x = (32 * progress) - 32;
|
||
|
}
|
||
|
ui.opacity = Math.round(255 * progress);
|
||
|
}
|
||
|
else {
|
||
|
// Action is executed
|
||
|
if (progress >= 1.0) {
|
||
|
this._sendKeyPress([keyList[kid]]);
|
||
|
}
|
||
|
ui.release();
|
||
|
this._actionWidgets[kidw] = ui = null;
|
||
|
}
|
||
|
} else if (state) {
|
||
|
this._actionWidgets[kidw] = ui = null;
|
||
|
}
|
||
|
}
|
||
|
else if (id >= 10 && id <= 17) {
|
||
|
//
|
||
|
// MEDIA & BRIGHTNESS
|
||
|
//
|
||
|
const keyList = [
|
||
|
Clutter.KEY_MonBrightnessUp,
|
||
|
Clutter.KEY_MonBrightnessDown,
|
||
|
Clutter.KEY_AudioRaiseVolume,
|
||
|
Clutter.KEY_AudioLowerVolume,
|
||
|
Clutter.KEY_AudioMute,
|
||
|
Clutter.KEY_AudioPlay,
|
||
|
Clutter.KEY_AudioNext,
|
||
|
Clutter.KEY_AudioPrev
|
||
|
];
|
||
|
let wid = 'keys_' + id;
|
||
|
let cid = 'keysn_' + id;
|
||
|
let keyId = keyList[id - 10];
|
||
|
let isRepeat = (id < 14);
|
||
|
let kidw = 'keyaction_' + id;
|
||
|
let ui = this._actionWidgets[kidw];
|
||
|
|
||
|
if (isRepeat) {
|
||
|
if (!state && (progress >= 1)) {
|
||
|
if (!this._keyRepeatInterval) {
|
||
|
this._actionWidgets[cid] = 0;
|
||
|
this._sendKeyPress([keyId]);
|
||
|
this._keyRepeatInterval = setInterval(
|
||
|
function (me, cid, keyId) {
|
||
|
if (me._actionWidgets[cid] >= 5) {
|
||
|
me._sendKeyPress([keyId]);
|
||
|
}
|
||
|
else {
|
||
|
me._actionWidgets[cid]++;
|
||
|
}
|
||
|
},
|
||
|
100,
|
||
|
this, cid, keyId
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
if (state) {
|
||
|
if (this._keyRepeatInterval) {
|
||
|
clearInterval(this._keyRepeatInterval);
|
||
|
}
|
||
|
this._keyRepeatInterval = 0;
|
||
|
this._actionWidgets[cid] = 0;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (!ui) {
|
||
|
const iconlist = [
|
||
|
'audio-volume-muted-symbolic',
|
||
|
'media-playback-start-symbolic',
|
||
|
'media-skip-forward-symbolic',
|
||
|
'media-skip-backward-symbolic'
|
||
|
];
|
||
|
let display = global.get_display();
|
||
|
let mrect = display.get_monitor_geometry(
|
||
|
display.get_primary_monitor()
|
||
|
);
|
||
|
ui = this._createUi(
|
||
|
'wgs-indicator-keys',
|
||
|
mrect.x + (mrect.width / 2) - 64,
|
||
|
mrect.y + (mrect.height / 2) - 64,
|
||
|
128, 128,
|
||
|
iconlist[id - 14],
|
||
|
null
|
||
|
);
|
||
|
ui.opacity = 0;
|
||
|
ui.scale_x = ui.scale_y = 0;
|
||
|
this._actionWidgets[kidw] = ui;
|
||
|
}
|
||
|
|
||
|
// Execute Progress
|
||
|
if (ui && ui != -1) {
|
||
|
if (!state) {
|
||
|
ui.scale_x = ui.scale_y = progress;
|
||
|
ui.opacity = Math.round(255 * progress);
|
||
|
}
|
||
|
else {
|
||
|
// Action is executed
|
||
|
if (progress >= 1.0) {
|
||
|
this._sendKeyPress([keyId]);
|
||
|
}
|
||
|
ui.aniRelease(progress);
|
||
|
this._actionWidgets[kidw] = ui = null;
|
||
|
}
|
||
|
}
|
||
|
else if (state) {
|
||
|
this._actionWidgets[kidw] = ui = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Non animated actions
|
||
|
//
|
||
|
else if (id == 18) {
|
||
|
if (this._isOnOverview()) {
|
||
|
// Ignore on overview
|
||
|
return;
|
||
|
}
|
||
|
if (!state || progress < 1.0) {
|
||
|
// Ignore if non end
|
||
|
return;
|
||
|
}
|
||
|
// ALT+TAB
|
||
|
this._sendKeyPress([Clutter.KEY_Alt_L, Clutter.KEY_Tab]);
|
||
|
}
|
||
|
else if (id == 19 || id == 20) {
|
||
|
if (!state || progress < 1.0) {
|
||
|
// Ignore if non end
|
||
|
return;
|
||
|
}
|
||
|
if (id == 19) {
|
||
|
Main.overview.show();
|
||
|
}
|
||
|
else {
|
||
|
Main.overview.showApps();
|
||
|
}
|
||
|
}
|
||
|
else if (id == 21) {
|
||
|
if (!state || progress < 1.0) {
|
||
|
// Ignore if non end
|
||
|
return;
|
||
|
}
|
||
|
// Quick Settings (Super+S)
|
||
|
Main.wm._toggleQuickSettings();
|
||
|
// this._sendKeyPress([Clutter.KEY_Super_L, Clutter.KEY_S + _LCASE]);
|
||
|
}
|
||
|
else if (id == 22) {
|
||
|
if (!state || progress < 1.0) {
|
||
|
// Ignore if non end
|
||
|
return;
|
||
|
}
|
||
|
// Notification (Super+V)
|
||
|
Main.wm._toggleCalendar();
|
||
|
// this._sendKeyPress([Clutter.KEY_Super_L, Clutter.KEY_V + _LCASE]);
|
||
|
}
|
||
|
else if (id == 23) {
|
||
|
if (!state || progress < 1.0) {
|
||
|
// Ignore if non end
|
||
|
return;
|
||
|
}
|
||
|
// Run (Alt+F2)
|
||
|
this._sendKeyPress([Clutter.KEY_Alt_L, Clutter.KEY_F2]);
|
||
|
}
|
||
|
|
||
|
else if (id >= 50 && id <= 53) {
|
||
|
//
|
||
|
// Maximized, Fullscreen, Spap Etc.
|
||
|
//
|
||
|
let activeWin = global.display.get_focus_window();
|
||
|
if (!activeWin || this._isOnOverview()) {
|
||
|
return; // Ignore on overview & no active window
|
||
|
}
|
||
|
if (this._isWindowBlacklist(activeWin)) {
|
||
|
return; // Ignore blacklisted
|
||
|
}
|
||
|
|
||
|
let winCanMax = activeWin.allows_move() && activeWin.can_maximize();
|
||
|
let winIsMaximized = activeWin.get_maximized();
|
||
|
let winMaxed = Meta.MaximizeFlags.BOTH == winIsMaximized;
|
||
|
if (activeWin.isTiled) {
|
||
|
winIsMaximized = Meta.MaximizeFlags.VERTICAL;
|
||
|
}
|
||
|
let winIsFullscreen = activeWin.is_fullscreen();
|
||
|
let allowFullscreen = this._getEnableFullscreen();
|
||
|
let ui = 0; // find action id
|
||
|
if (id < 53) {
|
||
|
// Maximize
|
||
|
if (winMaxed) {
|
||
|
if (winIsFullscreen) {
|
||
|
ui = 5; // un-fullscreen
|
||
|
}
|
||
|
else if (allowFullscreen) {
|
||
|
ui = 4; // fullscreen
|
||
|
}
|
||
|
else {
|
||
|
ui = 6; // if not allow fullscreen (restore)
|
||
|
}
|
||
|
}
|
||
|
else if (winCanMax) {
|
||
|
// 1. Max, 2. Snap Left, 3. Snap Right
|
||
|
ui = id - 49;
|
||
|
}
|
||
|
}
|
||
|
else if (winIsFullscreen) {
|
||
|
ui = 5; // un-fullscreen
|
||
|
}
|
||
|
else if (winIsMaximized) {
|
||
|
ui = 6; // restore
|
||
|
}
|
||
|
let wid = "wmax_state" + ui;
|
||
|
|
||
|
if (ui) {
|
||
|
if (!state) {
|
||
|
if (ui == 4) {
|
||
|
// fullsccreen
|
||
|
activeWin?.get_compositor_private()
|
||
|
.set_pivot_point(0.5, 1);
|
||
|
activeWin.get_compositor_private().scale_y =
|
||
|
1.0 + (progress * 0.025);
|
||
|
}
|
||
|
else if (ui >= 5) {
|
||
|
// un-fullsccreen / restore
|
||
|
activeWin?.get_compositor_private()
|
||
|
.set_pivot_point(0.5, 1);
|
||
|
if (ui == 6) {
|
||
|
activeWin.get_compositor_private().scale_y =
|
||
|
activeWin.get_compositor_private().scale_x =
|
||
|
1.0 - (progress * 0.04);
|
||
|
}
|
||
|
else {
|
||
|
activeWin.get_compositor_private().scale_y =
|
||
|
1.0 - (progress * 0.025);
|
||
|
}
|
||
|
}
|
||
|
else if (ui <= 3) {
|
||
|
if (!this._actionWidgets[wid]) {
|
||
|
if (this._actionWidgets.tilerHider) {
|
||
|
clearTimeout(this._actionWidgets.tilerHider);
|
||
|
this._actionWidgets.tilerHider = null;
|
||
|
}
|
||
|
let moarea = activeWin
|
||
|
.get_work_area_current_monitor();
|
||
|
if (ui == 1) {
|
||
|
// max
|
||
|
this._showPreview(
|
||
|
moarea.x,
|
||
|
moarea.y,
|
||
|
moarea.width,
|
||
|
moarea.height
|
||
|
);
|
||
|
}
|
||
|
else if (ui == 2) {
|
||
|
// snap left
|
||
|
this._showPreview(
|
||
|
moarea.x,
|
||
|
moarea.y,
|
||
|
moarea.width / 2,
|
||
|
moarea.height
|
||
|
);
|
||
|
}
|
||
|
else if (ui == 3) {
|
||
|
// snap right
|
||
|
this._showPreview(
|
||
|
moarea.x
|
||
|
+ (moarea.width / 2),
|
||
|
moarea.y,
|
||
|
moarea.width / 2,
|
||
|
moarea.height
|
||
|
);
|
||
|
}
|
||
|
this._actionWidgets[wid] = 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (ui <= 3) {
|
||
|
// max, snap
|
||
|
if (this._actionWidgets.tilerHider) {
|
||
|
clearTimeout(this._actionWidgets.tilerHider);
|
||
|
this._actionWidgets.tilerHider = null;
|
||
|
}
|
||
|
if (this._actionWidgets[wid] && (progress > 0)) {
|
||
|
if (ui == 1) {
|
||
|
activeWin.maximize(Meta.MaximizeFlags.BOTH);
|
||
|
}
|
||
|
else if (ui == 2) {
|
||
|
this._setSnapWindow(0);
|
||
|
}
|
||
|
else if (ui == 3) {
|
||
|
this._setSnapWindow(1);
|
||
|
}
|
||
|
}
|
||
|
this._actionWidgets.tilerHider = setTimeout(
|
||
|
function (me) {
|
||
|
me._hidePreview();
|
||
|
me._actionWidgets.tilerHider = null;
|
||
|
}, 100, this);
|
||
|
this._actionWidgets[wid] = 0;
|
||
|
}
|
||
|
else {
|
||
|
// resize back
|
||
|
activeWin?.get_compositor_private().ease({
|
||
|
duration: Math.round(200 * progress),
|
||
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||
|
scale_y: 1,
|
||
|
scale_x: 1,
|
||
|
onStopped: () => {
|
||
|
activeWin?.get_compositor_private()
|
||
|
.set_pivot_point(0, 0);
|
||
|
}
|
||
|
});
|
||
|
if (progress >= 0.5) {
|
||
|
if (ui == 4) {
|
||
|
// fullscreen
|
||
|
activeWin.make_fullscreen();
|
||
|
}
|
||
|
else if (ui == 5) {
|
||
|
// un-fullscreen
|
||
|
activeWin.unmake_fullscreen();
|
||
|
}
|
||
|
else if (ui == 6) {
|
||
|
// restore
|
||
|
activeWin.unmaximize(
|
||
|
Meta.MaximizeFlags.BOTH
|
||
|
);
|
||
|
if (activeWin.isTiled) {
|
||
|
this._sendKeyPress([
|
||
|
Clutter.KEY_Super_L, Clutter.KEY_Down
|
||
|
]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// End Of Actions
|
||
|
//
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Export Extension
|
||
|
export default class WindowGesturesExtension extends Extension {
|
||
|
// Enable Extension
|
||
|
enable() {
|
||
|
this.manager = new Manager(this);
|
||
|
}
|
||
|
|
||
|
// Disable Extension
|
||
|
disable() {
|
||
|
this.manager.destroy();
|
||
|
this.manager = null;
|
||
|
}
|
||
|
}
|