package oxbow
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
Dynamic window manager for the river Wayland compositor
Install
dune-project
Dependency
Authors
Maintainers
Sources
v0.1.0.tar.gz
md5=a637acaa0e19046cd65fff733874eb97
sha512=76230cbecd7510de7a05b5d1f335915ef7b6c4aa557d8dbfd23591606618d2cfa25082d17b93f2f4b53a118d1cbf6a80e4ad51cf0f099b4921fb83d6df0c9801
doc/src/oxbow.runtime/ipc_server.ml.html
Source file ipc_server.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163[@@@landmark "auto-off"] open! Oxbow_core open! Oxbow_ipc open! Oxbow_state module Handler = struct let respond_err flow msg = let r = Response.{ ok = false; err = Some msg; data = None } in let s = Yojson.Safe.to_string (Response.yojson_of_t r) ^ "\n" in Eio.Flow.copy_string s flow ;; let respond_ok flow data = let r = Response.{ ok = true; err = None; data } in let s = Yojson.Safe.to_string (Response.yojson_of_t r) ^ "\n" in Eio.Flow.copy_string s flow ;; let validate ~wm:_ (body : Request.Body.t) = match body with | Command c -> (match c with | Spawn "" -> Error "spawn: empty command" | Exec [||] | Exec [| "" |] -> Error "exec: empty command" | _ -> Ok ()) | Keymap _ | Query _ | Subscribe _ -> Ok () ;; let resolve_seat (wm : Wm.t) (req : Request.t) = match req.seat with | Some name -> (match List.find_opt (fun (s : Seat.t) -> Option.fold ~none:false ~some:(fun n -> n = name) s.name) wm.seats with | Some s -> Ok s | None -> Error (Printf.sprintf "no seat named %S" name)) | None -> Option.fold ~none:(Error "no primary seat available") ~some:(fun s -> Ok s) wm.primary_seat ;; let parse_json line = try Ok (Yojson.Safe.from_string line) with | Yojson.Json_error msg -> Error (Printf.sprintf "json parse: %s" msg) ;; let parse_request json = try Ok (Request.t_of_yojson json) with | Ppx_yojson_conv_lib.Yojson_conv.Of_yojson_error (Failure msg, _) -> Error msg | Ppx_yojson_conv_lib.Yojson_conv.Of_yojson_error _ -> Error "invalid request shape" | exn -> Error (Printexc.to_string exn) ;; let decode_line ~wm line = let open Result.Syntax in let* json = parse_json line in let* req = parse_request json in let* () = validate ~wm req.body in let* seat = resolve_seat wm req in Ok (req, seat) ;; let run_subscribe ~wm ~flow ~buf (s : Event.Subscribe.t) = respond_ok flow None; let kinds = match s.kinds with | [] -> Record.all | ks -> ks in let sub = Wm.Ipc.Subscriber. { kinds; output = s.output; pending = []; wake = Eio.Condition.create () } in Wm.add_subscriber wm sub; Events.seed wm sub; Fun.protect ~finally:(fun () -> Wm.remove_subscriber wm sub) @@ fun () -> try Eio.Fiber.first (fun () -> try ignore @@ Eio.Buf_read.line buf with | End_of_file -> ()) (fun () -> Eio.Buf_write.with_flow flow @@ fun w -> while true do while sub.pending = [] do Eio.Condition.await_no_mutex sub.wake done; let batch = sub.pending in sub.pending <- []; List.iter (fun (_, line) -> Eio.Buf_write.string w (line ^ "\n")) batch done) with | Eio.Io _ -> () ;; let handle_line ~wm ~flow ~buf line = match decode_line ~wm line with | Error e -> respond_err flow e | Ok (req, seat) -> (match req.body, wm.lifecycle with | Subscribe s, Running -> run_subscribe ~wm ~flow ~buf s | _, Running -> let p, u = Eio.Promise.create () in let open Pending_request in let request = { body = req.body; reply = Some u } in Seat.queue_pending seat request; (match Eio.Promise.await p with | Ok data -> respond_ok flow data | Error msg -> respond_err flow msg) | _, (Pending_exit _ | Exited | Close_requested) -> respond_err flow "wm shutting down") ;; let run ~wm flow = let buf = Eio.Buf_read.of_flow flow ~max_size:65536 in match Eio.Buf_read.line buf with | exception (Eio.Cancel.Cancelled _ as e) -> raise e | exception End_of_file -> () | exception _ -> respond_err flow "read failed" | line -> handle_line ~wm ~flow ~buf line ;; end let accept_loop ~sw ~wm socket = let rec loop () = let outcome = Eio.Fiber.first (fun () -> Lifecycle.await_shutdown wm; `Shutdown) (fun () -> Eio.Net.accept_fork ~sw socket ~on_error:(fun exn -> Log.warn @@ fun m -> m "ipc handler crashed: %s" (Printexc.to_string exn)) (fun flow _addr -> Eio.Fiber.first (fun () -> Lifecycle.await_shutdown wm) (fun () -> Handler.run ~wm flow)); `Accepted) in match outcome with | `Shutdown -> () | `Accepted -> loop () in loop () ;; let start ?socket_path ~sw ~net ~wm () = let path = Socket_path.resolve ?override:socket_path () in Unix.putenv "OXBOW_SOCKET" path; let socket = Eio.Net.listen ~sw ~backlog:128 ~reuse_addr:true net (`Unix path) in Eio.Fiber.fork ~sw (fun () -> accept_loop ~sw ~wm socket); Log.info @@ fun m -> m "ipc: listening on %s" path ;;
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>