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.state/output.ml.html

Source file output.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
open! Oxbow_core
include Types.Output

let from_stack o =
  match o.focus_stack with
  | w :: _ when Window.tag_visible w -> Some w
  | stack ->
    let visible_on_tags w =
      Window.tag_visible w && Window.on_tags w ~tags:o.tags.selected
    in
    (match List.find_opt visible_on_tags stack with
     | Some _ as s -> s
     | None -> List.find_opt Window.tag_visible stack)
;;

let focused_window o =
  if o.overview.enabled
  then (
    match o.overview.head with
    | Some w -> Some w
    | None -> from_stack o)
  else from_stack o
;;

let nav_stack o = if o.overview.enabled then o.focus_stack else o.wm_stack
let stack ~rev o = if rev then nav_stack o |> List.rev else nav_stack o

let tiled ~rev =
  Ring.wrapped_search Window.tag_visible (fun w ->
    match w.output with
    | Some o -> stack ~rev o
    | None -> [])
;;

let neighbor ~rev o =
  match focused_window o with
  | None -> None
  | Some f ->
    let rec after = function
      | [ w ] when w == f -> stack ~rev o |> tiled ~rev
      | w :: xs when w == f -> tiled ~rev xs
      | _ :: xs -> after xs
      | [] ->
        (Log.err @@ fun m -> m "focused window isn't in output window list");
        None
    in
    stack ~rev o |> after
;;

let next_window o = neighbor ~rev:false o
let prev_window o = neighbor ~rev:true o
let tag_data o tag = Tag.Table.find o.tag_data tag
let to_tag_data o = tag_data o o.tags.selected
let windows_on_tags o ~tags = List.filter (Window.on_tags ~tags) o.wm_stack
let visible_windows o = List.filter Window.tag_visible o.wm_stack
let visible_window_count o = visible_windows o |> List.length
let tiled_windows o = List.filter Window.is_tiled_on_tag o.wm_stack

let switch_tags ~tags o =
  if not (Tag.Set.is_empty tags || Tag.Set.equal tags o.tags.selected)
  then (
    o.tags.previous <- o.tags.selected;
    o.tags.selected <- tags;
    Schedule.manage ())
;;

let occupied_tags o = Window.occupied_tags o.wm_stack

let urgent_tags o =
  List.fold_left
    (fun s (w : Types.Window.t) -> if w.is_urgent then Tag.Set.union s w.tags else s)
    Tag.Set.empty
    o.wm_stack
;;

let current_layout o = (to_tag_data o).layout
let current_scheme o = (to_tag_data o).tiling.scheme
let at_point ~x ~y = List.find_opt (fun o -> Rect.contains ~x ~y o.geom)

let has_visible_fullscreen o =
  List.exists (fun w -> Window.is_fullscreen w && Window.tag_visible w) o.focus_stack
;;

let is_floating output =
  match output with
  | None -> false
  | Some o -> current_layout o = Floating
;;

let apply_layout (td : Types.Config.Data.t) ~layout = td.layout <- layout
let apply_scheme (td : Types.Config.Data.t) ~scheme = td.tiling.scheme <- scheme

let enter_overview o =
  if not o.overview.enabled
  then (
    o.overview.head <- focused_window o;
    o.overview.offset <- 0;
    o.overview.enabled <- true;
    Schedule.manage ())
;;

let exit_overview o =
  if o.overview.enabled
  then (
    o.overview.head <- None;
    o.overview.enabled <- false;
    Schedule.manage ())
;;

let apply_mfact (td : Types.Config.Data.t) ~(delta : float Delta.t) =
  let params = td.tiling in
  let mfact = Delta.resolve ~add:( +. ) ~current:params.mfact delta in
  params.mfact <- Float.(max 0.05 mfact |> min 0.95)
;;

let apply_nmaster (td : Types.Config.Data.t) ~(delta : int Delta.t) =
  let params = td.tiling in
  let nmaster = Delta.resolve ~add:( + ) ~current:params.nmaster delta in
  params.nmaster <- max 0 nmaster
;;

let apply_gaps_inner (td : Types.Config.Data.t) ~(delta : int Delta.t) =
  let params = td.gaps in
  let gaps_inner = Delta.resolve ~add:( + ) ~current:params.inner delta in
  params.inner <- max 0 gaps_inner
;;

let apply_gaps_outer (td : Types.Config.Data.t) ~(delta : int Delta.t) =
  let params = td.gaps in
  let outer = Delta.resolve ~add:( + ) ~current:params.outer delta in
  params.outer <- max 0 outer
;;

let apply_scrolling_align (td : Types.Config.Data.t) ~align = td.scrolling.align <- align
let apply_scrolling_orientation (td : Types.Config.Data.t) ~dir = td.scrolling.dir <- dir
let apply_tiling_orientation (td : Types.Config.Data.t) ~dir = td.tiling.dir <- dir

let set_gaps_overview o ~(delta : int Delta.t) =
  let gaps = Delta.resolve ~add:( + ) ~current:o.overview.gaps delta in
  o.overview.gaps <- max 0 gaps
;;

let set_overview_head o head = o.overview.head <- head

let set_wm_stack o ws =
  o.wm_stack <- ws;
  Schedule.manage ()
;;

let set_focus_stack o ws = o.focus_stack <- ws

let resolve_tag_arg ~(arg : Tag.Arg.t) o =
  match arg with
  | Concrete s -> s
  | Occupied -> occupied_tags o
;;

let to_vector o = Rect.to_int o.geom |> Vector.center
let matches_name name o = Option.fold ~none:false ~some:(fun s -> s = name) o.name

let resolve_output_logical ~(dir : Direction.Logical.t) (current : t) =
  match dir with
  | Next -> Ring.next_or_first current
  | Prev -> Ring.prev_or_last current
;;

let resolve_output_spatial ~from ~dir (current : t) =
  Vector.nearest_in_direction ~from ~dir (fun o ->
    if o == current then None else Some (to_vector o))
;;

let resolve_output_name name = List.find_opt (matches_name name)
let set_lifecycle o lifecycle = o.lifecycle <- lifecycle
let set_is_captured o is_captured = o.is_captured <- is_captured

let set_usable o usable =
  o.usable <- usable;
  Schedule.manage ()
;;

let set_name o name = o.name <- name

let add_label o label =
  if not @@ List.mem label o.labels
  then o.labels <- label :: o.labels |> List.sort String.compare
;;

let remove_label o label = o.labels <- List.filter (( <> ) label) o.labels
let set_geom o geom = o.geom <- geom
let set_scroll_offset o offset = (to_tag_data o).scrolling.offset <- offset
let apply_default_width td ~delta = Config.set_default_width ~delta td
let apply_float_seed td ~seed = Config.set_float_seed ~seed td

let arranges (window : Types.Window.t) =
  match window.output with
  | None -> false
  | Some o ->
    Window.is_tiled window
    && (not window.float_seed_pending)
    && Option.is_some window.committed.proposed
    && (o.overview.enabled || current_layout o <> Floating)
;;