linux-presets/gui/gnome/autocustom-gnome-macos/res/extensions/compiz-alike-magic-lamp-eff.../extension.js

482 lines
19 KiB
JavaScript
Executable File

/*
* Compiz-alike-magic-lamp-effect for GNOME Shell
*
* Copyright (C) 2020
* Mauro Pepe <https://github.com/hermes83/compiz-alike-magic-lamp-effect>
*
* This file is part of the gnome-shell extension Compiz-alike-magic-lamp-effect.
*
* gnome-shell extension Compiz-alike-magic-lamp-effect 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 3 of the License, or (at your option)
* any later version.
*
* gnome-shell extension Compiz-alike-magic-lamp-effect 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 gnome-shell extension Compiz-alike-magic-lamp-effect. If not, see
* <http://www.gnu.org/licenses/>.
*/
'use strict';
import GObject from 'gi://GObject';
import Clutter from 'gi://Clutter';
import St from 'gi://St';
import { Extension } from 'resource:///org/gnome/shell/extensions/extension.js';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import { SettingsData } from './settings_data.js';
const MINIMIZE_EFFECT_NAME = 'minimize-magic-lamp-effect';
const UNMINIMIZE_EFFECT_NAME = 'unminimize-magic-lamp-effect';
export default class CompizMagicLampEffectExtension extends Extension {
enable() {
this.settingsData = new SettingsData(this.getSettings());
// https://github.com/GNOME/gnome-shell/blob/master/js/ui/windowManager.js
Main.wm.original_minimizeMaximizeWindow_shouldAnimateActor = Main.wm._shouldAnimateActor;
Main.wm._shouldAnimateActor = function(actor, types) {
let stack = new Error().stack;
if (stack && (stack.indexOf("_minimizeWindow") !== -1 || stack.indexOf("_unminimizeWindow") !== -1)) {
return false;
}
return Main.wm.original_minimizeMaximizeWindow_shouldAnimateActor(actor, types);
};
Main.wm._shellwm.original_completed_minimize = Main.wm._shellwm.completed_minimize;
Main.wm._shellwm.completed_minimize = function(actor) {
return;
};
Main.wm._shellwm.original_completed_unminimize = Main.wm._shellwm.completed_unminimize;
Main.wm._shellwm.completed_unminimize = function(actor) {
return;
};
this.minimizeId = global.window_manager.connect("minimize", (e, actor) => {
if (Main.overview.visible) {
Main.wm._shellwm.original_completed_minimize(actor);
return;
}
let icon = this.getIcon(actor);
this.destroyActorEffect(actor);
actor.add_effect_with_name(MINIMIZE_EFFECT_NAME, new MagicLampMinimizeEffect({settingsData: this.settingsData, icon: icon}));
});
this.unminimizeId = global.window_manager.connect("unminimize", (e, actor) => {
actor.show();
if (Main.overview.visible) {
Main.wm._shellwm.original_completed_unminimize(actor);
return;
}
let icon = this.getIcon(actor);
this.destroyActorEffect(actor);
actor.add_effect_with_name(UNMINIMIZE_EFFECT_NAME, new MagicLampUnminimizeEffect({settingsData: this.settingsData, icon: icon}));
});
}
disable() {
if (this.settingsData) {
this.settingsData = null;
}
if (this.minimizeId) {
global.window_manager.disconnect(this.minimizeId);
}
if (this.minimizeId) {
global.window_manager.disconnect(this.unminimizeId);
}
global.get_window_actors().forEach((actor) => {
this.destroyActorEffect(actor);
});
if (Main.wm.original_minimizeMaximizeWindow_shouldAnimateActor) {
Main.wm._shouldAnimateActor = Main.wm.original_minimizeMaximizeWindow_shouldAnimateActor;
Main.wm.original_minimizeMaximizeWindow_shouldAnimateActor = null;
}
if (Main.wm._shellwm.original_completed_minimize) {
Main.wm._shellwm.completed_minimize = Main.wm._shellwm.original_completed_minimize;
Main.wm._shellwm.original_completed_minimize = null;
}
if (Main.wm._shellwm.original_completed_unminimize) {
Main.wm._shellwm.completed_unminimize = Main.wm._shellwm.original_completed_unminimize;
Main.wm._shellwm.original_completed_unminimize = null;
}
}
getIcon(actor) {
let [success, icon] = actor.meta_window.get_icon_geometry();
if (success) {
return icon;
}
let monitor = Main.layoutManager.monitors[actor.meta_window.get_monitor()];
if (monitor && Main.overview.dash) {
Main.overview.dash._redisplay();
let dashIcon = null;
let transformed_position = null;
let pids = null;
let pid = actor.get_meta_window() ? actor.get_meta_window().get_pid() : null;
if (pid) {
Main.overview.dash._box.get_children()
.filter(dashElement => dashElement.child && dashElement.child._delegate && dashElement.child._delegate.app)
.forEach(dashElement => {
pids = dashElement.child._delegate.app.get_pids();
if (pids && pids.indexOf(pid) >= 0) {
transformed_position = dashElement.get_transformed_position();
if (transformed_position && transformed_position[0]) {
dashIcon = {x: transformed_position[0], y: monitor.y + monitor.height, width: 0, height: 0};
return;
}
}
});
}
if (dashIcon) {
return dashIcon;
}
return {x: monitor.x + monitor.width / 2, y: monitor.y + monitor.height, width: 0, height: 0};
}
return {x: 0, y: 0, width: 0, height: 0};
}
destroyActorEffect(actor) {
if (!actor) {
return;
}
let minimizeEffect = actor.get_effect(MINIMIZE_EFFECT_NAME);
if (minimizeEffect) {
minimizeEffect.destroy();
}
let unminimizeEffect = actor.get_effect(UNMINIMIZE_EFFECT_NAME);
if (unminimizeEffect) {
unminimizeEffect.destroy();
}
}
}
class AbstractCommonMagicLampEffect extends Clutter.DeformEffect {
static {
GObject.registerClass(this);
}
_init(params = {}) {
super._init();
this.settingsData = params.settingsData;
this.EPSILON = 40;
this.isMinimizeEffect = false;
this.newFrameEvent = null;
this.completedEvent = null;
this.timerId = null;
this.msecs = 0;
this.monitor = {x: 0, y: 0, width: 0, height: 0};
this.iconMonitor = {x: 0, y: 0, width: 0, height: 0};
this.window = {x: 0, y: 0, width: 0, height: 0, scale: 1};
this.icon = params.icon;
this.progress = 0;
this.split = 0.3;
this.k = 0;
this.j = 0;
this.expandWidth = 0;
this.fullWidth = 0;
this.expandHeight = 0;
this.fullHeight = 0;
this.width = 0;
this.height = 0;
this.x = 0;
this.y = 0;
this.offsetX = 0;
this.offsetY = 0;
this.effectX = 0;
this.effectY = 0;
this.iconPosition = null;
this.toTheBorder = true; // true
this.maxIconSize = null; // 48
this.alignIcon = 'center'; // 'left-top'
this.EFFECT = this.settingsData.EFFECT.get(); //'default' - 'sine'
this.DURATION = this.settingsData.DURATION.get();
this.X_TILES = this.settingsData.X_TILES.get();
this.Y_TILES = this.settingsData.Y_TILES.get();
this.initialized = false;
}
destroy_actor(actor) {}
on_tick_elapsed(timer, msecs) {}
vfunc_set_actor(actor) {
super.vfunc_set_actor(actor);
if (!this.actor || this.initialized) {
return;
}
this.initialized = true;
this.monitor = Main.layoutManager.monitors[actor.meta_window.get_monitor()];
[this.window.x, this.window.y] = [this.actor.get_x() - this.monitor.x, this.actor.get_y() - this.monitor.y];
[this.window.width, this.window.height] = actor.get_size();
if (!this.icon || (this.icon.x == 0 && this.icon.y == 0 && this.icon.width == 0 && this.icon.height == 0)) {
this.icon.x = this.monitor.x + this.monitor.width / 2;
this.icon.y = this.monitor.height + this.monitor.y;
}
Main.layoutManager.monitors.forEach((monitor, monitorIndex) => {
let scale = 1;
if (global.display && global.display.get_monitor_scale) {
scale = global.display.get_monitor_scale(monitorIndex);
}
if (this.icon.x >= monitor.x && this.icon.x <= monitor.x + monitor.width * scale && this.icon.y >= monitor.y && this.icon.y <= monitor.y + monitor.height * scale) {
this.iconMonitor = monitor;
}
});
if (this.iconMonitor.x == 0 && this.iconMonitor.y == 0 && this.iconMonitor.width == 0 && this.iconMonitor.height == 0) {
this.iconMonitor = this.monitor;
// this.icon.x = this.monitor.x + this.monitor.width / 2;
// this.icon.y = this.monitor.height + this.monitor.y;
}
[this.icon.x, this.icon.y, this.icon.width, this.icon.height] = [this.icon.x - this.monitor.x, this.icon.y - this.monitor.y, this.icon.width, this.icon.height];
if (this.icon.y + this.icon.height >= this.monitor.height - this.EPSILON) {
this.iconPosition = St.Side.BOTTOM;
if (this.toTheBorder) {
this.icon.y = this.iconMonitor.y + this.iconMonitor.height - this.monitor.y
this.icon.height = 0;
}
} else if (this.icon.x <= this.EPSILON) {
this.iconPosition = St.Side.LEFT;
if (this.toTheBorder) {
this.icon.x = this.iconMonitor.x - this.monitor.x;
this.icon.width = 0;
}
} else if (this.icon.x + this.icon.width >= this.monitor.width - this.EPSILON) {
this.iconPosition = St.Side.RIGHT;
if (this.toTheBorder) {
this.icon.x = this.iconMonitor.x + this.iconMonitor.width - this.monitor.x;
this.icon.width = 0;
}
} else {
this.iconPosition = St.Side.TOP;
if (this.toTheBorder) {
this.icon.y = this.iconMonitor.y - this.monitor.y;
this.icon.height = 0;
}
}
this.set_n_tiles(this.X_TILES, this.Y_TILES);
this.timerId = new Clutter.Timeline({ actor: this.actor, duration: this.DURATION + (this.monitor.width * this.monitor.height) / (this.window.width * this.window.height) });
this.newFrameEvent = this.timerId.connect('new-frame', this.on_tick_elapsed.bind(this));
this.completedEvent = this.timerId.connect('completed', this.destroy.bind(this));
this.timerId.start();
}
destroy() {
if (this.timerId) {
if (this.newFrameEvent) {
this.timerId.disconnect(this.newFrameEvent);
this.newFrameEvent = null;
}
if (this.completedEvent) {
this.timerId.disconnect(this.completedEvent);
this.completedEvent = null;
}
this.timerId = null;
}
let actor = this.get_actor();
if (actor) {
if (this.paintEvent) {
actor.disconnect(this.paintEvent);
this.paintEvent = null;
}
actor.remove_effect(this);
this.destroy_actor(actor);
}
}
vfunc_deform_vertex(w, h, v) {
if (this.initialized) {
let propX = w / this.window.width;
let propY = h / this.window.height;
if (this.iconPosition == St.Side.LEFT) {
this.width = this.window.width - this.icon.width + this.window.x * this.k;
this.x = (this.width - this.j * this.width) * v.tx;
this.y = v.ty * this.window.height * (this.x + (this.width - this.x) * (1 - this.k)) / this.width +
v.ty * this.icon.height * (this.width - this.x) / this.width;
this.offsetX = this.icon.width - this.window.x * this.k;
this.offsetY = (this.icon.y - this.window.y) * ((this.width - this.x) / this.width) * this.k;
if (this.EFFECT === 'sine') {
this.effectY = Math.sin(this.x / this.width * Math.PI * 4) * this.window.height / 14 * this.k;
} else {
this.effectY = Math.sin((0.5 - (this.width - this.x) / this.width) * 2 * Math.PI) * (this.window.y + this.window.height * v.ty - (this.icon.y + this.icon.height * v.ty)) / 7 * this.k;
}
} else if (this.iconPosition == St.Side.TOP) {
this.height = this.window.height - this.icon.height + this.window.y * this.k;
this.y = (this.height - this.j * this.height) * v.ty;
this.x = v.tx * this.window.width * (this.y + (this.height - this.y) * (1 - this.k)) / this.height +
v.tx * this.icon.width * (this.height - this.y) / this.height;
this.offsetX = (this.icon.x - this.window.x) * ((this.height - this.y) / this.height) * this.k;
this.offsetY = this.icon.height - this.window.y * this.k;
if (this.EFFECT === 'sine') {
this.effectX = Math.sin(this.y / this.height * Math.PI * 4) * this.window.width / 14 * this.k;
} else {
this.effectX = Math.sin((0.5 - (this.height - this.y) / this.height) * 2 * Math.PI) * (this.window.x + this.window.width * v.tx - (this.icon.x + this.icon.width * v.tx)) / 7 * this.k;
}
} else if (this.iconPosition == St.Side.RIGHT) {
this.expandWidth = (this.iconMonitor.width - this.icon.width - this.window.x - this.window.width);
this.fullWidth = (this.iconMonitor.width - this.icon.width - this.window.x) - this.expandWidth * (1 - this.k);
this.width = this.fullWidth - this.j * this.fullWidth;
this.x = v.tx * this.width;
this.y = v.ty * (this.icon.height) +
v.ty * (this.window.height - this.icon.height) * (1 - this.j) * (1 - v.tx) +
v.ty * (this.window.height - this.icon.height) * (1 - this.k) * (v.tx);
this.offsetY = (this.icon.y - this.window.y) * (this.x / this.fullWidth) * this.k + (this.icon.y - this.window.y) * this.j;
this.offsetX = this.iconMonitor.width - this.icon.width - this.window.x - this.width - this.expandWidth * (1 - this.k);
if (this.EFFECT === 'sine') {
this.effectY = Math.sin((this.width - this.x) / this.fullWidth * Math.PI * 4) * this.window.height / 14 * this.k;
} else {
this.effectY = Math.sin(((this.width - this.x) / this.fullWidth) * 2 * Math.PI + Math.PI) * (this.window.y + this.window.height * v.ty - (this.icon.y + this.icon.height * v.ty)) / 7 * this.k;
}
} else if (this.iconPosition == St.Side.BOTTOM) {
this.expandHeight = (this.iconMonitor.height - this.icon.height - this.window.y - this.window.height);
this.fullHeight = (this.iconMonitor.height - this.icon.height - this.window.y) - this.expandHeight * (1 - this.k);
this.height = this.fullHeight - this.j * this.fullHeight;
this.y = v.ty * this.height;
this.x = v.tx * (this.icon.width) +
v.tx * (this.window.width - this.icon.width) * (1 - this.j) * (1 - v.ty) +
v.tx * (this.window.width - this.icon.width) * (1 - this.k) * (v.ty);
this.offsetX = (this.icon.x - this.window.x) * (this.y / this.fullHeight) * this.k + (this.icon.x - this.window.x) * this.j;
this.offsetY = this.iconMonitor.height - this.icon.height - this.window.y - this.height - this.expandHeight * (1 - this.k);
if (this.EFFECT === 'sine') {
this.effectX = Math.sin((this.height - this.y) / this.fullHeight * Math.PI * 4) * this.window.width / 14 * this.k;
} else {
this.effectX = Math.sin(((this.height - this.y) / this.fullHeight) * 2 * Math.PI + Math.PI) * (this.window.x + this.window.width * v.tx - (this.icon.x + this.icon.width * v.tx)) / 7 * this.k;
}
}
v.x = (this.x + this.offsetX + this.effectX) * propX;
v.y = (this.y + this.offsetY + this.effectY) * propY;
}
}
}
class MagicLampMinimizeEffect extends AbstractCommonMagicLampEffect {
static {
GObject.registerClass(this);
}
_init(params = {}) {
super._init(params);
this.k = 0;
this.j = 0;
this.isMinimizeEffect = true;
}
destroy_actor(actor) {
Main.wm._shellwm.original_completed_minimize(actor);
}
on_tick_elapsed(timer, msecs) {
if (Main.overview.visible) {
this.destroy();
}
this.progress = timer.get_progress();
this.k = this.progress <= this.split ? this.progress * (1 / 1 / this.split) : 1;
this.j = this.progress > this.split ? (this.progress - this.split) * (1 / 1 / (1 - this.split)) : 0;
this.actor.get_parent().queue_redraw();
this.invalidate();
}
vfunc_modify_paint_volume(pv) {
return false;
}
}
class MagicLampUnminimizeEffect extends AbstractCommonMagicLampEffect {
static {
GObject.registerClass(this);
}
_init(params = {}) {
super._init(params);
this.k = 1;
this.j = 1;
this.isMinimizeEffect = false;
}
destroy_actor(actor) {
Main.wm._shellwm.original_completed_unminimize(actor);
}
on_tick_elapsed(timer, msecs) {
if (Main.overview.visible) {
this.destroy();
}
this.progress = timer.get_progress();
this.k = 1 - (this.progress > (1 - this.split) ? (this.progress - (1 - this.split)) * (1 / 1 / (1 - (1 - this.split))) : 0);
this.j = 1 - (this.progress <= (1 - this.split) ? this.progress * (1 / 1 / (1 - this.split)) : 1);
this.actor.get_parent().queue_redraw();
this.invalidate();
}
vfunc_modify_paint_volume(pv) {
return false;
}
}