2025-05-09 09:48:24 +02:00

202 lines
7.7 KiB
JavaScript

/*
* Compiz-windows-effect for GNOME Shell
*
* Copyright (C) 2020
* Mauro Pepe <https://github.com/hermes83/compiz-windows-effect>
*
* This file is part of the gnome-shell extension Compiz-windows-effect.
*
* gnome-shell extension Compiz-windows-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-windows-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-windows-effect. If not, see
* <http://www.gnu.org/licenses/>.
*/
'use strict';
import Meta from 'gi://Meta';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import { Extension } from 'resource:///org/gnome/shell/extensions/extension.js';
import { SettingsData } from './settings_data.js';
import { WobblyEffect } from './src/effects/wobbly.js';
import { ResizeEffect } from './src/effects/resize.js';
const EFFECT_NAME = 'wobbly-compiz-effect';
export default class CompizWindowsEffectExtension extends Extension {
enable() {
this.settingsData = new SettingsData(this.getSettings());
this.allowedResizeOp = [Meta.GrabOp.RESIZING_W, Meta.GrabOp.RESIZING_E, Meta.GrabOp.RESIZING_S, Meta.GrabOp.RESIZING_N, Meta.GrabOp.RESIZING_NW, Meta.GrabOp.RESIZING_NE, Meta.GrabOp.RESIZING_SE, Meta.GrabOp.RESIZING_SW];
this.grabOpBeginId = null;
this.grabOpEndId = null;
this.resizedActor = null;
this.startResizeOpId = null;
this.endResizeOpId = null;
this.destroyId = null;
this.grabOpBeginId = global.display.connect('grab-op-begin', (display, window, op) => {
if (Meta.GrabOp.MOVING != op &&
(!Meta.GrabOp.MOVING_UNCONSTRAINED || Meta.GrabOp.MOVING_UNCONSTRAINED != op) &&
(!this.settingsData.RESIZE_EFFECT.get() || this.allowedResizeOp.indexOf(op) === -1)) {
return;
}
let actor = window ? window.get_compositor_private() : null;
if (!actor) {
return;
}
this.destroyActorEffect(actor);
actor.remove_effect_by_name(EFFECT_NAME);
if (Meta.GrabOp.MOVING === op || Meta.GrabOp.MOVING_UNCONSTRAINED === op) {
actor.add_effect_with_name(EFFECT_NAME, new WobblyEffect({settingsData: this.settingsData, op: 'move'}));
} else {
actor.add_effect_with_name(EFFECT_NAME, new ResizeEffect({settingsData: this.settingsData, op: op}));
}
});
this.grabOpEndId = global.display.connect('grab-op-end', (display, window, op) => {
let actor = window ? window.get_compositor_private() : null;
if (!actor) {
return;
}
let effect = actor.get_effect(EFFECT_NAME);
if (effect) {
effect.on_end_event(actor);
}
});
this.startResizeOpId = global.window_manager.connect('size-change', (wm, actor, op, oldFrameRect, oldBufferRect) => {
if (!actor) {
return;
}
this.resizedActor = actor;
this.resizedActor.sourceRect = actor.meta_window.get_frame_rect();
if (!op || Meta.SizeChange.UNMAXIMIZE != op) {
return;
}
let effect = actor.get_effect(EFFECT_NAME);
if (!effect || effect.operationType != 'move') {
this.destroyActorEffect(actor);
actor.add_effect_with_name(EFFECT_NAME, new WobblyEffect({settingsData: this.settingsData, op: 'unmaximized'}));
}
});
this.endResizeOpId = global.window_manager.connect('size-changed', (wm, actor) => {
if (!actor || !this.resizedActor || actor != this.resizedActor || !this.resizedActor.sourceRect) {
this.resizedActor = null;
return;
}
let sourceRect = this.resizedActor.sourceRect;
let targetRect = actor.meta_window.get_frame_rect();
this.resizedActor = null;
if (actor.metaWindow.get_maximized()) {
this.destroyActorEffect(actor);
if (!this.settingsData.MAXIMIZE_EFFECT.get()) {
return;
}
let monitor = Main.layoutManager.monitors[actor.meta_window.get_monitor()];
if (actor.metaWindow.get_maximized() === Meta.MaximizeFlags.BOTH ||
(
actor.metaWindow.get_maximized() === Meta.MaximizeFlags.VERTICAL &&
(
(sourceRect.y != targetRect.y) ||
(sourceRect.y + sourceRect.height != targetRect.y + targetRect.height) ||
(sourceRect.x === monitor.x && targetRect.x != monitor.x) ||
(sourceRect.x != monitor.x && targetRect.x === monitor.x) ||
(sourceRect.x + sourceRect.width === monitor.x + monitor.width && targetRect.x + targetRect.width != monitor.x + monitor.width) ||
(sourceRect.x + sourceRect.width != monitor.x + monitor.width && targetRect.x + targetRect.width === monitor.x + monitor.width)
)
)
)
{
actor.add_effect_with_name(EFFECT_NAME, new WobblyEffect({settingsData: this.settingsData, op: 'maximized'}));
}
} else {
let effect = actor.get_effect(EFFECT_NAME);
if (effect && 'move' === effect.operationType) {
this.destroyActorEffect(actor);
actor.add_effect_with_name(EFFECT_NAME, new WobblyEffect({settingsData: this.settingsData, op: 'move'}));
}
}
});
this.destroyId = global.window_manager.connect("destroy", (wm, actor) => {
this.destroyActorEffect(actor);
});
}
disable() {
if (this.settingsData) {
this.settingsData = null;
}
if (this.resizedActor) {
this.resizedActor = null;
}
if (this.allowedResizeOp) {
this.allowedResizeOp = null;
}
if (this.grabOpBeginId) {
global.display.disconnect(this.grabOpBeginId);
this.grabOpBeginId = null;
}
if (this.grabOpEndId) {
global.display.disconnect(this.grabOpEndId);
this.grabOpEndId = null;
}
if (this.endResizeOpId) {
global.window_manager.disconnect(this.endResizeOpId);
this.endResizeOpId = null;
}
if (this.startResizeOpId) {
global.window_manager.disconnect(this.startResizeOpId);
this.startResizeOpId = null;
}
if (this.destroyId) {
global.window_manager.disconnect(this.destroyId);
this.destroyId = null;
}
global.get_window_actors().forEach((actor) => {
this.destroyActorEffect(actor);
});
}
destroyActorEffect(actor) {
if (!actor) {
return;
}
let effect = actor.get_effect(EFFECT_NAME);
if (effect) {
effect.destroy();
}
}
}