From ba23ca40a1b35a11714a4c3525182cec58bec400 Mon Sep 17 00:00:00 2001 From: Aylur Date: Sat, 19 Aug 2023 03:22:58 +0200 Subject: [PATCH] export widgets, update the example --- example/config.js | 270 ++++++++++++++++++++----------------- src/ags.js.in | 4 +- src/ags.src.gresource.xml | 2 +- src/app.ts | 4 +- src/main.ts | 4 +- src/widget.ts | 91 +++++++------ src/widgets/box.ts | 2 +- src/widgets/button.ts | 2 +- src/widgets/centerbox.ts | 4 +- src/widgets/entry.ts | 2 +- src/widgets/eventbox.ts | 2 +- src/widgets/icon.ts | 2 +- src/widgets/label.ts | 2 +- src/widgets/menu.ts | 4 +- src/widgets/overlay.ts | 2 +- src/widgets/progressbar.ts | 2 +- src/widgets/revealer.ts | 2 +- src/widgets/scrollable.ts | 2 +- src/widgets/shared.ts | 8 +- src/widgets/slider.ts | 28 ++-- src/widgets/stack.ts | 2 +- src/widgets/window.ts | 4 +- 22 files changed, 239 insertions(+), 206 deletions(-) diff --git a/example/config.js b/example/config.js index a4d9715..3c99c1d 100644 --- a/example/config.js +++ b/example/config.js @@ -1,188 +1,212 @@ -// importing -const { Hyprland, Notifications, Mpris, Audio, Battery } = ags.Service; -const { exec, CONFIG_DIR } = ags.Utils; +// importing +import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js'; +import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js'; +import Mpris from 'resource:///com/github/Aylur/ags/service/mpris.js'; +import Audio from 'resource:///com/github/Aylur/ags/service/audio.js'; +import Battery from 'resource:///com/github/Aylur/ags/service/battery.js'; +import App from 'resource:///com/github/Aylur/ags/app.js'; +import { + Box, Button, Stack, Label, Icon, CenterBox, Window, Slider, ProgressBar +} from 'resource:///com/github/Aylur/ags/widget.js'; +import { exec, execAsync } from 'resource:///com/github/Aylur/ags/utils.js'; -const workspaces = { - type: 'box', +// import statements are long, so there is also the global ags object you can import from +// const { Hyprland, Notifications, Mpris, Audio, Battery } = ags.Service; +// const { App } = ags; +// const { exec } = ags.Utils; +// const { +// Box, Button, Stack, Label, Icon, CenterBox, Window, Slider, ProgressBar +// } = ags.Widget; + +// every widget is a subclass of Gtk. +// with a few extra available properties +// for example Box is a subclass of Gtk.Box + +// widgets can be only assigned as a child in one container +// so to make a reuseable widget, just make it a function +// then you can use it by calling simply calling it +const Workspaces = () => Box({ className: 'workspaces', - // box is an instance of Gtk.Box connections: [[Hyprland, box => { - // remove every children - box.get_children().forEach(ch => ch.destroy()); - - // add a button for each workspace - const workspaces = 10; - for (let i = 1; i <= workspaces; ++i) { - box.add(ags.Widget({ - type: 'button', - onClick: () => execAsync(`hyprctl dispatch workspace ${i}`), - child: i.toString(), - className: Hyprland.active.workspace.id == i ? 'focused' : '', - })); - } - - // make the box render it - box.show_all(); + // generate an array [1..10] then make buttons from the index + const arr = Array.from({ length: 10 }, (_, i) => i + 1); + box.children = arr.map(i => Button({ + onClicked: () => execAsync(`hyprctl dispatch workspace ${i}`), + child: Label({ label: `${i}` }), + className: Hyprland.active.workspace.id == i ? 'focused' : '', + })); }]], -}; +}); -const clientTitle = { - type: 'label', +const ClientTitle = () => Label({ className: 'client-title', - // label is an instance of Gtk.Label + // an initial label value can be given but its pointless + // because callbacks from connections are run on construction + // so in this case this is redundant + label: Hyprland.active.client.title || '', connections: [[Hyprland, label => { label.label = Hyprland.active.client.title || ''; }]], -}; +}); -const clock = { - type: 'label', +const Clock = () => Label({ className: 'clock', - // trim is for the whitespace at the end of the date output - // but doing this is actually bad practice - // because exec() will block the main thread, but in case of runnig date - // I don't think it matters - connections: [[1000, label => label.label = exec('date "+%H:%M:%S %b %e."').trim()]], -}; + connections: [ + // this is bad practice, since exec() will block the main event loop + // in the case of a simple date its not really a problem + [1000, label => label.label = exec('date "+%H:%M:%S %b %e."')], + + // this is what you should do + [1000, label => execAsync(['date', '+%H:%M:%S %b %e.']) + .then(date => label.label = date).catch(console.error)], + ], +}); // we don't need dunst or any other notification daemon // because ags has a notification daemon built in -const notification = { - type: 'box', +const Notification = () => Box({ className: 'notification', children: [ - { - type: 'icon', + Icon({ icon: 'preferences-system-notifications-symbolic', - // icon is an instance of Gtk.Image - connections: [[Notifications, icon => icon.visible = Notifications.popups.size > 0]] - }, - { - type: 'label', + connections: [ + [Notifications, icon => icon.visible = Notifications.popups.size > 0], + ], + }), + Label({ connections: [[Notifications, label => { // notifications is a map, to get the last elememnt lets make an array - label.label = Array.from(Notifications.popups)?.pop()?.[1].summary || ''; + label.label = Array.from(Notifications.popups.values())?.pop()?.summary || ''; }]], - }, + }), ], -}; +}); -const media = { - type: 'label', +const Media = () => Button({ + onPrimaryClick: () => Mpris.getPlayer('')?.playPause(), + onScrollUp: () => Mpris.getPlayer('')?.next(), + onScrollDown: () => Mpris.getPlayer('')?.previous(), className: 'media', - connections: [[Mpris, label => { - const mpris = Mpris.getPlayer(''); - if (mpris) - label.label = `${mpris.trackArtists.join(', ')} - ${mpris.trackTitle}`; - else - label.label = 'Nothing is playing'; - }]], -}; + child: Label({ + connections: [[Mpris, label => { + const mpris = Mpris.getPlayer(''); + // mpris player can be undefined + if (mpris) + label.label = `${mpris.trackArtists.join(', ')} - ${mpris.trackTitle}`; + else + label.label = 'Nothing is playing'; + }]], + }), +}); -const volume = { - type: 'box', +const Volume = () => Box({ className: 'volume', style: 'min-width: 180px', children: [ - { - type: 'dynamic', + Stack({ items: [ - { value: 101, widget: { type: 'icon', icon: 'audio-volume-overamplified-symbolic' } }, - { value: 67, widget: { type: 'icon', icon: 'audio-volume-high-symbolic' } }, - { value: 34, widget: { type: 'icon', icon: 'audio-volume-medium-symbolic' } }, - { value: 1, widget: { type: 'icon', icon: 'audio-volume-low-symbolic' } }, - { value: 0, widget: { type: 'icon', icon: 'audio-volume-muted-symbolic' } }, + // tuples of [string, Widget] + ['101', Icon('audio-volume-overamplified-symbolic')], + ['67', Icon('audio-volume-high-symbolic')], + ['34', Icon('audio-volume-medium-symbolic')], + ['1', Icon('audio-volume-low-symbolic')], + ['0', Icon('audio-volume-muted-symbolic')], ], - // dynamic is a Gtk.Box with an extra update method - connections: [[Audio, dynamic => dynamic.update(value => { + connections: [[Audio, stack => { if (!Audio.speaker) return; - if (Audio.speaker.isMuted) - return value === 0; + if (Audio.speaker.isMuted) { + stack.shown = '0'; + return; + } - return value <= (Audio.speaker.volume*100); - }), 'speaker-changed']], - }, - { - type: 'slider', + const show = [100, 66, 33, 1, 0].find( + threshold => threshold <= Audio.speaker.volume * 100); + + stack.shown = `${show + 1}`; + }, 'speaker-changed']], + }), + Slider({ hexpand: true, + drawValue: false, onChange: value => Audio.speaker.volume = value, connections: [[Audio, slider => { if (!Audio.speaker) return; - slider.adjustment.value = Audio.speaker.volume; + slider.value = Audio.speaker.volume; }, 'speaker-changed']], - } + }), ], -}; +}); -const battery = { - type: 'box', +const BatteryLabel = () => Box({ className: 'battery', children: [ - { - type: 'icon', + Icon({ connections: [[Battery, icon => { - // icon is an instance of Gtk.Image - icon.icon_name = `battery-level-${Math.floor(Battery.percent/10)*10}-symbolic`; - }]] - }, - { - type: 'progressbar', + icon.icon = `battery-level-${Math.floor(Battery.percent / 10) * 10}-symbolic`; + }]], + }), + ProgressBar({ valign: 'center', - // progressbar is a Gtk.ProgressBar, setValue() just calls set_fraction() - connections: [[Battery, progress => progress.setValue(Battery.percent/100)]], - }, + connections: [[Battery, progress => { + if (Battery.percent < 0) + return; + + progress.fraction = Battery.percent / 100; + }]], + }), ], -}; +}); // layout of the bar -const left = { - type: 'box', +const Left = () => Box({ + className: 'left', children: [ - workspaces, - clientTitle, + Workspaces(), + ClientTitle(), ], -}; +}); -const center = { - type: 'box', +const Center = () => Box({ className: 'center', children: [ - media, - notification, + Media(), + Notification(), ], -}; +}); -const right = { - type: 'box', +const Right = () => Box({ className: 'right', halign: 'end', children: [ - volume, - battery, - clock, + Volume(), + BatteryLabel(), + Clock(), ], -}; +}); -const bar = { - name: 'bar', +const Bar = ({ monitor }) => Window({ + name: `bar${monitor}`, // name has to be unique + monitor, anchor: ['top', 'left', 'right'], exclusive: true, - child: { - type: 'centerbox', - children: [ - left, - center, - right, - ], - }, -} + child: CenterBox({ + startWidget: Left(), + centerWidget: Center(), + endWidget: Right(), + }), +}) -// exporting the config -var config = { - style: CONFIG_DIR+'/style.css', - windows: [bar], +// exporting the config so ags can manage the windows +export default { + style: App.configDir + '/style.css', + windows: [ + Bar({ monitor: 0 }), + + // you can call it as many times + Bar({ monitor: 1 }) + ], }; diff --git a/src/ags.js.in b/src/ags.js.in index 26c4001..1b84a64 100755 --- a/src/ags.js.in +++ b/src/ags.js.in @@ -32,6 +32,6 @@ const { Repository } = imports.gi.GIRepository; Repository.prepend_search_path('@GVC_GIR@'); Repository.prepend_library_path('@GVC_GIR@'); -const module = await import('resource:///@RESOURCE_PATH@/js/main.js'); +const module = await import('resource:///@RESOURCE_PATH@/main.js'); const exitCode = await module.main([programInvocationName, ...programArgs]); -exit(exitCode); \ No newline at end of file +exit(exitCode); diff --git a/src/ags.src.gresource.xml b/src/ags.src.gresource.xml index d2b9d8f..72ff0a7 100644 --- a/src/ags.src.gresource.xml +++ b/src/ags.src.gresource.xml @@ -1,6 +1,6 @@ - + main.js app.js utils.js diff --git a/src/app.ts b/src/app.ts index ff93dac..83890ae 100644 --- a/src/app.ts +++ b/src/app.ts @@ -182,8 +182,8 @@ export default class App extends Gtk.Application { }); this.emit('config-parsed'); - } catch (_) { - print(`No config found at ${App.configPath}`); + } catch (err) { + logError(err as Error); } } diff --git a/src/main.ts b/src/main.ts index 92ee89a..c33df03 100644 --- a/src/main.ts +++ b/src/main.ts @@ -142,7 +142,9 @@ export function main(args: string[]) { quit = true; break; - default: break; + default: + console.error(`unknown option: ${args[i]}`); + break; } } diff --git a/src/widget.ts b/src/widget.ts index 9e87c7b..a7793f2 100644 --- a/src/widget.ts +++ b/src/widget.ts @@ -1,44 +1,57 @@ -import Gtk from 'gi://Gtk?version=3.0'; -import Box from './widgets/box.js'; -import CenterBox from './widgets/centerbox.js'; -import EventBox from './widgets/eventbox.js'; -import Icon from './widgets/icon.js'; -import Label from './widgets/label.js'; -import Button from './widgets/button.js'; -import Slider from './widgets/slider.js'; -import Scrollable from './widgets/scrollable.js'; -import Stack from './widgets/stack.js'; -import Overlay from './widgets/overlay.js'; -import Revealer from './widgets/revealer.js'; -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 AgsBox from './widgets/box.js'; +import AgsCenterBox from './widgets/centerbox.js'; +import AgsEventBox from './widgets/eventbox.js'; +import AgsIcon from './widgets/icon.js'; +import AgsLabel from './widgets/label.js'; +import AgsButton from './widgets/button.js'; +import AgsSlider from './widgets/slider.js'; +import AgsScrollable from './widgets/scrollable.js'; +import AgsStack from './widgets/stack.js'; +import AgsOverlay from './widgets/overlay.js'; +import AgsRevealer from './widgets/revealer.js'; +import AgsProgressBar from './widgets/progressbar.js'; +import AgsEntry from './widgets/entry.js'; +import { AgsMenu, AgsMenuItem } from './widgets/menu.js'; +import AgsWindow from './widgets/window.js'; import constructor from './widgets/shared.js'; +import { ctor } from './widgets/shared.js'; -interface Params { - type: { - new(...args: any[]): Gtk.Widget - } -} - -export default function Widget({ type, ...params }: Params) { +export default function Widget({ type, ...params }: { type: ctor }) { return constructor(type, params); } -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.Menu = (params: object) => constructor(Menu, params); -Widget.MenuItem = (params: object) => constructor(MenuItem, 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); +export const Box = (args: object) => constructor(AgsBox, args); +export const Button = (args: object) => constructor(AgsButton, args); +export const CenterBox = (args: object) => constructor(AgsCenterBox, args); +export const Entry = (args: object) => constructor(AgsEntry, args); +export const EventBox = (args: object) => constructor(AgsEventBox, args); +export const Icon = (args: object) => constructor(AgsIcon, args); +export const Label = (args: object) => constructor(AgsLabel, args); +export const Menu = (args: object) => constructor(AgsMenu, args); +export const MenuItem = (args: object) => constructor(AgsMenuItem, args); +export const Overlay = (args: object) => constructor(AgsOverlay, args); +export const ProgressBar = (args: object) => constructor(AgsProgressBar, args); +export const Revealer = (args: object) => constructor(AgsRevealer, args); +export const Scrollable = (args: object) => constructor(AgsScrollable, args); +export const Slider = (args: object) => constructor(AgsSlider, args); +export const Stack = (args: object) => constructor(AgsStack, args); +export const Window = (args: object) => constructor(AgsWindow, args); + +// so it is still in global scope through ags.Widget +Widget.Widget = Widget; +Widget.Box = Box; +Widget.Button = Button; +Widget.CenterBox = CenterBox; +Widget.Entry = Entry; +Widget.EventBox = EventBox; +Widget.Icon = Icon; +Widget.Label = Label; +Widget.Menu = Menu; +Widget.MenuItem = MenuItem; +Widget.Overlay = Overlay; +Widget.ProgressBar = ProgressBar; +Widget.Revealer = Revealer; +Widget.Scrollable = Scrollable; +Widget.Slider = Slider; +Widget.Stack = Stack; +Widget.Window = Window; diff --git a/src/widgets/box.ts b/src/widgets/box.ts index f5fd35b..60c121b 100644 --- a/src/widgets/box.ts +++ b/src/widgets/box.ts @@ -1,7 +1,7 @@ import GObject from 'gi://GObject'; import Gtk from 'gi://Gtk?version=3.0'; -export default class Box extends Gtk.Box { +export default class AgsBox extends Gtk.Box { static { GObject.registerClass({ GTypeName: 'AgsBox', diff --git a/src/widgets/button.ts b/src/widgets/button.ts index 280942e..c2eddb7 100644 --- a/src/widgets/button.ts +++ b/src/widgets/button.ts @@ -3,7 +3,7 @@ import Gtk from 'gi://Gtk?version=3.0'; import Gdk from 'gi://Gdk?version=3.0'; import { runCmd } from '../utils.js'; -export default class Button extends Gtk.Button { +export default class AgsButton extends Gtk.Button { static { GObject.registerClass({ GTypeName: 'AgsButton' }, this); } diff --git a/src/widgets/centerbox.ts b/src/widgets/centerbox.ts index a935b41..eb7a38b 100644 --- a/src/widgets/centerbox.ts +++ b/src/widgets/centerbox.ts @@ -1,8 +1,8 @@ import GObject from 'gi://GObject'; import Gtk from 'gi://Gtk?version=3.0'; -import Box from './box.js'; +import AgsBox from './box.js'; -export default class CenterBox extends Box { +export default class AgsCenterBox extends AgsBox { static { GObject.registerClass({ GTypeName: 'AgsCenterBox', diff --git a/src/widgets/entry.ts b/src/widgets/entry.ts index 63f4f09..9010954 100644 --- a/src/widgets/entry.ts +++ b/src/widgets/entry.ts @@ -2,7 +2,7 @@ import GObject from 'gi://GObject'; import Gtk from 'gi://Gtk?version=3.0'; import { runCmd } from '../utils.js'; -export default class Entry extends Gtk.Entry { +export default class AgsEntry extends Gtk.Entry { static { GObject.registerClass({ GTypeName: 'AgsEntry' }, this); } diff --git a/src/widgets/eventbox.ts b/src/widgets/eventbox.ts index a9fa9d2..3470110 100644 --- a/src/widgets/eventbox.ts +++ b/src/widgets/eventbox.ts @@ -3,7 +3,7 @@ import Gtk from 'gi://Gtk?version=3.0'; import Gdk from 'gi://Gdk?version=3.0'; import { runCmd } from '../utils.js'; -export default class EventBox extends Gtk.EventBox { +export default class AgsEventBox extends Gtk.EventBox { static { GObject.registerClass({ GTypeName: 'AgsEventBox' }, this); } diff --git a/src/widgets/icon.ts b/src/widgets/icon.ts index 01c4751..2b04bc2 100644 --- a/src/widgets/icon.ts +++ b/src/widgets/icon.ts @@ -4,7 +4,7 @@ import GLib from 'gi://GLib'; import GdkPixbuf from 'gi://GdkPixbuf'; import { Context } from 'gi-types/cairo1'; -export default class Icon extends Gtk.Image { +export default class AgsIcon extends Gtk.Image { static { GObject.registerClass({ GTypeName: 'AgsIcon', diff --git a/src/widgets/label.ts b/src/widgets/label.ts index bf52ac1..0d485ae 100644 --- a/src/widgets/label.ts +++ b/src/widgets/label.ts @@ -3,7 +3,7 @@ import Gtk from 'gi://Gtk?version=3.0'; const justification = ['left', 'center', 'right', 'fill']; -export default class Label extends Gtk.Label { +export default class AgsLabel extends Gtk.Label { static { GObject.registerClass({ GTypeName: 'AgsLabel', diff --git a/src/widgets/menu.ts b/src/widgets/menu.ts index 3e2d1e4..26dcceb 100644 --- a/src/widgets/menu.ts +++ b/src/widgets/menu.ts @@ -2,7 +2,7 @@ import GObject from 'gi://GObject'; import Gtk from 'gi://Gtk?version=3.0'; import { runCmd } from '../utils.js'; -export class Menu extends Gtk.Menu { +export class AgsMenu extends Gtk.Menu { static { GObject.registerClass({ GTypeName: 'AgsMenu' }, this); } @@ -49,7 +49,7 @@ export class Menu extends Gtk.Menu { } } -export class MenuItem extends Gtk.MenuItem { +export class AgsMenuItem extends Gtk.MenuItem { static { GObject.registerClass({ GTypeName: 'AgsMenuItem' }, this); } diff --git a/src/widgets/overlay.ts b/src/widgets/overlay.ts index bd3a2bd..86a2b84 100644 --- a/src/widgets/overlay.ts +++ b/src/widgets/overlay.ts @@ -1,7 +1,7 @@ import GObject from 'gi://GObject'; import Gtk from 'gi://Gtk?version=3.0'; -export default class Overlay extends Gtk.Overlay { +export default class AgsOverlay extends Gtk.Overlay { static { GObject.registerClass({ GTypeName: 'AgsOverlay', diff --git a/src/widgets/progressbar.ts b/src/widgets/progressbar.ts index 25bd5b3..303a20b 100644 --- a/src/widgets/progressbar.ts +++ b/src/widgets/progressbar.ts @@ -1,7 +1,7 @@ import GObject from 'gi://GObject'; import Gtk from 'gi://Gtk?version=3.0'; -export default class ProgressBar extends Gtk.ProgressBar { +export default class AgsProgressBar extends Gtk.ProgressBar { static { GObject.registerClass({ GTypeName: 'AgsProgressBar', diff --git a/src/widgets/revealer.ts b/src/widgets/revealer.ts index 1345c75..92825ad 100644 --- a/src/widgets/revealer.ts +++ b/src/widgets/revealer.ts @@ -7,7 +7,7 @@ const transitions = [ 'slide_up', 'slide_down', ]; -export default class Revealer extends Gtk.Revealer { +export default class AgsRevealer extends Gtk.Revealer { static { GObject.registerClass({ GTypeName: 'AgsRevealer', diff --git a/src/widgets/scrollable.ts b/src/widgets/scrollable.ts index 604e7eb..04d015f 100644 --- a/src/widgets/scrollable.ts +++ b/src/widgets/scrollable.ts @@ -3,7 +3,7 @@ import Gtk from 'gi://Gtk?version=3.0'; const policy = ['automatic', 'always', 'never', 'external']; -export default class Scrollable extends Gtk.ScrolledWindow { +export default class AgsScrollable extends Gtk.ScrolledWindow { static { GObject.registerClass({ GTypeName: 'AgsScrollable', diff --git a/src/widgets/shared.ts b/src/widgets/shared.ts index ce25123..05316af 100644 --- a/src/widgets/shared.ts +++ b/src/widgets/shared.ts @@ -111,8 +111,11 @@ function parseCommon(widget: Gtk.Widget, { else if (typeof s === 'number') interval(s, () => callback(widget), widget); - else + else if (typeof s?.instance?.connectWidget === 'function') s.instance.connectWidget(widget, callback, event); + + else + logError(new Error(`${s} is not an instanceof Service`)); }); } @@ -120,8 +123,9 @@ function parseCommon(widget: Gtk.Widget, { setup(widget); } +export type ctor = { new(...args: any[]): Gtk.Widget } export default function constructor( - ctor: { new(...args: any[]): Gtk.Widget }, + ctor: ctor, params: CommonParams | string = {}, ) { let widget; diff --git a/src/widgets/slider.ts b/src/widgets/slider.ts index 9d104b4..0d18af2 100644 --- a/src/widgets/slider.ts +++ b/src/widgets/slider.ts @@ -3,16 +3,11 @@ import Gtk from 'gi://Gtk?version=3.0'; import { runCmd } from '../utils.js'; import { EventButton, EventScroll } from 'gi-types/gdk3'; -export default class Slider extends Gtk.Scale { +export default class AgsSlider extends Gtk.Scale { static { GObject.registerClass({ GTypeName: 'AgsSlider', Properties: { - 'value': GObject.ParamSpec.float( - 'value', 'Value', 'Value', - GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT, - -100, 100, 0, - ), 'min': GObject.ParamSpec.float( 'min', 'Min', 'Min', GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT, @@ -44,16 +39,10 @@ export default class Slider extends Gtk.Scale { onChange: string | ((...args: any[]) => boolean); - constructor({ onChange = '', ...rest }) { + constructor({ onChange = '', value = 0, ...rest }) { super({ ...rest, adjustment: new Gtk.Adjustment() }); this.onChange = onChange; - this.bind_property( - 'value', this.adjustment, 'value', - GObject.BindingFlags.BIDIRECTIONAL | - GObject.BindingFlags.SYNC_CREATE, - ); - this.bind_property( 'min', this.adjustment, 'lower', GObject.BindingFlags.BIDIRECTIONAL | @@ -72,7 +61,7 @@ export default class Slider extends Gtk.Scale { GObject.BindingFlags.SYNC_CREATE, ); - this.connect('notify::value', ({ value }, event) => { + this.adjustment.connect('notify::value', ({ value }, event) => { if (!this._dragging) return; @@ -80,16 +69,17 @@ export default class Slider extends Gtk.Scale { ? this.onChange(this, event, value) : runCmd(onChange.replace(/\{\}/g, value)); }); + + if (value) + this.value = value; } - _value = 0; - get value() { return this._value; } + get value() { return this.adjustment.value; } set value(value: number) { - if (this.dragging) + if (this._dragging) return; - this._value = value; - this.notify('value'); + this.adjustment.value = value; } _min = 0; diff --git a/src/widgets/stack.ts b/src/widgets/stack.ts index e57fcd7..ab4343b 100644 --- a/src/widgets/stack.ts +++ b/src/widgets/stack.ts @@ -10,7 +10,7 @@ const transitions = [ 'over_up_down', 'over_down_up', 'over_left_right', 'over_right_left', ]; -export default class Stack extends Gtk.Stack { +export default class AgsStack extends Gtk.Stack { static { GObject.registerClass({ GTypeName: 'AgsStack', diff --git a/src/widgets/window.ts b/src/widgets/window.ts index 9a908ba..c3c6963 100644 --- a/src/widgets/window.ts +++ b/src/widgets/window.ts @@ -5,7 +5,7 @@ import App from '../app.js'; const { GtkLayerShell } = imports.gi; -export interface Params { +interface Params { anchor?: string[] exclusive?: boolean focusable?: boolean @@ -16,7 +16,7 @@ export interface Params { visible?: boolean | null } -export default class Window extends Gtk.Window { +export default class AgsWindow extends Gtk.Window { static { GObject.registerClass({ GTypeName: 'AgsWindow' }, this); }