es modules and clean up codebase

This commit is contained in:
Aylur
2023-08-16 01:47:57 +02:00
parent 791e3c6909
commit 737fc95e67
13 changed files with 277 additions and 1314 deletions
+10 -12
View File
@@ -5,24 +5,22 @@
<file>app.js</file>
<file>utils.js</file>
<file>widget.js</file>
<file>widgets.js</file>
<file>window.js</file>
<file>widgets/shared.js</file>
<file>widgets/box.js</file>
<file>widgets/eventbox.js</file>
<file>widgets/button.js</file>
<file>widgets/centerbox.js</file>
<file>widgets/entry.js</file>
<file>widgets/eventbox.js</file>
<file>widgets/icon.js</file>
<file>widgets/label.js</file>
<file>widgets/button.js</file>
<file>widgets/slider.js</file>
<file>widgets/scrollable.js</file>
<file>widgets/stack.js</file>
<file>widgets/overlay.js</file>
<file>widgets/revealer.js</file>
<file>widgets/progressbar.js</file>
<file>widgets/menu.js</file>
<file>widgets/entry.js</file>
<file>widgets/overlay.js</file>
<file>widgets/progressbar.js</file>
<file>widgets/revealer.js</file>
<file>widgets/scrollable.js</file>
<file>widgets/shared.js</file>
<file>widgets/slider.js</file>
<file>widgets/stack.js</file>
<file>widgets/window.js</file>
<file>service/service.js</file>
+46 -34
View File
@@ -3,16 +3,22 @@ import Gdk from 'gi://Gdk?version=3.0';
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import Window from './window.js';
import { error, warning, getConfig, timeout, connect } from './utils.js';
import { timeout, connect } from './utils.js';
const APP_BUS = 'com.github.Aylur.' + pkg.name;
interface Config {
windows?: Gtk.Window[]
style?: string
notificationPopupTimeout?: number
closeWindowDelay?: { [key: string]: number }
}
export default class App extends Gtk.Application {
private _windows: Map<string, Gtk.Window>;
private _closeDelay!: { [key: string]: number };
private _cssProviders: Gtk.CssProvider[] = [];
static configPath: string;
static config: Config;
static instance: App;
static {
@@ -32,7 +38,7 @@ export default class App extends Gtk.Application {
static getWindow(name: string) {
const w = App.instance._windows.get(name);
return w ? w : warning(`There is no window named ${name}`);
return w ? w : console.error(`There is no window named ${name}`);
}
static closeWindow(name: string) {
@@ -69,7 +75,7 @@ export default class App extends Gtk.Application {
static resetCss() {
const screen = Gdk.Screen.get_default();
if (!screen) {
error("couldn't get screen");
console.error("couldn't get screen");
return;
}
@@ -83,7 +89,7 @@ export default class App extends Gtk.Application {
static applyCss(path: string) {
const screen = Gdk.Screen.get_default();
if (!screen) {
error("couldn't get screen");
console.error("couldn't get screen");
return;
}
@@ -107,52 +113,58 @@ export default class App extends Gtk.Application {
connect(this, widget, callback, event);
}
constructor() {
constructor({ bus, config }: {
bus: string
config: string
}) {
super({
application_id: APP_BUS,
application_id: bus,
flags: Gio.ApplicationFlags.DEFAULT_FLAGS,
});
this._windows = new Map();
App.configPath = config;
App.instance = this;
}
vfunc_activate() {
this.hold();
this._load();
this._exportActions();
this._load();
}
_load() {
for (const [name, window] of this._windows) {
window.destroy();
this._windows.delete(name);
}
async _load() {
try {
const mod = await import(`file://${App.configPath}`);
const config = mod.default as Config;
App.config = config;
const config = getConfig();
if (!config) {
this.quit();
return;
}
this._closeDelay = config.closeWindowDelay || {};
if (config.style)
App.applyCss(config.style);
config.windows?.forEach(window => {
const w = Window(window);
w.connect('notify::visible', () => this.emit('window-toggled', w.name, w.visible));
if (this._windows.has(w.name)) {
error('name of window has to be unique!');
if (!config) {
this.quit();
return;
}
this._windows.set(w.name, w);
});
this._closeDelay = config.closeWindowDelay || {};
this.emit('config-parsed');
if (config.style)
App.applyCss(config.style);
config.windows?.forEach(w => {
w.connect('notify::visible', () => this.emit('window-toggled', w.name, w.visible));
if (this._windows.has(w.name)) {
console.error('name of window has to be unique!');
this.quit();
return;
}
this._windows.set(w.name, w);
});
this.emit('config-parsed');
} catch (error) {
logError(error as Error);
}
}
_addAction(
+108 -48
View File
@@ -3,7 +3,6 @@ import GLib from 'gi://GLib';
import * as Utils from './utils.js';
import App from './app.js';
import Service from './service/service.js';
import Window from './window.js';
import Widget from './widget.js';
import './service/apps.js';
import './service/audio.js';
@@ -14,10 +13,10 @@ import './service/mpris.js';
import './service/network.js';
import './service/notifications.js';
const APP_BUS = 'com.github.Aylur.' + pkg.name;
const APP_BUS = (name: string) => 'com.github.Aylur.' + name;
const APP_PATH = '/com/github/Aylur/' + pkg.name;
export const help = (bin: string) => `USAGE:
const help = (bin: string) => `USAGE:
${bin} [COMMAND] <ARGUMENTS>
COMMANDS:
@@ -29,64 +28,125 @@ COMMANDS:
run-js string\tRuns string as a js function
inspector\t\tOpen debugger`;
function client(bus: string, inspector: boolean, runJs: string, toggleWindow: string, quit: boolean) {
const actions = Gio.DBusActionGroup.get(
Gio.DBus.session, bus, APP_PATH);
if (toggleWindow)
actions.activate_action('toggle-window', new GLib.Variant('s', toggleWindow));
if (runJs)
actions.activate_action('run-js', new GLib.Variant('s', runJs));
if (inspector)
actions.activate_action('inspector', null);
if (quit)
actions.activate_action('quit', null);
}
function isRunning(dbusName: string) {
return Gio.DBus.session.call_sync(
'org.freedesktop.DBus',
'/org/freedesktop/DBus',
'org.freedesktop.DBus',
'NameHasOwner',
// @ts-ignore
GLib.Variant.new_tuple([new GLib.Variant('s', dbusName)]),
new GLib.VariantType('(b)'),
Gio.DBusCallFlags.NONE,
-1,
null,
).deepUnpack()?.toString() === 'true' || false;
}
export function main(args: string[]) {
switch (args[1]) {
case 'version':
case '-v':
case '--version':
print(pkg.version);
return;
let appBus = pkg.name;
let config = `${GLib.get_user_config_dir()}/${pkg.name}/config.js`;
let inspector = false;
let runJs = '';
let toggleWindow = '';
let quit = false;
case 'help':
case '-h':
case '--help':
print(help(args[0]));
return;
args.forEach((arg, i) => {
switch (arg) {
case 'version':
case '-v':
case '--version':
print(pkg.version);
return;
case 'clear-cache':
Utils.exec(`rm -r ${Utils.CACHE_DIR}`);
return;
case 'help':
case '-h':
case '--help':
print(help(args[0]));
return;
default:
break;
}
case 'clear-cache':
case '--clear-cache':
Utils.execAsync(`rm -r ${Utils.CACHE_DIR}`);
break;
case '-b':
case '--bus-name':
appBus = args[i + 1];
break;
case '-c':
case '--config':
config = args[i + 1];
break;
case 'inspector':
case '-i':
case '--inspector':
inspector = true;
break;
case 'run-js':
case '-r':
case '--run-js':
runJs = args[i + 1];
break;
case 'toggle-window':
case '-t':
case '--toggle-window':
toggleWindow = args[i + 1];
break;
case 'quit':
case '-q':
case '--quit':
quit = true;
break;
default:
break;
}
});
// @ts-ignore
globalThis.ags = {
App,
Utils,
Window,
Widget,
Service,
};
if (!Utils.isRunning(APP_BUS))
const bus = APP_BUS(appBus);
if (!isRunning(bus)) {
const app = new App({ bus, config });
app.connect('config-parsed', () => {
client(bus, inspector, runJs, toggleWindow, quit);
});
// @ts-ignore
return new App().runAsync(null);
const actions = Gio.DBusActionGroup.get(
Gio.DBus.session, APP_BUS, APP_PATH,
);
switch (args[1]) {
case 'toggle-window':
actions.activate_action('toggle-window', new GLib.Variant('s', args[2]));
return;
case 'run-js':
actions.activate_action('run-js', new GLib.Variant('s', args[2]));
return;
case 'inspector':
actions.activate_action('inspector', null);
return;
case 'quit':
actions.activate_action('quit', null);
return;
default:
print(help(args[0]));
return;
return app.runAsync(null);
}
client(bus, inspector, runJs, toggleWindow, quit);
if (args.length === 1)
print('Ags is already running');
}
+5 -5
View File
@@ -139,11 +139,11 @@ class BluetoothService extends Service {
get state() {
switch (this._client.default_adapter_state) {
case GnomeBluetooth.AdapterState.ON: return 'on';
case GnomeBluetooth.AdapterState.TURNING_ONON: return 'turning-on';
case GnomeBluetooth.AdapterState.OFF: return 'off';
case GnomeBluetooth.AdapterState.TURNING_OFF: return 'turning-off';
default: return 'absent';
case GnomeBluetooth.AdapterState.ON: return 'on';
case GnomeBluetooth.AdapterState.TURNING_ONON: return 'turning-on';
case GnomeBluetooth.AdapterState.OFF: return 'off';
case GnomeBluetooth.AdapterState.TURNING_OFF: return 'turning-off';
default: return 'absent';
}
}
+58 -58
View File
@@ -1,6 +1,6 @@
import GLib from 'gi://GLib';
import Service from './service.js';
import { error, execAsync, subprocess } from '../utils.js';
import { execAsync, subprocess } from '../utils.js';
const HIS = GLib.getenv('HYPRLAND_INSTANCE_SIGNATURE');
@@ -33,7 +33,7 @@ class HyprlandService extends Service {
constructor() {
if (!HIS)
error('Hyprland is not running');
console.error('Hyprland is not running');
super();
this._active = {
@@ -112,71 +112,71 @@ class HyprlandService extends Service {
try {
switch (e) {
case 'workspace':
case 'focusedmon':
case 'monitorremoved':
case 'monitoradded':
await this._syncMonitors();
break;
case 'workspace':
case 'focusedmon':
case 'monitorremoved':
case 'monitoradded':
await this._syncMonitors();
break;
case 'createworkspace':
case 'destroyworkspace':
await this._syncWorkspaces();
break;
case 'createworkspace':
case 'destroyworkspace':
await this._syncWorkspaces();
break;
case 'openwindow':
case 'movewindow':
case 'windowtitle':
await this._syncClients();
await this._syncWorkspaces();
break;
case 'openwindow':
case 'movewindow':
case 'windowtitle':
await this._syncClients();
await this._syncWorkspaces();
break;
case 'moveworkspace':
await this._syncWorkspaces();
await this._syncMonitors();
break;
case 'moveworkspace':
await this._syncWorkspaces();
await this._syncMonitors();
break;
case 'activewindow':
this._active.client.class = argv[0];
this._active.client.title = argv[1];
break;
case 'activewindow':
this._active.client.class = argv[0];
this._active.client.title = argv[1];
break;
case 'activewindowv2':
this._active.client.address = argv[0];
break;
case 'activewindowv2':
this._active.client.address = argv[0];
break;
case 'closewindow':
this._active.client = {
class: '',
title: '',
address: '',
};
await this._syncClients();
await this._syncWorkspaces();
break;
case 'closewindow':
this._active.client = {
class: '',
title: '',
address: '',
};
await this._syncClients();
await this._syncWorkspaces();
break;
case 'urgent':
this.emit('urgent-window', argv[0]);
break;
case 'urgent':
this.emit('urgent-window', argv[0]);
break;
case 'activelayout': {
const [kbName, layoutName] = argv[0].split(',');
this.emit('keyboard-layout', `${kbName}`, `${layoutName}`);
break;
}
case 'changefloating': {
const client = this._clients.get(argv[0]);
if (client)
// @ts-ignore
client.floating = argv[1] === '1';
break;
}
case 'submap':
this.emit('submap', argv[0]);
break;
case 'activelayout': {
const [kbName, layoutName] = argv[0].split(',');
this.emit('keyboard-layout', `${kbName}`, `${layoutName}`);
break;
}
case 'changefloating': {
const client = this._clients.get(argv[0]);
if (client)
// @ts-ignore
client.floating = argv[1] === '1';
break;
}
case 'submap':
this.emit('submap', argv[0]);
break;
default:
break;
default:
break;
}
} catch (error) {
logError(error as Error);
+11 -11
View File
@@ -209,17 +209,17 @@ class MprisPlayer extends GObject.Object {
shuffle() { this._playerProxy.Shuffle = !this._playerProxy.Shuffle; }
loop() {
switch (this._playerProxy.LoopStatus) {
case 'None':
this._playerProxy.LoopStatus = 'Track';
break;
case 'Track':
this._playerProxy.LoopStatus = 'Playlist';
break;
case 'Playlist':
this._playerProxy.LoopStatus = 'None';
break;
default:
break;
case 'None':
this._playerProxy.LoopStatus = 'Track';
break;
case 'Track':
this._playerProxy.LoopStatus = 'Playlist';
break;
case 'Playlist':
this._playerProxy.LoopStatus = 'None';
break;
default:
break;
}
}
}
+18 -18
View File
@@ -4,29 +4,29 @@ import { bulkConnect } from '../utils.js';
const _INTERNET = (device: NM.Device) => {
switch (device?.active_connection?.state) {
case NM.ActiveConnectionState.ACTIVATED: return 'connected';
case NM.ActiveConnectionState.ACTIVATING: return 'connecting';
case NM.ActiveConnectionState.DEACTIVATING:
case NM.ActiveConnectionState.DEACTIVATED:
default: return 'disconnected';
case NM.ActiveConnectionState.ACTIVATED: return 'connected';
case NM.ActiveConnectionState.ACTIVATING: return 'connecting';
case NM.ActiveConnectionState.DEACTIVATING:
case NM.ActiveConnectionState.DEACTIVATED:
default: return 'disconnected';
}
};
const _DEVICE_STATE = (device: NM.Device) => {
switch (device?.state) {
case NM.DeviceState.UNMANAGED: return 'unmanaged';
case NM.DeviceState.UNAVAILABLE: return 'unavailable';
case NM.DeviceState.DISCONNECTED: return 'disconnected';
case NM.DeviceState.PREPARE: return 'prepare';
case NM.DeviceState.CONFIG: return 'config';
case NM.DeviceState.NEED_AUTH: return 'need_auth';
case NM.DeviceState.IP_CONFIG: return 'ip_config';
case NM.DeviceState.IP_CHECK: return 'ip_check';
case NM.DeviceState.SECONDARIES: return 'secondaries';
case NM.DeviceState.ACTIVATED: return 'activated';
case NM.DeviceState.DEACTIVATING: return 'deactivating';
case NM.DeviceState.FAILED: return 'failed';
default: return 'unknown';
case NM.DeviceState.UNMANAGED: return 'unmanaged';
case NM.DeviceState.UNAVAILABLE: return 'unavailable';
case NM.DeviceState.DISCONNECTED: return 'disconnected';
case NM.DeviceState.PREPARE: return 'prepare';
case NM.DeviceState.CONFIG: return 'config';
case NM.DeviceState.NEED_AUTH: return 'need_auth';
case NM.DeviceState.IP_CONFIG: return 'ip_config';
case NM.DeviceState.IP_CHECK: return 'ip_check';
case NM.DeviceState.SECONDARIES: return 'secondaries';
case NM.DeviceState.ACTIVATED: return 'activated';
case NM.DeviceState.DEACTIVATING: return 'deactivating';
case NM.DeviceState.FAILED: return 'failed';
default: return 'unknown';
}
};
+3 -2
View File
@@ -2,8 +2,9 @@ import Gio from 'gi://Gio';
import GdkPixbuf from 'gi://GdkPixbuf';
import GLib from 'gi://GLib';
import Service from './service.js';
import App from '../app.js';
import { NotificationIFace } from '../dbus/notifications.js';
import { NOTIFICATIONS_CACHE_PATH, ensureDirectory, getConfig, readFileAsync, timeout, writeFile } from '../utils.js';
import { NOTIFICATIONS_CACHE_PATH, ensureDirectory, readFileAsync, timeout, writeFile } from '../utils.js';
interface action {
id: string
@@ -45,7 +46,7 @@ class NotificationsService extends Service {
_notifications: Map<number, Notification>;
_dnd = false;
_idCount = 0;
_timeout = getConfig()?.notificationPopupTimeout || 3000;
_timeout = App.config.notificationPopupTimeout || 3000;
constructor() {
super();
+1 -89
View File
@@ -2,71 +2,11 @@ import Gtk from 'gi://Gtk?version=3.0';
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import App from './app.js';
import { type Window } from './window.js';
interface Config {
windows?: Window[]
style?: string
stackTraceOnError?: boolean
baseIconSize?: number
notificationPopupTimeout?: number
exitOnError?: boolean
closeWindowDelay: { [key: string]: number }
}
export const USER = GLib.get_user_name();
export const CACHE_DIR = `${GLib.get_user_cache_dir()}/${pkg.name}`;
export const MEDIA_CACHE_PATH = `${CACHE_DIR}/media`;
export const NOTIFICATIONS_CACHE_PATH = `${CACHE_DIR}/notifications`;
export const CONFIG_DIR = `${GLib.get_user_config_dir()}/${pkg.name}`;
export function error(message: string) {
getConfig()?.stackTraceOnError
? logError(new Error(message))
: print(`AGS ERROR: ${message}`);
if (getConfig()?.exitOnError)
App.quit();
}
export function warning(message: string) {
getConfig()?.stackTraceOnError
? logError(new Error(message))
: print(`AGS WARNING: ${message}`);
}
export function typecheck(key: string, value: unknown, type: string | string[], widget: string) {
if (Array.isArray(type)) {
for (const t of type) {
if (t === 'array' && Array.isArray(value))
return true;
if (typeof value === t)
return true;
}
warning(`"${key}" has to be one of ${type.join(' or ')} on ${widget}`);
return false;
}
if (type === 'array' && Array.isArray(value))
return true;
if (typeof value === type)
return true;
warning(`"${key}" has to be a ${type} on ${widget} but it is of type ${typeof value}`);
return false;
}
export function restcheck(rest: object, widget: string) {
const keys = Object.keys(rest);
if (keys.length === 0)
return;
warning(`unknown keys on ${widget}: ${JSON.stringify(keys)}`);
}
export function readFile(path: string) {
try {
@@ -164,7 +104,7 @@ export function timeout(ms: number, callback: () => void) {
export function runCmd(cmd: string | ((...args: any[]) => boolean), ...args: any[]) {
if (typeof cmd !== 'string' && typeof cmd !== 'function') {
warning('Command has to be string or function');
console.error('Command has to be string or function');
return false;
}
@@ -182,19 +122,6 @@ export function runCmd(cmd: string | ((...args: any[]) => boolean), ...args: any
return false;
}
export function getConfig() {
try {
imports.searchPath.push(CONFIG_DIR);
return imports.config.config as Config;
} catch (err) {
GLib.file_test(CONFIG_DIR + '/config.js', GLib.FileTest.EXISTS)
? logError(err as Error)
: print('No config was provided');
return null;
}
}
export function lookUpIcon(name?: string, size = 16) {
if (!name)
return null;
@@ -222,21 +149,6 @@ export function ensureDirectory(path?: string) {
}
}
export function isRunning(dbusName: string) {
return Gio.DBus.session.call_sync(
'org.freedesktop.DBus',
'/org/freedesktop/DBus',
'org.freedesktop.DBus',
'NameHasOwner',
// @ts-ignore
GLib.Variant.new_tuple([new GLib.Variant('s', dbusName)]),
new GLib.VariantType('(b)'),
Gio.DBusCallFlags.NONE,
-1,
null,
).deepUnpack()?.toString() === 'true' || false;
}
export function execAsync(cmd: string | string[]): Promise<string> {
const proc = Gio.Subprocess.new(
typeof cmd === 'string' ? cmd.split(' ') : cmd,
+13 -198
View File
@@ -1,7 +1,4 @@
import Gtk from 'gi://Gtk?version=3.0';
import { typecheck, error, warning, interval } from './utils.js';
import * as Widgets from './widgets.js';
import { constructor } from './widgets/shared.js';
import Box from './widgets/box.js';
import CenterBox from './widgets/centerbox.js';
import EventBox from './widgets/eventbox.js';
@@ -17,209 +14,27 @@ import ProgressBar from './widgets/progressbar.js';
import Entry from './widgets/entry.js';
import { Menu, MenuItem } from './widgets/menu.js';
import Window from './widgets/window.js';
import constructor from './widgets/shared.js';
interface ServiceAPI {
instance: {
connectWidget: (widget: Gtk.Widget, callback: (widget: Gtk.Widget, ...args: any[]) => void, event?: string) => void
}
function Widget({ type, ...params }: { type: { new(...args: any[]): Gtk.Widget } }) {
return constructor(type, params);
}
interface Widget {
type: string | (() => Gtk.Widget)
className?: string
style?: string
halign?: 'start' | 'center' | 'end' | 'fill'
valign?: 'start' | 'center' | 'end' | 'fill'
hexpand?: boolean
vexpand?: boolean
sensitive?: boolean
tooltip?: string
visible?: boolean
connections?: (
[string, (...args: any[]) => any] |
[number, (...args: any[]) => any] |
[ServiceAPI, (...args: any[]) => any, string]
)[]
properties?: [any, any][]
setup?: (widget: Gtk.Widget) => void
}
const widgets: { [key: string]: (props: any) => Gtk.Widget } = {
'box': Widgets.Box,
'button': Widgets.Button,
'centerbox': Widgets.CenterBox,
'dynamic': Widgets.Dynamic,
'entry': Widgets.Entry,
'eventbox': Widgets.EventBox,
'icon': Widgets.Icon,
'label': Widgets.Label,
'overlay': Widgets.Overlay,
'progressbar': Widgets.ProgressBar,
'revealer': Widgets.Revealer,
'scrollable': Widgets.Scrollable,
'slider': Widgets.Slider,
'stack': Widgets.Stack,
'switch': Widgets.Switch,
'menubutton': Widgets.MenuButton,
'popover': Widgets.Popover,
'menu': Widgets.Menu,
'menuitem': Widgets.MenutItem,
};
export function setStyle(widget: Gtk.Widget, css: string) {
const provider = new Gtk.CssProvider();
const style = `* { ${css} }`;
provider.load_from_data(style);
widget.get_style_context().add_provider(provider, Gtk.STYLE_PROVIDER_PRIORITY_USER);
}
export function toggleClassName(widget: Gtk.Widget, className: string, condition = true) {
condition
? widget.get_style_context().add_class(className)
: widget.get_style_context().remove_class(className);
}
function parseParams(widget: Gtk.Widget, {
type, className, style, sensitive, tooltip, connections, properties, setup,
halign, valign, hexpand, vexpand, visible = true,
}: Widget) {
type = type.toString();
typecheck('className', className, ['string', 'undefined'], type);
typecheck('style', style, ['string', 'undefined'], type);
typecheck('sensitive', sensitive, ['boolean', 'undefined'], type);
typecheck('tooltip', tooltip, ['string', 'undefined'], type);
typecheck('halign', halign, ['string', 'undefined'], type);
typecheck('valign', valign, ['string', 'undefined'], type);
typecheck('hexpand', hexpand, ['boolean', 'undefined'], type);
typecheck('vexpand', vexpand, ['boolean', 'undefined'], type);
typecheck('visible', visible, 'boolean', type);
// @ts-ignore
widget.setStyle = (css: string) => setStyle(widget, css);
// @ts-ignore
widget.toggleClassName = (className: string, condition = true) => toggleClassName(widget, className, condition);
if (typeof className === 'string') {
className.split(' ').forEach(cn => {
widget.get_style_context().add_class(cn);
});
}
if (typeof halign === 'string') {
// @ts-ignore
const align = Gtk.Align[halign.toUpperCase()];
if (typeof align !== 'number')
warning('wrong halign value');
widget.halign = align;
}
if (typeof valign === 'string') {
// @ts-ignore
const align = Gtk.Align[valign.toUpperCase()];
if (typeof align !== 'number')
warning('wrong valign value');
widget.valign = align;
}
if (typeof hexpand === 'boolean')
widget.hexpand = hexpand;
if (typeof vexpand === 'boolean')
widget.vexpand = vexpand;
if (typeof sensitive === 'boolean')
widget.sensitive = sensitive;
if (typeof tooltip === 'string')
widget.set_tooltip_text(tooltip);
if (typeof style === 'string')
setStyle(widget, style);
if (typeof visible === 'boolean')
widget.visible = visible;
if (properties) {
properties.forEach(([key, value]) => {
// @ts-ignore
widget[`_${key}`] = value;
});
}
if (connections) {
connections.forEach(([s, callback, event]) => {
if (typeof s === 'string')
widget.connect(s, callback);
else if (typeof s === 'number')
interval(s, () => callback(widget), widget);
else
s.instance.connectWidget(widget, callback, event);
});
}
if (typeof setup === 'function')
setup(widget);
}
export default function Widget(params: Widget | string | (() => Gtk.Widget) | Gtk.Widget): Gtk.Widget {
if (!params) {
error('Widget from null/undefined');
return new Gtk.Label({ label: `error widget from: "${params}"` });
}
if (typeof params === 'string')
return new Gtk.Label({ label: params });
if (typeof params === 'function')
return params();
if (params instanceof Gtk.Widget)
return params;
const {
type, className, style, halign, valign, connections, properties,
hexpand, vexpand, sensitive, tooltip, visible, setup,
...props
}: Widget = params;
let widget: Gtk.Widget | null = null;
if (typeof type === 'function')
widget = type();
if (typeof type === 'string' && type in widgets)
widget = widgets[type]({ type, ...props });
if (widget === null) {
error(`There is no widget with type ${type}`);
return new Gtk.Label({ label: `${type} doesn't exist` });
}
parseParams(widget, {
type, className, style, halign, valign, connections, properties,
hexpand, vexpand, sensitive, tooltip, visible, setup,
});
return widget;
}
Widget.widgets = widgets;
Widget.Box = (params: object) => constructor(Box, params);
Widget.Button = (params: object) => constructor(Button, params);
Widget.CenterBox = (params: object) => constructor(CenterBox, params);
Widget.Entry = (params: object) => constructor(Entry, params);
Widget.EventBox = (params: object) => constructor(EventBox, params);
Widget.Icon = (params: object) => constructor(Icon, params);
Widget.Label = (params: object) => constructor(Label, params);
Widget.Button = (params: object) => constructor(Button, params);
Widget.Slider = (params: object) => constructor(Slider, params);
Widget.Stack = (params: object) => constructor(Stack, params);
Widget.Scrollable = (params: object) => constructor(Scrollable, params);
Widget.Overlay = (params: object) => constructor(Overlay, params);
Widget.Revealer = (params: object) => constructor(Revealer, params);
Widget.ProgressBar = (params: object) => constructor(ProgressBar, params);
Widget.Menu = (params: object) => constructor(Menu, params);
Widget.MenuItem = (params: object) => constructor(MenuItem, params);
Widget.Entry = (params: object) => constructor(Entry, params);
Widget.Overlay = (params: object) => constructor(Overlay, params);
Widget.ProgressBar = (params: object) => constructor(ProgressBar, params);
Widget.Revealer = (params: object) => constructor(Revealer, params);
Widget.Scrollable = (params: object) => constructor(Scrollable, params);
Widget.Slider = (params: object) => constructor(Slider, params);
Widget.Stack = (params: object) => constructor(Stack, params);
Widget.Window = (params: object) => constructor(Window, params);
Widget.Widget = ({ type, ...params }: { type: { new(...args: any[]): Gtk.Widget } }) => constructor(type, params);
export default Widget;
-690
View File
@@ -1,690 +0,0 @@
import Gtk from 'gi://Gtk?version=3.0';
import Gdk from 'gi://Gdk?version=3.0';
import GLib from 'gi://GLib';
import GdkPixbuf from 'gi://GdkPixbuf';
import Widget from './widget.js';
import { typecheck, runCmd, restcheck, warning, getConfig } from './utils.js';
function _orientation(str = 'horizontal') {
if (str === 'v')
str = 'vertical';
if (str === 'h')
str = 'horizontal';
const orientation = Gtk.Orientation[str.toUpperCase()];
if (typeof orientation !== 'number')
warning('wrong orientation value');
return orientation;
}
export function Box({
type,
orientation = 'horizontal',
homogeneous = false,
children = [],
...rest
}) {
typecheck('orientation', orientation, 'string', type);
typecheck('homogeneous', homogeneous, 'boolean', type);
typecheck('children', children, 'array', type);
restcheck(rest, type);
const box = new Gtk.Box({
orientation: _orientation(orientation),
homogeneous,
});
children.forEach(w => box.add(Widget(w)));
return box;
}
export function EventBox({
type,
onClick = '',
onSecondaryClick = '',
onMiddleClick = '',
onClickRelease = '',
onSecondaryClickRelease = '',
onMiddleClickRelease = '',
onHover = '',
onHoverLost = '',
onScrollUp = '',
onScrollDown = '',
child, ...rest
}) {
typecheck('onClick', onClick, ['string', 'function'], type);
typecheck('onSecondaryClick', onSecondaryClick, ['string', 'function'], type);
typecheck('onMiddleClick', onMiddleClick, ['string', 'function'], type);
typecheck('onClickRelease', onClickRelease, ['string', 'function'], type);
typecheck('onMiddleClickRelease', onMiddleClickRelease, ['string', 'function'], type);
typecheck('onSecondaryClickRelease', onSecondaryClickRelease, ['string', 'function'], type);
typecheck('onHover', onHover, ['string', 'function'], type);
typecheck('onHoverLost', onHoverLost, ['string', 'function'], type);
typecheck('onScrollUp', onScrollUp, ['string', 'function'], type);
typecheck('onScrollDown', onScrollDown, ['string', 'function'], type);
restcheck(rest, type);
const box = new Gtk.EventBox();
box.connect('enter-notify-event', (box, event) => {
box.set_state_flags(Gtk.StateFlags.PRELIGHT, false);
runCmd(onHover, box, event);
});
box.connect('leave-notify-event', (box, event) => {
box.unset_state_flags(Gtk.StateFlags.PRELIGHT);
runCmd(onHoverLost, box, event);
});
box.connect('button-press-event', (box, event) => {
box.set_state_flags(Gtk.StateFlags.ACTIVE, false);
if (event.get_button()[1] === Gdk.BUTTON_PRIMARY)
runCmd(onClick, box, event);
else if (event.get_button()[1] === Gdk.BUTTON_SECONDARY)
runCmd(onSecondaryClick, box, event);
else if (event.get_button()[1] === Gdk.BUTTON_MIDDLE)
runCmd(onMiddleClick, box, event);
});
box.connect('button-release-event', (box, event) => {
box.unset_state_flags(Gtk.StateFlags.ACTIVE);
if (event.get_button()[1] === Gdk.BUTTON_PRIMARY)
runCmd(onClickRelease, box, event);
else if (event.get_button()[1] === Gdk.BUTTON_SECONDARY)
runCmd(onSecondaryClickRelease, box, event);
else if (event.get_button()[1] === Gdk.BUTTON_MIDDLE)
runCmd(onMiddleClickRelease, box, event);
});
if (onScrollUp || onScrollDown) {
box.add_events(Gdk.EventMask.SCROLL_MASK);
box.connect('scroll-event', (box, event) => {
if (event.get_scroll_direction()[1] === Gdk.ScrollDirection.UP)
runCmd(onScrollUp, box, event);
else if (event.get_scroll_direction()[1] === Gdk.ScrollDirection.DOWN)
runCmd(onScrollDown, box, event);
});
}
if (child)
box.add(Widget(child));
return box;
}
export function CenterBox({ type, children = [], ...props }) {
typecheck('children', children, 'array', type);
if (children.length !== 3)
warning(`${type} should have exactly 3 children!`);
const box = Box({ type, ...props });
box.pack_start(Widget(children[0]), true, true, 0);
box.set_center_widget(Widget(children[1]));
box.pack_end(Widget(children[2]), true, true, 0);
return box;
}
export function Icon({
type,
icon = '',
size = getConfig()?.baseIconSize || 16,
...rest
}) {
typecheck('icon', icon, 'string', type);
typecheck('icon', size, 'number', type);
restcheck(rest, type);
return GLib.file_test(icon, GLib.FileTest.EXISTS)
? Gtk.Image.new_from_pixbuf(
GdkPixbuf.Pixbuf.new_from_file_at_size(icon, size, size),
)
: new Gtk.Image({
icon_name: icon,
icon_size: 1,
pixel_size: size,
});
}
export function Label({
type,
label = '',
markup = false,
wrap = false,
maxWidth = -1,
angle = 0,
justify = 'center',
xalign = 0.5,
yalign = 0.5,
...rest
}) {
typecheck('label', label, 'string', type);
typecheck('markup', markup || false, 'boolean', type);
typecheck('wrap', wrap || false, 'boolean', type);
typecheck('angle', angle || 0, 'number', type);
typecheck('justify', justify || '', 'string', type);
typecheck('xalign', xalign, 'number', type);
typecheck('yalign', yalign, 'number', type);
restcheck(rest, type);
const _justify = Gtk.Justification[justify.toUpperCase()];
if (typeof _justify !== 'number')
warning('wrong justify value');
const lbl = new Gtk.Label({
label,
angle,
justify: _justify,
use_markup: markup,
max_width_chars: maxWidth,
wrap,
xalign,
yalign,
});
return lbl;
}
export function Button({
type,
child,
onClick = '',
onMiddleClick = '',
onSecondaryClick = '',
onClickRelease = '',
onMiddleClickRelease = '',
onSecondaryClickRelease = '',
onScrollUp = '',
onScrollDown = '',
...rest
}) {
typecheck('onClick', onClick, ['string', 'function'], type);
typecheck('onMiddleClick', onMiddleClick, ['string', 'function'], type);
typecheck('onSecondaryClick', onSecondaryClick, ['string', 'function'], type);
typecheck('onClickRelease', onClickRelease, ['string', 'function'], type);
typecheck('onMiddleClickRelease', onMiddleClickRelease, ['string', 'function'], type);
typecheck('onSecondaryClick', onSecondaryClickRelease, ['string', 'function'], type);
typecheck('onScrollUp', onScrollUp, ['string', 'function'], type);
typecheck('onScrollDown', onScrollDown, ['string', 'function'], type);
restcheck(rest, type);
const btn = new Gtk.Button();
if (child)
btn.add(Widget(child));
btn.connect('button-press-event', (btn, event) => {
if (event.get_button()[1] === Gdk.BUTTON_PRIMARY)
runCmd(onClick, btn, event);
else if (event.get_button()[1] === Gdk.BUTTON_SECONDARY)
runCmd(onSecondaryClick, btn, event);
else if (event.get_button()[1] === Gdk.BUTTON_MIDDLE)
runCmd(onMiddleClick, btn, event);
});
btn.connect('button-release-event', (btn, event) => {
if (event.get_button()[1] === Gdk.BUTTON_PRIMARY)
runCmd(onClickRelease, btn, event);
else if (event.get_button()[1] === Gdk.BUTTON_SECONDARY)
runCmd(onSecondaryClickRelease, btn, event);
else if (event.get_button()[1] === Gdk.BUTTON_MIDDLE)
runCmd(onMiddleClickRelease, btn, event);
});
if (onScrollUp || onScrollDown) {
btn.add_events(Gdk.EventMask.SCROLL_MASK);
btn.connect('scroll-event', (btn, event) => {
if (event.get_scroll_direction()[1] === Gdk.ScrollDirection.UP)
runCmd(onScrollUp, btn, event);
else if (event.get_scroll_direction()[1] === Gdk.ScrollDirection.DOWN)
runCmd(onScrollDown, btn, event);
});
}
return btn;
}
export function Slider({
type,
inverted = false,
orientation = 'horizontal',
min = 0,
max = 1,
value = 0,
onChange = '',
drawValue = false,
...rest
}) {
typecheck('inverted', inverted, 'boolean', type);
typecheck('orientation', orientation, 'string', type);
typecheck('min', min, 'number', type);
typecheck('max', max, 'number', type);
typecheck('onChange', onChange, ['string', 'function'], type);
typecheck('value', value, 'number', type);
typecheck('drawValue', drawValue, 'boolean', type);
restcheck(rest, type);
const slider = new Gtk.Scale({
orientation: _orientation(orientation),
adjustment: new Gtk.Adjustment({
value: min,
lower: min,
upper: max,
step_increment: (max - min) / 100,
}),
draw_value: drawValue,
inverted: inverted,
});
slider.connect('button-press-event', () => { slider._dragging = true; });
slider.connect('button-release-event', () => { slider._dragging = false; });
slider.connect('scroll-event', ({ adjustment }, event) => {
const [, , y] = event.get_scroll_deltas();
slider._dragging = true;
y > 0
? adjustment.value -= adjustment.step_increment
: adjustment.value += adjustment.step_increment;
slider._dragging = false;
});
if (onChange) {
slider.adjustment.connect('notify::value', ({ value }, event) => {
if (!slider._dragging)
return;
typeof onChange === 'function'
? onChange(slider, event, value)
: runCmd(onChange.replace(/\{\}/g, value));
});
}
return slider;
}
export function Dynamic({ type, items = [], ...rest } = {}) {
typecheck('items', items, 'array', type);
restcheck(rest, type);
const children = items.map(({ value, widget }) => {
if (!widget)
return null;
const w = Widget(widget);
w._value = value;
w.hide();
return w;
}).filter(item => item !== null);
const box = Box({ children });
box.update = condition => {
box.hide();
for (const item of children)
item.hide();
for (const item of children) {
if (condition(item._value)) {
box.show();
item.show();
return;
}
}
};
return box;
}
export function Stack({
type,
items = [],
hhomogeneous = true,
vhomogeneous = true,
interpolateSize = false,
transition = 'none',
transitionDuration = 200,
...rest
}) {
typecheck('hhomogeneous', hhomogeneous, 'boolean', type);
typecheck('vhomogeneous', vhomogeneous, 'boolean', type);
typecheck('interpolateSize', interpolateSize, 'boolean', type);
typecheck('transition', transition, 'string', type);
typecheck('transitionDuration', transitionDuration, 'number', type);
typecheck('items', items, 'array', type);
restcheck(rest, type);
const transitionType = Gtk.StackTransitionType[transition.toUpperCase()];
if (typeof transitionType !== 'number')
warning('wrong transition value');
const stack = new Gtk.Stack({
hhomogeneous,
vhomogeneous,
interpolateSize,
transitionDuration,
transitionType,
});
items.forEach(([name, widget]) => {
if (widget)
stack.add_named(Widget(widget), name);
});
stack.showChild = name => {
const n = typeof name === 'function' ? name() : name;
stack.visible = true;
stack.get_child_by_name(n)
? stack.set_visible_child_name(n)
: stack.visible = false;
};
return stack;
}
export function Entry({
type,
text = '',
placeholder = '',
onChange = '',
onAccept = '',
password = false,
...rest
}) {
typecheck('text', text, 'string', type);
typecheck('placeholder', placeholder, 'string', type);
typecheck('onChange', onChange, ['string', 'function'], type);
typecheck('onAccept', onAccept, ['string', 'function'], type);
typecheck('password', password, 'boolean', type);
restcheck(rest, type);
const entry = new Gtk.Entry({
placeholder_text: placeholder,
visibility: !password,
text,
});
if (onAccept) {
entry.connect('activate', ({ text }, event) => {
typeof onAccept === 'function'
? onAccept(entry, event, text)
: runCmd(onAccept.replace(/\{\}/g, text));
});
}
if (onChange) {
entry.connect('notify::text', ({ text }, event) => {
typeof onAccept === 'function'
? onChange(entry, event, text)
: runCmd(onChange.replace(/\{\}/g, text));
});
}
return entry;
}
export function Scrollable({
type,
child,
hscroll = 'automatic',
vscroll = 'automatic',
...rest
}) {
typecheck('hscroll', hscroll, 'string', type);
typecheck('vscroll', vscroll, 'string', type);
restcheck(rest, type);
const scrollable = new Gtk.ScrolledWindow({
hadjustment: new Gtk.Adjustment(),
vadjustment: new Gtk.Adjustment(),
});
scrollable.set_policy(
Gtk.PolicyType[hscroll.toUpperCase()],
Gtk.PolicyType[vscroll.toUpperCase()],
);
if (child)
scrollable.add(Widget(child));
return scrollable;
}
export function Revealer({
type,
transition = 'crossfade',
duration = 250,
revealChild = false,
child,
...rest
}) {
typecheck('transition', transition, 'string', type);
typecheck('duration', duration, 'number', type);
typecheck('revealChild', revealChild, 'boolean', type);
restcheck(rest, type);
const transitionType = Gtk.RevealerTransitionType[transition.toUpperCase()];
if (typeof transitionType !== 'number')
warning('wrong transition type');
const revealer = new Gtk.Revealer({
transitionType,
revealChild,
transitionDuration: duration,
});
if (child)
revealer.add(Widget(child));
return revealer;
}
export function Overlay({ type, children = [], passthrough = true, ...rest }) {
typecheck('passthrough', passthrough, 'boolean', type);
typecheck('children', children, 'array', type);
restcheck(rest, type);
const overlay = new Gtk.Overlay();
if (children[0]) {
overlay.add(Widget(children[0]));
children.splice(1).forEach(ch => overlay.add_overlay(Widget(ch)));
}
if (passthrough)
overlay.get_children().forEach(ch => overlay.set_overlay_pass_through(ch, true));
return overlay;
}
export function ProgressBar({
type,
value = 0,
inverted = false,
orientation = 'horizontal',
...rest
}) {
typecheck('inverted', inverted, 'boolean', type);
typecheck('orientation', orientation, 'string', type);
typecheck('value', value, 'number', type);
restcheck(rest, type);
const bar = new Gtk.ProgressBar({
orientation: _orientation(orientation),
inverted,
fraction: value,
});
bar.setValue = v => bar.set_fraction(v);
return bar;
}
export function Switch({
type,
active = false,
onActivate = '',
...rest
}) {
typecheck('active', active, 'boolean', type);
typecheck('onActivate', onActivate, ['string', 'function'], type);
restcheck(rest, type);
const gtkswitch = new Gtk.Switch({ active });
if (onActivate) {
gtkswitch.connect('notify::active', ({ active }, event) => {
typeof onActivate === 'function'
? onActivate(gtkswitch, event, active)
: runCmd(onActivate.replace(/\{\}/g, active));
});
}
return gtkswitch;
}
export function Popover({
type,
child,
modal = true,
position = 'bottom',
pointingTo,
relativeTo,
...rest
}) {
typecheck('position', position, 'string', type);
typecheck('modal', modal, 'boolean', type);
typecheck('pointingTo', pointingTo, ['undefined', 'object'], type);
restcheck(rest, type);
const _position = Gtk.PositionType[position.toUpperCase()];
if (typeof _position !== 'number')
warning('wrong position value');
const popover = new Gtk.Popover({
position: _position,
modal,
});
if (child)
popover.add(Widget(child));
if (pointingTo)
popover.set_pointing_to(new Gdk.Rectangle(pointingTo));
if (relativeTo)
popover.set_relative_to(relativeTo);
return popover;
}
export function MenuButton({
type,
child,
popover,
popup,
onToggled = '',
...rest
}) {
typecheck('onToggled', onToggled, ['string', 'function'], type);
restcheck(rest, type);
const button = new Gtk.MenuButton({
use_popover: true,
});
if (onToggled)
button.connect('toggled', (...args) => runCmd(onToggled, ...args));
if (popover)
button.set_popover(Widget(popover));
if (popup)
button.set_popup(Widget(popup));
if (child)
button.add(Widget(child));
return button;
}
export function Menu({
type,
children = [],
yOffset = 0,
xOffset = 0,
onPopup = '',
onMoveScroll = '',
attachTo,
...rest
}) {
typecheck('children', children, 'array', type);
typecheck('yOffset', yOffset, 'number', type);
typecheck('xOffset', xOffset, 'number', type);
typecheck('onPopup', onPopup, ['string', 'function'], type);
typecheck('onMoveScroll', onMoveScroll, ['string', 'function'], type);
restcheck(rest, type);
const menu = new Gtk.Menu({
rect_anchor_dx: xOffset,
rect_anchor_dy: yOffset,
});
children.forEach(item => {
menu.add(Widget(item));
});
if (attachTo)
menu.attach_widget = attachTo;
if (onPopup)
menu.connect('popped-up', (...args) => runCmd(onPopup, ...args));
if (onMoveScroll)
menu.connect('move-scroll', (...args) => runCmd(onMoveScroll, ...args));
menu.show_all();
menu.hide();
return menu;
}
export function MenutItem({
type,
child,
submenu,
onActivate = '',
onSelect = '',
onDeselect = '',
...rest
}) {
typecheck('onActivate', onActivate, ['string', 'function'], type);
typecheck('onSelect', onSelect, ['string', 'function'], type);
typecheck('onDeselect', onDeselect, ['string', 'function'], type);
restcheck(rest, type);
const item = new Gtk.MenuItem();
if (child)
item.add(Widget(child));
if (submenu)
item.submenu = Widget(submenu);
[[onActivate, 'activate'], [onSelect, 'select'], [onDeselect, 'deselect']]
.forEach(([handler, signal]) => {
if (handler)
item.connect(signal, (...args) => runCmd(handler, ...args));
});
return item;
}
+4 -4
View File
@@ -1,5 +1,5 @@
import Gtk from 'gi://Gtk?version=3.0';
import { warning, interval } from '../utils.js';
import { interval } from '../utils.js';
interface ServiceAPI {
instance: {
@@ -65,7 +65,7 @@ function parseCommon(widget: Gtk.Widget, {
// @ts-ignore
const align = Gtk.Align[halign.toUpperCase()];
if (typeof align !== 'number')
warning('wrong halign value');
console.error('wrong halign value');
widget.halign = align;
}
@@ -73,7 +73,7 @@ function parseCommon(widget: Gtk.Widget, {
// @ts-ignore
const align = Gtk.Align[valign.toUpperCase()];
if (typeof align !== 'number')
warning('wrong valign value');
console.error('wrong valign value');
widget.valign = align;
}
@@ -104,7 +104,7 @@ function parseCommon(widget: Gtk.Widget, {
setup(widget);
}
export function constructor(ctor: { new(...args: any[]): Gtk.Widget }, params: CommonParams | string = {}) {
export default function constructor(ctor: { new(...args: any[]): Gtk.Widget }, params: CommonParams | string = {}) {
let widget;
if (typeof params === 'string') {
widget = new ctor(params);
-145
View File
@@ -1,145 +0,0 @@
import Gtk from 'gi://Gtk?version=3.0';
import Gdk from 'gi://Gdk?version=3.0';
import { restcheck, typecheck, warning } from './utils.js';
import Widget from './widget.js';
import App from './app.js';
import { setStyle, toggleClassName } from './widget.js';
imports.gi.versions.GtkLayerShell = '0.1';
const { GtkLayerShell: GtkLayerShell } = imports.gi;
export interface Window {
anchor?: string[]
child?: { type: string } | Gtk.Widget | null
className?: string
exclusive?: boolean
focusable?: boolean
layer?: string
margin?: number[] | number
monitor?: number
name?: string
popup?: boolean
style?: string
visible?: boolean
setup?: (win: Gtk.Window) => void,
}
export default function Window({
name = 'gtk-layer-shell',
anchor = [],
margin = [],
layer = 'top',
exclusive = false,
popup = false,
focusable = false,
child = null,
className = '',
style = '',
monitor,
visible = true,
setup,
...rest
}: Window): Gtk.Window {
typecheck('name', name, 'string', 'window');
typecheck('anchor', anchor, 'array', 'window');
typecheck('margin', margin, ['number', 'array'], 'window');
typecheck('layer', layer, 'string', 'window');
typecheck('exclusive', exclusive, 'boolean', 'window');
typecheck('popup', popup, 'boolean', 'window');
typecheck('focusable', focusable, 'boolean', 'window');
typecheck('className', className, 'string', 'window');
typecheck('monitor', monitor, ['number', 'undefined'], 'window');
restcheck(rest, `window: ${name}`);
const win = new Gtk.Window({ name });
GtkLayerShell.init_for_window(win);
GtkLayerShell.set_namespace(win, name);
// @ts-ignore
win.setStyle = (css: string) => setStyle(win, css);
// @ts-ignore
win.toggleClassName = (className: string, condition) => toggleClassName(win, className, condition);
if (anchor) {
anchor.forEach(side => GtkLayerShell
.set_anchor(
win,
GtkLayerShell.Edge[side.toUpperCase()],
true,
),
);
}
if (margin) {
let margins: [side: string, index: number][] = [];
if (typeof margin === 'number')
margin = [margin];
switch (margin.length) {
case 1:
margins = [['TOP', 0], ['RIGHT', 0], ['BOTTOM', 0], ['LEFT', 0]];
break;
case 2:
margins = [['TOP', 0], ['RIGHT', 1], ['BOTTOM', 0], ['LEFT', 1]];
break;
case 3:
margins = [['TOP', 0], ['RIGHT', 1], ['BOTTOM', 2], ['LEFT', 1]];
break;
case 4:
margins = [['TOP', 0], ['RIGHT', 1], ['BOTTOM', 2], ['LEFT', 3]];
break;
default:
break;
}
margins.forEach(([side, i]) =>
GtkLayerShell.set_margin(win, GtkLayerShell.Edge[side], (margin as number[])[i]),
);
}
GtkLayerShell.set_layer(win, GtkLayerShell.Layer[layer?.toUpperCase()]);
if (exclusive)
GtkLayerShell.auto_exclusive_zone_enable(win);
if (typeof monitor === 'number') {
const display = Gdk.Display.get_default();
display
? GtkLayerShell.set_monitor(win, display.get_monitor(monitor))
: warning(`Could not find monitor with id: ${monitor}`);
}
if (className) {
className.split(' ').forEach(cn => {
win.get_style_context().add_class(cn);
});
}
if (style)
setStyle(win, style);
if (child)
win.add(Widget(child));
if (popup) {
win.connect('key-press-event', (_, event) => {
if (event.get_keyval()[1] === Gdk.KEY_Escape)
App.getWindow(name) ? App.closeWindow(name) : win.hide();
});
visible = false;
}
if (focusable)
GtkLayerShell.set_keyboard_mode(win, GtkLayerShell.KeyboardMode.ON_DEMAND);
win.show_all();
if (typeof visible === 'boolean')
win.visible = visible;
if (setup)
setup(win);
return win;
}