summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/question.md2
-rw-r--r--README.md5
-rw-r--r--docs/guide/getting-started/installation.md14
-rw-r--r--docs/guide/getting-started/nix.md208
-rw-r--r--docs/guide/libraries/tray.md2
-rw-r--r--docs/guide/lua/examples.md4
-rw-r--r--docs/guide/lua/first-widgets.md5
-rw-r--r--docs/guide/lua/installation.md2
-rw-r--r--docs/guide/lua/theming.md2
-rw-r--r--docs/guide/lua/widget.md8
-rw-r--r--docs/guide/typescript/cli-app.md31
-rw-r--r--docs/guide/typescript/examples.md14
-rw-r--r--docs/guide/typescript/faq.md23
-rw-r--r--docs/guide/typescript/first-widgets.md126
-rw-r--r--docs/guide/typescript/gobject.md2
-rw-r--r--docs/guide/typescript/installation.md80
-rw-r--r--docs/guide/typescript/theming.md77
-rw-r--r--docs/package.json2
-rw-r--r--docs/vitepress.config.ts2
-rw-r--r--examples/js/simple-bar/README.md1
-rw-r--r--examples/lua/simple-bar/README.md1
-rw-r--r--examples/py/simple-bar/README.md1
-rw-r--r--examples/vala/simple-bar/README.md1
-rw-r--r--examples/vala/simple-bar/widget/Bar.vala7
-rw-r--r--lang/gjs/meson.build1
-rw-r--r--lang/gjs/package.json2
-rw-r--r--lang/gjs/src/_app.ts1
-rw-r--r--lang/gjs/src/gobject.ts6
-rw-r--r--lang/gjs/src/gtk3/astalify.ts6
-rw-r--r--lang/gjs/src/gtk3/index.ts4
-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.ts69
-rw-r--r--lang/gjs/tsconfig.json1
-rw-r--r--lang/lua/astal-dev-1.rockspec2
-rw-r--r--lang/lua/astal/binding.lua26
-rw-r--r--lang/lua/astal/gtk3/app.lua47
-rw-r--r--lang/lua/astal/gtk3/astalify.lua4
-rw-r--r--lang/lua/astal/gtk3/widget.lua1
-rw-r--r--lang/lua/astal/init.lua1
-rw-r--r--lang/lua/astal/variable.lua25
-rw-r--r--lib/astal/gtk3/src/widget/circularprogress.vala63
l---------[-rw-r--r--]lib/astal/gtk4/gir.py59
l---------[-rw-r--r--]lib/astal/io/gir.py59
-rw-r--r--lib/gir.py3
-rw-r--r--lib/hyprland/hyprland.vala18
-rw-r--r--lib/hyprland/monitor.vala24
-rw-r--r--lib/mpris/cli.vala4
-rw-r--r--lib/mpris/ifaces.vala2
-rw-r--r--lib/mpris/player.vala6
-rw-r--r--lib/notifd/notification.vala4
-rw-r--r--lib/powerprofiles/cli.vala49
l---------lib/powerprofiles/gir.py1
-rw-r--r--lib/powerprofiles/meson.build44
-rw-r--r--lib/powerprofiles/power-profiles.vala109
-rw-r--r--lib/tray/meson.build2
56 files changed, 609 insertions, 658 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/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/getting-started/installation.md b/docs/guide/getting-started/installation.md
index fa7863e..e32b6a9 100644
--- a/docs/guide/getting-started/installation.md
+++ b/docs/guide/getting-started/installation.md
@@ -1,11 +1,5 @@
# Installation
-## Nix
-
-maintainer: [@Aylur](https://github.com/Aylur)
-
-Read more about it on the [nix page](./nix#astal)
-
## Arch
maintainer: [@kotontrion](https://github.com/kotontrion)
@@ -22,7 +16,13 @@ yay -S libastal-meta
:::
-## Bulding libastal from source
+## Nix
+
+maintainer: [@Aylur](https://github.com/Aylur)
+
+Read more about it on the [nix page](./nix#astal)
+
+## Bulding From Source
1. Install the following dependencies
diff --git a/docs/guide/getting-started/nix.md b/docs/guide/getting-started/nix.md
index 1e0572e..6bc5d9b 100644
--- a/docs/guide/getting-started/nix.md
+++ b/docs/guide/getting-started/nix.md
@@ -5,13 +5,15 @@ next:
---
# Nix
-## Astal
-
Using Astal on Nix will require you to package your project.
+## TypeScript
+
+Using [AGS](https://aylur.github.io/ags/) as the bundler.
+
:::code-group
-```nix [<i class="devicon-lua-plain"></i> Lua]
+```nix [<i class="devicon-nixos-plain"></i> flake.nix]
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
@@ -19,80 +21,49 @@ Using Astal on Nix will require you to package your project.
url = "github:aylur/astal";
inputs.nixpkgs.follows = "nixpkgs";
};
+ ags = {
+ url = "github:aylur/ags";
+ inputs.nixpkgs.follows = "nixpkgs";
+ };
};
- outputs = { self, nixpkgs, astal }: let
+ outputs = { self, nixpkgs, astal, ags }: let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
in {
- packages.${system}.default = astal.lib.mkLuaPackage {
- inherit pkgs;
- src = ./path/to/project; # should contain init.lua
-
- # add extra glib packages or binaries
- extraPackages = [
- astal.packages.${system}.battery
- pkgs.dart-sass
+ packages.${system}. default = pkgs.stdenvNoCC.mkDerivation rec {
+ name = "my-shell";
+ src = ./.;
+
+ nativeBuildInputs = [
+ ags.packages.${system}.default
+ pkgs.wrapGAppsHook
+ pkgs.gobject-introspection
];
- };
- };
-}
-```
-```nix [<i class="devicon-python-plain"></i> Python]
-# Not documented yet
-```
-
-```nix [<i class="devicon-vala-plain"></i> Vala]
-# keep in mind that this is just the nix derivation
-# and you still have to use some build tool like meson
-{
- inputs = {
- nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
- astal.url = "github:aylur/astal";
- };
-
- outputs = { self, nixpkgs, astal }: let
- system = "x86_64-linux";
- pkgs = nixpkgs.legacyPackages.${system};
- in {
- packages.${system} = {
- default = pkgs.stdenv.mkDerivation {
- name = "my-shell";
- src = ./.;
-
- nativeBuildInputs = with pkgs; [
- meson
- ninja
- pkg-config
- vala
- gobject-introspection
- ];
+ buildInputs = with astal.packages.${system}; [
+ astal3
+ io
+ # any other package
+ ];
- # add extra packages
- buildInputs = [
- astal.packages.${system}.astal
- ];
- };
+ installPhase = ''
+ mkdir -p $out/bin
+ ags bundle app.ts $out/bin/${name}
+ '';
};
};
}
```
-```nix [<i class="devicon-typescript-plain"></i> TypeScript]
-# The usage of AGS (read below) is recommended
-# Usage without AGS is not yet documented
-```
-
:::
-## AGS
-
-The recommended way to use [AGS](../typescript/first-widgets#first-widgets) on NixOS is through the home-manager module.
-
-Example content of a `flake.nix` file that contains your `homeConfigurations`.
+:::tip
+You can use any other bundler too like `esbuild`
+which is what `ags` uses under the hood.
+:::
-<!--TODO: remove v2 after merge-->
+## Lua
:::code-group
@@ -100,28 +71,26 @@ Example content of a `flake.nix` file that contains your `homeConfigurations`.
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
- home-manager = {
- url = "github:nix-community/home-manager";
+ astal = {
+ url = "github:aylur/astal";
inputs.nixpkgs.follows = "nixpkgs";
};
-
- # add ags https://github.com/Aylur/ags/pull/504
- ags.url = "github:aylur/ags/v2";
};
- outputs = { home-manager, nixpkgs, ... }@inputs:
- let
+ outputs = { self, nixpkgs, astal }: let
system = "x86_64-linux";
- in
- {
- homeConfigurations."${username}" = home-manager.lib.homeManagerConfiguration {
- pkgs = import nixpkgs { inherit system; };
-
- # pass inputs as specialArgs
- extraSpecialArgs = { inherit inputs; };
+ pkgs = nixpkgs.legacyPackages.${system};
+ in {
+ packages.${system}.default = astal.lib.mkLuaPackage {
+ inherit pkgs;
+ name = "my-shell"; # how to name the executable
+ src = ./path/to/project; # should contain init.lua
- # import your home.nix
- modules = [ ./home-manager/home.nix ];
+ # add extra glib packages or binaries
+ extraPackages = [
+ astal.packages.${system}.battery
+ pkgs.dart-sass
+ ];
};
};
}
@@ -129,65 +98,58 @@ Example content of a `flake.nix` file that contains your `homeConfigurations`.
:::
-Example content of `home.nix` file
+## Python
:::code-group
-```nix [<i class="devicon-nixos-plain"></i> home.nix]
-{ inputs, pkgs, ... }:
-{
- # add the home manager module
- imports = [ inputs.ags.homeManagerModules.default ];
-
- programs.ags = {
- enable = true;
- configDir = ../ags;
-
- # additional packages to add to gjs's runtime
- extraPackages = with pkgs; [
- inputs.ags.packages.${pkgs.system}.battery
- fzf
- ];
- };
-}
+```nix [<i class="devicon-nixos-plain"></i> flake.nix]
+# Not documented yet
```
:::
-AGS by default only includes the core `astal3/astal4` and `astal-io` libraries.
-If you want to include any other [library](../libraries/references) you have to add them to `extraPackages`.
-You can also add binaries which will be added to the gjs runtime.
-
-:::warning
-The `configDir` option symlinks the given path to `~/.config/ags`.
-If you already have your source code there leave it as `null`.
-:::
+## Vala
-The AGS flake does not expose the `astal` cli to the home environment, you have to do that yourself if you want:
+Keep in mind that this is just the nix derivation
+and you still have to use some build tool like meson.
:::code-group
-```nix [<i class="devicon-nixos-plain"></i> home.nix]
-home.packages = [ inputs.ags.packages.${pkgs.system}.io ];
-```
-
-```sh [<i class="devicon-bash-plain"></i> sh]
-astal --help
-```
-
-:::
-
-Same applies to the `extraPackages` option, it does not expose the passed packages to the home environment.
-To make astal cli tools available to home environments, you have to add them yourself:
-
-:::code-group
+```nix [<i class="devicon-nixos-plain"></i> flake.nix]
+{
+ inputs = {
+ nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
+ astal = {
+ url = "github:aylur/astal";
+ inputs.nixpkgs.follows = "nixpkgs";
+ };
+ };
-```nix [<i class="devicon-nixos-plain"></i> home.nix]
-home.packages = [ inputs.ags.packages.${pkgs.system}.notifd ];
-```
+ outputs = { self, nixpkgs, astal }: let
+ system = "x86_64-linux";
+ pkgs = nixpkgs.legacyPackages.${system};
+ in {
+ packages.${system}.default = pkgs.stdenv.mkDerivation {
+ name = "my-shell";
+ src = ./.;
+
+ nativeBuildInputs = with pkgs; [
+ meson
+ ninja
+ pkg-config
+ vala
+ gobject-introspection
+ ];
-```sh [<i class="devicon-bash-plain"></i> sh]
-astal-notifd --help
+ buildInputs = [
+ astal.packages.${system}.io
+ astal.packages.${system}.astal3
+ astal.packages.${system}.battery
+ # add extra packages
+ ];
+ };
+ };
+}
```
:::
diff --git a/docs/guide/libraries/tray.md b/docs/guide/libraries/tray.md
index 39dffc1..43b3aa6 100644
--- a/docs/guide/libraries/tray.md
+++ b/docs/guide/libraries/tray.md
@@ -62,7 +62,7 @@ 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
+sudo dnf install meson gcc gtk3-devel libdbusmenu-gtk3-devel gobject-introspection-devel
```
```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
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/first-widgets.md b/docs/guide/lua/first-widgets.md
index efc1c4f..70cfe0c 100644
--- a/docs/guide/lua/first-widgets.md
+++ b/docs/guide/lua/first-widgets.md
@@ -13,8 +13,7 @@ local App = require("astal.gtk3.app")
App:start({
main = function()
-- you will instantiate Widgets here
- -- or setup anything else if you need
- print("hi")
+ -- and setup anything else if you need
end
})
```
@@ -22,7 +21,7 @@ App:start({
:::
Then run `lua init.lua` in the terminal, and that's it!
-Now you have an instance running with Lua.
+Now you have an Astal instance running written in Lua.
## Root of every shell component: Window
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/theming.md b/docs/guide/lua/theming.md
index 502e8e9..4f556fc 100644
--- a/docs/guide/lua/theming.md
+++ b/docs/guide/lua/theming.md
@@ -39,7 +39,7 @@ App:start({
:::
:::warning
-When using relative paths, so for example `./style.css` keep in mind that they
+When using relative paths, for example `./style.css` keep in mind that they
will be relative to the current working directory.
:::
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/cli-app.md b/docs/guide/typescript/cli-app.md
index 85b117c..9b299aa 100644
--- a/docs/guide/typescript/cli-app.md
+++ b/docs/guide/typescript/cli-app.md
@@ -6,7 +6,6 @@ Depending on gtk version import paths will differ
```ts
import { App } from "astal/gtk3"
-
import { App } from "astal/gtk4"
```
@@ -53,20 +52,11 @@ App.start({
})
```
-:::code-group
-
-```sh [astal]
+```sh
astal say hi
# hi cli
```
-```sh [ags]
-ags request "say hi"
-# hi cli
-```
-
-:::
-
If you want to run arbitrary JavaScript from CLI, you can use `App.eval`
which will evaluate the passed string as the body of an `async` function.
@@ -102,7 +92,7 @@ In order for Astal to know about your windows, you have to register them.
You can do this by specifying a **unique** `name` and calling `App.add_window`
```tsx {4}
-import { App } from "astal"
+import { App } from "astal/gtk3"
function Bar() {
return <window name="Bar" setup={self => App.add_window(self)}>
@@ -114,7 +104,7 @@ function Bar() {
You can also invoke `App.add_window` by simply passing the `App` to the `application` prop.
```tsx {4}
-import { App } from "astal"
+import { App } from "astal/gtk3"
function Bar() {
return <window name="Bar" application={App}>
@@ -128,24 +118,13 @@ When assigning the `application` prop make sure `name` comes before.
Props are set sequentially and if name is applied after application it won't work.
:::
-:::code-group
-
```sh [astal]
astal -t Bar
```
-```sh [ags]
-ags toggle Bar
-```
-
-:::
-
-## Bundled scripts
-
-The produced scripts when bundling can run as the main instance
-and a "client" instance.
+## Client
-The first time you execute your bundled script the `main` function gets called.
+The first time you execute your script the `main` function gets called.
While that instance is running any subsequent execution of the script will call
the `client` function.
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 48c802c..4ee616b 100644
--- a/docs/guide/typescript/faq.md
+++ b/docs/guide/typescript/faq.md
@@ -7,7 +7,7 @@ the same as the compositor. Instead use the `gdkmonitor` property which expects
a `Gdk.Monitor` object.
```tsx
-import { App } from "astal"
+import { App } from "astal/gtk3"
function Bar(gdkmonitor) {
return <window gdkmonitor={gdkmonitor} />
@@ -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()
+ }
})
```
@@ -162,7 +164,7 @@ export default function Bar(gdkmonitor: Gdk.Monitor) {
:::code-group
```ts [app.ts]
-import { Gdk, Gtk } from "astal"
+import { Gdk, Gtk } from "astal/gtk3"
import Bar from "./Bar"
function main() {
@@ -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 96a1275..77b2f61 100644
--- a/docs/guide/typescript/first-widgets.md
+++ b/docs/guide/typescript/first-widgets.md
@@ -2,41 +2,26 @@
## Getting Started
-Start by initializing a project
+Start by importing the singleton
+[Astal.Application](https://aylur.github.io/libastal/astal3/class.Application.html) instance.
-```sh
-ags init
-```
+:::code-group
-then run `ags run` in the terminal
+```ts [app.ts]
+import { App } from "astal/gtk3"
-```sh
-ags run
+App.start({
+ main() {
+ // you will instantiate Widgets here
+ // and setup anything else if you need
+ }
+})
```
-:::details Usage without AGS
-🚧 Not yet documented. 🚧
:::
-That's it! You have now a custom written bar using Gtk.
-
-:::tip
-AGS will transpile every `.ts`, `.jsx` and `.tsx` files into regular JavaScript, then
-it will bundle everything into a single JavaScript file which then GJS can execute.
-:::
-
-The AGS init command will generate the following files
-
-```txt
-.
-├── @girs/ # generated types
-├── widget/
-│ └── Bar.tsx
-├── app.ts # entry proint
-├── env.d.ts # additional types
-├── style.css
-└── tsconfig.json # needed by LSPs
-```
+After your [bundle step](./installation.md) run `gjs -m app.js`, and that's it!
+Now you have an Astal instance running written in TypeScript.
## Root of every shell component: Window
@@ -290,7 +275,7 @@ function Counter() {
<label label={bind(count).as(num => num.toString())} />
<button onClicked={increment}>
Click to increment
- <button>
+ </button>
</box>
}
```
@@ -369,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/guide/typescript/installation.md b/docs/guide/typescript/installation.md
index e0f1bd5..0c19325 100644
--- a/docs/guide/typescript/installation.md
+++ b/docs/guide/typescript/installation.md
@@ -1,89 +1,19 @@
# Installation
-It is recommended to use [AGS](https://github.com/aylur/ags)
+It is recommended to use [AGS](https://aylur.github.io/ags/)
to scaffold and run projects in TypeScript.
It lets you
- generate TypeScript types using [ts-for-gir](https://github.com/gjsify/ts-for-gir)
-- generate a tsconfig which is used by LSPs
-- bundle your TypeScript and JavaScript code using [esbuild](https://esbuild.github.io/).
+- generate a tsconfig which is used by LSPs to provide intellisense
+- bundle your TypeScript and JavaScript code using [esbuild](https://esbuild.github.io/)
:::details Trivia
AGS is the predecessor of Astal, which was written purely in TypeScript and so only supported
-JavaScript/TypeScript. Now it serves as a scaffolding tool for Astal+TypeScript+JSX projects.
+JavaScript/TypeScript. Now it serves as a scaffolding tool for Astal+TypeScript projects.
:::
-## Nix
-
-maintainer: [@Aylur](https://github.com/Aylur)
-
-Read more about it on the [nix page](../getting-started/nix#ags)
-
-You can try without installing.
-
-<!--TODO: remove v2 after merge-->
-```sh
-nix run github:aylur/ags/v2#agsFull -- --help
-```
-
-## From source
-
-1. [Install Astal](../getting-started/installation.md) if you have not already
-
-2. Install the Astal GJS package
-
-```sh
-git clone https://github.com/aylur/astal /tmp/astal
-cd /tmp/astal/lang/gjs
-meson setup --prefix /usr build
-meson install -C build
-```
-
-:::tip
-You might be wondering why it is recommended to install a JavaScript
-package on the system instead of installing it as a node module.
-It is solely to keep it in **sync** with the core `astal-io` and `astal3`/`astal4` package.
-:::
-
-3. Install the following dependencies
-
-:::code-group
-
-```sh [<i class="devicon-archlinux-plain"></i> Arch]
-sudo pacman -Syu go npm gjs
-```
-
-```sh [<i class="devicon-fedora-plain"></i> Fedora]
-sudo dnf install golang npm gjs
-```
-
-```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu]
-sudo apt install golang-go npm gjs
-```
-
-:::
-
-3. Clone the repo and Install
-
-<!--TODO: remove v2 after merge-->
-```sh
-git clone https://github.com/aylur/ags.git /tmp/ags
-cd /tmp/ags
-git checkout v2 # https://github.com/Aylur/ags/pull/504
-go install
-```
-
-:::tip
-`go install` installs the `ags` binary to `$GOPATH/bin` so make sure its in your `$PATH`.
-You can move it to another directory if you like. For example
-
-```sh
-sudo mv $GOPATH/bin/ags /usr/bin/ags
-```
-
-:::
-
-## Without AGS
+## Setting up a project
🚧 Setting up a dev environment without AGS is not yet documented. 🚧
diff --git a/docs/guide/typescript/theming.md b/docs/guide/typescript/theming.md
index 10a3981..5944c4e 100644
--- a/docs/guide/typescript/theming.md
+++ b/docs/guide/typescript/theming.md
@@ -23,28 +23,24 @@ You can pass a path to a file or css as a string in `App.start`
:::code-group
```ts [app.ts]
-import style from "inline:./style.css"
-
-const inlineCssInCode = `
-window {
- background-color: transparent;
-}
+const inlineCss = `
+ window {
+ background-color: transparent;
+ }
`
App.start({
- css: "./style.css",
- css: style,
- css: `${SRC}/style.css'`,
css: inlineCss,
+ css: "./style.css",
+ css: "/path/to/style.css",
})
```
:::
-:::info
-When using AGS the global `SRC` will point to the directory `app.ts` is in.
-AGS will set the current working directory to `--config`, so `./style.css` also works.
-If you are not using AGS you should inline import CSS instead.
+:::warning
+When using relative paths, for example `./style.css` keep in mind that they
+will be relative to the current working directory.
:::
## Css Property on Widgets
@@ -90,20 +86,11 @@ You can reset stylesheets with `App.resetCss`
If you are not sure about the widget hierarchy or any CSS selector,
you can use the [GTK inspector](https://wiki.gnome.org/Projects/GTK/Inspector)
-::: code-group
-
-```sh [astal]
+```sh
# to bring up the inspector run
astal --inspector
```
-```sh [ags]
-# to bring up the inspector run
-ags --inspector
-```
-
-:::
-
## Using SCSS
Gtk's CSS only supports a subset of what the web offers.
@@ -126,54 +113,22 @@ npm install -g sass # not packaged on Ubuntu
:::
-Importing `scss` files will simply return transpiled css.
-
:::code-group
```ts [app.ts]
-import style from "./style.scss"
+import { exec } from "astal/process"
+
+exec("sass", "./style.scss", "/tmp/style.css")
App.start({
- css: style,
+ css: "/tmp/style.css",
main() {},
})
```
:::
-:::details Without AGS
-AGS uses a plugin to transpile scss files before importing them.
-If you are not using AGS, you can use a plugin for your chosen bundler.
-:::
-
:::tip
-If you for example want to set scss varibles from JS,
-You can inline import, compose, and transpile yourself.
-
-```ts [app.ts]
-import style1 from "inline:./style1.scss"
-import style2 from "inline:./style2.scss"
-
-const tmpscss = "/tmp/style.scss"
-const target = "/tmp/style.css"
-
-writeFile(tmpscss, `
- $var1: red;
- $var1: blue;
- ${style1}
- ${style1}
-`)
-
-exec(`sass ${tmpscss} ${target}`)
-
-App.start({
- css: target,
-})
-
-```
-
-:::
-
-:::info
-If you want other preprocessors support builtin open an Issue.
+You could also transpile scss into css using a bundler
+and simply passing the path of the resulting css file to `css`.
:::
diff --git a/docs/package.json b/docs/package.json
index fea7e8f..ad76c9a 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -1,5 +1,5 @@
{
- "name": "docs",
+ "name": "astal-docs",
"type": "module",
"devDependencies": {
"@eslint/js": "^9.12.0",
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/simple-bar/README.md b/examples/js/simple-bar/README.md
index 6488d14..f92b20e 100644
--- a/examples/js/simple-bar/README.md
+++ b/examples/js/simple-bar/README.md
@@ -4,7 +4,6 @@
A simple bar for Hyprland using
-- [Audio library](https://aylur.github.io/astal/guide/libraries/audio).
- [Battery library](https://aylur.github.io/astal/guide/libraries/battery).
- [Hyprland library](https://aylur.github.io/astal/guide/libraries/hyprland).
- [Mpris library](https://aylur.github.io/astal/guide/libraries/mpris).
diff --git a/examples/lua/simple-bar/README.md b/examples/lua/simple-bar/README.md
index bcc6bba..48cc27c 100644
--- a/examples/lua/simple-bar/README.md
+++ b/examples/lua/simple-bar/README.md
@@ -4,7 +4,6 @@
A simple bar for Hyprland using
-- [Audio library](https://aylur.github.io/astal/guide/libraries/audio).
- [Battery library](https://aylur.github.io/astal/guide/libraries/battery).
- [Hyprland library](https://aylur.github.io/astal/guide/libraries/hyprland).
- [Mpris library](https://aylur.github.io/astal/guide/libraries/mpris).
diff --git a/examples/py/simple-bar/README.md b/examples/py/simple-bar/README.md
index bcc6bba..48cc27c 100644
--- a/examples/py/simple-bar/README.md
+++ b/examples/py/simple-bar/README.md
@@ -4,7 +4,6 @@
A simple bar for Hyprland using
-- [Audio library](https://aylur.github.io/astal/guide/libraries/audio).
- [Battery library](https://aylur.github.io/astal/guide/libraries/battery).
- [Hyprland library](https://aylur.github.io/astal/guide/libraries/hyprland).
- [Mpris library](https://aylur.github.io/astal/guide/libraries/mpris).
diff --git a/examples/vala/simple-bar/README.md b/examples/vala/simple-bar/README.md
index bcc6bba..48cc27c 100644
--- a/examples/vala/simple-bar/README.md
+++ b/examples/vala/simple-bar/README.md
@@ -4,7 +4,6 @@
A simple bar for Hyprland using
-- [Audio library](https://aylur.github.io/astal/guide/libraries/audio).
- [Battery library](https://aylur.github.io/astal/guide/libraries/battery).
- [Hyprland library](https://aylur.github.io/astal/guide/libraries/hyprland).
- [Mpris library](https://aylur.github.io/astal/guide/libraries/mpris).
diff --git a/examples/vala/simple-bar/widget/Bar.vala b/examples/vala/simple-bar/widget/Bar.vala
index 17db831..ba4062c 100644
--- a/examples/vala/simple-bar/widget/Bar.vala
+++ b/examples/vala/simple-bar/widget/Bar.vala
@@ -113,9 +113,6 @@ class SysTray : Gtk.Box {
var item = tray.get_item(id);
- if (item.icon_theme_path != null)
- App.instance.add_icons(item.icon_theme_path);
-
var menu = item.create_menu();
var btn = new Astal.Button();
var icon = new Astal.Icon();
@@ -131,8 +128,10 @@ class SysTray : Gtk.Box {
});
item.bind_property("tooltip-markup", btn, "tooltip-markup", BindingFlags.SYNC_CREATE);
- item.bind_property("gicon", icon, "gicon", BindingFlags.SYNC_CREATE);
+ item.bind_property("gicon", icon, "g-icon", BindingFlags.SYNC_CREATE);
+ btn.add(icon);
add(btn);
+ btn.show_all();
items.set(id, btn);
}
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/package.json b/lang/gjs/package.json
index da88d90..43a7702 100644
--- a/lang/gjs/package.json
+++ b/lang/gjs/package.json
@@ -4,7 +4,7 @@
"description": "Building blocks for building linux desktop shell",
"type": "module",
"author": "Aylur",
- "license": "GPL",
+ "license": "LGPL-2.1",
"repository": {
"type": "git",
"url": "https://github.com/aylur/astal.git",
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 59dd62a..b744cfb 100644
--- a/lang/gjs/src/gobject.ts
+++ b/lang/gjs/src/gobject.ts
@@ -51,6 +51,8 @@ export function register(options: MetaInfo = {}) {
Properties: { ...cls[meta]?.Properties },
...options,
}, cls)
+
+ delete cls[meta]
}
}
@@ -124,7 +126,9 @@ export function signal(
}
}
else {
- target.constructor[meta].Signals[name] = declaration
+ target.constructor[meta].Signals[name] = declaration || {
+ param_types: [],
+ }
}
if (!desc) {
diff --git a/lang/gjs/src/gtk3/astalify.ts b/lang/gjs/src/gtk3/astalify.ts
index b9621be..6973805 100644
--- a/lang/gjs/src/gtk3/astalify.ts
+++ b/lang/gjs/src/gtk3/astalify.ts
@@ -43,7 +43,7 @@ function setProp(obj: any, prop: string, value: any) {
export default function astalify<
C extends { new(...args: any[]): Gtk.Widget },
->(cls: C) {
+>(cls: C, clsName = cls.name) {
class Widget extends cls {
get css(): string { return Astal.widget_get_css(this) }
set css(css: string) { Astal.widget_set_css(this, css) }
@@ -233,7 +233,7 @@ export default function astalify<
}
GObject.registerClass({
- GTypeName: `Astal_${cls.name}`,
+ GTypeName: `Astal_${clsName}`,
Properties: {
"class-name": GObject.ParamSpec.string(
"class-name", "", "", GObject.ParamFlags.READWRITE, "",
@@ -256,7 +256,7 @@ export default function astalify<
return Widget
}
-type BindableProps<T> = {
+export type BindableProps<T> = {
[K in keyof T]: Binding<T[K]> | T[K];
}
diff --git a/lang/gjs/src/gtk3/index.ts b/lang/gjs/src/gtk3/index.ts
index cfafbda..ff641af 100644
--- a/lang/gjs/src/gtk3/index.ts
+++ b/lang/gjs/src/gtk3/index.ts
@@ -1,9 +1,9 @@
import Astal from "gi://Astal?version=3.0"
import Gtk from "gi://Gtk?version=3.0"
import Gdk from "gi://Gdk?version=3.0"
-import astalify, { type ConstructProps } from "./astalify.js"
+import astalify, { type ConstructProps, type BindableProps } from "./astalify.js"
export { Astal, Gtk, Gdk }
export { default as App } from "./app.js"
-export { astalify, ConstructProps }
+export { astalify, ConstructProps, BindableProps }
export * as Widget from "./widget.js"
diff --git a/lang/gjs/src/gtk3/jsx-runtime.ts b/lang/gjs/src/gtk3/jsx-runtime.ts
index 22dc424..9da4bb6 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..6643ba5
--- /dev/null
+++ b/lang/gjs/src/overrides.ts
@@ -0,0 +1,69 @@
+/**
+ * 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_schemas")
+ patch(Player.prototype, "supportedUriSchemas")
+ 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")
+})
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/lang/lua/astal-dev-1.rockspec b/lang/lua/astal-dev-1.rockspec
index 3970672..d8ee9be 100644
--- a/lang/lua/astal-dev-1.rockspec
+++ b/lang/lua/astal-dev-1.rockspec
@@ -8,7 +8,7 @@ source = {
description = {
summary = "lua bindings for libastal.",
homepage = "https://aylur.github.io/astal/",
- license = "GPL-3",
+ license = "LGPL-2.1",
}
dependencies = {
diff --git a/lang/lua/astal/binding.lua b/lang/lua/astal/binding.lua
index 2944ec4..dd2df7f 100644
--- a/lang/lua/astal/binding.lua
+++ b/lang/lua/astal/binding.lua
@@ -2,12 +2,14 @@ local lgi = require("lgi")
local GObject = lgi.require("GObject", "2.0")
---@class Binding
----@field emitter table|Variable
+---@field emitter table | Variable | userdata
---@field property? string
---@field transform_fn function
+---@overload fun(emitter: table | userdata, property?: string): Binding
local Binding = {}
+Binding.__index = Binding
----@param emitter table
+---@param emitter table | Variable | userdata
---@param property? string
---@return Binding
function Binding.new(emitter, property)
@@ -28,14 +30,15 @@ function Binding:__tostring()
return str .. ">"
end
+---@return any
function Binding:get()
if self.property ~= nil and GObject.Object:is_type_of(self.emitter) then
return self.transform_fn(self.emitter[self.property])
- end
- if type(self.emitter.get) == "function" then
+ elseif type(self.emitter.get) == "function" then
return self.transform_fn(self.emitter:get())
+ else
+ error("can not get: Not a GObject or a Variable " + self)
end
- error("can not get: Not a GObject or a Variable " + self)
end
---@param transform fun(value: any): any
@@ -58,14 +61,17 @@ function Binding:subscribe(callback)
return function()
GObject.signal_handler_disconnect(self.emitter, id)
end
- end
- if type(self.emitter.subscribe) == "function" then
+ elseif type(self.emitter.subscribe) == "function" then
return self.emitter:subscribe(function()
callback(self:get())
end)
+ else
+ error("can not subscribe: Not a GObject or a Variable " + self)
end
- error("can not subscribe: Not a GObject or a Variable " + self)
end
-Binding.__index = Binding
-return Binding
+return setmetatable(Binding, {
+ __call = function(_, emitter, prop)
+ return Binding.new(emitter, prop)
+ end,
+})
diff --git a/lang/lua/astal/gtk3/app.lua b/lang/lua/astal/gtk3/app.lua
index 7895f69..58564ce 100644
--- a/lang/lua/astal/gtk3/app.lua
+++ b/lang/lua/astal/gtk3/app.lua
@@ -25,29 +25,26 @@ end
local app = AstalLua()
---@class StartConfig
----@field icons? string
----@field instance_name? string
----@field gtk_theme? string
----@field icon_theme? string
----@field cursor_theme? string
----@field css? string
----@field hold? boolean
----@field request_handler? fun(msg: string, response: fun(res: any))
----@field main? fun(...): unknown
----@field client? fun(message: fun(msg: string): string, ...): unknown
+---@field icons string?
+---@field instance_name string?
+---@field gtk_theme string?
+---@field icon_theme string?
+---@field cursor_theme string?
+---@field css string?
+---@field hold boolean?
+---@field request_handler fun(msg: string, response: fun(res: any)): nil
+---@field main fun(...): nil
+---@field client fun(message: fun(msg: string): string, ...): nil
----@param config StartConfig | nil
+---@param config? StartConfig
function Astal.Application:start(config)
- if config == nil then
- config = {}
- end
+ config = config or {}
- if config.client == nil then
- config.client = function()
+ config.client = config.client
+ or function()
print('Astal instance "' .. app.instance_name .. '" is already running')
os.exit(1)
end
- end
if config.hold == nil then
config.hold = true
@@ -61,17 +58,11 @@ function Astal.Application:start(config)
if config.icons then
self:add_icons(config.icons)
end
- if config.instance_name then
- self.instance_name = config.instance_name
- end
- if config.gtk_theme then
- self.gtk_theme = config.gtk_theme
- end
- if config.icon_theme then
- self.icon_theme = config.icon_theme
- end
- if config.cursor_theme then
- self.cursor_theme = config.cursor_theme
+
+ for _, key in ipairs({ "instance_name", "gtk_theme", "icon_theme", "cursor_theme" }) do
+ if config[key] then
+ self[key] = config[key]
+ end
end
app.on_activate = function()
diff --git a/lang/lua/astal/gtk3/astalify.lua b/lang/lua/astal/gtk3/astalify.lua
index 211a1d4..95faa2c 100644
--- a/lang/lua/astal/gtk3/astalify.lua
+++ b/lang/lua/astal/gtk3/astalify.lua
@@ -163,9 +163,7 @@ return function(ctor)
end
return function(tbl)
- if tbl == nil then
- tbl = {}
- end
+ tbl = tbl or {}
local bindings = {}
local setup = tbl.setup
diff --git a/lang/lua/astal/gtk3/widget.lua b/lang/lua/astal/gtk3/widget.lua
index beaad6c..c8857e7 100644
--- a/lang/lua/astal/gtk3/widget.lua
+++ b/lang/lua/astal/gtk3/widget.lua
@@ -3,6 +3,7 @@ local Astal = lgi.require("Astal", "3.0")
local Gtk = lgi.require("Gtk", "3.0")
local astalify = require("astal.gtk3.astalify")
+---@overload fun(ctor: any): function
local Widget = {
astalify = astalify,
Box = astalify(Astal.Box),
diff --git a/lang/lua/astal/init.lua b/lang/lua/astal/init.lua
index 5630ba4..190994a 100644
--- a/lang/lua/astal/init.lua
+++ b/lang/lua/astal/init.lua
@@ -7,6 +7,7 @@ local Binding = require("astal.binding")
local File = require("astal.file")
local Process = require("astal.process")
local Time = require("astal.time")
+---@type Variable | fun(v: any): Variable
local Variable = require("astal.variable")
return {
diff --git a/lang/lua/astal/variable.lua b/lang/lua/astal/variable.lua
index 2305a71..ad59a3f 100644
--- a/lang/lua/astal/variable.lua
+++ b/lang/lua/astal/variable.lua
@@ -17,6 +17,7 @@ local Process = require("astal.process")
---@field private poll_fn? function
---@field private watch_transform? fun(next: any, prev: any): any
---@field private watch_exec? string[] | string
+---@overload fun(transform?: fun(v: any): any): Binding
local Variable = {}
Variable.__index = Variable
@@ -24,23 +25,23 @@ Variable.__index = Variable
---@return Variable
function Variable.new(value)
local v = Astal.VariableBase()
- local variable = setmetatable({
- variable = v,
- _value = value,
- }, Variable)
+ local variable = setmetatable({ variable = v, _value = value }, Variable)
+
v.on_dropped = function()
variable:stop_watch()
variable:stop_poll()
end
+
v.on_error = function(_, err)
if variable.err_handler then
variable.err_handler(err)
end
end
+
return variable
end
----@param transform? fun(v: any): any
+---@param transform? fun(v: any): any
---@return Binding
function Variable:__call(transform)
if type(transform) == "nil" then
@@ -54,10 +55,13 @@ function Variable:__tostring()
return "Variable<" .. tostring(self:get()) .. ">"
end
+---@return any
function Variable:get()
return self._value
end
+---@param value any
+---@return nil
function Variable:set(value)
if value ~= self:get() then
self._value = value
@@ -107,7 +111,6 @@ function Variable:start_watch()
end)
end
-
function Variable:stop_poll()
if self:is_polling() then
self._poll.cancel()
@@ -122,7 +125,6 @@ function Variable:stop_watch()
self._watch = nil
end
-
function Variable:drop()
self.variable.emit_dropped()
end
@@ -180,8 +182,9 @@ end
---@param exec string | string[]
---@param transform? fun(next: any, prev: any): any
+---@return Variable
function Variable:watch(exec, transform)
- transform = transform or function (next)
+ transform = transform or function(next)
return next
end
@@ -240,7 +243,7 @@ function Variable.derive(deps, transform)
for i, var in ipairs(deps) do
if getmetatable(var) == Variable then
- deps[i] = Binding.new(var)
+ deps[i] = var()
end
end
@@ -249,7 +252,7 @@ function Variable.derive(deps, transform)
for i, binding in ipairs(deps) do
params[i] = binding:get()
end
- return transform(table.unpack(params), 1, #deps)
+ return transform(table.unpack(params, 1, #deps))
end
local var = Variable.new(update())
@@ -272,4 +275,4 @@ return setmetatable(Variable, {
__call = function(_, v)
return Variable.new(v)
end,
-}) \ No newline at end of file
+})
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/gtk4/gir.py b/lib/astal/gtk4/gir.py
index 9ef680f..16a3a64 100644..120000
--- a/lib/astal/gtk4/gir.py
+++ b/lib/astal/gtk4/gir.py
@@ -1,58 +1 @@
-"""
-Vala's generated gir does not contain comments,
-so we use valadoc to generate them. However, they are formatted
-for valadoc and not gi-docgen so we need to fix it.
-"""
-
-import xml.etree.ElementTree as ET
-import html
-import sys
-import subprocess
-
-
-def fix_gir(name: str, gir: str, out: str):
- namespaces = {
- "": "http://www.gtk.org/introspection/core/1.0",
- "c": "http://www.gtk.org/introspection/c/1.0",
- "glib": "http://www.gtk.org/introspection/glib/1.0",
- }
- for prefix, uri in namespaces.items():
- ET.register_namespace(prefix, uri)
-
- tree = ET.parse(gir)
- root = tree.getroot()
-
- for doc in root.findall(".//doc", namespaces):
- if doc.text:
- doc.text = (
- html.unescape(doc.text).replace("<para>", "").replace("</para>", "")
- )
-
- if (inc := root.find("c:include", namespaces)) is not None:
- inc.set("name", f"{name}.h")
- else:
- print("no c:include tag found", file=sys.stderr)
- exit(1)
-
- tree.write(out, encoding="utf-8", xml_declaration=True)
-
-
-def valadoc(name: str, gir: str, args: list[str]):
- cmd = ["valadoc", "-o", "docs", "--package-name", name, "--gir", gir, *args]
- try:
- subprocess.run(cmd, check=True, text=True, capture_output=True)
- except subprocess.CalledProcessError as e:
- print(e.stderr, file=sys.stderr)
- exit(1)
-
-
-if __name__ == "__main__":
- name = sys.argv[1]
- in_out = sys.argv[2].split(":")
- args = sys.argv[3:]
-
- gir = in_out[0]
- out = in_out[1] if len(in_out) > 1 else gir
-
- valadoc(name, gir, args)
- fix_gir(name, gir, out)
+../../gir.py \ No newline at end of file
diff --git a/lib/astal/io/gir.py b/lib/astal/io/gir.py
index 9ef680f..16a3a64 100644..120000
--- a/lib/astal/io/gir.py
+++ b/lib/astal/io/gir.py
@@ -1,58 +1 @@
-"""
-Vala's generated gir does not contain comments,
-so we use valadoc to generate them. However, they are formatted
-for valadoc and not gi-docgen so we need to fix it.
-"""
-
-import xml.etree.ElementTree as ET
-import html
-import sys
-import subprocess
-
-
-def fix_gir(name: str, gir: str, out: str):
- namespaces = {
- "": "http://www.gtk.org/introspection/core/1.0",
- "c": "http://www.gtk.org/introspection/c/1.0",
- "glib": "http://www.gtk.org/introspection/glib/1.0",
- }
- for prefix, uri in namespaces.items():
- ET.register_namespace(prefix, uri)
-
- tree = ET.parse(gir)
- root = tree.getroot()
-
- for doc in root.findall(".//doc", namespaces):
- if doc.text:
- doc.text = (
- html.unescape(doc.text).replace("<para>", "").replace("</para>", "")
- )
-
- if (inc := root.find("c:include", namespaces)) is not None:
- inc.set("name", f"{name}.h")
- else:
- print("no c:include tag found", file=sys.stderr)
- exit(1)
-
- tree.write(out, encoding="utf-8", xml_declaration=True)
-
-
-def valadoc(name: str, gir: str, args: list[str]):
- cmd = ["valadoc", "-o", "docs", "--package-name", name, "--gir", gir, *args]
- try:
- subprocess.run(cmd, check=True, text=True, capture_output=True)
- except subprocess.CalledProcessError as e:
- print(e.stderr, file=sys.stderr)
- exit(1)
-
-
-if __name__ == "__main__":
- name = sys.argv[1]
- in_out = sys.argv[2].split(":")
- args = sys.argv[3:]
-
- gir = in_out[0]
- out = in_out[1] if len(in_out) > 1 else gir
-
- valadoc(name, gir, args)
- fix_gir(name, gir, out)
+../../gir.py \ No newline at end of file
diff --git a/lib/gir.py b/lib/gir.py
index a0a81dc..66cbcfd 100644
--- a/lib/gir.py
+++ b/lib/gir.py
@@ -9,6 +9,7 @@ import html
import sys
import subprocess
import re
+import os
# valac fails on gi-docgen compliant markdown
@@ -47,7 +48,7 @@ def fix_gir(name: str, gir: str, out: str):
def valadoc(name: str, gir: str, args: list[str]):
- cmd = ["valadoc", "-o", "docs", "--package-name", name, "--gir", gir, *args]
+ cmd = [os.getenv("VALADOC", "valadoc"), "-o", "docs", "--package-name", name, "--gir", gir, *args]
try:
subprocess.run(cmd, check=True, text=True, capture_output=True)
except subprocess.CalledProcessError as e:
diff --git a/lib/hyprland/hyprland.vala b/lib/hyprland/hyprland.vala
index ea95cab..17c426c 100644
--- a/lib/hyprland/hyprland.vala
+++ b/lib/hyprland/hyprland.vala
@@ -381,20 +381,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,6 +421,17 @@ public class Hyprland : Object {
minimize(get_client(argv[0]), argv[1] == "0");
break;
+ // first event that signals a new window not openwindow
+ case "windowtitlev2":
+ 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 "windowtitle":
yield sync_clients();
break;
diff --git a/lib/hyprland/monitor.vala b/lib/hyprland/monitor.vala
index d7b8028..6c46142 100644
--- a/lib/hyprland/monitor.vala
+++ b/lib/hyprland/monitor.vala
@@ -1,5 +1,4 @@
-namespace AstalHyprland {
-public class Monitor : Object {
+public class AstalHyprland.Monitor : Object {
public signal void removed ();
public int id { get; private set; }
@@ -20,6 +19,7 @@ public class Monitor : Object {
public int reserved_left { get; private set; }
public int reserved_right { get; private set; }
public double scale { get; private set; }
+ public Transform transform { get; private set; }
public bool focused { get; private set; }
public bool dpms_status { get; private set; }
public bool vrr { get; private set; }
@@ -43,6 +43,7 @@ public class Monitor : Object {
x = (int)obj.get_int_member("x");
y = (int)obj.get_int_member("y");
scale = obj.get_double_member("scale");
+ transform = (Transform)obj.get_int_member("transform");
focused = obj.get_boolean_member("focused");
dpms_status = obj.get_boolean_member("dpmsStatus");
vrr = obj.get_boolean_member("vrr");
@@ -67,5 +68,22 @@ public class Monitor : Object {
public void focus() {
Hyprland.get_default().dispatch("focusmonitor", id.to_string());
}
-}
+
+ public enum Transform {
+ NORMAL = 0,
+ /** rotate by 90° counter clockwise */
+ ROTATE_90_DEG = 1,
+ /** rotate by 180° */
+ ROTATE_180_DEG = 2,
+ /** rotate by 270° counter clockwise */
+ ROTATE_270_DEG = 3,
+ /** mirror both axis */
+ FLIPPED = 4,
+ /** flip and rotate by 90° */
+ FLIPPED_ROTATE_90_DEG = 5,
+ /** flip and rotate by 180° */
+ FLIPPED_ROTATE_180_DEG = 6,
+ /** flip and rotate by 270° */
+ FLIPPED_ROTATE_270_DEG = 7,
+ }
}
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..c69eb21 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)
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 7be01d2..1e5cc70 100644
--- a/lib/powerprofiles/cli.vala
+++ b/lib/powerprofiles/cli.vala
@@ -56,16 +56,16 @@ int main(string[] argv) {
if (daemonize) {
var loop = new MainLoop();
- stdout.printf("%s\n", profiles.to_json_string());
+ stdout.printf("%s\n", to_json_string(profiles));
stdout.flush();
profiles.notify.connect(() => {
- stdout.printf("%s\n", profiles.to_json_string());
+ stdout.printf("%s\n", to_json_string(profiles));
stdout.flush();
});
profiles.profile_released.connect(() => {
- stdout.printf("%s\n", profiles.to_json_string());
+ stdout.printf("%s\n", to_json_string(profiles));
stdout.flush();
});
@@ -73,8 +73,49 @@ int main(string[] argv) {
}
if (set == null && !daemonize) {
- stdout.printf("%s\n", profiles.to_json_string());
+ stdout.printf("%s\n", to_json_string(profiles));
}
return 0;
}
+
+string to_json_string(AstalPowerProfiles.PowerProfiles profiles) {
+ var acts = new Json.Builder().begin_array();
+ foreach (var action in profiles.actions) {
+ acts.add_string_value(action);
+ }
+
+ var active_holds = new Json.Builder().begin_array();
+ foreach (var action in profiles.active_profile_holds) {
+ active_holds.add_value(new Json.Builder()
+ .begin_object()
+ .set_member_name("application_id").add_string_value(action.application_id)
+ .set_member_name("profile").add_string_value(action.profile)
+ .set_member_name("reason").add_string_value(action.reason)
+ .end_object()
+ .get_root());
+ }
+
+ var profs = new Json.Builder().begin_array();
+ 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("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)
+ .end_object()
+ .get_root());
+ }
+
+ return Json.to_string(new Json.Builder()
+ .begin_object()
+ .set_member_name("active_profile").add_string_value(profiles.active_profile)
+ .set_member_name("icon_name").add_string_value(profiles.icon_name)
+ .set_member_name("performance_degraded").add_string_value(profiles.performance_degraded)
+ .set_member_name("actions").add_value(acts.end_array().get_root())
+ .set_member_name("active_profile_holds").add_value(active_holds.end_array().get_root())
+ .set_member_name("profiles").add_value(profs.end_array().get_root())
+ .end_object()
+ .get_root(), false);
+}
diff --git a/lib/powerprofiles/gir.py b/lib/powerprofiles/gir.py
new file mode 120000
index 0000000..b5b4f1d
--- /dev/null
+++ b/lib/powerprofiles/gir.py
@@ -0,0 +1 @@
+../gir.py \ No newline at end of file
diff --git a/lib/powerprofiles/meson.build b/lib/powerprofiles/meson.build
index d0fe78f..cd8cc2b 100644
--- a/lib/powerprofiles/meson.build
+++ b/lib/powerprofiles/meson.build
@@ -39,32 +39,38 @@ deps = [
dependency('json-glib-1.0'),
]
-sources = [
- config,
+sources = [config] + files(
'power-profiles.vala',
-]
+)
if get_option('lib')
lib = library(
meson.project_name(),
sources,
dependencies: deps,
+ vala_args: ['--vapi-comments'],
vala_header: meson.project_name() + '.h',
vala_vapi: meson.project_name() + '-' + api_version + '.vapi',
- vala_gir: gir,
version: meson.project_version(),
install: true,
- install_dir: [true, true, true, true],
+ install_dir: [true, true, true],
)
- import('pkgconfig').generate(
- lib,
- name: meson.project_name(),
- filebase: meson.project_name() + '-' + api_version,
- version: meson.project_version(),
- subdirs: meson.project_name(),
- requires: deps,
- install_dir: get_option('libdir') / 'pkgconfig',
+ pkgs = []
+ foreach dep : deps
+ pkgs += ['--pkg=' + dep.name()]
+ endforeach
+
+ gir_tgt = custom_target(
+ gir,
+ command: [find_program('python3'), files('gir.py'), meson.project_name(), gir]
+ + pkgs
+ + sources,
+ input: sources,
+ depends: lib,
+ output: gir,
+ install: true,
+ install_dir: get_option('datadir') / 'gir-1.0',
)
custom_target(
@@ -77,10 +83,20 @@ if get_option('lib')
],
input: lib,
output: typelib,
- depends: lib,
+ depends: [lib, gir_tgt],
install: true,
install_dir: get_option('libdir') / 'girepository-1.0',
)
+
+ import('pkgconfig').generate(
+ lib,
+ name: meson.project_name(),
+ filebase: meson.project_name() + '-' + api_version,
+ version: meson.project_version(),
+ subdirs: meson.project_name(),
+ requires: deps,
+ install_dir: get_option('libdir') / 'pkgconfig',
+ )
endif
if get_option('cli')
diff --git a/lib/powerprofiles/power-profiles.vala b/lib/powerprofiles/power-profiles.vala
index ab98505..a104d2e 100644
--- a/lib/powerprofiles/power-profiles.vala
+++ b/lib/powerprofiles/power-profiles.vala
@@ -16,11 +16,17 @@ private interface IPowerProfiles : DBusProxy {
}
public PowerProfiles get_default() {
+ /** Gets the default singleton PowerProfiles instance. */
return PowerProfiles.get_default();
}
+/**
+ * Client for [[https://freedesktop-team.pages.debian.net/power-profiles-daemon/gdbus-org.freedesktop.UPower.PowerProfiles.html|PowerProfiles]].
+ */
public class PowerProfiles : Object {
private static PowerProfiles instance;
+
+ /** Gets the default singleton PowerProfiles instance. */
public static PowerProfiles get_default() {
if (instance == null)
instance = new PowerProfiles();
@@ -52,19 +58,34 @@ public class PowerProfiles : Object {
}
}
+ /**
+ * The type of the currently active profile.
+ * It might change automatically if a profile is held,
+ * using the [[email protected]_profile] method.
+ */
public string active_profile {
owned get { return proxy.active_profile; }
set { proxy.active_profile = value; }
}
+ /**
+ * Return a named icon based [[email protected]:active_profile].
+ */
public string icon_name {
owned get { return @"power-profile-$active_profile-symbolic"; }
}
+ /**
+ * List of the "actions" implemented in the running daemon.
+ * This can used to figure out whether particular functionality is available in the daemon.
+ */
public string[] actions {
owned get { return proxy.actions.copy(); }
}
+ /**
+ * List of dictionaries representing the current profile holds.
+ */
public Hold[] active_profile_holds {
owned get {
Hold[] holds = new Hold[proxy.active_profile_holds.length];
@@ -80,14 +101,21 @@ public class PowerProfiles : Object {
}
}
+ /**
+ * This will be set if the performance power profile is running in degraded mode,
+ * with the value being used to identify the reason for that degradation.
+ * Possible values are:
+ * - "lap-detected" (the computer is sitting on the user's lap)
+ * - "high-operating-temperature" (the computer is close to overheating)
+ * - "" (the empty string, if not performance is not degraded)
+ */
public string performance_degraded {
owned get { return proxy.performance_degraded; }
}
- public string performance_inhibited {
- owned get { return proxy.performance_degraded; }
- }
-
+ /**
+ * List of each profile.
+ */
public Profile[] profiles {
owned get {
Profile[] profs = new Profile[proxy.profiles.length];
@@ -104,12 +132,31 @@ public class PowerProfiles : Object {
}
}
+ /**
+ * The version of the power-profiles-daemon software.
+ */
public string version {
owned get { return proxy.version; }
}
+ /**
+ * Emitted when the profile is released because
+ * [[email protected]:active_profile] was manually changed.
+ * This will only be emitted to the process that originally called
+ * [[email protected]_profile].
+ */
public signal void profile_released (uint cookie);
+ /**
+ * This forces the passed profile (either 'power-saver' or 'performance')
+ * to be activated until either the caller quits,
+ * [[email protected]_profile] is called,
+ * or the [[email protected]:active_profile] is changed by the user.
+ * When conflicting profiles are requested to be held,
+ * the 'power-saver' profile will be activated in preference to the 'performance' profile.
+ * Those holds will be automatically cancelled if the user manually switches to another profile,
+ * and the [[email protected]::profile_released] signal will be emitted.
+ */
public int hold_profile(string profile, string reason, string application_id) {
try {
return (int)proxy.hold_profile(profile, reason, application_id);
@@ -119,6 +166,9 @@ public class PowerProfiles : Object {
}
}
+ /**
+ * This removes the hold that was set on a profile.
+ */
public void release_profile(uint cookie) {
try {
proxy.release_profile(cookie);
@@ -126,54 +176,21 @@ public class PowerProfiles : Object {
critical(error.message);
}
}
-
- public string to_json_string() {
- var acts = new Json.Builder().begin_array();
- foreach (var action in actions) {
- acts.add_string_value(action);
- }
-
- var active_holds = new Json.Builder().begin_array();
- foreach (var action in active_profile_holds) {
- active_holds.add_value(new Json.Builder()
- .begin_object()
- .set_member_name("application_id").add_string_value(action.application_id)
- .set_member_name("profile").add_string_value(action.profile)
- .set_member_name("reason").add_string_value(action.reason)
- .end_object()
- .get_root());
- }
-
- var profs = new Json.Builder().begin_array();
- foreach (var prof in profiles) {
- profs.add_value(new Json.Builder()
- .begin_object()
- .set_member_name("profie").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)
- .end_object()
- .get_root());
- }
-
- return Json.to_string(new Json.Builder()
- .begin_object()
- .set_member_name("active_profile").add_string_value(active_profile)
- .set_member_name("icon_name").add_string_value(icon_name)
- .set_member_name("performance_degraded").add_string_value(performance_degraded)
- .set_member_name("performance_inhibited").add_string_value(performance_inhibited)
- .set_member_name("actions").add_value(acts.end_array().get_root())
- .set_member_name("active_profile_holds").add_value(active_holds.end_array().get_root())
- .set_member_name("profiles").add_value(profs.end_array().get_root())
- .end_object()
- .get_root(), false);
- }
}
public struct Profile {
+ /**
+ * Will be one of:
+ * - "power-saver" (battery saving profile)
+ * - "balanced" (the default profile)
+ * - "performance" (a profile that does not care about noise or battery consumption)
+ */
public string profile;
public string cpu_driver;
public string platform_driver;
+ /**
+ * Identifies the power-profiles-daemon backend code used to implement the profile.
+ */
public string driver;
}
diff --git a/lib/tray/meson.build b/lib/tray/meson.build
index fbb6672..fbf2f98 100644
--- a/lib/tray/meson.build
+++ b/lib/tray/meson.build
@@ -76,7 +76,7 @@ if get_option('lib')
c_args: dbusmenu_cflags.split(' '),
link_args: dbusmenu_libs.split(' '),
install: true,
- install_dir: true,
+ install_dir: [true, true, true]
)
pkgs = ['--pkg', 'DbusmenuGtk3-0.4', '--pkg', 'Dbusmenu-0.4']