diff options
Diffstat (limited to 'README.md')
-rw-r--r-- | README.md | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/README.md b/README.md new file mode 100644 index 0000000..71594f7 --- /dev/null +++ b/README.md @@ -0,0 +1,206 @@ +# libastal + +> [!WARNING] +> WIP: everything is subject to change + +The main goal of this project is to further abstract gtk bindings in higher level +languages with custom state management mechanisms, namely in javascript (gjs, node), +lua (lua-lgi). + +`libastal`, which is the library written in Vala, +comes with a few widgets built on top of gtk3 and +tools to execute external binaries and store their output. +It also comes with a builtin cli client to send messages to the running +processes through a socket. + +## Developing + +first install libastal or enter nix shell + +```bash +# non nix +meson setup build +meson insall -C build +``` + +```bash +# nix +nix develop .#astal +``` + +lua should be stright forward, just run the interpreter + +for javascript do + +```bash +cd gjs +npm i +npm run types +npm run build +``` + +## Gtk abstractions + +`Variable` and `Binding` objects and a function that turns widget constructors +into ones that can take `Binding` objects as parameters are added on top +of gtk bindings. This mechanism takes care of all state management one would need. + +This works the same in lua too, but demonstrated in js + +```javascript +// this example will work with Variable<string> +// but it can take any type of value +const v = Variable("value") + .poll(1000, "some-executable on $PATH") + .poll(1000, ["some-executable", "with", "args"]) + .poll(1000, () => "some-function") + .watch("some-executable") + .watch(["some-executable", "with", "args"]) + .observe(someGObject, "signal", (...args) => "some output") + .observe([[gobj1, "signal"], [gobj2, "signal"]], (...args) => "some output") + .onError(console.error) // when the script fails + .onDropped(() => "clean-up") // cleanup resources if needed on drop() or GC + +Button({ + label: bind(v), + label: bind(v).as(v => "transformed"), + label: v(t => "transformed"), // shorthand for the above + + // in ags we have Service.bind("prop") + // here we will do this, since gobject implementations + // will come from Vala code and not js + label: bind(anyGObject, "one-of-its-prop").as(prop => "transformed"), + + // event handlers + on_signalname(self, ...args) { print(self, args) }, + + // setup prop is still here, but should be rarely needed + setup(self) { + self.hook(v, (self) => print(self)) + self.hook(gobject, "signal", (self) => print(self)) + } +}) + +// some additional Variable and Binding methods +v.stop_poll() +v.start_poll() + +v.stop_watch() +v.start_watch() + +v.get() +v.set("new-value") + +const unsub = v.subscribe(value => console.log(value)) +unsub() // to unsubscribe + +const b = bind(v) +b.get() +// note that its value cannot be set through a Binding +// if you want to, you are doing something wrong + +// same subscribe mechanism +const unsub = b.subscribe(value => console.log(value)) +unsub() + +const derived = Variable.derive([v, b], (vval, bval) => { + return "can take a list of Variable | Binding" +}) + +v.drop() // dispose when no longer needed + +// handle cli client +App.start({ + instanceName: "my-instance", + responseHandler(msg, response) { + console.log("message from cli", msg) + response("hi") + } +}) +``` + +after `App.start` is called, it will open a socket, which can be used +with the cli client that comes with libastal + +```bash +astal --instance-name my-instance "message was sent from cli" +``` + +## Lower level languages + +As said before, the main goal is to make js/lua DX better, but libastal +can be used in **any** language that has bindings for glib/gtk. +`Binding` is not implemented in Vala, but in each language, because +they are language specific, and it doesn't make much sense for lower +level languages as they usually don't have a way to declaratively build +layouts. Subclassed widgets and `Variable` can still be used, but they will +need to be hooked **imperatively**. For languages like rust/go/c++ +you will mostly benefit from the other libraries (called `Service` in ags). +I can also recommend using [blueprint](https://jwestman.pages.gitlab.gnome.org/blueprint-compiler/) +which lets you define layouts declaratively and hook functionality in your +preferred language. + +I am open to add support for any other language if it makes sense, +but if using blueprint makes more sense, I would rather maintain +templates and examples instead to get started with development. + +## Goals + +- libastal + - Variables + - [x] poll (interval, string) + - [x] pollv (interval, string[]) + - [x] pollfn (interval, closure) + - [x] watch (string) + - [x] watchv (string[]) + - ~~[ ] observe (object, signal, closure)~~ + - Time + - [x] interval + - [x] timeout + - [x] idle + - [x] now signal + - Process + - [x] exec: string, error as Error + - [x] execAsync: proc, stdout, stderr signal + - [x] subprocess: proc, stdout, stderr signal + - app instance with a socket: Application + - [x] gtk settings as props + - [x] window getters + - [x] include cli client + - few additional widgets + - [x] window widget with gtk-layer-shell + - [x] box with children prop + - [x] button with abstract signals for button-event + - [ ] ?custom calendar like gtk4 + - [x] centerbox + - [ ] circularprogress + - [x] eventbox + - [x] icon + - [x] overlay + - [ ] scrollable/viewport + - [x] slider + - [ ] stack, shown, children setter + - widgets with no additional behaviour only for the sake of it + - [ ] ?drawingarea + - [ ] ?entry + - [ ] ?fixed + - [ ] ?flowbox + - [ ] ?label + - [ ] ?levelbar + - [ ] ?revealer + - [ ] ?switch + - widget prop setters + - [x] css + - [x] class-names + - [x] cursor + - [x] click-through + +- language bindings + - Binding for Variable and any GObject `bind(gobject, property).as(transform)` + - .hook() for widgets + - setup prop for widgets + - constructor overrides to take bindings + - override default `visible` for widgets to true + - wrap Variable in native object to make sure no GValue crashes + - Variable.observe for signals + - Variable.derive that takes either Variables or Bindings |