(ns glimmer-cosmic.ffi "Raw bindings for libjoltcosmic (`crates/jolt-cosmic/src/lib.rs`). The node half is libvidya's tree ABI under a `cosmic_` prefix. The loop half is not: libcosmic owns the main thread, so `run!` blocks there while the reconciler works from another thread, and its edits are published with `commit!`. **Any thread may call anything here except `raw-run`.** The arena sits behind a mutex; nothing is thread-local. **Strings returned are borrowed** until the next call of the same family — jolt copies a `:string` return as it crosses, so holding the value is safe." (:require [jolt.ffi :as ffi])) ;; --- the loop ---------------------------------------------------------------- ;; :blocking releases the calling thread to Chez for the life of the call. ;; Without it, the worker would stall at its first collection waiting on a ;; thread parked inside libcosmic. A :blocking procedure may not take a string, ;; which is why the title is set by a call of its own. (ffi/defcfn set-title! "cosmic_set_title" [:string] :void) (ffi/defcfn raw-run "cosmic_run" [:int :int :int] :int {:blocking true}) (ffi/defcfn raw-wait "cosmic_wait" [:int] :int {:blocking true}) (ffi/defcfn wake! "cosmic_wake" [] :void) (ffi/defcfn quit! "cosmic_quit" [] :void) (ffi/defcfn raw-should-close "cosmic_should_close" [] :int) (ffi/defcfn raw-commit "cosmic_tree_commit" [] :int) ;; --- the tree ---------------------------------------------------------------- (ffi/defcfn tree-root "cosmic_tree_root" [] :int) (ffi/defcfn node-new "cosmic_node_new" [:string] :int) (ffi/defcfn node-free! "cosmic_node_free" [:int] :void) (ffi/defcfn raw-node-exists "cosmic_node_exists" [:int] :int) (ffi/defcfn node-set-str! "cosmic_node_set_str" [:int :string :string] :void) (ffi/defcfn node-set-num! "cosmic_node_set_num" [:int :string :double] :void) (ffi/defcfn raw-node-set-bool "cosmic_node_set_bool" [:int :string :int] :void) (ffi/defcfn node-clear-props! "cosmic_node_clear_props" [:int] :void) (ffi/defcfn node-tag "cosmic_node_tag" [:int] :string) (ffi/defcfn node-child-count "cosmic_node_child_count" [:int] :int) (ffi/defcfn node-child-at "cosmic_node_child_at" [:int :int] :int) (ffi/defcfn tree-dump "cosmic_tree_dump" [:int] :string) (ffi/defcfn raw-node-append "cosmic_node_append" [:int :int] :int) (ffi/defcfn node-remove! "cosmic_node_remove" [:int :int] :void) (ffi/defcfn raw-node-insert-after "cosmic_node_insert_after" [:int :int :int] :int) (ffi/defcfn raw-node-replace "cosmic_node_replace" [:int :int :int] :int) ;; --- events ------------------------------------------------------------------ (ffi/defcfn raw-poll-event "cosmic_tree_poll_event" [] :int) (ffi/defcfn event-node "cosmic_tree_event_node" [] :int) (ffi/defcfn event-name "cosmic_tree_event_name" [] :string) (ffi/defcfn event-text "cosmic_tree_event_text" [] :string) (ffi/defcfn event-num "cosmic_tree_event_num" [] :double) ;; --- the int/bool seam ------------------------------------------------------- (def system-mode 0) (def dark-mode 1) (def light-mode 2) (defn run! "Open the window and block in libcosmic until it closes. Main thread only. Answers 0 on a clean exit, 1 on an error, 2 if a window already ran in this process." [width height title mode] (set-title! title) (raw-run width height mode)) (defn wait! "Block up to `ms` for an event, a `wake!`, or the window closing. True when an event is waiting." [ms] (not (zero? (raw-wait ms)))) (defn commit! [] (not (zero? (raw-commit)))) (defn should-close? [] (not (zero? (raw-should-close)))) (defn node-exists? [node] (not (zero? (raw-node-exists node)))) (defn node-set-bool! [node key value] (raw-node-set-bool node key (if value 1 0))) (defn node-append! [parent child] (not (zero? (raw-node-append parent child)))) (defn node-insert-after! [parent child sibling] (not (zero? (raw-node-insert-after parent child sibling)))) (defn node-replace! [parent old new] (not (zero? (raw-node-replace parent old new)))) (defn poll-event! [] (not (zero? (raw-poll-event))))