let () = let state = Kutu.State.new_state in print_endline "Started Kutu WM"; Bindings.Core.register_callbacks state; Mruby.Core.mrb_load_string state.mrb {|#ruby MOD_MAP = { none: 0, alt: 8, super: 64 } KEY_MAP = { "tab" => 23, "q" => 24, "w" => 25, "e" => 26, "r" => 27, "f" => 41, "n" => 57, "b" => 56, "m" => 58, "v" => 55, } def bind(key, mod = :alt, &block) key = KEY_MAP[key] mod = MOD_MAP[mod] raise "unknown key" unless key raise "unknown modifier" unless mod _bind key, mod, &block end def unbind(key, mod = :alt) key = KEY_MAP[key] mod = MOD_MAP[mod] raise "unknown key" unless key raise "unknown modifier" unless mod _unbind key, mod end bind "tab" do system "firefox >/dev/null 2>&1 &" end bind ?q do |x| kill x end bind ?w do system "kitty >/dev/null 2>&1 &" end bind ?e do exit end bind ?r do unbind ?w end bind ?f do |x| toggle_float x end bind ?v do |_, x| remove_ws x end bind ?b do |_, x| jump_ws ((x - 1 + ws_count) % ws_count) end bind ?n do |_, x| jump_ws ((x + 1) % ws_count) end bind ?m do new_ws end |}; Mruby.Core.error_check state.mrb; if Xcb.Connection.flush state.conn <= 0 then exit 1; while state.running do (match Xcb.Event.next state.conn with | None -> () | Some ev -> (match Xcb.Event.rtype ev with | KeyPress -> let req = Xcb.Types.Events.Key.from ev in let key = Xcb.Types.Events.Key.detail req in let modifier = Xcb.Types.Events.Key.state req in Bindings.Keybinds.dispatch_keybind state.mrb state.blocks key modifier state.focus (Unsigned.UInt32.of_int state.current) | MapRequest -> let req = Xcb.Types.Events.Map_request.from ev in let window = Xcb.Types.Events.Map_request.window req in Xcb.Window.map state.conn window; Xcb.Window.focus state.conn window; Xcb.Window.move_to_bottom state.conn window; state.focus <- window; let ws = List.nth state.workspaces state.current in ws.ws_root <- Kutu.Layout.insert Kutu.Layout.Horizontal window ws.ws_root; List.iter (fun { Kutu.Layout.fw_window = window; fw_rect = rect } -> Xcb.Window.reshape state.conn window rect) (Kutu.Layout.calculate state.screen ws.ws_root) | Create -> let req = Xcb.Types.Events.Create.from ev in let window = Xcb.Types.Events.Create.window req in let override_ridirect = Xcb.Types.Events.Create.override_redirect req in if override_ridirect == Unsigned.UInt8.of_int 0 then Xcb.Window.setup_window state.conn window | Enter -> let req = Xcb.Types.Events.Enter.from ev in let window = Xcb.Types.Events.Enter.window req in state.focus <- window; Xcb.Window.focus state.conn window | Destroy -> let req = Xcb.Types.Events.Destroy.from ev in let window = Xcb.Types.Events.Destroy.window req in let ws = List.nth state.workspaces state.current in let new_root, removed = Kutu.Layout.remove window ws.ws_root in if removed then ws.ws_root <- new_root else ws.ws_fwindows <- Kutu.Layout.remove_fwindow window ws.ws_fwindows; Xcb.Window.focus state.conn state.root; state.focus <- state.root; List.iter (fun { Kutu.Layout.fw_window = window; fw_rect = rect } -> Xcb.Window.reshape state.conn window rect) (Kutu.Layout.calculate state.screen ws.ws_root) | _ -> ()); Xcb.Utils.free ev); Mruby.Core.error_check state.mrb; if Xcb.Connection.flush state.conn <= 0 then exit 1; Unix.sleepf 0.01 done; Bindings.Keybinds.cleanup state.mrb state.blocks; Mruby.Core.mrb_close state.mrb; Xcb.Connection.disconnect state.conn; print_endline "Closing up Kutu WM"