mirror of
https://github.com/zoriya/ags.git
synced 2026-06-09 04:46:08 +00:00
es modules and clean up codebase
This commit is contained in:
+10
-12
@@ -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
@@ -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
@@ -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');
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user