mirror of
https://github.com/gosticks/PaperWM.git
synced 2026-02-10 02:42:43 +00:00
260 lines
8.6 KiB
JavaScript
260 lines
8.6 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 Clutter = imports.gi.Clutter;
|
|
var Tweener = Extension.imports.utils.tweener;
|
|
var Main = imports.ui.main;
|
|
var Lang = imports.lang;
|
|
var St = imports.gi.St;
|
|
var Pango = imports.gi.Pango;
|
|
|
|
var Tiling = Extension.imports.tiling;
|
|
var utils = Extension.imports.utils;
|
|
var debug = utils.debug;
|
|
|
|
var prefs = Extension.imports.settings.prefs;
|
|
|
|
var MINIMAP_SCALE = 0.15;
|
|
|
|
function calcOffset(metaWindow) {
|
|
let buffer = metaWindow.get_buffer_rect();
|
|
let frame = metaWindow.get_frame_rect();
|
|
let x_offset = frame.x - buffer.x;
|
|
let y_offset = frame.y - buffer.y;
|
|
return [x_offset, y_offset];
|
|
}
|
|
|
|
class Minimap extends Array {
|
|
constructor(space, monitor) {
|
|
super();
|
|
this.space = space;
|
|
this.monitor = monitor;
|
|
let actor = new St.Widget({name: 'minimap-background',
|
|
style_class: 'switcher-list'});
|
|
this.actor = actor;
|
|
actor.height = space.height*0.20;
|
|
|
|
let highlight = new St.Widget({name: 'minimap-highlight',
|
|
style_class: 'item-box'});
|
|
highlight.add_style_pseudo_class('selected');
|
|
this.highlight = highlight;
|
|
let label = new St.Label();
|
|
label.clutter_text.ellipsize = Pango.EllipsizeMode.END;
|
|
this.label = label;;
|
|
|
|
let clip = new St.Widget({name: 'container-clip'});
|
|
this.clip = clip;
|
|
let container = new St.Widget({name: 'minimap-container'});
|
|
this.container = container;
|
|
container.height = Math.round(space.height*MINIMAP_SCALE) - prefs.window_gap;
|
|
|
|
actor.add_actor(highlight);
|
|
actor.add_actor(label);
|
|
actor.add_actor(clip);
|
|
clip.add_actor(container);
|
|
clip.set_position(12 + prefs.window_gap, 12 + Math.round(1.5*prefs.window_gap));
|
|
highlight.y = clip.y - 10;
|
|
Main.uiGroup.add_actor(this.actor);
|
|
this.actor.opacity = 0;
|
|
this.createClones();
|
|
|
|
this.signals = new utils.Signals();
|
|
this.signals.connect(space, 'select', this.select.bind(this));
|
|
this.signals.connect(space, 'window-added', this.addWindow.bind(this));
|
|
this.signals.connect(space, 'window-removed', this.removeWindow.bind(this));
|
|
this.signals.connect(space, 'layout', this.layout.bind(this));
|
|
this.signals.connect(space, 'swapped', this.swapped.bind(this));
|
|
this.signals.connect(space, 'full-layout', this.reset.bind(this));
|
|
|
|
this.layout();
|
|
}
|
|
|
|
static get [Symbol.species]() { return Array; }
|
|
|
|
reset() {
|
|
this.splice(0,this.length).forEach(c => c.forEach(x => x.destroy()))
|
|
this.createClones()
|
|
this.layout();
|
|
}
|
|
|
|
addWindow(space, metaWindow, index, row) {
|
|
let clone = this.createClone(metaWindow);
|
|
if (row !== undefined && this[index]) {
|
|
let column = this[index];
|
|
column.splice(row, 0, clone);
|
|
} else {
|
|
row = row || 0;
|
|
this.splice(index, 0, [clone]);
|
|
}
|
|
this.layout();
|
|
}
|
|
|
|
removeWindow(space, metaWindow, index, row) {
|
|
let clone = this[index][row];
|
|
let column = this[index];
|
|
column.splice(row, 1);
|
|
if (column.length === 0)
|
|
this.splice(index, 1);
|
|
this.container.remove_child(clone);
|
|
this.layout();
|
|
}
|
|
|
|
swapped(space, index, targetIndex, row, targetRow) {
|
|
let column = this[index];
|
|
utils.swap(this, index, targetIndex);
|
|
utils.swap(column, row, targetRow);
|
|
this.layout();
|
|
}
|
|
|
|
show(animate) {
|
|
if (this.destroyed)
|
|
return;
|
|
let time = animate ? 0.25 : 0;
|
|
this.actor.show();
|
|
Tweener.addTween(this.actor,
|
|
{opacity: 255, time, mode: Clutter.AnimationMode.EASE_OUT_EXPO});
|
|
}
|
|
|
|
hide(animate) {
|
|
if (this.destroyed)
|
|
return;
|
|
let time = animate ? 0.25 : 0;
|
|
Tweener.addTween(this.actor,
|
|
{opacity: 0, time, mode: Clutter.AnimationMode.EASE_OUT_EXPO,
|
|
onComplete: () => this.actor.hide() });
|
|
}
|
|
|
|
createClones() {
|
|
for (let column of this.space) {
|
|
this.push(column.map(this.createClone.bind(this)));
|
|
}
|
|
}
|
|
|
|
createClone(mw) {
|
|
let windowActor = mw.get_compositor_private();
|
|
let clone = new Clutter.Clone({ source: windowActor });
|
|
let container = new Clutter.Actor({
|
|
// layout_manager: new WindowCloneLayout(this),
|
|
name: "window-clone-container"
|
|
});
|
|
clone.meta_window = mw;
|
|
container.clone = clone;
|
|
container.meta_window = mw;
|
|
container.add_actor(clone);
|
|
this.container.add_actor(container);
|
|
this._allocateClone(container);
|
|
return container;
|
|
}
|
|
|
|
_allocateClone(container) {
|
|
let clone = container.clone;
|
|
let meta_window = clone.meta_window;
|
|
let buffer = meta_window.get_buffer_rect();
|
|
let frame = meta_window.get_frame_rect();
|
|
clone.set_size(buffer.width*MINIMAP_SCALE, buffer.height*MINIMAP_SCALE - prefs.window_gap);
|
|
clone.set_position(((buffer.x - frame.x)*MINIMAP_SCALE),
|
|
(buffer.y - frame.y)*MINIMAP_SCALE);
|
|
container.set_size(frame.width*MINIMAP_SCALE, frame.height*MINIMAP_SCALE);
|
|
}
|
|
|
|
layout() {
|
|
if (this.destroyed)
|
|
return;
|
|
let gap = prefs.window_gap;
|
|
let x = 0;
|
|
for (let column of this) {
|
|
let y = 0, w = 0;
|
|
for (let c of column) {
|
|
c.set_position(x, y);
|
|
this._allocateClone(c);
|
|
w = Math.max(w, c.width);
|
|
y += c.height;
|
|
}
|
|
x += w + gap;
|
|
}
|
|
|
|
this.clip.width = Math.min(this.container.width,
|
|
this.monitor.width - this.clip.x*2 - 24);
|
|
this.actor.width = this.clip.width + this.clip.x*2;
|
|
this.clip.set_clip(0, 0, this.clip.width, this.clip.height);
|
|
this.label.set_style(`max-width: ${this.clip.width}px;`);
|
|
this.actor.set_position(
|
|
this.monitor.x + Math.floor((this.monitor.width - this.actor.width)/2),
|
|
this.monitor.y + Math.floor((this.monitor.height - this.actor.height)/2));
|
|
this.select();
|
|
}
|
|
|
|
select() {
|
|
let position = this.space.positionOf();
|
|
let highlight = this.highlight;
|
|
if (!position) {
|
|
this.highlight.hide();
|
|
return;
|
|
}
|
|
let [index, row] = position;
|
|
if (!(index in this && row in this[index]))
|
|
return;
|
|
highlight.show();
|
|
let clip = this.clip;
|
|
let container = this.container;
|
|
let label = this.label;
|
|
let selected = this[index][row];
|
|
if (!selected)
|
|
return;
|
|
|
|
label.text = selected.meta_window.title;
|
|
|
|
if (selected.x + selected.width + container.x > clip.width) {
|
|
// Align right edge of selected with the clip
|
|
container.x = clip.width - (selected.x + selected.width)
|
|
container.x -= 500; // margin
|
|
}
|
|
if (selected.x + container.x < 0) {
|
|
// Align left edge of selected with the clip
|
|
container.x = -selected.x
|
|
container.x += 500; // margin
|
|
}
|
|
|
|
if (container.x + container.width < clip.width)
|
|
container.x = clip.width - container.width;
|
|
|
|
if (container.x > 0)
|
|
container.x = 0;
|
|
|
|
let gap = prefs.window_gap;
|
|
highlight.x = Math.round(
|
|
clip.x + container.x + selected.x - gap/2);
|
|
highlight.y = Math.round(
|
|
clip.y + selected.y - prefs.window_gap);
|
|
highlight.set_size(Math.round(selected.width + gap),
|
|
Math.round(Math.min(selected.height, this.clip.height + gap) + gap));
|
|
|
|
let x = highlight.x
|
|
+ (highlight.width - label.width)/2;
|
|
if (x + label.width > clip.x + clip.width)
|
|
x = clip.x + clip.width - label.width + 5;
|
|
if (x < 0)
|
|
x = clip.x - 5;
|
|
|
|
label.set_position(
|
|
Math.round(x),
|
|
clip.y + Math.round(clip.height + 20));
|
|
|
|
this.actor.height = this.label.y + this.label.height + 12;
|
|
}
|
|
|
|
destroy() {
|
|
if (this.destroyed)
|
|
return;
|
|
this.destroyed = true;
|
|
this.signals.destroy();
|
|
this.splice(0,this.length);
|
|
this.actor.destroy();
|
|
this.actor = null;
|
|
}
|
|
}
|