summaryrefslogtreecommitdiff
path: root/lib/Wayland/Display.lean
diff options
context:
space:
mode:
authorHannes Schulze <haschu0103@outlook.de>2026-03-08 18:26:33 +0100
committerHannes Schulze <haschu0103@outlook.de>2026-03-08 18:26:33 +0100
commitc290706fed69d622cfe988e732e1ad01d09e569d (patch)
tree8822cb160e3596657fc6aa7020026d16632e8e5f /lib/Wayland/Display.lean
parent658b74715751cb4b52b2a968325ece9a62a29fc3 (diff)
rework file structure
Diffstat (limited to 'lib/Wayland/Display.lean')
-rw-r--r--lib/Wayland/Display.lean99
1 files changed, 59 insertions, 40 deletions
diff --git a/lib/Wayland/Display.lean b/lib/Wayland/Display.lean
index 18a05fa..7c628f3 100644
--- a/lib/Wayland/Display.lean
+++ b/lib/Wayland/Display.lean
@@ -1,53 +1,38 @@
import Wayland.Native
+import Wayland.Basic.PosixSignal
+import Wayland.Basic.Duration
+import Wayland.Basic.Lens
-namespace Wayland
-
-def EventSource := Native.EventSource
-
-structure PosixSignal where
- private signum : UInt32
- deriving Repr, BEq, Inhabited
-
-def PosixSignal.SIGINT : PosixSignal := ⟨Native.SIGINT⟩
-def PosixSignal.SIGUSR1 : PosixSignal := ⟨Native.SIGUSR1⟩
-def PosixSignal.SIGUSR2 : PosixSignal := ⟨Native.SIGUSR2⟩
-
-structure Duration where
- private milliseconds : UInt32
- deriving Repr, BEq, Inhabited
+/-!
+# The Display Monad
-def Duration.ofMilliseconds (val : UInt32) : Duration := ⟨val⟩
-def Duration.ofSeconds (val : UInt32) : Duration := .ofMilliseconds (val * 1000)
-def Duration.ofMinutes (val : UInt32) : Duration := .ofSeconds (val * 60)
+All event handlers and effectful code is run within the `DisplayM` monad, which encapsulates the connection to a
+Wayland server. Its main purpose is managing its event loop -- processing timers, signal handlers, and Wayland events.
+Furthermore, it manages a global state `σ` and allows focussing on a relevant part of that state using
+lenses.
+-/
-def Duration.toMilliseconds (val : Duration) : UInt32 := val.milliseconds
-def Duration.toSeconds (val : Duration) : UInt32 := val.toMilliseconds / 1000
-def Duration.toMinutes (val : Duration) : UInt32 := val.toSeconds / 60
-
-notation:2000 val "ms" => Duration.ofMilliseconds val
-notation:2000 val "sec" => Duration.ofSeconds val
-notation:2000 val "min" => Duration.ofMinutes val
+variable {σ α : Type}
-structure Lens (O I : Type) where
- get : O → I
- set : I → O → O
+namespace Wayland
-macro "mk_lens " field:ident : term => do
- let lvalNode := Lean.mkNode `Lean.Parser.Term.structInstLVal #[field.raw, Lean.mkNullNode #[]]
- let lval : Lean.TSyntax `Lean.Parser.Term.structInstLVal := ⟨lvalNode⟩
- `({ get := fun x => x.$field, set := fun i x => { x with $lval := i } })
+/-- A token managing a single source of events such as a timer or a signal handler. This can be used to unregister the
+event. -/
+def EventSource : Type := Native.EventSource
-abbrev Handler (σ : Type) := StateT σ IO Unit
+/-- Internal handler interface passed as a message to the event loop. -/
+private abbrev Handler (σ : Type) := StateT σ IO Unit
+/-- Access to the display and event loop, providing the main functionality. -/
structure Display (σ : Type) where
- disp : Native.Display
- addTimer : (delayMs : UInt32) → (msg : Handler σ) → IO EventSource
- addSignal : (signum : UInt32) → (msg : Handler σ) → IO EventSource
- remove : (source : EventSource) → IO Unit
- quit : IO Unit
-
-variable {σ α : Type}
+ private disp : Native.Display
+ private addTimer : (delayMs : UInt32) → (msg : Handler σ) → IO EventSource
+ private addSignal : (signum : UInt32) → (msg : Handler σ) → IO EventSource
+ private remove : (source : EventSource) → IO Unit
+ private quit : IO Unit
+/-- The display monad: A monad extending the `IO` monad with Wayland display related operations as well as state
+management for a state type σ. -/
def DisplayM (σ : Type) : Type → Type :=
ReaderT (Display σ) (StateT σ IO)
@@ -57,6 +42,12 @@ deriving instance MonadState σ for DisplayM σ
private instance : MonadLift (ReaderT (Display σ) (StateT σ IO)) (DisplayM σ) where
monadLift := id
+/-- Connect to a Wayland server and start the application's main loop.
+
+Parameters:
+· `setUp`: Executed on startup before launching the event loop.
+· `initialState`: The initial state value within the monad.
+· `name`: Socket name for connecting to the Wayland server (by default, `wayland-0` is used). -/
partial def DisplayM.run' (setUp : DisplayM σ Unit) (initialState : σ) (name : Option String := .none) : IO σ := do
let disp ← Native.Display.new name
let loop ← Native.EventLoop.new
@@ -76,23 +67,48 @@ partial def DisplayM.run' (setUp : DisplayM σ Unit) (initialState : σ) (name :
inner
main.run initialState |>.map Prod.snd
+/-- Connect to a Wayland server and start the application's main loop.
+
+Parameters:
+· `setUp`: Executed on startup before launching the event loop.
+· `initialState`: The initial state value within the monad.
+· `name`: Socket name for connecting to the Wayland server (by default, `wayland-0` is used). -/
def DisplayM.run (setUp : DisplayM σ Unit) (initialState : σ) (name : Option String := .none) : IO Unit :=
DisplayM.run' setUp initialState (name := name) |> discard
+/-- Lift an `IO` operation into the Display monad.
+
+Note that `DisplayM` does not provide an instance for `MonadLift IO` to make access to `IO` more explicit. This should
+not be used often. -/
def DisplayM.liftIO (io : IO α) : DisplayM σ α :=
io
+/-- Request the application to stop processing events and exit the event loop.
+
+This can be sent at any time and stops the event loop before any further events can be processed. -/
def DisplayM.requestQuit : DisplayM σ Unit := do
(← read).quit
+/-- Register a (POSIX) signal handler.
+
+When the given `signal` is caught, the `handler` is executed as a part of the event loop. The returned event source can
+be used to unregister the handler. -/
def DisplayM.registerSignal (signal : PosixSignal) (handler : DisplayM σ Unit) : DisplayM σ EventSource := do
let global ← read
global.addSignal signal.signum (ReaderT.run handler global)
+/-- Register a (one-shot) timer.
+
+After the given `timeout`, the `handler` is executed as a part of the event loop. The returned event source can be used
+to cancel the timer. -/
def DisplayM.registerTimer (timeout : Duration) (handler : DisplayM σ Unit) : DisplayM σ EventSource := do
let global ← read
global.addTimer timeout.toMilliseconds (ReaderT.run handler global)
+/-- Unregister a previously registered event source.
+
+If the handler is currently active, it will run to completion, but the event is no longer processed as a part of the
+event loop. -/
def DisplayM.unregister (source : EventSource) : DisplayM σ Unit := do
(← read).remove source
@@ -102,6 +118,9 @@ private def zoomState {σ₁ σ₂ : Type} {m : Type → Type} [Monad m] (lens :
set (lens.set newInner oldOuter)
return res
+/-- Zoom into a specific part of the state using a lens.
+
+This is possible because handlers can only ever be submitted in the `DisplayM` monad, but never retrieved. -/
def DisplayM.zoom {σ₁ σ₂ : Type} (lens : Lens σ₁ σ₂) (inner : DisplayM σ₂ α) : DisplayM σ₁ α := do
let global₁ : Display σ₁ ← read
let global₂ : Display σ₂ :=