mirror of
https://github.com/gosticks/PaperWM.git
synced 2026-07-06 17:10:03 +00:00
The window is resized automatically when moved to scratch so makes sense to automatically maximize on reinsertion. Ideally some special casing on whether the window was explicitly sized should also be done.
230 lines
6.9 KiB
JavaScript
230 lines
6.9 KiB
JavaScript
var Extension;
|
|
if (imports.misc.extensionUtils.extensions) {
|
|
Extension = imports.misc.extensionUtils.extensions["paperwm@hedning:matrix.org"];
|
|
} else {
|
|
Extension = imports.ui.main.extensionManager.lookup("paperwm@hedning:matrix.org");
|
|
}
|
|
|
|
var Meta = imports.gi.Meta;
|
|
var Main = imports.ui.main;
|
|
|
|
var TopBar = Extension.imports.topbar;
|
|
var Tiling = Extension.imports.tiling;
|
|
var utils = Extension.imports.utils;
|
|
var debug = utils.debug;
|
|
var float, scratchFrame; // symbols used for expando properties on metawindow
|
|
|
|
|
|
function focusMonitor() {
|
|
if (global.display.focus_window) {
|
|
return Main.layoutManager.monitors[global.display.focus_window.get_monitor()]
|
|
} else {
|
|
return Main.layoutManager.primaryMonitor;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Tween window to "frame-coordinate" (targetX, targetY).
|
|
The frame is moved once the tween is done.
|
|
|
|
The actual window actor (not clone) is tweened to ensure it's on top of the
|
|
other windows/clones (clones if the space animates)
|
|
*/
|
|
function tweenScratch(metaWindow, targetX, targetY, tweenParams={}) {
|
|
let Tweener = Extension.imports.utils.tweener;
|
|
let Settings = Extension.imports.settings;
|
|
let f = metaWindow.get_frame_rect();
|
|
let b = metaWindow.get_buffer_rect();
|
|
let dx = f.x - b.x;
|
|
let dy = f.y - b.y;
|
|
|
|
Tweener.addTween(metaWindow.get_compositor_private(), Object.assign(
|
|
{
|
|
time: Settings.prefs.animation_time,
|
|
x: targetX - dx,
|
|
y: targetY - dy,
|
|
},
|
|
tweenParams,
|
|
{
|
|
onComplete: function(...args) {
|
|
metaWindow.move_frame(true, targetX , targetY);
|
|
tweenParams.onComplete && tweenParams.onComplete.apply(this, args);
|
|
}
|
|
}));
|
|
}
|
|
|
|
function makeScratch(metaWindow) {
|
|
let fromNonScratch = !metaWindow[float];
|
|
let fromTiling = false;
|
|
// Relevant when called while navigating. Use the position the user actually sees.
|
|
let windowPositionSeen;
|
|
|
|
if (fromNonScratch) {
|
|
// Figure out some stuff before the window is removed from the tiling
|
|
let space = Tiling.spaces.spaceOfWindow(metaWindow);
|
|
fromTiling = space.indexOf(metaWindow) > -1;
|
|
windowPositionSeen = metaWindow.clone.get_transformed_position().map(Math.round);
|
|
}
|
|
|
|
metaWindow[float] = true;
|
|
metaWindow.make_above();
|
|
metaWindow.stick(); // NB! Removes the window from the tiling (synchronously)
|
|
|
|
if (!metaWindow.minimized)
|
|
Tiling.showWindow(metaWindow);
|
|
|
|
if (fromTiling) {
|
|
metaWindow._initialResizeDone = false; // [free-resize] automaximize on future insertion
|
|
let f = metaWindow.get_frame_rect();
|
|
let targetFrame = null;
|
|
|
|
if (metaWindow[scratchFrame]) {
|
|
let sf = metaWindow[scratchFrame];
|
|
if (utils.monitorOfPoint(sf.x, sf.y) === focusMonitor()) {
|
|
targetFrame = sf;
|
|
}
|
|
}
|
|
|
|
if (!targetFrame) {
|
|
// Default to moving the window slightly down and reducing the height
|
|
let vDisplacement = 30;
|
|
let [x, y] = windowPositionSeen; // The window could be non-placable so can't use frame
|
|
|
|
targetFrame = new Meta.Rectangle({
|
|
x: x, y: y + vDisplacement,
|
|
width: f.width,
|
|
height: Math.min(f.height - vDisplacement, Math.floor(f.height * 0.9))
|
|
})
|
|
}
|
|
|
|
if (!metaWindow.minimized) {
|
|
metaWindow.move_resize_frame(true, f.x, f.y,
|
|
targetFrame.width, targetFrame.height);
|
|
tweenScratch(metaWindow, targetFrame.x, targetFrame.y,
|
|
{onComplete: () => delete metaWindow[scratchFrame]});
|
|
} else {
|
|
// Can't restore the scratch geometry immediately since it distort the minimize animation
|
|
// ASSUMPTION: minimize animation is not disabled and not already done
|
|
let actor = metaWindow.get_compositor_private();
|
|
let signal = actor.connect('effects-completed', () => {
|
|
metaWindow.move_resize_frame(true, targetFrame.x, targetFrame.y,
|
|
targetFrame.width, targetFrame.height);
|
|
actor.disconnect(signal)
|
|
})
|
|
}
|
|
}
|
|
|
|
let monitor = focusMonitor();
|
|
if (monitor.clickOverlay)
|
|
monitor.clickOverlay.hide();
|
|
}
|
|
|
|
function unmakeScratch(metaWindow) {
|
|
if (!metaWindow[scratchFrame])
|
|
metaWindow[scratchFrame] = metaWindow.get_frame_rect();
|
|
metaWindow[float] = false;
|
|
metaWindow.unmake_above();
|
|
metaWindow.unstick();
|
|
}
|
|
|
|
function toggle(metaWindow) {
|
|
if (isScratchWindow(metaWindow)) {
|
|
unmakeScratch(metaWindow);
|
|
hide();
|
|
} else {
|
|
makeScratch(metaWindow);
|
|
|
|
if (metaWindow.has_focus) {
|
|
let space = Tiling.spaces.get(global.workspace_manager.get_active_workspace());
|
|
space.setSelectionInactive();
|
|
}
|
|
}
|
|
}
|
|
|
|
function isScratchWindow(metaWindow) {
|
|
return metaWindow && metaWindow[float];
|
|
}
|
|
|
|
/** Return scratch windows in MRU order */
|
|
function getScratchWindows() {
|
|
return global.display.get_tab_list(Meta.TabList.NORMAL, null)
|
|
.filter(isScratchWindow);
|
|
}
|
|
|
|
function isScratchActive() {
|
|
return getScratchWindows().some(metaWindow => !metaWindow.minimized);
|
|
}
|
|
|
|
function toggleScratch() {
|
|
if (isScratchActive())
|
|
hide();
|
|
else
|
|
show();
|
|
}
|
|
|
|
function toggleScratchWindow() {
|
|
let focus = global.display.focus_window;
|
|
if (isScratchWindow(focus))
|
|
hide();
|
|
else
|
|
show(true);
|
|
}
|
|
|
|
function show(top) {
|
|
let windows = getScratchWindows();
|
|
if (windows.length === 0) {
|
|
return;
|
|
}
|
|
if (top)
|
|
windows = windows.slice(0,1);
|
|
|
|
TopBar.show();
|
|
|
|
windows.slice().reverse()
|
|
.map(function(meta_window) {
|
|
meta_window.unminimize();
|
|
meta_window.make_above();
|
|
meta_window.get_compositor_private().show();
|
|
});
|
|
windows[0].activate(global.get_current_time());
|
|
|
|
let monitor = focusMonitor();
|
|
if (monitor.clickOverlay)
|
|
monitor.clickOverlay.hide();
|
|
}
|
|
|
|
function hide() {
|
|
let windows = getScratchWindows();
|
|
windows.map(function(meta_window) {
|
|
meta_window.minimize();
|
|
});
|
|
}
|
|
|
|
// Monkey patch the alt-space menu
|
|
var PopupMenu = imports.ui.popupMenu;
|
|
var WindowMenu = imports.ui.windowMenu;
|
|
var originalBuildMenu = WindowMenu.WindowMenu.prototype._buildMenu;
|
|
|
|
function init() {
|
|
float = Symbol();
|
|
scratchFrame = Symbol();
|
|
}
|
|
|
|
function enable() {
|
|
WindowMenu.WindowMenu.prototype._buildMenu =
|
|
function (window) {
|
|
let item;
|
|
item = this.addAction(_('Scratch'), () => {
|
|
toggle(window);
|
|
});
|
|
if (isScratchWindow(window))
|
|
item.setOrnament(PopupMenu.Ornament.CHECK);
|
|
|
|
originalBuildMenu.call(this, window);
|
|
};
|
|
}
|
|
|
|
function disable() {
|
|
WindowMenu.WindowMenu.prototype._buildMenu = originalBuildMenu;
|
|
}
|