Adding 45/vertical-workspaces version 37+20231208 [0c80cb1].
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
ff47e23e0d
commit
fefbcf8b74
53 changed files with 23800 additions and 0 deletions
525
extensions/45/vertical-workspaces/lib/winTmb.js
Normal file
525
extensions/45/vertical-workspaces/lib/winTmb.js
Normal file
|
@ -0,0 +1,525 @@
|
|||
/**
|
||||
* V-Shell (Vertical Workspaces)
|
||||
* WinTmb
|
||||
*
|
||||
* @author GdH <G-dH@github.com>
|
||||
* @copyright 2021-2023
|
||||
* @license GPL-3.0
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import GLib from 'gi://GLib';
|
||||
import Clutter from 'gi://Clutter';
|
||||
import St from 'gi://St';
|
||||
import Meta from 'gi://Meta';
|
||||
import GObject from 'gi://GObject';
|
||||
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||
import * as DND from 'resource:///org/gnome/shell/ui/dnd.js';
|
||||
import * as AltTab from 'resource:///org/gnome/shell/ui/altTab.js';
|
||||
|
||||
let Me;
|
||||
let opt;
|
||||
|
||||
const SCROLL_ICON_OPACITY = 240;
|
||||
const DRAG_OPACITY = 200;
|
||||
const CLOSE_BTN_OPACITY = 240;
|
||||
|
||||
|
||||
export const WinTmbModule = class {
|
||||
constructor(me) {
|
||||
Me = me;
|
||||
opt = Me.opt;
|
||||
|
||||
this._firstActivation = true;
|
||||
this.moduleEnabled = false;
|
||||
}
|
||||
|
||||
cleanGlobals() {
|
||||
Me = null;
|
||||
opt = null;
|
||||
}
|
||||
|
||||
update(reset) {
|
||||
this._removeTimeouts();
|
||||
|
||||
this.moduleEnabled = opt.get('windowThumbnailModule');
|
||||
|
||||
reset = reset || !this.moduleEnabled;
|
||||
|
||||
// don't touch the original code if module disabled
|
||||
if (reset && !this._firstActivation) {
|
||||
this._disableModule();
|
||||
} else if (!reset) {
|
||||
this._firstActivation = false;
|
||||
this._activateModule();
|
||||
}
|
||||
if (reset && this._firstActivation)
|
||||
console.debug(' WinTmb - Keeping untouched');
|
||||
}
|
||||
|
||||
_activateModule() {
|
||||
this._timeouts = {};
|
||||
if (!this._windowThumbnails)
|
||||
this._windowThumbnails = [];
|
||||
|
||||
Main.overview.connectObject('hidden', () => this.showThumbnails(), this);
|
||||
console.debug(' WinTmb - Activated');
|
||||
}
|
||||
|
||||
_disableModule() {
|
||||
Main.overview.disconnectObject(this);
|
||||
this._disconnectStateAdjustment();
|
||||
this.removeAllThumbnails();
|
||||
console.debug(' WinTmb - Disabled');
|
||||
}
|
||||
|
||||
_removeTimeouts() {
|
||||
if (this._timeouts) {
|
||||
Object.values(this._timeouts).forEach(t => {
|
||||
if (t)
|
||||
GLib.source_remove(t);
|
||||
});
|
||||
this._timeouts = null;
|
||||
}
|
||||
}
|
||||
|
||||
createThumbnail(metaWin) {
|
||||
const thumbnail = new WindowThumbnail(metaWin, {
|
||||
'height': Math.floor(opt.WINDOW_THUMBNAIL_SCALE * global.display.get_monitor_geometry(global.display.get_current_monitor()).height),
|
||||
'thumbnailsOnScreen': this._windowThumbnails.length,
|
||||
});
|
||||
|
||||
this._windowThumbnails.push(thumbnail);
|
||||
thumbnail.connect('removed', tmb => {
|
||||
this._windowThumbnails.splice(this._windowThumbnails.indexOf(tmb), 1);
|
||||
tmb.destroy();
|
||||
if (!this._windowThumbnails.length)
|
||||
this._disconnectStateAdjustment();
|
||||
});
|
||||
|
||||
if (!this._stateAdjustmentConId) {
|
||||
this._stateAdjustmentConId = Main.overview._overview.controls._stateAdjustment.connectObject('notify::value', () => {
|
||||
if (!this._thumbnailsHidden && (!opt.OVERVIEW_MODE2 || opt.WORKSPACE_MODE))
|
||||
this.hideThumbnails();
|
||||
}, this);
|
||||
}
|
||||
}
|
||||
|
||||
hideThumbnails() {
|
||||
this._windowThumbnails.forEach(tmb => {
|
||||
tmb.ease({
|
||||
opacity: 0,
|
||||
duration: 200,
|
||||
mode: Clutter.AnimationMode.LINEAR,
|
||||
onComplete: () => tmb.hide(),
|
||||
});
|
||||
});
|
||||
this._thumbnailsHidden = true;
|
||||
}
|
||||
|
||||
showThumbnails() {
|
||||
this._windowThumbnails.forEach(tmb => {
|
||||
tmb.show();
|
||||
tmb.ease({
|
||||
opacity: 255,
|
||||
duration: 100,
|
||||
mode: Clutter.AnimationMode.LINEAR,
|
||||
});
|
||||
});
|
||||
this._thumbnailsHidden = false;
|
||||
}
|
||||
|
||||
removeAllThumbnails() {
|
||||
this._windowThumbnails.forEach(tmb => tmb.remove());
|
||||
this._windowThumbnails = [];
|
||||
}
|
||||
|
||||
_disconnectStateAdjustment() {
|
||||
Main.overview._overview.controls._stateAdjustment.disconnectObject(this);
|
||||
}
|
||||
};
|
||||
|
||||
const WindowThumbnail = GObject.registerClass({
|
||||
Signals: { 'removed': {} },
|
||||
}, class WindowThumbnail extends St.Widget {
|
||||
_init(metaWin, args) {
|
||||
this._hoverShowsPreview = false;
|
||||
this._customOpacity = 255;
|
||||
this._initTmbHeight = args.height;
|
||||
this._minimumHeight = Math.floor(5 / 100 * global.display.get_monitor_geometry(global.display.get_current_monitor()).height);
|
||||
this._scrollTimeout = 100;
|
||||
this._positionOffset = args.thumbnailsOnScreen;
|
||||
this._reverseTmbWheelFunc = false;
|
||||
this._click_count = 1;
|
||||
this._prevBtnPressTime = 0;
|
||||
this.w = metaWin;
|
||||
super._init({
|
||||
layout_manager: new Clutter.BinLayout(),
|
||||
visible: true,
|
||||
reactive: true,
|
||||
can_focus: true,
|
||||
track_hover: true,
|
||||
});
|
||||
this.connect('button-release-event', this._onBtnReleased.bind(this));
|
||||
this.connect('scroll-event', this._onScrollEvent.bind(this));
|
||||
// this.connect('motion-event', this._onMouseMove.bind(this)); // may be useful in the future..
|
||||
|
||||
this._delegate = this;
|
||||
this._draggable = DND.makeDraggable(this, { dragActorOpacity: DRAG_OPACITY });
|
||||
this._draggable.connect('drag-end', this._end_drag.bind(this));
|
||||
this._draggable.connect('drag-cancelled', this._end_drag.bind(this));
|
||||
this._draggable._animateDragEnd = eventTime => {
|
||||
this._draggable._animationInProgress = true;
|
||||
this._draggable._onAnimationComplete(this._draggable._dragActor, eventTime);
|
||||
this.opacity = this._customOpacity;
|
||||
};
|
||||
|
||||
this.clone = new Clutter.Clone({ reactive: true });
|
||||
Main.layoutManager.addChrome(this);
|
||||
|
||||
this.window = this.w.get_compositor_private();
|
||||
|
||||
this.clone.set_source(this.window);
|
||||
|
||||
this.add_child(this.clone);
|
||||
this._addCloseButton();
|
||||
this._addScrollModeIcon();
|
||||
|
||||
this.connect('enter-event', () => {
|
||||
global.display.set_cursor(Meta.Cursor.POINTING_HAND);
|
||||
this._closeButton.opacity = CLOSE_BTN_OPACITY;
|
||||
this._scrollModeBin.opacity = SCROLL_ICON_OPACITY;
|
||||
if (this._hoverShowsPreview && !Main.overview._shown) {
|
||||
this._closeButton.opacity = 50;
|
||||
this._showWindowPreview(false, true);
|
||||
}
|
||||
});
|
||||
|
||||
this.connect('leave-event', () => {
|
||||
global.display.set_cursor(Meta.Cursor.DEFAULT);
|
||||
this._closeButton.opacity = 0;
|
||||
this._scrollModeBin.opacity = 0;
|
||||
if (this._winPreview)
|
||||
this._destroyWindowPreview();
|
||||
});
|
||||
|
||||
this._setSize(true);
|
||||
this.set_position(...this._getInitialPosition());
|
||||
this.show();
|
||||
this.window_id = this.w.get_id();
|
||||
this.tmbRedrawDirection = true;
|
||||
|
||||
// remove thumbnail content and hide thumbnail if its window is destroyed
|
||||
this.windowConnect = this.window.connect('destroy', () => {
|
||||
if (this)
|
||||
this.remove();
|
||||
});
|
||||
}
|
||||
|
||||
_getInitialPosition() {
|
||||
const offset = 20;
|
||||
let monitor = Main.layoutManager.monitors[global.display.get_current_monitor()];
|
||||
let x = Math.min(monitor.x + monitor.width - (this.window.width * this.scale) - offset);
|
||||
let y = Math.min(monitor.y + monitor.height - (this.window.height * this.scale) - offset - ((this._positionOffset * this._initTmbHeight) % (monitor.height - this._initTmbHeight)));
|
||||
return [x, y];
|
||||
}
|
||||
|
||||
_setSize(resetScale = false) {
|
||||
if (resetScale)
|
||||
this.scale = Math.min(1.0, this._initTmbHeight / this.window.height);
|
||||
|
||||
const width = this.window.width * this.scale;
|
||||
const height = this.window.height * this.scale;
|
||||
this.set_size(width, height);
|
||||
/* if (this.icon) {
|
||||
this.icon.scale_x = this.scale;
|
||||
this.icon.scale_y = this.scale;
|
||||
}*/
|
||||
|
||||
// when the scale of this. actor change, this.clone resize accordingly,
|
||||
// but the reactive area of the actor doesn't change until the actor is redrawn
|
||||
// this updates the actor's input region area:
|
||||
Main.layoutManager._queueUpdateRegions();
|
||||
}
|
||||
|
||||
/* _onMouseMove(actor, event) {
|
||||
let [pos_x, pos_y] = event.get_coords();
|
||||
let state = event.get_state();
|
||||
if (this._ctrlPressed(state)) {
|
||||
}
|
||||
}*/
|
||||
|
||||
_onBtnReleased(actor, event) {
|
||||
// Clutter.Event.click_count property in no longer available, since GS42
|
||||
if ((event.get_time() - this._prevBtnPressTime) < Clutter.Settings.get_default().double_click_time)
|
||||
this._click_count += 1;
|
||||
else
|
||||
this._click_count = 1;
|
||||
|
||||
this._prevBtnPressTime = event.get_time();
|
||||
|
||||
if (this._click_count === 2 && event.get_button() === Clutter.BUTTON_PRIMARY)
|
||||
this.w.activate(global.get_current_time());
|
||||
|
||||
|
||||
const button = event.get_button();
|
||||
const state = event.get_state();
|
||||
switch (button) {
|
||||
case Clutter.BUTTON_PRIMARY:
|
||||
if (this._ctrlPressed(state)) {
|
||||
this._setSize();
|
||||
} else {
|
||||
this._reverseTmbWheelFunc = !this._reverseTmbWheelFunc;
|
||||
this._scrollModeBin.set_child(this._reverseTmbWheelFunc ? this._scrollModeSourceIcon : this._scrollModeResizeIcon);
|
||||
}
|
||||
return Clutter.EVENT_STOP;
|
||||
case Clutter.BUTTON_SECONDARY:
|
||||
if (this._ctrlPressed(state)) {
|
||||
this.remove();
|
||||
} else {
|
||||
this._hoverShowsPreview = !this._hoverShowsPreview;
|
||||
this._showWindowPreview();
|
||||
}
|
||||
return Clutter.EVENT_STOP;
|
||||
case Clutter.BUTTON_MIDDLE:
|
||||
if (this._ctrlPressed(state))
|
||||
this.w.delete(global.get_current_time());
|
||||
return Clutter.EVENT_STOP;
|
||||
default:
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
}
|
||||
}
|
||||
|
||||
_onScrollEvent(actor, event) {
|
||||
let direction = Me.Util.getScrollDirection(event);
|
||||
|
||||
if (this._actionTimeoutActive())
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
let state = event.get_state();
|
||||
switch (direction) {
|
||||
case Clutter.ScrollDirection.UP:
|
||||
if (this._shiftPressed(state)) {
|
||||
this.opacity = Math.min(255, this.opacity + 24);
|
||||
this._customOpacity = this.opacity;
|
||||
} else if (this._reverseTmbWheelFunc !== this._ctrlPressed(state)) {
|
||||
this._switchSourceWin(-1);
|
||||
} else if (this._reverseTmbWheelFunc === this._ctrlPressed(state)) {
|
||||
this.scale = Math.max(0.05, this.scale - 0.025);
|
||||
}
|
||||
break;
|
||||
case Clutter.ScrollDirection.DOWN:
|
||||
if (this._shiftPressed(state)) {
|
||||
this.opacity = Math.max(48, this.opacity - 24);
|
||||
this._customOpacity = this.opacity;
|
||||
} else if (this._reverseTmbWheelFunc !== this._ctrlPressed(state)) {
|
||||
this._switchSourceWin(+1);
|
||||
} else if (this._reverseTmbWheelFunc === this._ctrlPressed(state)) {
|
||||
this.scale = Math.min(1, this.scale + 0.025);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
}
|
||||
this._setSize();
|
||||
return Clutter.EVENT_STOP;
|
||||
}
|
||||
|
||||
remove() {
|
||||
if (this.clone) {
|
||||
this.window.disconnect(this.windowConnect);
|
||||
this.clone.set_source(null);
|
||||
}
|
||||
if (this._winPreview)
|
||||
this._destroyWindowPreview();
|
||||
|
||||
this.emit('removed');
|
||||
}
|
||||
|
||||
_end_drag() {
|
||||
this.set_position(this._draggable._dragOffsetX + this._draggable._dragX, this._draggable._dragOffsetY + this._draggable._dragY);
|
||||
this._setSize();
|
||||
}
|
||||
|
||||
_ctrlPressed(state) {
|
||||
return (state & Clutter.ModifierType.CONTROL_MASK) !== 0;
|
||||
}
|
||||
|
||||
_shiftPressed(state) {
|
||||
return (state & Clutter.ModifierType.SHIFT_MASK) !== 0;
|
||||
}
|
||||
|
||||
_switchSourceWin(direction) {
|
||||
let windows = global.display.get_tab_list(Meta.TabList.NORMAL_ALL, null);
|
||||
windows = windows.filter(w => !(w.skip_taskbar || w.minimized));
|
||||
let idx = -1;
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
if (windows[i] === this.w) {
|
||||
idx = i + direction;
|
||||
break;
|
||||
}
|
||||
}
|
||||
idx = idx >= windows.length ? 0 : idx;
|
||||
idx = idx < 0 ? windows.length - 1 : idx;
|
||||
let w = windows[idx];
|
||||
let win = w.get_compositor_private();
|
||||
this.clone.set_source(win);
|
||||
this.window.disconnect(this.windowConnect);
|
||||
// the new thumbnail should be the same height as the previous one
|
||||
this.scale = (this.scale * this.window.height) / win.height;
|
||||
this.window = win;
|
||||
this.windowConnect = this.window.connect('destroy', () => {
|
||||
if (this)
|
||||
this.remove();
|
||||
});
|
||||
this.w = w;
|
||||
|
||||
if (this._winPreview)
|
||||
this._showWindowPreview(true);
|
||||
}
|
||||
|
||||
_actionTimeoutActive() {
|
||||
const timeout = this._reverseTmbWheelFunc ? this._scrollTimeout : this._scrollTimeout / 4;
|
||||
if (!this._lastActionTime || Date.now() - this._lastActionTime > timeout) {
|
||||
this._lastActionTime = Date.now();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* _setIcon() {
|
||||
let tracker = Shell.WindowTracker.get_default();
|
||||
let app = tracker.get_window_app(this.w);
|
||||
let icon = app
|
||||
? app.create_icon_texture(this.height)
|
||||
: new St.Icon({ icon_name: 'icon-missing', icon_size: this.height });
|
||||
icon.x_expand = icon.y_expand = true;
|
||||
if (this.icon)
|
||||
this.icon.destroy();
|
||||
this.icon = icon;
|
||||
}*/
|
||||
|
||||
_addCloseButton() {
|
||||
const closeButton = new St.Button({
|
||||
opacity: 0,
|
||||
style_class: 'window-close',
|
||||
child: new St.Icon({ icon_name: 'preview-close-symbolic' }),
|
||||
x_align: Clutter.ActorAlign.END,
|
||||
y_align: Clutter.ActorAlign.START,
|
||||
x_expand: true,
|
||||
y_expand: true,
|
||||
});
|
||||
|
||||
closeButton.set_style(`
|
||||
margin: 3px;
|
||||
background-color: rgba(200, 0, 0, 0.9);
|
||||
`);
|
||||
|
||||
closeButton.connect('clicked', () => {
|
||||
this.remove();
|
||||
return Clutter.EVENT_STOP;
|
||||
});
|
||||
|
||||
this._closeButton = closeButton;
|
||||
this.add_child(this._closeButton);
|
||||
}
|
||||
|
||||
_addScrollModeIcon() {
|
||||
this._scrollModeBin = new St.Bin({
|
||||
x_expand: true,
|
||||
y_expand: true,
|
||||
});
|
||||
this._scrollModeResizeIcon = new St.Icon({
|
||||
icon_name: 'view-fullscreen-symbolic',
|
||||
x_align: Clutter.ActorAlign.CENTER,
|
||||
y_align: Clutter.ActorAlign.END,
|
||||
x_expand: true,
|
||||
y_expand: true,
|
||||
opacity: SCROLL_ICON_OPACITY,
|
||||
style_class: 'icon-dropshadow',
|
||||
scale_x: 0.5,
|
||||
scale_y: 0.5,
|
||||
});
|
||||
this._scrollModeResizeIcon.set_style(`
|
||||
margin: 13px;
|
||||
color: rgb(255, 255, 255);
|
||||
box-shadow: 0 0 40px 40px rgba(0,0,0,0.7);
|
||||
`);
|
||||
this._scrollModeSourceIcon = new St.Icon({
|
||||
icon_name: 'media-skip-forward-symbolic',
|
||||
x_align: Clutter.ActorAlign.CENTER,
|
||||
y_align: Clutter.ActorAlign.END,
|
||||
x_expand: true,
|
||||
y_expand: true,
|
||||
opacity: SCROLL_ICON_OPACITY,
|
||||
style_class: 'icon-dropshadow',
|
||||
scale_x: 0.5,
|
||||
scale_y: 0.5,
|
||||
});
|
||||
this._scrollModeSourceIcon.set_style(`
|
||||
margin: 13px;
|
||||
color: rgb(255, 255, 255);
|
||||
box-shadow: 0 0 40px 40px rgba(0,0,0,0.7);
|
||||
`);
|
||||
this._scrollModeBin.set_child(this._scrollModeResizeIcon);
|
||||
this.add_child(this._scrollModeBin);
|
||||
this._scrollModeBin.opacity = 0;
|
||||
}
|
||||
|
||||
_showWindowPreview(update = false, dontDestroy = false) {
|
||||
if (this._winPreview && !dontDestroy) {
|
||||
this._destroyWindowPreview();
|
||||
this._previewCreationTime = 0;
|
||||
this._closeButton.opacity = CLOSE_BTN_OPACITY;
|
||||
if (!update)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._winPreview) {
|
||||
this._winPreview = new AltTab.CyclerHighlight();
|
||||
global.window_group.add_actor(this._winPreview);
|
||||
[this._winPreview._xPointer, this._winPreview._yPointer] = global.get_pointer();
|
||||
}
|
||||
|
||||
if (!update) {
|
||||
this._winPreview.opacity = 0;
|
||||
this._winPreview.ease({
|
||||
opacity: 255,
|
||||
duration: 70,
|
||||
mode: Clutter.AnimationMode.LINEAR,
|
||||
/* onComplete: () => {
|
||||
this._closeButton.opacity = 50;
|
||||
},*/
|
||||
});
|
||||
|
||||
this.ease({
|
||||
opacity: Math.min(50, this._customOpacity),
|
||||
duration: 70,
|
||||
mode: Clutter.AnimationMode.LINEAR,
|
||||
onComplete: () => {
|
||||
},
|
||||
});
|
||||
} else {
|
||||
this._winPreview.opacity = 255;
|
||||
}
|
||||
this._winPreview.window = this.w;
|
||||
this._winPreview._window = this.w;
|
||||
global.window_group.set_child_above_sibling(this._winPreview, null);
|
||||
}
|
||||
|
||||
_destroyWindowPreview() {
|
||||
if (this._winPreview) {
|
||||
this._winPreview.ease({
|
||||
opacity: 0,
|
||||
duration: 100,
|
||||
mode: Clutter.AnimationMode.LINEAR,
|
||||
onComplete: () => {
|
||||
this._winPreview.destroy();
|
||||
this._winPreview = null;
|
||||
this.opacity = this._customOpacity;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue