summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitattributes1
-rw-r--r--docs/guide/getting-started/supported-languages.md9
-rw-r--r--docs/guide/libraries/apps.md68
-rw-r--r--docs/guide/libraries/auth.md90
-rw-r--r--docs/guide/libraries/battery.md78
-rw-r--r--docs/guide/libraries/bluetooth.md78
-rw-r--r--docs/guide/libraries/cava.md80
-rw-r--r--docs/guide/libraries/greet.md78
-rw-r--r--docs/guide/libraries/hyprland.md68
-rw-r--r--docs/guide/libraries/mpris.md92
-rw-r--r--docs/guide/libraries/network.md68
-rw-r--r--docs/guide/libraries/notifd.md68
-rw-r--r--docs/guide/libraries/powerprofiles.md78
-rw-r--r--docs/guide/libraries/references.md2
-rw-r--r--docs/guide/libraries/river.md68
-rw-r--r--docs/guide/libraries/tray.md68
-rw-r--r--docs/guide/libraries/wireplumber.md68
-rw-r--r--examples/js/.gitignore1
-rw-r--r--examples/js/applauncher/README.md5
-rw-r--r--examples/js/applauncher/app.ts9
-rw-r--r--examples/js/applauncher/style.scss1
-rw-r--r--examples/js/applauncher/widget/Applauncher.scss59
-rw-r--r--examples/js/applauncher/widget/Applauncher.tsx87
-rw-r--r--examples/js/media-player/README.md5
-rw-r--r--examples/js/media-player/app.ts11
-rw-r--r--examples/js/media-player/style.scss1
-rw-r--r--examples/js/media-player/widget/MediaPlayer.scss56
-rw-r--r--examples/js/media-player/widget/MediaPlayer.tsx94
-rw-r--r--examples/js/notifications/README.md5
-rw-r--r--examples/js/notifications/app.ts9
-rw-r--r--examples/js/notifications/notifications/Notification.scss125
-rw-r--r--examples/js/notifications/notifications/Notification.tsx107
-rw-r--r--examples/js/notifications/notifications/NotificationPopups.tsx105
-rw-r--r--examples/js/notifications/style.scss1
-rw-r--r--examples/js/simple-bar/.gitignore2
-rw-r--r--lang/gjs/src/gtk3/astalify.ts2
-rw-r--r--lib/network/network.vala26
37 files changed, 1232 insertions, 541 deletions
diff --git a/.gitattributes b/.gitattributes
index df23535..cd3dbf9 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -2,3 +2,4 @@
*.js linguist-language=TypeScript
*.vue linguist-vendored
*.h linguist-vendored
+examples/** linguist-vendored
diff --git a/docs/guide/getting-started/supported-languages.md b/docs/guide/getting-started/supported-languages.md
index d6d669d..eacd1da 100644
--- a/docs/guide/getting-started/supported-languages.md
+++ b/docs/guide/getting-started/supported-languages.md
@@ -21,6 +21,15 @@ Examples:
- [Simple Bar](https://github.com/Aylur/astal/tree/main/examples/js/simple-bar)
![simple-bar](https://github.com/user-attachments/assets/a306c864-56b7-44c4-8820-81f424f32b9b)
+- [Notification Popups](https://github.com/Aylur/astal/tree/main/examples/js/notifications)
+![notification-popups](https://github.com/user-attachments/assets/0df0eddc-5c74-4af0-a694-48dc8ec6bb44)
+
+- [Applauncher](https://github.com/Aylur/astal/tree/main/examples/js/applauncher)
+![launcher](https://github.com/user-attachments/assets/2695e3bb-dff4-478a-b392-279fe638bfd3)
+
+- [Media Player](https://github.com/Aylur/astal/tree/main/examples/js/media-player)
+![media-player](https://github.com/user-attachments/assets/891e9706-74db-4505-bd83-c3628d7b4fd0)
+
## Lua
Lua is well-supported, but I would still recommend TypeScript, as Lua lacks a type system, which in turn limits editor support.
diff --git a/docs/guide/libraries/apps.md b/docs/guide/libraries/apps.md
index 1871d18..f1748db 100644
--- a/docs/guide/libraries/apps.md
+++ b/docs/guide/libraries/apps.md
@@ -3,40 +3,6 @@
Library and CLI tool for querying and launching
applications that have a corresponding `.desktop` file.
-## Installation
-
-1. install dependencies
-
-:::code-group
-
-```sh [<i class="devicon-archlinux-plain"></i> Arch]
-sudo pacman -Syu meson vala json-glib gobject-introspection
-```
-
-```sh [<i class="devicon-fedora-plain"></i> Fedora]
-sudo dnf install meson vala valadoc json-glib-devel gobject-introspection-devel
-```
-
-```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
-sudo apt install meson valac libjson-glib-dev gobject-introspection
-```
-
-:::
-
-2. clone repo
-
-```sh
-git clone https://github.com/aylur/astal.git
-cd astal/lib/apps
-```
-
-3. install
-
-```sh
-meson setup --prefix /usr build
-meson install -C build
-```
-
## Usage
You can browse the [Apps reference](https://aylur.github.io/libastal/apps).
@@ -106,3 +72,37 @@ foreach (var app in apps.fuzzy_query("firefox")) {
```
:::
+
+## Installation
+
+1. install dependencies
+
+:::code-group
+
+```sh [<i class="devicon-archlinux-plain"></i> Arch]
+sudo pacman -Syu meson vala json-glib gobject-introspection
+```
+
+```sh [<i class="devicon-fedora-plain"></i> Fedora]
+sudo dnf install meson vala valadoc json-glib-devel gobject-introspection-devel
+```
+
+```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
+sudo apt install meson valac libjson-glib-dev gobject-introspection
+```
+
+:::
+
+2. clone repo
+
+```sh
+git clone https://github.com/aylur/astal.git
+cd astal/lib/apps
+```
+
+3. install
+
+```sh
+meson setup --prefix /usr build
+meson install -C build
+```
diff --git a/docs/guide/libraries/auth.md b/docs/guide/libraries/auth.md
index d5f0a49..b52e38a 100644
--- a/docs/guide/libraries/auth.md
+++ b/docs/guide/libraries/auth.md
@@ -2,51 +2,6 @@
Library and CLI tool for authentication using [pam](https://github.com/linux-pam/linux-pam).
-## Installation
-
-1. install dependencies
-
-:::code-group
-
-```sh [<i class="devicon-archlinux-plain"></i> Arch]
-sudo pacman -Syu meson pam gobject-introspection
-```
-
-```sh [<i class="devicon-fedora-plain"></i> Fedora]
-sudo dnf install meson pam-devel gobject-introspection-devel
-```
-
-```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
-# Not yet documented
-```
-
-:::
-
-::: warning On NixOS you have to add `astal-auth` to `security.pam`.
-::: code-group
-
-```nix [configuration.nix]
-{
- security.pam.services.astal-auth = {}
-}
-```
-
-:::
-
-2. clone repo
-
-```sh
-git clone https://github.com/aylur/astal.git
-cd astal/lib/auth
-```
-
-3. install
-
-```sh
-meson setup --prefix /usr build
-meson install -C build
-```
-
## Usage
You can browse the [Auth reference](https://aylur.github.io/libastal/auth).
@@ -105,3 +60,48 @@ end)
```
:::
+
+## Installation
+
+1. install dependencies
+
+:::code-group
+
+```sh [<i class="devicon-archlinux-plain"></i> Arch]
+sudo pacman -Syu meson pam gobject-introspection
+```
+
+```sh [<i class="devicon-fedora-plain"></i> Fedora]
+sudo dnf install meson pam-devel gobject-introspection-devel
+```
+
+```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
+# Not yet documented
+```
+
+:::
+
+::: warning On NixOS you have to add `astal-auth` to `security.pam`.
+::: code-group
+
+```nix [configuration.nix]
+{
+ security.pam.services.astal-auth = {}
+}
+```
+
+:::
+
+2. clone repo
+
+```sh
+git clone https://github.com/aylur/astal.git
+cd astal/lib/auth
+```
+
+3. install
+
+```sh
+meson setup --prefix /usr build
+meson install -C build
+```
diff --git a/docs/guide/libraries/battery.md b/docs/guide/libraries/battery.md
index 56f955c..7e6fe24 100644
--- a/docs/guide/libraries/battery.md
+++ b/docs/guide/libraries/battery.md
@@ -2,45 +2,6 @@
Library and CLI tool for monitoring [upowerd](https://upower.freedesktop.org/) devices.
-## Installation
-
-1. install dependencies
-
-:::code-group
-
-```sh [<i class="devicon-archlinux-plain"></i> Arch]
-sudo pacman -Syu meson vala json-glib gobject-introspection
-```
-
-```sh [<i class="devicon-fedora-plain"></i> Fedora]
-sudo dnf install meson vala valadoc json-glib-devel gobject-introspection-devel
-```
-
-```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
-sudo apt install meson valac libjson-glib-dev gobject-introspection
-```
-
-:::
-
-::: info
-Although UPower is not a direct build dependency,
-it should be self-explanatory that the daemon is required to be available at runtime.
-:::
-
-2. clone repo
-
-```sh
-git clone https://github.com/aylur/astal.git
-cd astal/lib/battery
-```
-
-3. install
-
-```sh
-meson setup --prefix /usr build
-meson install -C build
-```
-
## Usage
You can browse the [Battery reference](https://aylur.github.io/libastal/battery).
@@ -84,3 +45,42 @@ print(battery.percentage)
```
:::
+
+## Installation
+
+1. install dependencies
+
+:::code-group
+
+```sh [<i class="devicon-archlinux-plain"></i> Arch]
+sudo pacman -Syu meson vala json-glib gobject-introspection
+```
+
+```sh [<i class="devicon-fedora-plain"></i> Fedora]
+sudo dnf install meson vala valadoc json-glib-devel gobject-introspection-devel
+```
+
+```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
+sudo apt install meson valac libjson-glib-dev gobject-introspection
+```
+
+:::
+
+::: info
+Although UPower is not a direct build dependency,
+it should be self-explanatory that the daemon is required to be available at runtime.
+:::
+
+2. clone repo
+
+```sh
+git clone https://github.com/aylur/astal.git
+cd astal/lib/battery
+```
+
+3. install
+
+```sh
+meson setup --prefix /usr build
+meson install -C build
+```
diff --git a/docs/guide/libraries/bluetooth.md b/docs/guide/libraries/bluetooth.md
index 03ac9c9..9a3e5b8 100644
--- a/docs/guide/libraries/bluetooth.md
+++ b/docs/guide/libraries/bluetooth.md
@@ -2,45 +2,6 @@
Library for monitoring [bluez](https://www.bluez.org/) over dbus.
-## Installation
-
-1. install dependencies
-
-:::code-group
-
-```sh [<i class="devicon-archlinux-plain"></i> Arch]
-sudo pacman -Syu meson vala gobject-introspection
-```
-
-```sh [<i class="devicon-fedora-plain"></i> Fedora]
-sudo dnf install meson vala valadoc gobject-introspection-devel
-```
-
-```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
-sudo apt install meson valac gobject-introspection
-```
-
-:::
-
-::: info
-Although bluez is not a direct build dependency,
-it should be self-explanatory that the daemon is required to be available at runtime.
-:::
-
-2. clone repo
-
-```sh
-git clone https://github.com/aylur/astal.git
-cd astal/lib/bluetooth
-```
-
-3. install
-
-```sh
-meson setup --prefix /usr build
-meson install -C build
-```
-
## Usage
You can browse the [Bluetooth reference](https://aylur.github.io/libastal/bluetooth).
@@ -91,3 +52,42 @@ end
```
:::
+
+## Installation
+
+1. install dependencies
+
+:::code-group
+
+```sh [<i class="devicon-archlinux-plain"></i> Arch]
+sudo pacman -Syu meson vala gobject-introspection
+```
+
+```sh [<i class="devicon-fedora-plain"></i> Fedora]
+sudo dnf install meson vala valadoc gobject-introspection-devel
+```
+
+```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
+sudo apt install meson valac gobject-introspection
+```
+
+:::
+
+::: info
+Although bluez is not a direct build dependency,
+it should be self-explanatory that the daemon is required to be available at runtime.
+:::
+
+2. clone repo
+
+```sh
+git clone https://github.com/aylur/astal.git
+cd astal/lib/bluetooth
+```
+
+3. install
+
+```sh
+meson setup --prefix /usr build
+meson install -C build
+```
diff --git a/docs/guide/libraries/cava.md b/docs/guide/libraries/cava.md
index e695e16..60b2824 100644
--- a/docs/guide/libraries/cava.md
+++ b/docs/guide/libraries/cava.md
@@ -2,6 +2,46 @@
Audio visualizer using [cava](https://github.com/karlstav/cava).
+## Usage
+
+You can browse the [Cava reference](https://aylur.github.io/libastal/cava).
+
+### CLI
+
+There is no CLI for this library, use the one provided by cava.
+
+```sh
+cava
+```
+
+### Library
+
+:::code-group
+
+```js [<i class="devicon-javascript-plain"></i> JavaScript]
+import Cava from "gi://AstalCava"
+
+const cava = Cava.get_default()
+
+cava.connect("notify::values", () => {
+ print(cava.get_values())
+})
+```
+
+```py [<i class="devicon-python-plain"></i> Python]
+# Not yet documented
+```
+
+```lua [<i class="devicon-lua-plain"></i> Lua]
+-- Not yet documented
+```
+
+```vala [<i class="devicon-vala-plain"></i> Vala]
+// Not yet documented
+```
+
+:::
+
## Installation
1. install dependencies
@@ -49,43 +89,3 @@ meson setup --prefix /usr build
```
:::
-
-## Usage
-
-You can browse the [Cava reference](https://aylur.github.io/libastal/cava).
-
-### CLI
-
-There is no CLI for this library, use the one provided by cava.
-
-```sh
-cava
-```
-
-### Library
-
-:::code-group
-
-```js [<i class="devicon-javascript-plain"></i> JavaScript]
-import Cava from "gi://AstalCava"
-
-const cava = Cava.get_default()
-
-cava.connect("notify::values", () => {
- print(cava.get_values())
-})
-```
-
-```py [<i class="devicon-python-plain"></i> Python]
-# Not yet documented
-```
-
-```lua [<i class="devicon-lua-plain"></i> Lua]
--- Not yet documented
-```
-
-```vala [<i class="devicon-vala-plain"></i> Vala]
-// Not yet documented
-```
-
-:::
diff --git a/docs/guide/libraries/greet.md b/docs/guide/libraries/greet.md
index f0cd012..47f98b9 100644
--- a/docs/guide/libraries/greet.md
+++ b/docs/guide/libraries/greet.md
@@ -2,45 +2,6 @@
Library and CLI tool for sending requests to [greetd](https://sr.ht/~kennylevinsen/greetd/).
-## Installation
-
-1. install dependencies
-
-:::code-group
-
-```sh [<i class="devicon-archlinux-plain"></i> Arch]
-sudo pacman -Syu meson vala json-glib gobject-introspection
-```
-
-```sh [<i class="devicon-fedora-plain"></i> Fedora]
-sudo dnf install meson vala valadoc json-glib-devel gobject-introspection-devel
-```
-
-```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
-sudo apt install meson valac libjson-glib-dev gobject-introspection
-```
-
-:::
-
-::: info
-Although `greetd` is not a direct build dependency,
-it should be self-explanatory that the daemon is required to be available at runtime.
-:::
-
-2. clone repo
-
-```sh
-git clone https://github.com/aylur/astal.git
-cd astal/lib/greet
-```
-
-3. install
-
-```sh
-meson setup --prefix /usr build
-meson install -C build
-```
-
## Usage
You can browse the [Greet reference](https://aylur.github.io/libastal/greet).
@@ -92,3 +53,42 @@ try {
```
:::
+
+## Installation
+
+1. install dependencies
+
+:::code-group
+
+```sh [<i class="devicon-archlinux-plain"></i> Arch]
+sudo pacman -Syu meson vala json-glib gobject-introspection
+```
+
+```sh [<i class="devicon-fedora-plain"></i> Fedora]
+sudo dnf install meson vala valadoc json-glib-devel gobject-introspection-devel
+```
+
+```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
+sudo apt install meson valac libjson-glib-dev gobject-introspection
+```
+
+:::
+
+::: info
+Although `greetd` is not a direct build dependency,
+it should be self-explanatory that the daemon is required to be available at runtime.
+:::
+
+2. clone repo
+
+```sh
+git clone https://github.com/aylur/astal.git
+cd astal/lib/greet
+```
+
+3. install
+
+```sh
+meson setup --prefix /usr build
+meson install -C build
+```
diff --git a/docs/guide/libraries/hyprland.md b/docs/guide/libraries/hyprland.md
index 94a398f..82d9e9d 100644
--- a/docs/guide/libraries/hyprland.md
+++ b/docs/guide/libraries/hyprland.md
@@ -2,40 +2,6 @@
Library and CLI tool for monitoring the [Hyprland socket](https://wiki.hyprland.org/IPC/).
-## Installation
-
-1. install dependencies
-
-:::code-group
-
-```sh [<i class="devicon-archlinux-plain"></i> Arch]
-sudo pacman -Syu meson vala json-glib gobject-introspection
-```
-
-```sh [<i class="devicon-fedora-plain"></i> Fedora]
-sudo dnf install meson vala valadoc json-glib-devel gobject-introspection-devel
-```
-
-```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
-sudo apt install meson valac libjson-glib-dev gobject-introspection
-```
-
-:::
-
-2. clone repo
-
-```sh
-git clone https://github.com/aylur/astal.git
-cd astal/lib/hyprland
-```
-
-3. install
-
-```sh
-meson setup --prefix /usr build
-meson install -C build
-```
-
## Usage
You can browse the [Hyprland reference](https://aylur.github.io/libastal/hyprland).
@@ -84,3 +50,37 @@ end
```
:::
+
+## Installation
+
+1. install dependencies
+
+:::code-group
+
+```sh [<i class="devicon-archlinux-plain"></i> Arch]
+sudo pacman -Syu meson vala json-glib gobject-introspection
+```
+
+```sh [<i class="devicon-fedora-plain"></i> Fedora]
+sudo dnf install meson vala valadoc json-glib-devel gobject-introspection-devel
+```
+
+```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
+sudo apt install meson valac libjson-glib-dev gobject-introspection
+```
+
+:::
+
+2. clone repo
+
+```sh
+git clone https://github.com/aylur/astal.git
+cd astal/lib/hyprland
+```
+
+3. install
+
+```sh
+meson setup --prefix /usr build
+meson install -C build
+```
diff --git a/docs/guide/libraries/mpris.md b/docs/guide/libraries/mpris.md
index 30f3d13..c2283cc 100644
--- a/docs/guide/libraries/mpris.md
+++ b/docs/guide/libraries/mpris.md
@@ -6,52 +6,6 @@ exposing an mpris interface through dbus.
An alternative for [playerctl](https://github.com/altdesktop/playerctl) that better integrates
with astal.
-:::warning
-In order for network cover art urls to be cached (spotify for example)
-make sure `gvfs` is enabled.
-
-:::code-group
-
-```nix [<i class="devicon-nixos-plain"></i> configuration.nix]
-services.gvfs.enable = true;
-```
-
-:::
-
-## Installation
-
-1. install dependencies
-
-:::code-group
-
-```sh [<i class="devicon-archlinux-plain"></i> Arch]
-sudo pacman -Syu meson vala gvfs json-glib gobject-introspection
-```
-
-```sh [<i class="devicon-fedora-plain"></i> Fedora]
-sudo dnf install meson vala valadoc gvfs json-glib-devel gobject-introspection-devel
-```
-
-```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
-sudo apt install meson valac gvfs libjson-glib-dev gobject-introspection
-```
-
-:::
-
-2. clone repo
-
-```sh
-git clone https://github.com/aylur/astal.git
-cd astal/lib/mpris
-```
-
-3. install
-
-```sh
-meson setup --prefix /usr build
-meson install -C build
-```
-
## Usage
You can browse the [Mpris reference](https://aylur.github.io/libastal/mpris).
@@ -99,3 +53,49 @@ end
```
:::
+
+## Installation
+
+1. install dependencies
+
+:::code-group
+
+```sh [<i class="devicon-archlinux-plain"></i> Arch]
+sudo pacman -Syu meson vala gvfs json-glib gobject-introspection
+```
+
+```sh [<i class="devicon-fedora-plain"></i> Fedora]
+sudo dnf install meson vala valadoc gvfs json-glib-devel gobject-introspection-devel
+```
+
+```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
+sudo apt install meson valac gvfs libjson-glib-dev gobject-introspection
+```
+
+:::
+
+2. clone repo
+
+```sh
+git clone https://github.com/aylur/astal.git
+cd astal/lib/mpris
+```
+
+3. install
+
+```sh
+meson setup --prefix /usr build
+meson install -C build
+```
+
+:::warning
+In order for network cover art urls to be cached (spotify for example)
+make sure `gvfs` is enabled.
+
+:::code-group
+
+```nix [<i class="devicon-nixos-plain"></i> configuration.nix]
+services.gvfs.enable = true;
+```
+
+:::
diff --git a/docs/guide/libraries/network.md b/docs/guide/libraries/network.md
index 21c7b10..79a217c 100644
--- a/docs/guide/libraries/network.md
+++ b/docs/guide/libraries/network.md
@@ -2,40 +2,6 @@
Wrapper library over [networkmanager](https://networkmanager.dev/) to better integrate with Astal.
-## Installation
-
-1. install dependencies
-
-:::code-group
-
-```sh [<i class="devicon-archlinux-plain"></i> Arch]
-sudo pacman -Syu meson vala libnm gobject-introspection
-```
-
-```sh [<i class="devicon-fedora-plain"></i> Fedora]
-sudo dnf install meson vala valadoc NetworkManager-libnm-devel gobject-introspection-devel
-```
-
-```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
-sudo apt install meson valac libnm-dev gobject-introspection
-```
-
-:::
-
-2. clone repo
-
-```sh
-git clone https://github.com/aylur/astal.git
-cd astal/lib/network
-```
-
-3. install
-
-```sh
-meson setup --prefix /usr build
-meson install -C build
-```
-
## Usage
You can browse the [Network reference](https://aylur.github.io/libastal/network).
@@ -81,3 +47,37 @@ print(network.wifi.ssid)
```
:::
+
+## Installation
+
+1. install dependencies
+
+:::code-group
+
+```sh [<i class="devicon-archlinux-plain"></i> Arch]
+sudo pacman -Syu meson vala libnm gobject-introspection
+```
+
+```sh [<i class="devicon-fedora-plain"></i> Fedora]
+sudo dnf install meson vala valadoc NetworkManager-libnm-devel gobject-introspection-devel
+```
+
+```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
+sudo apt install meson valac libnm-dev gobject-introspection
+```
+
+:::
+
+2. clone repo
+
+```sh
+git clone https://github.com/aylur/astal.git
+cd astal/lib/network
+```
+
+3. install
+
+```sh
+meson setup --prefix /usr build
+meson install -C build
+```
diff --git a/docs/guide/libraries/notifd.md b/docs/guide/libraries/notifd.md
index 4208700..1d61099 100644
--- a/docs/guide/libraries/notifd.md
+++ b/docs/guide/libraries/notifd.md
@@ -6,40 +6,6 @@ A [notification daemon](https://specifications.freedesktop.org/notification-spec
The first instantiation of the [Notifd](https://aylur.github.io/libastal/notifd/class.Notifd.html) class will become the daemon and every subsequent instantiation will queue up to act as the daemon and will act as a client in the meantime. This means this library can be used throughout multiple processes.
-## Installation
-
-1. install dependencies
-
-:::code-group
-
-```sh [<i class="devicon-archlinux-plain"></i> Arch]
-sudo pacman -Syu meson vala gdk-pixbuf2 json-glib gobject-introspection
-```
-
-```sh [<i class="devicon-fedora-plain"></i> Fedora]
-sudo dnf install meson vala valadoc gdk-pixbuf2-devel json-glib-devel gobject-introspection-devel
-```
-
-```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
-sudo apt install meson valac libgdk-pixbuf-2.0-dev libjson-glib-dev gobject-introspection
-```
-
-:::
-
-2. clone repo
-
-```sh
-git clone https://github.com/aylur/astal.git
-cd astal/lib/notifd
-```
-
-3. install
-
-```sh
-meson setup --prefix /usr build
-meson install -C build
-```
-
## Usage
You can browse the [Notifd reference](https://aylur.github.io/libastal/notifd).
@@ -93,3 +59,37 @@ end
```
:::
+
+## Installation
+
+1. install dependencies
+
+:::code-group
+
+```sh [<i class="devicon-archlinux-plain"></i> Arch]
+sudo pacman -Syu meson vala gdk-pixbuf2 json-glib gobject-introspection
+```
+
+```sh [<i class="devicon-fedora-plain"></i> Fedora]
+sudo dnf install meson vala valadoc gdk-pixbuf2-devel json-glib-devel gobject-introspection-devel
+```
+
+```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
+sudo apt install meson valac libgdk-pixbuf-2.0-dev libjson-glib-dev gobject-introspection
+```
+
+:::
+
+2. clone repo
+
+```sh
+git clone https://github.com/aylur/astal.git
+cd astal/lib/notifd
+```
+
+3. install
+
+```sh
+meson setup --prefix /usr build
+meson install -C build
+```
diff --git a/docs/guide/libraries/powerprofiles.md b/docs/guide/libraries/powerprofiles.md
index bdafcde..b42d7c6 100644
--- a/docs/guide/libraries/powerprofiles.md
+++ b/docs/guide/libraries/powerprofiles.md
@@ -2,45 +2,6 @@
Library and CLI tool for monitoring [upowerd](https://upower.freedesktop.org/) powerprofiles.
-## Installation
-
-1. install dependencies
-
-:::code-group
-
-```sh [<i class="devicon-archlinux-plain"></i> Arch]
-sudo pacman -Syu meson vala json-glib gobject-introspection
-```
-
-```sh [<i class="devicon-fedora-plain"></i> Fedora]
-sudo dnf install meson vala valadoc json-glib-devel gobject-introspection-devel
-```
-
-```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
-sudo apt install meson valac libjson-glib-dev gobject-introspection
-```
-
-:::
-
-::: info
-Although UPower is not a direct build dependency,
-it should be self-explanatory that the daemon is required to be available at runtime.
-:::
-
-2. clone repo
-
-```sh
-git clone https://github.com/aylur/astal.git
-cd astal/lib/powerprofiles
-```
-
-3. install
-
-```sh
-meson setup --prefix /usr build
-meson install -C build
-```
-
## Usage
You can browse the [PowerProfiles reference](https://aylur.github.io/libastal/powerprofiles).
@@ -84,3 +45,42 @@ print(powerprofiles.active_profile)
```
:::
+
+## Installation
+
+1. install dependencies
+
+:::code-group
+
+```sh [<i class="devicon-archlinux-plain"></i> Arch]
+sudo pacman -Syu meson vala json-glib gobject-introspection
+```
+
+```sh [<i class="devicon-fedora-plain"></i> Fedora]
+sudo dnf install meson vala valadoc json-glib-devel gobject-introspection-devel
+```
+
+```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
+sudo apt install meson valac libjson-glib-dev gobject-introspection
+```
+
+:::
+
+::: info
+Although UPower is not a direct build dependency,
+it should be self-explanatory that the daemon is required to be available at runtime.
+:::
+
+2. clone repo
+
+```sh
+git clone https://github.com/aylur/astal.git
+cd astal/lib/powerprofiles
+```
+
+3. install
+
+```sh
+meson setup --prefix /usr build
+meson install -C build
+```
diff --git a/docs/guide/libraries/references.md b/docs/guide/libraries/references.md
index 3a85d73..f8ab4d8 100644
--- a/docs/guide/libraries/references.md
+++ b/docs/guide/libraries/references.md
@@ -33,6 +33,8 @@ Reading their documentation will vary depending on the language they are used in
- [Auth](https://aylur.github.io/libastal/auth): Authentication library using PAM
- [Battery](https://aylur.github.io/libastal/battery): DBus proxy library for upower daemon
- [Bluetooth](https://aylur.github.io/libastal/bluetooth): Library to control bluez over dbus
+- [Cava](https://aylur.github.io/libastal/cava): Audio visualizer library using cava
+- [Greet](https://aylur.github.io/libastal/greet): Library and CLI tool for sending requests to greetd
- [Hyprland](https://aylur.github.io/libastal/hyprland): Library and cli tool for Hyprland IPC socket
- [Mpris](https://aylur.github.io/libastal/mpris): Library and cli tool for controlling media players
- [Network](https://aylur.github.io/libastal/network): NetworkManager wrapper library
diff --git a/docs/guide/libraries/river.md b/docs/guide/libraries/river.md
index 299aa8c..dc1c71e 100644
--- a/docs/guide/libraries/river.md
+++ b/docs/guide/libraries/river.md
@@ -2,40 +2,6 @@
Library and CLI tool for monitoring the [River Wayland Compositor](https://isaacfreund.com/software/river/).
-## Installation
-
-1. install dependencies
-
-:::code-group
-
-```sh [<i class="devicon-archlinux-plain"></i> Arch]
-sudo pacman -Syu meson json-glib gobject-introspection
-```
-
-```sh [<i class="devicon-fedora-plain"></i> Fedora]
-sudo dnf install meson gcc json-glib-devel gobject-introspection-devel
-```
-
-```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
-sudo apt install meson libjson-glib-dev gobject-introspection
-```
-
-:::
-
-2. clone repo
-
-```sh
-git clone https://github.com/aylur/astal.git
-cd astal/lib/river
-```
-
-3. install
-
-```sh
-meson setup --prefix /usr build
-meson install -C build
-```
-
## Usage
You can browse the [River reference](https://aylur.github.io/libastal/river).
@@ -84,3 +50,37 @@ end
```
:::
+
+## Installation
+
+1. install dependencies
+
+:::code-group
+
+```sh [<i class="devicon-archlinux-plain"></i> Arch]
+sudo pacman -Syu meson json-glib gobject-introspection
+```
+
+```sh [<i class="devicon-fedora-plain"></i> Fedora]
+sudo dnf install meson gcc json-glib-devel gobject-introspection-devel
+```
+
+```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
+sudo apt install meson libjson-glib-dev gobject-introspection
+```
+
+:::
+
+2. clone repo
+
+```sh
+git clone https://github.com/aylur/astal.git
+cd astal/lib/river
+```
+
+3. install
+
+```sh
+meson setup --prefix /usr build
+meson install -C build
+```
diff --git a/docs/guide/libraries/tray.md b/docs/guide/libraries/tray.md
index b5cccc7..39dffc1 100644
--- a/docs/guide/libraries/tray.md
+++ b/docs/guide/libraries/tray.md
@@ -2,40 +2,6 @@
Library for managing the systemtray by implementing the [StatusNotifierItem](https://www.freedesktop.org/wiki/Specifications/StatusNotifierItem/) protocol.
-## Installation
-
-1. install dependencies
-
-:::code-group
-
-```sh [<i class="devicon-archlinux-plain"></i> Arch]
-sudo pacman -Syu meson gtk3 gobject-introspection libdbusmenu-gtk3
-```
-
-```sh [<i class="devicon-fedora-plain"></i> Fedora]
-sudo dnf install meson gcc gtk3-devel libdbusmenu-gtk3 gobject-introspection-devel
-```
-
-```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
-sudo apt install meson libgtk-3-dev libdbusmenu-gtk3-dev gobject-introspection
-```
-
-:::
-
-2. clone repo
-
-```sh
-git clone https://github.com/aylur/astal.git
-cd astal/lib/tray
-```
-
-3. install
-
-```sh
-meson setup --prefix /usr build
-meson install -C build
-```
-
## Usage
You can browse the [Tray reference](https://aylur.github.io/libastal/tray).
@@ -84,3 +50,37 @@ end
```
:::
+
+## Installation
+
+1. install dependencies
+
+:::code-group
+
+```sh [<i class="devicon-archlinux-plain"></i> Arch]
+sudo pacman -Syu meson gtk3 gobject-introspection libdbusmenu-gtk3
+```
+
+```sh [<i class="devicon-fedora-plain"></i> Fedora]
+sudo dnf install meson gcc gtk3-devel libdbusmenu-gtk3 gobject-introspection-devel
+```
+
+```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
+sudo apt install meson libgtk-3-dev libdbusmenu-gtk3-dev gobject-introspection
+```
+
+:::
+
+2. clone repo
+
+```sh
+git clone https://github.com/aylur/astal.git
+cd astal/lib/tray
+```
+
+3. install
+
+```sh
+meson setup --prefix /usr build
+meson install -C build
+```
diff --git a/docs/guide/libraries/wireplumber.md b/docs/guide/libraries/wireplumber.md
index c06161e..d6faea1 100644
--- a/docs/guide/libraries/wireplumber.md
+++ b/docs/guide/libraries/wireplumber.md
@@ -2,40 +2,6 @@
Wrapper library over [wireplumber](https://pipewire.pages.freedesktop.org/wireplumber/) to better integrate with Astal.
-## Installation
-
-1. install dependencies
-
-:::code-group
-
-```sh [<i class="devicon-archlinux-plain"></i> Arch]
-sudo pacman -Syu meson vala wireplumber gobject-introspection
-```
-
-```sh [<i class="devicon-fedora-plain"></i> Fedora]
-sudo dnf install meson vala valadoc wireplumber-devel gobject-introspection-devel
-```
-
-```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
-# Not yet documented
-```
-
-:::
-
-2. clone repo
-
-```sh
-git clone https://github.com/aylur/astal.git
-cd astal/lib/wireplumber
-```
-
-3. install
-
-```sh
-meson setup --prefix /usr build
-meson install -C build
-```
-
## Usage
You can browse the [Wireplumber reference](https://aylur.github.io/libastal/wireplumber).
@@ -81,3 +47,37 @@ print(audio.default_speaker.volume)
```
:::
+
+## Installation
+
+1. install dependencies
+
+:::code-group
+
+```sh [<i class="devicon-archlinux-plain"></i> Arch]
+sudo pacman -Syu meson vala wireplumber gobject-introspection
+```
+
+```sh [<i class="devicon-fedora-plain"></i> Fedora]
+sudo dnf install meson vala valadoc wireplumber-devel gobject-introspection-devel
+```
+
+```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
+# Not yet documented
+```
+
+:::
+
+2. clone repo
+
+```sh
+git clone https://github.com/aylur/astal.git
+cd astal/lib/wireplumber
+```
+
+3. install
+
+```sh
+meson setup --prefix /usr build
+meson install -C build
+```
diff --git a/examples/js/.gitignore b/examples/js/.gitignore
index 261d669..d53b85b 100644
--- a/examples/js/.gitignore
+++ b/examples/js/.gitignore
@@ -2,5 +2,6 @@
tsconfig.json
env.d.ts
dist/
+node_modules/
package.json
package-lock.json
diff --git a/examples/js/applauncher/README.md b/examples/js/applauncher/README.md
new file mode 100644
index 0000000..682adf1
--- /dev/null
+++ b/examples/js/applauncher/README.md
@@ -0,0 +1,5 @@
+# Applauncher
+
+![launcher](https://github.com/user-attachments/assets/2695e3bb-dff4-478a-b392-279fe638bfd3)
+
+Using [Apps](https://aylur.github.io/astal/guide/libraries/apps).
diff --git a/examples/js/applauncher/app.ts b/examples/js/applauncher/app.ts
new file mode 100644
index 0000000..d6c9e1c
--- /dev/null
+++ b/examples/js/applauncher/app.ts
@@ -0,0 +1,9 @@
+import { App } from "astal/gtk3"
+import style from "./style.scss"
+import Applauncher from "./widget/Applauncher"
+
+App.start({
+ instanceName: "launcher",
+ css: style,
+ main: Applauncher,
+})
diff --git a/examples/js/applauncher/style.scss b/examples/js/applauncher/style.scss
new file mode 100644
index 0000000..ba13eed
--- /dev/null
+++ b/examples/js/applauncher/style.scss
@@ -0,0 +1 @@
+@use "./widget/Applauncher.scss"
diff --git a/examples/js/applauncher/widget/Applauncher.scss b/examples/js/applauncher/widget/Applauncher.scss
new file mode 100644
index 0000000..ae2453d
--- /dev/null
+++ b/examples/js/applauncher/widget/Applauncher.scss
@@ -0,0 +1,59 @@
+@use "sass:string";
+
+@function gtkalpha($c, $a) {
+ @return string.unquote("alpha(#{$c},#{$a})");
+}
+
+// https://gitlab.gnome.org/GNOME/gtk/-/blob/gtk-3-24/gtk/theme/Adwaita/_colors-public.scss
+$fg-color: #{"@theme_fg_color"};
+$bg-color: #{"@theme_bg_color"};
+
+window#launcher {
+ all: unset;
+
+ box.Applauncher {
+ background-color: $bg-color;
+ border-radius: 11px;
+ margin: 1rem;
+ padding: .8rem;
+ box-shadow: 2px 3px 8px 0 gtkalpha(black, .4);
+
+ entry {
+ margin-bottom: .8rem;
+ }
+
+ button {
+ min-width: 0;
+ min-height: 0;
+ padding: .5rem;
+
+ icon {
+ font-size: 3em;
+ margin-right: .3rem;
+ }
+
+ label.name {
+ font-weight: bold;
+ font-size: 1.1em
+ }
+
+ label.description {
+ color: gtkalpha($fg-color, .8);
+ }
+ }
+
+ box.not-found {
+ padding: 1rem;
+
+ icon {
+ font-size: 6em;
+ color: gtkalpha($fg-color, .7);
+ }
+
+ label {
+ color: gtkalpha($fg-color, .9);
+ font-size: 1.2em;
+ }
+ }
+ }
+}
diff --git a/examples/js/applauncher/widget/Applauncher.tsx b/examples/js/applauncher/widget/Applauncher.tsx
new file mode 100644
index 0000000..c7bac68
--- /dev/null
+++ b/examples/js/applauncher/widget/Applauncher.tsx
@@ -0,0 +1,87 @@
+import Apps from "gi://AstalApps"
+import { App, Astal, Gdk, Gtk } from "astal/gtk3"
+import { Variable } from "astal"
+
+const MAX_ITEMS = 8
+
+function hide() {
+ App.get_window("launcher")!.hide()
+}
+
+function AppButton({ app }: { app: Apps.Application }) {
+ return <button
+ className="AppButton"
+ onClicked={() => { hide(); app.launch() }}>
+ <box>
+ <icon icon={app.iconName} />
+ <box valign={Gtk.Align.CENTER} vertical>
+ <label
+ className="name"
+ truncate
+ xalign={0}
+ label={app.name}
+ />
+ {app.description && <label
+ className="description"
+ wrap
+ xalign={0}
+ label={app.description}
+ />}
+ </box>
+ </box>
+ </button>
+}
+
+export default function Applauncher() {
+ const { CENTER } = Gtk.Align
+ const apps = new Apps.Apps()
+
+ const text = Variable("")
+ const list = text(text => apps.fuzzy_query(text).slice(0, MAX_ITEMS))
+ const onEnter = () => {
+ apps.fuzzy_query(text.get())?.[0].launch()
+ hide()
+ }
+
+ return <window
+ name="launcher"
+ anchor={Astal.WindowAnchor.TOP | Astal.WindowAnchor.BOTTOM}
+ exclusivity={Astal.Exclusivity.IGNORE}
+ keymode={Astal.Keymode.ON_DEMAND}
+ application={App}
+ onShow={() => text.set("")}
+ onKeyPressEvent={function (self, event: Gdk.Event) {
+ if (event.get_keyval()[1] === Gdk.KEY_Escape)
+ self.hide()
+ }}>
+ <box>
+ <eventbox widthRequest={4000} expand onClick={hide} />
+ <box hexpand={false} vertical>
+ <eventbox heightRequest={100} onClick={hide} />
+ <box widthRequest={500} className="Applauncher" vertical>
+ <entry
+ placeholderText="Search"
+ text={text()}
+ onChanged={self => text.set(self.text)}
+ onActivate={onEnter}
+ />
+ <box spacing={6} vertical>
+ {list.as(list => list.map(app => (
+ <AppButton app={app} />
+ )))}
+ </box>
+ <box
+ halign={CENTER}
+ className="not-found"
+ vertical
+ visible={list.as(l => l.length === 0)}>
+ <icon icon="system-search-symbolic" />
+ <label label="No match found" />
+ </box>
+ </box>
+ <eventbox expand onClick={hide} />
+ </box>
+ <eventbox widthRequest={4000} expand onClick={hide} />
+ </box>
+ </window>
+}
diff --git a/examples/js/media-player/README.md b/examples/js/media-player/README.md
new file mode 100644
index 0000000..4e3d237
--- /dev/null
+++ b/examples/js/media-player/README.md
@@ -0,0 +1,5 @@
+# Media Player
+
+![mpris](https://github.com/user-attachments/assets/891e9706-74db-4505-bd83-c3628d7b4fd0)
+
+Using [Mpris](https://aylur.github.io/astal/guide/libraries/mpris).
diff --git a/examples/js/media-player/app.ts b/examples/js/media-player/app.ts
new file mode 100644
index 0000000..5b7558a
--- /dev/null
+++ b/examples/js/media-player/app.ts
@@ -0,0 +1,11 @@
+import { App, Widget } from "astal/gtk3"
+import style from "./style.scss"
+import MprisPlayers from "./widget/MediaPlayer"
+
+App.start({
+ instanceName: "players",
+ css: style,
+ main: () => {
+ new Widget.Window({}, MprisPlayers())
+ }
+})
diff --git a/examples/js/media-player/style.scss b/examples/js/media-player/style.scss
new file mode 100644
index 0000000..2e2f625
--- /dev/null
+++ b/examples/js/media-player/style.scss
@@ -0,0 +1 @@
+@use "./widget/MediaPlayer.scss";
diff --git a/examples/js/media-player/widget/MediaPlayer.scss b/examples/js/media-player/widget/MediaPlayer.scss
new file mode 100644
index 0000000..e1597c2
--- /dev/null
+++ b/examples/js/media-player/widget/MediaPlayer.scss
@@ -0,0 +1,56 @@
+// https://gitlab.gnome.org/GNOME/gtk/-/blob/gtk-3-24/gtk/theme/Adwaita/_colors-public.scss
+$fg-color: #{"@theme_fg_color"};
+$bg-color: #{"@theme_bg_color"};
+
+window {
+ all: unset;
+}
+
+box.MediaPlayer {
+ padding: .6rem;
+ background-color: $bg-color;
+
+ box.cover-art {
+ min-width: 120px;
+ min-height: 120px;
+ border-radius: 9px;
+ margin-right: .6rem;
+ background-size: contain;
+ background-position: center;
+ }
+
+ box.title {
+ label {
+ font-weight: bold;
+ font-size: 1.1em;
+ }
+ }
+
+ scale {
+ padding: 0;
+ margin: .4rem 0;
+
+ trough {
+ min-height: 8px;
+ }
+
+ highlight {
+ background-color: $fg-color;
+ }
+
+ slider {
+ all: unset;
+ }
+ }
+
+ centerbox.actions {
+ min-width: 220px;
+
+ button {
+ min-width: 0;
+ min-height: 0;
+ padding: .4rem;
+ margin: 0 .2rem;
+ }
+ }
+}
diff --git a/examples/js/media-player/widget/MediaPlayer.tsx b/examples/js/media-player/widget/MediaPlayer.tsx
new file mode 100644
index 0000000..06c7e77
--- /dev/null
+++ b/examples/js/media-player/widget/MediaPlayer.tsx
@@ -0,0 +1,94 @@
+import { Astal, Gtk } from "astal/gtk3"
+import Mpris from "gi://AstalMpris"
+import { bind } from "astal"
+
+function lengthStr(length: number) {
+ const min = Math.floor(length / 60)
+ const sec = Math.floor(length % 60)
+ const sec0 = sec < 10 ? "0" : ""
+ return `${min}:${sec0}${sec}`
+}
+
+
+function MediaPlayer({ player }: { player: Mpris.Player }) {
+ const { START, END } = Gtk.Align
+
+ const title = bind(player, "title").as(t =>
+ t || "Unknown Track")
+
+ const artist = bind(player, "artist").as(a =>
+ a || "Unknown Artist")
+
+ const coverArt = bind(player, "coverArt").as(c =>
+ `background-image: url('${c}')`)
+
+ const playerIcon = bind(player, "entry").as(e =>
+ Astal.Icon.lookup_icon(e) ? e : "audio-x-generic-symbolic")
+
+ const position = bind(player, "position").as(p => player.length > 0
+ ? p / player.length : 0)
+
+ const playIcon = bind(player, "playbackStatus").as(s =>
+ s === Mpris.PlaybackStatus.PLAYING
+ ? "media-playback-pause-symbolic"
+ : "media-playback-start-symbolic"
+ )
+
+ return <box className="MediaPlayer">
+ <box className="cover-art" css={coverArt} />
+ <box vertical>
+ <box className="title">
+ <label truncate hexpand halign={START} label={title} />
+ <icon icon={playerIcon} />
+ </box>
+ <label halign={START} valign={START} vexpand wrap label={artist} />
+ <slider
+ visible={bind(player, "length").as(l => l > 0)}
+ onDragged={({ value }) => player.position = value * player.length}
+ value={position}
+ />
+ <centerbox className="actions">
+ <label
+ hexpand
+ className="position"
+ halign={START}
+ visible={bind(player, "length").as(l => l > 0)}
+ label={bind(player, "position").as(lengthStr)}
+ />
+ <box>
+ <button
+ onClicked={() => player.previous()}
+ visible={bind(player, "canGoPrevious")}>
+ <icon icon="media-skip-backward-symbolic" />
+ </button>
+ <button
+ onClicked={() => player.play_pause()}
+ visible={bind(player, "canControl")}>
+ <icon icon={playIcon} />
+ </button>
+ <button
+ onClicked={() => player.next()}
+ visible={bind(player, "canGoNext")}>
+ <icon icon="media-skip-forward-symbolic" />
+ </button>
+ </box>
+ <label
+ className="length"
+ hexpand
+ halign={END}
+ visible={bind(player, "length").as(l => l > 0)}
+ label={bind(player, "length").as(l => l > 0 ? lengthStr(l) : "0:00")}
+ />
+ </centerbox>
+ </box>
+ </box>
+}
+
+export default function MprisPlayers() {
+ const mpris = Mpris.get_default()
+ return <box vertical>
+ {bind(mpris, "players").as(arr => arr.map(player => (
+ <MediaPlayer player={player} />
+ )))}
+ </box>
+}
diff --git a/examples/js/notifications/README.md b/examples/js/notifications/README.md
new file mode 100644
index 0000000..60dad60
--- /dev/null
+++ b/examples/js/notifications/README.md
@@ -0,0 +1,5 @@
+# Notifications Popups
+
+![notifs](https://github.com/user-attachments/assets/0df0eddc-5c74-4af0-a694-48dc8ec6bb44)
+
+A replacement for dunst and other daemons using [Notifd](https://aylur.github.io/astal/guide/libraries/notifd).
diff --git a/examples/js/notifications/app.ts b/examples/js/notifications/app.ts
new file mode 100644
index 0000000..ed53292
--- /dev/null
+++ b/examples/js/notifications/app.ts
@@ -0,0 +1,9 @@
+import { App } from "astal/gtk3"
+import style from "./style.scss"
+import NotificationPopups from "./notifications/NotificationPopups"
+
+App.start({
+ instanceName: "notifications",
+ css: style,
+ main: () => App.get_monitors().map(NotificationPopups),
+})
diff --git a/examples/js/notifications/notifications/Notification.scss b/examples/js/notifications/notifications/Notification.scss
new file mode 100644
index 0000000..a32f08b
--- /dev/null
+++ b/examples/js/notifications/notifications/Notification.scss
@@ -0,0 +1,125 @@
+@use "sass:string";
+
+@function gtkalpha($c, $a) {
+ @return string.unquote("alpha(#{$c},#{$a})");
+}
+
+// https://gitlab.gnome.org/GNOME/gtk/-/blob/gtk-3-24/gtk/theme/Adwaita/_colors-public.scss
+$fg-color: #{"@theme_fg_color"};
+$bg-color: #{"@theme_bg_color"};
+$error: red;
+
+window.NotificationPopups {
+ all: unset;
+}
+
+eventbox.Notification {
+
+ &:first-child>box {
+ margin-top: 1rem;
+ }
+
+ &:last-child>box {
+ margin-bottom: 1rem;
+ }
+
+ // eventboxes can not take margins so we style its inner box instead
+ >box {
+ min-width: 400px;
+ border-radius: 13px;
+ background-color: $bg-color;
+ margin: .5rem 1rem .5rem 1rem;
+ box-shadow: 2px 3px 8px 0 gtkalpha(black, .4);
+ border: 1pt solid gtkalpha($fg-color, .03);
+ }
+
+ &.critical>box {
+ border: 1pt solid gtkalpha($error, .4);
+
+ .header {
+
+ .app-name {
+ color: gtkalpha($error, .8);
+
+ }
+
+ .app-icon {
+ color: gtkalpha($error, .6);
+ }
+ }
+ }
+
+ .header {
+ padding: .5rem;
+ color: gtkalpha($fg-color, 0.5);
+
+ .app-icon {
+ margin: 0 .4rem;
+ }
+
+ .app-name {
+ margin-right: .3rem;
+ font-weight: bold;
+
+ &:first-child {
+ margin-left: .4rem;
+ }
+ }
+
+ .time {
+ margin: 0 .4rem;
+ }
+
+ button {
+ padding: .2rem;
+ min-width: 0;
+ min-height: 0;
+ }
+ }
+
+ separator {
+ margin: 0 .4rem;
+ background-color: gtkalpha($fg-color, .1);
+ }
+
+ .content {
+ margin: 1rem;
+ margin-top: .5rem;
+
+ .summary {
+ font-size: 1.2em;
+ color: $fg-color;
+ }
+
+ .body {
+ color: gtkalpha($fg-color, 0.8);
+ }
+
+ .image {
+ border: 1px solid gtkalpha($fg-color, .02);
+ margin-right: .5rem;
+ border-radius: 9px;
+ min-width: 100px;
+ min-height: 100px;
+ background-size: cover;
+ background-position: center;
+ }
+ }
+
+ .actions {
+ margin: 1rem;
+ margin-top: 0;
+
+ button {
+ margin: 0 .3rem;
+
+ &:first-child {
+ margin-left: 0;
+ }
+
+ &:last-child {
+ margin-right: 0;
+ }
+ }
+ }
+}
diff --git a/examples/js/notifications/notifications/Notification.tsx b/examples/js/notifications/notifications/Notification.tsx
new file mode 100644
index 0000000..5149d5b
--- /dev/null
+++ b/examples/js/notifications/notifications/Notification.tsx
@@ -0,0 +1,107 @@
+import { GLib } from "astal"
+import { Gtk, Astal } from "astal/gtk3"
+import { type EventBox } from "astal/gtk3/widget"
+import Notifd from "gi://AstalNotifd"
+
+const isIcon = (icon: string) =>
+ !!Astal.Icon.lookup_icon(icon)
+
+const fileExists = (path: string) =>
+ GLib.file_test(path, GLib.FileTest.EXISTS)
+
+const time = (time: number, format = "%H:%M") => GLib.DateTime
+ .new_from_unix_local(time)
+ .format(format)!
+
+const urgency = (n: Notifd.Notification) => {
+ const { LOW, NORMAL, CRITICAL } = Notifd.Urgency
+ // match operator when?
+ switch (n.urgency) {
+ case LOW: return "low"
+ case CRITICAL: return "critical"
+ case NORMAL:
+ default: return "normal"
+ }
+}
+
+type Props = {
+ setup(self: EventBox): void
+ onHoverLost(self: EventBox): void
+ notification: Notifd.Notification
+}
+
+export default function Notification(props: Props) {
+ const { notification: n, onHoverLost, setup } = props
+ const { START, CENTER, END } = Gtk.Align
+
+ return <eventbox
+ className={`Notification ${urgency(n)}`}
+ setup={setup}
+ onHoverLost={onHoverLost}>
+ <box vertical>
+ <box className="header">
+ {(n.appIcon || n.desktopEntry) && <icon
+ className="app-icon"
+ visible={Boolean(n.appIcon || n.desktopEntry)}
+ icon={n.appIcon || n.desktopEntry}
+ />}
+ <label
+ className="app-name"
+ halign={START}
+ truncate
+ label={n.appName || "Unknown"}
+ />
+ <label
+ className="time"
+ hexpand
+ halign={END}
+ label={time(n.time)}
+ />
+ <button onClicked={() => n.dismiss()}>
+ <icon icon="window-close-symbolic" />
+ </button>
+ </box>
+ <Gtk.Separator visible />
+ <box className="content">
+ {n.image && fileExists(n.image) && <box
+ valign={START}
+ className="image"
+ css={`background-image: url('${n.image}')`}
+ />}
+ {n.image && isIcon(n.image) && <box
+ expand={false}
+ valign={START}
+ className="icon-image">
+ <icon icon={n.image} expand halign={CENTER} valign={CENTER} />
+ </box>}
+ <box vertical>
+ <label
+ className="summary"
+ halign={START}
+ xalign={0}
+ label={n.summary}
+ truncate
+ />
+ {n.body && <label
+ className="body"
+ wrap
+ useMarkup
+ halign={START}
+ xalign={0}
+ justifyFill
+ label={n.body}
+ />}
+ </box>
+ </box>
+ {n.get_actions().length > 0 && <box className="actions">
+ {n.get_actions().map(({ label, id }) => (
+ <button
+ hexpand
+ onClicked={() => n.invoke(id)}>
+ <label label={label} halign={CENTER} hexpand />
+ </button>
+ ))}
+ </box>}
+ </box>
+ </eventbox>
+}
diff --git a/examples/js/notifications/notifications/NotificationPopups.tsx b/examples/js/notifications/notifications/NotificationPopups.tsx
new file mode 100644
index 0000000..a8088c9
--- /dev/null
+++ b/examples/js/notifications/notifications/NotificationPopups.tsx
@@ -0,0 +1,105 @@
+import { Astal, Gtk, Gdk } from "astal/gtk3"
+import Notifd from "gi://AstalNotifd"
+import Notification from "./Notification"
+import { type Subscribable } from "astal/binding"
+import { GLib, Variable, bind, timeout } from "astal"
+
+// see comment below in constructor
+const TIMEOUT_DELAY = 5000
+
+// The purpose if this class is to replace Variable<Array<Widget>>
+// with a Map<number, Widget> type in order to track notification widgets
+// by their id, while making it conviniently bindable as an array
+class NotifiationMap implements Subscribable {
+ // the underlying map to keep track of id widget pairs
+ private map: Map<number, Gtk.Widget> = new Map()
+
+ // it makes sense to use a Variable under the hood and use its
+ // reactivity implementation instead of keeping track of subscribers ourselves
+ private var: Variable<Array<Gtk.Widget>> = Variable([])
+
+ // notify subscribers to rerender when state changes
+ private notifiy() {
+ this.var.set([...this.map.values()].reverse())
+ }
+
+ private constructor() {
+ const notifd = Notifd.get_default()
+
+ /**
+ * uncomment this if you want to
+ * ignore timeout by senders and enforce our own timeout
+ * note that if the notification has any actions
+ * they might not work, since the sender already treats them as resolved
+ */
+ // notifd.ignoreTimeout = true
+
+ notifd.connect("notified", (_, id) => {
+ this.set(id, Notification({
+ notification: notifd.get_notification(id)!,
+
+ // once hovering over the notification is done
+ // destroy the widget without calling notification.dismiss()
+ // so that it acts as a "popup" and we can still display it
+ // in a notification center like widget
+ // but clicking on the close button will close it
+ onHoverLost: () => this.delete(id),
+
+ // notifd by default does not close notifications
+ // until user input or the timeout specified by sender
+ // which we set to ignore above
+ setup: () => timeout(TIMEOUT_DELAY, () => {
+ /**
+ * uncomment this if you want to "hide" the notifications
+ * after TIMEOUT_DELAY
+ */
+ // this.delete(id)
+ })
+ }))
+ })
+
+ // notifications can be closed by the outside before
+ // any user input, which have to be handled too
+ notifd.connect("resolved", (_, id) => {
+ this.delete(id)
+ })
+ }
+
+ private set(key: number, value: Gtk.Widget) {
+ // in case of replacecment destroy previous widget
+ this.map.get(key)?.destroy()
+ this.map.set(key, value)
+ this.notifiy()
+ }
+
+ private delete(key: number) {
+ this.map.get(key)?.destroy()
+ this.map.delete(key)
+ this.notifiy()
+ }
+
+ // needed by the Subscribable interface
+ get() {
+ return this.var.get()
+ }
+
+ // needed by the Subscribable interface
+ subscribe(callback: (list: Array<Gtk.Widget>) => void) {
+ return this.var.subscribe(callback)
+ }
+}
+
+export default function NotificationPopups(gdkmonitor: Gdk.Monitor) {
+ const { TOP, RIGHT } = Astal.WindowAnchor
+ const notifs = new NotifiationMap()
+
+ return <window
+ className="NotificationPopups"
+ gdkmonitor={gdkmonitor}
+ exclusivity={Astal.Exclusivity.EXCLUSIVE}
+ anchor={TOP | RIGHT}>
+ <box vertical>
+ {bind(notifs)}
+ </box>
+ </window>
+}
diff --git a/examples/js/notifications/style.scss b/examples/js/notifications/style.scss
new file mode 100644
index 0000000..7ef0168
--- /dev/null
+++ b/examples/js/notifications/style.scss
@@ -0,0 +1 @@
+@use "./notifications/Notification.scss";
diff --git a/examples/js/simple-bar/.gitignore b/examples/js/simple-bar/.gitignore
deleted file mode 100644
index 6850183..0000000
--- a/examples/js/simple-bar/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-@girs/
-node_modules/ \ No newline at end of file
diff --git a/lang/gjs/src/gtk3/astalify.ts b/lang/gjs/src/gtk3/astalify.ts
index 736ab17..b9621be 100644
--- a/lang/gjs/src/gtk3/astalify.ts
+++ b/lang/gjs/src/gtk3/astalify.ts
@@ -65,7 +65,7 @@ export default function astalify<
get_click_through(): boolean { return this.clickThrough }
set_click_through(clickThrough: boolean) { this.clickThrough = clickThrough }
- declare __no_implicit_destroy: boolean
+ declare private __no_implicit_destroy: boolean
get noImplicitDestroy(): boolean { return this.__no_implicit_destroy }
set noImplicitDestroy(value: boolean) { this.__no_implicit_destroy = value }
diff --git a/lib/network/network.vala b/lib/network/network.vala
index fb7efa0..96e19c8 100644
--- a/lib/network/network.vala
+++ b/lib/network/network.vala
@@ -149,19 +149,19 @@ public enum AstalNetwork.Connectivity {
// alias for NM.DeviceState
public enum AstalNetwork.DeviceState {
- UNKNOWN,
- UNMANAGED,
- UNAVAILABLE,
- DISCONNECTED,
- PREPARE,
- CONFIG,
- NEED_AUTH,
- IP_CONFIG,
- IP_CHECK,
- SECONDARIES,
- ACTIVATED,
- DEACTIVATING,
- FAILED;
+ UNKNOWN = 0,
+ UNMANAGED = 10,
+ UNAVAILABLE = 20,
+ DISCONNECTED = 30,
+ PREPARE = 40,
+ CONFIG = 50,
+ NEED_AUTH = 60,
+ IP_CONFIG = 70,
+ IP_CHECK = 80,
+ SECONDARIES = 90,
+ ACTIVATED = 100,
+ DEACTIVATING = 110,
+ FAILED = 120;
public string to_string() {
switch (this) {