diff --git a/config.rb b/config.rb index 08ffa36..c720c35 100644 --- a/config.rb +++ b/config.rb @@ -1,20 +1,24 @@ -system 'bash ~/main/ocaml/epq/scripts/startup.sh >/dev/null 2>&1 &' +tmp_src = '@src@' +SRC = if tmp_src == '@src@' + '~/main/ocaml/epq/scripts' + else + tmp_src + end MAX_PROJECTS = 3 SPECIAL = { - term1: { cmd: 'kitty' }, - term2: { cmd: 'kitty' }, + terminal: { cmd: 'kitty' }, browser: { cmd: 'firefox' }, misc: { cmd: nil } } $current = 0 -$p_sub = Array.new(9, 0) +system "bash #{SRC}/startup.sh >/dev/null 2>&1 &" def project_ws(n) - :"p#{n}_#{$p_sub[$current]}" + :"p#{n}" end def go_project(n) @@ -47,11 +51,11 @@ bind 'w' do end bind 'e' do - system 'bash ~/main/ocaml/epq/scripts/power.sh >/dev/null 2>&1 &' + system "bash #{SRC}/power.sh >/dev/null 2>&1 &" end bind 'd' do - system 'bash ~/main/ocaml/epq/scripts/run.sh >/dev/null 2>&1 &' + system "bash #{SRC}/run.sh >/dev/null 2>&1 &" end bind 'v' do @@ -123,12 +127,8 @@ bind 'f' do system 'kitty -e fish -c "btop" >/dev/null 2>&1 &' end -bind '[' do |_, ws| - go_special :term1, ws -end - -bind ']' do |_, ws| - go_special :term2, ws +bind 80, :none do |_, ws| + go_special :terminal, ws end bind 79, :none do |_, ws| @@ -164,11 +164,4 @@ bind 82, :none do |_, ws| go_project(n) end -bind 80, :none do |_, ws| - next unless in_project?(ws) - - $p_sub[$current] = $p_sub[$current] == 1 ? 0 : 1 - go_project($current) -end - go_project(0) diff --git a/src/bindings/window_op.ml b/src/bindings/window_op.ml index 27c600f..afdf903 100644 --- a/src/bindings/window_op.ml +++ b/src/bindings/window_op.ml @@ -34,18 +34,21 @@ let register_toggle_float (state : Kutu.State.wm_state) = 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; _ } -> + match + List.find_opt + (fun { Kutu.Layout.wr_window = w; wr_rect } -> w = window) + windows + with + | Some _ -> 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; + ws.ws_fwindows <- window :: ws.ws_fwindows; Xcb.Window.move_to_top state.conn window; List.iter - (fun { Kutu.Layout.fw_window = window; fw_rect = rect } -> + (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 @@ -59,7 +62,7 @@ let register_toggle_float (state : Kutu.State.wm_state) = Some (Kutu.Layout.insert Kutu.Layout.Horizontal window ws.ws_root); List.iter - (fun { Kutu.Layout.fw_window = window; fw_rect = rect } -> + (fun { Kutu.Layout.wr_window = window; wr_rect = rect } -> Xcb.Window.reshape state.conn window rect) (Kutu.Layout.calculate state.screen ws.ws_root) | None -> @@ -73,3 +76,5 @@ let register_toggle_float (state : Kutu.State.wm_state) = (Mruby.Types.Mrb_state.get_object_class state.mrb) "toggle_float" toggle_float (Mruby.Bindings.mrb_args_req 1) + +(* Add a window moving operation to move between workspaces. *) diff --git a/src/bindings/ws_op.ml b/src/bindings/ws_op.ml index 2542409..d9b3bd6 100644 --- a/src/bindings/ws_op.ml +++ b/src/bindings/ws_op.ml @@ -26,24 +26,22 @@ let register_jump (state : Kutu.State.wm_state) = begin match Hashtbl.find_opt state.workspaces state.current with | Some old_ws -> List.iter - (fun { Kutu.Layout.fw_window = window; fw_rect } -> + (fun { Kutu.Layout.wr_window = window; wr_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) + (fun window -> 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 } -> + (fun { Kutu.Layout.wr_window = window; wr_rect = rect } -> Xcb.Window.map state.conn window; Xcb.Window.reshape state.conn window rect) (Kutu.Layout.calculate state.screen new_ws.ws_root); List.iter - (fun { Kutu.Layout.fw_window = window; fw_rect } -> - Xcb.Window.map state.conn window) + (fun window -> Xcb.Window.map state.conn window) new_ws.ws_fwindows); self in diff --git a/src/kutu/layout.ml b/src/kutu/layout.ml index d0c9fc9..aee9518 100644 --- a/src/kutu/layout.ml +++ b/src/kutu/layout.ml @@ -9,21 +9,24 @@ type layout = layout_r : layout; } -type fwindow = { fw_rect : Decl.Types.rect; fw_window : Xcb.Types.Window.t } +type window_result = { + wr_rect : Decl.Types.rect; + wr_window : Xcb.Types.Window.t; +} type workspace = { mutable ws_root : layout option; - mutable ws_fwindows : fwindow list; + mutable ws_fwindows : Xcb.Types.Window.t 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 + List.find_opt (fun fw -> fw = window) fwindows let remove_fwindow window fwindows = - List.filter (fun fw -> fw.fw_window <> window) fwindows + List.filter (fun fw -> fw <> window) fwindows let flip_direction = function Horizontal -> Vertical | Vertical -> Horizontal @@ -122,7 +125,7 @@ let rec calculate rect = function | Some l -> ( match l with | Leaf { layout_window } -> - [ { fw_rect = rect; fw_window = layout_window } ] + [ { wr_rect = rect; wr_window = layout_window } ] | Split { layout_direction; layout_ratio; layout_l; layout_r } -> let left_rect, right_rect = split_rect rect layout_direction layout_ratio diff --git a/src/main.ml b/src/main.ml index fc141c5..b9a6db0 100644 --- a/src/main.ml +++ b/src/main.ml @@ -16,12 +16,8 @@ let () = (match startup_script with | Some s -> - print_string s; - print_endline " : Have something"; Mruby.Core.mrb_load_string state.mrb (Mruby.Initial.initial_code s) - | None -> - print_endline "Nothing"; - Mruby.Core.mrb_load_string state.mrb (Mruby.Initial.initial_code "")); + | 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; @@ -44,6 +40,7 @@ let () = 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 @@ -55,7 +52,7 @@ let () = 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 } -> + (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 @@ -89,7 +86,7 @@ let () = Hashtbl.remove state.window_workspace window; if ws_name = state.current then List.iter - (fun { Kutu.Layout.fw_window = window; fw_rect = rect } -> + (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 diff --git a/src/shims.c b/src/shims.c index 355aaf5..d59e54a 100644 --- a/src/shims.c +++ b/src/shims.c @@ -4,6 +4,8 @@ #include #include #include +#include +#include mrb_value kutu_mrb_int_value(mrb_state *mrb, uint32_t value) { return mrb_int_value(mrb, (mrb_int)value); @@ -22,3 +24,45 @@ void kutu_mrb_load_file(mrb_state *mrb, const char *filename) { mrb_load_file(mrb, file); fclose(file); } + +xcb_size_hints_t kutu_wm_n_hints(xcb_connection_t *conn, xcb_window_t win) { + xcb_size_hints_t hints; + xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_normal_hints(conn, win); + if (!xcb_icccm_get_wm_normal_hints_reply(conn, cookie, &hints, NULL)) + return (xcb_size_hints_t){0}; + return hints; +} + +xcb_icccm_wm_hints_t kutu_wm_hints(xcb_connection_t *conn, xcb_window_t win) { + xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_hints(conn, win); + xcb_icccm_wm_hints_t hints; + xcb_icccm_get_wm_hints_reply(conn, cookie, &hints, NULL); + return hints; +} + +char *kutu_wm_name(xcb_connection_t *conn, xcb_window_t win) { + xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_name(conn, win); + xcb_icccm_get_text_property_reply_t reply; + xcb_icccm_get_wm_name_reply(conn, cookie, &reply, NULL); + return reply.name; +} + +uint8_t kutu_wm_transient_for(xcb_connection_t *conn, xcb_window_t win) { + xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_transient_for(conn, win); + return xcb_icccm_get_wm_transient_for_reply(conn, cookie, &win, NULL); +} + +void kutu_set_wm_state(xcb_connection_t *conn, xcb_window_t win, int state) { + xcb_intern_atom_cookie_t cookie = + xcb_intern_atom(conn, 0, strlen("WM_STATE"), "WM_STATE"); + xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, cookie, NULL); + if (!reply) + return; + xcb_atom_t WM_STATE = reply->atom; + free(reply); + uint32_t data[2]; + data[0] = state; + data[1] = XCB_WINDOW_NONE; + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win, WM_STATE, WM_STATE, 32, + 2, data); +} diff --git a/src/xcb/types.ml b/src/xcb/types.ml index 8575f8e..7d4d1e1 100644 --- a/src/xcb/types.ml +++ b/src/xcb/types.ml @@ -228,6 +228,31 @@ module Screen_iterator = struct let screen ptr = !@(getf ptr data) end +module Size_hints = struct + type t + + let typ : t structure typ = structure "xcb_size_hints_t" + let flags = field typ "flags" uint32_t + let x = field typ "x" int32_t + let y = field typ "y" int32_t + let width = field typ "width" int32_t + let height = field typ "height" int32_t + let min_width = field typ "min_width" int32_t + let min_height = field typ "min_height" int32_t + let max_width = field typ "max_width" int32_t + let max_height = field typ "max_height" int32_t + let width_inc = field typ "width_inc" int32_t + let height_inc = field typ "height_inc" int32_t + let min_aspect_num = field typ "min_aspect_num" int32_t + let min_aspect_den = field typ "min_aspect_den" int32_t + let max_aspect_num = field typ "max_aspect_num" int32_t + let max_aspect_den = field typ "max_aspect_den" int32_t + let base_width = field typ "base_width" int32_t + let base_height = field typ "base_height" int32_t + let win_gravity = field typ "win_gravity" uint32_t + let () = seal typ +end + (* TODO: convert all these: /* Opcode for xcb_create_notify. */ /** diff --git a/src/xcb/window.ml b/src/xcb/window.ml index 2bcb2cf..a830590 100644 --- a/src/xcb/window.ml +++ b/src/xcb/window.ml @@ -132,6 +132,77 @@ let focus conn window = in Error.check conn cookie +let _xcb_wm_n_hints = + foreign "kutu_wm_n_hints" + (ptr Types.Connection.typ @-> Types.Window.typ + @-> returning Types.Size_hints.typ) + +let has_flag flags flag = + Unsigned.UInt32.logand flags (Unsigned.UInt32.of_int flag) + <> Unsigned.UInt32.zero + +let p_size = 1 lsl 3 +let p_min_size = 1 lsl 4 +let p_max_size = 1 lsl 5 +let p_resize_inc = 1 lsl 6 +let p_aspect = 1 lsl 7 + +let make_window conn window = + let hints = _xcb_wm_n_hints conn window in + let flags = getf hints Types.Size_hints.flags in + let has_min = has_flag flags p_min_size in + let has_size = has_flag flags p_size in + let has_max = has_flag flags p_max_size in + let has_aspect = has_flag flags p_aspect in + let size = + if has_size then + Some + (getf hints Types.Size_hints.width, getf hints Types.Size_hints.height) + else None + in + let min = + if has_min then + Some + ( getf hints Types.Size_hints.min_width, + getf hints Types.Size_hints.min_height ) + else None + in + let max = + if has_max then + Some + ( getf hints Types.Size_hints.max_width, + getf hints Types.Size_hints.max_height ) + else None + in + let fixed_size = + match (size, min, max) with + | Some size, _, _ -> Some size + | _, Some min, _ -> Some min + | _, _, Some max -> Some max + | _ -> None + in + let fixed_aspect = + if has_aspect then + let min_num = getf hints Types.Size_hints.min_aspect_num in + let min_den = getf hints Types.Size_hints.min_aspect_den in + let max_num = getf hints Types.Size_hints.max_aspect_num in + let max_den = getf hints Types.Size_hints.max_aspect_den in + if min_den <> Int32.zero then + Some + ( Int32.div (Int32.mul (Int32.of_int 100) min_num) min_den, + Int32.of_int 100 ) + else if max_den <> Int32.zero then + Some + ( Int32.div (Int32.mul (Int32.of_int 100) max_num) max_den, + Int32.of_int 100 ) + else None + else None + in + match (fixed_size, fixed_aspect) with + | Some (x, y), _ -> Some (x, y) + | _, Some (x, y) -> Some (x, y) + | _ -> None + let _xcb_kill_client = foreign "xcb_kill_client" (ptr Types.Connection.typ @-> Types.Window.typ