package oxbow

  1. Overview
  2. Docs
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/cycle.ml.html

Source file cycle.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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
open! Oxbow_core
open! Oxbow_state
open! Oxbow_ops

let remove_outputs ctx =
  let wm = Ctx.wm ctx in
  let removed, retained =
    List.partition
      (fun (o : Output.t) ->
         match o.lifecycle with
         | Removed -> true
         | Active -> false)
      wm.outputs
  in
  let first = List.nth_opt retained 0 in
  Wm.set_outputs wm retained;
  List.iter
    (fun (s : Seat.t) ->
       match s.output with
       | Some o when List.memq o removed -> Focus.set_output (Ctx.wm ctx) s first
       | _ -> ())
    wm.seats;
  List.iter
    (fun (w : Window.t) ->
       match w.output with
       | Some o when List.memq o removed -> Window.set_output w None
       | _ -> ())
    wm.windows;
  List.iter
    (fun (o : Output.t) -> Emit.destroy_output ~output:o.obj ~layer_shell:o.layer_shell)
    removed
;;

let disconnect_seat window (seat : Seat.t) =
  (match seat.hovered with
   | Some w when w == window -> Seat.set_hovered seat None
   | _ -> ());
  (match seat.interacted with
   | Some w when w == window -> Seat.set_interacted seat None
   | _ -> ());
  (match seat.focus_state with
   | Refresh w when w == window -> Seat.set_focus_state seat Idle
   | _ -> ());
  (match seat.cursor_target with
   | Some w when w == window -> Seat.set_cursor_target seat None
   | _ -> ());
  match seat.op with
  | Some (Move { window = w; _ } | Resize { window = w; _ }) when w == window ->
    Seat.clear_op seat
  | _ -> ()
;;

let disconnect_seats window = List.iter (disconnect_seat window)

let close_windows ctx =
  let wm = Ctx.wm ctx in
  Wm.set_windows wm
  @@ List.filter
       (fun (w : Window.t) ->
          match w.lifecycle with
          | Closing ->
            disconnect_seats w wm.seats;
            Swallow.on_close w;
            Focus.remove_window (Ctx.wm ctx) w;
            List.iter
              (fun (c : Window.t) ->
                 if Phys.opt_holds w c.parent then Window.set_parent c ~parent:None)
              wm.windows;
            Window.destroy w;
            Schedule.manage ();
            false
          | New | Active -> true)
       wm.windows
;;

let close_seats ctx =
  let wm = Ctx.wm ctx in
  Wm.set_seats wm
  @@ List.filter
       (fun (s : Seat.t) ->
          match s.lifecycle with
          | Closing ->
            Emit.destroy_seat ~seat:s.obj ~layer_shell:s.layer_shell ~xkb_seat:s.xkb_seat;
            false
          | _ -> true)
       wm.seats
;;

let manage_window ctx (window : Window.t) =
  let wm = Ctx.wm ctx in
  List.rev window.requests |> List.iter (Window_request.handle wm window);
  Window.clear_requests window
;;

let manage_new_window ctx (window : Window.t) =
  let wm = Ctx.wm ctx in
  let position, focus = Window_rules.spawn_for wm window in
  Option.iter (Stacking.spawn ~position ~focus ~window) window.output;
  if window.is_fixed || Option.is_some window.parent
  then Window.set_presentation window Floating;
  Window_rules.apply_for wm window;
  manage_window ctx window;
  Swallow.try_swallow wm window;
  Window.set_lifecycle window Active;
  match window.output with
  | Some o ->
    if Window.floats window o && Option.is_none window.float_rel
    then Window.set_float_seed_pending window true
  | _ -> ()
;;

let manage_new_seat ctx (seat : Seat.t) =
  match seat.lifecycle with
  | Active | Closing -> ()
  | New ->
    let wm = Ctx.wm ctx in
    Bind.install_defaults wm seat;
    Seat.set_lifecycle seat Active;
    (match wm.init_handle, wm.init_command with
     | None, Some cmd when Phys.opt_holds seat wm.primary_seat ->
       let init_handle = Init_script.fork ~cmd in
       Wm.set_init_handle wm @@ Some init_handle;
       Log.debug @@ fun m -> m "init script forked: pid=%d" init_handle.pid
     | _ -> ())
;;

let manage_seat ctx seat =
  let rec drain () =
    match Seat.drain_pending seat with
    | None -> ()
    | Some r ->
      Dispatch.handle ctx seat r;
      drain ()
  in
  let wm = Ctx.wm ctx in
  Focus.seat_sync wm seat;
  Focus.apply_request wm seat;
  Focus.apply_interaction wm seat;
  drain ();
  Drag.step wm seat
;;

let manage_output ctx (output : Output.t) =
  match output.lifecycle with
  | Removed -> ()
  | Active ->
    Arrange.retile ctx output;
    Focus.refresh ctx output
;;

let reap ctx =
  remove_outputs ctx;
  close_windows ctx;
  close_seats ctx
;;

let admit ctx =
  let wm = Ctx.wm ctx in
  Focus.wm_sync wm;
  List.iter (manage_new_seat ctx) wm.seats;
  List.iter
    (fun (w : Window.t) ->
       match w.lifecycle with
       | New -> manage_new_window ctx w
       | Active | Closing -> ())
    wm.windows
;;

let apply ctx =
  let wm = Ctx.wm ctx in
  List.iter (manage_window ctx) wm.windows;
  List.iter (manage_seat ctx) wm.seats
;;

let arrange ctx =
  let wm = Ctx.wm ctx in
  List.iter (manage_output wm) wm.outputs
;;

let publish ctx = Ctx.wm ctx |> Events.publish

let manage (wm : Wm.t) proxy =
  match wm.lifecycle with
  | Pending_exit _ -> Lifecycle.dispatch_pending wm
  | Close_requested -> River.Window_management.River_window_manager_v1.manage_finish proxy
  | Exited -> Log.err @@ fun m -> m "wayland session should have exited..."
  | Running ->
    Fun.protect
      ~finally:(fun () ->
        River.Window_management.River_window_manager_v1.manage_finish proxy)
      (fun () ->
         Exceptions.guard "manage cycle"
         @@ fun () ->
         Ctx.with_manage wm (fun ctx ->
           Focus.layer_shell_sync wm;
           reap ctx;
           admit ctx;
           apply ctx;
           arrange ctx;
           Commit.manage ctx;
           publish ctx))
;;

let render wm proxy =
  Fun.protect
    ~finally:(fun () ->
      River.Window_management.River_window_manager_v1.render_finish proxy)
    (fun () ->
       Exceptions.guard "render cycle"
       @@ fun () -> Ctx.with_render wm (fun ctx -> Commit.render ctx))
;;