let () = let startup_script = if Array.length Sys.argv = 2 then Some Sys.argv.(1) else let default = Filename.concat (Sys.getenv "HOME") ".config/kutu/config.rb" in if Sys.file_exists default then Some default else None in let state = Kutu.State.new_state in print_endline "Started Kutu WM"; Bindings.Core.register_callbacks state; (match startup_script with | Some s -> Mruby.Core.mrb_load_string state.mrb (Mruby.Initial.initial_code s) | None -> Mruby.Core.mrb_load_string state.mrb (Mruby.Initial.initial_code "")); 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 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; (* TODO: check if window wants to be floating and if so float it instead. *) let ws = match Hashtbl.find_opt state.workspaces state.current with | Some ws -> ws | None -> let ws = { Kutu.Layout.ws_root = None; ws_fwindows = [] } in Hashtbl.add state.workspaces state.current ws; ws in ws.ws_root <- Some (Kutu.Layout.insert Kutu.Layout.Horizontal window ws.ws_root); List.iter (fun { Kutu.Layout.wr_window = window; wr_rect = rect } -> Xcb.Window.reshape state.conn window rect) (Kutu.Layout.calculate state.screen ws.ws_root); Hashtbl.replace state.window_workspace window state.current | 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 begin match Hashtbl.find_opt state.window_workspace window with | None -> () | Some ws_name -> let ws = Hashtbl.find state.workspaces ws_name in let new_root, tiled_removed = Kutu.Layout.remove window ws.ws_root in if tiled_removed then ws.ws_root <- new_root else ws.ws_fwindows <- Kutu.Layout.remove_fwindow window ws.ws_fwindows; Hashtbl.remove state.window_workspace window; if ws_name = state.current then List.iter (fun { Kutu.Layout.wr_window = window; wr_rect = rect } -> Xcb.Window.reshape state.conn window rect) (Kutu.Layout.calculate state.screen ws.ws_root) end | _ -> ()); 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"