From 1a1a5d63f89ab51eb3487b3310139139f6103267 Mon Sep 17 00:00:00 2001 From: retrozinndev Date: Fri, 28 Feb 2025 10:21:37 -0300 Subject: [PATCH] ags: lot of stuff lmao --- ags/scripts/brightness.ts | 4 +- ags/scripts/notification-handler.ts | 65 +++++++++++- ags/scripts/style-handler.ts | 2 +- ags/style/_bar.scss | 20 +++- ags/style/_colors.scss | 4 +- ags/style/_control-center.scss | 58 +++++++++++ ags/style/_wal.scss | 40 ++++---- ags/widget/Calendar.ts | 24 ++++- ags/widget/PopupWindow.ts | 76 ++++++++++++-- ags/widget/Separator.ts | 4 +- ags/widget/bar/Audio.ts | 5 +- ags/widget/bar/FocusedClient.ts | 10 +- ags/widget/bar/Logo.ts | 17 ++-- ags/widget/bar/Media.ts | 10 +- ags/widget/center-window/BigMedia.ts | 59 +++++++++-- ags/widget/control-center/Pages.ts | 40 ++++++++ ags/widget/control-center/QuickActions.ts | 7 +- ags/widget/control-center/Tiles.ts | 25 +++-- ags/widget/control-center/pages/Bluetooth.ts | 98 ++++++++++++++++++ ags/widget/control-center/pages/Internet.ts | 38 +++++++ ags/widget/control-center/tiles/Bluetooth.ts | 21 ++++ ags/widget/control-center/tiles/Internet.ts | 28 ++++- ags/widget/control-center/tiles/Tile.ts | 101 ++++++++++++++----- ags/window/CenterWindow.ts | 15 ++- ags/window/ControlCenter.ts | 27 ++--- ags/window/FloatingNotifications.ts | 64 ------------ ags/window/LogoutMenu.ts | 20 ++-- ags/window/Runner.ts | 10 +- ags/window/SelectWallpaper.ts | 0 ags/window/Wallpaper.ts | 44 ++++++++ ags/windows.ts | 29 +++--- 31 files changed, 748 insertions(+), 217 deletions(-) create mode 100644 ags/widget/control-center/Pages.ts create mode 100644 ags/widget/control-center/pages/Bluetooth.ts create mode 100644 ags/widget/control-center/pages/Internet.ts create mode 100644 ags/widget/control-center/tiles/Bluetooth.ts create mode 100644 ags/window/SelectWallpaper.ts create mode 100644 ags/window/Wallpaper.ts diff --git a/ags/scripts/brightness.ts b/ags/scripts/brightness.ts index 4ce516b..085b31c 100644 --- a/ags/scripts/brightness.ts +++ b/ags/scripts/brightness.ts @@ -3,7 +3,7 @@ import { Connectable } from "astal/binding"; /** !!TODO!! Needs more work and testing - * I(retrozinndev) don't have a monitor that has software-controlled brightness + * I(retrozinndev) don't have a monitor that has software-controlled brightness :( */ @register({ GTypeName: "Brightness" }) class Brightness extends GObject.Object implements Connectable { @@ -16,7 +16,7 @@ class Brightness extends GObject.Object implements Connectable { constructor(backlightDevice?: string) { super(); - this.backlight = backlightDevice || ""; + this.backlight = backlightDevice || "intel_backlight"; this.max = Number.parseInt(exec(`brightnessctl -d ${backlightDevice} max`)) this.brightness = Number.parseInt(exec(`brightnessctl -d ${backlightDevice} get`)) diff --git a/ags/scripts/notification-handler.ts b/ags/scripts/notification-handler.ts index 3b75380..bc99437 100644 --- a/ags/scripts/notification-handler.ts +++ b/ags/scripts/notification-handler.ts @@ -4,6 +4,7 @@ import { Subscribable } from "astal/binding"; import { GObject, property, register, Variable } from "astal"; import { Windows } from "../windows"; import { FloatingNotifications } from "../window/FloatingNotifications"; +import { Gtk, Widget } from "astal/gtk3"; @register({ GTypeName: "Notifications" }) class NotificationsClass extends GObject.Object implements Subscribable { @@ -74,7 +75,6 @@ class NotificationsClass extends GObject.Object implements Subscribable { notification.urgency !== AstalNotifd.Urgency.CRITICAL && timeout(notificationTimeout, () => { - notification.dismiss(); this.notifications.set(this.notifications.get().filter((item) => item.id !== notification.id)); this.addHistory(notification); }); @@ -106,4 +106,67 @@ class NotificationsClass extends GObject.Object implements Subscribable { } } +function NotificationWidget(notification: AstalNotifd.Notification): Gtk.Widget { + return new Widget.Box({ + className: "notification", + homogeneous: false, + expand: false, + orientation: Gtk.Orientation.VERTICAL, + children: [ + new Widget.Box({ + className: "top", + orientation: Gtk.Orientation.HORIZONTAL, + hexpand: true, + vexpand: false, + children: [ + new Widget.Icon({ + className: "icon", + visible: notification.appIcon !== "", + icon: notification.appIcon || "image-missing", + iconSize: Gtk.IconSize.DND, + css: ".icon { font-size: 24px; }" + }), + new Widget.Label({ + className: "app-name", + halign: Gtk.Align.START, + label: notification.appName || "Unknown Application" + } as Widget.LabelProps), + new Widget.Button({ + className: "close nf", + onClick: () => notification.dismiss(), + label: "󰅖" + } as Widget.ButtonProps) + ] + } as Widget.BoxProps), + new Widget.Box({ + className: "content", + orientation: Gtk.Orientation.HORIZONTAL, + children: [ + new Widget.Box({ + className: "image", + visible: notification.image !== "", + css: `box.image { background-image: url('${notification.image}'); }` + } as Widget.BoxProps), + new Widget.Box({ + className: "text", + orientation: Gtk.Orientation.VERTICAL, + children: [ + new Widget.Label({ + className: "summary", + useMarkup: true, + label: notification.summary + }), + new Widget.Label({ + className: "body", + useMarkup: true, + label: notification.body + } as Widget.LabelProps) + ] + } as Widget.BoxProps) + ] + } as Widget.BoxProps) + ] + } as Widget.BoxProps); +} + export const Notifications = new NotificationsClass(); diff --git a/ags/scripts/style-handler.ts b/ags/scripts/style-handler.ts index 08bb97a..fe2b327 100644 --- a/ags/scripts/style-handler.ts +++ b/ags/scripts/style-handler.ts @@ -41,7 +41,7 @@ function watch(): void { `${path}`, (file: string) => { // Ignore tmp files - if(!file.endsWith('~')) { + if(!file.endsWith('~') && !Number.isNaN(file)) { console.log(`[LOG] Stylesheet ${file} file updated`) compileStyle(); applyStyle(); diff --git a/ags/style/_bar.scss b/ags/style/_bar.scss index 37de1dc..d71f3f4 100644 --- a/ags/style/_bar.scss +++ b/ags/style/_bar.scss @@ -13,7 +13,7 @@ @include mixins.reset-props; font-size: 12px; - font-weight: 500; + font-weight: 600; } // Style widget groups @@ -194,4 +194,22 @@ } } } + + .logo { + & > box { + border-radius: 12px; + transition: 100ms linear; + padding: 0 8px; + + & > label { + font-size: 14px; + margin-right: 1px; + } + } + &:hover { + & > box { + background: colors.$bg-primary; + } + } + } } diff --git a/ags/style/_colors.scss b/ags/style/_colors.scss index b9ddd46..b3f2f6c 100644 --- a/ags/style/_colors.scss +++ b/ags/style/_colors.scss @@ -2,11 +2,11 @@ @use "./wal"; @use "./functions" as funs; -$bg-primary: funs.toRGB(color.adjust($color: wal.$color1, $lightness: -35%)); +$bg-primary: funs.toRGB(color.adjust($color: wal.$color1, $lightness: -34%)); $bg-secondary: funs.toRGB(color.adjust($color: wal.$color1, $lightness: -16%)); $bg-tertiary: funs.toRGB(color.adjust($color: $bg-secondary, $lightness: 10%)); $bg-light: wal.$foreground; -$bg-translucent: funs.toRGB(color.change($color: $bg-primary, $alpha: 72%)); +$bg-translucent: funs.toRGB(color.change($color: $bg-primary, $alpha: 75%)); $fg-primary: wal.$foreground; $fg-light: $bg-primary; $fg-disabled: funs.toRGB(color.adjust($color: wal.$foreground, $lightness: -11%)); diff --git a/ags/style/_control-center.scss b/ags/style/_control-center.scss index 6fc4c27..5b74654 100644 --- a/ags/style/_control-center.scss +++ b/ags/style/_control-center.scss @@ -65,3 +65,61 @@ } } } + +.tiles-container { + @include mixins.reset-props; + + & > flowbox { + & > flowboxchild .tile-eventbox { + &:hover:not(.toggled) > .tile { + background: colors.$bg-secondary; + } + + &.toggled:hover > .tile { + box-shadow: inset 0 0 0 100px rgba($color: colors.$fg-primary, $alpha: .2); + } + + &.toggled > .tile { + background: colors.$bg-secondary; + } + + & > .tile { + background: colors.$bg-primary; + border-radius: 16px; + + & > .content { + padding: 8px; + padding-right: 0; + & > .icon { + margin-right: 6px; + } + + & > .text { + & > .title { + font-weight: 600; + font-size: 15.1px; + } + + & > .description { + font-size: 13px; + font-weight: 400; + } + } + } + + & > .more { + border-top-right-radius: inherit; + border-bottom-right-radius: inherit; + + & label { + font-size: 16px; + } + + &:hover { + box-shadow: inset 0 0 0 100px rgba($color: colors.$fg-disabled, $alpha: .4); + } + } + } + } + } +} diff --git a/ags/style/_wal.scss b/ags/style/_wal.scss index 32387bc..5c9c132 100644 --- a/ags/style/_wal.scss +++ b/ags/style/_wal.scss @@ -1,26 +1,26 @@ // SCSS Variables // Generated by 'wal' -$wallpaper: "/home/joaov/wallpapers/Miku Bush.jpg"; +$wallpaper: "/home/joaov/wallpapers/Bocchi The Rock!.png"; // Special -$background: #0f1b06; -$foreground: #c3c6c0; -$cursor: #c3c6c0; +$background: #0a0a0c; +$foreground: #c1c1c2; +$cursor: #c1c1c2; // Colors -$color0: #0f1b06; -$color1: #4e7278; -$color2: #5b7b94; -$color3: #71807c; -$color4: #7b9882; -$color5: #a3a881; -$color6: #778591; -$color7: #93988d; -$color8: #626d59; -$color9: #6898A1; -$color10: #7AA5C6; -$color11: #97ABA6; -$color12: #A5CBAE; -$color13: #DAE0AC; -$color14: #9FB2C2; -$color15: #c3c6c0; +$color0: #0a0a0c; +$color1: #935d6d; +$color2: #967e84; +$color3: #ac8486; +$color4: #bcae7a; +$color5: #a49c9c; +$color6: #bcb79c; +$color7: #8a8a96; +$color8: #565669; +$color9: #C57C92; +$color10: #C9A9B0; +$color11: #E6B1B3; +$color12: #FBE8A3; +$color13: #DBD1D0; +$color14: #FBF5D1; +$color15: #c1c1c2; diff --git a/ags/widget/Calendar.ts b/ags/widget/Calendar.ts index 8ad1dfb..368b697 100644 --- a/ags/widget/Calendar.ts +++ b/ags/widget/Calendar.ts @@ -1 +1,23 @@ -//TODO +//TODO Needs more work + +import { Gtk, Widget } from "astal/gtk3"; + +type CalendarProps = Pick & { + + showWeekDays: boolean; + showHeader: boolean; + fillGrid: boolean; // I need a better name for this LMAOOO +}; + +export function Calendar(props?: Partial): Gtk.Widget { + return new Widget.Box({ + ...props, + children: [] + } as Widget.BoxProps); +} diff --git a/ags/widget/PopupWindow.ts b/ags/widget/PopupWindow.ts index 5961c2c..61b9b22 100644 --- a/ags/widget/PopupWindow.ts +++ b/ags/widget/PopupWindow.ts @@ -1,18 +1,72 @@ -import { Astal, Gtk, Widget } from "astal/gtk3"; +import { Binding } from "astal"; +import { Astal, Gdk, Gtk, Widget } from "astal/gtk3"; const { TOP, BOTTOM, LEFT, RIGHT }: typeof Astal.WindowAnchor = Astal.WindowAnchor; -/** - * Creates a screen-size window and opens the provided window after it. - * When clicking in the transparent background window, it closes(hides) - * the provided window. - * @param window the window to be rendered and closed when clicking outside of it - */ -export function PopupWindow(window: Gtk.Window) { - const bgWindow: Gtk.Window = new Widget.Window({ - namespace: "popup-bg-window", +export interface PopupWindowProps { + className?: string | Binding; + namespace: string | Binding; + visible?: boolean | Binding; + halign?: Gtk.Align | Binding; + valign?: Gtk.Align | Binding; + hexpand?: boolean | Binding; + vexpand?: boolean | Binding; + expand?: boolean | Binding; + monitor?: number | Binding; + marginTop?: number | Binding; + marginBottom?: number | Binding; + marginLeft?: number | Binding; + marginRight?: number | Binding; + widthRequest?: number | Binding; + heightRequest?: number | Binding; + layer?: Astal.Layer | Binding; + onClose?: () => void; + child: Gtk.Widget; +} + +export function PopupWindow(props: PopupWindowProps): Widget.Window { + return new Widget.Window({ + namespace: props?.namespace || "popup-window", + className: "popup-window", anchor: TOP | BOTTOM | LEFT | RIGHT, + exclusivity: Astal.Exclusivity.NORMAL, + keymode: Astal.Keymode.EXCLUSIVE, + layer: props?.layer || Astal.Layer.OVERLAY, + focusOnMap: true, + visible: props?.visible, + acceptFocus: true, + monitor: props?.monitor || 0, + onButtonPressEvent: (_, event: Gdk.Event) => { + const [, posX, posY] = event.get_coords(); + const childAllocation = _.get_child()!.get_allocation(); - } as Widget.WindowProps); + if((posX < childAllocation.x || posX > (childAllocation.x + childAllocation.width)) || + (posY < childAllocation.y || posY > (childAllocation.y + childAllocation.height))) { + _.hide(); + props?.onClose && props.onClose(); + } + }, + onKeyPressEvent: (_, event: Gdk.Event) => + event.get_keyval()[1] === Gdk.KEY_Escape && _.hide(), + child: new Widget.Box({ + className: (props?.className instanceof Binding) ? + props.className.as((clsName: string|undefined) => + `popup ${clsName || ""}`) + : `popup ${props?.className || ""}`, + halign: props?.halign || Gtk.Align.CENTER, + valign: props?.valign || Gtk.Align.CENTER, + expand: props?.expand || false, + widthRequest: props?.widthRequest, + heightRequest: props?.heightRequest, + hexpand: props?.hexpand || false, + visible: true, + vexpand: props?.vexpand || false, + marginTop: props?.marginTop || 0, + marginBottom: props?.marginBottom || 0, + marginLeft: props?.marginLeft || 0, + marginRight: props?.marginRight || 0, + child: props.child + } as Widget.BoxProps) + } as Widget.WindowProps);; } diff --git a/ags/widget/Separator.ts b/ags/widget/Separator.ts index 53d4559..5f3c883 100644 --- a/ags/widget/Separator.ts +++ b/ags/widget/Separator.ts @@ -20,11 +20,11 @@ export function Separator(props: SeparatorProps) { } .separator-horizontal { padding-bottom: ${props.size || 1 }px; - margin: 7px 4px; + margin: 4px 4px; } .separator-vertical { padding-right: ${props.size || 1 }px; - margin: 4px 7px; + margin: 7px 7px; }`, } as Widget.BoxProps); } diff --git a/ags/widget/bar/Audio.ts b/ags/widget/bar/Audio.ts index 40e5e60..24e192d 100644 --- a/ags/widget/bar/Audio.ts +++ b/ags/widget/bar/Audio.ts @@ -1,13 +1,10 @@ import { bind, Process } from "astal"; import { Widget } from "astal/gtk3"; -import AstalWp from "gi://AstalWp"; import { Wireplumber } from "../../scripts/volume"; import { ControlCenter } from "../../window/ControlCenter"; -const wp = AstalWp.get_default(); - export function Audio() { - return wp && new Widget.EventBox({ + return new Widget.EventBox({ className: bind(ControlCenter, "visible").as((visible: boolean) => visible ? "audio open" : "audio"), onClick: () => Process.exec_async("astal toggle control-center", () => {}), diff --git a/ags/widget/bar/FocusedClient.ts b/ags/widget/bar/FocusedClient.ts index fcafa29..51920cb 100644 --- a/ags/widget/bar/FocusedClient.ts +++ b/ags/widget/bar/FocusedClient.ts @@ -12,6 +12,8 @@ export function FocusedClient() { children: [ new Widget.Icon({ className: "icon", + vexpand: true, + css: ".icon { font-size: 18px; }", icon: bind(hyprland, "focusedClient").as((client: AstalHyprland.Client) => client ? (getAppIcon(client.initialClass) || client.initialClass) @@ -29,15 +31,15 @@ export function FocusedClient() { new Widget.Label({ className: "class", xalign: 0, - max_width_chars: 65, - truncate: false, + maxWidthChars: 50, + truncate: true, label: bind(focusedClient, "class") } as Widget.LabelProps), new Widget.Label({ className: "title", xalign: 0, - max_width_chars: 48, - truncate: false, + maxWidthChars: 45, + truncate: true, label: bind(focusedClient, "title") } as Widget.LabelProps) ] : [] diff --git a/ags/widget/bar/Logo.ts b/ags/widget/bar/Logo.ts index 2a11914..15083d7 100644 --- a/ags/widget/bar/Logo.ts +++ b/ags/widget/bar/Logo.ts @@ -2,13 +2,14 @@ import { Widget } from "astal/gtk3"; import AstalHyprland from "gi://AstalHyprland"; export function Logo() { - return new Widget.Box({ + return new Widget.EventBox({ + onClickRelease: () => AstalHyprland.get_default().dispatch("exec", "anyrun"), className: "logo", - //tooltipText: tr("bar.logo.tooltip"), - child: new Widget.Button({ - onClick: () => AstalHyprland.get_default().dispatch("exec", "anyrun"), - className: "nf", - label: "", - } as Widget.ButtonProps) - } as Widget.BoxProps); + child: new Widget.Box({ + child: new Widget.Label({ + className: "nf", + label: "", + } as Widget.LabelProps) + } as Widget.BoxProps) + } as Widget.EventBoxProps); } diff --git a/ags/widget/bar/Media.ts b/ags/widget/bar/Media.ts index 49e1d20..1214d5c 100644 --- a/ags/widget/bar/Media.ts +++ b/ags/widget/bar/Media.ts @@ -82,12 +82,14 @@ export function Media(): Gtk.Widget { className: "player-icon nf", label: bind(players[0], "busName").as((busName: string) => { const playerName: string = busName.split('.')[busName.split('.').length-1]; - return playerIcons[playerName as keyof typeof playerIcons] || "󰎇"; + return playerIcons[playerName.toLowerCase() as keyof typeof playerIcons] || "󰎇"; }) } as Widget.LabelProps), new Widget.Label({ className: "title", - label: bind(players[0], "title").as((title: string) => title || "No Title") + label: bind(players[0], "title").as((title: string) => title || "No Title"), + maxWidthChars: 20, + truncate: true } as Widget.LabelProps), Separator({ orientation: Gtk.Orientation.VERTICAL, @@ -97,7 +99,9 @@ export function Media(): Gtk.Widget { } as SeparatorProps), new Widget.Label({ className: "artist", - label: bind(players[0], "artist").as((artist: string) => artist || "No Artist") + label: bind(players[0], "artist").as((artist: string) => artist || "No Artist"), + maxWidthChars: 18, + truncate: true } as Widget.LabelProps) ] : new Widget.Label({ label: "Crazy to think this widget haven't disappeared yet!" diff --git a/ags/widget/center-window/BigMedia.ts b/ags/widget/center-window/BigMedia.ts index dcb5cfd..c289aa5 100644 --- a/ags/widget/center-window/BigMedia.ts +++ b/ags/widget/center-window/BigMedia.ts @@ -1,4 +1,4 @@ -import { AstalIO, bind, GLib, Process, timeout } from "astal"; +import { AstalIO, bind, Binding, GLib, Process, timeout } from "astal"; import { Gtk, Widget } from "astal/gtk3"; import AstalMpris from "gi://AstalMpris"; @@ -19,10 +19,9 @@ export const BigMedia: Gtk.Widget = new Widget.Box({ className: "image", hexpand: false, orientation: Gtk.Orientation.VERTICAL, - visible: bind(players[0], "coverArt").as((coverArt: string) => - coverArt !== ""), - css: bind(players[0], "coverArt").as((coverArt: string) => - `.image { background-image: url('${coverArt}'); }`), + visible: getAlbumArt(players[0]).as(Boolean), + css: getAlbumArt(players[0]).as((artUrl: string|undefined) => + artUrl ? `.image { background-image: url('${artUrl}'); }` : undefined), width_request: 132, height_request: 128 } as Widget.BoxProps) @@ -35,13 +34,15 @@ export const BigMedia: Gtk.Widget = new Widget.Box({ className: "title", tooltipText: bind(players[0], "title").as((title: string) => !title ? "No Title" : title), label: bind(players[0], "title").as((title: string) => !title ? "No Title" : title), - truncate: true + truncate: true, + maxWidthChars: 25, } as Widget.LabelProps), new Widget.Label({ className: "artist", tooltipText: bind(players[0], "artist").as((artist: string) => !artist ? "No Artist" : artist), label: bind(players[0], "artist").as((artist: string) => !artist ? "No Artist" : artist), - truncate: true + maxWidthChars: 28, + truncate: true, } as Widget.LabelProps) ] } as Widget.BoxProps), @@ -101,6 +102,15 @@ export const BigMedia: Gtk.Widget = new Widget.Box({ players[0].get_meta("xesam:url") === null), onClick: () => Process.exec(`wl-copy ${players[0].get_meta("xesam:url")?.get_string()[0]}`) } as Widget.ButtonProps), + new Widget.Button({ + className: "shuffle nf", + visible: bind(players[0], "shuffleStatus").as((shuffleStatus: AstalMpris.Shuffle) => + shuffleStatus !== AstalMpris.Shuffle.UNSUPPORTED), + label: bind(players[0], "shuffleStatus").as((shuffleStatus: AstalMpris.Shuffle) => + shuffleStatus === AstalMpris.Shuffle.ON ? "󰒝" : "󰒞"), + tooltipText: "Toggle Shuffle", + onClick: () => players[0].shuffle() + } as Widget.ButtonProps), new Widget.Button({ className: "previous nf", label: "󰒮", @@ -125,6 +135,20 @@ export const BigMedia: Gtk.Widget = new Widget.Box({ label: "󰒭", tooltipText: "Next", onClick: () => players[0].canGoNext && players[0].next() + } as Widget.ButtonProps), + new Widget.Button({ + className: "repeat nf", + visible: bind(players[0], "loopStatus").as((loopStatus: AstalMpris.Loop) => + loopStatus !== AstalMpris.Loop.UNSUPPORTED), + label: bind(players[0], "loopStatus").as((loopStatus: AstalMpris.Loop) => { + switch(loopStatus) { + case AstalMpris.Loop.TRACK: return "󰑘"; + case AstalMpris.Loop.PLAYLIST: return "󰑖"; + default: return "󰑗"; + } + }), + tooltipText: "Toggle Loop", + onClick: () => players[0].loop() } as Widget.ButtonProps) ] } as Widget.BoxProps), @@ -142,3 +166,24 @@ export const BigMedia: Gtk.Widget = new Widget.Box({ }) ]) } as Widget.BoxProps); + + +/** + * This function handles album art/cover of playing media. If a file is provided + * by the player, it adds the "file://" uri as a prefix, so you can use it in css. + * + * @param player the player you want to pull album art from + * @returns Binding to player.artUrl containing the album art uri, or an undefined binding ig none was found. +* */ +function getAlbumArt(player: AstalMpris.Player): Binding { + return bind(player, "artUrl").as((artUrl: string) => { + const finalUrl: string = artUrl; + + if(/^(https|http)$/.test(finalUrl.split("://")[0])) + return artUrl; + else if(artUrl.startsWith("/")) + return "file://" + artUrl; + + return undefined; + }); +} diff --git a/ags/widget/control-center/Pages.ts b/ags/widget/control-center/Pages.ts new file mode 100644 index 0000000..0fa9204 --- /dev/null +++ b/ags/widget/control-center/Pages.ts @@ -0,0 +1,40 @@ +import { timeout, Variable } from "astal"; +import { Gtk, Widget } from "astal/gtk3"; + +const empty = new Widget.Box(); +const page = new Variable(empty); +let connectionId: (number|undefined); + +export const PagesWidget: Widget.Revealer = new Widget.Revealer({ + revealChild: false, + transitionType: Gtk.RevealerTransitionType.SLIDE_DOWN, + transitionDuration: 250, + child: page() +} as Widget.RevealerProps); + +export function showPages(child: Gtk.Widget, onShow?: (self: Widget.Revealer) => void): void { + page.set(child); + PagesWidget.set_reveal_child(true); + connectionId !== undefined && PagesWidget.disconnect(connectionId); + connectionId = PagesWidget.connect("show", (_) => + onShow && onShow(_)); +} + +export function getPage(): (Gtk.Widget|null) { + return page.get(); +} + +export function togglePage(page: Gtk.Widget): void { + PagesWidget.revealChild ? + hidePages() + : showPages(page); +} + +export function hidePages(onHide?: () => void) { + PagesWidget.set_reveal_child(false); + console.log("heyyyyy"); + timeout(300, () => { + page.set(empty); + onHide && onHide(); + }); +} diff --git a/ags/widget/control-center/QuickActions.ts b/ags/widget/control-center/QuickActions.ts index b4f56cf..4dd3ac6 100644 --- a/ags/widget/control-center/QuickActions.ts +++ b/ags/widget/control-center/QuickActions.ts @@ -1,4 +1,4 @@ -import { Process, Variable } from "astal"; +import { execAsync, Process, Variable } from "astal"; import { Gtk, Widget } from "astal/gtk3"; import AstalHyprland from "gi://AstalHyprland"; @@ -53,10 +53,7 @@ function LogoutButton(): Widget.Button { return new Widget.Button({ className: "nf", label: "󰗽", - onClick: () => Process.exec_async( - "bash -c 'wlogout -b 5'", - () => {} - ) + onClick: () => execAsync("astal open logout-menu") } as Widget.ButtonProps); } diff --git a/ags/widget/control-center/Tiles.ts b/ags/widget/control-center/Tiles.ts index a1f7c4e..6de110f 100644 --- a/ags/widget/control-center/Tiles.ts +++ b/ags/widget/control-center/Tiles.ts @@ -1,21 +1,30 @@ import { Gtk, Widget } from "astal/gtk3"; +import { TileInternet } from "./tiles/Internet"; +import { TileBluetooth } from "./tiles/Bluetooth"; -export const tileList: Array = []; +export const tileList: Array = [ + TileInternet, + TileBluetooth +]; export function TilesWidget(): Gtk.Widget { const tilesFlowBox: Gtk.FlowBox = new Gtk.FlowBox({ visible: true, - noShowAll: false, - orientation: Gtk.Orientation.HORIZONTAL - } as Gtk.Grid.ConstructorProps); + orientation: Gtk.Orientation.HORIZONTAL, + rowSpacing: 6, + columnSpacing: 6, + minChildrenPerLine: 2, + maxChildrenPerLine: 2, + expand: true, + homogeneous: true, + } as Gtk.FlowBox.ConstructorProps); - tileList.map((item: Gtk.Widget) => + tileList.map((item: Gtk.Widget) => tilesFlowBox.insert(item, -1)); return new Widget.Box({ - children: [ - tilesFlowBox - ] + className: "tiles-container", + child: tilesFlowBox } as Widget.BoxProps); } diff --git a/ags/widget/control-center/pages/Bluetooth.ts b/ags/widget/control-center/pages/Bluetooth.ts new file mode 100644 index 0000000..e59850a --- /dev/null +++ b/ags/widget/control-center/pages/Bluetooth.ts @@ -0,0 +1,98 @@ +import { bind, timeout } from "astal"; +import { Gtk, Widget } from "astal/gtk3"; +import AstalBluetooth from "gi://AstalBluetooth?version=0.1"; + +let watchingDevices: boolean = false; + +export function BluetoothPage() { + watchNewDevices(); + + return new Widget.Box({ + className: "page bluetooth container", + orientation: Gtk.Orientation.VERTICAL, + hexpand: true, + children: [ + new Widget.Box({ + className: "header", + children: [ + new Widget.Label({ + hexpand: true, + className: "title", + label: "Bluetooth", + halign: Gtk.Align.START + } as Widget.LabelProps), + ] + } as Widget.BoxProps), + new Widget.Box({ + className: "connections", + orientation: Gtk.Orientation.VERTICAL, + expand: true, + children: bind(AstalBluetooth.get_default(), "devices").as((devices: Array) => + devices.filter((device: AstalBluetooth.Device) => device.connected + ).map((dev: AstalBluetooth.Device) => + new Widget.Button({ + onClick: () => dev.connected ? dev.disconnect_device(null) : dev.connect_device(null), + child: new Widget.Box({ + className: "device", + orientation: Gtk.Orientation.HORIZONTAL, + expand: true, + children: [ + new Widget.Label({ + className: "alias", + halign: Gtk.Align.START, + label: bind(dev, "alias") + } as Widget.LabelProps), + new Widget.Label({ + className: "battery", + halign: Gtk.Align.END, + label: bind(dev, "batteryPercentage").as(String) + } as Widget.LabelProps) + ] + } as Widget.BoxProps) + } as Widget.ButtonProps)).concat( + devices.filter((device: AstalBluetooth.Device) => !device.connected + ).map((dev: AstalBluetooth.Device) => + new Widget.Button({ + onClick: () => dev.connect_device(() => {}), + child: new Widget.Box({ + className: "device", + orientation: Gtk.Orientation.HORIZONTAL, + expand: true, + children: [ + new Widget.Label({ + className: "alias", + halign: Gtk.Align.START, + label: bind(dev, "alias") + } as Widget.LabelProps), + new Widget.Label({ + className: "battery", + halign: Gtk.Align.END, + label: bind(dev, "batteryPercentage").as(String) + } as Widget.LabelProps) + ] + } as Widget.BoxProps) + } as Widget.ButtonProps)) + ) + ) + } as Widget.BoxProps) + ] + } as Widget.BoxProps) +} + +function watchNewDevices(): void { + if(watchingDevices) { + timeout(10000, () => { + reloadDevicesList(); + watchNewDevices(); + }); + } +} + +function stopDeviceWatch(): void { + watchingDevices = false; +} + +function reloadDevicesList(): void { + AstalBluetooth.get_default().adapter.start_discovery(); + timeout(5000, () => AstalBluetooth.get_default().adapter.stop_discovery()); +} diff --git a/ags/widget/control-center/pages/Internet.ts b/ags/widget/control-center/pages/Internet.ts new file mode 100644 index 0000000..15e561b --- /dev/null +++ b/ags/widget/control-center/pages/Internet.ts @@ -0,0 +1,38 @@ +import { bind } from "astal"; +import { Gtk, Widget } from "astal/gtk3"; +import AstalBluetooth from "gi://AstalBluetooth"; + +export function WifiPage() { + return new Widget.Box({ + className: "page bluetooth container", + orientation: Gtk.Orientation.VERTICAL, + hexpand: true, + children: [ + new Widget.Box({ + className: "connections", + orientation: Gtk.Orientation.VERTICAL, + expand: true, + children: bind(AstalBluetooth.get_default(), "devices").as((devices: Array) => + devices && devices.filter((device: AstalBluetooth.Device) => device.connected + ).map((dev: AstalBluetooth.Device) => + new Widget.Box({ + className: "device", + orientation: Gtk.Orientation.HORIZONTAL, + expand: true, + children: [ + new Widget.Label({ + className: "alias", + halign: Gtk.Align.START, + label: bind(dev, "alias") + } as Widget.LabelProps), + new Widget.Label({ + className: "battery", + halign: Gtk.Align.END, + } as Widget.LabelProps) + ] + } as Widget.BoxProps) + )) + } as Widget.BoxProps) + ] + } as Widget.BoxProps); +} diff --git a/ags/widget/control-center/tiles/Bluetooth.ts b/ags/widget/control-center/tiles/Bluetooth.ts new file mode 100644 index 0000000..7bb8467 --- /dev/null +++ b/ags/widget/control-center/tiles/Bluetooth.ts @@ -0,0 +1,21 @@ +import { bind } from "astal"; +import { Tile, TileProps } from "./Tile"; +import AstalBluetooth from "gi://AstalBluetooth"; +import { togglePage } from "../Pages"; +import { BluetoothPage } from "../pages/Bluetooth"; + +export const TileBluetooth = Tile({ + title: "Bluetooth", + description: bind(AstalBluetooth.get_default(), "devices").as((devices: Array) => { + const connected: Array = devices.filter( + (dev: AstalBluetooth.Device) => dev.connected); + + return connected[0] ? connected[0].get_alias() : undefined; + }), + onToggledOn: () => AstalBluetooth.get_default().adapter.set_powered(true), + onToggledOff: () => AstalBluetooth.get_default().adapter.set_powered(false), + onClickMore: () => togglePage(BluetoothPage()), + icon: "󰂯", + iconSize: 16, + toggleState: bind(AstalBluetooth.get_default().adapter, "powered") +} as TileProps); diff --git a/ags/widget/control-center/tiles/Internet.ts b/ags/widget/control-center/tiles/Internet.ts index 41b6a40..6be34af 100644 --- a/ags/widget/control-center/tiles/Internet.ts +++ b/ags/widget/control-center/tiles/Internet.ts @@ -1,8 +1,26 @@ -import { Gtk, Widget } from "astal/gtk3"; +import { bind, execAsync } from "astal"; +import { Tile, TileProps } from "./Tile"; +import AstalNetwork from "gi://AstalNetwork"; +import { Widget } from "astal/gtk3"; export const TileInternet = new Widget.Box({ - className: "tile more internet", - children: [ - toggleButton - ] + child: bind(AstalNetwork.get_default(), "wired").as((wired: AstalNetwork.Wired) => Tile({ + title: "Wired", + description: bind(wired, "internet").as((internet: AstalNetwork.Internet) => { + switch(internet) { + case AstalNetwork.Internet.CONNECTED: + return "Connected"; + case AstalNetwork.Internet.DISCONNECTED: + return "Disconnected"; + case AstalNetwork.Internet.CONNECTING: + return "Connecting..."; + } + }), + onToggledOn: () => execAsync("nmcli n on"), + onToggledOff: () => execAsync("nmcli n off"), + icon: "󰛳", + iconSize: 16, + toggleState: bind(wired, "internet").as((internet: AstalNetwork.Internet) => + internet === AstalNetwork.Internet.CONNECTING || internet === AstalNetwork.Internet.CONNECTED) + } as TileProps)) } as Widget.BoxProps); diff --git a/ags/widget/control-center/tiles/Tile.ts b/ags/widget/control-center/tiles/Tile.ts index 78bdb39..f60ca82 100644 --- a/ags/widget/control-center/tiles/Tile.ts +++ b/ags/widget/control-center/tiles/Tile.ts @@ -1,39 +1,94 @@ -import { Binding } from "astal"; +import { Binding, Variable } from "astal"; import { Gtk, Widget } from "astal/gtk3"; export type TileProps = { className?: string | Binding; - iconName?: string | Binding; + icon?: string | Binding; visible?: boolean | Binding; iconSize?: number | Binding; - title: string | Binding; + title: string | Binding; description?: string | Binding; - defaultToggleState?: boolean; + toggleState?: boolean | Binding; onToggledOn: () => void; onToggledOff: () => void; onClickMore?: () => void; } -export function Tile(props: TileProps): Widget.Box { +export function Tile(props: TileProps): Widget.EventBox { + const toggled = new Variable(props.toggleState instanceof Binding ? + (props.toggleState.get() || false) : (props.toggleState || false)); - const toggleButton = new Gtk.ToggleButton(); - toggleButton.set_active(props.defaultToggleState || false); + if(props?.toggleState instanceof Binding) + props.toggleState.subscribe(val => toggled.set(val || false))(); - const moreButton = new Widget.Button({ - className: "more", - visible: props.onClickMore - }); + return new Widget.EventBox({ + className: toggled().as((state: boolean) => + state ? "tile-eventbox toggled" : "tile-eventbox"), + expand: true, + onClick: () => { + if(toggled.get()) { + toggled.set(false); + console.log(toggled.get()); + props.onToggledOff && props.onToggledOff(); + return; + } - return new Widget.Box({ - className: (typeof Binding) === (typeof props.className) ? - (props.className as Binding).as((clsName: (string|undefined)) => - `tile ${clsName || ""}`) - : - props.className, - visible: props.visible, - children: [ - toggleButton, - moreButton - ] - }) + toggled.set(true); + props.onToggledOn && props.onToggledOn(); + }, + child: new Widget.Box({ + className: (props.className instanceof Binding) ? + props.className.as((clsName: (string|undefined)) => + `tile ${clsName || ""}`) + : `tile ${props.className || ""}`, + visible: props.visible, + expand: true, + hexpand: true, + children: [ + new Widget.Box({ + className: "content", + expand: true, + children: [ + new Widget.Label({ + className: "icon nf", + label: props.icon || "icon", + css: `.icon { font-size: ${props.iconSize || "12px"} }` + } as Widget.LabelProps), + new Widget.Box({ + className: "text", + orientation: Gtk.Orientation.VERTICAL, + vexpand: true, + valign: Gtk.Align.CENTER, + children: [ + new Widget.Label({ + className: "title", + xalign: 0, + truncate: true, + label: props.title + } as Widget.LabelProps), + new Widget.Label({ + className: "description", + visible: props.description, + truncate: true, + xalign: 0, + label: props.description + } as Widget.LabelProps) + ] + } as Widget.BoxProps) + ] + } as Widget.BoxProps), + new Widget.Button({ + className: "more icon", + visible: props.onClickMore !== undefined, + halign: Gtk.Align.END, + image: new Widget.Icon({ + icon: "go-next-symbolic", + css: "icon { font-size: 16px; }" + }), + onClick: () => props.onClickMore && props?.onClickMore(), + widthRequest: 32 + }) + ] + }) + } as Widget.EventBoxProps) } diff --git a/ags/window/CenterWindow.ts b/ags/window/CenterWindow.ts index d415f21..34a02e4 100644 --- a/ags/window/CenterWindow.ts +++ b/ags/window/CenterWindow.ts @@ -1,20 +1,19 @@ -import { Astal, Gtk, Widget } from "astal/gtk3"; +import { Gtk, Widget } from "astal/gtk3"; import { bind, GLib } from "astal"; import { getDateTime } from "../scripts/time"; import { BigMedia } from "../widget/center-window/BigMedia"; import { Separator, SeparatorProps } from "../widget/Separator"; +import { PopupWindow, PopupWindowProps } from "../widget/PopupWindow"; -export const CenterWindow: Widget.Window = new Widget.Window({ +export const CenterWindow: Widget.Window = PopupWindow({ className: "center-window", namespace: "center-window", - canFocus: true, monitor: 0, - layer: Astal.Layer.OVERLAY, - exclusivity: Astal.Exclusivity.NORMAL, visible: false, - margin_top: 10, - anchor: Astal.WindowAnchor.TOP, + marginTop: 10, + valign: Gtk.Align.START, + halign: Gtk.Align.CENTER, child: new Widget.Box({ className: "center-window-container", children: [ @@ -69,4 +68,4 @@ export const CenterWindow: Widget.Window = new Widget.Window({ } as Widget.BoxProps) ] } as Widget.BoxProps) -} as Widget.WindowProps); +} as PopupWindowProps); diff --git a/ags/window/ControlCenter.ts b/ags/window/ControlCenter.ts index 04d6e6e..e5ab433 100644 --- a/ags/window/ControlCenter.ts +++ b/ags/window/ControlCenter.ts @@ -1,26 +1,29 @@ -import { Astal, Gtk, Widget } from "astal/gtk3"; +import { Gtk, Widget } from "astal/gtk3"; import { QuickActions } from "../widget/control-center/QuickActions"; import { Tiles } from "../widget/control-center/Tiles"; import { Sliders } from "../widget/control-center/Sliders"; +import { PopupWindow, PopupWindowProps } from "../widget/PopupWindow"; +import { hidePages, PagesWidget } from "../widget/control-center/Pages"; const widgetsContainer: Widget.Box = new Widget.Box({ className: "control-center-container", orientation: Gtk.Orientation.VERTICAL, + widthRequest: 400, } as Widget.BoxProps, QuickActions, Sliders, -Tiles); +Tiles, +PagesWidget); -export const ControlCenter: Widget.Window = new Widget.Window({ +export const ControlCenter: Widget.Window = PopupWindow({ className: "control-center", namespace: "control-center", - canFocus: true, - exclusivity: Astal.Exclusivity.NORMAL, - anchor: Astal.WindowAnchor.TOP | Astal.WindowAnchor.RIGHT, - layer: Astal.Layer.OVERLAY, - margin_top: 10, - margin_right: 10, - width_request: 400, + marginTop: 10, + marginRight: 10, monitor: 0, - visible: false -} as Widget.WindowProps, widgetsContainer); + onClose: () => hidePages(), + halign: Gtk.Align.END, + valign: Gtk.Align.START, + visible: false, + child: widgetsContainer +} as PopupWindowProps); diff --git a/ags/window/FloatingNotifications.ts b/ags/window/FloatingNotifications.ts index e0a6692..ecdc120 100644 --- a/ags/window/FloatingNotifications.ts +++ b/ags/window/FloatingNotifications.ts @@ -1,71 +1,7 @@ import { Astal, Gtk, Widget } from "astal/gtk3"; import AstalNotifd from "gi://AstalNotifd"; -import { bind } from "astal"; import { Notifications } from "../scripts/notification-handler"; -function NotificationWidget(notification: AstalNotifd.Notification): Gtk.Widget { - return new Widget.Box({ - className: "notification", - homogeneous: false, - expand: false, - orientation: Gtk.Orientation.VERTICAL, - children: [ - new Widget.Box({ - className: "top", - orientation: Gtk.Orientation.HORIZONTAL, - hexpand: true, - vexpand: false, - children: [ - new Widget.Icon({ - className: "icon", - visible: notification.appIcon !== "", - icon: notification.appIcon || "image-missing", - iconSize: Gtk.IconSize.DND, - css: ".icon { font-size: 24px; }" - }), - new Widget.Label({ - className: "app-name", - halign: Gtk.Align.START, - label: notification.appName || "Unknown Application" - } as Widget.LabelProps), - new Widget.Button({ - className: "close nf", - onClick: () => notification.dismiss(), - label: "󰅖" - } as Widget.ButtonProps) - ] - } as Widget.BoxProps), - new Widget.Box({ - className: "content", - orientation: Gtk.Orientation.HORIZONTAL, - children: [ - new Widget.Box({ - className: "image", - visible: notification.image !== "", - css: `box.image { background-image: url('${notification.image}'); }` - } as Widget.BoxProps), - new Widget.Box({ - className: "text", - orientation: Gtk.Orientation.VERTICAL, - children: [ - new Widget.Label({ - className: "summary", - useMarkup: true, - label: notification.summary - }), - new Widget.Label({ - className: "body", - useMarkup: true, - label: notification.body - } as Widget.LabelProps) - ] - } as Widget.BoxProps) - ] - } as Widget.BoxProps) - ] - } as Widget.BoxProps); -} - export const FloatingNotifications: Widget.Window = new Widget.Window({ namespace: "floating-notifications", canFocus: false, diff --git a/ags/window/LogoutMenu.ts b/ags/window/LogoutMenu.ts index 50274c7..58a7c8a 100644 --- a/ags/window/LogoutMenu.ts +++ b/ags/window/LogoutMenu.ts @@ -1,6 +1,6 @@ import { Astal, Gdk, Gtk, Widget } from "astal/gtk3"; import { getDateTime } from "../scripts/time"; -import { execAsync, GLib, Process } from "astal"; +import { execAsync, GLib } from "astal"; const { TOP, LEFT, RIGHT, BOTTOM } = Astal.WindowAnchor; @@ -10,19 +10,25 @@ export const LogoutMenu: Widget.Window = new Widget.Window({ anchor: TOP | LEFT | RIGHT | BOTTOM, layer: Astal.Layer.OVERLAY, exclusivity: Astal.Exclusivity.IGNORE, + keymode: Astal.Keymode.EXCLUSIVE, monitor: 0, visible: false, + onKeyPressEvent: (_, event: Gdk.Event) => { + event.get_keyval()[1] === Gdk.KEY_Escape && + execAsync("astal close logout-menu") + }, child: new Widget.EventBox({ className: "logout-menu", - onClick: () => Process.exec_async("astal close logout-menu", () => {}), + onClick: () => execAsync("astal close logout-menu"), child: new Widget.Box({ - homogeneous: false, + expand: true, orientation: Gtk.Orientation.VERTICAL, children: [ new Widget.Box({ className: "top", - expand: true, + expand: false, orientation: Gtk.Orientation.VERTICAL, + valign: Gtk.Align.START, children: [ new Widget.Label({ className: "time", @@ -45,17 +51,17 @@ export const LogoutMenu: Widget.Window = new Widget.Window({ new Widget.Button({ className: "poweroff nf", label: "󰐥", - onClick: "ask user if it's fr!" + onClick: () => execAsync("systemctl poweroff") } as Widget.ButtonProps), new Widget.Button({ className: "reboot nf", label: "󰜉", - onClick: "ask user if it's fr!" + onClick: () => execAsync("systemctl reboot") } as Widget.ButtonProps), new Widget.Button({ className: "suspend nf", label: "󰤄", - onClick: "ask user if it's fr!" + onClick: () => execAsync("systemctl suspend") } as Widget.ButtonProps), new Widget.Button({ className: "logout nf", diff --git a/ags/window/Runner.ts b/ags/window/Runner.ts index 82410a7..80c6ddb 100644 --- a/ags/window/Runner.ts +++ b/ags/window/Runner.ts @@ -1,10 +1,12 @@ import { Variable } from "astal"; import { Astal, Gtk, Widget } from "astal/gtk3"; +import { PopupWindow, PopupWindowProps } from "../widget/PopupWindow"; // TODO export interface RunnerProps { - anchor?: Astal.WindowAnchor; + halign?: Gtk.Align; + valign?: Gtk.Align; width?: number; height?: number; entryPlaceHolder?: string; @@ -20,8 +22,10 @@ export function Runner(props?: RunnerProps) { } as Widget.BoxProps); - return new Widget.Window({ + return PopupWindow({ namespace: "runner", + halign: props?.halign || Gtk.Align.CENTER, + valign: props?.valign || Gtk.Align.CENTER, widthRequest: props?.width || 600, heightRequest: props?.height || 500, child: new Widget.Box({ @@ -33,5 +37,5 @@ export function Runner(props?: RunnerProps) { } as Widget.EntryProps), ] } as Widget.BoxProps) - } as Widget.WindowProps); + } as PopupWindowProps); } diff --git a/ags/window/SelectWallpaper.ts b/ags/window/SelectWallpaper.ts new file mode 100644 index 0000000..e69de29 diff --git a/ags/window/Wallpaper.ts b/ags/window/Wallpaper.ts new file mode 100644 index 0000000..c507d70 --- /dev/null +++ b/ags/window/Wallpaper.ts @@ -0,0 +1,44 @@ +import { Variable } from "astal"; +import { Astal, Gdk, Gtk, Widget } from "astal/gtk3"; +import { restartInstance } from "../scripts/reload-handler"; + +const { LEFT, RIGHT, TOP, BOTTOM } = Astal.WindowAnchor; +const wallpaper: Variable = new Variable(undefined); + +const changeWallpaperButton = new Gtk.MenuItem(); +changeWallpaperButton.set_label("Change wallpaper"); + +const reloadShellButton = new Gtk.MenuItem(); +reloadShellButton.set_label("Reload Shell"); +reloadShellButton.connect("activate", (_) => restartInstance()); + +const desktopMenuButtons: Array = [ + changeWallpaperButton, + reloadShellButton +]; + +export const Wallpaper: Widget.Window = new Widget.Window({ + namespace: "wallpaper", + layer: Astal.Layer.BACKGROUND, + anchor: LEFT | RIGHT | TOP | BOTTOM, + exclusivity: Astal.Exclusivity.IGNORE, + keymode: Astal.Keymode.NONE, + visible: true, + monitor: 0, //Needs rework for all monitors + child: new Widget.Box({ + className: "wallpaper", + } as Widget.BoxProps), + onButtonPressEvent: (_, event: Gdk.Event) => { + const [ , x, y ] = event.get_coords(); + if(event.get_button()[1] === Gdk.BUTTON_SECONDARY) + desktopMenu.popup_at_pointer(Gdk.Event.peek()); + } +} as Widget.WindowProps); + +const desktopMenu: Gtk.Menu = new Gtk.Menu({ + visible: true, + monitor: Wallpaper.monitor || 0 +} as Gtk.Menu.ConstructorProps); + +desktopMenuButtons.map((item: Gtk.MenuItem) => + desktopMenu.insert(item, -1)) diff --git a/ags/windows.ts b/ags/windows.ts index dbe36f9..5a94184 100644 --- a/ags/windows.ts +++ b/ags/windows.ts @@ -5,28 +5,25 @@ import { OSD } from "./window/OSD"; import { ControlCenter } from "./window/ControlCenter"; import { CenterWindow } from "./window/CenterWindow"; import { FloatingNotifications } from "./window/FloatingNotifications"; -import { GObject } from "astal"; +import { GObject, register } from "astal"; import { LogoutMenu } from "./window/LogoutMenu"; +import { Wallpaper } from "./window/Wallpaper"; /** * get open windows / interact with windows(e.g.: close, open or toggle) */ -export const Windows = GObject.registerClass({ - GTypeName: "Windows" -}, class WindowsClass extends GObject.Object { +@register({ GTypeName: "Windows" }) +class WindowsClass extends GObject.Object { private static windowsMap: Map = new Map(); static { - WindowsClass.windowsMap.set("bar", Bar); - WindowsClass.windowsMap.set("osd", OSD); - WindowsClass.windowsMap.set("control-center", ControlCenter); - WindowsClass.windowsMap.set("center-window", CenterWindow); - WindowsClass.windowsMap.set("logout-menu", LogoutMenu); - WindowsClass.windowsMap.set("floating-notifications", FloatingNotifications); - } - - public _init(...args: any[]) { - super._init(args); + this.setWindow("bar", Bar); + this.setWindow("osd", OSD); + this.setWindow("control-center", ControlCenter); + this.setWindow("center-window", CenterWindow); + this.setWindow("logout-menu", LogoutMenu); + this.setWindow("floating-notifications", FloatingNotifications); + this.setWindow("wallpaper", Wallpaper); } public static setWindow(name: string, window: Gtk.Window): void { @@ -56,4 +53,6 @@ export const Windows = GObject.registerClass({ public static toggle(window: Gtk.Window): void { window.is_visible() ? WindowsClass.close(window) : WindowsClass.open(window); } -}); +} + +export { WindowsClass as Windows };