PaperWM/utils.js
2018-07-18 22:37:34 +02:00

231 lines
6.3 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const Extension = imports.misc.extensionUtils.extensions['paperwm@hedning:matrix.org']
const Gdk = imports.gi.Gdk;
var Meta = imports.gi.Meta;
var screen = global.screen;
var display = global.display;
var debug_all = false; // Turn off by default
var debug_filter = {};
function debug() {
let keyword = arguments[0];
let filter = debug_filter[keyword];
if (filter === false)
return;
if (debug_all || filter === true)
print(Array.prototype.join.call(arguments, " | "));
}
function warn(...args) {
print("WARNING:", ...args);
}
function assert(condition, message, ...dump) {
if (!condition) {
throw new Error(message + "\n", dump);
}
}
function print_stacktrace(error) {
let trace;
if (!error) {
trace = (new Error()).stack.split("\n")
// Remove _this_ frame
trace.splice(0, 1);
} else {
trace = error.stack.split("\n");
}
// Remove some uninteresting frames
let filtered = trace.filter((frame) => {
return frame !== "wrapper@resource:///org/gnome/gjs/modules/lang.js:178"
});
let args = [...arguments];
args.splice(0, 1, "stacktrace:"+(args[0] ? args[0] : ""))
// Use non-breaking space to encode new lines (otherwise every frame is
// prefixed by timestamp)
let nl = " ";
args.push(nl+filtered.join(nl))
debug.apply(null, args);
}
function framestr(rect) {
return "[ x:"+rect.x + ", y:" + rect.y + " w:" + rect.width + " h:"+rect.height + " ]";
}
/**
* Look up the function by name at call time. This makes it convenient to
* redefine the function without re-registering all signal handler, keybindings,
* etc. (this is like a function symbol in lisp)
*/
function dynamic_function_ref(handler_name, owner_obj) {
owner_obj = owner_obj || window;
return function() {
owner_obj[handler_name].apply(this, arguments);
}
}
function swap(array, i, j) {
let temp = array[i];
array[i] = array[j];
array[j] = temp;
}
function in_bounds(array, i) {
return i >= 0 && i < array.length;
}
function isPointInsideActor(actor, x, y) {
return (actor.x <= x && x <= actor.x+actor.width)
&& (actor.y <= y && y <= actor.y+actor.height);
}
//// Debug and development utils
const Tiling = Extension.imports.tiling;
function setDevGlobals() {
// Accept the risk of this interfering with existing code for now
metaWindow = display.focus_window;
meta_window = display.focus_window;
workspace = screen.get_active_workspace();
actor = metaWindow.get_compositor_private();
space = Tiling.spaces.spaceOfWindow(metaWindow);
}
/**
* Visualize the frame and buffer bounding boxes of a meta window
*/
function toggleWindowBoxes(metaWindow) {
metaWindow = metaWindow || display.focus_window;
if(metaWindow._paperDebugBoxes) {
metaWindow._paperDebugBoxes.forEach(box => {
box.destroy();
});
delete metaWindow._paperDebugBoxes;
return [];
}
let frame = metaWindow.get_frame_rect()
let inputFrame = metaWindow.get_buffer_rect()
let actor = metaWindow.get_compositor_private();
makeFrameBox = function({x, y, width, height}, color) {
let frameBox = new imports.gi.St.Widget();
frameBox.set_position(x, y)
frameBox.set_size(width, height)
frameBox.set_style("border: 2px" + color + " solid");
return frameBox;
}
let boxes = [];
boxes.push(makeFrameBox(frame, "red"));
boxes.push(makeFrameBox(inputFrame, "blue"));
if(inputFrame.x !== actor.x || inputFrame.y !== actor.y
|| inputFrame.width !== actor.width || inputFrame.height !== actor.height) {
boxes.push(makeFrameBox(actor, "yellow"));
}
boxes.forEach(box => global.stage.add_actor(box));
metaWindow._paperDebugBoxes = boxes;
return boxes;
}
var markNewClonesSignalId = null;
function toggleCloneMarks() {
// NB: doesn't clean up signal on disable
function markCloneOf(metaWindow) {
if (metaWindow.clone)
metaWindow.clone.opacity = 190;
}
function unmarkCloneOf(metaWindow) {
if (metaWindow.clone)
metaWindow.clone.opacity = 255;
}
let windows = display.get_tab_list(Meta.TabList.NORMAL_ALL, null);
if (markNewClonesSignalId) {
display.disconnect(markNewClonesSignalId);
markNewClonesSignalId = null;
windows.forEach(unmarkCloneOf);
} else {
markNewClonesSignalId = display.connect_after(
"window-created", (_, mw) => markCloneOf(mw))
windows.forEach(markCloneOf);
}
}
function sum(array) {
return array.reduce((a, b) => a + b, 0);
}
function setWorkspaceName(name, workspace) {
let i;
if (workspace === undefined) {
i = screen.get_active_workspace_index();
} else {
i = workspace.index();
}
let settings = new Gio.Settings({ schema_id:
'org.gnome.desktop.wm.preferences'});
let names = settings.get_strv('workspace-names');
let oldName = names[i];
names[i] = name;
settings.set_strv('workspace-names', names);
return oldName;
}
function getPointerPosition() {
let display = Gdk.Display.get_default();
let deviceManager = display.get_device_manager();
let pointer = deviceManager.get_client_pointer();
let [gdkscreen, x, y] = pointer.get_position();
return [x, y, gdkscreen, pointer]
}
function warpPointer(x, y) {
let display = Gdk.Display.get_default();
let deviceManager = display.get_device_manager();
let pointer = deviceManager.get_client_pointer();
pointer.warp(Gdk.Screen.get_default(), x, y)
}
class Signals extends Map {
static get [Symbol.species]() { return Map; }
connect(object, signal, handler) {
let signals = this.get(object);
if (!signals) {
signals = [];
this.set(object, signals);
}
let id = object.connect(signal, handler);
signals.push(id);
return id;
}
disconnect(object) {
let ids = this.get(object);
if (ids) {
ids.forEach(id => object.disconnect(id));
this.delete(object);
}
}
destroy() {
for (let [object, signals] of this) {
signals.forEach(id => object.disconnect(id));
this.delete(object);
}
}
}