summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/question.md2
-rw-r--r--CHANGELOG.md5
-rw-r--r--README.md5
-rw-r--r--docs/guide/lua/examples.md4
-rw-r--r--docs/guide/lua/installation.md2
-rw-r--r--docs/guide/lua/widget.md8
-rw-r--r--docs/guide/typescript/examples.md14
-rw-r--r--docs/guide/typescript/faq.md19
-rw-r--r--docs/guide/typescript/first-widgets.md85
-rw-r--r--docs/guide/typescript/gobject.md2
-rw-r--r--docs/vitepress.config.ts2
-rw-r--r--examples/js/notifications/notifications/NotificationPopups.tsx4
-rw-r--r--examples/js/simple-bar/style.scss14
-rw-r--r--examples/js/simple-bar/widget/Bar.tsx6
-rw-r--r--examples/lua/simple-bar/style.scss14
-rw-r--r--examples/py/simple-bar/style.scss14
-rw-r--r--examples/vala/simple-bar/style.scss14
-rw-r--r--lang/gjs/meson.build1
-rw-r--r--lang/gjs/src/_app.ts1
-rw-r--r--lang/gjs/src/gobject.ts2
-rw-r--r--lang/gjs/src/gtk3/jsx-runtime.ts3
-rw-r--r--lang/gjs/src/index.ts1
-rw-r--r--lang/gjs/src/overrides.ts84
-rw-r--r--lang/gjs/tsconfig.json1
-rw-r--r--lib/astal/gtk3/src/widget/circularprogress.vala63
-rw-r--r--lib/astal/io/process.vala13
-rw-r--r--lib/astal/io/variable.vala2
-rw-r--r--lib/hyprland/hyprland.vala24
-rw-r--r--lib/mpris/cli.vala4
-rw-r--r--lib/mpris/ifaces.vala2
-rw-r--r--lib/mpris/player.vala16
-rw-r--r--lib/network/network.vala16
-rw-r--r--lib/notifd/notification.vala4
-rw-r--r--lib/powerprofiles/cli.vala2
-rw-r--r--lib/powerprofiles/power-profiles.vala13
35 files changed, 343 insertions, 123 deletions
diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md
index 936a648..990ede7 100644
--- a/.github/ISSUE_TEMPLATE/question.md
+++ b/.github/ISSUE_TEMPLATE/question.md
@@ -10,7 +10,7 @@ assignees: ''
**Have you read through the documentation?**
- [ ] [Astal docs](https://aylur.github.io/astal/)
- [ ] [Library references](https://aylur.github.io/astal/guide/libraries/references)
-- [ ] [FAQ](https://aylur.github.io/astal/guide/ags/faq)
+- [ ] [FAQ](https://aylur.github.io/astal/guide/typescript/faq)
**Describe what have you tried so far**
A description or example code of what you have got so far.
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..df8746e
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,5 @@
+# Changelog
+
+## 0.1.0
+
+WIP
diff --git a/README.md b/README.md
index d8f4971..248d666 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,3 @@
# Astal
-> [!WARNING]
-> WIP: nothing is stable yet, every library is subject to change
-
-## Getting Started
-
To get started read the [wiki](https://aylur.github.io/astal/)
diff --git a/docs/guide/lua/examples.md b/docs/guide/lua/examples.md
new file mode 100644
index 0000000..be46b6e
--- /dev/null
+++ b/docs/guide/lua/examples.md
@@ -0,0 +1,4 @@
+# Lua examples
+
+## [Simple Bar](https://github.com/Aylur/astal/tree/main/examples/lua/simple-bar)
+![simple-bar](https://github.com/user-attachments/assets/a306c864-56b7-44c4-8820-81f424f32b9b)
diff --git a/docs/guide/lua/installation.md b/docs/guide/lua/installation.md
index b99d8df..f647ed7 100644
--- a/docs/guide/lua/installation.md
+++ b/docs/guide/lua/installation.md
@@ -9,7 +9,7 @@ Read more about it on the [nix page](../getting-started/nix)
## Arch
```sh
-yay -S lua-libastal-git
+yay -S libastal-lua-git
```
## From Source
diff --git a/docs/guide/lua/widget.md b/docs/guide/lua/widget.md
index d9f99fa..593628e 100644
--- a/docs/guide/lua/widget.md
+++ b/docs/guide/lua/widget.md
@@ -139,18 +139,18 @@ These widgets are available by default in Lua.
- Button: [Astal.Button](https://aylur.github.io/libastal/astal3/class.Button.html)
- CenterBox: [Astal.CenterBox](https://aylur.github.io/libastal/astal3/class.CenterBox.html)
- CircularProgress: [Astal.CircularProgress](https://aylur.github.io/libastal/astal3/class.CircularProgress.html)
-- DrawingArea: [Gtk.DrawingArea](https://docs.gtk.org/gtk3/astal3/class.DrawingArea.html)
-- Entry: [Gtk.Entry](https://docs.gtk.org/gtk3/astal3/class.Entry.html)
+- DrawingArea: [Gtk.DrawingArea](https://docs.gtk.org/gtk3/class.DrawingArea.html)
+- Entry: [Gtk.Entry](https://docs.gtk.org/gtk3/class.Entry.html)
- Eventbox: [Astal.EventBox](https://aylur.github.io/libastal/astal3/class.EventBox.html)
- Icon: [Astal.Icon](https://aylur.github.io/libastal/astal3/class.Icon.html)
- Label: [Astal.Label](https://aylur.github.io/libastal/astal3/class.Label.html)
- Levelbar: [Astal.LevelBar](https://aylur.github.io/libastal/astal3/class.LevelBar.html)
- Overlay: [Astal.Overlay](https://aylur.github.io/libastal/astal3/class.Overlay.html)
-- Revealer: [Gtk.Revealer](https://docs.gtk.org/gtk3/astal3/class.Revealer.html)
+- Revealer: [Gtk.Revealer](https://docs.gtk.org/gtk3/class.Revealer.html)
- Scrollable: [Astal.Scrollable](https://aylur.github.io/libastal/astal3/class.Scrollable.html)
- Slider: [Astal.Slider](https://aylur.github.io/libastal/astal3/class.Slider.html)
- Stack: [Astal.Stack](https://aylur.github.io/libastal/astal3/class.Stack.html)
-- Switch: [Gtk.Switch](https://docs.gtk.org/gtk3/astal3/class.Switch.html)
+- Switch: [Gtk.Switch](https://docs.gtk.org/gtk3/class.Switch.html)
- Window: [Astal.Window](https://aylur.github.io/libastal/astal3/class.Window.html)
## Gtk4
diff --git a/docs/guide/typescript/examples.md b/docs/guide/typescript/examples.md
new file mode 100644
index 0000000..ec51e89
--- /dev/null
+++ b/docs/guide/typescript/examples.md
@@ -0,0 +1,14 @@
+# TypeScript Examples
+
+## Gtk3
+
+### [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)
diff --git a/docs/guide/typescript/faq.md b/docs/guide/typescript/faq.md
index a151099..4ee616b 100644
--- a/docs/guide/typescript/faq.md
+++ b/docs/guide/typescript/faq.md
@@ -92,7 +92,7 @@ printerr("print this line to stderr")
## Populate the global scope with frequently accessed variables
-It might be annoying to always import Gtk only for `Gtk.Align` enums.
+It might be annoying to always import Gtk only for the `Gtk.Align` enum.
:::code-group
@@ -118,7 +118,7 @@ Object.assign(globalThis, {
:::code-group
-```tsx [Bar.tsx]
+```tsx [Bar.tsx] {3}
export default function Bar() {
return <window>
<box halign={START} />
@@ -131,11 +131,13 @@ export default function Bar() {
:::code-group
```ts [app.ts]
-import "./globals"
+import "./globals" // don't forget to import it first // [!code ++]
import Bar from "./Bar"
App.start({
- main: Bar
+ main() {
+ Bar()
+ }
})
```
@@ -197,11 +199,14 @@ These happen when accessing list type properties. Gjs fails to correctly bind
import Notifd from "gi://AstalNotifd"
const notifd = Notifd.get_default()
-notifd.notifications // ❌ // [!code error]
-
-notifd.get_notifications() // ✅
+notifd.notifications // [!code --]
+notifd.get_notifications() // [!code ++]
```
+:::tip
+Open up an issue/PR to add a [workaround](https://github.com/Aylur/astal/blob/main/lang/gjs/src/overrides.ts).
+:::
+
## How to create regular floating windows
Use `Gtk.Window` with [Widget.astalify](/guide/typescript/widget#how-to-use-non-builtin-gtk-widgets).
diff --git a/docs/guide/typescript/first-widgets.md b/docs/guide/typescript/first-widgets.md
index a467382..77b2f61 100644
--- a/docs/guide/typescript/first-widgets.md
+++ b/docs/guide/typescript/first-widgets.md
@@ -275,7 +275,7 @@ function Counter() {
<label label={bind(count).as(num => num.toString())} />
<button onClicked={increment}>
Click to increment
- <button>
+ </button>
</box>
}
```
@@ -354,42 +354,75 @@ inner state of widgets that does not need to be recreated. In this case
you can create a [custom reactive structure](./binding#example-custom-subscribable)
:::
-When there is at least one `Binding` passed as a child, the `children`
-parameter will always be a flattened `Binding<Array<JSX.Element>>`.
-When there is a single `Binding` passed as a child, the `child` parameter will
-be a `Binding<JSX.Element>` or a flattened `Binding<Array<JSX.Element>>`.
+# How children are passed
+
+Here is full list of how children and bound children can be passed to custom widgets.
```tsx
-import { type Binding } from "astal"
+import Binding from "astal/binding"
-function MyContainer({ children }: {
- children?: Binding<Array<JSX.Element>>
-}) {
- // children is a Binding over an Array of widgets
-}
+function Parent(props: {
+ child?: JSX.Element | Binding<JSX.Element> | Binding<Array<JSX.Element>>
+ children?: Array<JSX.Element> | Binding<Array<JSX.Element>>
+})
-return <MyContainer>
- <box />
- {num(n => range(n).map(i => (
- <button>
- {i.toString()}
- <button/>
- )))}
- [
- [
- <button />
- ]
- <button />
- ]
-</MyContainer>
+// { child: JSX.Element }
+<Parent>
+ <child />
+</Parent>
+
+// { children: Array<JSX.Element> }
+<Parent>
+ <child />
+ <child />
+</Parent>
+
+// { child: Binding<JSX.Element> }
+<Parent>
+ {variable(c => (
+ <child />
+ ))}
+</Parent>
+
+// { child: Binding<Array<JSX.Element>> }
+<Parent>
+ {variable(c => (
+ <child />
+ <child />
+ ))}
+</Parent>
+
+// { children: Binding<Array<JSX.Element>> }
+<Parent>
+ <child />
+ {variable(c => (
+ <child />
+ ))}
+</Parent>
+
+
+// { children: Binding<Array<JSX.Element>> }
+<Parent>
+ <child />
+ {variable(c => (
+ <child />
+ <child />
+ ))}
+</Parent>
```
+:::tip
+If you have a widget where you pass widgets in various ways, you can
+wrap `child` in `children` in a [`Subscribable`](./faq#custom-widgets-with-bindable-properties) and handle all cases
+as if they were bindings.
+:::
+
:::info
You can pass the followings as children:
- widgets
- deeply nested arrays of widgets
-- bindings of widgets,
+- bindings of widgets
- bindings of deeply nested arrays of widgets
[falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy) values are not rendered and anything not from this list
diff --git a/docs/guide/typescript/gobject.md b/docs/guide/typescript/gobject.md
index f7f001d..4e40845 100644
--- a/docs/guide/typescript/gobject.md
+++ b/docs/guide/typescript/gobject.md
@@ -74,7 +74,7 @@ class MyObj extends GObject.Object {
declare myProp: string
constructor() {
- super({ myProp: "default-value" })
+ super({ myProp: "default-value" } as any)
}
}
```
diff --git a/docs/vitepress.config.ts b/docs/vitepress.config.ts
index 7e16eb7..3593b40 100644
--- a/docs/vitepress.config.ts
+++ b/docs/vitepress.config.ts
@@ -73,6 +73,7 @@ export default defineConfig({
{ text: "GObject", link: "/gobject" },
{ text: "Utilities", link: "/utilities" },
{ text: "FAQ", link: "/faq" },
+ { text: "Examples", link: "/examples" },
],
},
{
@@ -90,6 +91,7 @@ export default defineConfig({
// { text: "GObject", link: "/gobject" },
{ text: "Utilities", link: "/utilities" },
// { text: "FAQ", link: "/faq" },
+ { text: "Examples", link: "/examples" },
],
},
{
diff --git a/examples/js/notifications/notifications/NotificationPopups.tsx b/examples/js/notifications/notifications/NotificationPopups.tsx
index a8088c9..9b84d84 100644
--- a/examples/js/notifications/notifications/NotificationPopups.tsx
+++ b/examples/js/notifications/notifications/NotificationPopups.tsx
@@ -2,7 +2,7 @@ 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"
+import { Variable, bind, timeout } from "astal"
// see comment below in constructor
const TIMEOUT_DELAY = 5000
@@ -23,7 +23,7 @@ class NotifiationMap implements Subscribable {
this.var.set([...this.map.values()].reverse())
}
- private constructor() {
+ constructor() {
const notifd = Notifd.get_default()
/**
diff --git a/examples/js/simple-bar/style.scss b/examples/js/simple-bar/style.scss
index f98286e..1dcf729 100644
--- a/examples/js/simple-bar/style.scss
+++ b/examples/js/simple-bar/style.scss
@@ -1,3 +1,5 @@
+@use "sass:color";
+
$bg: #212223;
$fg: #f1f1f1;
$accent: #378DF7;
@@ -16,12 +18,12 @@ window.Bar {
background-color: transparent;
&:hover label {
- background-color: transparentize($fg, 0.84);
- border-color: transparentize($accent, 0.8);
+ background-color: color.adjust($fg, $alpha: -0.84);
+ border-color: color.adjust($accent, $alpha: -0.8);
}
&:active label {
- background-color: transparentize($fg, 0.8)
+ background-color: color.adjust($fg, $alpha: -0.8)
}
}
@@ -64,10 +66,12 @@ window.Bar {
margin-right: .6em;
}
- margin: 0 1em;
+ & {
+ margin: 0 1em;
+ }
trough {
- background-color: transparentize($fg, 0.8);
+ background-color: color.adjust($fg, $alpha: -0.8);
border-radius: $radius;
}
diff --git a/examples/js/simple-bar/widget/Bar.tsx b/examples/js/simple-bar/widget/Bar.tsx
index 029aca1..f5e96cb 100644
--- a/examples/js/simple-bar/widget/Bar.tsx
+++ b/examples/js/simple-bar/widget/Bar.tsx
@@ -128,15 +128,13 @@ function Time({ format = "%H:%M - %A %e." }) {
}
export default function Bar(monitor: Gdk.Monitor) {
- const anchor = Astal.WindowAnchor.TOP
- | Astal.WindowAnchor.LEFT
- | Astal.WindowAnchor.RIGHT
+ const { TOP, LEFT, RIGHT } = Astal.WindowAnchor
return <window
className="Bar"
gdkmonitor={monitor}
exclusivity={Astal.Exclusivity.EXCLUSIVE}
- anchor={anchor}>
+ anchor={TOP | LEFT | RIGHT}>
<centerbox>
<box hexpand halign={Gtk.Align.START}>
<Workspaces />
diff --git a/examples/lua/simple-bar/style.scss b/examples/lua/simple-bar/style.scss
index f98286e..1dcf729 100644
--- a/examples/lua/simple-bar/style.scss
+++ b/examples/lua/simple-bar/style.scss
@@ -1,3 +1,5 @@
+@use "sass:color";
+
$bg: #212223;
$fg: #f1f1f1;
$accent: #378DF7;
@@ -16,12 +18,12 @@ window.Bar {
background-color: transparent;
&:hover label {
- background-color: transparentize($fg, 0.84);
- border-color: transparentize($accent, 0.8);
+ background-color: color.adjust($fg, $alpha: -0.84);
+ border-color: color.adjust($accent, $alpha: -0.8);
}
&:active label {
- background-color: transparentize($fg, 0.8)
+ background-color: color.adjust($fg, $alpha: -0.8)
}
}
@@ -64,10 +66,12 @@ window.Bar {
margin-right: .6em;
}
- margin: 0 1em;
+ & {
+ margin: 0 1em;
+ }
trough {
- background-color: transparentize($fg, 0.8);
+ background-color: color.adjust($fg, $alpha: -0.8);
border-radius: $radius;
}
diff --git a/examples/py/simple-bar/style.scss b/examples/py/simple-bar/style.scss
index f98286e..1dcf729 100644
--- a/examples/py/simple-bar/style.scss
+++ b/examples/py/simple-bar/style.scss
@@ -1,3 +1,5 @@
+@use "sass:color";
+
$bg: #212223;
$fg: #f1f1f1;
$accent: #378DF7;
@@ -16,12 +18,12 @@ window.Bar {
background-color: transparent;
&:hover label {
- background-color: transparentize($fg, 0.84);
- border-color: transparentize($accent, 0.8);
+ background-color: color.adjust($fg, $alpha: -0.84);
+ border-color: color.adjust($accent, $alpha: -0.8);
}
&:active label {
- background-color: transparentize($fg, 0.8)
+ background-color: color.adjust($fg, $alpha: -0.8)
}
}
@@ -64,10 +66,12 @@ window.Bar {
margin-right: .6em;
}
- margin: 0 1em;
+ & {
+ margin: 0 1em;
+ }
trough {
- background-color: transparentize($fg, 0.8);
+ background-color: color.adjust($fg, $alpha: -0.8);
border-radius: $radius;
}
diff --git a/examples/vala/simple-bar/style.scss b/examples/vala/simple-bar/style.scss
index f98286e..1dcf729 100644
--- a/examples/vala/simple-bar/style.scss
+++ b/examples/vala/simple-bar/style.scss
@@ -1,3 +1,5 @@
+@use "sass:color";
+
$bg: #212223;
$fg: #f1f1f1;
$accent: #378DF7;
@@ -16,12 +18,12 @@ window.Bar {
background-color: transparent;
&:hover label {
- background-color: transparentize($fg, 0.84);
- border-color: transparentize($accent, 0.8);
+ background-color: color.adjust($fg, $alpha: -0.84);
+ border-color: color.adjust($accent, $alpha: -0.8);
}
&:active label {
- background-color: transparentize($fg, 0.8)
+ background-color: color.adjust($fg, $alpha: -0.8)
}
}
@@ -64,10 +66,12 @@ window.Bar {
margin-right: .6em;
}
- margin: 0 1em;
+ & {
+ margin: 0 1em;
+ }
trough {
- background-color: transparentize($fg, 0.8);
+ background-color: color.adjust($fg, $alpha: -0.8);
border-radius: $radius;
}
diff --git a/lang/gjs/meson.build b/lang/gjs/meson.build
index f4272ee..51496dc 100644
--- a/lang/gjs/meson.build
+++ b/lang/gjs/meson.build
@@ -14,6 +14,7 @@ install_data(
'src/process.ts',
'src/time.ts',
'src/variable.ts',
+ 'src/overrides.ts',
'src/_app.ts',
],
install_dir: dest,
diff --git a/lang/gjs/src/_app.ts b/lang/gjs/src/_app.ts
index 82e8bb5..3dadd04 100644
--- a/lang/gjs/src/_app.ts
+++ b/lang/gjs/src/_app.ts
@@ -1,3 +1,4 @@
+import "./overrides.js"
import { setConsoleLogDomain } from "console"
import { exit, programArgs } from "system"
import IO from "gi://AstalIO"
diff --git a/lang/gjs/src/gobject.ts b/lang/gjs/src/gobject.ts
index b744cfb..6bd9969 100644
--- a/lang/gjs/src/gobject.ts
+++ b/lang/gjs/src/gobject.ts
@@ -178,7 +178,7 @@ function defaultValue(declaration: PropertyDeclaration) {
switch (declaration) {
case String:
- return "default-string"
+ return ""
case Number:
return 0
case Boolean:
diff --git a/lang/gjs/src/gtk3/jsx-runtime.ts b/lang/gjs/src/gtk3/jsx-runtime.ts
index 10b3bcf..19a3b7d 100644
--- a/lang/gjs/src/gtk3/jsx-runtime.ts
+++ b/lang/gjs/src/gtk3/jsx-runtime.ts
@@ -10,7 +10,8 @@ export function Fragment({ children = [], child }: {
child?: BindableChild
children?: Array<BindableChild>
}) {
- return mergeBindings([...children, child])
+ if (child) children.push(child)
+ return mergeBindings(children)
}
export function jsx(
diff --git a/lang/gjs/src/index.ts b/lang/gjs/src/index.ts
index cabc961..8fe8d01 100644
--- a/lang/gjs/src/index.ts
+++ b/lang/gjs/src/index.ts
@@ -1,3 +1,4 @@
+import "./overrides.js"
export { default as AstalIO } from "gi://AstalIO?version=0.1"
export * from "./process.js"
export * from "./time.js"
diff --git a/lang/gjs/src/overrides.ts b/lang/gjs/src/overrides.ts
new file mode 100644
index 0000000..0d09e7b
--- /dev/null
+++ b/lang/gjs/src/overrides.ts
@@ -0,0 +1,84 @@
+/**
+ * Workaround for "Can't convert non-null pointer to JS value "
+ */
+
+export { }
+
+const snakeify = (str: string) => str
+ .replace(/([a-z])([A-Z])/g, "$1_$2")
+ .replaceAll("-", "_")
+ .toLowerCase()
+
+async function suppress<T>(mod: Promise<{ default: T }>, patch: (m: T) => void) {
+ return mod.then(m => patch(m.default)).catch(() => void 0)
+}
+
+function patch<P extends object>(proto: P, prop: Extract<keyof P, string>) {
+ Object.defineProperty(proto, prop, {
+ get() { return this[`get_${snakeify(prop)}`]() },
+ })
+}
+
+await suppress(import("gi://AstalApps"), ({ Apps, Application }) => {
+ patch(Apps.prototype, "list")
+ patch(Application.prototype, "keywords")
+ patch(Application.prototype, "categories")
+})
+
+await suppress(import("gi://AstalBattery"), ({ UPower }) => {
+ patch(UPower.prototype, "devices")
+})
+
+await suppress(import("gi://AstalBluetooth"), ({ Adapter, Bluetooth, Device }) => {
+ patch(Adapter.prototype, "uuids")
+ patch(Bluetooth.prototype, "adapters")
+ patch(Bluetooth.prototype, "devices")
+ patch(Device.prototype, "uuids")
+})
+
+await suppress(import("gi://AstalHyprland"), ({ Hyprland, Monitor, Workspace }) => {
+ patch(Hyprland.prototype, "monitors")
+ patch(Hyprland.prototype, "workspaces")
+ patch(Hyprland.prototype, "clients")
+ patch(Monitor.prototype, "availableModes")
+ patch(Monitor.prototype, "available_modes")
+ patch(Workspace.prototype, "clients")
+})
+
+await suppress(import("gi://AstalMpris"), ({ Mpris, Player }) => {
+ patch(Mpris.prototype, "players")
+ patch(Player.prototype, "supported_uri_schemes")
+ patch(Player.prototype, "supportedUriSchemes")
+ patch(Player.prototype, "supported_mime_types")
+ patch(Player.prototype, "supportedMimeTypes")
+ patch(Player.prototype, "comments")
+})
+
+await suppress(import("gi://AstalNetwork"), ({ Wifi }) => {
+ patch(Wifi.prototype, "access_points")
+ patch(Wifi.prototype, "accessPoints")
+})
+
+await suppress(import("gi://AstalNotifd"), ({ Notifd, Notification }) => {
+ patch(Notifd.prototype, "notifications")
+ patch(Notification.prototype, "actions")
+})
+
+await suppress(import("gi://AstalPowerProfiles"), ({ PowerProfiles }) => {
+ patch(PowerProfiles.prototype, "actions")
+})
+
+await suppress(import("gi://AstalWp"), ({ Wp, Audio, Video }) => {
+ patch(Wp.prototype, "endpoints")
+ patch(Wp.prototype, "devices")
+ patch(Audio.prototype, "streams")
+ patch(Audio.prototype, "recorders")
+ patch(Audio.prototype, "microphones")
+ patch(Audio.prototype, "speakers")
+ patch(Audio.prototype, "devices")
+ patch(Video.prototype, "streams")
+ patch(Video.prototype, "recorders")
+ patch(Video.prototype, "sinks")
+ patch(Video.prototype, "sources")
+ patch(Video.prototype, "devices")
+})
diff --git a/lang/gjs/tsconfig.json b/lang/gjs/tsconfig.json
index 4e57e37..7a3a8c8 100644
--- a/lang/gjs/tsconfig.json
+++ b/lang/gjs/tsconfig.json
@@ -1,6 +1,7 @@
{
"compilerOptions": {
"experimentalDecorators": true,
+ "module": "ES2022",
"target": "ES2023",
"outDir": "dist",
"strict": true,
diff --git a/lib/astal/gtk3/src/widget/circularprogress.vala b/lib/astal/gtk3/src/widget/circularprogress.vala
index a3ecdf1..df1635d 100644
--- a/lib/astal/gtk3/src/widget/circularprogress.vala
+++ b/lib/astal/gtk3/src/widget/circularprogress.vala
@@ -44,26 +44,53 @@ public class Astal.CircularProgress : Gtk.Bin {
set_css_name("circular-progress");
}
+ public override Gtk.SizeRequestMode get_request_mode() {
+ if(get_child() != null) return get_child().get_request_mode();
+ return Gtk.SizeRequestMode.HEIGHT_FOR_WIDTH;
+ }
+
public override void get_preferred_height(out int minh, out int nath) {
- var val = get_style_context().get_property("min-height", Gtk.StateFlags.NORMAL);
- if (val.get_int() <= 0) {
- minh = 40;
- nath = 40;
+ if(get_child() != null) {
+ int minw, natw;
+ get_child().get_preferred_height(out minh, out nath);
+ get_child().get_preferred_width(out minw, out natw);
+
+ minh = int.max(minw, minh);
+ nath = int.max(natw, nath);
}
+ var w_val = get_style_context().get_property("min-width", Gtk.StateFlags.NORMAL);
+ var h_val = get_style_context().get_property("min-height", Gtk.StateFlags.NORMAL);
+ minh = int.max(w_val.get_int(), minh);
+ nath = int.max(w_val.get_int(), nath);
+ minh = int.max(h_val.get_int(), minh);
+ nath = int.max(h_val.get_int(), nath);
+ }
- minh = val.get_int();
- nath = val.get_int();
+ public override void get_preferred_height_for_width(int width, out int minh, out int nath) {
+ minh = width;
+ nath = width;
}
public override void get_preferred_width(out int minw, out int natw) {
- var val = get_style_context().get_property("min-width", Gtk.StateFlags.NORMAL);
- if (val.get_int() <= 0) {
- minw = 40;
- natw = 40;
+ if(get_child() != null) {
+ int minh, nath;
+ get_child().get_preferred_height(out minh, out nath);
+ get_child().get_preferred_width(out minw, out natw);
+
+ minw = int.max(minw, minh);
+ natw = int.max(natw, nath);
}
+ var w_val = get_style_context().get_property("min-width", Gtk.StateFlags.NORMAL);
+ var h_val = get_style_context().get_property("min-height", Gtk.StateFlags.NORMAL);
+ minw = int.max(w_val.get_int(), minw);
+ natw = int.max(w_val.get_int(), natw);
+ minw = int.max(h_val.get_int(), minw);
+ natw = int.max(h_val.get_int(), natw);
+ }
- minw = val.get_int();
- natw = val.get_int();
+ public override void get_preferred_width_for_height(int height, out int minw, out int natw) {
+ minw = height;
+ natw = height;
}
private double to_radian(double percentage) {
@@ -115,6 +142,12 @@ public class Astal.CircularProgress : Gtk.Bin {
Gtk.Allocation allocation;
get_allocation(out allocation);
+ if (get_child() != null) {
+ get_child().size_allocate(allocation);
+ propagate_draw(get_child(), cr);
+ }
+
+
var styles = get_style_context();
var width = allocation.width;
var height = allocation.height;
@@ -195,12 +228,6 @@ public class Astal.CircularProgress : Gtk.Bin {
cr.arc(end_x, end_y, fg_stroke / 2, 0, 0 - 0.01);
cr.fill();
}
-
- if (get_child() != null) {
- get_child().size_allocate(allocation);
- propagate_draw(get_child(), cr);
- }
-
return true;
}
}
diff --git a/lib/astal/io/process.vala b/lib/astal/io/process.vala
index cfd05b9..4b77aee 100644
--- a/lib/astal/io/process.vala
+++ b/lib/astal/io/process.vala
@@ -76,7 +76,7 @@ public class AstalIO.Process : Object {
*
* The first element of the vector is executed with the remaining elements as the argument list.
*/
- public Process.subprocessv(string[] cmd) throws Error {
+ public Process(string[] cmd) throws Error {
Object(argv: cmd);
process = new Subprocess.newv(cmd,
SubprocessFlags.STDIN_PIPE |
@@ -91,13 +91,22 @@ public class AstalIO.Process : Object {
}
/**
+ * Start a new subprocess with the given command.
+ *
+ * The first element of the vector is executed with the remaining elements as the argument list.
+ */
+ public static Process subprocessv(string[] cmd) throws Error {
+ return new Process(cmd);
+ }
+
+ /**
* Start a new subprocess with the given command
* which is parsed using [[email protected]_parse_argv].
*/
public static Process subprocess(string cmd) throws Error {
string[] argv;
Shell.parse_argv(cmd, out argv);
- return new Process.subprocessv(argv);
+ return Process.subprocessv(argv);
}
/**
diff --git a/lib/astal/io/variable.vala b/lib/astal/io/variable.vala
index 312a27a..e4105f8 100644
--- a/lib/astal/io/variable.vala
+++ b/lib/astal/io/variable.vala
@@ -172,7 +172,7 @@ public class AstalIO.Variable : VariableBase {
return_if_fail(watch_proc == null);
return_if_fail(watch_exec != null);
- watch_proc = new Process.subprocessv(watch_exec);
+ watch_proc = Process.subprocessv(watch_exec);
watch_proc.stdout.connect((str) => set_closure(str, watch_transform));
watch_proc.stderr.connect((str) => this.error(str));
}
diff --git a/lib/hyprland/hyprland.vala b/lib/hyprland/hyprland.vala
index ea95cab..5bdff81 100644
--- a/lib/hyprland/hyprland.vala
+++ b/lib/hyprland/hyprland.vala
@@ -309,17 +309,30 @@ public class Hyprland : Object {
switch (args[0]) {
case "workspacev2":
yield sync_workspaces();
+ yield sync_monitors();
focused_workspace = get_workspace(int.parse(args[1]));
break;
case "focusedmon":
var argv = args[1].split(",", 2);
+ yield sync_monitors();
focused_monitor = get_monitor_by_name(argv[0]);
focused_workspace = get_workspace_by_name(argv[1]);
break;
+ // first event that signals a new client
case "activewindowv2":
- focused_client = get_client(args[1]);
+ if (args[1] != "" && get_client(args[1]) == null) {
+ var client = new Client();
+ _clients.insert(args[1], client);
+ yield sync_clients();
+ yield sync_workspaces();
+ client_added(client);
+ notify_property("clients");
+ focused_client = client;
+ } else {
+ focused_client = get_client(args[1]);
+ }
break;
// TODO: nag vaxry for fullscreenv2 that passes address
@@ -381,20 +394,15 @@ public class Hyprland : Object {
break;
case "openwindow":
- var addr = args[1].split(",")[0];
- var client = new Client();
- _clients.insert(addr, client);
yield sync_clients();
yield sync_workspaces();
- client_added(client);
- notify_property("clients");
break;
case "closewindow":
_clients.get(args[1]).removed();
_clients.remove(args[1]);
- client_removed(args[1]);
yield sync_workspaces();
+ client_removed(args[1]);
notify_property("clients");
break;
@@ -426,7 +434,7 @@ public class Hyprland : Object {
minimize(get_client(argv[0]), argv[1] == "0");
break;
- case "windowtitle":
+ case "windowtitlev2":
yield sync_clients();
break;
diff --git a/lib/mpris/cli.vala b/lib/mpris/cli.vala
index b71def9..7e15c6e 100644
--- a/lib/mpris/cli.vala
+++ b/lib/mpris/cli.vala
@@ -179,7 +179,7 @@ int main(string[] argv) {
Json.Node to_json(Player p) {
var uris = new Json.Builder().begin_array();
- foreach (var uri in p.supported_uri_schemas)
+ foreach (var uri in p.supported_uri_schemes)
uris.add_string_value(uri);
uris.end_array();
@@ -189,7 +189,7 @@ Json.Node to_json(Player p) {
.set_member_name("available").add_boolean_value(p.available)
.set_member_name("identity").add_string_value(p.identity)
.set_member_name("entry").add_string_value(p.entry)
- .set_member_name("supported_uri_schemas").add_value(uris.get_root())
+ .set_member_name("supported_uri_schemes").add_value(uris.get_root())
.set_member_name("loop_status").add_string_value(p.loop_status.to_string())
.set_member_name("shuffle_status").add_string_value(p.shuffle_status.to_string())
.set_member_name("rate").add_double_value(p.rate)
diff --git a/lib/mpris/ifaces.vala b/lib/mpris/ifaces.vala
index 298a288..8755723 100644
--- a/lib/mpris/ifaces.vala
+++ b/lib/mpris/ifaces.vala
@@ -21,7 +21,7 @@ private interface AstalMpris.IMpris : PropsIface {
public abstract bool has_track_list { get; }
public abstract string identity { owned get; }
public abstract string desktop_entry { owned get; }
- public abstract string[] supported_uri_schemas { owned get; }
+ public abstract string[] supported_uri_schemes { owned get; }
public abstract string[] supported_mime_types { owned get; }
}
diff --git a/lib/mpris/player.vala b/lib/mpris/player.vala
index 2050f61..e6d84bf 100644
--- a/lib/mpris/player.vala
+++ b/lib/mpris/player.vala
@@ -87,7 +87,7 @@ public class AstalMpris.Player : Object {
* Almost every media player will include support for the "file" scheme.
* Other common schemes are "http" and "rtsp".
*/
- public string[] supported_uri_schemas { owned get; private set; }
+ public string[] supported_uri_schemes { owned get; private set; }
/**
* The mime-types supported by the player.
@@ -160,7 +160,7 @@ public class AstalMpris.Player : Object {
}
/**
- * uri scheme should be an element of [[email protected]:supported_uri_schemas]
+ * uri scheme should be an element of [[email protected]:supported_uri_schemes]
* and the mime-type should match one of the elements of [[email protected]:supported_mime_types].
*
* @param uri Uri of the track to load.
@@ -425,7 +425,7 @@ public class AstalMpris.Player : Object {
// has_track_list = proxy.has_track_list;
identity = proxy.identity;
entry = proxy.desktop_entry;
- supported_uri_schemas = proxy.supported_uri_schemas;
+ supported_uri_schemes = proxy.supported_uri_schemes;
supported_mime_types = proxy.supported_mime_types;
if (position >= 0)
@@ -440,6 +440,9 @@ public class AstalMpris.Player : Object {
_loop_status = Loop.from_string(proxy.loop_status);
notify_property("loop-status");
}
+ } else {
+ _loop_status = Loop.UNSUPPORTED;
+ notify_property("loop-status");
}
if (rate != proxy.rate) {
@@ -452,6 +455,9 @@ public class AstalMpris.Player : Object {
_shuffle_status = Shuffle.from_bool(proxy.shuffle);
notify_property("shuffle-status");
}
+ } else {
+ _shuffle_status = Shuffle.UNSUPPORTED;
+ notify_property("shuffle-status");
}
if (volume != proxy.volume) {
@@ -498,8 +504,10 @@ public class AstalMpris.Player : Object {
}
private async void cache_cover() {
- if (art_url == null || art_url == "")
+ if (art_url == null || art_url == "") {
+ cover_art = null;
return;
+ }
var file = File.new_for_uri(art_url);
if (file.get_path() != null) {
diff --git a/lib/network/network.vala b/lib/network/network.vala
index 96e19c8..b5a6c61 100644
--- a/lib/network/network.vala
+++ b/lib/network/network.vala
@@ -104,14 +104,14 @@ public enum AstalNetwork.Primary {
// alias for NM.State
public enum AstalNetwork.State {
- UNKNOWN,
- ASLEEP,
- DISCONNECTED,
- DISCONNECTING,
- CONNECTING,
- CONNECTED_LOCAL,
- CONNECTED_SITE,
- CONNECTED_GLOBAL;
+ UNKNOWN = 0,
+ ASLEEP = 10,
+ DISCONNECTED = 20,
+ DISCONNECTING = 30,
+ CONNECTING = 40,
+ CONNECTED_LOCAL = 50,
+ CONNECTED_SITE = 60,
+ CONNECTED_GLOBAL = 70;
public string to_string() {
switch (this) {
diff --git a/lib/notifd/notification.vala b/lib/notifd/notification.vala
index 29c6c56..c28138f 100644
--- a/lib/notifd/notification.vala
+++ b/lib/notifd/notification.vala
@@ -142,9 +142,11 @@ public class AstalNotifd.Notification : Object {
return 0;
var v = hints.get(hint);
- if (v.get_type_string() == "b")
+ // daemon uses byte as per spec
+ if (v.get_type_string() == "y")
return v.get_byte();
+ // proxy uses int64 from json
if (v.get_type_string() == "x")
return (uint8)v.get_int64();
diff --git a/lib/powerprofiles/cli.vala b/lib/powerprofiles/cli.vala
index 1e5cc70..87ffe82 100644
--- a/lib/powerprofiles/cli.vala
+++ b/lib/powerprofiles/cli.vala
@@ -100,7 +100,7 @@ string to_json_string(AstalPowerProfiles.PowerProfiles profiles) {
foreach (var prof in profiles.profiles) {
profs.add_value(new Json.Builder()
.begin_object()
- .set_member_name("profie").add_string_value(prof.profile)
+ .set_member_name("profile").add_string_value(prof.profile)
.set_member_name("driver").add_string_value(prof.driver)
.set_member_name("cpu_driver").add_string_value(prof.cpu_driver)
.set_member_name("platform_driver").add_string_value(prof.platform_driver)
diff --git a/lib/powerprofiles/power-profiles.vala b/lib/powerprofiles/power-profiles.vala
index a104d2e..931fc04 100644
--- a/lib/powerprofiles/power-profiles.vala
+++ b/lib/powerprofiles/power-profiles.vala
@@ -113,6 +113,11 @@ public class PowerProfiles : Object {
owned get { return proxy.performance_degraded; }
}
+ private string? get_hashtable_string(HashTable<string, Variant> table, string key) {
+ var v = table.get(key);
+ return v == null ? null : v.get_string();
+ }
+
/**
* List of each profile.
*/
@@ -122,10 +127,10 @@ public class PowerProfiles : Object {
for (var i = 0; i < proxy.profiles.length; ++i) {
var prof = proxy.profiles[i];
profs[i] = Profile() {
- profile = prof.get("Profile").get_string(),
- cpu_driver = prof.get("CpuDriver").get_string(),
- platform_driver = prof.get("PlatformDriver").get_string(),
- driver = prof.get("Driver").get_string()
+ profile = get_hashtable_string(prof, "Profile"),
+ cpu_driver = get_hashtable_string(prof, "CpuDriver"),
+ platform_driver = get_hashtable_string(prof, "PlatformDriver"),
+ driver = get_hashtable_string(prof, "Driver"),
};
}
return profs;