diff --git a/config.rb b/config.rb new file mode 100644 index 0000000..e74a09d --- /dev/null +++ b/config.rb @@ -0,0 +1,130 @@ +# ==== State ==== + +MAX_PROJECTS = 9 +SUBS = 2 # workspaces per project + +$current_project = 1 # 1..MAX_PROJECTS +$current_sub = 0 # 0..SUBS-1 + +# For each special workspace, remembers which workspace you were on +# before you jumped into it -- so hitting the mode key again toggles back. +$special_origin = {} + +SPECIAL = { + terminal: { cmd: "kitty" }, + browser: { cmd: "firefox" }, + music: { cmd: "spotify" }, + misc: { cmd: nil }, # doesn't start anything + todo: { cmd: nil }, # doesn't start anything +} + +# ==== Helpers ==== + +def project_ws(n, sub) + :"p#{n}_#{sub}" +end + +def running?(process) + system("pgrep -x #{process} > /dev/null 2>&1") +end + +def go_project(n, sub) + $current_project = n + $current_sub = sub + jump_ws project_ws(n, sub) +end + +def in_project?(ws) + !SPECIAL.key?(ws) +end + +# Toggle between a special-mode workspace (terminal/browser/music/misc/todo) +# and whatever workspace you were last on. Starts the associated app if +# it isn't already running. `ws` is the current workspace, passed in by +# the bind block (bind gives us (window, current_ws)). +def go_special(name, ws) + cfg = SPECIAL.fetch(name) + + if ws == name + target = $special_origin[name] || project_ws($current_project, $current_sub) + jump_ws target + else + $special_origin[name] = ws + jump_ws name + system("#{cfg[:cmd]} >/dev/null 2>&1 &") if cfg[:cmd] && !running?(cfg[:cmd]) + end +end + +# ==== Untouched bindings ==== + +bind ?q do |x| + kill x +end + +bind ?w do + system "kitty >/dev/null 2>&1 &" +end + +bind ?e do + exit +end + +bind ?f do |x| + toggle_float x +end + +# ==== Mode switches ==== + +bind ?[ do |_, ws| + go_special :terminal, ws +end + +bind ?] do |_, ws| + go_special :misc, ws +end + +bind "tab" do |_, ws| + go_special :browser, ws +end + +bind 89 do |_, ws| + go_special :music, ws +end + +bind 81 do |_, ws| + go_special :todo, ws +end + +# ==== Project navigation ==== + +(1..MAX_PROJECTS).each do |n| + bind n.to_s do + go_project(n, $current_sub) + end +end + +bind 86 do |_, ws| + next unless in_project?(ws) + n = (($current_project - 2) % MAX_PROJECTS) + 1 + go_project(n, $current_sub) +end + +bind 82 do |_, ws| + next unless in_project?(ws) + n = ($current_project % MAX_PROJECTS) + 1 + go_project(n, $current_sub) +end + +bind 79 do |_, ws| + next unless in_project?(ws) + go_project($current_project, ($current_sub + 1) % SUBS) +end + +bind 80 do |_, ws| + next unless in_project?(ws) + go_project($current_project, ($current_sub - 1 + SUBS) % SUBS) +end + +# ==== Startup ==== + +go_project(1, 0) diff --git a/flake.nix b/flake.nix index 357cb16..b2036e2 100644 --- a/flake.nix +++ b/flake.nix @@ -62,7 +62,7 @@ set -e if [ -z "$DISPLAY" ]; then exec ${pkgs.xinit}/bin/startx \ - ${kutu}/bin/kutu \ + ${kutu}/bin/kutu "$@" \ -- \ ${pkgs.xorg-server}/bin/X else @@ -76,7 +76,7 @@ cleanup() { kill "$XEPHYR_PID" 2>/dev/null || true; } trap cleanup EXIT INT TERM sleep 1 - DISPLAY=$DISPLAY_NUM ${kutu}/bin/kutu + DISPLAY=$DISPLAY_NUM ${kutu}/bin/kutu "$@" echo "Returned: $?" fi ''; diff --git a/src/bindings/core.ml b/src/bindings/core.ml index 2a09b9c..7bdc439 100644 --- a/src/bindings/core.ml +++ b/src/bindings/core.ml @@ -15,8 +15,6 @@ let register_callbacks state = register_exit state; Window_op.register_kill state; Window_op.register_toggle_float state; - Ws_op.register_new state; - Ws_op.register_remove state; Ws_op.register_jump state; Ws_op.register_ws_count state; Keybinds.register_bind state; diff --git a/src/bindings/keybinds.ml b/src/bindings/keybinds.ml index bcfa06b..5a3ee1c 100644 --- a/src/bindings/keybinds.ml +++ b/src/bindings/keybinds.ml @@ -73,7 +73,10 @@ let dispatch_keybind mrb hashtbl key modifier value1 value2 = | None -> () | Some block -> let arg1 = Mruby.Bindings.mrb_int_value mrb value1 in - let arg2 = Mruby.Bindings.mrb_int_value mrb value2 in + let arg2 = + Mruby.Bindings.mrb_intern_cstr mrb value2 + |> Mruby.Bindings.mrb_symbol_value + in let argv = CArray.of_list Mruby.Types.Mrb_value.typ [ arg1; arg2 ] in ignore (Mruby.Bindings.mrb_funcall_argv mrb block diff --git a/src/bindings/window_op.ml b/src/bindings/window_op.ml index 9b5a8de..27c600f 100644 --- a/src/bindings/window_op.ml +++ b/src/bindings/window_op.ml @@ -31,35 +31,42 @@ let register_toggle_float (state : Kutu.State.wm_state) = let win_id = allocate int64_t 0L in ignore (mrb_get_args mrb "i" win_id); let window = Unsigned.UInt32.of_int64 !@win_id in - let ws = List.nth state.workspaces state.current in - let windows = Kutu.Layout.calculate state.screen ws.ws_root in - (match Kutu.Layout.find_fwindow window windows with - | Some { fw_rect; _ } -> - begin match Kutu.Layout.find_fwindow window ws.ws_fwindows with - | Some _ -> print_endline "Error: window already floating" + begin match Hashtbl.find_opt state.workspaces state.current with + | Some ws -> ( + let windows = Kutu.Layout.calculate state.screen ws.ws_root in + match Kutu.Layout.find_fwindow window windows with + | Some { fw_rect; _ } -> + begin match Kutu.Layout.find_fwindow window ws.ws_fwindows with + | Some _ -> print_endline "Error: window already floating" + | None -> + let new_root, _ = Kutu.Layout.remove window ws.ws_root in + ws.ws_root <- new_root; + ws.ws_fwindows <- + { fw_rect; fw_window = window } :: ws.ws_fwindows; + Xcb.Window.move_to_top state.conn window; + 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) + end | None -> - let new_root, _ = Kutu.Layout.remove window ws.ws_root in - ws.ws_root <- new_root; - ws.ws_fwindows <- { fw_rect; fw_window = window } :: ws.ws_fwindows; - Xcb.Window.move_to_top state.conn window; - 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) - end - | None -> - begin match Kutu.Layout.find_fwindow window ws.ws_fwindows with - | Some _ -> - ws.ws_fwindows <- Kutu.Layout.remove_fwindow window ws.ws_fwindows; - Xcb.Window.move_to_bottom state.conn window; - 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) - | None -> print_endline "Error: window is neither tiled nor floating" - end); + begin match Kutu.Layout.find_fwindow window ws.ws_fwindows with + | Some _ -> + ws.ws_fwindows <- + Kutu.Layout.remove_fwindow window ws.ws_fwindows; + Xcb.Window.move_to_bottom state.conn window; + ws.ws_root <- + Some + (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) + | None -> + print_endline "Error: window is neither tiled nor floating" + end) + | None -> () + end; self in Mruby.Bindings.mrb_define_method state.mrb diff --git a/src/bindings/ws_op.ml b/src/bindings/ws_op.ml index 65f2bbf..2c4a0f3 100644 --- a/src/bindings/ws_op.ml +++ b/src/bindings/ws_op.ml @@ -1,98 +1,41 @@ open Ctypes open Foreign -let register_new (state : Kutu.State.wm_state) = - let new_ws (mrb : Mruby.Types.Mrb_state.t structure ptr) - (self : Mruby.Types.Mrb_value.t structure) = - let old_ws = List.nth state.workspaces state.current in - state.workspaces <- - List.append state.workspaces [ { ws_root = Nothing; ws_fwindows = [] } ]; - state.current <- List.length state.workspaces - 1; - List.iter - (fun { Kutu.Layout.fw_window = window; fw_rect } -> - Xcb.Window.unmap state.conn window) - (Kutu.Layout.calculate state.screen old_ws.ws_root); - List.iter - (fun { Kutu.Layout.fw_window = window; fw_rect } -> - Xcb.Window.unmap state.conn window) - old_ws.ws_fwindows; - self - in - Mruby.Bindings.mrb_define_method state.mrb - (Mruby.Types.Mrb_state.get_object_class state.mrb) - "new_ws" new_ws (Unsigned.UInt32.of_int 0) - -let rec remove_at index = function - | [] -> [] - | _ :: rest when index = 0 -> rest - | x :: rest -> x :: remove_at (index - 1) rest - -let register_remove (state : Kutu.State.wm_state) = - let mrb_get_args = - foreign "mrb_get_args" - (ptr Mruby.Types.Mrb_state.typ - @-> string @-> ptr int64_t @-> returning int) - in - let remove_ws (mrb : Mruby.Types.Mrb_state.t structure ptr) - (self : Mruby.Types.Mrb_value.t structure) = - let ws_number = allocate int64_t 0L in - ignore (mrb_get_args mrb "i" ws_number); - let ws_number = Signed.Int64.to_int !@ws_number in - let total = List.length state.workspaces in - if total > 1 && ws_number < total && ws_number >= 0 then ( - let dest_idx = if ws_number > 0 then ws_number - 1 else 1 in - let removed = List.nth state.workspaces ws_number in - let dest = List.nth state.workspaces dest_idx in - dest.ws_fwindows <- dest.ws_fwindows @ removed.ws_fwindows; - List.iter - (fun { Kutu.Layout.fw_window = window; fw_rect } -> - dest.ws_root <- Kutu.Layout.insert Horizontal window dest.ws_root; - Xcb.Window.unmap state.conn window) - (Kutu.Layout.calculate state.screen removed.ws_root); - state.workspaces <- remove_at ws_number state.workspaces; - if ws_number = state.current then - state.current <- (if ws_number > 0 then ws_number - 1 else 0) - else if ws_number > state.current then state.current <- state.current - 1; - List.iter - (fun { Kutu.Layout.fw_window = window; fw_rect = rect } -> - Xcb.Window.map state.conn window; - Xcb.Window.reshape state.conn window rect) - (Kutu.Layout.calculate state.screen dest.ws_root); - List.iter - (fun { Kutu.Layout.fw_window = window; fw_rect } -> - Xcb.Window.map state.conn window) - dest.ws_fwindows); - self - in - Mruby.Bindings.mrb_define_method state.mrb - (Mruby.Types.Mrb_state.get_object_class state.mrb) - "remove_ws" remove_ws - (Mruby.Bindings.mrb_args_req 1) - let register_jump (state : Kutu.State.wm_state) = let mrb_get_args = foreign "mrb_get_args" (ptr Mruby.Types.Mrb_state.typ - @-> string @-> ptr int64_t @-> returning int) + @-> string + @-> ptr Mruby.Types.Mrb_sym.typ + @-> returning int) in let jump_ws (mrb : Mruby.Types.Mrb_state.t structure ptr) (self : Mruby.Types.Mrb_value.t structure) = - let ws_number = allocate int64_t 0L in - ignore (mrb_get_args mrb "i" ws_number); - let ws_number = Signed.Int64.to_int !@ws_number in - let total = List.length state.workspaces in - if ws_number < total && ws_number >= 0 && ws_number <> state.current then ( - let old_ws = List.nth state.workspaces state.current in - let new_ws = List.nth state.workspaces ws_number in - state.current <- ws_number; - List.iter - (fun { Kutu.Layout.fw_window = window; fw_rect } -> - Xcb.Window.unmap state.conn window) - (Kutu.Layout.calculate state.screen old_ws.ws_root); - List.iter - (fun { Kutu.Layout.fw_window = window; fw_rect } -> - Xcb.Window.unmap state.conn window) - old_ws.ws_fwindows; + let name = allocate Mruby.Types.Mrb_sym.typ (Unsigned.UInt32.of_int 0) in + ignore (mrb_get_args mrb "n" name); + let name = Mruby.Bindings.mrb_sym_name mrb !@name in + let new_ws = + match Hashtbl.find_opt state.workspaces name with + | Some ws -> ws + | None -> + let ws = { Kutu.Layout.ws_root = None; ws_fwindows = [] } in + Hashtbl.add state.workspaces name ws; + ws + in + if state.current <> name then ( + begin match Hashtbl.find_opt state.workspaces state.current with + | Some old_ws -> + List.iter + (fun { Kutu.Layout.fw_window = window; fw_rect } -> + Xcb.Window.unmap state.conn window) + (Kutu.Layout.calculate state.screen old_ws.ws_root); + List.iter + (fun { Kutu.Layout.fw_window = window; fw_rect } -> + Xcb.Window.unmap state.conn window) + old_ws.ws_fwindows + | None -> () + end; + state.current <- name; List.iter (fun { Kutu.Layout.fw_window = window; fw_rect = rect } -> Xcb.Window.map state.conn window; @@ -113,7 +56,7 @@ let register_ws_count (state : Kutu.State.wm_state) = let ws_count (mrb : Mruby.Types.Mrb_state.t structure ptr) (_ : Mruby.Types.Mrb_value.t structure) = Mruby.Bindings.mrb_int_value mrb - (List.length state.workspaces |> Unsigned.UInt32.of_int) + (Hashtbl.length state.workspaces |> Unsigned.UInt32.of_int) in Mruby.Bindings.mrb_define_method state.mrb (Mruby.Types.Mrb_state.get_object_class state.mrb) diff --git a/src/kutu/layout.ml b/src/kutu/layout.ml index 49fd30d..d0c9fc9 100644 --- a/src/kutu/layout.ml +++ b/src/kutu/layout.ml @@ -1,7 +1,6 @@ type direction = Horizontal | Vertical type layout = - | Nothing | Leaf of { layout_window : Xcb.Types.Window.t } | Split of { layout_direction : direction; @@ -13,10 +12,13 @@ type layout = type fwindow = { fw_rect : Decl.Types.rect; fw_window : Xcb.Types.Window.t } type workspace = { - mutable ws_root : layout; + mutable ws_root : layout option; mutable ws_fwindows : fwindow list; } +let empty_workspace () = { ws_root = None; ws_fwindows = [] } +let is_empty_workspace ws = ws.ws_root = None && ws.ws_fwindows = [] + let find_fwindow window fwindows = List.find_opt (fun fw -> fw.fw_window = window) fwindows @@ -26,39 +28,51 @@ let remove_fwindow window fwindows = let flip_direction = function Horizontal -> Vertical | Vertical -> Horizontal let rec insert direction window = function - | Nothing -> Leaf { layout_window = window } - | Leaf { layout_window = existing } -> - Split - { - layout_direction = direction; - layout_ratio = 0.5; - layout_l = Leaf { layout_window = existing }; - layout_r = Leaf { layout_window = window }; - } - | Split { layout_direction; layout_ratio; layout_l; layout_r } -> - Split - { - layout_direction; - layout_ratio; - layout_l; - layout_r = insert (flip_direction layout_direction) window layout_r; - } + | None -> Leaf { layout_window = window } + | Some l -> ( + match l with + | Leaf { layout_window = existing } -> + Split + { + layout_direction = direction; + layout_ratio = 0.5; + layout_l = Leaf { layout_window = existing }; + layout_r = Leaf { layout_window = window }; + } + | Split { layout_direction; layout_ratio; layout_l; layout_r } -> + Split + { + layout_direction; + layout_ratio; + layout_l; + layout_r = + insert (flip_direction layout_direction) window (Some layout_r); + }) let rec remove window = function - | Nothing -> (Nothing, false) - | Leaf { layout_window = existing } -> - if existing = window then (Nothing, true) - else (Leaf { layout_window = existing }, false) - | Split { layout_direction; layout_ratio; layout_l; layout_r } -> ( - let l', l_removed = remove window layout_l in - let r', r_removed = remove window layout_r in - let removed = l_removed || r_removed in - match (l', r') with - | Nothing, r -> (r, removed) - | l, Nothing -> (l, removed) - | l, r -> - ( Split { layout_direction; layout_ratio; layout_l = l; layout_r = r }, - removed )) + | None -> (None, false) + | Some l -> ( + match l with + | Leaf { layout_window = existing } -> + if existing = window then (None, true) + else (Some (Leaf { layout_window = existing }), false) + | Split { layout_direction; layout_ratio; layout_l; layout_r } -> ( + let l', l_removed = remove window (Some layout_l) in + let r', r_removed = remove window (Some layout_r) in + let removed = l_removed || r_removed in + match (l', r') with + | None, r -> (r, removed) + | l, None -> (l, removed) + | Some l, Some r -> + ( Some + (Split + { + layout_direction; + layout_ratio; + layout_l = l; + layout_r = r; + }), + removed ))) let split_rect (rect : Decl.Types.rect) direction ratio = match direction with @@ -104,12 +118,15 @@ let split_rect (rect : Decl.Types.rect) direction ratio = (top, bottom) let rec calculate rect = function - | Nothing -> [] - | Leaf { layout_window } -> [ { fw_rect = rect; fw_window = layout_window } ] - | Split { layout_direction; layout_ratio; layout_l; layout_r } -> - let left_rect, right_rect = - split_rect rect layout_direction layout_ratio - in - let left_windows = calculate left_rect layout_l in - let right_windows = calculate right_rect layout_r in - left_windows @ right_windows + | None -> [] + | Some l -> ( + match l with + | Leaf { layout_window } -> + [ { fw_rect = rect; fw_window = layout_window } ] + | Split { layout_direction; layout_ratio; layout_l; layout_r } -> + let left_rect, right_rect = + split_rect rect layout_direction layout_ratio + in + let left_windows = calculate left_rect (Some layout_l) in + let right_windows = calculate right_rect (Some layout_r) in + left_windows @ right_windows) diff --git a/src/kutu/state.ml b/src/kutu/state.ml index 11b60f2..a2d8d26 100644 --- a/src/kutu/state.ml +++ b/src/kutu/state.ml @@ -4,8 +4,9 @@ type wm_state = { mrb : Mruby.Types.Mrb_state.mrb_ptr; root : Xcb.Types.Window.t; mutable focus : Xcb.Types.Window.t; - mutable workspaces : Layout.workspace list; - mutable current : int; + mutable current : string; + workspaces : (string, Layout.workspace) Hashtbl.t; + window_workspace : (Xcb.Types.Window.t, string) Hashtbl.t; screen : Decl.Types.rect; blocks : (int64, Mruby.Types.Mrb_value.t Ctypes.structure) Hashtbl.t; } @@ -21,9 +22,9 @@ let new_state = mrb; root; focus = root; - workspaces = - [ { Layout.ws_root = Layout.Nothing; Layout.ws_fwindows = [] } ]; - current = 0; + current = "default"; + workspaces = Hashtbl.create 16; + window_workspace = Hashtbl.create 16; screen = Xcb.Screen_iterator.screen_rect conn; blocks = Hashtbl.create 16; } diff --git a/src/main.ml b/src/main.ml index ebb7b5f..032d111 100644 --- a/src/main.ml +++ b/src/main.ml @@ -1,4 +1,10 @@ let () = + let startup_script = + if Array.length Sys.argv <> 2 then ( + Printf.eprintf "usage: kutu \n"; + exit 1) + else Sys.argv.(1) + in let state = Kutu.State.new_state in print_endline "Started Kutu WM"; @@ -18,59 +24,39 @@ let () = "e" => 26, "r" => 27, "f" => 41, - "n" => 57, "b" => 56, "m" => 58, "v" => 55, + "]" => 35, + "[" => 34, + "1" => 10, + "2" => 11, + "3" => 12, + "4" => 13, + "5" => 14, + "6" => 15, + "7" => 16, + "8" => 17, + "9" => 18, + "0" => 19 } def bind(key, mod = :alt, &block) - key = KEY_MAP[key] + key_ = key.is_a?(String) ? KEY_MAP[key] : key mod = MOD_MAP[mod] - raise "unknown key" unless key + raise "unknown key #{key.to_s}" unless key_ raise "unknown modifier" unless mod - _bind key, mod, &block + _bind key_, mod, &block end def unbind(key, mod = :alt) - key = KEY_MAP[key] + key_ = key.is_a?(String) ? KEY_MAP[key] : key mod = MOD_MAP[mod] - raise "unknown key" unless key + raise "unknown key #{key.to_s}" 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 + _unbind key_, mod end |}; + Mruby.Core.mrb_load_file state.mrb startup_script; Mruby.Core.error_check state.mrb; if Xcb.Connection.flush state.conn <= 0 then exit 1; @@ -85,8 +71,7 @@ let () = 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) + 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 @@ -94,13 +79,21 @@ let () = 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 + 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 <- - Kutu.Layout.insert Kutu.Layout.Horizontal window ws.ws_root; + Some (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) + (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 @@ -117,17 +110,24 @@ let () = | 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) + 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.fw_window = window; fw_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; diff --git a/src/mruby/bindings.ml b/src/mruby/bindings.ml index b0a9fb9..06fe824 100644 --- a/src/mruby/bindings.ml +++ b/src/mruby/bindings.ml @@ -34,8 +34,16 @@ let mrb_intern_cstr = let call_sym mrb = mrb_intern_cstr mrb "call" +let mrb_symbol_value = + foreign "kutu_mrb_symbol_value" + (Types.Mrb_sym.typ @-> returning Types.Mrb_value.typ) + let mrb_funcall_argv = foreign "mrb_funcall_argv" (ptr Types.Mrb_state.typ @-> Types.Mrb_value.typ @-> Types.Mrb_sym.typ @-> int64_t @-> ptr Types.Mrb_value.typ @-> returning Types.Mrb_value.typ) + +let mrb_sym_name = + foreign "mrb_sym_name" + (ptr Types.Mrb_state.typ @-> Types.Mrb_sym.typ @-> returning string) diff --git a/src/mruby/core.ml b/src/mruby/core.ml index 4805eea..d34ef8c 100644 --- a/src/mruby/core.ml +++ b/src/mruby/core.ml @@ -12,6 +12,10 @@ let mrb_load_string = foreign "mrb_load_string" (ptr Types.Mrb_state.typ @-> string @-> returning void) +let mrb_load_file = + foreign "kutu_mrb_load_file" + (ptr Types.Mrb_state.typ @-> string @-> returning void) + let error_check mrb_ptr = if Types.Mrb_state.has_error mrb_ptr then begin mrb_print_error mrb_ptr; diff --git a/src/shims.c b/src/shims.c index 7a17151..f25aa02 100644 --- a/src/shims.c +++ b/src/shims.c @@ -1,9 +1,30 @@ #include +#include #include #include +#include mrb_value kutu_mrb_int_value(mrb_state *mrb, uint64_t value) { return mrb_int_value(mrb, (mrb_int)value); } + +mrb_value +kutu_mrb_symbol_value(mrb_sym i) +{ + return mrb_symbol_value(i); +} + +void +kutu_mrb_load_file(mrb_state *mrb, const char *filename) +{ + FILE *file = fopen(filename, "rb"); + if (file == NULL) { + mrb_raisef(mrb, E_RUNTIME_ERROR, + "could not open file: %s", filename); + return; + } + mrb_load_file(mrb, file); + fclose(file); +}