/**
* Helper classes / enums for the settings.xml used in the extension files
* *and* prefs files
*/
/**
* A Singleton providing access to the settings.
*/
export class Settings {
static _settings;
static initialize(gioSettings) {
this._settings = gioSettings;
}
static destroy() {
this._settings = null;
}
/**
* @returns {import("./dependencies/gi.js").Gio.Settings} the Gio.Settings object.
*/
static getGioObject() {
return this._settings;
}
/**
* Listens for the change of a setting.
*
* @param {string} key a settings key.
* @param {*} func function to call when the setting changed.
*/
static changed(key, func) {
return this._settings.connect(`changed::${key}`, func);
}
static disconnect(id) {
this._settings.disconnect(id);
}
/**
* Getters
*/
static getEnum(key) {
return this._settings.get_enum(key);
}
static getString(key) {
return this._settings.get_string(key);
}
static getStrv(key) {
return this._settings.get_strv(key);
}
static getInt(key) {
return this._settings.get_int(key);
}
static getBoolean(key) {
return this._settings.get_boolean(key);
}
static getValue(key) {
return this._settings.get_value(key);
}
static getUserValue(key) {
return this._settings.get_user_value(key);
}
/**
* Setters
*/
static setEnum(key, value) {
this._settings.set_enum(key, value);
}
static setString(key, value) {
this._settings.set_string(key, value);
}
static setStrv(key, value) {
this._settings.set_strv(key, value);
}
static setInt(key, value) {
this._settings.set_int(key, value);
}
static setBoolean(key, value) {
this._settings.set_boolean(key, value);
}
static setValue(key, value) {
return this._settings.set_value(key, value);
}
static reset(key) {
this._settings.reset(key);
}
}
/**
* A Singleton providing access to the shortcut keys except the
* ones related to the Layouts.
*/
export class Shortcuts {
/**
* @returns {string[]} the settings keys for the shortcuts in the same
* order as they appear in the preference window.
*/
static getAllKeys() {
return [
'toggle-tiling-popup',
'tile-edit-mode',
'auto-tile',
'toggle-always-on-top',
'tile-maximize',
'tile-maximize-vertically',
'tile-maximize-horizontally',
'restore-window',
'center-window',
'tile-top-half',
'tile-bottom-half',
'tile-left-half',
'tile-right-half',
'tile-topleft-quarter',
'tile-topright-quarter',
'tile-bottomleft-quarter',
'tile-bottomright-quarter',
'tile-top-half-ignore-ta',
'tile-bottom-half-ignore-ta',
'tile-left-half-ignore-ta',
'tile-right-half-ignore-ta',
'tile-topleft-quarter-ignore-ta',
'tile-topright-quarter-ignore-ta',
'tile-bottomleft-quarter-ignore-ta',
'tile-bottomright-quarter-ignore-ta',
'debugging-show-tiled-rects',
'debugging-free-rects'
];
}
}
export class DynamicKeybindings {
// Order comes from prefs
static DISABLED = 0;
static FOCUS = 1;
static TILING_STATE = 2;
static TILING_STATE_WINDOWS = 3;
static FAVORITE_LAYOUT = 4;
}
export const FocusHint = Object.freeze({
DISABLED: 0,
ANIMATED_OUTLINE: 1,
ANIMATED_UPSCALE: 2,
STATIC_OUTLINE: 3
});
export const FocusHintOutlineStyle = Object.freeze({
SOLID_BG: 0,
BORDER: 1
});
export class MoveModes {
// Order comes from prefs
static EDGE_TILING = 0;
static ADAPTIVE_TILING = 1;
static FAVORITE_LAYOUT = 2;
static IGNORE_TA = 3;
}
export class Orientation {
static H = 1;
static V = 2;
}
export class Direction {
static N = 1;
static E = 2;
static S = 4;
static W = 8;
static opposite(dir) {
let opposite = 0;
if (dir & this.N)
opposite |= this.S;
if (dir & this.S)
opposite |= this.N;
if (dir & this.W)
opposite |= this.E;
if (dir & this.E)
opposite |= this.W;
return opposite;
}
}
// Classes for the layouts:
// See src/prefs/layoutsPrefs.js for details on layouts.
export class Layout {
/**
* @param {object} layout is the parsed object from the layouts file.
*/
constructor(layout = null) {
this._name = layout?._name ?? '';
this._items = layout?._items ?? [];
}
/**
* @returns {string}
*/
getName() {
return this._name;
}
/**
* @param {string} name
*/
setName(name) {
this._name = name;
}
/**
* @param {number} index
* @returns {LayoutItem}
*/
getItem(index) {
return this._items[index];
}
/**
* @param {LayoutItem|null} item
* @returns {LayoutItem} the added item.
*/
addItem(item = null) {
item = item ?? new LayoutItem();
this._items.push(item);
return item;
}
/**
* @param {number} index
* @returns {LayoutItem|null} the removed item.
*/
removeItem(index) {
return this._items.splice(index, 1)[0];
}
/**
* @param {boolean} filterOutEmptyRects
* @returns {LayoutItem[]}
*/
getItems(filterOutEmptyRects = true) {
return filterOutEmptyRects
? this._items.filter(i => Object.keys(i.rect).length === 4)
: this._items;
}
/**
* @param {LayoutItem[]} items
*/
setItems(items) {
this._items = items;
}
/**
* @param {boolean} filterOutEmptyRects
* @returns {number}
*/
getItemCount(filterOutEmptyRects = false) {
return filterOutEmptyRects
? this.getItems().length
: this._items.length;
}
/**
* @returns {[boolean, string, number]} whether the layout has valid rects and
* a potential error message.
*/
validate() {
const rects = this.getItems().map(i => i.rect);
if (!rects.length)
return [false, 'No valid rectangles defined.', -1];
const getOverlapArea = (r1, r2) => {
return Math.max(0, Math.min(r1.x + r1.width, r2.x + r2.width) - Math.max(r1.x, r2.x)) *
Math.max(0, Math.min(r1.y + r1.height, r2.y + r2.height) - Math.max(r1.y, r2.y));
};
for (let i = 0; i < rects.length; i++) {
const rect = rects[i];
if (rect.width <= 0 || rect.width > 1)
return [false, `Rectangle ${i} has an invalid width.`, i];
if (rect.height <= 0 || rect.height > 1)
return [false, `Rectangle ${i} has an invalid height.`, i];
if (rect.x < 0 || rect.y < 0 || rect.x + rect.width > 1 || rect.y + rect.height > 1)
return [false, `Rectangle ${i} extends beyond the screen.`, i];
for (let j = i + 1; j < rects.length; j++) {
if (getOverlapArea(rect, rects[j]) !== 0)
return [false, `Rectangles ${i} and ${j} overlap.`, j];
}
}
return [true, '', -1];
}
}
var LayoutItem = class LayoutItem {
constructor() {
this.rect = {};
this.appId = null;
this.loopType = null;
}
};