| Bring vidya in cfd3e36 nandi 19d ago | 1 | (ns glimmer-vidya.ffi |
| 2 | "Raw bindings for Vidya's retained-tree ABI (`ffi/include/vidya_tree.h`). |
| 3 | |
| 4 | Nothing here interprets a prop or an event; that is |
| 5 | `glimmer-vidya.core`'s job. This namespace exists so the boundary is one |
| 6 | readable list of symbols, and so the marshalling rules that come with it — |
| 7 | which pointers die when, which calls must stay on the window thread — are |
| 8 | stated once. |
| 9 | |
| 10 | **Strings returned by this library are borrowed.** `node-get-str`, |
| 11 | `event-name` and `event-text` all answer the same scratch buffer, which the |
| 12 | next such call overwrites. Jolt copies a `:string` return into a Scheme |
| 13 | string as it crosses, so holding the value is safe; holding the *pointer* is |
| 14 | not, and there is no way to do that from here anyway. |
| 15 | |
| 16 | **Every call belongs to the thread that opened the window.** The library |
| 17 | keeps its state in thread-local storage, so a call from anywhere else is |
| 18 | inert rather than unsound — but it is still a bug. `glimmer-vidya.core` |
| 19 | routes off-thread work through glimmer's `schedule`." |
| 20 | (:require [jolt.ffi :as ffi])) |
| 21 | |
| 22 | ;; --- window and frame (shared with the push/pop ABI) ------------------------- |
| 23 | (ffi/defcfn raw-open "vidya_open" [:int :int :string] :int) |
| 24 | (ffi/defcfn close! "vidya_close" [] :void) |
| 25 | (ffi/defcfn raw-should-close "vidya_should_close" [] :int) |
| 26 | (ffi/defcfn set-target-fps! "vidya_set_target_fps" [:int] :void) |
| 27 | (ffi/defcfn set-mode! "vidya_set_mode" [:int] :void) |
| 28 | (ffi/defcfn raw-load-font "vidya_load_font" [:string :int] :int) |
| 29 | |
| 30 | ;; --- the tree ---------------------------------------------------------------- |
| 31 | (ffi/defcfn tree-root "vidya_tree_root" [] :int) |
| 32 | (ffi/defcfn node-new "vidya_node_new" [:string] :int) |
| 33 | (ffi/defcfn node-free! "vidya_node_free" [:int] :void) |
| 34 | (ffi/defcfn raw-node-exists "vidya_node_exists" [:int] :int) |
| 35 | |
| 36 | (ffi/defcfn node-set-str! "vidya_node_set_str" [:int :string :string] :void) |
| 37 | (ffi/defcfn node-set-num! "vidya_node_set_num" [:int :string :double] :void) |
| 38 | (ffi/defcfn raw-node-set-bool "vidya_node_set_bool" [:int :string :int] :void) |
| 39 | (ffi/defcfn node-clear-props! "vidya_node_clear_props" [:int] :void) |
| 40 | |
| 41 | (ffi/defcfn node-get-str "vidya_node_get_str" [:int :string] :string) |
| 42 | (ffi/defcfn node-get-num "vidya_node_get_num" [:int :string] :double) |
| 43 | (ffi/defcfn raw-node-get-bool "vidya_node_get_bool" [:int :string] :int) |
| 44 | |
| 45 | (ffi/defcfn node-tag "vidya_node_tag" [:int] :string) |
| 46 | (ffi/defcfn node-child-count "vidya_node_child_count" [:int] :int) |
| 47 | (ffi/defcfn node-child-at "vidya_node_child_at" [:int :int] :int) |
| 48 | (ffi/defcfn tree-dump "vidya_tree_dump" [:int] :string) |
| 49 | |
| 50 | (ffi/defcfn raw-node-append "vidya_node_append" [:int :int] :int) |
| 51 | (ffi/defcfn node-remove! "vidya_node_remove" [:int :int] :void) |
| 52 | (ffi/defcfn raw-node-insert-after "vidya_node_insert_after" [:int :int :int] :int) |
| 53 | (ffi/defcfn raw-node-replace "vidya_node_replace" [:int :int :int] :int) |
| 54 | |
| 55 | ;; --- frame and events -------------------------------------------------------- |
| 56 | (ffi/defcfn tree-frame! "vidya_tree_frame" [] :void) |
| 57 | (ffi/defcfn raw-poll-event "vidya_tree_poll_event" [] :int) |
| 58 | (ffi/defcfn event-node "vidya_tree_event_node" [] :int) |
| 59 | (ffi/defcfn event-name "vidya_tree_event_name" [] :string) |
| 60 | (ffi/defcfn event-text "vidya_tree_event_text" [] :string) |
| 61 | (ffi/defcfn event-num "vidya_tree_event_num" [] :double) |
| 62 | |
| Tell a caller how big the window is 42dabb0 nandi 19d ago | 63 | |
| 64 | ;; --- the window -------------------------------------------------------------- |
| 65 | ;; Its size in points, following the window as it is dragged. Points rather |
| 66 | ;; than pixels because a caller asking is about to lay something out. |
| 67 | (ffi/defcfn screen-width "vidya_screen_width" [] :float) |
| 68 | (ffi/defcfn screen-height "vidya_screen_height" [] :float) |
| 69 | |
| Bring vidya in cfd3e36 nandi 19d ago | 70 | ;; --- live frames ------------------------------------------------------------- |
| 71 | ;; Pixels pushed in under a name, painted by an `:image` whose `:feed` names it. |
| 72 | ;; `rgba` is a foreign pointer to width*height*4 bytes, copied before the call |
| 73 | ;; returns — the backend keeps nothing, so the caller may reuse its buffer. The |
| 74 | ;; pointer form is the point: a video frame moved through jolt as a byte array |
| 75 | ;; would be copied twice a frame for nothing. |
| 76 | (ffi/defcfn raw-frame-rgba "vidya_frame_rgba" [:string :int :int :pointer] :int) |
| 77 | (ffi/defcfn raw-frame-drop "vidya_frame_drop" [:string] :int) |
| 78 | |
| 79 | ;; --- the clipboard ----------------------------------------------------------- |
| 80 | ;; Not an event: egui carries clipboard text into a frame and nothing else, so a |
| 81 | ;; pasted picture is asked for rather than waited for. |
| 82 | (ffi/defcfn raw-clipboard-image-png "vidya_clipboard_image_png" [:string] :int) |
| 83 | |
| 84 | ;; --- the browser ------------------------------------------------------------- |
| 85 | ;; Leaving for a page and coming back is the platform's business: xdg-open on a |
| 86 | ;; desktop, an ACTION_VIEW intent on Android. |
| 87 | (ffi/defcfn raw-open-url "vidya_open_url" [:string] :int) |
| 88 | |
| Catch up with vidya c90f8af nandi 19d ago | 89 | ;; --- the platform's picture chooser ------------------------------------------ |
| 90 | ;; Opened here, answered later: the reader leaves for a screen of the system's |
| 91 | ;; own, so the pick is polled for rather than returned. |
| 92 | (ffi/defcfn raw-pick-image "vidya_pick_image" [] :int) |
| 93 | (ffi/defcfn raw-picked-image "vidya_picked_image" [:string] :int) |
| 94 | |
| Bring vidya in cfd3e36 nandi 19d ago | 95 | ;; --- the int/bool seam ------------------------------------------------------- |
| 96 | ;; C has no booleans; every predicate here crosses as 0 or 1. Converting at the |
| 97 | ;; binding rather than at each call site keeps the rest of the backend written |
| 98 | ;; in jolt's own truthiness. |
| 99 | |
| 100 | (def dark-mode 0) |
| 101 | (def light-mode 1) |
| 102 | |
| 103 | (defn open! |
| 104 | [width height title] |
| 105 | (not (zero? (raw-open width height title)))) |
| 106 | |
| 107 | (defn should-close? [] (not (zero? (raw-should-close)))) |
| 108 | (defn load-font! [path] (not (zero? (raw-load-font path 32)))) |
| 109 | (defn node-exists? [node] (not (zero? (raw-node-exists node)))) |
| 110 | (defn node-set-bool! [node key value] (raw-node-set-bool node key (if value 1 0))) |
| 111 | (defn node-get-bool [node key] (not (zero? (raw-node-get-bool node key)))) |
| 112 | (defn node-append! [parent child] (not (zero? (raw-node-append parent child)))) |
| 113 | (defn clipboard-image-png! |
| 114 | "Write the clipboard's picture to `path` as a PNG; true when there was one." |
| 115 | [path] |
| 116 | (not (zero? (raw-clipboard-image-png path)))) |
| 117 | (defn open-url! |
| 118 | "Hand `url` to the platform's browser; true when something took it." |
| 119 | [url] |
| 120 | (not (zero? (raw-open-url url)))) |
| Catch up with vidya c90f8af nandi 19d ago | 121 | (defn pick-image! |
| 122 | "Open the platform's picture chooser; true when one opened." |
| 123 | [] |
| 124 | (not (zero? (raw-pick-image)))) |
| 125 | (defn picked-image! |
| 126 | "Move the picture chosen since the last call to `path`; true when there was |
| 127 | one." |
| 128 | [path] |
| 129 | (not (zero? (raw-picked-image path)))) |
| Bring vidya in cfd3e36 nandi 19d ago | 130 | (defn frame-rgba! |
| 131 | "Paint `rgba` — a pointer to width*height*4 un-premultiplied bytes — under |
| 132 | `key`. True when the frame was accepted; false for dimensions the length does |
| 133 | not match." |
| 134 | [key width height rgba] |
| 135 | (not (zero? (raw-frame-rgba key width height rgba)))) |
| 136 | (defn frame-drop! |
| 137 | "Forget the feed named `key`; true when there was one." |
| 138 | [key] |
| 139 | (not (zero? (raw-frame-drop key)))) |
| 140 | (defn node-insert-after! [parent child sibling] |
| 141 | (not (zero? (raw-node-insert-after parent child sibling)))) |
| 142 | (defn node-replace! [parent old new] (not (zero? (raw-node-replace parent old new)))) |
| 143 | (defn poll-event! [] (not (zero? (raw-poll-event)))) |