From 1efd5f819f9986bf27e390f4988359388606cea0 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sat, 11 Nov 2017 14:41:18 -0500 Subject: Wire up output frame loop --- sway/commands/move.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sway/commands/move.c') diff --git a/sway/commands/move.c b/sway/commands/move.c index 8d89f2ef..52c73e22 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -1,3 +1,4 @@ +#define _POSIX_C_SOURCE 200809L #include #include #include -- cgit v1.2.3 From 733993a651c71f7e2198d505960d6bbd31e0e107 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sat, 18 Nov 2017 11:22:02 -0500 Subject: Move everything to sway/old/ --- CMakeLists.txt | 12 +- common/log.c | 2 +- include/sway.h | 6 - include/sway/border.h | 28 - include/sway/commands.h | 214 --- include/sway/config.h | 406 ----- include/sway/container.h | 362 ----- include/sway/criteria.h | 42 - include/sway/focus.h | 45 - include/sway/handlers.h | 11 - include/sway/input.h | 24 - include/sway/input_state.h | 102 -- include/sway/ipc-json.h | 15 - include/sway/ipc-server.h | 41 - include/sway/layout.h | 85 - include/sway/old/border.h | 28 + include/sway/old/commands.h | 214 +++ include/sway/old/config.h | 406 +++++ include/sway/old/container.h | 362 +++++ include/sway/old/criteria.h | 42 + include/sway/old/focus.h | 45 + include/sway/old/input.h | 24 + include/sway/old/input_state.h | 102 ++ include/sway/old/ipc-json.h | 15 + include/sway/old/ipc-server.h | 33 + include/sway/old/layout.h | 85 + include/sway/old/output.h | 36 + include/sway/old/workspace.h | 22 + include/sway/output.h | 22 +- include/sway/workspace.h | 22 - sway/CMakeLists.txt | 27 - sway/border.c | 510 ------ sway/commands.c | 686 -------- sway/commands/assign.c | 57 - sway/commands/bar.c | 59 - sway/commands/bar/activate_button.c | 26 - sway/commands/bar/binding_mode_indicator.c | 27 - sway/commands/bar/bindsym.c | 48 - sway/commands/bar/colors.c | 129 -- sway/commands/bar/context_button.c | 26 - sway/commands/bar/font.c | 26 - sway/commands/bar/height.c | 21 - sway/commands/bar/hidden_state.c | 79 - sway/commands/bar/icon_theme.c | 25 - sway/commands/bar/id.c | 33 - sway/commands/bar/mode.c | 81 - sway/commands/bar/modifier.c | 35 - sway/commands/bar/output.c | 50 - sway/commands/bar/pango_markup.c | 27 - sway/commands/bar/position.c | 33 - sway/commands/bar/secondary_button.c | 26 - sway/commands/bar/separator_symbol.c | 21 - sway/commands/bar/status_command.c | 21 - sway/commands/bar/strip_workspace_numbers.c | 27 - sway/commands/bar/swaybar_command.c | 21 - sway/commands/bar/tray_output.c | 29 - sway/commands/bar/tray_padding.c | 34 - sway/commands/bar/workspace_buttons.c | 27 - sway/commands/bar/wrap_scroll.c | 27 - sway/commands/bind.c | 170 -- sway/commands/border.c | 65 - sway/commands/client.c | 72 - sway/commands/clipboard.c | 38 - sway/commands/commands.c | 26 - sway/commands/debuglog.c | 27 - sway/commands/default_border.c | 44 - sway/commands/default_floating_border.c | 45 - sway/commands/exec.c | 16 - sway/commands/exec_always.c | 85 - sway/commands/exit.c | 17 - sway/commands/floating.c | 81 - sway/commands/floating_maximum_size.c | 38 - sway/commands/floating_minimum_size.c | 38 - sway/commands/floating_mod.c | 42 - sway/commands/floating_scroll.c | 46 - sway/commands/focus.c | 100 -- sway/commands/focus_follows_mouse.c | 13 - sway/commands/font.c | 27 - sway/commands/for_window.c | 41 - sway/commands/force_focus_wrapping.c | 13 - sway/commands/fullscreen.c | 60 - sway/commands/gaps.c | 166 -- sway/commands/hide_edge_borders.c | 27 - sway/commands/include.c | 15 - sway/commands/input.c | 55 - sway/commands/input/accel_profile.c | 27 - sway/commands/input/click_method.c | 30 - sway/commands/input/drag_lock.c | 26 - sway/commands/input/dwt.c | 26 - sway/commands/input/events.c | 30 - sway/commands/input/left_handed.c | 26 - sway/commands/input/middle_emulation.c | 26 - sway/commands/input/natural_scroll.c | 26 - sway/commands/input/pointer_accel.c | 24 - sway/commands/input/scroll_method.c | 30 - sway/commands/input/tap.c | 29 - sway/commands/ipc.c | 162 -- sway/commands/kill.c | 12 - sway/commands/layout.c | 196 --- sway/commands/log_colors.c | 22 - sway/commands/mark.c | 87 - sway/commands/mode.c | 57 - sway/commands/mouse_warping.c | 17 - sway/commands/move.c | 189 --- sway/commands/new_float.c | 8 - sway/commands/new_window.c | 8 - sway/commands/no_focus.c | 41 - sway/commands/orientation.c | 21 - sway/commands/output.c | 219 --- sway/commands/permit.c | 108 -- sway/commands/reload.c | 19 - sway/commands/resize.c | 375 ----- sway/commands/scratchpad.c | 72 - sway/commands/seamless_mouse.c | 13 - sway/commands/set.c | 61 - sway/commands/show_marks.c | 13 - sway/commands/smart_gaps.c | 20 - sway/commands/split.c | 98 -- sway/commands/sticky.c | 25 - sway/commands/unmark.c | 31 - sway/commands/workspace.c | 92 -- sway/commands/workspace_auto_back_and_forth.c | 18 - sway/commands/workspace_layout.c | 40 - sway/config.c | 1449 ----------------- sway/debug_log.c | 103 -- sway/desktop/output.c | 19 +- sway/desktop/xdg_shell_v6.c | 61 +- sway/handlers.c | 1143 ------------- sway/input_state.c | 490 ------ sway/ipc-json.c | 521 ------ sway/ipc-server.c | 845 ---------- sway/main.c | 48 +- sway/old/border.c | 510 ++++++ sway/old/commands.c | 686 ++++++++ sway/old/commands/assign.c | 57 + sway/old/commands/bar.c | 59 + sway/old/commands/bar/activate_button.c | 26 + sway/old/commands/bar/binding_mode_indicator.c | 27 + sway/old/commands/bar/bindsym.c | 48 + sway/old/commands/bar/colors.c | 129 ++ sway/old/commands/bar/context_button.c | 26 + sway/old/commands/bar/font.c | 26 + sway/old/commands/bar/height.c | 21 + sway/old/commands/bar/hidden_state.c | 79 + sway/old/commands/bar/icon_theme.c | 25 + sway/old/commands/bar/id.c | 33 + sway/old/commands/bar/mode.c | 81 + sway/old/commands/bar/modifier.c | 35 + sway/old/commands/bar/output.c | 50 + sway/old/commands/bar/pango_markup.c | 27 + sway/old/commands/bar/position.c | 33 + sway/old/commands/bar/secondary_button.c | 26 + sway/old/commands/bar/separator_symbol.c | 21 + sway/old/commands/bar/status_command.c | 21 + sway/old/commands/bar/strip_workspace_numbers.c | 27 + sway/old/commands/bar/swaybar_command.c | 21 + sway/old/commands/bar/tray_output.c | 29 + sway/old/commands/bar/tray_padding.c | 34 + sway/old/commands/bar/workspace_buttons.c | 27 + sway/old/commands/bar/wrap_scroll.c | 27 + sway/old/commands/bind.c | 170 ++ sway/old/commands/border.c | 65 + sway/old/commands/client.c | 72 + sway/old/commands/clipboard.c | 38 + sway/old/commands/commands.c | 26 + sway/old/commands/debuglog.c | 27 + sway/old/commands/default_border.c | 44 + sway/old/commands/default_floating_border.c | 45 + sway/old/commands/exec.c | 16 + sway/old/commands/exec_always.c | 85 + sway/old/commands/exit.c | 17 + sway/old/commands/floating.c | 81 + sway/old/commands/floating_maximum_size.c | 38 + sway/old/commands/floating_minimum_size.c | 38 + sway/old/commands/floating_mod.c | 42 + sway/old/commands/floating_scroll.c | 46 + sway/old/commands/focus.c | 100 ++ sway/old/commands/focus_follows_mouse.c | 13 + sway/old/commands/font.c | 27 + sway/old/commands/for_window.c | 41 + sway/old/commands/force_focus_wrapping.c | 13 + sway/old/commands/fullscreen.c | 60 + sway/old/commands/gaps.c | 166 ++ sway/old/commands/hide_edge_borders.c | 27 + sway/old/commands/include.c | 15 + sway/old/commands/input.c | 55 + sway/old/commands/input/accel_profile.c | 27 + sway/old/commands/input/click_method.c | 30 + sway/old/commands/input/drag_lock.c | 26 + sway/old/commands/input/dwt.c | 26 + sway/old/commands/input/events.c | 30 + sway/old/commands/input/left_handed.c | 26 + sway/old/commands/input/middle_emulation.c | 26 + sway/old/commands/input/natural_scroll.c | 26 + sway/old/commands/input/pointer_accel.c | 24 + sway/old/commands/input/scroll_method.c | 30 + sway/old/commands/input/tap.c | 29 + sway/old/commands/ipc.c | 162 ++ sway/old/commands/kill.c | 12 + sway/old/commands/layout.c | 196 +++ sway/old/commands/log_colors.c | 22 + sway/old/commands/mark.c | 87 + sway/old/commands/mode.c | 57 + sway/old/commands/mouse_warping.c | 17 + sway/old/commands/move.c | 189 +++ sway/old/commands/new_float.c | 8 + sway/old/commands/new_window.c | 8 + sway/old/commands/no_focus.c | 41 + sway/old/commands/orientation.c | 21 + sway/old/commands/output.c | 219 +++ sway/old/commands/permit.c | 108 ++ sway/old/commands/reload.c | 19 + sway/old/commands/resize.c | 375 +++++ sway/old/commands/scratchpad.c | 72 + sway/old/commands/seamless_mouse.c | 13 + sway/old/commands/set.c | 61 + sway/old/commands/show_marks.c | 13 + sway/old/commands/smart_gaps.c | 20 + sway/old/commands/split.c | 98 ++ sway/old/commands/sticky.c | 25 + sway/old/commands/unmark.c | 31 + sway/old/commands/workspace.c | 92 ++ sway/old/commands/workspace_auto_back_and_forth.c | 18 + sway/old/commands/workspace_layout.c | 40 + sway/old/config.c | 1313 +++++++++++++++ sway/old/container.c | 1024 ++++++++++++ sway/old/criteria.c | 451 ++++++ sway/old/focus.c | 278 ++++ sway/old/handlers.c | 1143 +++++++++++++ sway/old/input_state.c | 490 ++++++ sway/old/ipc-json.c | 521 ++++++ sway/old/ipc-server.c | 840 ++++++++++ sway/old/layout.c | 1773 +++++++++++++++++++++ sway/old/output.c | 278 ++++ sway/old/security.c | 228 +++ sway/old/workspace.c | 373 +++++ sway/security.c | 228 --- sway/server.c | 2 - sway/tree/container.c | 1024 ------------ sway/tree/criteria.c | 451 ------ sway/tree/focus.c | 278 ---- sway/tree/layout.c | 1773 --------------------- sway/tree/output.c | 278 ---- sway/tree/workspace.c | 373 ----- 244 files changed, 16064 insertions(+), 16418 deletions(-) delete mode 100644 include/sway.h delete mode 100644 include/sway/border.h delete mode 100644 include/sway/commands.h delete mode 100644 include/sway/config.h delete mode 100644 include/sway/container.h delete mode 100644 include/sway/criteria.h delete mode 100644 include/sway/focus.h delete mode 100644 include/sway/handlers.h delete mode 100644 include/sway/input.h delete mode 100644 include/sway/input_state.h delete mode 100644 include/sway/ipc-json.h delete mode 100644 include/sway/ipc-server.h delete mode 100644 include/sway/layout.h create mode 100644 include/sway/old/border.h create mode 100644 include/sway/old/commands.h create mode 100644 include/sway/old/config.h create mode 100644 include/sway/old/container.h create mode 100644 include/sway/old/criteria.h create mode 100644 include/sway/old/focus.h create mode 100644 include/sway/old/input.h create mode 100644 include/sway/old/input_state.h create mode 100644 include/sway/old/ipc-json.h create mode 100644 include/sway/old/ipc-server.h create mode 100644 include/sway/old/layout.h create mode 100644 include/sway/old/output.h create mode 100644 include/sway/old/workspace.h delete mode 100644 include/sway/workspace.h delete mode 100644 sway/border.c delete mode 100644 sway/commands.c delete mode 100644 sway/commands/assign.c delete mode 100644 sway/commands/bar.c delete mode 100644 sway/commands/bar/activate_button.c delete mode 100644 sway/commands/bar/binding_mode_indicator.c delete mode 100644 sway/commands/bar/bindsym.c delete mode 100644 sway/commands/bar/colors.c delete mode 100644 sway/commands/bar/context_button.c delete mode 100644 sway/commands/bar/font.c delete mode 100644 sway/commands/bar/height.c delete mode 100644 sway/commands/bar/hidden_state.c delete mode 100644 sway/commands/bar/icon_theme.c delete mode 100644 sway/commands/bar/id.c delete mode 100644 sway/commands/bar/mode.c delete mode 100644 sway/commands/bar/modifier.c delete mode 100644 sway/commands/bar/output.c delete mode 100644 sway/commands/bar/pango_markup.c delete mode 100644 sway/commands/bar/position.c delete mode 100644 sway/commands/bar/secondary_button.c delete mode 100644 sway/commands/bar/separator_symbol.c delete mode 100644 sway/commands/bar/status_command.c delete mode 100644 sway/commands/bar/strip_workspace_numbers.c delete mode 100644 sway/commands/bar/swaybar_command.c delete mode 100644 sway/commands/bar/tray_output.c delete mode 100644 sway/commands/bar/tray_padding.c delete mode 100644 sway/commands/bar/workspace_buttons.c delete mode 100644 sway/commands/bar/wrap_scroll.c delete mode 100644 sway/commands/bind.c delete mode 100644 sway/commands/border.c delete mode 100644 sway/commands/client.c delete mode 100644 sway/commands/clipboard.c delete mode 100644 sway/commands/commands.c delete mode 100644 sway/commands/debuglog.c delete mode 100644 sway/commands/default_border.c delete mode 100644 sway/commands/default_floating_border.c delete mode 100644 sway/commands/exec.c delete mode 100644 sway/commands/exec_always.c delete mode 100644 sway/commands/exit.c delete mode 100644 sway/commands/floating.c delete mode 100644 sway/commands/floating_maximum_size.c delete mode 100644 sway/commands/floating_minimum_size.c delete mode 100644 sway/commands/floating_mod.c delete mode 100644 sway/commands/floating_scroll.c delete mode 100644 sway/commands/focus.c delete mode 100644 sway/commands/focus_follows_mouse.c delete mode 100644 sway/commands/font.c delete mode 100644 sway/commands/for_window.c delete mode 100644 sway/commands/force_focus_wrapping.c delete mode 100644 sway/commands/fullscreen.c delete mode 100644 sway/commands/gaps.c delete mode 100644 sway/commands/hide_edge_borders.c delete mode 100644 sway/commands/include.c delete mode 100644 sway/commands/input.c delete mode 100644 sway/commands/input/accel_profile.c delete mode 100644 sway/commands/input/click_method.c delete mode 100644 sway/commands/input/drag_lock.c delete mode 100644 sway/commands/input/dwt.c delete mode 100644 sway/commands/input/events.c delete mode 100644 sway/commands/input/left_handed.c delete mode 100644 sway/commands/input/middle_emulation.c delete mode 100644 sway/commands/input/natural_scroll.c delete mode 100644 sway/commands/input/pointer_accel.c delete mode 100644 sway/commands/input/scroll_method.c delete mode 100644 sway/commands/input/tap.c delete mode 100644 sway/commands/ipc.c delete mode 100644 sway/commands/kill.c delete mode 100644 sway/commands/layout.c delete mode 100644 sway/commands/log_colors.c delete mode 100644 sway/commands/mark.c delete mode 100644 sway/commands/mode.c delete mode 100644 sway/commands/mouse_warping.c delete mode 100644 sway/commands/move.c delete mode 100644 sway/commands/new_float.c delete mode 100644 sway/commands/new_window.c delete mode 100644 sway/commands/no_focus.c delete mode 100644 sway/commands/orientation.c delete mode 100644 sway/commands/output.c delete mode 100644 sway/commands/permit.c delete mode 100644 sway/commands/reload.c delete mode 100644 sway/commands/resize.c delete mode 100644 sway/commands/scratchpad.c delete mode 100644 sway/commands/seamless_mouse.c delete mode 100644 sway/commands/set.c delete mode 100644 sway/commands/show_marks.c delete mode 100644 sway/commands/smart_gaps.c delete mode 100644 sway/commands/split.c delete mode 100644 sway/commands/sticky.c delete mode 100644 sway/commands/unmark.c delete mode 100644 sway/commands/workspace.c delete mode 100644 sway/commands/workspace_auto_back_and_forth.c delete mode 100644 sway/commands/workspace_layout.c delete mode 100644 sway/config.c delete mode 100644 sway/debug_log.c delete mode 100644 sway/handlers.c delete mode 100644 sway/input_state.c delete mode 100644 sway/ipc-json.c delete mode 100644 sway/ipc-server.c create mode 100644 sway/old/border.c create mode 100644 sway/old/commands.c create mode 100644 sway/old/commands/assign.c create mode 100644 sway/old/commands/bar.c create mode 100644 sway/old/commands/bar/activate_button.c create mode 100644 sway/old/commands/bar/binding_mode_indicator.c create mode 100644 sway/old/commands/bar/bindsym.c create mode 100644 sway/old/commands/bar/colors.c create mode 100644 sway/old/commands/bar/context_button.c create mode 100644 sway/old/commands/bar/font.c create mode 100644 sway/old/commands/bar/height.c create mode 100644 sway/old/commands/bar/hidden_state.c create mode 100644 sway/old/commands/bar/icon_theme.c create mode 100644 sway/old/commands/bar/id.c create mode 100644 sway/old/commands/bar/mode.c create mode 100644 sway/old/commands/bar/modifier.c create mode 100644 sway/old/commands/bar/output.c create mode 100644 sway/old/commands/bar/pango_markup.c create mode 100644 sway/old/commands/bar/position.c create mode 100644 sway/old/commands/bar/secondary_button.c create mode 100644 sway/old/commands/bar/separator_symbol.c create mode 100644 sway/old/commands/bar/status_command.c create mode 100644 sway/old/commands/bar/strip_workspace_numbers.c create mode 100644 sway/old/commands/bar/swaybar_command.c create mode 100644 sway/old/commands/bar/tray_output.c create mode 100644 sway/old/commands/bar/tray_padding.c create mode 100644 sway/old/commands/bar/workspace_buttons.c create mode 100644 sway/old/commands/bar/wrap_scroll.c create mode 100644 sway/old/commands/bind.c create mode 100644 sway/old/commands/border.c create mode 100644 sway/old/commands/client.c create mode 100644 sway/old/commands/clipboard.c create mode 100644 sway/old/commands/commands.c create mode 100644 sway/old/commands/debuglog.c create mode 100644 sway/old/commands/default_border.c create mode 100644 sway/old/commands/default_floating_border.c create mode 100644 sway/old/commands/exec.c create mode 100644 sway/old/commands/exec_always.c create mode 100644 sway/old/commands/exit.c create mode 100644 sway/old/commands/floating.c create mode 100644 sway/old/commands/floating_maximum_size.c create mode 100644 sway/old/commands/floating_minimum_size.c create mode 100644 sway/old/commands/floating_mod.c create mode 100644 sway/old/commands/floating_scroll.c create mode 100644 sway/old/commands/focus.c create mode 100644 sway/old/commands/focus_follows_mouse.c create mode 100644 sway/old/commands/font.c create mode 100644 sway/old/commands/for_window.c create mode 100644 sway/old/commands/force_focus_wrapping.c create mode 100644 sway/old/commands/fullscreen.c create mode 100644 sway/old/commands/gaps.c create mode 100644 sway/old/commands/hide_edge_borders.c create mode 100644 sway/old/commands/include.c create mode 100644 sway/old/commands/input.c create mode 100644 sway/old/commands/input/accel_profile.c create mode 100644 sway/old/commands/input/click_method.c create mode 100644 sway/old/commands/input/drag_lock.c create mode 100644 sway/old/commands/input/dwt.c create mode 100644 sway/old/commands/input/events.c create mode 100644 sway/old/commands/input/left_handed.c create mode 100644 sway/old/commands/input/middle_emulation.c create mode 100644 sway/old/commands/input/natural_scroll.c create mode 100644 sway/old/commands/input/pointer_accel.c create mode 100644 sway/old/commands/input/scroll_method.c create mode 100644 sway/old/commands/input/tap.c create mode 100644 sway/old/commands/ipc.c create mode 100644 sway/old/commands/kill.c create mode 100644 sway/old/commands/layout.c create mode 100644 sway/old/commands/log_colors.c create mode 100644 sway/old/commands/mark.c create mode 100644 sway/old/commands/mode.c create mode 100644 sway/old/commands/mouse_warping.c create mode 100644 sway/old/commands/move.c create mode 100644 sway/old/commands/new_float.c create mode 100644 sway/old/commands/new_window.c create mode 100644 sway/old/commands/no_focus.c create mode 100644 sway/old/commands/orientation.c create mode 100644 sway/old/commands/output.c create mode 100644 sway/old/commands/permit.c create mode 100644 sway/old/commands/reload.c create mode 100644 sway/old/commands/resize.c create mode 100644 sway/old/commands/scratchpad.c create mode 100644 sway/old/commands/seamless_mouse.c create mode 100644 sway/old/commands/set.c create mode 100644 sway/old/commands/show_marks.c create mode 100644 sway/old/commands/smart_gaps.c create mode 100644 sway/old/commands/split.c create mode 100644 sway/old/commands/sticky.c create mode 100644 sway/old/commands/unmark.c create mode 100644 sway/old/commands/workspace.c create mode 100644 sway/old/commands/workspace_auto_back_and_forth.c create mode 100644 sway/old/commands/workspace_layout.c create mode 100644 sway/old/config.c create mode 100644 sway/old/container.c create mode 100644 sway/old/criteria.c create mode 100644 sway/old/focus.c create mode 100644 sway/old/handlers.c create mode 100644 sway/old/input_state.c create mode 100644 sway/old/ipc-json.c create mode 100644 sway/old/ipc-server.c create mode 100644 sway/old/layout.c create mode 100644 sway/old/output.c create mode 100644 sway/old/security.c create mode 100644 sway/old/workspace.c delete mode 100644 sway/security.c delete mode 100644 sway/tree/container.c delete mode 100644 sway/tree/criteria.c delete mode 100644 sway/tree/focus.c delete mode 100644 sway/tree/layout.c delete mode 100644 sway/tree/output.c delete mode 100644 sway/tree/workspace.c (limited to 'sway/commands/move.c') diff --git a/CMakeLists.txt b/CMakeLists.txt index 34098eb3..b53670b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -116,7 +116,8 @@ add_subdirectory(wayland) add_subdirectory(sway) if(enable-swaybg) if(CAIRO_FOUND AND PANGO_FOUND) - add_subdirectory(swaybg) + # TODO WLR + #add_subdirectory(swaybg) else() message(WARNING "Not building swaybg - cairo, and pango are required.") endif() @@ -125,18 +126,21 @@ if(enable-swaymsg) add_subdirectory(swaymsg) endif() if(enable-swaygrab) - add_subdirectory(swaygrab) + # TODO WLR + #add_subdirectory(swaygrab) endif() if(enable-swaybar) if(CAIRO_FOUND AND PANGO_FOUND) - add_subdirectory(swaybar) + # TODO WLR + #add_subdirectory(swaybar) else() message(WARNING "Not building swaybar - cairo, and pango are required.") endif() endif() if(enable-swaylock) if(CAIRO_FOUND AND PANGO_FOUND AND PAM_FOUND) - add_subdirectory(swaylock) + # TODO WLR + #add_subdirectory(swaylock) else() message(WARNING "Not building swaylock - cairo, pango, and PAM are required.") endif() diff --git a/common/log.c b/common/log.c index 6dc9d743..c47b4eea 100644 --- a/common/log.c +++ b/common/log.c @@ -9,7 +9,6 @@ #include #include #include "log.h" -#include "sway.h" #include "readline.h" static int colored = 1; @@ -117,6 +116,7 @@ void _sway_log(const char *filename, int line, log_importance_t verbosity, const va_end(args); } +void sway_terminate(int code); void _sway_abort(const char *filename, int line, const char* format, ...) { va_list args; diff --git a/include/sway.h b/include/sway.h deleted file mode 100644 index b5cfb668..00000000 --- a/include/sway.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _SWAY_SWAY_H -#define _SWAY_SWAY_H - -void sway_terminate(int exit_code); - -#endif diff --git a/include/sway/border.h b/include/sway/border.h deleted file mode 100644 index c30c9da3..00000000 --- a/include/sway/border.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _SWAY_BORDER_H -#define _SWAY_BORDER_H -#include -#include "container.h" - -/** - * Border pixel buffer and corresponding geometry. - */ -struct border { - unsigned char *buffer; - struct wlc_geometry geometry; -}; - -/** - * Clear border buffer. - */ -void border_clear(struct border *border); - -/** - * Recursively update all of the borders within a container. - */ -void update_container_border(swayc_t *container); - -void render_view_borders(wlc_handle view); -int get_font_text_height(const char *font); -bool should_hide_top_border(swayc_t *con, double y); - -#endif diff --git a/include/sway/commands.h b/include/sway/commands.h deleted file mode 100644 index 660da2c2..00000000 --- a/include/sway/commands.h +++ /dev/null @@ -1,214 +0,0 @@ -#ifndef _SWAY_COMMANDS_H -#define _SWAY_COMMANDS_H -#include -#include -#include -#include "config.h" - -// Container that a called command should act upon. Only valid in command functions. -extern swayc_t *current_container; - -/** - * Indicates the result of a command's execution. - */ -enum cmd_status { - CMD_SUCCESS, /**< The command was successful */ - CMD_FAILURE, /**< The command resulted in an error */ - CMD_INVALID, /**< Unknown command or parser error */ - CMD_DEFER, /**< Command execution deferred */ - // Config Blocks - CMD_BLOCK_END, - CMD_BLOCK_MODE, - CMD_BLOCK_BAR, - CMD_BLOCK_BAR_COLORS, - CMD_BLOCK_INPUT, - CMD_BLOCK_COMMANDS, - CMD_BLOCK_IPC, - CMD_BLOCK_IPC_EVENTS, -}; - -/** - * Stores the result of executing a command. - */ -struct cmd_results { - enum cmd_status status; - char *input; - /** - * Human friendly error message, or NULL on success - */ - char *error; -}; - -enum expected_args { - EXPECTED_MORE_THAN, - EXPECTED_AT_LEAST, - EXPECTED_LESS_THAN, - EXPECTED_EQUAL_TO -}; - -struct cmd_results *checkarg(int argc, const char *name, enum expected_args type, int val); -struct cmd_results *add_color(const char*, char*, const char*); -void input_cmd_apply(struct input_config *input); -void hide_view_in_scratchpad(swayc_t *sp_view); - -swayc_t *sp_view; -int sp_index; - -/** - * Parse and handles a command. - */ -struct cmd_results *handle_command(char *command, enum command_context context); -/** - * Parse and handles a command during config file loading. - * - * Do not use this under normal conditions. - */ -struct cmd_results *config_command(char *command, enum cmd_status block); -/* - * Parses a command policy rule. - */ -struct cmd_results *config_commands_command(char *exec); - -/** - * Allocates a cmd_results object. - */ -struct cmd_results *cmd_results_new(enum cmd_status status, const char* input, const char *error, ...); -/** - * Frees a cmd_results object. - */ -void free_cmd_results(struct cmd_results *results); -/** - * Serializes cmd_results to a JSON string. - * - * Free the JSON string later on. - */ -const char *cmd_results_to_json(struct cmd_results *results); - -void remove_view_from_scratchpad(swayc_t *); - -/** - * Actual command function signatures for individual .c files in commands/ directory. - */ - -typedef struct cmd_results *sway_cmd(int argc, char **argv); - -sway_cmd cmd_assign; -sway_cmd cmd_bar; -sway_cmd cmd_bindcode; -sway_cmd cmd_bindsym; -sway_cmd cmd_border; -sway_cmd cmd_client_focused; -sway_cmd cmd_client_focused_inactive; -sway_cmd cmd_client_unfocused; -sway_cmd cmd_client_urgent; -sway_cmd cmd_client_placeholder; -sway_cmd cmd_client_background; -sway_cmd cmd_clipboard; -sway_cmd cmd_commands; -sway_cmd cmd_debuglog; -sway_cmd cmd_default_border; -sway_cmd cmd_default_floating_border; -sway_cmd cmd_exec; -sway_cmd cmd_exec_always; -sway_cmd cmd_exit; -sway_cmd cmd_floating; -sway_cmd cmd_floating_maximum_size; -sway_cmd cmd_floating_minimum_size; -sway_cmd cmd_floating_mod; -sway_cmd cmd_floating_scroll; -sway_cmd cmd_focus; -sway_cmd cmd_focus_follows_mouse; -sway_cmd cmd_font; -sway_cmd cmd_for_window; -sway_cmd cmd_force_focus_wrapping; -sway_cmd cmd_fullscreen; -sway_cmd cmd_gaps; -sway_cmd cmd_hide_edge_borders; -sway_cmd cmd_include; -sway_cmd cmd_input; -sway_cmd cmd_ipc; -sway_cmd cmd_kill; -sway_cmd cmd_layout; -sway_cmd cmd_log_colors; -sway_cmd cmd_mark; -sway_cmd cmd_mode; -sway_cmd cmd_mouse_warping; -sway_cmd cmd_move; -sway_cmd cmd_new_float; -sway_cmd cmd_new_window; -sway_cmd cmd_no_focus; -sway_cmd cmd_orientation; -sway_cmd cmd_output; -sway_cmd cmd_permit; -sway_cmd cmd_reject; -sway_cmd cmd_reload; -sway_cmd cmd_resize; -sway_cmd cmd_scratchpad; -sway_cmd cmd_seamless_mouse; -sway_cmd cmd_set; -sway_cmd cmd_show_marks; -sway_cmd cmd_smart_gaps; -sway_cmd cmd_split; -sway_cmd cmd_splith; -sway_cmd cmd_splitt; -sway_cmd cmd_splitv; -sway_cmd cmd_sticky; -sway_cmd cmd_unmark; -sway_cmd cmd_workspace; -sway_cmd cmd_ws_auto_back_and_forth; -sway_cmd cmd_workspace_layout; - -sway_cmd bar_cmd_activate_button; -sway_cmd bar_cmd_binding_mode_indicator; -sway_cmd bar_cmd_bindsym; -sway_cmd bar_cmd_colors; -sway_cmd bar_cmd_context_button; -sway_cmd bar_cmd_font; -sway_cmd bar_cmd_mode; -sway_cmd bar_cmd_modifier; -sway_cmd bar_cmd_output; -sway_cmd bar_cmd_height; -sway_cmd bar_cmd_hidden_state; -sway_cmd bar_cmd_icon_theme; -sway_cmd bar_cmd_id; -sway_cmd bar_cmd_position; -sway_cmd bar_cmd_secondary_button; -sway_cmd bar_cmd_separator_symbol; -sway_cmd bar_cmd_status_command; -sway_cmd bar_cmd_pango_markup; -sway_cmd bar_cmd_strip_workspace_numbers; -sway_cmd bar_cmd_swaybar_command; -sway_cmd bar_cmd_tray_output; -sway_cmd bar_cmd_tray_padding; -sway_cmd bar_cmd_wrap_scroll; -sway_cmd bar_cmd_workspace_buttons; - -sway_cmd bar_colors_cmd_active_workspace; -sway_cmd bar_colors_cmd_background; -sway_cmd bar_colors_cmd_focused_background; -sway_cmd bar_colors_cmd_binding_mode; -sway_cmd bar_colors_cmd_focused_workspace; -sway_cmd bar_colors_cmd_inactive_workspace; -sway_cmd bar_colors_cmd_separator; -sway_cmd bar_colors_cmd_focused_separator; -sway_cmd bar_colors_cmd_statusline; -sway_cmd bar_colors_cmd_focused_statusline; -sway_cmd bar_colors_cmd_urgent_workspace; - -sway_cmd input_cmd_accel_profile; -sway_cmd input_cmd_click_method; -sway_cmd input_cmd_drag_lock; -sway_cmd input_cmd_dwt; -sway_cmd input_cmd_events; -sway_cmd input_cmd_left_handed; -sway_cmd input_cmd_middle_emulation; -sway_cmd input_cmd_natural_scroll; -sway_cmd input_cmd_pointer_accel; -sway_cmd input_cmd_scroll_method; -sway_cmd input_cmd_tap; - -sway_cmd cmd_ipc_cmd; -sway_cmd cmd_ipc_events; -sway_cmd cmd_ipc_event_cmd; - -#endif diff --git a/include/sway/config.h b/include/sway/config.h deleted file mode 100644 index a05d5ede..00000000 --- a/include/sway/config.h +++ /dev/null @@ -1,406 +0,0 @@ -#ifndef _SWAY_CONFIG_H -#define _SWAY_CONFIG_H - -#define PID_WORKSPACE_TIMEOUT 60 - -#include -#include -#include -#include -#include -#include -#include "wayland-desktop-shell-server-protocol.h" -#include "list.h" -#include "layout.h" -#include "container.h" - -/** - * Describes a variable created via the `set` command. - */ -struct sway_variable { - char *name; - char *value; -}; - -/** - * A key binding and an associated command. - */ -struct sway_binding { - int order; - bool release; - bool bindcode; - list_t *keys; - uint32_t modifiers; - char *command; -}; - -/** - * A mouse binding and an associated command. - */ -struct sway_mouse_binding { - uint32_t button; - char *command; -}; - -/** - * A "mode" of keybindings created via the `mode` command. - */ -struct sway_mode { - char *name; - list_t *bindings; -}; - -/** - * libinput options for input devices - */ -struct input_config { - char *identifier; - - int accel_profile; - int click_method; - int drag_lock; - int dwt; - int left_handed; - int middle_emulation; - int natural_scroll; - float pointer_accel; - int scroll_method; - int send_events; - int tap; - - bool capturable; - struct wlc_geometry region; -}; - -/** - * Size and position configuration for a particular output. - * - * This is set via the `output` command. - */ -struct output_config { - char *name; - int enabled; - int width, height; - int x, y; - int scale; - char *background; - char *background_option; -}; - -/** - * Maps a workspace name to an output name. - * - * Set via `workspace output ` - */ -struct workspace_output { - char *output; - char *workspace; -}; - -struct pid_workspace { - pid_t *pid; - char *workspace; - time_t *time_added; -}; - -struct bar_config { - /** - * One of "dock", "hide", "invisible" - * - * Always visible in dock mode. Visible only when modifier key is held in hide mode. - * Never visible in invisible mode. - */ - char *mode; - /** - * One of "show" or "hide". - * - * In "show" mode, it will always be shown on top of the active workspace. - */ - char *hidden_state; - /** - * Id name used to identify the bar through IPC. - * - * Defaults to bar-x, where x corresponds to the position of the - * embedding bar block in the config file (bar-0, bar-1, ...). - */ - char *id; - uint32_t modifier; - list_t *outputs; - enum desktop_shell_panel_position position; - list_t *bindings; - char *status_command; - bool pango_markup; - char *swaybar_command; - char *font; - int height; // -1 not defined - -#ifdef ENABLE_TRAY - // Tray - char *tray_output; - char *icon_theme; - uint32_t tray_padding; - uint32_t activate_button; - uint32_t context_button; - uint32_t secondary_button; -#endif - - bool workspace_buttons; - bool wrap_scroll; - char *separator_symbol; - bool strip_workspace_numbers; - bool binding_mode_indicator; - bool verbose; - pid_t pid; - struct { - char *background; - char *statusline; - char *separator; - char *focused_background; - char *focused_statusline; - char *focused_separator; - char *focused_workspace_border; - char *focused_workspace_bg; - char *focused_workspace_text; - char *active_workspace_border; - char *active_workspace_bg; - char *active_workspace_text; - char *inactive_workspace_border; - char *inactive_workspace_bg; - char *inactive_workspace_text; - char *urgent_workspace_border; - char *urgent_workspace_bg; - char *urgent_workspace_text; - char *binding_mode_border; - char *binding_mode_bg; - char *binding_mode_text; - } colors; -}; - -struct border_colors { - uint32_t border; - uint32_t background; - uint32_t text; - uint32_t indicator; - uint32_t child_border; -}; - -enum edge_border_types { - E_NONE, /**< Don't hide edge borders */ - E_VERTICAL, /**< hide vertical edge borders */ - E_HORIZONTAL, /**< hide horizontal edge borders */ - E_BOTH, /**< hide vertical and horizontal edge borders */ - E_SMART /**< hide both if precisely one window is present in workspace */ -}; - -enum command_context { - CONTEXT_CONFIG = 1, - CONTEXT_BINDING = 2, - CONTEXT_IPC = 4, - CONTEXT_CRITERIA = 8, - CONTEXT_ALL = 0xFFFFFFFF, -}; - -struct command_policy { - char *command; - uint32_t context; -}; - -enum secure_feature { - FEATURE_LOCK = 1, - FEATURE_PANEL = 2, - FEATURE_BACKGROUND = 4, - FEATURE_SCREENSHOT = 8, - FEATURE_FULLSCREEN = 16, - FEATURE_KEYBOARD = 32, - FEATURE_MOUSE = 64, -}; - -struct feature_policy { - char *program; - uint32_t features; -}; - -enum ipc_feature { - IPC_FEATURE_COMMAND = 1, - IPC_FEATURE_GET_WORKSPACES = 2, - IPC_FEATURE_GET_OUTPUTS = 4, - IPC_FEATURE_GET_TREE = 8, - IPC_FEATURE_GET_MARKS = 16, - IPC_FEATURE_GET_BAR_CONFIG = 32, - IPC_FEATURE_GET_VERSION = 64, - IPC_FEATURE_GET_INPUTS = 128, - IPC_FEATURE_EVENT_WORKSPACE = 256, - IPC_FEATURE_EVENT_OUTPUT = 512, - IPC_FEATURE_EVENT_MODE = 1024, - IPC_FEATURE_EVENT_WINDOW = 2048, - IPC_FEATURE_EVENT_BINDING = 4096, - IPC_FEATURE_EVENT_INPUT = 8192, - IPC_FEATURE_GET_CLIPBOARD = 16384, - - IPC_FEATURE_ALL_COMMANDS = 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 16384, - IPC_FEATURE_ALL_EVENTS = 256 | 512 | 1024 | 2048 | 4096 | 8192, - - IPC_FEATURE_ALL = IPC_FEATURE_ALL_COMMANDS | IPC_FEATURE_ALL_EVENTS, -}; - -struct ipc_policy { - char *program; - uint32_t features; -}; - -/** - * The configuration struct. The result of loading a config file. - */ -struct sway_config { - list_t *symbols; - list_t *modes; - list_t *bars; - list_t *cmd_queue; - list_t *workspace_outputs; - list_t *pid_workspaces; - list_t *output_configs; - list_t *input_configs; - list_t *criteria; - list_t *no_focus; - list_t *active_bar_modifiers; - struct sway_mode *current_mode; - struct bar_config *current_bar; - uint32_t floating_mod; - uint32_t dragging_key; - uint32_t resizing_key; - char *floating_scroll_up_cmd; - char *floating_scroll_down_cmd; - char *floating_scroll_left_cmd; - char *floating_scroll_right_cmd; - enum swayc_layouts default_orientation; - enum swayc_layouts default_layout; - char *font; - int font_height; - - // Flags - bool focus_follows_mouse; - bool mouse_warping; - bool force_focus_wrapping; - bool active; - bool failed; - bool reloading; - bool reading; - bool auto_back_and_forth; - bool seamless_mouse; - bool show_marks; - - bool edge_gaps; - bool smart_gaps; - int gaps_inner; - int gaps_outer; - - list_t *config_chain; - const char *current_config; - - enum swayc_border_types border; - enum swayc_border_types floating_border; - int border_thickness; - int floating_border_thickness; - enum edge_border_types hide_edge_borders; - - // border colors - struct { - struct border_colors focused; - struct border_colors focused_inactive; - struct border_colors unfocused; - struct border_colors urgent; - struct border_colors placeholder; - uint32_t background; - } border_colors; - - // floating view - int32_t floating_maximum_width; - int32_t floating_maximum_height; - int32_t floating_minimum_width; - int32_t floating_minimum_height; - - // Security - list_t *command_policies; - list_t *feature_policies; - list_t *ipc_policies; -}; - -void pid_workspace_add(struct pid_workspace *pw); -void free_pid_workspace(struct pid_workspace *pw); - -/** - * Loads the main config from the given path. is_active should be true when - * reloading the config. - */ -bool load_main_config(const char *path, bool is_active); - -/** - * Loads an included config. Can only be used after load_main_config. - */ -bool load_include_configs(const char *path, struct sway_config *config); - -/** - * Reads the config from the given FILE. - */ -bool read_config(FILE *file, struct sway_config *config); - -/** - * Free config struct - */ -void free_config(struct sway_config *config); -/** - * Does variable replacement for a string based on the config's currently loaded variables. - */ -char *do_var_replacement(char *str); - -struct cmd_results *check_security_config(); - -int input_identifier_cmp(const void *item, const void *data); -void merge_input_config(struct input_config *dst, struct input_config *src); -void apply_input_config(struct input_config *ic, struct libinput_device *dev); -void free_input_config(struct input_config *ic); - -int output_name_cmp(const void *item, const void *data); -void merge_output_config(struct output_config *dst, struct output_config *src); -/** Sets up a WLC output handle based on a given output_config. - */ -void apply_output_config(struct output_config *oc, swayc_t *output); -void free_output_config(struct output_config *oc); - -/** - * Updates the list of active bar modifiers - */ -void update_active_bar_modifiers(void); - -int workspace_output_cmp_workspace(const void *a, const void *b); - -int sway_binding_cmp(const void *a, const void *b); -int sway_binding_cmp_qsort(const void *a, const void *b); -int sway_binding_cmp_keys(const void *a, const void *b); -void free_sway_binding(struct sway_binding *sb); -struct sway_binding *sway_binding_dup(struct sway_binding *sb); - -int sway_mouse_binding_cmp(const void *a, const void *b); -int sway_mouse_binding_cmp_qsort(const void *a, const void *b); -int sway_mouse_binding_cmp_buttons(const void *a, const void *b); -void free_sway_mouse_binding(struct sway_mouse_binding *smb); - -void load_swaybars(); -void terminate_swaybg(pid_t pid); - -/** - * Allocate and initialize default bar configuration. - */ -struct bar_config *default_bar_config(void); - -/** - * Global config singleton. - */ -extern struct sway_config *config; - -/** - * Config file currently being read. - */ -extern const char *current_config_path; - -#endif diff --git a/include/sway/container.h b/include/sway/container.h deleted file mode 100644 index d46ffa63..00000000 --- a/include/sway/container.h +++ /dev/null @@ -1,362 +0,0 @@ -#ifndef _SWAY_CONTAINER_H -#define _SWAY_CONTAINER_H -#include -#include -#include -#include -#include "list.h" - -typedef struct sway_container swayc_t; - -extern swayc_t root_container; -extern swayc_t *current_focus; - -struct sway_view; - -/** - * Different kinds of containers. - * - * This enum is in order. A container will never be inside of a container below - * it on this list. - */ -enum swayc_types { - C_ROOT, /**< The root container. Only one of these ever exists. */ - C_OUTPUT, /**< An output (aka monitor, head, etc). */ - C_WORKSPACE, /**< A workspace. */ - C_CONTAINER, /**< A manually created container. */ - C_VIEW, /**< A view (aka window). */ - // Keep last - C_TYPES, -}; - -/** - * Different ways to arrange a container. - */ -enum swayc_layouts { - L_NONE, /**< Used for containers that have no layout (views, root) */ - L_HORIZ, - L_VERT, - L_STACKED, - L_TABBED, - L_FLOATING, /**< A psuedo-container, removed from the tree, to hold floating windows */ - - /* Awesome/Monad style auto layouts */ - L_AUTO_LEFT, - L_AUTO_RIGHT, - L_AUTO_TOP, - L_AUTO_BOTTOM, - - L_AUTO_FIRST = L_AUTO_LEFT, - L_AUTO_LAST = L_AUTO_BOTTOM, - - // Keep last - L_LAYOUTS, -}; - -enum swayc_border_types { - B_NONE, /**< No border */ - B_PIXEL, /**< 1px border */ - B_NORMAL /**< Normal border with title bar */ -}; - -/** - * Stores information about a container. - * - * The tree is made of these. Views are containers that cannot have children. - */ -struct sway_container { - // TODO WLR: reconcile these - wlc_handle handle; - - union { - struct sway_output *output; - struct sway_view *view; - } _handle; - - /** - * A unique ID to identify this container. Primarily used in the - * get_tree JSON output. - */ - size_t id; - - enum swayc_types type; - enum swayc_layouts layout; - enum swayc_layouts prev_layout; - enum swayc_layouts workspace_layout; - - /** - * Width and height of this container, without borders or gaps. - */ - double width, height; - - /** - * Views may request geometry, which is stored in this and ignored until - * the views are floated. - */ - int desired_width, desired_height; - - /** - * The coordinates that this view appear at, relative to the output they - * are located on (output containers have absolute coordinates). - */ - double x, y; - - /** - * Cached geometry used to store view/container geometry when switching - * between tabbed/stacked and horizontal/vertical layouts. - */ - struct wlc_geometry cached_geometry; - - /** - * False if this view is invisible. It could be in the scratchpad or on a - * workspace that is not shown. - */ - bool visible; - bool is_floating; - bool is_focused; - bool sticky; // floating view always visible on its output - - // Attributes that mostly views have. - char *name; - char *class; - char *instance; - char *app_id; - - // Used by output containers to keep track of swaybg child processes. - pid_t bg_pid; - - int gaps; - - list_t *children; - /** - * Children of this container that are floated. - */ - list_t *floating; - /** - * Unmanaged view handles in this container. - */ - list_t *unmanaged; - - /** - * The parent of this container. NULL for the root container. - */ - struct sway_container *parent; - /** - * Which of this container's children has focus. - */ - struct sway_container *focused; - /** - * If this container's children include a fullscreen view, this is that view. - */ - struct sway_container *fullscreen; - /** - * If this container is a view, this may be set to the window's decoration - * buffer (or NULL). - */ - struct border *border; - enum swayc_border_types border_type; - struct wlc_geometry border_geometry; - struct wlc_geometry title_bar_geometry; - struct wlc_geometry actual_geometry; - int border_thickness; - - /** - * Number of master views in auto layouts. - */ - size_t nb_master; - - /** - * Number of slave groups (e.g. columns) in auto layouts. - */ - size_t nb_slave_groups; - - /** - * Marks applied to the container, list_t of char*. - */ - list_t *marks; -}; - -enum visibility_mask { - VISIBLE = true -} visible; - -struct sway_output; -/** - * Allocates a new output container. - */ -swayc_t *new_output(struct sway_output *sway_output); -/** - * Allocates a new workspace container. - */ -swayc_t *new_workspace(swayc_t *output, const char *name); -/** - * Allocates a new container and places a child into it. - * - * This is used from the split command, which creates a new container with the - * requested layout and replaces the focused container in the tree with the new - * one. Then the removed container is added as a child of the new container. - */ -swayc_t *new_container(swayc_t *child, enum swayc_layouts layout); -/** - * Allocates a new view container. - * - * Pass in a sibling view, or a workspace to become this container's parent. - */ -swayc_t *new_view(swayc_t *sibling, struct sway_view *view); -/** - * Allocates a new floating view in the active workspace. - */ -swayc_t *new_floating_view(wlc_handle handle); - -void floating_view_sane_size(swayc_t *view); - -/** - * Frees an output's container. - */ -swayc_t *destroy_output(swayc_t *output); -/** - * Destroys a workspace container and returns the parent pointer, or NULL. - */ -swayc_t *destroy_workspace(swayc_t *workspace); -/** - * Destroys a container and all empty parents. Returns the topmost non-empty - * parent container, or NULL. - */ -swayc_t *destroy_container(swayc_t *container); -/** - * Destroys a view container and all empty parents. Returns the topmost - * non-empty parent container, or NULL. - */ -swayc_t *destroy_view(swayc_t *view); - -/** - * Finds a container based on test criteria. Returns the first container that - * passes the test. - */ -swayc_t *swayc_by_test(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data); -/** - * Finds a parent container with the given swayc_type. - */ -swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types); -/** - * Finds a parent with the given swayc_layout. - */ -swayc_t *swayc_parent_by_layout(swayc_t *container, enum swayc_layouts); -/** - * Finds the bottom-most focused container of a type. - */ -swayc_t *swayc_focus_by_type(swayc_t *container, enum swayc_types); -/** - * Finds the bottom-most focused container of a layout. - */ -swayc_t *swayc_focus_by_layout(swayc_t *container, enum swayc_layouts); - -/** - * Gets the swayc_t associated with a wlc_handle. - */ -swayc_t *swayc_by_handle(wlc_handle handle); -/** - * Gets the named swayc_t. - */ -swayc_t *swayc_by_name(const char *name); -/** - * Gets the active output's container. - */ -swayc_t *swayc_active_output(void); -/** - * Gets the active workspace's container. - */ -swayc_t *swayc_active_workspace(void); -/** - * Gets the workspace for the given view container. - */ -swayc_t *swayc_active_workspace_for(swayc_t *view); -/** - * Finds the container currently underneath the pointer. - */ -swayc_t *container_under_pointer(void); -/** - * Finds the first container following a callback. - */ -swayc_t *container_find(swayc_t *container, bool (*f)(swayc_t *, const void *), const void *data); - -/** - * Returns true if a container is fullscreen. - */ -bool swayc_is_fullscreen(swayc_t *view); -/** - * Returns true if this view is focused. - */ -bool swayc_is_active(swayc_t *view); -/** - * Returns true if the parent is an ancestor of the child. - */ -bool swayc_is_parent_of(swayc_t *parent, swayc_t *child); -/** - * Returns true if the child is a desecendant of the parent. - */ -bool swayc_is_child_of(swayc_t *child, swayc_t *parent); - -/** - * Returns true if this container is an empty workspace. - */ -bool swayc_is_empty_workspace(swayc_t *container); - -/** - * Returns the top most tabbed or stacked parent container. Returns NULL if - * view is not in a tabbed/stacked layout. - */ -swayc_t *swayc_tabbed_stacked_ancestor(swayc_t *view); - -/** - * Returns the immediate tabbed or stacked parent container. Returns NULL if - * view is not directly in a tabbed/stacked layout. - */ -swayc_t *swayc_tabbed_stacked_parent(swayc_t *view); - -/** - * Returns the gap (padding) of the container. - * - * This returns the inner gaps for a view, the outer gaps for a workspace, and - * 0 otherwise. - */ -int swayc_gap(swayc_t *container); - -/** - * Maps a container's children over a function. - */ -void container_map(swayc_t *, void (*f)(swayc_t *, void *), void *); - -/** - * Set a view as visible or invisible. - * - * This will perform the required wlc calls as well; it is not sufficient to - * simply toggle the boolean in swayc_t. - */ -void set_view_visibility(swayc_t *view, void *data); -/** - * Set the gaps value for a view. - */ -void set_gaps(swayc_t *view, void *amount); -/** - * Add to the gaps value for a view. - */ -void add_gaps(swayc_t *view, void *amount); - -/** - * Issue wlc calls to make the visibility of a container consistent. - */ -void update_visibility(swayc_t *container); - -/** - * Close all child views of container - */ -void close_views(swayc_t *container); - -/** - * Assign layout to a container. Needed due to workspace container specifics. - * Workspace should always have either L_VERT or L_HORIZ layout. - */ -swayc_t *swayc_change_layout(swayc_t *container, enum swayc_layouts layout); - -#endif diff --git a/include/sway/criteria.h b/include/sway/criteria.h deleted file mode 100644 index c5ed9857..00000000 --- a/include/sway/criteria.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef _SWAY_CRITERIA_H -#define _SWAY_CRITERIA_H - -#include "container.h" -#include "list.h" - -/** - * Maps criteria (as a list of criteria tokens) to a command list. - * - * A list of tokens together represent a single criteria string (e.g. - * '[class="abc" title="xyz"]' becomes two criteria tokens). - * - * for_window: Views matching all criteria will have the bound command list - * executed on them. - * - * Set via `for_window `. - */ -struct criteria { - list_t *tokens; // struct crit_token, contains compiled regex. - char *crit_raw; // entire criteria string (for logging) - - char *cmdlist; -}; - -int criteria_cmp(const void *item, const void *data); -void free_criteria(struct criteria *crit); - -// Pouplate list with crit_tokens extracted from criteria string, returns error -// string or NULL if successful. -char *extract_crit_tokens(list_t *tokens, const char *criteria); - -// Returns list of criteria that match given container. These criteria have -// been set with `for_window` commands and have an associated cmdlist. -list_t *criteria_for(swayc_t *cont); - -// Returns a list of all containers that match the given list of tokens. -list_t *container_for(list_t *tokens); - -// Returns true if any criteria in the given list matches this container -bool criteria_any(swayc_t *cont, list_t *criteria); - -#endif diff --git a/include/sway/focus.h b/include/sway/focus.h deleted file mode 100644 index 652cdccc..00000000 --- a/include/sway/focus.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef _SWAY_FOCUS_H -#define _SWAY_FOCUS_H -enum movement_direction { - MOVE_LEFT, - MOVE_RIGHT, - MOVE_UP, - MOVE_DOWN, - MOVE_PARENT, - MOVE_CHILD, - MOVE_NEXT, - MOVE_PREV, - MOVE_FIRST -}; - -#include "container.h" - -// focused_container - the container found by following the `focused` pointer -// from a given container to a container with `is_focused` boolean set -// --- -// focused_view - the container found by following the `focused` pointer from a -// given container to a view. -// --- - -swayc_t *get_focused_container(swayc_t *parent); -swayc_t *get_focused_view(swayc_t *parent); -swayc_t *get_focused_float(swayc_t *ws); - -// a special-case function to get the focused view, regardless -// of whether it's tiled or floating -swayc_t *get_focused_view_include_floating(swayc_t *parent); - -bool set_focused_container(swayc_t *container); -bool set_focused_container_for(swayc_t *ancestor, swayc_t *container); - -// lock focused container/view. locked by windows with OVERRIDE attribute -// and unlocked when they are destroyed - -extern bool locked_container_focus; - -// Prevents wss from being destroyed on focus switch -extern bool suspend_workspace_cleanup; - -bool move_focus(enum movement_direction direction); - -#endif diff --git a/include/sway/handlers.h b/include/sway/handlers.h deleted file mode 100644 index 956b98f4..00000000 --- a/include/sway/handlers.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _SWAY_HANDLERS_H -#define _SWAY_HANDLERS_H -#include "container.h" -#include -#include - -void register_wlc_handlers(); - -extern uint32_t keys_pressed[32]; - -#endif diff --git a/include/sway/input.h b/include/sway/input.h deleted file mode 100644 index eb92e470..00000000 --- a/include/sway/input.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _SWAY_INPUT_H -#define _SWAY_INPUT_H -#include -#include "sway/server.h" -#include "config.h" -#include "list.h" - -struct sway_input { - list_t *input_devices; -}; - -struct input_config *new_input_config(const char* identifier); - -char* libinput_dev_unique_id(struct libinput_device *dev); - -struct sway_input *sway_input_create(struct sway_server *server); - -/** - * Pointer used when reading input blocked. - * Shared so that it can be cleared from commands.c when closing the block - */ -extern struct input_config *current_input_config; - -#endif diff --git a/include/sway/input_state.h b/include/sway/input_state.h deleted file mode 100644 index fd5a3a25..00000000 --- a/include/sway/input_state.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef _SWAY_KEY_STATE_H -#define _SWAY_KEY_STATE_H -#include -#include -#include "container.h" - -/* Keyboard state */ - -// returns true if key has been pressed, otherwise false -bool check_key(uint32_t key_sym, uint32_t key_code); - -// returns true if key_sym matches latest released key. -bool check_released_key(uint32_t key_sym); - -// sets a key as pressed -void press_key(uint32_t key_sym, uint32_t key_code); - -// unsets a key as pressed -void release_key(uint32_t key_sym, uint32_t key_code); - - -/* Pointer state */ - -enum pointer_values { - M_LEFT_CLICK = 272, - M_RIGHT_CLICK = 273, - M_SCROLL_CLICK = 274, - M_SCROLL_UP = 275, - M_SCROLL_DOWN = 276, -}; - -enum pointer_mode { - // Target - M_FLOATING = 1, - M_TILING = 2, - // Action - M_DRAGGING = 4, - M_RESIZING = 8, -}; - -struct pointer_button_state { - bool held; - // state at the point it was pressed - int x, y; - swayc_t *view; -}; - -extern struct pointer_state { - // mouse clicks - struct pointer_button_state left; - struct pointer_button_state right; - struct pointer_button_state scroll; - - // change in pointer position - struct { - int x, y; - } delta; - - // view pointer is currently over - swayc_t *view; - - // Pointer mode - int mode; -} pointer_state; - -enum modifier_state { - MOD_STATE_UNCHANGED = 0, - MOD_STATE_PRESSED = 1, - MOD_STATE_RELEASED = 2 -}; - -void pointer_position_set(double new_x, double new_y, bool force_focus); -void center_pointer_on(swayc_t *view); - -// on button release unset mode depending on the button. -// on button press set mode conditionally depending on the button -void pointer_mode_set(uint32_t button, bool condition); - -// Update mode in mouse motion -void pointer_mode_update(void); - -// Reset mode on any keypress; -void pointer_mode_reset(void); - -void input_init(void); - -/** - * Check if state of mod changed from current state to new_state. - * - * Returns MOD_STATE_UNCHANGED if the state didn't change, MOD_STATE_PRESSED if - * the state changed to pressed and MOD_STATE_RELEASED if the state changed to - * released. - */ -uint32_t modifier_state_changed(uint32_t new_state, uint32_t mod); - -/** - * Update the current modifiers state to new_state. - */ -void modifiers_state_update(uint32_t new_state); - -#endif - diff --git a/include/sway/ipc-json.h b/include/sway/ipc-json.h deleted file mode 100644 index 3a5af0f5..00000000 --- a/include/sway/ipc-json.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _SWAY_IPC_JSON_H -#define _SWAY_IPC_JSON_H - -#include -#include "config.h" -#include "container.h" - -json_object *ipc_json_get_version(); -json_object *ipc_json_describe_bar_config(struct bar_config *bar); -json_object *ipc_json_describe_container(swayc_t *c); -json_object *ipc_json_describe_container_recursive(swayc_t *c); -json_object *ipc_json_describe_window(swayc_t *c); -json_object *ipc_json_describe_input(struct libinput_device *device); - -#endif diff --git a/include/sway/ipc-server.h b/include/sway/ipc-server.h deleted file mode 100644 index 1d199134..00000000 --- a/include/sway/ipc-server.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _SWAY_IPC_SERVER_H -#define _SWAY_IPC_SERVER_H - -#include - -#include "container.h" -#include "config.h" -#include "ipc.h" - -void ipc_init(void); -void ipc_terminate(void); -struct sockaddr_un *ipc_user_sockaddr(void); - -void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change); -void ipc_event_barconfig_update(struct bar_config *bar); -/** - * Send IPC mode event to all listening clients - */ -void ipc_event_mode(const char *mode); -/** - * Send IPC window change event - */ -void ipc_event_window(swayc_t *window, const char *change); -/** - * Sends an IPC modifier event to all listening clients. The modifier event - * includes a key 'change' with the value of state and a key 'modifier' with - * the name of that modifier. - */ -void ipc_event_modifier(uint32_t modifier, const char *state); -/** - * Send IPC keyboard binding event. - */ -void ipc_event_binding_keyboard(struct sway_binding *sb); -const char *swayc_type_string(enum swayc_types type); - -/** - * Send pixel data to registered clients. - */ -void ipc_get_pixels(wlc_handle output); - -#endif diff --git a/include/sway/layout.h b/include/sway/layout.h deleted file mode 100644 index f0791588..00000000 --- a/include/sway/layout.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef _SWAY_LAYOUT_H -#define _SWAY_LAYOUT_H - -#include -#include "log.h" -#include "list.h" -#include "container.h" -#include "focus.h" - -extern list_t *scratchpad; - -extern int min_sane_w; -extern int min_sane_h; - -// Set initial values for root_container -void init_layout(void); - -// Returns the index of child for its parent -int index_child(const swayc_t *child); - -// Adds child to parent, if parent has no focus, it is set to child -// parent must be of type C_WORKSPACE or C_CONTAINER -void add_child(swayc_t *parent, swayc_t *child); - -// Adds child to parent at index, if parent has no focus, it is set to child -// parent must be of type C_WORKSPACE or C_CONTAINER -void insert_child(swayc_t *parent, swayc_t *child, int index); - -// Adds child as floating window to ws, if there is no focus it is set to child. -// ws must be of type C_WORKSPACE -void add_floating(swayc_t *ws, swayc_t *child); - -// insert child after sibling in parents children. -swayc_t *add_sibling(swayc_t *sibling, swayc_t *child); - -// Replace child with new_child in parents children -// new_child will inherit childs geometry, childs geometry will be reset -// if parents focus is on child, it will be changed to new_child -swayc_t *replace_child(swayc_t *child, swayc_t *new_child); - -// Remove child from its parent, if focus is on child, focus will be changed to -// a sibling, or to a floating window, or NULL -swayc_t *remove_child(swayc_t *child); - -// 2 containers are swapped, they inherit eachothers focus -void swap_container(swayc_t *a, swayc_t *b); - -// 2 Containers geometry are swapped, used with `swap_container` -void swap_geometry(swayc_t *a, swayc_t *b); - -void move_container(swayc_t* container, enum movement_direction direction, int move_amt); -void move_container_to(swayc_t* container, swayc_t* destination); -void move_workspace_to(swayc_t* workspace, swayc_t* destination); - -// Layout -/** - * Update child container geometries when switching between layouts. - */ -void update_layout_geometry(swayc_t *parent, enum swayc_layouts prev_layout); -void update_geometry(swayc_t *view); -void arrange_windows(swayc_t *container, double width, double height); -void arrange_backgrounds(void); - -swayc_t *get_focused_container(swayc_t *parent); -swayc_t *get_swayc_in_direction(swayc_t *container, enum movement_direction dir); -swayc_t *get_swayc_in_direction_under(swayc_t *container, enum movement_direction dir, swayc_t *limit); - -void recursive_resize(swayc_t *container, double amount, enum wlc_resize_edge edge); - -void layout_log(const swayc_t *c, int depth); -void swayc_log(log_importance_t verbosity, swayc_t *cont, const char* format, ...) __attribute__((format(printf,3,4))); - -/** - * Get default layout. - */ -enum swayc_layouts default_layout(swayc_t *output); - -bool is_auto_layout(enum swayc_layouts layout); -int auto_group_start_index(const swayc_t *container, int index); -int auto_group_end_index(const swayc_t *container, int index); -size_t auto_group_count(const swayc_t *container); -size_t auto_group_index(const swayc_t *container, int index); -bool auto_group_bounds(const swayc_t *container, size_t group_index, int *start, int *end); - -#endif diff --git a/include/sway/old/border.h b/include/sway/old/border.h new file mode 100644 index 00000000..c30c9da3 --- /dev/null +++ b/include/sway/old/border.h @@ -0,0 +1,28 @@ +#ifndef _SWAY_BORDER_H +#define _SWAY_BORDER_H +#include +#include "container.h" + +/** + * Border pixel buffer and corresponding geometry. + */ +struct border { + unsigned char *buffer; + struct wlc_geometry geometry; +}; + +/** + * Clear border buffer. + */ +void border_clear(struct border *border); + +/** + * Recursively update all of the borders within a container. + */ +void update_container_border(swayc_t *container); + +void render_view_borders(wlc_handle view); +int get_font_text_height(const char *font); +bool should_hide_top_border(swayc_t *con, double y); + +#endif diff --git a/include/sway/old/commands.h b/include/sway/old/commands.h new file mode 100644 index 00000000..660da2c2 --- /dev/null +++ b/include/sway/old/commands.h @@ -0,0 +1,214 @@ +#ifndef _SWAY_COMMANDS_H +#define _SWAY_COMMANDS_H +#include +#include +#include +#include "config.h" + +// Container that a called command should act upon. Only valid in command functions. +extern swayc_t *current_container; + +/** + * Indicates the result of a command's execution. + */ +enum cmd_status { + CMD_SUCCESS, /**< The command was successful */ + CMD_FAILURE, /**< The command resulted in an error */ + CMD_INVALID, /**< Unknown command or parser error */ + CMD_DEFER, /**< Command execution deferred */ + // Config Blocks + CMD_BLOCK_END, + CMD_BLOCK_MODE, + CMD_BLOCK_BAR, + CMD_BLOCK_BAR_COLORS, + CMD_BLOCK_INPUT, + CMD_BLOCK_COMMANDS, + CMD_BLOCK_IPC, + CMD_BLOCK_IPC_EVENTS, +}; + +/** + * Stores the result of executing a command. + */ +struct cmd_results { + enum cmd_status status; + char *input; + /** + * Human friendly error message, or NULL on success + */ + char *error; +}; + +enum expected_args { + EXPECTED_MORE_THAN, + EXPECTED_AT_LEAST, + EXPECTED_LESS_THAN, + EXPECTED_EQUAL_TO +}; + +struct cmd_results *checkarg(int argc, const char *name, enum expected_args type, int val); +struct cmd_results *add_color(const char*, char*, const char*); +void input_cmd_apply(struct input_config *input); +void hide_view_in_scratchpad(swayc_t *sp_view); + +swayc_t *sp_view; +int sp_index; + +/** + * Parse and handles a command. + */ +struct cmd_results *handle_command(char *command, enum command_context context); +/** + * Parse and handles a command during config file loading. + * + * Do not use this under normal conditions. + */ +struct cmd_results *config_command(char *command, enum cmd_status block); +/* + * Parses a command policy rule. + */ +struct cmd_results *config_commands_command(char *exec); + +/** + * Allocates a cmd_results object. + */ +struct cmd_results *cmd_results_new(enum cmd_status status, const char* input, const char *error, ...); +/** + * Frees a cmd_results object. + */ +void free_cmd_results(struct cmd_results *results); +/** + * Serializes cmd_results to a JSON string. + * + * Free the JSON string later on. + */ +const char *cmd_results_to_json(struct cmd_results *results); + +void remove_view_from_scratchpad(swayc_t *); + +/** + * Actual command function signatures for individual .c files in commands/ directory. + */ + +typedef struct cmd_results *sway_cmd(int argc, char **argv); + +sway_cmd cmd_assign; +sway_cmd cmd_bar; +sway_cmd cmd_bindcode; +sway_cmd cmd_bindsym; +sway_cmd cmd_border; +sway_cmd cmd_client_focused; +sway_cmd cmd_client_focused_inactive; +sway_cmd cmd_client_unfocused; +sway_cmd cmd_client_urgent; +sway_cmd cmd_client_placeholder; +sway_cmd cmd_client_background; +sway_cmd cmd_clipboard; +sway_cmd cmd_commands; +sway_cmd cmd_debuglog; +sway_cmd cmd_default_border; +sway_cmd cmd_default_floating_border; +sway_cmd cmd_exec; +sway_cmd cmd_exec_always; +sway_cmd cmd_exit; +sway_cmd cmd_floating; +sway_cmd cmd_floating_maximum_size; +sway_cmd cmd_floating_minimum_size; +sway_cmd cmd_floating_mod; +sway_cmd cmd_floating_scroll; +sway_cmd cmd_focus; +sway_cmd cmd_focus_follows_mouse; +sway_cmd cmd_font; +sway_cmd cmd_for_window; +sway_cmd cmd_force_focus_wrapping; +sway_cmd cmd_fullscreen; +sway_cmd cmd_gaps; +sway_cmd cmd_hide_edge_borders; +sway_cmd cmd_include; +sway_cmd cmd_input; +sway_cmd cmd_ipc; +sway_cmd cmd_kill; +sway_cmd cmd_layout; +sway_cmd cmd_log_colors; +sway_cmd cmd_mark; +sway_cmd cmd_mode; +sway_cmd cmd_mouse_warping; +sway_cmd cmd_move; +sway_cmd cmd_new_float; +sway_cmd cmd_new_window; +sway_cmd cmd_no_focus; +sway_cmd cmd_orientation; +sway_cmd cmd_output; +sway_cmd cmd_permit; +sway_cmd cmd_reject; +sway_cmd cmd_reload; +sway_cmd cmd_resize; +sway_cmd cmd_scratchpad; +sway_cmd cmd_seamless_mouse; +sway_cmd cmd_set; +sway_cmd cmd_show_marks; +sway_cmd cmd_smart_gaps; +sway_cmd cmd_split; +sway_cmd cmd_splith; +sway_cmd cmd_splitt; +sway_cmd cmd_splitv; +sway_cmd cmd_sticky; +sway_cmd cmd_unmark; +sway_cmd cmd_workspace; +sway_cmd cmd_ws_auto_back_and_forth; +sway_cmd cmd_workspace_layout; + +sway_cmd bar_cmd_activate_button; +sway_cmd bar_cmd_binding_mode_indicator; +sway_cmd bar_cmd_bindsym; +sway_cmd bar_cmd_colors; +sway_cmd bar_cmd_context_button; +sway_cmd bar_cmd_font; +sway_cmd bar_cmd_mode; +sway_cmd bar_cmd_modifier; +sway_cmd bar_cmd_output; +sway_cmd bar_cmd_height; +sway_cmd bar_cmd_hidden_state; +sway_cmd bar_cmd_icon_theme; +sway_cmd bar_cmd_id; +sway_cmd bar_cmd_position; +sway_cmd bar_cmd_secondary_button; +sway_cmd bar_cmd_separator_symbol; +sway_cmd bar_cmd_status_command; +sway_cmd bar_cmd_pango_markup; +sway_cmd bar_cmd_strip_workspace_numbers; +sway_cmd bar_cmd_swaybar_command; +sway_cmd bar_cmd_tray_output; +sway_cmd bar_cmd_tray_padding; +sway_cmd bar_cmd_wrap_scroll; +sway_cmd bar_cmd_workspace_buttons; + +sway_cmd bar_colors_cmd_active_workspace; +sway_cmd bar_colors_cmd_background; +sway_cmd bar_colors_cmd_focused_background; +sway_cmd bar_colors_cmd_binding_mode; +sway_cmd bar_colors_cmd_focused_workspace; +sway_cmd bar_colors_cmd_inactive_workspace; +sway_cmd bar_colors_cmd_separator; +sway_cmd bar_colors_cmd_focused_separator; +sway_cmd bar_colors_cmd_statusline; +sway_cmd bar_colors_cmd_focused_statusline; +sway_cmd bar_colors_cmd_urgent_workspace; + +sway_cmd input_cmd_accel_profile; +sway_cmd input_cmd_click_method; +sway_cmd input_cmd_drag_lock; +sway_cmd input_cmd_dwt; +sway_cmd input_cmd_events; +sway_cmd input_cmd_left_handed; +sway_cmd input_cmd_middle_emulation; +sway_cmd input_cmd_natural_scroll; +sway_cmd input_cmd_pointer_accel; +sway_cmd input_cmd_scroll_method; +sway_cmd input_cmd_tap; + +sway_cmd cmd_ipc_cmd; +sway_cmd cmd_ipc_events; +sway_cmd cmd_ipc_event_cmd; + +#endif diff --git a/include/sway/old/config.h b/include/sway/old/config.h new file mode 100644 index 00000000..a05d5ede --- /dev/null +++ b/include/sway/old/config.h @@ -0,0 +1,406 @@ +#ifndef _SWAY_CONFIG_H +#define _SWAY_CONFIG_H + +#define PID_WORKSPACE_TIMEOUT 60 + +#include +#include +#include +#include +#include +#include +#include "wayland-desktop-shell-server-protocol.h" +#include "list.h" +#include "layout.h" +#include "container.h" + +/** + * Describes a variable created via the `set` command. + */ +struct sway_variable { + char *name; + char *value; +}; + +/** + * A key binding and an associated command. + */ +struct sway_binding { + int order; + bool release; + bool bindcode; + list_t *keys; + uint32_t modifiers; + char *command; +}; + +/** + * A mouse binding and an associated command. + */ +struct sway_mouse_binding { + uint32_t button; + char *command; +}; + +/** + * A "mode" of keybindings created via the `mode` command. + */ +struct sway_mode { + char *name; + list_t *bindings; +}; + +/** + * libinput options for input devices + */ +struct input_config { + char *identifier; + + int accel_profile; + int click_method; + int drag_lock; + int dwt; + int left_handed; + int middle_emulation; + int natural_scroll; + float pointer_accel; + int scroll_method; + int send_events; + int tap; + + bool capturable; + struct wlc_geometry region; +}; + +/** + * Size and position configuration for a particular output. + * + * This is set via the `output` command. + */ +struct output_config { + char *name; + int enabled; + int width, height; + int x, y; + int scale; + char *background; + char *background_option; +}; + +/** + * Maps a workspace name to an output name. + * + * Set via `workspace output ` + */ +struct workspace_output { + char *output; + char *workspace; +}; + +struct pid_workspace { + pid_t *pid; + char *workspace; + time_t *time_added; +}; + +struct bar_config { + /** + * One of "dock", "hide", "invisible" + * + * Always visible in dock mode. Visible only when modifier key is held in hide mode. + * Never visible in invisible mode. + */ + char *mode; + /** + * One of "show" or "hide". + * + * In "show" mode, it will always be shown on top of the active workspace. + */ + char *hidden_state; + /** + * Id name used to identify the bar through IPC. + * + * Defaults to bar-x, where x corresponds to the position of the + * embedding bar block in the config file (bar-0, bar-1, ...). + */ + char *id; + uint32_t modifier; + list_t *outputs; + enum desktop_shell_panel_position position; + list_t *bindings; + char *status_command; + bool pango_markup; + char *swaybar_command; + char *font; + int height; // -1 not defined + +#ifdef ENABLE_TRAY + // Tray + char *tray_output; + char *icon_theme; + uint32_t tray_padding; + uint32_t activate_button; + uint32_t context_button; + uint32_t secondary_button; +#endif + + bool workspace_buttons; + bool wrap_scroll; + char *separator_symbol; + bool strip_workspace_numbers; + bool binding_mode_indicator; + bool verbose; + pid_t pid; + struct { + char *background; + char *statusline; + char *separator; + char *focused_background; + char *focused_statusline; + char *focused_separator; + char *focused_workspace_border; + char *focused_workspace_bg; + char *focused_workspace_text; + char *active_workspace_border; + char *active_workspace_bg; + char *active_workspace_text; + char *inactive_workspace_border; + char *inactive_workspace_bg; + char *inactive_workspace_text; + char *urgent_workspace_border; + char *urgent_workspace_bg; + char *urgent_workspace_text; + char *binding_mode_border; + char *binding_mode_bg; + char *binding_mode_text; + } colors; +}; + +struct border_colors { + uint32_t border; + uint32_t background; + uint32_t text; + uint32_t indicator; + uint32_t child_border; +}; + +enum edge_border_types { + E_NONE, /**< Don't hide edge borders */ + E_VERTICAL, /**< hide vertical edge borders */ + E_HORIZONTAL, /**< hide horizontal edge borders */ + E_BOTH, /**< hide vertical and horizontal edge borders */ + E_SMART /**< hide both if precisely one window is present in workspace */ +}; + +enum command_context { + CONTEXT_CONFIG = 1, + CONTEXT_BINDING = 2, + CONTEXT_IPC = 4, + CONTEXT_CRITERIA = 8, + CONTEXT_ALL = 0xFFFFFFFF, +}; + +struct command_policy { + char *command; + uint32_t context; +}; + +enum secure_feature { + FEATURE_LOCK = 1, + FEATURE_PANEL = 2, + FEATURE_BACKGROUND = 4, + FEATURE_SCREENSHOT = 8, + FEATURE_FULLSCREEN = 16, + FEATURE_KEYBOARD = 32, + FEATURE_MOUSE = 64, +}; + +struct feature_policy { + char *program; + uint32_t features; +}; + +enum ipc_feature { + IPC_FEATURE_COMMAND = 1, + IPC_FEATURE_GET_WORKSPACES = 2, + IPC_FEATURE_GET_OUTPUTS = 4, + IPC_FEATURE_GET_TREE = 8, + IPC_FEATURE_GET_MARKS = 16, + IPC_FEATURE_GET_BAR_CONFIG = 32, + IPC_FEATURE_GET_VERSION = 64, + IPC_FEATURE_GET_INPUTS = 128, + IPC_FEATURE_EVENT_WORKSPACE = 256, + IPC_FEATURE_EVENT_OUTPUT = 512, + IPC_FEATURE_EVENT_MODE = 1024, + IPC_FEATURE_EVENT_WINDOW = 2048, + IPC_FEATURE_EVENT_BINDING = 4096, + IPC_FEATURE_EVENT_INPUT = 8192, + IPC_FEATURE_GET_CLIPBOARD = 16384, + + IPC_FEATURE_ALL_COMMANDS = 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 16384, + IPC_FEATURE_ALL_EVENTS = 256 | 512 | 1024 | 2048 | 4096 | 8192, + + IPC_FEATURE_ALL = IPC_FEATURE_ALL_COMMANDS | IPC_FEATURE_ALL_EVENTS, +}; + +struct ipc_policy { + char *program; + uint32_t features; +}; + +/** + * The configuration struct. The result of loading a config file. + */ +struct sway_config { + list_t *symbols; + list_t *modes; + list_t *bars; + list_t *cmd_queue; + list_t *workspace_outputs; + list_t *pid_workspaces; + list_t *output_configs; + list_t *input_configs; + list_t *criteria; + list_t *no_focus; + list_t *active_bar_modifiers; + struct sway_mode *current_mode; + struct bar_config *current_bar; + uint32_t floating_mod; + uint32_t dragging_key; + uint32_t resizing_key; + char *floating_scroll_up_cmd; + char *floating_scroll_down_cmd; + char *floating_scroll_left_cmd; + char *floating_scroll_right_cmd; + enum swayc_layouts default_orientation; + enum swayc_layouts default_layout; + char *font; + int font_height; + + // Flags + bool focus_follows_mouse; + bool mouse_warping; + bool force_focus_wrapping; + bool active; + bool failed; + bool reloading; + bool reading; + bool auto_back_and_forth; + bool seamless_mouse; + bool show_marks; + + bool edge_gaps; + bool smart_gaps; + int gaps_inner; + int gaps_outer; + + list_t *config_chain; + const char *current_config; + + enum swayc_border_types border; + enum swayc_border_types floating_border; + int border_thickness; + int floating_border_thickness; + enum edge_border_types hide_edge_borders; + + // border colors + struct { + struct border_colors focused; + struct border_colors focused_inactive; + struct border_colors unfocused; + struct border_colors urgent; + struct border_colors placeholder; + uint32_t background; + } border_colors; + + // floating view + int32_t floating_maximum_width; + int32_t floating_maximum_height; + int32_t floating_minimum_width; + int32_t floating_minimum_height; + + // Security + list_t *command_policies; + list_t *feature_policies; + list_t *ipc_policies; +}; + +void pid_workspace_add(struct pid_workspace *pw); +void free_pid_workspace(struct pid_workspace *pw); + +/** + * Loads the main config from the given path. is_active should be true when + * reloading the config. + */ +bool load_main_config(const char *path, bool is_active); + +/** + * Loads an included config. Can only be used after load_main_config. + */ +bool load_include_configs(const char *path, struct sway_config *config); + +/** + * Reads the config from the given FILE. + */ +bool read_config(FILE *file, struct sway_config *config); + +/** + * Free config struct + */ +void free_config(struct sway_config *config); +/** + * Does variable replacement for a string based on the config's currently loaded variables. + */ +char *do_var_replacement(char *str); + +struct cmd_results *check_security_config(); + +int input_identifier_cmp(const void *item, const void *data); +void merge_input_config(struct input_config *dst, struct input_config *src); +void apply_input_config(struct input_config *ic, struct libinput_device *dev); +void free_input_config(struct input_config *ic); + +int output_name_cmp(const void *item, const void *data); +void merge_output_config(struct output_config *dst, struct output_config *src); +/** Sets up a WLC output handle based on a given output_config. + */ +void apply_output_config(struct output_config *oc, swayc_t *output); +void free_output_config(struct output_config *oc); + +/** + * Updates the list of active bar modifiers + */ +void update_active_bar_modifiers(void); + +int workspace_output_cmp_workspace(const void *a, const void *b); + +int sway_binding_cmp(const void *a, const void *b); +int sway_binding_cmp_qsort(const void *a, const void *b); +int sway_binding_cmp_keys(const void *a, const void *b); +void free_sway_binding(struct sway_binding *sb); +struct sway_binding *sway_binding_dup(struct sway_binding *sb); + +int sway_mouse_binding_cmp(const void *a, const void *b); +int sway_mouse_binding_cmp_qsort(const void *a, const void *b); +int sway_mouse_binding_cmp_buttons(const void *a, const void *b); +void free_sway_mouse_binding(struct sway_mouse_binding *smb); + +void load_swaybars(); +void terminate_swaybg(pid_t pid); + +/** + * Allocate and initialize default bar configuration. + */ +struct bar_config *default_bar_config(void); + +/** + * Global config singleton. + */ +extern struct sway_config *config; + +/** + * Config file currently being read. + */ +extern const char *current_config_path; + +#endif diff --git a/include/sway/old/container.h b/include/sway/old/container.h new file mode 100644 index 00000000..d46ffa63 --- /dev/null +++ b/include/sway/old/container.h @@ -0,0 +1,362 @@ +#ifndef _SWAY_CONTAINER_H +#define _SWAY_CONTAINER_H +#include +#include +#include +#include +#include "list.h" + +typedef struct sway_container swayc_t; + +extern swayc_t root_container; +extern swayc_t *current_focus; + +struct sway_view; + +/** + * Different kinds of containers. + * + * This enum is in order. A container will never be inside of a container below + * it on this list. + */ +enum swayc_types { + C_ROOT, /**< The root container. Only one of these ever exists. */ + C_OUTPUT, /**< An output (aka monitor, head, etc). */ + C_WORKSPACE, /**< A workspace. */ + C_CONTAINER, /**< A manually created container. */ + C_VIEW, /**< A view (aka window). */ + // Keep last + C_TYPES, +}; + +/** + * Different ways to arrange a container. + */ +enum swayc_layouts { + L_NONE, /**< Used for containers that have no layout (views, root) */ + L_HORIZ, + L_VERT, + L_STACKED, + L_TABBED, + L_FLOATING, /**< A psuedo-container, removed from the tree, to hold floating windows */ + + /* Awesome/Monad style auto layouts */ + L_AUTO_LEFT, + L_AUTO_RIGHT, + L_AUTO_TOP, + L_AUTO_BOTTOM, + + L_AUTO_FIRST = L_AUTO_LEFT, + L_AUTO_LAST = L_AUTO_BOTTOM, + + // Keep last + L_LAYOUTS, +}; + +enum swayc_border_types { + B_NONE, /**< No border */ + B_PIXEL, /**< 1px border */ + B_NORMAL /**< Normal border with title bar */ +}; + +/** + * Stores information about a container. + * + * The tree is made of these. Views are containers that cannot have children. + */ +struct sway_container { + // TODO WLR: reconcile these + wlc_handle handle; + + union { + struct sway_output *output; + struct sway_view *view; + } _handle; + + /** + * A unique ID to identify this container. Primarily used in the + * get_tree JSON output. + */ + size_t id; + + enum swayc_types type; + enum swayc_layouts layout; + enum swayc_layouts prev_layout; + enum swayc_layouts workspace_layout; + + /** + * Width and height of this container, without borders or gaps. + */ + double width, height; + + /** + * Views may request geometry, which is stored in this and ignored until + * the views are floated. + */ + int desired_width, desired_height; + + /** + * The coordinates that this view appear at, relative to the output they + * are located on (output containers have absolute coordinates). + */ + double x, y; + + /** + * Cached geometry used to store view/container geometry when switching + * between tabbed/stacked and horizontal/vertical layouts. + */ + struct wlc_geometry cached_geometry; + + /** + * False if this view is invisible. It could be in the scratchpad or on a + * workspace that is not shown. + */ + bool visible; + bool is_floating; + bool is_focused; + bool sticky; // floating view always visible on its output + + // Attributes that mostly views have. + char *name; + char *class; + char *instance; + char *app_id; + + // Used by output containers to keep track of swaybg child processes. + pid_t bg_pid; + + int gaps; + + list_t *children; + /** + * Children of this container that are floated. + */ + list_t *floating; + /** + * Unmanaged view handles in this container. + */ + list_t *unmanaged; + + /** + * The parent of this container. NULL for the root container. + */ + struct sway_container *parent; + /** + * Which of this container's children has focus. + */ + struct sway_container *focused; + /** + * If this container's children include a fullscreen view, this is that view. + */ + struct sway_container *fullscreen; + /** + * If this container is a view, this may be set to the window's decoration + * buffer (or NULL). + */ + struct border *border; + enum swayc_border_types border_type; + struct wlc_geometry border_geometry; + struct wlc_geometry title_bar_geometry; + struct wlc_geometry actual_geometry; + int border_thickness; + + /** + * Number of master views in auto layouts. + */ + size_t nb_master; + + /** + * Number of slave groups (e.g. columns) in auto layouts. + */ + size_t nb_slave_groups; + + /** + * Marks applied to the container, list_t of char*. + */ + list_t *marks; +}; + +enum visibility_mask { + VISIBLE = true +} visible; + +struct sway_output; +/** + * Allocates a new output container. + */ +swayc_t *new_output(struct sway_output *sway_output); +/** + * Allocates a new workspace container. + */ +swayc_t *new_workspace(swayc_t *output, const char *name); +/** + * Allocates a new container and places a child into it. + * + * This is used from the split command, which creates a new container with the + * requested layout and replaces the focused container in the tree with the new + * one. Then the removed container is added as a child of the new container. + */ +swayc_t *new_container(swayc_t *child, enum swayc_layouts layout); +/** + * Allocates a new view container. + * + * Pass in a sibling view, or a workspace to become this container's parent. + */ +swayc_t *new_view(swayc_t *sibling, struct sway_view *view); +/** + * Allocates a new floating view in the active workspace. + */ +swayc_t *new_floating_view(wlc_handle handle); + +void floating_view_sane_size(swayc_t *view); + +/** + * Frees an output's container. + */ +swayc_t *destroy_output(swayc_t *output); +/** + * Destroys a workspace container and returns the parent pointer, or NULL. + */ +swayc_t *destroy_workspace(swayc_t *workspace); +/** + * Destroys a container and all empty parents. Returns the topmost non-empty + * parent container, or NULL. + */ +swayc_t *destroy_container(swayc_t *container); +/** + * Destroys a view container and all empty parents. Returns the topmost + * non-empty parent container, or NULL. + */ +swayc_t *destroy_view(swayc_t *view); + +/** + * Finds a container based on test criteria. Returns the first container that + * passes the test. + */ +swayc_t *swayc_by_test(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data); +/** + * Finds a parent container with the given swayc_type. + */ +swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types); +/** + * Finds a parent with the given swayc_layout. + */ +swayc_t *swayc_parent_by_layout(swayc_t *container, enum swayc_layouts); +/** + * Finds the bottom-most focused container of a type. + */ +swayc_t *swayc_focus_by_type(swayc_t *container, enum swayc_types); +/** + * Finds the bottom-most focused container of a layout. + */ +swayc_t *swayc_focus_by_layout(swayc_t *container, enum swayc_layouts); + +/** + * Gets the swayc_t associated with a wlc_handle. + */ +swayc_t *swayc_by_handle(wlc_handle handle); +/** + * Gets the named swayc_t. + */ +swayc_t *swayc_by_name(const char *name); +/** + * Gets the active output's container. + */ +swayc_t *swayc_active_output(void); +/** + * Gets the active workspace's container. + */ +swayc_t *swayc_active_workspace(void); +/** + * Gets the workspace for the given view container. + */ +swayc_t *swayc_active_workspace_for(swayc_t *view); +/** + * Finds the container currently underneath the pointer. + */ +swayc_t *container_under_pointer(void); +/** + * Finds the first container following a callback. + */ +swayc_t *container_find(swayc_t *container, bool (*f)(swayc_t *, const void *), const void *data); + +/** + * Returns true if a container is fullscreen. + */ +bool swayc_is_fullscreen(swayc_t *view); +/** + * Returns true if this view is focused. + */ +bool swayc_is_active(swayc_t *view); +/** + * Returns true if the parent is an ancestor of the child. + */ +bool swayc_is_parent_of(swayc_t *parent, swayc_t *child); +/** + * Returns true if the child is a desecendant of the parent. + */ +bool swayc_is_child_of(swayc_t *child, swayc_t *parent); + +/** + * Returns true if this container is an empty workspace. + */ +bool swayc_is_empty_workspace(swayc_t *container); + +/** + * Returns the top most tabbed or stacked parent container. Returns NULL if + * view is not in a tabbed/stacked layout. + */ +swayc_t *swayc_tabbed_stacked_ancestor(swayc_t *view); + +/** + * Returns the immediate tabbed or stacked parent container. Returns NULL if + * view is not directly in a tabbed/stacked layout. + */ +swayc_t *swayc_tabbed_stacked_parent(swayc_t *view); + +/** + * Returns the gap (padding) of the container. + * + * This returns the inner gaps for a view, the outer gaps for a workspace, and + * 0 otherwise. + */ +int swayc_gap(swayc_t *container); + +/** + * Maps a container's children over a function. + */ +void container_map(swayc_t *, void (*f)(swayc_t *, void *), void *); + +/** + * Set a view as visible or invisible. + * + * This will perform the required wlc calls as well; it is not sufficient to + * simply toggle the boolean in swayc_t. + */ +void set_view_visibility(swayc_t *view, void *data); +/** + * Set the gaps value for a view. + */ +void set_gaps(swayc_t *view, void *amount); +/** + * Add to the gaps value for a view. + */ +void add_gaps(swayc_t *view, void *amount); + +/** + * Issue wlc calls to make the visibility of a container consistent. + */ +void update_visibility(swayc_t *container); + +/** + * Close all child views of container + */ +void close_views(swayc_t *container); + +/** + * Assign layout to a container. Needed due to workspace container specifics. + * Workspace should always have either L_VERT or L_HORIZ layout. + */ +swayc_t *swayc_change_layout(swayc_t *container, enum swayc_layouts layout); + +#endif diff --git a/include/sway/old/criteria.h b/include/sway/old/criteria.h new file mode 100644 index 00000000..c5ed9857 --- /dev/null +++ b/include/sway/old/criteria.h @@ -0,0 +1,42 @@ +#ifndef _SWAY_CRITERIA_H +#define _SWAY_CRITERIA_H + +#include "container.h" +#include "list.h" + +/** + * Maps criteria (as a list of criteria tokens) to a command list. + * + * A list of tokens together represent a single criteria string (e.g. + * '[class="abc" title="xyz"]' becomes two criteria tokens). + * + * for_window: Views matching all criteria will have the bound command list + * executed on them. + * + * Set via `for_window `. + */ +struct criteria { + list_t *tokens; // struct crit_token, contains compiled regex. + char *crit_raw; // entire criteria string (for logging) + + char *cmdlist; +}; + +int criteria_cmp(const void *item, const void *data); +void free_criteria(struct criteria *crit); + +// Pouplate list with crit_tokens extracted from criteria string, returns error +// string or NULL if successful. +char *extract_crit_tokens(list_t *tokens, const char *criteria); + +// Returns list of criteria that match given container. These criteria have +// been set with `for_window` commands and have an associated cmdlist. +list_t *criteria_for(swayc_t *cont); + +// Returns a list of all containers that match the given list of tokens. +list_t *container_for(list_t *tokens); + +// Returns true if any criteria in the given list matches this container +bool criteria_any(swayc_t *cont, list_t *criteria); + +#endif diff --git a/include/sway/old/focus.h b/include/sway/old/focus.h new file mode 100644 index 00000000..652cdccc --- /dev/null +++ b/include/sway/old/focus.h @@ -0,0 +1,45 @@ +#ifndef _SWAY_FOCUS_H +#define _SWAY_FOCUS_H +enum movement_direction { + MOVE_LEFT, + MOVE_RIGHT, + MOVE_UP, + MOVE_DOWN, + MOVE_PARENT, + MOVE_CHILD, + MOVE_NEXT, + MOVE_PREV, + MOVE_FIRST +}; + +#include "container.h" + +// focused_container - the container found by following the `focused` pointer +// from a given container to a container with `is_focused` boolean set +// --- +// focused_view - the container found by following the `focused` pointer from a +// given container to a view. +// --- + +swayc_t *get_focused_container(swayc_t *parent); +swayc_t *get_focused_view(swayc_t *parent); +swayc_t *get_focused_float(swayc_t *ws); + +// a special-case function to get the focused view, regardless +// of whether it's tiled or floating +swayc_t *get_focused_view_include_floating(swayc_t *parent); + +bool set_focused_container(swayc_t *container); +bool set_focused_container_for(swayc_t *ancestor, swayc_t *container); + +// lock focused container/view. locked by windows with OVERRIDE attribute +// and unlocked when they are destroyed + +extern bool locked_container_focus; + +// Prevents wss from being destroyed on focus switch +extern bool suspend_workspace_cleanup; + +bool move_focus(enum movement_direction direction); + +#endif diff --git a/include/sway/old/input.h b/include/sway/old/input.h new file mode 100644 index 00000000..eb92e470 --- /dev/null +++ b/include/sway/old/input.h @@ -0,0 +1,24 @@ +#ifndef _SWAY_INPUT_H +#define _SWAY_INPUT_H +#include +#include "sway/server.h" +#include "config.h" +#include "list.h" + +struct sway_input { + list_t *input_devices; +}; + +struct input_config *new_input_config(const char* identifier); + +char* libinput_dev_unique_id(struct libinput_device *dev); + +struct sway_input *sway_input_create(struct sway_server *server); + +/** + * Pointer used when reading input blocked. + * Shared so that it can be cleared from commands.c when closing the block + */ +extern struct input_config *current_input_config; + +#endif diff --git a/include/sway/old/input_state.h b/include/sway/old/input_state.h new file mode 100644 index 00000000..fd5a3a25 --- /dev/null +++ b/include/sway/old/input_state.h @@ -0,0 +1,102 @@ +#ifndef _SWAY_KEY_STATE_H +#define _SWAY_KEY_STATE_H +#include +#include +#include "container.h" + +/* Keyboard state */ + +// returns true if key has been pressed, otherwise false +bool check_key(uint32_t key_sym, uint32_t key_code); + +// returns true if key_sym matches latest released key. +bool check_released_key(uint32_t key_sym); + +// sets a key as pressed +void press_key(uint32_t key_sym, uint32_t key_code); + +// unsets a key as pressed +void release_key(uint32_t key_sym, uint32_t key_code); + + +/* Pointer state */ + +enum pointer_values { + M_LEFT_CLICK = 272, + M_RIGHT_CLICK = 273, + M_SCROLL_CLICK = 274, + M_SCROLL_UP = 275, + M_SCROLL_DOWN = 276, +}; + +enum pointer_mode { + // Target + M_FLOATING = 1, + M_TILING = 2, + // Action + M_DRAGGING = 4, + M_RESIZING = 8, +}; + +struct pointer_button_state { + bool held; + // state at the point it was pressed + int x, y; + swayc_t *view; +}; + +extern struct pointer_state { + // mouse clicks + struct pointer_button_state left; + struct pointer_button_state right; + struct pointer_button_state scroll; + + // change in pointer position + struct { + int x, y; + } delta; + + // view pointer is currently over + swayc_t *view; + + // Pointer mode + int mode; +} pointer_state; + +enum modifier_state { + MOD_STATE_UNCHANGED = 0, + MOD_STATE_PRESSED = 1, + MOD_STATE_RELEASED = 2 +}; + +void pointer_position_set(double new_x, double new_y, bool force_focus); +void center_pointer_on(swayc_t *view); + +// on button release unset mode depending on the button. +// on button press set mode conditionally depending on the button +void pointer_mode_set(uint32_t button, bool condition); + +// Update mode in mouse motion +void pointer_mode_update(void); + +// Reset mode on any keypress; +void pointer_mode_reset(void); + +void input_init(void); + +/** + * Check if state of mod changed from current state to new_state. + * + * Returns MOD_STATE_UNCHANGED if the state didn't change, MOD_STATE_PRESSED if + * the state changed to pressed and MOD_STATE_RELEASED if the state changed to + * released. + */ +uint32_t modifier_state_changed(uint32_t new_state, uint32_t mod); + +/** + * Update the current modifiers state to new_state. + */ +void modifiers_state_update(uint32_t new_state); + +#endif + diff --git a/include/sway/old/ipc-json.h b/include/sway/old/ipc-json.h new file mode 100644 index 00000000..3a5af0f5 --- /dev/null +++ b/include/sway/old/ipc-json.h @@ -0,0 +1,15 @@ +#ifndef _SWAY_IPC_JSON_H +#define _SWAY_IPC_JSON_H + +#include +#include "config.h" +#include "container.h" + +json_object *ipc_json_get_version(); +json_object *ipc_json_describe_bar_config(struct bar_config *bar); +json_object *ipc_json_describe_container(swayc_t *c); +json_object *ipc_json_describe_container_recursive(swayc_t *c); +json_object *ipc_json_describe_window(swayc_t *c); +json_object *ipc_json_describe_input(struct libinput_device *device); + +#endif diff --git a/include/sway/old/ipc-server.h b/include/sway/old/ipc-server.h new file mode 100644 index 00000000..0cc26d99 --- /dev/null +++ b/include/sway/old/ipc-server.h @@ -0,0 +1,33 @@ +#ifndef _SWAY_IPC_SERVER_H +#define _SWAY_IPC_SERVER_H +#include "container.h" +#include "config.h" +#include "ipc.h" + +void ipc_init(void); +void ipc_terminate(void); +struct sockaddr_un *ipc_user_sockaddr(void); + +void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change); +void ipc_event_barconfig_update(struct bar_config *bar); +/** + * Send IPC mode event to all listening clients + */ +void ipc_event_mode(const char *mode); +/** + * Send IPC window change event + */ +void ipc_event_window(swayc_t *window, const char *change); +/** + * Sends an IPC modifier event to all listening clients. The modifier event + * includes a key 'change' with the value of state and a key 'modifier' with + * the name of that modifier. + */ +void ipc_event_modifier(uint32_t modifier, const char *state); +/** + * Send IPC keyboard binding event. + */ +void ipc_event_binding_keyboard(struct sway_binding *sb); +const char *swayc_type_string(enum swayc_types type); + +#endif diff --git a/include/sway/old/layout.h b/include/sway/old/layout.h new file mode 100644 index 00000000..f0791588 --- /dev/null +++ b/include/sway/old/layout.h @@ -0,0 +1,85 @@ +#ifndef _SWAY_LAYOUT_H +#define _SWAY_LAYOUT_H + +#include +#include "log.h" +#include "list.h" +#include "container.h" +#include "focus.h" + +extern list_t *scratchpad; + +extern int min_sane_w; +extern int min_sane_h; + +// Set initial values for root_container +void init_layout(void); + +// Returns the index of child for its parent +int index_child(const swayc_t *child); + +// Adds child to parent, if parent has no focus, it is set to child +// parent must be of type C_WORKSPACE or C_CONTAINER +void add_child(swayc_t *parent, swayc_t *child); + +// Adds child to parent at index, if parent has no focus, it is set to child +// parent must be of type C_WORKSPACE or C_CONTAINER +void insert_child(swayc_t *parent, swayc_t *child, int index); + +// Adds child as floating window to ws, if there is no focus it is set to child. +// ws must be of type C_WORKSPACE +void add_floating(swayc_t *ws, swayc_t *child); + +// insert child after sibling in parents children. +swayc_t *add_sibling(swayc_t *sibling, swayc_t *child); + +// Replace child with new_child in parents children +// new_child will inherit childs geometry, childs geometry will be reset +// if parents focus is on child, it will be changed to new_child +swayc_t *replace_child(swayc_t *child, swayc_t *new_child); + +// Remove child from its parent, if focus is on child, focus will be changed to +// a sibling, or to a floating window, or NULL +swayc_t *remove_child(swayc_t *child); + +// 2 containers are swapped, they inherit eachothers focus +void swap_container(swayc_t *a, swayc_t *b); + +// 2 Containers geometry are swapped, used with `swap_container` +void swap_geometry(swayc_t *a, swayc_t *b); + +void move_container(swayc_t* container, enum movement_direction direction, int move_amt); +void move_container_to(swayc_t* container, swayc_t* destination); +void move_workspace_to(swayc_t* workspace, swayc_t* destination); + +// Layout +/** + * Update child container geometries when switching between layouts. + */ +void update_layout_geometry(swayc_t *parent, enum swayc_layouts prev_layout); +void update_geometry(swayc_t *view); +void arrange_windows(swayc_t *container, double width, double height); +void arrange_backgrounds(void); + +swayc_t *get_focused_container(swayc_t *parent); +swayc_t *get_swayc_in_direction(swayc_t *container, enum movement_direction dir); +swayc_t *get_swayc_in_direction_under(swayc_t *container, enum movement_direction dir, swayc_t *limit); + +void recursive_resize(swayc_t *container, double amount, enum wlc_resize_edge edge); + +void layout_log(const swayc_t *c, int depth); +void swayc_log(log_importance_t verbosity, swayc_t *cont, const char* format, ...) __attribute__((format(printf,3,4))); + +/** + * Get default layout. + */ +enum swayc_layouts default_layout(swayc_t *output); + +bool is_auto_layout(enum swayc_layouts layout); +int auto_group_start_index(const swayc_t *container, int index); +int auto_group_end_index(const swayc_t *container, int index); +size_t auto_group_count(const swayc_t *container); +size_t auto_group_index(const swayc_t *container, int index); +bool auto_group_bounds(const swayc_t *container, size_t group_index, int *start, int *end); + +#endif diff --git a/include/sway/old/output.h b/include/sway/old/output.h new file mode 100644 index 00000000..2a222238 --- /dev/null +++ b/include/sway/old/output.h @@ -0,0 +1,36 @@ +#ifndef _SWAY_OUTPUT_H +#define _SWAY_OUTPUT_H +#include +#include +#include +#include "container.h" +#include "focus.h" + +struct sway_server; + +struct sway_output { + struct wlr_output *wlr_output; + struct wl_listener frame; + struct sway_server *server; + struct timespec last_frame; +}; + +// Position is absolute coordinates on the edge where the adjacent output +// should be searched for. +swayc_t *output_by_name(const char* name, const struct wlc_point *abs_pos); +swayc_t *swayc_opposite_output(enum movement_direction dir, const struct wlc_point *abs_pos); +swayc_t *swayc_adjacent_output(swayc_t *output, enum movement_direction dir, const struct wlc_point *abs_pos, bool pick_closest); + +// Place absolute coordinates for given container into given wlc_point. +void get_absolute_position(swayc_t *container, struct wlc_point *point); + +// Place absolute coordinates for the center point of given container into +// given wlc_point. +void get_absolute_center_position(swayc_t *container, struct wlc_point *point); + +// stable sort workspaces on this output +void sort_workspaces(swayc_t *output); + +void output_get_scaled_size(wlc_handle handle, struct wlc_size *size); + +#endif diff --git a/include/sway/old/workspace.h b/include/sway/old/workspace.h new file mode 100644 index 00000000..c268fafa --- /dev/null +++ b/include/sway/old/workspace.h @@ -0,0 +1,22 @@ +#ifndef _SWAY_WORKSPACE_H +#define _SWAY_WORKSPACE_H + +#include +#include +#include "list.h" +#include "layout.h" + +extern char *prev_workspace_name; + +char *workspace_next_name(const char *output_name); +swayc_t *workspace_create(const char*); +swayc_t *workspace_by_name(const char*); +swayc_t *workspace_by_number(const char*); +bool workspace_switch(swayc_t*); +swayc_t *workspace_output_next(); +swayc_t *workspace_next(); +swayc_t *workspace_output_prev(); +swayc_t *workspace_prev(); +swayc_t *workspace_for_pid(pid_t pid); + +#endif diff --git a/include/sway/output.h b/include/sway/output.h index 2a222238..ffc6708d 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -3,34 +3,14 @@ #include #include #include -#include "container.h" -#include "focus.h" struct sway_server; struct sway_output { struct wlr_output *wlr_output; - struct wl_listener frame; struct sway_server *server; struct timespec last_frame; + struct wl_listener frame; }; -// Position is absolute coordinates on the edge where the adjacent output -// should be searched for. -swayc_t *output_by_name(const char* name, const struct wlc_point *abs_pos); -swayc_t *swayc_opposite_output(enum movement_direction dir, const struct wlc_point *abs_pos); -swayc_t *swayc_adjacent_output(swayc_t *output, enum movement_direction dir, const struct wlc_point *abs_pos, bool pick_closest); - -// Place absolute coordinates for given container into given wlc_point. -void get_absolute_position(swayc_t *container, struct wlc_point *point); - -// Place absolute coordinates for the center point of given container into -// given wlc_point. -void get_absolute_center_position(swayc_t *container, struct wlc_point *point); - -// stable sort workspaces on this output -void sort_workspaces(swayc_t *output); - -void output_get_scaled_size(wlc_handle handle, struct wlc_size *size); - #endif diff --git a/include/sway/workspace.h b/include/sway/workspace.h deleted file mode 100644 index c268fafa..00000000 --- a/include/sway/workspace.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _SWAY_WORKSPACE_H -#define _SWAY_WORKSPACE_H - -#include -#include -#include "list.h" -#include "layout.h" - -extern char *prev_workspace_name; - -char *workspace_next_name(const char *output_name); -swayc_t *workspace_create(const char*); -swayc_t *workspace_by_name(const char*); -swayc_t *workspace_by_number(const char*); -bool workspace_switch(swayc_t*); -swayc_t *workspace_output_next(); -swayc_t *workspace_next(); -swayc_t *workspace_output_prev(); -swayc_t *workspace_prev(); -swayc_t *workspace_for_pid(pid_t pid); - -#endif diff --git a/sway/CMakeLists.txt b/sway/CMakeLists.txt index f9209189..73531a84 100644 --- a/sway/CMakeLists.txt +++ b/sway/CMakeLists.txt @@ -1,6 +1,5 @@ include_directories( ${PROTOCOLS_INCLUDE_DIRS} - ${WLC_INCLUDE_DIRS} ${WLR_INCLUDE_DIRS} ${PCRE_INCLUDE_DIRS} ${JSONC_INCLUDE_DIRS} @@ -11,37 +10,12 @@ include_directories( ${WAYLAND_INCLUDE_DIR} ) -file(GLOB cmds - "commands/*.c" - "commands/bar/*.c" - "commands/input/*.c" -) - add_executable(sway desktop/output.c desktop/xdg_shell_v6.c - tree/container.c - tree/criteria.c - tree/focus.c - tree/output.c - tree/workspace.c - tree/layout.c - - input/input.c - - commands.c - ${cmds} - base64.c - config.c - debug_log.c - input_state.c - ipc-json.c - ipc-server.c main.c - border.c - security.c server.c ) @@ -53,7 +27,6 @@ target_link_libraries(sway sway-common sway-protocols sway-wayland - ${WLC_LIBRARIES} ${WLR_LIBRARIES} ${XKBCOMMON_LIBRARIES} ${PCRE_LIBRARIES} diff --git a/sway/border.c b/sway/border.c deleted file mode 100644 index df0022ce..00000000 --- a/sway/border.c +++ /dev/null @@ -1,510 +0,0 @@ -#define _XOPEN_SOURCE 700 -#include -#include -#include -#include -#include -#include -#include -#include -#include "sway/border.h" -#include "sway/container.h" -#include "sway/config.h" -#include "client/pango.h" - -void cairo_set_source_u32(cairo_t *cairo, uint32_t color) { - color = htonl(color); - - cairo_set_source_rgba(cairo, - (color >> (2*8) & 0xFF) / 255.0, - (color >> (1*8) & 0xFF) / 255.0, - (color >> (0*8) & 0xFF) / 255.0, - (color >> (3*8) & 0xFF) / 255.0); -} - -void border_clear(struct border *border) { - if (border && border->buffer) { - free(border->buffer); - border->buffer = NULL; - } -} - -static cairo_t *create_border_buffer(swayc_t *view, struct wlc_geometry g, cairo_surface_t **surface) { - if (view->border == NULL) { - view->border = malloc(sizeof(struct border)); - if (!view->border) { - sway_log(L_ERROR, "Unable to allocate window border information"); - return NULL; - } - } - cairo_t *cr; - int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, g.size.w); - view->border->buffer = calloc(stride * g.size.h, sizeof(unsigned char)); - view->border->geometry = g; - if (!view->border->buffer) { - sway_log(L_ERROR, "Unable to allocate window border buffer"); - return NULL; - } - *surface = cairo_image_surface_create_for_data(view->border->buffer, - CAIRO_FORMAT_ARGB32, g.size.w, g.size.h, stride); - if (cairo_surface_status(*surface) != CAIRO_STATUS_SUCCESS) { - border_clear(view->border); - sway_log(L_ERROR, "Unable to allocate window border surface"); - return NULL; - } - cr = cairo_create(*surface); - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - if (cairo_status(cr) != CAIRO_STATUS_SUCCESS) { - cairo_surface_destroy(*surface); - border_clear(view->border); - sway_log(L_ERROR, "Unable to create cairo context"); - return NULL; - } - return cr; -} - -// TODO: move to client/cairo.h when local set_source_u32 is fixed. -/** - * Renders a sharp line of any width and height. - * - * The line is drawn from (x,y) to (x+width,y+height) where width/height is 0 - * if the line has a width/height of one pixel, respectively. - */ -static void render_sharp_line(cairo_t *cairo, uint32_t color, double x, double y, double width, double height) { - cairo_set_source_u32(cairo, color); - - if (width > 1 && height > 1) { - cairo_rectangle(cairo, x, y, width, height); - cairo_fill(cairo); - } else { - if (width == 1) { - x += 0.5; - height += y; - width = x; - } - - if (height == 1) { - y += 0.5; - width += x; - height = y; - } - - cairo_move_to(cairo, x, y); - cairo_set_line_width(cairo, 1.0); - cairo_line_to(cairo, width, height); - cairo_stroke(cairo); - } -} - -int get_font_text_height(const char *font) { - cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 200, 200); - cairo_t *cr = cairo_create(surface); - int width, height; - get_text_size(cr, font, &width, &height, 1, false, "Gg"); - cairo_surface_destroy(surface); - cairo_destroy(cr); - return height; -} - -static void render_borders(swayc_t *view, cairo_t *cr, struct border_colors *colors, bool top) { - struct wlc_geometry *g = &view->border->geometry; - struct wlc_geometry *b = &view->border_geometry; - struct wlc_geometry *v = &view->actual_geometry; - enum swayc_layouts layout = view->parent->layout; - uint32_t color; - - int x = b->origin.x - g->origin.x; - int y = b->origin.y - g->origin.y; - - // draw vertical/horizontal indicator if container is the only child of its parent container - bool is_only_child = view->parent && view->parent->children && view->parent->children->length == 1; - - // left border - int left_border = v->origin.x - b->origin.x; - if (left_border > 0) { - render_sharp_line(cr, - colors->child_border, - x, y, - left_border, - b->size.h); - } - - // right border - int right_border = b->size.w - v->size.w - left_border; - if (right_border > 0) { - if (is_only_child && layout == L_HORIZ && !view->is_floating) { - color = colors->indicator; - } else { - color = colors->child_border; - } - render_sharp_line(cr, - color, - x + b->size.w - right_border, - y, - right_border, - b->size.h); - } - - // top border - int top_border = v->origin.y - b->origin.y; - if (top && top_border > 0) { - render_sharp_line(cr, - colors->child_border, - x, y, - b->size.w, - top_border); - } - - // bottom border - int bottom_border = b->size.h - (top_border + v->size.h); - if (bottom_border > 0) { - if (is_only_child && layout == L_VERT && !view->is_floating) { - color = colors->indicator; - } else { - color = colors->child_border; - } - render_sharp_line(cr, - color, - x, - y + b->size.h - bottom_border, - b->size.w, - bottom_border); - } -} - -static void render_title_bar(swayc_t *view, cairo_t *cr, struct wlc_geometry *b, struct border_colors *colors) { - struct wlc_geometry *tb = &view->title_bar_geometry; - int x = MIN(tb->origin.x, tb->origin.x - b->origin.x); - int y = MIN(tb->origin.y, tb->origin.y - b->origin.y); - - // title bar background - cairo_set_source_u32(cr, colors->background); - cairo_rectangle(cr, x, y, tb->size.w, tb->size.h); - cairo_fill(cr); - - // header top line - render_sharp_line(cr, colors->border, x, y, tb->size.w, 1); - - // text - if (view->name) { - int width, height; - get_text_size(cr, config->font, &width, &height, 1, false, "%s", view->name); - cairo_move_to(cr, x + 2, y + 2); - cairo_set_source_u32(cr, colors->text); - pango_printf(cr, config->font, 1, false, "%s", view->name); - } - // Marks - if (config->show_marks && view->marks) { - int total_len = 0; - - for(int i = view->marks->length - 1; i >= 0; --i) { - char *mark = (char *)view->marks->items[i]; - if (*mark != '_') { - int width, height; - get_text_size(cr, config->font, &width, &height, 1, false, "[%s]", mark); - total_len += width; - if ((int)tb->size.w + x - (total_len + 2) < x + 2) { - break; - } else { - cairo_move_to(cr, (int)tb->size.w + x - (total_len + 2), y + 2); - cairo_set_source_u32(cr, colors->text); - pango_printf(cr, config->font, 1, false, "[%s]", mark); - } - } - } - } - - // titlebars has a border all around for tabbed layouts - if (view->parent->layout == L_TABBED) { - // header bottom line - render_sharp_line(cr, colors->border, x, y + tb->size.h - 1, - tb->size.w, 1); - - // left border - render_sharp_line(cr, colors->border, x, y, 1, tb->size.h); - - // right border - render_sharp_line(cr, colors->border, x + tb->size.w - 1, y, - 1, tb->size.h); - - return; - } - - if ((uint32_t)(view->actual_geometry.origin.y - tb->origin.y) == tb->size.h) { - // header bottom line - render_sharp_line(cr, colors->border, - x + view->actual_geometry.origin.x - tb->origin.x, - y + tb->size.h - 1, - view->actual_geometry.size.w, 1); - } else { - // header bottom line - render_sharp_line(cr, colors->border, x, - y + tb->size.h - 1, - tb->size.w, 1); - } -} - -/** - * Generate nested container title for tabbed/stacked layouts - */ -static char *generate_container_title(swayc_t *container) { - char layout = 'H'; - char *name, *prev_name = NULL; - switch (container->layout) { - case L_TABBED: - layout = 'T'; - break; - case L_STACKED: - layout = 'S'; - break; - case L_VERT: - layout = 'V'; - break; - default: - layout = 'H'; - } - int len = 9; - name = malloc(len * sizeof(char)); - if (!name) { - sway_log(L_ERROR, "Unable to allocate container title"); - return NULL; - } - snprintf(name, len, "sway: %c[", layout); - - int i; - for (i = 0; i < container->children->length; ++i) { - prev_name = name; - swayc_t* child = container->children->items[i]; - const char *title = NULL; - if (child->type == C_VIEW) { - title = child->app_id ? child->app_id : - (child->instance ? child->instance : - (child->class ? child->class :"(null)")); - } else { //child->type == C_CONTAINER - title = generate_container_title(child); - } - - len = strlen(name) + strlen(title) + 1; - if (i < container->children->length-1) { - len++; - } - - name = malloc(len * sizeof(char)); - if (!name) { - free(prev_name); - sway_log(L_ERROR, "Unable to allocate container title"); - return NULL; - } - if (i < container->children->length-1) { - snprintf(name, len, "%s%s ", prev_name, title); - } else { - snprintf(name, len, "%s%s", prev_name, title); - } - free(prev_name); - } - - prev_name = name; - len = strlen(name) + 2; - name = malloc(len * sizeof(char)); - if (!name) { - free(prev_name); - sway_log(L_ERROR, "Unable to allocate container title"); - return NULL; - } - snprintf(name, len, "%s]", prev_name); - free(prev_name); - free(container->name); - container->name = name; - return container->name + 6; // don't include "sway: " -} - -void update_tabbed_stacked_titlebars(swayc_t *c, cairo_t *cr, struct wlc_geometry *g, swayc_t *focused, swayc_t *focused_inactive) { - if (c->type == C_CONTAINER) { - if (c->parent->focused == c) { - render_title_bar(c, cr, g, &config->border_colors.focused_inactive); - } else { - render_title_bar(c, cr, g, &config->border_colors.unfocused); - } - - if (!c->visible) { - return; - } - - int i; - for (i = 0; i < c->children->length; ++i) { - swayc_t *child = c->children->items[i]; - update_tabbed_stacked_titlebars(child, cr, g, focused, focused_inactive); - } - } else { - bool is_child_of_focused = swayc_is_child_of(c, get_focused_container(&root_container)); - - if (focused == c || is_child_of_focused) { - render_title_bar(c, cr, g, &config->border_colors.focused); - } else if (focused_inactive == c) { - render_title_bar(c, cr, g, &config->border_colors.focused_inactive); - } else { - render_title_bar(c, cr, g, &config->border_colors.unfocused); - } - } -} - -static void update_view_border(swayc_t *view) { - if (!view->visible) { - return; - } - - cairo_t *cr = NULL; - cairo_surface_t *surface = NULL; - - // clear previous border buffer. - border_clear(view->border); - - // get focused and focused_inactive views - swayc_t *focused = get_focused_view(&root_container); - swayc_t *container = swayc_parent_by_type(view, C_CONTAINER); - swayc_t *focused_inactive = NULL; - - bool is_child_of_focused = swayc_is_parent_of(get_focused_container(&root_container), view); - - if (container) { - focused_inactive = swayc_focus_by_type(container, C_VIEW); - } else { - container = swayc_parent_by_type(view, C_WORKSPACE); - if (container) { - focused_inactive = swayc_focus_by_type(container, C_VIEW); - } - } - - // for tabbed/stacked layouts the focused view has to draw all the - // titlebars of the hidden views. - swayc_t *p = NULL; - if (view->parent->focused == view && (p = swayc_tabbed_stacked_ancestor(view))) { - struct wlc_geometry g = { - .origin = { - .x = p->x, - .y = p->y - }, - .size = { - .w = p->width, - .h = p->height - } - }; - cr = create_border_buffer(view, g, &surface); - if (!cr) { - goto cleanup; - } - - bool render_top = !should_hide_top_border(view, view->y); - if (view == focused || is_child_of_focused) { - render_borders(view, cr, &config->border_colors.focused, render_top); - } else { - render_borders(view, cr, &config->border_colors.focused_inactive, render_top); - } - - // generate container titles - int i; - for (i = 0; i < p->children->length; ++i) { - swayc_t *child = p->children->items[i]; - if (child->type == C_CONTAINER) { - generate_container_title(child); - } - } - - update_tabbed_stacked_titlebars(p, cr, &g, focused, focused_inactive); - } else { - switch (view->border_type) { - case B_NONE: - break; - case B_PIXEL: - cr = create_border_buffer(view, view->border_geometry, &surface); - if (!cr) { - break; - } - - if (focused == view || is_child_of_focused) { - render_borders(view, cr, &config->border_colors.focused, true); - } else if (focused_inactive == view) { - render_borders(view, cr, &config->border_colors.focused_inactive, true); - } else { - render_borders(view, cr, &config->border_colors.unfocused, true); - } - - break; - case B_NORMAL: - cr = create_border_buffer(view, view->border_geometry, &surface); - if (!cr) { - break; - } - - if (focused == view || is_child_of_focused) { - render_borders(view, cr, &config->border_colors.focused, false); - render_title_bar(view, cr, &view->border_geometry, - &config->border_colors.focused); - } else if (focused_inactive == view) { - render_borders(view, cr, &config->border_colors.focused_inactive, false); - render_title_bar(view, cr, &view->border_geometry, - &config->border_colors.focused_inactive); - } else { - render_borders(view, cr, &config->border_colors.unfocused, false); - render_title_bar(view, cr, &view->border_geometry, - &config->border_colors.unfocused); - } - - break; - } - } - -cleanup: - - if (surface) { - cairo_surface_flush(surface); - cairo_surface_destroy(surface); - } - - if (cr) { - cairo_destroy(cr); - } -} - -void update_container_border(swayc_t *container) { - if (container->type == C_VIEW) { - update_view_border(container); - return; - } else { - for (int i = 0; i < container->children->length; ++i) { - update_container_border(container->children->items[i]); - } - } -} - -void render_view_borders(wlc_handle view) { - swayc_t *c = swayc_by_handle(view); - - - // emulate i3 behavior for drawing borders for tabbed and stacked layouts: - // if we are not the only child in the container, always draw borders, - // regardless of the border setting on the individual view - if (!c || (c->border_type == B_NONE - && !((c->parent->layout == L_TABBED || c->parent->layout == L_STACKED) - && c->parent->children->length > 1))) { - return; - } - - if (c->border && c->border->buffer) { - wlc_pixels_write(WLC_RGBA8888, &c->border->geometry, c->border->buffer); - } -} - -bool should_hide_top_border(swayc_t *con, double y) { - // returns true if container is child of tabbed/stacked layout and is - // sharing top border with tabbed titlebar - swayc_t *par = con->parent; - while (par->type != C_WORKSPACE) { - if (par->layout == L_TABBED || par->layout == L_STACKED) { - return con->y == y; - } - con = par; - par = par->parent; - } - return false; -} diff --git a/sway/commands.c b/sway/commands.c deleted file mode 100644 index e1181893..00000000 --- a/sway/commands.c +++ /dev/null @@ -1,686 +0,0 @@ -#define _XOPEN_SOURCE 700 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sway/layout.h" -#include "sway/focus.h" -#include "sway/workspace.h" -#include "sway/commands.h" -#include "sway/container.h" -#include "sway/output.h" -#include "sway/handlers.h" -#include "sway/input_state.h" -#include "sway/criteria.h" -#include "sway/ipc-server.h" -#include "sway/security.h" -#include "sway/input.h" -#include "sway/border.h" -#include "stringop.h" -#include "sway.h" -#include "util.h" -#include "list.h" -#include "log.h" - -struct cmd_handler { - char *command; - sway_cmd *handle; -}; - -int sp_index = 0; - -swayc_t *current_container = NULL; - -// Returns error object, or NULL if check succeeds. -struct cmd_results *checkarg(int argc, const char *name, enum expected_args type, int val) { - struct cmd_results *error = NULL; - switch (type) { - case EXPECTED_MORE_THAN: - if (argc > val) { - return NULL; - } - error = cmd_results_new(CMD_INVALID, name, "Invalid %s command " - "(expected more than %d argument%s, got %d)", - name, val, (char*[2]){"s", ""}[argc==1], argc); - break; - case EXPECTED_AT_LEAST: - if (argc >= val) { - return NULL; - } - error = cmd_results_new(CMD_INVALID, name, "Invalid %s command " - "(expected at least %d argument%s, got %d)", - name, val, (char*[2]){"s", ""}[argc==1], argc); - break; - case EXPECTED_LESS_THAN: - if (argc < val) { - return NULL; - }; - error = cmd_results_new(CMD_INVALID, name, "Invalid %s command " - "(expected less than %d argument%s, got %d)", - name, val, (char*[2]){"s", ""}[argc==1], argc); - break; - case EXPECTED_EQUAL_TO: - if (argc == val) { - return NULL; - }; - error = cmd_results_new(CMD_INVALID, name, "Invalid %s command " - "(expected %d arguments, got %d)", name, val, argc); - break; - } - return error; -} - -void hide_view_in_scratchpad(swayc_t *sp_view) { - if (sp_view == NULL) { - return; - } - - wlc_view_set_mask(sp_view->handle, 0); - sp_view->visible = false; - swayc_t *ws = sp_view->parent; - remove_child(sp_view); - if (swayc_active_workspace() != ws && ws->floating->length == 0 && ws->children->length == 0) { - destroy_workspace(ws); - } else { - arrange_windows(ws, -1, -1); - } - set_focused_container(container_under_pointer()); -} - -void input_cmd_apply(struct input_config *input) { - int i; - i = list_seq_find(config->input_configs, input_identifier_cmp, input->identifier); - if (i >= 0) { - // merge existing config - struct input_config *ic = config->input_configs->items[i]; - merge_input_config(ic, input); - free_input_config(input); - input = ic; - } else { - list_add(config->input_configs, input); - } - - current_input_config = input; - - if (input->identifier) { - // Try to find the input device and apply configuration now. If - // this is during startup then there will be no container and config - // will be applied during normal "new input" event from wlc. - /* TODO WLR - struct libinput_device *device = NULL; - for (int i = 0; i < input_devices->length; ++i) { - device = input_devices->items[i]; - char* dev_identifier = libinput_dev_unique_id(device); - if (!dev_identifier) { - break; - } - int match = dev_identifier && strcmp(dev_identifier, input->identifier) == 0; - free(dev_identifier); - if (match) { - apply_input_config(input, device); - break; - } - } - */ - } -} - -void remove_view_from_scratchpad(swayc_t *view) { - int i; - for (i = 0; i < scratchpad->length; i++) { - if (scratchpad->items[i] == view) { - if (sp_index == 0) { - sp_index = scratchpad->length - 1; - } else { - sp_index--; - } - list_del(scratchpad, sp_index); - sp_view = NULL; - } - } -} - -/* Keep alphabetized */ -static struct cmd_handler handlers[] = { - { "assign", cmd_assign }, - { "bar", cmd_bar }, - { "bindcode", cmd_bindcode }, - { "bindsym", cmd_bindsym }, - { "border", cmd_border }, - { "client.background", cmd_client_background }, - { "client.focused", cmd_client_focused }, - { "client.focused_inactive", cmd_client_focused_inactive }, - { "client.placeholder", cmd_client_placeholder }, - { "client.unfocused", cmd_client_unfocused }, - { "client.urgent", cmd_client_urgent }, - { "clipboard", cmd_clipboard }, - { "commands", cmd_commands }, - { "debuglog", cmd_debuglog }, - { "default_border", cmd_default_border }, - { "default_floating_border", cmd_default_floating_border }, - { "default_orientation", cmd_orientation }, - { "exec", cmd_exec }, - { "exec_always", cmd_exec_always }, - { "exit", cmd_exit }, - { "floating", cmd_floating }, - { "floating_maximum_size", cmd_floating_maximum_size }, - { "floating_minimum_size", cmd_floating_minimum_size }, - { "floating_modifier", cmd_floating_mod }, - { "floating_scroll", cmd_floating_scroll }, - { "focus", cmd_focus }, - { "focus_follows_mouse", cmd_focus_follows_mouse }, - { "font", cmd_font }, - { "for_window", cmd_for_window }, - { "force_focus_wrapping", cmd_force_focus_wrapping }, - { "fullscreen", cmd_fullscreen }, - { "gaps", cmd_gaps }, - { "hide_edge_borders", cmd_hide_edge_borders }, - { "include", cmd_include }, - { "input", cmd_input }, - { "ipc", cmd_ipc }, - { "kill", cmd_kill }, - { "layout", cmd_layout }, - { "log_colors", cmd_log_colors }, - { "mark", cmd_mark }, - { "mode", cmd_mode }, - { "mouse_warping", cmd_mouse_warping }, - { "move", cmd_move }, - { "new_float", cmd_new_float }, - { "new_window", cmd_new_window }, - { "no_focus", cmd_no_focus }, - { "output", cmd_output }, - { "permit", cmd_permit }, - { "reject", cmd_reject }, - { "reload", cmd_reload }, - { "resize", cmd_resize }, - { "scratchpad", cmd_scratchpad }, - { "seamless_mouse", cmd_seamless_mouse }, - { "set", cmd_set }, - { "show_marks", cmd_show_marks }, - { "smart_gaps", cmd_smart_gaps }, - { "split", cmd_split }, - { "splith", cmd_splith }, - { "splitt", cmd_splitt }, - { "splitv", cmd_splitv }, - { "sticky", cmd_sticky }, - { "unmark", cmd_unmark }, - { "workspace", cmd_workspace }, - { "workspace_auto_back_and_forth", cmd_ws_auto_back_and_forth }, - { "workspace_layout", cmd_workspace_layout }, -}; - -static struct cmd_handler bar_handlers[] = { - { "activate_button", bar_cmd_activate_button }, - { "binding_mode_indicator", bar_cmd_binding_mode_indicator }, - { "bindsym", bar_cmd_bindsym }, - { "colors", bar_cmd_colors }, - { "context_button", bar_cmd_context_button }, - { "font", bar_cmd_font }, - { "height", bar_cmd_height }, - { "hidden_state", bar_cmd_hidden_state }, - { "icon_theme", bar_cmd_icon_theme }, - { "id", bar_cmd_id }, - { "mode", bar_cmd_mode }, - { "modifier", bar_cmd_modifier }, - { "output", bar_cmd_output }, - { "pango_markup", bar_cmd_pango_markup }, - { "position", bar_cmd_position }, - { "secondary_button", bar_cmd_secondary_button }, - { "separator_symbol", bar_cmd_separator_symbol }, - { "status_command", bar_cmd_status_command }, - { "strip_workspace_numbers", bar_cmd_strip_workspace_numbers }, - { "swaybar_command", bar_cmd_swaybar_command }, - { "tray_output", bar_cmd_tray_output }, - { "tray_padding", bar_cmd_tray_padding }, - { "workspace_buttons", bar_cmd_workspace_buttons }, - { "wrap_scroll", bar_cmd_wrap_scroll }, -}; - -/** - * Check and add color to buffer. - * - * return error object, or NULL if color is valid. - */ -struct cmd_results *add_color(const char *name, char *buffer, const char *color) { - int len = strlen(color); - if (len != 7 && len != 9) { - return cmd_results_new(CMD_INVALID, name, "Invalid color definition %s", color); - } - - if (color[0] != '#') { - return cmd_results_new(CMD_INVALID, name, "Invalid color definition %s", color); - } - - int i; - for (i = 1; i < len; ++i) { - if (!isxdigit(color[i])) { - return cmd_results_new(CMD_INVALID, name, "Invalid color definition %s", color); - } - } - - // copy color to buffer - strncpy(buffer, color, len); - // add default alpha channel if color was defined without it - if (len == 7) { - buffer[7] = 'f'; - buffer[8] = 'f'; - } - buffer[9] = '\0'; - - return NULL; -} - -static struct cmd_handler input_handlers[] = { - { "accel_profile", input_cmd_accel_profile }, - { "click_method", input_cmd_click_method }, - { "drag_lock", input_cmd_drag_lock }, - { "dwt", input_cmd_dwt }, - { "events", input_cmd_events }, - { "left_handed", input_cmd_left_handed }, - { "middle_emulation", input_cmd_middle_emulation }, - { "natural_scroll", input_cmd_natural_scroll }, - { "pointer_accel", input_cmd_pointer_accel }, - { "scroll_method", input_cmd_scroll_method }, - { "tap", input_cmd_tap }, -}; - -static struct cmd_handler bar_colors_handlers[] = { - { "active_workspace", bar_colors_cmd_active_workspace }, - { "background", bar_colors_cmd_background }, - { "binding_mode", bar_colors_cmd_binding_mode }, - { "focused_background", bar_colors_cmd_focused_background }, - { "focused_separator", bar_colors_cmd_focused_separator }, - { "focused_statusline", bar_colors_cmd_focused_statusline }, - { "focused_workspace", bar_colors_cmd_focused_workspace }, - { "inactive_workspace", bar_colors_cmd_inactive_workspace }, - { "separator", bar_colors_cmd_separator }, - { "statusline", bar_colors_cmd_statusline }, - { "urgent_workspace", bar_colors_cmd_urgent_workspace }, -}; - -static struct cmd_handler ipc_handlers[] = { - { "*", cmd_ipc_cmd }, - { "bar-config", cmd_ipc_cmd }, - { "command", cmd_ipc_cmd }, - { "events", cmd_ipc_events }, - { "inputs", cmd_ipc_cmd }, - { "marks", cmd_ipc_cmd }, - { "outputs", cmd_ipc_cmd }, - { "tree", cmd_ipc_cmd }, - { "workspaces", cmd_ipc_cmd }, -}; - -static struct cmd_handler ipc_event_handlers[] = { - { "*", cmd_ipc_event_cmd }, - { "binding", cmd_ipc_event_cmd }, - { "input", cmd_ipc_event_cmd }, - { "mode", cmd_ipc_event_cmd }, - { "output", cmd_ipc_event_cmd }, - { "window", cmd_ipc_event_cmd }, - { "workspace", cmd_ipc_event_cmd }, -}; - -static int handler_compare(const void *_a, const void *_b) { - const struct cmd_handler *a = _a; - const struct cmd_handler *b = _b; - return strcasecmp(a->command, b->command); -} - -static struct cmd_handler *find_handler(char *line, enum cmd_status block) { - struct cmd_handler d = { .command=line }; - struct cmd_handler *res = NULL; - sway_log(L_DEBUG, "find_handler(%s) %d", line, block == CMD_BLOCK_INPUT); - if (block == CMD_BLOCK_BAR) { - res = bsearch(&d, bar_handlers, - sizeof(bar_handlers) / sizeof(struct cmd_handler), - sizeof(struct cmd_handler), handler_compare); - } else if (block == CMD_BLOCK_BAR_COLORS){ - res = bsearch(&d, bar_colors_handlers, - sizeof(bar_colors_handlers) / sizeof(struct cmd_handler), - sizeof(struct cmd_handler), handler_compare); - } else if (block == CMD_BLOCK_INPUT) { - res = bsearch(&d, input_handlers, - sizeof(input_handlers) / sizeof(struct cmd_handler), - sizeof(struct cmd_handler), handler_compare); - } else if (block == CMD_BLOCK_IPC) { - res = bsearch(&d, ipc_handlers, - sizeof(ipc_handlers) / sizeof(struct cmd_handler), - sizeof(struct cmd_handler), handler_compare); - } else if (block == CMD_BLOCK_IPC_EVENTS) { - res = bsearch(&d, ipc_event_handlers, - sizeof(ipc_event_handlers) / sizeof(struct cmd_handler), - sizeof(struct cmd_handler), handler_compare); - } else { - res = bsearch(&d, handlers, - sizeof(handlers) / sizeof(struct cmd_handler), - sizeof(struct cmd_handler), handler_compare); - } - return res; -} - -struct cmd_results *handle_command(char *_exec, enum command_context context) { - // Even though this function will process multiple commands we will only - // return the last error, if any (for now). (Since we have access to an - // error string we could e.g. concatonate all errors there.) - struct cmd_results *results = NULL; - char *exec = strdup(_exec); - char *head = exec; - char *cmdlist; - char *cmd; - list_t *containers = NULL; - - head = exec; - do { - // Extract criteria (valid for this command list only). - if (*head == '[') { - ++head; - char *criteria_string = argsep(&head, "]"); - if (head) { - ++head; - list_t *tokens = create_list(); - char *error; - - if ((error = extract_crit_tokens(tokens, criteria_string))) { - results = cmd_results_new(CMD_INVALID, criteria_string, - "Can't parse criteria string: %s", error); - free(error); - free(tokens); - goto cleanup; - } - containers = container_for(tokens); - - free(tokens); - } else { - if (!results) { - results = cmd_results_new(CMD_INVALID, criteria_string, "Unmatched ["); - } - goto cleanup; - } - // Skip leading whitespace - head += strspn(head, whitespace); - } - // Split command list - cmdlist = argsep(&head, ";"); - cmdlist += strspn(cmdlist, whitespace); - do { - // Split commands - cmd = argsep(&cmdlist, ","); - cmd += strspn(cmd, whitespace); - if (strcmp(cmd, "") == 0) { - sway_log(L_INFO, "Ignoring empty command."); - continue; - } - sway_log(L_INFO, "Handling command '%s'", cmd); - //TODO better handling of argv - int argc; - char **argv = split_args(cmd, &argc); - if (strcmp(argv[0], "exec") != 0) { - int i; - for (i = 1; i < argc; ++i) { - if (*argv[i] == '\"' || *argv[i] == '\'') { - strip_quotes(argv[i]); - } - } - } - struct cmd_handler *handler = find_handler(argv[0], CMD_BLOCK_END); - if (!handler) { - if (results) { - free_cmd_results(results); - } - results = cmd_results_new(CMD_INVALID, cmd, "Unknown/invalid command"); - free_argv(argc, argv); - goto cleanup; - } - if (!(get_command_policy_mask(argv[0]) & context)) { - if (results) { - free_cmd_results(results); - } - results = cmd_results_new(CMD_INVALID, cmd, - "Permission denied for %s via %s", cmd, - command_policy_str(context)); - free_argv(argc, argv); - goto cleanup; - } - int i = 0; - do { - if (!containers) { - current_container = get_focused_container(&root_container); - } else if (containers->length == 0) { - if (results) { - free_cmd_results(results); - } - results = cmd_results_new(CMD_FAILURE, argv[0], "No matching container"); - goto cleanup; - } else { - current_container = (swayc_t *)containers->items[i]; - } - sway_log(L_INFO, "Running on container '%s'", current_container->name); - - struct cmd_results *res = handler->handle(argc-1, argv+1); - if (res->status != CMD_SUCCESS) { - free_argv(argc, argv); - if (results) { - free_cmd_results(results); - } - results = res; - goto cleanup; - } - free_cmd_results(res); - ++i; - } while(containers && i < containers->length); - - free_argv(argc, argv); - } while(cmdlist); - - if (containers) { - list_free(containers); - containers = NULL; - } - } while(head); - cleanup: - free(exec); - if (containers) { - free(containers); - } - if (!results) { - results = cmd_results_new(CMD_SUCCESS, NULL, NULL); - } - return results; -} - -// this is like handle_command above, except: -// 1) it ignores empty commands (empty lines) -// 2) it does variable substitution -// 3) it doesn't split commands (because the multiple commands are supposed to -// be chained together) -// 4) handle_command handles all state internally while config_command has some -// state handled outside (notably the block mode, in read_config) -struct cmd_results *config_command(char *exec, enum cmd_status block) { - struct cmd_results *results = NULL; - int argc; - char **argv = split_args(exec, &argc); - if (!argc) { - results = cmd_results_new(CMD_SUCCESS, NULL, NULL); - goto cleanup; - } - - sway_log(L_INFO, "handling config command '%s'", exec); - // Endblock - if (**argv == '}') { - results = cmd_results_new(CMD_BLOCK_END, NULL, NULL); - goto cleanup; - } - struct cmd_handler *handler = find_handler(argv[0], block); - if (!handler) { - char *input = argv[0] ? argv[0] : "(empty)"; - results = cmd_results_new(CMD_INVALID, input, "Unknown/invalid command"); - goto cleanup; - } - int i; - // Var replacement, for all but first argument of set - for (i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) { - argv[i] = do_var_replacement(argv[i]); - unescape_string(argv[i]); - } - /* Strip quotes for first argument. - * TODO This part needs to be handled much better */ - if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) { - strip_quotes(argv[1]); - } - if (handler->handle) { - results = handler->handle(argc-1, argv+1); - } else { - results = cmd_results_new(CMD_INVALID, argv[0], "This command is shimmed, but unimplemented"); - } - -cleanup: - free_argv(argc, argv); - return results; -} - -struct cmd_results *config_commands_command(char *exec) { - struct cmd_results *results = NULL; - int argc; - char **argv = split_args(exec, &argc); - if (!argc) { - results = cmd_results_new(CMD_SUCCESS, NULL, NULL); - goto cleanup; - } - - // Find handler for the command this is setting a policy for - char *cmd = argv[0]; - - if (strcmp(cmd, "}") == 0) { - results = cmd_results_new(CMD_BLOCK_END, NULL, NULL); - goto cleanup; - } - - struct cmd_handler *handler = find_handler(cmd, CMD_BLOCK_END); - if (!handler && strcmp(cmd, "*") != 0) { - char *input = cmd ? cmd : "(empty)"; - results = cmd_results_new(CMD_INVALID, input, "Unknown/invalid command"); - goto cleanup; - } - - enum command_context context = 0; - - struct { - char *name; - enum command_context context; - } context_names[] = { - { "config", CONTEXT_CONFIG }, - { "binding", CONTEXT_BINDING }, - { "ipc", CONTEXT_IPC }, - { "criteria", CONTEXT_CRITERIA }, - { "all", CONTEXT_ALL }, - }; - - for (int i = 1; i < argc; ++i) { - size_t j; - for (j = 0; j < sizeof(context_names) / sizeof(context_names[0]); ++j) { - if (strcmp(context_names[j].name, argv[i]) == 0) { - break; - } - } - if (j == sizeof(context_names) / sizeof(context_names[0])) { - results = cmd_results_new(CMD_INVALID, cmd, - "Invalid command context %s", argv[i]); - goto cleanup; - } - context |= context_names[j].context; - } - - struct command_policy *policy = NULL; - for (int i = 0; i < config->command_policies->length; ++i) { - struct command_policy *p = config->command_policies->items[i]; - if (strcmp(p->command, cmd) == 0) { - policy = p; - break; - } - } - if (!policy) { - policy = alloc_command_policy(cmd); - sway_assert(policy, "Unable to allocate security policy"); - if (policy) { - list_add(config->command_policies, policy); - } - } - policy->context = context; - - sway_log(L_INFO, "Set command policy for %s to %d", - policy->command, policy->context); - - results = cmd_results_new(CMD_SUCCESS, NULL, NULL); - -cleanup: - free_argv(argc, argv); - return results; -} - -struct cmd_results *cmd_results_new(enum cmd_status status, const char* input, const char *format, ...) { - struct cmd_results *results = malloc(sizeof(struct cmd_results)); - if (!results) { - sway_log(L_ERROR, "Unable to allocate command results"); - return NULL; - } - results->status = status; - if (input) { - results->input = strdup(input); // input is the command name - } else { - results->input = NULL; - } - if (format) { - char *error = malloc(256); - va_list args; - va_start(args, format); - if (error) { - vsnprintf(error, 256, format, args); - } - va_end(args); - results->error = error; - } else { - results->error = NULL; - } - return results; -} - -void free_cmd_results(struct cmd_results *results) { - if (results->input) { - free(results->input); - } - if (results->error) { - free(results->error); - } - free(results); -} - -const char *cmd_results_to_json(struct cmd_results *results) { - json_object *result_array = json_object_new_array(); - json_object *root = json_object_new_object(); - json_object_object_add(root, "success", json_object_new_boolean(results->status == CMD_SUCCESS)); - if (results->input) { - json_object_object_add(root, "input", json_object_new_string(results->input)); - } - if (results->error) { - json_object_object_add(root, "error", json_object_new_string(results->error)); - } - json_object_array_add(result_array, root); - const char *json = json_object_to_json_string(result_array); - free(result_array); - free(root); - return json; -} diff --git a/sway/commands/assign.c b/sway/commands/assign.c deleted file mode 100644 index c3b03bbc..00000000 --- a/sway/commands/assign.c +++ /dev/null @@ -1,57 +0,0 @@ -#define _XOPEN_SOURCE 700 -#include -#include -#include "sway/commands.h" -#include "sway/criteria.h" -#include "list.h" -#include "log.h" - -struct cmd_results *cmd_assign(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "assign", EXPECTED_AT_LEAST, 2))) { - return error; - } - - char *criteria = *argv++; - - if (strncmp(*argv, "→", strlen("→")) == 0) { - if (argc < 3) { - return cmd_results_new(CMD_INVALID, "assign", "Missing workspace"); - } - argv++; - } - - char *movecmd = "move container to workspace "; - int arglen = strlen(movecmd) + strlen(*argv) + 1; - char *cmdlist = calloc(1, arglen); - if (!cmdlist) { - return cmd_results_new(CMD_FAILURE, "assign", "Unable to allocate command list"); - } - snprintf(cmdlist, arglen, "%s%s", movecmd, *argv); - - struct criteria *crit = malloc(sizeof(struct criteria)); - if (!crit) { - free(cmdlist); - return cmd_results_new(CMD_FAILURE, "assign", "Unable to allocate criteria"); - } - crit->crit_raw = strdup(criteria); - crit->cmdlist = cmdlist; - crit->tokens = create_list(); - char *err_str = extract_crit_tokens(crit->tokens, crit->crit_raw); - - if (err_str) { - error = cmd_results_new(CMD_INVALID, "assign", err_str); - free(err_str); - free_criteria(crit); - } else if (crit->tokens->length == 0) { - error = cmd_results_new(CMD_INVALID, "assign", "Found no name/value pairs in criteria"); - free_criteria(crit); - } else if (list_seq_find(config->criteria, criteria_cmp, crit) != -1) { - sway_log(L_DEBUG, "assign: Duplicate, skipping."); - free_criteria(crit); - } else { - sway_log(L_DEBUG, "assign: '%s' -> '%s' added", crit->crit_raw, crit->cmdlist); - list_add(config->criteria, crit); - } - return error ? error : cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/bar.c b/sway/commands/bar.c deleted file mode 100644 index 04745a6e..00000000 --- a/sway/commands/bar.c +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "log.h" -#include "util.h" - -struct cmd_results *cmd_bar(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "bar", EXPECTED_AT_LEAST, 1))) { - return error; - } - - if (config->reading && strcmp("{", argv[0]) != 0) { - return cmd_results_new(CMD_INVALID, "bar", - "Expected '{' at start of bar config definition."); - } - - if (!config->reading) { - if (argc > 1) { - if (strcasecmp("mode", argv[0]) == 0) { - return bar_cmd_mode(argc-1, argv + 1); - } - - if (strcasecmp("hidden_state", argv[0]) == 0) { - return bar_cmd_hidden_state(argc-1, argv + 1); - } - } - - return cmd_results_new(CMD_FAILURE, "bar", "Can only be used in config file."); - } - - // Create new bar with default values - struct bar_config *bar = default_bar_config(); - if (!bar) { - return cmd_results_new(CMD_FAILURE, "bar", "Unable to allocate bar state"); - } - - // set bar id - int i; - for (i = 0; i < config->bars->length; ++i) { - if (bar == config->bars->items[i]) { - const int len = 5 + numlen(i); // "bar-" + i + \0 - bar->id = malloc(len * sizeof(char)); - if (bar->id) { - snprintf(bar->id, len, "bar-%d", i); - } else { - return cmd_results_new(CMD_FAILURE, "bar", "Unable to allocate bar ID"); - } - break; - } - } - - // Set current bar - config->current_bar = bar; - sway_log(L_DEBUG, "Configuring bar %s", bar->id); - return cmd_results_new(CMD_BLOCK_BAR, NULL, NULL); -} diff --git a/sway/commands/bar/activate_button.c b/sway/commands/bar/activate_button.c deleted file mode 100644 index 32a1d3e5..00000000 --- a/sway/commands/bar/activate_button.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include "sway/commands.h" -#include "log.h" - -struct cmd_results *bar_cmd_activate_button(int argc, char **argv) { - const char *cmd_name = "activate_button"; -#ifndef ENABLE_TRAY - return cmd_results_new(CMD_INVALID, cmd_name, "Invalid %s command " - "%s called, but sway was compiled without tray support", - cmd_name, cmd_name); -#else - struct cmd_results *error = NULL; - if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 1))) { - return error; - } - - if (!config->current_bar) { - return cmd_results_new(CMD_FAILURE, cmd_name, "No bar defined."); - } - - // User should be able to prefix with 0x or whatever they want - config->current_bar->secondary_button = strtoul(argv[0], NULL, 0); - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -#endif -} diff --git a/sway/commands/bar/binding_mode_indicator.c b/sway/commands/bar/binding_mode_indicator.c deleted file mode 100644 index 64f5b84f..00000000 --- a/sway/commands/bar/binding_mode_indicator.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "log.h" - -struct cmd_results *bar_cmd_binding_mode_indicator(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "binding_mode_indicator", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - if (!config->current_bar) { - return cmd_results_new(CMD_FAILURE, "binding_mode_indicator", "No bar defined."); - } - - if (strcasecmp("yes", argv[0]) == 0) { - config->current_bar->binding_mode_indicator = true; - sway_log(L_DEBUG, "Enabling binding mode indicator on bar: %s", config->current_bar->id); - } else if (strcasecmp("no", argv[0]) == 0) { - config->current_bar->binding_mode_indicator = false; - sway_log(L_DEBUG, "Disabling binding mode indicator on bar: %s", config->current_bar->id); - } else { - error = cmd_results_new(CMD_INVALID, "binding_mode_indicator", "Invalid value %s", argv[0]); - return error; - } - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/bar/bindsym.c b/sway/commands/bar/bindsym.c deleted file mode 100644 index 5f90b51a..00000000 --- a/sway/commands/bar/bindsym.c +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "list.h" -#include "log.h" -#include "stringop.h" - -struct cmd_results *bar_cmd_bindsym(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1))) { - return error; - } else if (!config->reading) { - return cmd_results_new(CMD_FAILURE, "bindsym", "Can only be used in config file."); - } - - if (!config->current_bar) { - return cmd_results_new(CMD_FAILURE, "bindsym", "No bar defined."); - } - - if (strlen(argv[1]) != 7) { - return cmd_results_new(CMD_INVALID, "bindsym", "Invalid mouse binding %s", argv[1]); - } - uint32_t numbutton = (uint32_t)atoi(argv[1] + 6); - if (numbutton < 1 || numbutton > 5 || strncmp(argv[1], "button", 6) != 0) { - return cmd_results_new(CMD_INVALID, "bindsym", "Invalid mouse binding %s", argv[1]); - } - struct sway_mouse_binding *binding = malloc(sizeof(struct sway_mouse_binding)); - if (!binding) { - return cmd_results_new(CMD_FAILURE, "bindsym", "Unable to allocate binding"); - } - binding->button = numbutton; - binding->command = join_args(argv + 1, argc - 1); - - struct bar_config *bar = config->current_bar; - int i = list_seq_find(bar->bindings, sway_mouse_binding_cmp_buttons, binding); - if (i > -1) { - sway_log(L_DEBUG, "bindsym - '%s' for swaybar already exists, overwriting", argv[0]); - struct sway_mouse_binding *dup = bar->bindings->items[i]; - free_sway_mouse_binding(dup); - list_del(bar->bindings, i); - } - list_add(bar->bindings, binding); - list_qsort(bar->bindings, sway_mouse_binding_cmp_qsort); - - sway_log(L_DEBUG, "bindsym - Bound %s to command %s when clicking swaybar", argv[0], binding->command); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/bar/colors.c b/sway/commands/bar/colors.c deleted file mode 100644 index 8b3b0aac..00000000 --- a/sway/commands/bar/colors.c +++ /dev/null @@ -1,129 +0,0 @@ -#include -#include "sway/commands.h" - -static struct cmd_results *parse_single_color(char **color, const char *cmd_name, int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 1))) { - return error; - } - - if (!*color) { - *color = malloc(10); - if (!*color) { - return cmd_results_new(CMD_FAILURE, cmd_name, "Unable to allocate color"); - } - } - - error = add_color(cmd_name, *color, argv[0]); - if (error) { - return error; - } - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} - -static struct cmd_results *parse_three_colors(char ***colors, const char *cmd_name, int argc, char **argv) { - struct cmd_results *error = NULL; - if (argc != 3) { - return cmd_results_new(CMD_INVALID, cmd_name, "Requires exactly three color values"); - } - - int i; - for (i = 0; i < 3; i++) { - if (!*colors[i]) { - *(colors[i]) = malloc(10); - if (!*(colors[i])) { - return cmd_results_new(CMD_FAILURE, cmd_name, "Unable to allocate color"); - } - } - error = add_color(cmd_name, *(colors[i]), argv[i]); - if (error) { - return error; - } - } - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} - -struct cmd_results *bar_cmd_colors(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "colors", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - if (strcmp("{", argv[0]) != 0) { - return cmd_results_new(CMD_INVALID, "colors", - "Expected '{' at the start of colors config definition."); - } - - return cmd_results_new(CMD_BLOCK_BAR_COLORS, NULL, NULL); -} - -struct cmd_results *bar_colors_cmd_active_workspace(int argc, char **argv) { - char **colors[3] = { - &(config->current_bar->colors.active_workspace_border), - &(config->current_bar->colors.active_workspace_bg), - &(config->current_bar->colors.active_workspace_text) - }; - return parse_three_colors(colors, "active_workspace", argc, argv); -} - -struct cmd_results *bar_colors_cmd_background(int argc, char **argv) { - return parse_single_color(&(config->current_bar->colors.background), "background", argc, argv); -} - -struct cmd_results *bar_colors_cmd_focused_background(int argc, char **argv) { - return parse_single_color(&(config->current_bar->colors.focused_background), "focused_background", argc, argv); -} - -struct cmd_results *bar_colors_cmd_binding_mode(int argc, char **argv) { - char **colors[3] = { - &(config->current_bar->colors.binding_mode_border), - &(config->current_bar->colors.binding_mode_bg), - &(config->current_bar->colors.binding_mode_text) - }; - return parse_three_colors(colors, "binding_mode", argc, argv); -} - -struct cmd_results *bar_colors_cmd_focused_workspace(int argc, char **argv) { - char **colors[3] = { - &(config->current_bar->colors.focused_workspace_border), - &(config->current_bar->colors.focused_workspace_bg), - &(config->current_bar->colors.focused_workspace_text) - }; - return parse_three_colors(colors, "focused_workspace", argc, argv); -} - -struct cmd_results *bar_colors_cmd_inactive_workspace(int argc, char **argv) { - char **colors[3] = { - &(config->current_bar->colors.inactive_workspace_border), - &(config->current_bar->colors.inactive_workspace_bg), - &(config->current_bar->colors.inactive_workspace_text) - }; - return parse_three_colors(colors, "inactive_workspace", argc, argv); -} - -struct cmd_results *bar_colors_cmd_separator(int argc, char **argv) { - return parse_single_color(&(config->current_bar->colors.separator), "separator", argc, argv); -} - -struct cmd_results *bar_colors_cmd_focused_separator(int argc, char **argv) { - return parse_single_color(&(config->current_bar->colors.focused_separator), "focused_separator", argc, argv); -} - -struct cmd_results *bar_colors_cmd_statusline(int argc, char **argv) { - return parse_single_color(&(config->current_bar->colors.statusline), "statusline", argc, argv); -} - -struct cmd_results *bar_colors_cmd_focused_statusline(int argc, char **argv) { - return parse_single_color(&(config->current_bar->colors.focused_separator), "focused_separator", argc, argv); -} - -struct cmd_results *bar_colors_cmd_urgent_workspace(int argc, char **argv) { - char **colors[3] = { - &(config->current_bar->colors.urgent_workspace_border), - &(config->current_bar->colors.urgent_workspace_bg), - &(config->current_bar->colors.urgent_workspace_text) - }; - return parse_three_colors(colors, "urgent_workspace", argc, argv); -} diff --git a/sway/commands/bar/context_button.c b/sway/commands/bar/context_button.c deleted file mode 100644 index 6d7d7aec..00000000 --- a/sway/commands/bar/context_button.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include "sway/commands.h" -#include "log.h" - -struct cmd_results *bar_cmd_context_button(int argc, char **argv) { - const char *cmd_name = "context_button"; -#ifndef ENABLE_TRAY - return cmd_results_new(CMD_INVALID, cmd_name, "Invalid %s command " - "%s called, but sway was compiled without tray support", - cmd_name, cmd_name); -#else - struct cmd_results *error = NULL; - if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 1))) { - return error; - } - - if (!config->current_bar) { - return cmd_results_new(CMD_FAILURE, cmd_name, "No bar defined."); - } - - // User should be able to prefix with 0x or whatever they want - config->current_bar->context_button = strtoul(argv[0], NULL, 0); - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -#endif -} diff --git a/sway/commands/bar/font.c b/sway/commands/bar/font.c deleted file mode 100644 index c586c5bc..00000000 --- a/sway/commands/bar/font.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include "sway/commands.h" -#include "log.h" -#include "stringop.h" - -struct cmd_results *bar_cmd_font(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "font", EXPECTED_AT_LEAST, 1))) { - return error; - } - - if (!config->current_bar) { - return cmd_results_new(CMD_FAILURE, "font", "No bar defined."); - } - - char *font = join_args(argv, argc); - free(config->current_bar->font); - if (strlen(font) > 6 && strncmp("pango:", font, 6) == 0) { - config->current_bar->font = font; - } else { - config->current_bar->font = font; - } - - sway_log(L_DEBUG, "Settings font '%s' for bar: %s", config->current_bar->font, config->current_bar->id); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/bar/height.c b/sway/commands/bar/height.c deleted file mode 100644 index eb576ab3..00000000 --- a/sway/commands/bar/height.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "log.h" - -struct cmd_results *bar_cmd_height(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "height", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - int height = atoi(argv[0]); - if (height < 0) { - return cmd_results_new(CMD_INVALID, "height", - "Invalid height value: %s", argv[0]); - } - - config->current_bar->height = height; - sway_log(L_DEBUG, "Setting bar height to %d on bar: %s", height, config->current_bar->id); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/bar/hidden_state.c b/sway/commands/bar/hidden_state.c deleted file mode 100644 index 0b49aa6b..00000000 --- a/sway/commands/bar/hidden_state.c +++ /dev/null @@ -1,79 +0,0 @@ -#define _XOPEN_SOURCE 500 -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/ipc-server.h" -#include "log.h" - -static struct cmd_results *bar_set_hidden_state(struct bar_config *bar, const char *hidden_state) { - char *old_state = bar->hidden_state; - if (strcasecmp("toggle", hidden_state) == 0 && !config->reading) { - if (strcasecmp("hide", bar->hidden_state) == 0) { - bar->hidden_state = strdup("show"); - } else if (strcasecmp("show", bar->hidden_state) == 0) { - bar->hidden_state = strdup("hide"); - } - } else if (strcasecmp("hide", hidden_state) == 0) { - bar->hidden_state = strdup("hide"); - } else if (strcasecmp("show", hidden_state) == 0) { - bar->hidden_state = strdup("show"); - } else { - return cmd_results_new(CMD_INVALID, "hidden_state", "Invalid value %s", hidden_state); - } - - if (strcmp(old_state, bar->hidden_state) != 0) { - if (!config->reading) { - ipc_event_barconfig_update(bar); - } - sway_log(L_DEBUG, "Setting hidden_state: '%s' for bar: %s", bar->hidden_state, bar->id); - } - - // free old mode - free(old_state); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} - -struct cmd_results *bar_cmd_hidden_state(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "hidden_state", EXPECTED_AT_LEAST, 1))) { - return error; - } - if ((error = checkarg(argc, "hidden_state", EXPECTED_LESS_THAN, 3))) { - return error; - } - - if (config->reading && argc > 1) { - return cmd_results_new(CMD_INVALID, "hidden_state", "Unexpected value %s in config mode", argv[1]); - } - - const char *state = argv[0]; - - if (config->reading) { - return bar_set_hidden_state(config->current_bar, state); - } - - const char *id = NULL; - if (argc == 2) { - id = argv[1]; - } - - int i; - struct bar_config *bar; - for (i = 0; i < config->bars->length; ++i) { - bar = config->bars->items[i]; - if (id && strcmp(id, bar->id) == 0) { - return bar_set_hidden_state(bar, state); - } - - error = bar_set_hidden_state(bar, state); - if (error) { - return error; - } - } - - // active bar modifiers might have changed. - update_active_bar_modifiers(); - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/bar/icon_theme.c b/sway/commands/bar/icon_theme.c deleted file mode 100644 index cbfc0be5..00000000 --- a/sway/commands/bar/icon_theme.c +++ /dev/null @@ -1,25 +0,0 @@ -#define _XOPEN_SOURCE 500 -#include -#include "sway/commands.h" - -struct cmd_results *bar_cmd_icon_theme(int argc, char **argv) { - const char *cmd_name = "tray_output"; -#ifndef ENABLE_TRAY - return cmd_results_new(CMD_INVALID, cmd_name, "Invalid %s command " - "%s called, but sway was compiled without tray support", - cmd_name, cmd_name); -#else - struct cmd_results *error = NULL; - if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 1))) { - return error; - } - - if (!config->current_bar) { - return cmd_results_new(CMD_FAILURE, cmd_name, "No bar defined."); - } - - config->current_bar->icon_theme = strdup(argv[0]); - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -#endif -} diff --git a/sway/commands/bar/id.c b/sway/commands/bar/id.c deleted file mode 100644 index 1221ebf6..00000000 --- a/sway/commands/bar/id.c +++ /dev/null @@ -1,33 +0,0 @@ -#define _XOPEN_SOURCE 500 -#include -#include "sway/commands.h" -#include "log.h" - -struct cmd_results *bar_cmd_id(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "id", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - const char *name = argv[0]; - const char *oldname = config->current_bar->id; - - // check if id is used by a previously defined bar - int i; - for (i = 0; i < config->bars->length; ++i) { - struct bar_config *find = config->bars->items[i]; - if (strcmp(name, find->id) == 0 && config->current_bar != find) { - return cmd_results_new(CMD_FAILURE, "id", - "Id '%s' already defined for another bar. Id unchanged (%s).", - name, oldname); - } - } - - sway_log(L_DEBUG, "Renaming bar: '%s' to '%s'", oldname, name); - - // free old bar id - free(config->current_bar->id); - - config->current_bar->id = strdup(name); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/bar/mode.c b/sway/commands/bar/mode.c deleted file mode 100644 index 36816b93..00000000 --- a/sway/commands/bar/mode.c +++ /dev/null @@ -1,81 +0,0 @@ -#define _XOPEN_SOURCE 500 -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/ipc-server.h" -#include "log.h" - -static struct cmd_results *bar_set_mode(struct bar_config *bar, const char *mode) { - char *old_mode = bar->mode; - if (strcasecmp("toggle", mode) == 0 && !config->reading) { - if (strcasecmp("dock", bar->mode) == 0) { - bar->mode = strdup("hide"); - } else if (strcasecmp("hide", bar->mode) == 0) { - bar->mode = strdup("dock"); - } - } else if (strcasecmp("dock", mode) == 0) { - bar->mode = strdup("dock"); - } else if (strcasecmp("hide", mode) == 0) { - bar->mode = strdup("hide"); - } else if (strcasecmp("invisible", mode) == 0) { - bar->mode = strdup("invisible"); - } else { - return cmd_results_new(CMD_INVALID, "mode", "Invalid value %s", mode); - } - - if (strcmp(old_mode, bar->mode) != 0) { - if (!config->reading) { - ipc_event_barconfig_update(bar); - - // active bar modifiers might have changed. - update_active_bar_modifiers(); - } - sway_log(L_DEBUG, "Setting mode: '%s' for bar: %s", bar->mode, bar->id); - } - - // free old mode - free(old_mode); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} - -struct cmd_results *bar_cmd_mode(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "mode", EXPECTED_AT_LEAST, 1))) { - return error; - } - if ((error = checkarg(argc, "mode", EXPECTED_LESS_THAN, 3))) { - return error; - } - - if (config->reading && argc > 1) { - return cmd_results_new(CMD_INVALID, "mode", "Unexpected value %s in config mode", argv[1]); - } - - const char *mode = argv[0]; - - if (config->reading) { - return bar_set_mode(config->current_bar, mode); - } - - const char *id = NULL; - if (argc == 2) { - id = argv[1]; - } - - int i; - struct bar_config *bar; - for (i = 0; i < config->bars->length; ++i) { - bar = config->bars->items[i]; - if (id && strcmp(id, bar->id) == 0) { - return bar_set_mode(bar, mode); - } - - error = bar_set_mode(bar, mode); - if (error) { - return error; - } - } - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/bar/modifier.c b/sway/commands/bar/modifier.c deleted file mode 100644 index 153d87e6..00000000 --- a/sway/commands/bar/modifier.c +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include "sway/commands.h" -#include "log.h" -#include "stringop.h" -#include "util.h" - -struct cmd_results *bar_cmd_modifier(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "modifier", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - if (!config->current_bar) { - return cmd_results_new(CMD_FAILURE, "modifier", "No bar defined."); - } - - uint32_t mod = 0; - - list_t *split = split_string(argv[0], "+"); - for (int i = 0; i < split->length; ++i) { - uint32_t tmp_mod; - if ((tmp_mod = get_modifier_mask_by_name(split->items[i])) > 0) { - mod |= tmp_mod; - continue; - } else { - free_flat_list(split); - return cmd_results_new(CMD_INVALID, "modifier", "Unknown modifier '%s'", split->items[i]); - } - } - free_flat_list(split); - - config->current_bar->modifier = mod; - sway_log(L_DEBUG, "Show/Hide the bar when pressing '%s' in hide mode.", argv[0]); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/bar/output.c b/sway/commands/bar/output.c deleted file mode 100644 index a5710bc0..00000000 --- a/sway/commands/bar/output.c +++ /dev/null @@ -1,50 +0,0 @@ -#define _XOPEN_SOURCE 500 -#include -#include "sway/commands.h" -#include "list.h" -#include "log.h" - -struct cmd_results *bar_cmd_output(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "output", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - if (!config->current_bar) { - return cmd_results_new(CMD_FAILURE, "output", "No bar defined."); - } - - const char *output = argv[0]; - list_t *outputs = config->current_bar->outputs; - if (!outputs) { - outputs = create_list(); - config->current_bar->outputs = outputs; - } - - int i; - int add_output = 1; - if (strcmp("*", output) == 0) { - // remove all previous defined outputs and replace with '*' - for (i = 0; i < outputs->length; ++i) { - free(outputs->items[i]); - list_del(outputs, i); - } - } else { - // only add output if not already defined with either the same - // name or as '*' - for (i = 0; i < outputs->length; ++i) { - const char *find = outputs->items[i]; - if (strcmp("*", find) == 0 || strcmp(output, find) == 0) { - add_output = 0; - break; - } - } - } - - if (add_output) { - list_add(outputs, strdup(output)); - sway_log(L_DEBUG, "Adding bar: '%s' to output '%s'", config->current_bar->id, output); - } - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/bar/pango_markup.c b/sway/commands/bar/pango_markup.c deleted file mode 100644 index f69e882f..00000000 --- a/sway/commands/bar/pango_markup.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "log.h" - -struct cmd_results *bar_cmd_pango_markup(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "pango_markup", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - if (!config->current_bar) { - return cmd_results_new(CMD_FAILURE, "pango_markup", "No bar defined."); - } - - if (strcasecmp("enabled", argv[0]) == 0) { - config->current_bar->pango_markup = true; - sway_log(L_DEBUG, "Enabling pango markup for bar: %s", config->current_bar->id); - } else if (strcasecmp("disabled", argv[0]) == 0) { - config->current_bar->pango_markup = false; - sway_log(L_DEBUG, "Disabling pango markup for bar: %s", config->current_bar->id); - } else { - error = cmd_results_new(CMD_INVALID, "pango_markup", "Invalid value %s", argv[0]); - return error; - } - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/bar/position.c b/sway/commands/bar/position.c deleted file mode 100644 index 50de58e2..00000000 --- a/sway/commands/bar/position.c +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "log.h" - -struct cmd_results *bar_cmd_position(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "position", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - if (!config->current_bar) { - return cmd_results_new(CMD_FAILURE, "position", "No bar defined."); - } - - if (strcasecmp("top", argv[0]) == 0) { - config->current_bar->position = DESKTOP_SHELL_PANEL_POSITION_TOP; - } else if (strcasecmp("bottom", argv[0]) == 0) { - config->current_bar->position = DESKTOP_SHELL_PANEL_POSITION_BOTTOM; - } else if (strcasecmp("left", argv[0]) == 0) { - sway_log(L_INFO, "Warning: swaybar currently only supports top and bottom positioning. YMMV"); - config->current_bar->position = DESKTOP_SHELL_PANEL_POSITION_LEFT; - } else if (strcasecmp("right", argv[0]) == 0) { - sway_log(L_INFO, "Warning: swaybar currently only supports top and bottom positioning. YMMV"); - config->current_bar->position = DESKTOP_SHELL_PANEL_POSITION_RIGHT; - } else { - error = cmd_results_new(CMD_INVALID, "position", "Invalid value %s", argv[0]); - return error; - } - - sway_log(L_DEBUG, "Setting bar position '%s' for bar: %s", argv[0], config->current_bar->id); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/bar/secondary_button.c b/sway/commands/bar/secondary_button.c deleted file mode 100644 index 745045c5..00000000 --- a/sway/commands/bar/secondary_button.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include "sway/commands.h" -#include "log.h" - -struct cmd_results *bar_cmd_secondary_button(int argc, char **argv) { - const char *cmd_name = "secondary_button"; -#ifndef ENABLE_TRAY - return cmd_results_new(CMD_INVALID, cmd_name, "Invalid %s command " - "%s called, but sway was compiled without tray support", - cmd_name, cmd_name); -#else - struct cmd_results *error = NULL; - if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 1))) { - return error; - } - - if (!config->current_bar) { - return cmd_results_new(CMD_FAILURE, cmd_name, "No bar defined."); - } - - // User should be able to prefix with 0x or whatever they want - config->current_bar->secondary_button = strtoul(argv[0], NULL, 0); - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -#endif -} diff --git a/sway/commands/bar/separator_symbol.c b/sway/commands/bar/separator_symbol.c deleted file mode 100644 index 2766d8a2..00000000 --- a/sway/commands/bar/separator_symbol.c +++ /dev/null @@ -1,21 +0,0 @@ -#define _XOPEN_SOURCE 500 -#include -#include "sway/commands.h" -#include "log.h" - -struct cmd_results *bar_cmd_separator_symbol(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "separator_symbol", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - if (!config->current_bar) { - return cmd_results_new(CMD_FAILURE, "separator_symbol", "No bar defined."); - } - - free(config->current_bar->separator_symbol); - config->current_bar->separator_symbol = strdup(argv[0]); - sway_log(L_DEBUG, "Settings separator_symbol '%s' for bar: %s", config->current_bar->separator_symbol, config->current_bar->id); - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/bar/status_command.c b/sway/commands/bar/status_command.c deleted file mode 100644 index b227ac47..00000000 --- a/sway/commands/bar/status_command.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include "sway/commands.h" -#include "log.h" -#include "stringop.h" - -struct cmd_results *bar_cmd_status_command(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "status_command", EXPECTED_AT_LEAST, 1))) { - return error; - } - - if (!config->current_bar) { - return cmd_results_new(CMD_FAILURE, "status_command", "No bar defined."); - } - - free(config->current_bar->status_command); - config->current_bar->status_command = join_args(argv, argc); - sway_log(L_DEBUG, "Feeding bar with status command: %s", config->current_bar->status_command); - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/bar/strip_workspace_numbers.c b/sway/commands/bar/strip_workspace_numbers.c deleted file mode 100644 index 9ac32482..00000000 --- a/sway/commands/bar/strip_workspace_numbers.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "log.h" - -struct cmd_results *bar_cmd_strip_workspace_numbers(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "strip_workspace_numbers", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - if (!config->current_bar) { - return cmd_results_new(CMD_FAILURE, "strip_workspace_numbers", "No bar defined."); - } - - if (strcasecmp("yes", argv[0]) == 0) { - config->current_bar->strip_workspace_numbers = true; - sway_log(L_DEBUG, "Stripping workspace numbers on bar: %s", config->current_bar->id); - } else if (strcasecmp("no", argv[0]) == 0) { - config->current_bar->strip_workspace_numbers = false; - sway_log(L_DEBUG, "Enabling workspace numbers on bar: %s", config->current_bar->id); - } else { - error = cmd_results_new(CMD_INVALID, "strip_workspace_numbers", "Invalid value %s", argv[0]); - return error; - } - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/bar/swaybar_command.c b/sway/commands/bar/swaybar_command.c deleted file mode 100644 index 452e2df5..00000000 --- a/sway/commands/bar/swaybar_command.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include "sway/commands.h" -#include "log.h" -#include "stringop.h" - -struct cmd_results *bar_cmd_swaybar_command(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "swaybar_command", EXPECTED_AT_LEAST, 1))) { - return error; - } - - if (!config->current_bar) { - return cmd_results_new(CMD_FAILURE, "swaybar_command", "No bar defined."); - } - - free(config->current_bar->swaybar_command); - config->current_bar->swaybar_command = join_args(argv, argc); - sway_log(L_DEBUG, "Using custom swaybar command: %s", config->current_bar->swaybar_command); - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/bar/tray_output.c b/sway/commands/bar/tray_output.c deleted file mode 100644 index 012304a9..00000000 --- a/sway/commands/bar/tray_output.c +++ /dev/null @@ -1,29 +0,0 @@ -#define _XOPEN_SOURCE 500 -#include -#include "sway/commands.h" - -struct cmd_results *bar_cmd_tray_output(int argc, char **argv) { - const char *cmd_name = "tray_output"; -#ifndef ENABLE_TRAY - return cmd_results_new(CMD_INVALID, cmd_name, "Invalid %s command " - "%s called, but sway was compiled without tray support", - cmd_name, cmd_name); -#else - struct cmd_results *error = NULL; - if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 1))) { - return error; - } - - if (!config->current_bar) { - return cmd_results_new(CMD_FAILURE, cmd_name, "No bar defined."); - } - - if (strcmp(argv[0], "all") == 0) { - // Default behaviour - return cmd_results_new(CMD_SUCCESS, NULL, NULL); - } - config->current_bar->tray_output = strdup(argv[0]); - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -#endif -} diff --git a/sway/commands/bar/tray_padding.c b/sway/commands/bar/tray_padding.c deleted file mode 100644 index ac0572ce..00000000 --- a/sway/commands/bar/tray_padding.c +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "log.h" - -struct cmd_results *bar_cmd_tray_padding(int argc, char **argv) { - const char *cmd_name = "tray_padding"; -#ifndef ENABLE_TRAY - return cmd_results_new(CMD_INVALID, cmd_name, "Invalid %s command" - "%s called, but sway was compiled without tray support", - cmd_name, cmd_name); -#else - struct cmd_results *error = NULL; - if ((error = checkarg(argc, cmd_name, EXPECTED_AT_LEAST, 1))) { - return error; - } - - if (!config->current_bar) { - return cmd_results_new(CMD_FAILURE, cmd_name, "No bar defined."); - } - - if (argc == 1 || (argc == 2 && strcasecmp("px", argv[1]) == 0)) { - char *inv; - uint32_t padding = strtoul(argv[0], &inv, 10); - if (*inv == '\0' || strcasecmp(inv, "px") == 0) { - config->current_bar->tray_padding = padding; - sway_log(L_DEBUG, "Enabling tray padding of %d px on bar: %s", padding, config->current_bar->id); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); - } - } - return cmd_results_new(CMD_FAILURE, cmd_name, - "Expected 'tray_padding [px]'"); -#endif -} diff --git a/sway/commands/bar/workspace_buttons.c b/sway/commands/bar/workspace_buttons.c deleted file mode 100644 index 67dd2d31..00000000 --- a/sway/commands/bar/workspace_buttons.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "log.h" - -struct cmd_results *bar_cmd_workspace_buttons(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "workspace_buttons", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - if (!config->current_bar) { - return cmd_results_new(CMD_FAILURE, "workspace_buttons", "No bar defined."); - } - - if (strcasecmp("yes", argv[0]) == 0) { - config->current_bar->workspace_buttons = true; - sway_log(L_DEBUG, "Enabling workspace buttons on bar: %s", config->current_bar->id); - } else if (strcasecmp("no", argv[0]) == 0) { - config->current_bar->workspace_buttons = false; - sway_log(L_DEBUG, "Disabling workspace buttons on bar: %s", config->current_bar->id); - } else { - error = cmd_results_new(CMD_INVALID, "workspace_buttons", "Invalid value %s", argv[0]); - return error; - } - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/bar/wrap_scroll.c b/sway/commands/bar/wrap_scroll.c deleted file mode 100644 index 4ed1f12a..00000000 --- a/sway/commands/bar/wrap_scroll.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "log.h" - -struct cmd_results *bar_cmd_wrap_scroll(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "wrap_scroll", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - if (!config->current_bar) { - return cmd_results_new(CMD_FAILURE, "wrap_scroll", "No bar defined."); - } - - if (strcasecmp("yes", argv[0]) == 0) { - config->current_bar->wrap_scroll = true; - sway_log(L_DEBUG, "Enabling wrap scroll on bar: %s", config->current_bar->id); - } else if (strcasecmp("no", argv[0]) == 0) { - config->current_bar->wrap_scroll = false; - sway_log(L_DEBUG, "Disabling wrap scroll on bar: %s", config->current_bar->id); - } else { - error = cmd_results_new(CMD_INVALID, "wrap_scroll", "Invalid value %s", argv[0]); - return error; - } - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/bind.c b/sway/commands/bind.c deleted file mode 100644 index d9ea37b7..00000000 --- a/sway/commands/bind.c +++ /dev/null @@ -1,170 +0,0 @@ -#include -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/input_state.h" -#include "list.h" -#include "log.h" -#include "stringop.h" -#include "util.h" - -int binding_order = 0; - -struct cmd_results *cmd_bindsym(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1))) { - return error; - } - - struct sway_binding *binding = malloc(sizeof(struct sway_binding)); - if (!binding) { - return cmd_results_new(CMD_FAILURE, "bindsym", - "Unable to allocate binding"); - } - binding->keys = create_list(); - binding->modifiers = 0; - binding->release = false; - binding->bindcode = false; - - // Handle --release - if (strcmp("--release", argv[0]) == 0) { - if (argc >= 3) { - binding->release = true; - argv++; - argc--; - } else { - free_sway_binding(binding); - return cmd_results_new(CMD_FAILURE, "bindsym", - "Invalid bindsym command " - "(expected more than 2 arguments, got %d)", argc); - } - } - - binding->command = join_args(argv + 1, argc - 1); - - list_t *split = split_string(argv[0], "+"); - for (int i = 0; i < split->length; ++i) { - // Check for a modifier key - uint32_t mod; - if ((mod = get_modifier_mask_by_name(split->items[i])) > 0) { - binding->modifiers |= mod; - continue; - } - // Check for xkb key - xkb_keysym_t sym = xkb_keysym_from_name(split->items[i], - XKB_KEYSYM_CASE_INSENSITIVE); - - // Check for mouse binding - if (strncasecmp(split->items[i], "button", strlen("button")) == 0 && - strlen(split->items[i]) == strlen("button0")) { - sym = ((char *)split->items[i])[strlen("button")] - '1' + M_LEFT_CLICK; - } - if (!sym) { - struct cmd_results *ret = cmd_results_new(CMD_INVALID, "bindsym", - "Unknown key '%s'", (char *)split->items[i]); - free_sway_binding(binding); - free_flat_list(split); - return ret; - } - xkb_keysym_t *key = malloc(sizeof(xkb_keysym_t)); - if (!key) { - free_sway_binding(binding); - free_flat_list(split); - return cmd_results_new(CMD_FAILURE, "bindsym", - "Unable to allocate binding"); - } - *key = sym; - list_add(binding->keys, key); - } - free_flat_list(split); - - struct sway_mode *mode = config->current_mode; - int i = list_seq_find(mode->bindings, sway_binding_cmp_keys, binding); - if (i > -1) { - sway_log(L_DEBUG, "bindsym - '%s' already exists, overwriting", argv[0]); - struct sway_binding *dup = mode->bindings->items[i]; - free_sway_binding(dup); - list_del(mode->bindings, i); - } - binding->order = binding_order++; - list_add(mode->bindings, binding); - list_qsort(mode->bindings, sway_binding_cmp_qsort); - - sway_log(L_DEBUG, "bindsym - Bound %s to command %s", argv[0], binding->command); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} - -struct cmd_results *cmd_bindcode(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "bindcode", EXPECTED_MORE_THAN, 1))) { - return error; - } - - struct sway_binding *binding = malloc(sizeof(struct sway_binding)); - if (!binding) { - return cmd_results_new(CMD_FAILURE, "bindsym", - "Unable to allocate binding"); - } - binding->keys = create_list(); - binding->modifiers = 0; - binding->release = false; - binding->bindcode = true; - - // Handle --release - if (strcmp("--release", argv[0]) == 0) { - if (argc >= 3) { - binding->release = true; - argv++; - argc--; - } else { - free_sway_binding(binding); - return cmd_results_new(CMD_FAILURE, "bindcode", - "Invalid bindcode command " - "(expected more than 2 arguments, got %d)", argc); - } - } - - binding->command = join_args(argv + 1, argc - 1); - - list_t *split = split_string(argv[0], "+"); - for (int i = 0; i < split->length; ++i) { - // Check for a modifier key - uint32_t mod; - if ((mod = get_modifier_mask_by_name(split->items[i])) > 0) { - binding->modifiers |= mod; - continue; - } - // parse keycode - xkb_keycode_t keycode = (int)strtol(split->items[i], NULL, 10); - if (!xkb_keycode_is_legal_ext(keycode)) { - error = cmd_results_new(CMD_INVALID, "bindcode", "Invalid keycode '%s'", (char *)split->items[i]); - free_sway_binding(binding); - list_free(split); - return error; - } - xkb_keycode_t *key = malloc(sizeof(xkb_keycode_t)); - *key = keycode - 8; - list_add(binding->keys, key); - } - free_flat_list(split); - - struct sway_mode *mode = config->current_mode; - int i = list_seq_find(mode->bindings, sway_binding_cmp_keys, binding); - if (i > -1) { - struct sway_binding *dup = mode->bindings->items[i]; - if (dup->bindcode) { - sway_log(L_DEBUG, "bindcode - '%s' already exists, overwriting", argv[0]); - } else { - sway_log(L_DEBUG, "bindcode - '%s' already exists as bindsym, overwriting", argv[0]); - } - free_sway_binding(dup); - list_del(mode->bindings, i); - } - binding->order = binding_order++; - list_add(mode->bindings, binding); - list_qsort(mode->bindings, sway_binding_cmp_qsort); - - sway_log(L_DEBUG, "bindcode - Bound %s to command %s", argv[0], binding->command); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/border.c b/sway/commands/border.c deleted file mode 100644 index c888622e..00000000 --- a/sway/commands/border.c +++ /dev/null @@ -1,65 +0,0 @@ -#include -#include -#include -#include -#include "sway/commands.h" -#include "sway/container.h" -#include "sway/focus.h" - -struct cmd_results *cmd_border(int argc, char **argv) { - struct cmd_results *error = NULL; - if (!config->active) { - return cmd_results_new(CMD_FAILURE, "border", "Can only be used when sway is running."); - } - if ((error = checkarg(argc, "border", EXPECTED_AT_LEAST, 1))) { - return error; - } - - if (argc > 2) { - return cmd_results_new(CMD_INVALID, "border", - "Expected 'border []"); - } - - swayc_t *view = current_container; - enum swayc_border_types border = view->border_type; - int thickness = view->border_thickness; - - if (strcasecmp(argv[0], "none") == 0) { - border = B_NONE; - } else if (strcasecmp(argv[0], "normal") == 0) { - border = B_NORMAL; - } else if (strcasecmp(argv[0], "pixel") == 0) { - border = B_PIXEL; - } else if (strcasecmp(argv[0], "toggle") == 0) { - switch (border) { - case B_NONE: - border = B_PIXEL; - break; - case B_NORMAL: - border = B_NONE; - break; - case B_PIXEL: - border = B_NORMAL; - break; - } - } else { - return cmd_results_new(CMD_INVALID, "border", - "Expected 'border "); - } - - if (argc == 2 && (border == B_NORMAL || border == B_PIXEL)) { - thickness = (int)strtol(argv[1], NULL, 10); - if (errno == ERANGE || thickness < 0) { - errno = 0; - return cmd_results_new(CMD_INVALID, "border", "Number is out of range."); - } - } - - if (view) { - view->border_type = border; - view->border_thickness = thickness; - update_geometry(view); - } - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/client.c b/sway/commands/client.c deleted file mode 100644 index f3d879cd..00000000 --- a/sway/commands/client.c +++ /dev/null @@ -1,72 +0,0 @@ -#include -#include -#include "sway/commands.h" - -static struct cmd_results *parse_border_color(struct border_colors *border_colors, const char *cmd_name, int argc, char **argv) { - struct cmd_results *error = NULL; - if (argc < 3 || argc > 5) { - return cmd_results_new(CMD_INVALID, cmd_name, "Requires between three and five color values"); - } - - uint32_t *colors[5] = { - &border_colors->border, - &border_colors->background, - &border_colors->text, - &border_colors->indicator, - &border_colors->child_border - }; - int i; - for (i = 0; i < argc; i++) { - char buffer[10]; - error = add_color(cmd_name, buffer, argv[i]); - if (error) { - return error; - } - *colors[i] = strtoul(buffer + 1, NULL, 16); - } - - if (argc < 5) { - border_colors->child_border = border_colors->background; - } - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} - -struct cmd_results *cmd_client_focused(int argc, char **argv) { - return parse_border_color(&config->border_colors.focused, "client.focused", argc, argv); -} - -struct cmd_results *cmd_client_focused_inactive(int argc, char **argv) { - return parse_border_color(&config->border_colors.focused_inactive, "client.focused_inactive", argc, argv); -} - -struct cmd_results *cmd_client_unfocused(int argc, char **argv) { - return parse_border_color(&config->border_colors.unfocused, "client.unfocused", argc, argv); -} - -struct cmd_results *cmd_client_urgent(int argc, char **argv) { - return parse_border_color(&config->border_colors.urgent, "client.urgent", argc, argv); -} - -struct cmd_results *cmd_client_placeholder(int argc, char **argv) { - return parse_border_color(&config->border_colors.placeholder, "client.placeholder", argc, argv); -} - -struct cmd_results *cmd_client_background(int argc, char **argv) { - char buffer[10]; - struct cmd_results *error = NULL; - uint32_t background; - - if (argc != 1) { - return cmd_results_new(CMD_INVALID, "client.background", "Requires exactly one color value"); - } - - error = add_color("client.background", buffer, argv[0]); - if (error) { - return error; - } - - background = strtoul(buffer+1, NULL, 16); - config->border_colors.background = background; - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/clipboard.c b/sway/commands/clipboard.c deleted file mode 100644 index 95514e78..00000000 --- a/sway/commands/clipboard.c +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include -#include -#include "sway/commands.h" -#include "stringop.h" - -static void send_clipboard(void *data, const char *type, int fd) { - if (strcmp(type, "text/plain") != 0 - && strcmp(type, "text/plain;charset=utf-8") != 0) { - close(fd); - return; - } - - const char *str = data; - write(fd, str, strlen(str)); - close(fd); -} - -struct cmd_results *cmd_clipboard(int argc, char **argv) { - static char *current_data = NULL; - - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "clipboard", EXPECTED_AT_LEAST, 1))) { - return error; - } - - static const char *types[2] = { - "text/plain", - "text/plain;charset=utf-8" - }; - - char *str = join_args(argv, argc); - wlc_set_selection(str, types, 2, &send_clipboard); - - free(current_data); - current_data = str; - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/commands.c b/sway/commands/commands.c deleted file mode 100644 index 0c64970c..00000000 --- a/sway/commands/commands.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "list.h" -#include "log.h" - -struct cmd_results *cmd_commands(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "commands", EXPECTED_EQUAL_TO, 1))) { - return error; - } - if ((error = check_security_config())) { - return error; - } - - if (strcmp(argv[0], "{") != 0) { - return cmd_results_new(CMD_FAILURE, "commands", "Expected block declaration"); - } - - if (!config->reading) { - return cmd_results_new(CMD_FAILURE, "commands", "Can only be used in config file."); - } - - return cmd_results_new(CMD_BLOCK_COMMANDS, NULL, NULL); -} diff --git a/sway/commands/debuglog.c b/sway/commands/debuglog.c deleted file mode 100644 index 658d6165..00000000 --- a/sway/commands/debuglog.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "log.h" - -struct cmd_results *cmd_debuglog(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "debuglog", EXPECTED_EQUAL_TO, 1))) { - return error; - } else if (strcasecmp(argv[0], "toggle") == 0) { - if (config->reading) { - return cmd_results_new(CMD_FAILURE, "debuglog toggle", "Can't be used in config file."); - } - if (toggle_debug_logging()) { - sway_log(L_DEBUG, "Debuglog turned on."); - } - } else if (strcasecmp(argv[0], "on") == 0) { - set_log_level(L_DEBUG); - sway_log(L_DEBUG, "Debuglog turned on."); - } else if (strcasecmp(argv[0], "off") == 0) { - reset_log_level(); - } else { - return cmd_results_new(CMD_FAILURE, "debuglog", "Expected 'debuglog on|off|toggle'"); - } - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} - diff --git a/sway/commands/default_border.c b/sway/commands/default_border.c deleted file mode 100644 index 8fbe8d19..00000000 --- a/sway/commands/default_border.c +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include -#include -#include "sway/commands.h" -#include "sway/container.h" - -struct cmd_results *cmd_default_border(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "default_border", EXPECTED_AT_LEAST, 1))) { - return error; - } - - if (argc > 2) { - return cmd_results_new(CMD_INVALID, "default_border", - "Expected 'default_border []"); - } - - enum swayc_border_types border = config->border; - int thickness = config->border_thickness; - - if (strcasecmp(argv[0], "none") == 0) { - border = B_NONE; - } else if (strcasecmp(argv[0], "normal") == 0) { - border = B_NORMAL; - } else if (strcasecmp(argv[0], "pixel") == 0) { - border = B_PIXEL; - } else { - return cmd_results_new(CMD_INVALID, "default_border", - "Expected 'default_border []"); - } - - if (argc == 2 && (border == B_NORMAL || border == B_PIXEL)) { - thickness = (int)strtol(argv[1], NULL, 10); - if (errno == ERANGE || thickness < 0) { - errno = 0; - return cmd_results_new(CMD_INVALID, "default_border", "Number is out out of range."); - } - } - - config->border = border; - config->border_thickness = thickness; - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/default_floating_border.c b/sway/commands/default_floating_border.c deleted file mode 100644 index fb48c1c0..00000000 --- a/sway/commands/default_floating_border.c +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include -#include -#include "sway/commands.h" -#include "sway/container.h" - -struct cmd_results *cmd_default_floating_border(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "default_floating_border", EXPECTED_AT_LEAST, 1))) { - return error; - } - - if (argc > 2) { - return cmd_results_new(CMD_INVALID, "default_floating_border", - "Expected 'default_floating_border []"); - } - - enum swayc_border_types border = config->floating_border; - int thickness = config->floating_border_thickness; - - if (strcasecmp(argv[0], "none") == 0) { - border = B_NONE; - } else if (strcasecmp(argv[0], "normal") == 0) { - border = B_NORMAL; - } else if (strcasecmp(argv[0], "pixel") == 0) { - border = B_PIXEL; - } else { - return cmd_results_new(CMD_INVALID, "default_floating_border", - "Expected 'default_floating_border []"); - } - - if (argc == 2 && (border == B_NORMAL || border == B_PIXEL)) { - thickness = (int)strtol(argv[1], NULL, 10); - if (errno == ERANGE || thickness < 0) { - errno = 0; - return cmd_results_new(CMD_INVALID, "default_floating_border", - "Number is out out of range."); - } - } - - config->floating_border = border; - config->floating_border_thickness = thickness; - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/exec.c b/sway/commands/exec.c deleted file mode 100644 index 58ef5f94..00000000 --- a/sway/commands/exec.c +++ /dev/null @@ -1,16 +0,0 @@ -#include -#include "sway/commands.h" -#include "log.h" -#include "stringop.h" - -struct cmd_results *cmd_exec(int argc, char **argv) { - if (!config->active) return cmd_results_new(CMD_DEFER, "exec", NULL); - if (config->reloading) { - char *args = join_args(argv, argc); - sway_log(L_DEBUG, "Ignoring 'exec %s' due to reload", args); - free(args); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); - } - return cmd_exec_always(argc, argv); -} - diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c deleted file mode 100644 index ab2d8622..00000000 --- a/sway/commands/exec_always.c +++ /dev/null @@ -1,85 +0,0 @@ -#define _XOPEN_SOURCE 500 -#include -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "log.h" -#include "stringop.h" - -struct cmd_results *cmd_exec_always(int argc, char **argv) { - struct cmd_results *error = NULL; - if (!config->active) return cmd_results_new(CMD_DEFER, NULL, NULL); - if ((error = checkarg(argc, "exec_always", EXPECTED_MORE_THAN, 0))) { - return error; - } - - char *tmp = NULL; - if (strcmp((char*)*argv, "--no-startup-id") == 0) { - sway_log(L_INFO, "exec switch '--no-startup-id' not supported, ignored."); - if ((error = checkarg(argc - 1, "exec_always", EXPECTED_MORE_THAN, 0))) { - return error; - } - - tmp = join_args(argv + 1, argc - 1); - } else { - tmp = join_args(argv, argc); - } - - // Put argument into cmd array - char cmd[4096]; - strncpy(cmd, tmp, sizeof(cmd)); - cmd[sizeof(cmd) - 1] = 0; - free(tmp); - sway_log(L_DEBUG, "Executing %s", cmd); - - int fd[2]; - if (pipe(fd) != 0) { - sway_log(L_ERROR, "Unable to create pipe for fork"); - } - - pid_t pid; - pid_t *child = malloc(sizeof(pid_t)); // malloc'd so that Linux can avoid copying the process space - if (!child) { - return cmd_results_new(CMD_FAILURE, "exec_always", "Unable to allocate child pid"); - } - // Fork process - if ((pid = fork()) == 0) { - // Fork child process again - setsid(); - if ((*child = fork()) == 0) { - execl("/bin/sh", "/bin/sh", "-c", cmd, (void *)NULL); - /* Not reached */ - } - close(fd[0]); - ssize_t s = 0; - while ((size_t)s < sizeof(pid_t)) { - s += write(fd[1], ((uint8_t *)child) + s, sizeof(pid_t) - s); - } - close(fd[1]); - _exit(0); // Close child process - } else if (pid < 0) { - free(child); - return cmd_results_new(CMD_FAILURE, "exec_always", "fork() failed"); - } - close(fd[1]); // close write - ssize_t s = 0; - while ((size_t)s < sizeof(pid_t)) { - s += read(fd[0], ((uint8_t *)child) + s, sizeof(pid_t) - s); - } - close(fd[0]); - // cleanup child process - wait(0); - swayc_t *ws = swayc_active_workspace(); - if (*child > 0 && ws) { - sway_log(L_DEBUG, "Child process created with pid %d for workspace %s", *child, ws->name); - struct pid_workspace *pw = malloc(sizeof(struct pid_workspace)); - pw->pid = child; - pw->workspace = strdup(ws->name); - pid_workspace_add(pw); - } else { - free(child); - } - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/exit.c b/sway/commands/exit.c deleted file mode 100644 index f192f86a..00000000 --- a/sway/commands/exit.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "sway/commands.h" -#include "sway/container.h" - -void sway_terminate(int exit_code); - -struct cmd_results *cmd_exit(int argc, char **argv) { - struct cmd_results *error = NULL; - if (config->reading) return cmd_results_new(CMD_FAILURE, "exit", "Can't be used in config file."); - if ((error = checkarg(argc, "exit", EXPECTED_EQUAL_TO, 0))) { - return error; - } - // Close all views - close_views(&root_container); - sway_terminate(EXIT_SUCCESS); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} - diff --git a/sway/commands/floating.c b/sway/commands/floating.c deleted file mode 100644 index ccfde532..00000000 --- a/sway/commands/floating.c +++ /dev/null @@ -1,81 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "sway/container.h" -#include "sway/ipc-server.h" -#include "sway/layout.h" -#include "list.h" -#include "log.h" - -struct cmd_results *cmd_floating(int argc, char **argv) { - struct cmd_results *error = NULL; - if (config->reading) return cmd_results_new(CMD_FAILURE, "floating", "Can't be used in config file."); - if ((error = checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1))) { - return error; - } - swayc_t *view = current_container; - bool wants_floating; - if (strcasecmp(argv[0], "enable") == 0) { - wants_floating = true; - } else if (strcasecmp(argv[0], "disable") == 0) { - wants_floating = false; - } else if (strcasecmp(argv[0], "toggle") == 0) { - wants_floating = !view->is_floating; - } else { - return cmd_results_new(CMD_FAILURE, "floating", - "Expected 'floating "); - } - - // Prevent running floating commands on things like workspaces - if (view->type != C_VIEW) { - return cmd_results_new(CMD_SUCCESS, NULL, NULL); - } - - // Change from nonfloating to floating - if (!view->is_floating && wants_floating) { - // Remove view from its current location - destroy_container(remove_child(view)); - - // and move it into workspace floating - add_floating(swayc_active_workspace(), view); - view->x = (swayc_active_workspace()->width - view->width)/2; - view->y = (swayc_active_workspace()->height - view->height)/2; - if (view->desired_width != -1) { - view->width = view->desired_width; - } - if (view->desired_height != -1) { - view->height = view->desired_height; - } - arrange_windows(swayc_active_workspace(), -1, -1); - - } else if (view->is_floating && !wants_floating) { - // Delete the view from the floating list and unset its is_floating flag - remove_child(view); - view->is_floating = false; - // Get the properly focused container, and add in the view there - swayc_t *focused = container_under_pointer(); - // If focused is null, it's because the currently focused container is a workspace - if (focused == NULL || focused->is_floating) { - focused = swayc_active_workspace(); - } - set_focused_container(focused); - - sway_log(L_DEBUG, "Non-floating focused container is %p", focused); - - // Case of focused workspace, just create as child of it - if (focused->type == C_WORKSPACE) { - add_child(focused, view); - } - // Regular case, create as sibling of current container - else { - add_sibling(focused, view); - } - // Refocus on the view once its been put back into the layout - view->width = view->height = 0; - arrange_windows(swayc_active_workspace(), -1, -1); - remove_view_from_scratchpad(view); - ipc_event_window(view, "floating"); - } - set_focused_container(view); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/floating_maximum_size.c b/sway/commands/floating_maximum_size.c deleted file mode 100644 index 5bca4d7c..00000000 --- a/sway/commands/floating_maximum_size.c +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "log.h" - -struct cmd_results *cmd_floating_maximum_size(int argc, char **argv) { - struct cmd_results *error = NULL; - int32_t width; - int32_t height; - char *ptr; - - if ((error = checkarg(argc, "floating_maximum_size", EXPECTED_EQUAL_TO, 3))) { - return error; - } - width = strtol(argv[0], &ptr, 10); - height = strtol(argv[2], &ptr, 10); - - if (width < -1) { - sway_log(L_DEBUG, "floating_maximum_size invalid width value: '%s'", argv[0]); - - } else { - config->floating_maximum_width = width; - - } - - if (height < -1) { - sway_log(L_DEBUG, "floating_maximum_size invalid height value: '%s'", argv[2]); - } - else { - config->floating_maximum_height = height; - - } - - sway_log(L_DEBUG, "New floating_maximum_size: '%d' x '%d'", config->floating_maximum_width, - config->floating_maximum_height); - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/floating_minimum_size.c b/sway/commands/floating_minimum_size.c deleted file mode 100644 index ba72454c..00000000 --- a/sway/commands/floating_minimum_size.c +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "log.h" - -struct cmd_results *cmd_floating_minimum_size(int argc, char **argv) { - struct cmd_results *error = NULL; - int32_t width; - int32_t height; - char *ptr; - - if ((error = checkarg(argc, "floating_minimum_size", EXPECTED_EQUAL_TO, 3))) { - return error; - } - width = strtol(argv[0], &ptr, 10); - height = strtol(argv[2], &ptr, 10); - - if (width <= 0) { - sway_log(L_DEBUG, "floating_minimum_size invalid width value: '%s'", argv[0]); - - } else { - config->floating_minimum_width = width; - - } - - if (height <= 0) { - sway_log(L_DEBUG, "floating_minimum_size invalid height value: '%s'", argv[2]); - } - else { - config->floating_minimum_height = height; - - } - - sway_log(L_DEBUG, "New floating_minimum_size: '%d' x '%d'", config->floating_minimum_width, - config->floating_minimum_height); - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/floating_mod.c b/sway/commands/floating_mod.c deleted file mode 100644 index b8e81ab9..00000000 --- a/sway/commands/floating_mod.c +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "sway/input_state.h" -#include "list.h" -#include "log.h" -#include "stringop.h" -#include "util.h" - -struct cmd_results *cmd_floating_mod(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "floating_modifier", EXPECTED_AT_LEAST, 1))) { - return error; - } - int i; - list_t *split = split_string(argv[0], "+"); - config->floating_mod = 0; - - // set modifier keys - for (i = 0; i < split->length; ++i) { - config->floating_mod |= get_modifier_mask_by_name(split->items[i]); - } - free_flat_list(split); - if (!config->floating_mod) { - error = cmd_results_new(CMD_INVALID, "floating_modifier", "Unknown keys %s", argv[0]); - return error; - } - - if (argc >= 2) { - if (strcasecmp("inverse", argv[1]) == 0) { - config->dragging_key = M_RIGHT_CLICK; - config->resizing_key = M_LEFT_CLICK; - } else if (strcasecmp("normal", argv[1]) == 0) { - config->dragging_key = M_LEFT_CLICK; - config->resizing_key = M_RIGHT_CLICK; - } else { - error = cmd_results_new(CMD_INVALID, "floating_modifier", "Invalid definition %s", argv[1]); - return error; - } - } - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/floating_scroll.c b/sway/commands/floating_scroll.c deleted file mode 100644 index 8c50c5bd..00000000 --- a/sway/commands/floating_scroll.c +++ /dev/null @@ -1,46 +0,0 @@ -#define _XOPEN_SOURCE 500 -#include -#include -#include "sway/commands.h" -#include "log.h" -#include "stringop.h" - -struct cmd_results *cmd_floating_scroll(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "floating_scroll", EXPECTED_AT_LEAST, 1))) { - return error; - } - if (!strcasecmp("up", argv[0])) { - free(config->floating_scroll_up_cmd); - if (argc < 2) { - config->floating_scroll_up_cmd = strdup(""); - } else { - config->floating_scroll_up_cmd = join_args(argv + 1, argc - 1); - } - } else if (!strcasecmp("down", argv[0])) { - free(config->floating_scroll_down_cmd); - if (argc < 2) { - config->floating_scroll_down_cmd = strdup(""); - } else { - config->floating_scroll_down_cmd = join_args(argv + 1, argc - 1); - } - } else if (!strcasecmp("left", argv[0])) { - free(config->floating_scroll_left_cmd); - if (argc < 2) { - config->floating_scroll_left_cmd = strdup(""); - } else { - config->floating_scroll_left_cmd = join_args(argv + 1, argc - 1); - } - } else if (!strcasecmp("right", argv[0])) { - free(config->floating_scroll_right_cmd); - if (argc < 2) { - config->floating_scroll_right_cmd = strdup(""); - } else { - config->floating_scroll_right_cmd = join_args(argv + 1, argc - 1); - } - } else { - error = cmd_results_new(CMD_INVALID, "floating_scroll", "Unknown command: '%s'", argv[0]); - return error; - } - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/focus.c b/sway/commands/focus.c deleted file mode 100644 index c83157b8..00000000 --- a/sway/commands/focus.c +++ /dev/null @@ -1,100 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include "sway/commands.h" -#include "sway/container.h" -#include "sway/focus.h" -#include "sway/input_state.h" -#include "sway/output.h" -#include "sway/workspace.h" - -struct cmd_results *cmd_focus(int argc, char **argv) { - if (config->reading) return cmd_results_new(CMD_FAILURE, "focus", "Can't be used in config file."); - struct cmd_results *error = NULL; - if (argc > 0 && strcasecmp(argv[0], "output") == 0) { - swayc_t *output = NULL; - struct wlc_point abs_pos; - get_absolute_center_position(get_focused_container(&root_container), &abs_pos); - if ((error = checkarg(argc, "focus", EXPECTED_EQUAL_TO, 2))) { - return error; - } else if (!(output = output_by_name(argv[1], &abs_pos))) { - return cmd_results_new(CMD_FAILURE, "focus output", - "Can't find output with name/at direction '%s' @ (%i,%i)", argv[1], abs_pos.x, abs_pos.y); - } else if (!workspace_switch(swayc_active_workspace_for(output))) { - return cmd_results_new(CMD_FAILURE, "focus output", - "Switching to workspace on output '%s' was blocked", argv[1]); - } else if (config->mouse_warping) { - swayc_t *focused = get_focused_view(output); - if (focused && focused->type == C_VIEW) { - center_pointer_on(focused); - } - } - return cmd_results_new(CMD_SUCCESS, NULL, NULL); - } else if (argc == 0) { - set_focused_container(current_container); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); - } else if ((error = checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1))) { - return error; - } - static int floating_toggled_index = 0; - static int tiled_toggled_index = 0; - if (strcasecmp(argv[0], "left") == 0) { - move_focus(MOVE_LEFT); - } else if (strcasecmp(argv[0], "right") == 0) { - move_focus(MOVE_RIGHT); - } else if (strcasecmp(argv[0], "up") == 0) { - move_focus(MOVE_UP); - } else if (strcasecmp(argv[0], "down") == 0) { - move_focus(MOVE_DOWN); - } else if (strcasecmp(argv[0], "parent") == 0) { - move_focus(MOVE_PARENT); - } else if (strcasecmp(argv[0], "child") == 0) { - move_focus(MOVE_CHILD); - } else if (strcasecmp(argv[0], "next") == 0) { - move_focus(MOVE_NEXT); - } else if (strcasecmp(argv[0], "prev") == 0) { - move_focus(MOVE_PREV); - } else if (strcasecmp(argv[0], "mode_toggle") == 0) { - int i; - swayc_t *workspace = swayc_active_workspace(); - swayc_t *focused = get_focused_view(workspace); - if (focused->is_floating) { - if (workspace->children->length > 0) { - for (i = 0;i < workspace->floating->length; i++) { - if (workspace->floating->items[i] == focused) { - floating_toggled_index = i; - break; - } - } - if (workspace->children->length > tiled_toggled_index) { - set_focused_container(get_focused_view(workspace->children->items[tiled_toggled_index])); - } else { - set_focused_container(get_focused_view(workspace->children->items[0])); - tiled_toggled_index = 0; - } - } - } else { - if (workspace->floating->length > 0) { - for (i = 0;i < workspace->children->length; i++) { - if (workspace->children->items[i] == focused) { - tiled_toggled_index = i; - break; - } - } - if (workspace->floating->length > floating_toggled_index) { - swayc_t *floating = workspace->floating->items[floating_toggled_index]; - set_focused_container(get_focused_view(floating)); - } else { - swayc_t *floating = workspace->floating->items[workspace->floating->length - 1]; - set_focused_container(get_focused_view(floating)); - tiled_toggled_index = workspace->floating->length - 1; - } - } - } - } else { - return cmd_results_new(CMD_INVALID, "focus", - "Expected 'focus ' or 'focus output '"); - } - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/focus_follows_mouse.c b/sway/commands/focus_follows_mouse.c deleted file mode 100644 index 7c9c2b13..00000000 --- a/sway/commands/focus_follows_mouse.c +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include -#include "sway/commands.h" - -struct cmd_results *cmd_focus_follows_mouse(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - config->focus_follows_mouse = !strcasecmp(argv[0], "yes"); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/font.c b/sway/commands/font.c deleted file mode 100644 index 32994f8a..00000000 --- a/sway/commands/font.c +++ /dev/null @@ -1,27 +0,0 @@ -#define _XOPEN_SOURCE 500 -#include -#include "sway/border.h" -#include "sway/commands.h" -#include "log.h" -#include "stringop.h" - -struct cmd_results *cmd_font(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "font", EXPECTED_AT_LEAST, 1))) { - return error; - } - - char *font = join_args(argv, argc); - free(config->font); - if (strlen(font) > 6 && strncmp("pango:", font, 6) == 0) { - config->font = strdup(font + 6); - free(font); - } else { - config->font = font; - } - - config->font_height = get_font_text_height(config->font); - - sway_log(L_DEBUG, "Settings font %s", config->font); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/for_window.c b/sway/commands/for_window.c deleted file mode 100644 index d1fd1641..00000000 --- a/sway/commands/for_window.c +++ /dev/null @@ -1,41 +0,0 @@ -#define _XOPEN_SOURCE 500 -#include -#include "sway/commands.h" -#include "sway/criteria.h" -#include "list.h" -#include "log.h" -#include "stringop.h" - -struct cmd_results *cmd_for_window(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "for_window", EXPECTED_AT_LEAST, 2))) { - return error; - } - // add command to a criteria/command pair that is run against views when they appear. - char *criteria = argv[0], *cmdlist = join_args(argv + 1, argc - 1); - - struct criteria *crit = malloc(sizeof(struct criteria)); - if (!crit) { - return cmd_results_new(CMD_FAILURE, "for_window", "Unable to allocate criteria"); - } - crit->crit_raw = strdup(criteria); - crit->cmdlist = cmdlist; - crit->tokens = create_list(); - char *err_str = extract_crit_tokens(crit->tokens, crit->crit_raw); - - if (err_str) { - error = cmd_results_new(CMD_INVALID, "for_window", err_str); - free(err_str); - free_criteria(crit); - } else if (crit->tokens->length == 0) { - error = cmd_results_new(CMD_INVALID, "for_window", "Found no name/value pairs in criteria"); - free_criteria(crit); - } else if (list_seq_find(config->criteria, criteria_cmp, crit) != -1) { - sway_log(L_DEBUG, "for_window: Duplicate, skipping."); - free_criteria(crit); - } else { - sway_log(L_DEBUG, "for_window: '%s' -> '%s' added", crit->crit_raw, crit->cmdlist); - list_add(config->criteria, crit); - } - return error ? error : cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/force_focus_wrapping.c b/sway/commands/force_focus_wrapping.c deleted file mode 100644 index f19dd163..00000000 --- a/sway/commands/force_focus_wrapping.c +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include -#include "sway/commands.h" - -struct cmd_results *cmd_force_focus_wrapping(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "force_focus_wrapping", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - config->force_focus_wrapping = !strcasecmp(argv[0], "yes"); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c deleted file mode 100644 index bfff82f9..00000000 --- a/sway/commands/fullscreen.c +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include -#include -#include "sway/commands.h" -#include "sway/container.h" -#include "sway/focus.h" -#include "sway/ipc-server.h" -#include "sway/layout.h" - -struct cmd_results *cmd_fullscreen(int argc, char **argv) { - struct cmd_results *error = NULL; - if (config->reading) return cmd_results_new(CMD_FAILURE, "fullscreen", "Can't be used in config file."); - if (!config->active) return cmd_results_new(CMD_FAILURE, "fullscreen", "Can only be used when sway is running."); - if ((error = checkarg(argc, "fullscreen", EXPECTED_AT_LEAST, 0))) { - return error; - } - swayc_t *container = current_container; - if(container->type != C_VIEW){ - return cmd_results_new(CMD_INVALID, "fullscreen", "Only views can fullscreen"); - } - swayc_t *workspace = swayc_parent_by_type(container, C_WORKSPACE); - bool current = swayc_is_fullscreen(container); - wlc_view_set_state(container->handle, WLC_BIT_FULLSCREEN, !current); - - if (container->is_floating) { - if (current) { - // set dimensions back to what they were before we fullscreened this - container->x = container->cached_geometry.origin.x; - container->y = container->cached_geometry.origin.y; - container->width = container->cached_geometry.size.w; - container->height = container->cached_geometry.size.h; - } else { - // cache dimensions so we can reset them after we "unfullscreen" this - struct wlc_geometry geo = { - .origin = { - .x = container->x, - .y = container->y - }, - .size = { - .w = container->width, - .h = container->height - } - }; - container->cached_geometry = geo; - } - } - - // Resize workspace if going from fullscreen -> notfullscreen - // otherwise just resize container - if (!current) { - arrange_windows(workspace, -1, -1); - workspace->fullscreen = container; - } else { - arrange_windows(container, -1, -1); - workspace->fullscreen = NULL; - } - ipc_event_window(container, "fullscreen_mode"); - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/gaps.c b/sway/commands/gaps.c deleted file mode 100644 index 0a48592d..00000000 --- a/sway/commands/gaps.c +++ /dev/null @@ -1,166 +0,0 @@ -#include -#include -#include -#include -#include -#include "sway/commands.h" -#include "sway/container.h" -#include "sway/focus.h" -#include "sway/layout.h" - -struct cmd_results *cmd_gaps(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 1))) { - return error; - } - const char *expected_syntax = - "Expected 'gaps edge_gaps ' or " - "'gaps '"; - const char *amount_str = argv[0]; - // gaps amount - if (argc >= 1 && isdigit(*amount_str)) { - int amount = (int)strtol(amount_str, NULL, 10); - if (errno == ERANGE) { - errno = 0; - return cmd_results_new(CMD_INVALID, "gaps", "Number is out out of range."); - } - config->gaps_inner = config->gaps_outer = amount; - arrange_windows(&root_container, -1, -1); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); - } - // gaps inner|outer n - else if (argc >= 2 && isdigit((amount_str = argv[1])[0])) { - int amount = (int)strtol(amount_str, NULL, 10); - if (errno == ERANGE) { - errno = 0; - return cmd_results_new(CMD_INVALID, "gaps", "Number is out out of range."); - } - const char *target_str = argv[0]; - if (strcasecmp(target_str, "inner") == 0) { - config->gaps_inner = amount; - } else if (strcasecmp(target_str, "outer") == 0) { - config->gaps_outer = amount; - } - arrange_windows(&root_container, -1, -1); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); - } else if (argc == 2 && strcasecmp(argv[0], "edge_gaps") == 0) { - // gaps edge_gaps - if (strcasecmp(argv[1], "toggle") == 0) { - if (config->reading) { - return cmd_results_new(CMD_FAILURE, "gaps edge_gaps toggle", - "Can't be used in config file."); - } - config->edge_gaps = !config->edge_gaps; - } else { - config->edge_gaps = - (strcasecmp(argv[1], "yes") == 0 || strcasecmp(argv[1], "on") == 0); - } - arrange_windows(&root_container, -1, -1); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); - } - // gaps inner|outer current|all set|plus|minus n - if (argc < 4 || config->reading) { - return cmd_results_new(CMD_INVALID, "gaps", expected_syntax); - } - // gaps inner|outer ... - const char *inout_str = argv[0]; - enum {INNER, OUTER} inout; - if (strcasecmp(inout_str, "inner") == 0) { - inout = INNER; - } else if (strcasecmp(inout_str, "outer") == 0) { - inout = OUTER; - } else { - return cmd_results_new(CMD_INVALID, "gaps", expected_syntax); - } - - // gaps ... current|all ... - const char *target_str = argv[1]; - enum {CURRENT, WORKSPACE, ALL} target; - if (strcasecmp(target_str, "current") == 0) { - target = CURRENT; - } else if (strcasecmp(target_str, "all") == 0) { - target = ALL; - } else if (strcasecmp(target_str, "workspace") == 0) { - if (inout == OUTER) { - target = CURRENT; - } else { - // Set gap for views in workspace - target = WORKSPACE; - } - } else { - return cmd_results_new(CMD_INVALID, "gaps", expected_syntax); - } - - // gaps ... n - amount_str = argv[3]; - int amount = (int)strtol(amount_str, NULL, 10); - if (errno == ERANGE) { - errno = 0; - return cmd_results_new(CMD_INVALID, "gaps", "Number is out out of range."); - } - - // gaps ... set|plus|minus ... - const char *method_str = argv[2]; - enum {SET, ADD} method; - if (strcasecmp(method_str, "set") == 0) { - method = SET; - } else if (strcasecmp(method_str, "plus") == 0) { - method = ADD; - } else if (strcasecmp(method_str, "minus") == 0) { - method = ADD; - amount *= -1; - } else { - return cmd_results_new(CMD_INVALID, "gaps", expected_syntax); - } - - if (target == CURRENT) { - swayc_t *cont; - if (inout == OUTER) { - if ((cont = swayc_active_workspace()) == NULL) { - return cmd_results_new(CMD_FAILURE, "gaps", "There's no active workspace."); - } - } else { - if ((cont = get_focused_view(&root_container))->type != C_VIEW) { - return cmd_results_new(CMD_FAILURE, "gaps", "Currently focused item is not a view."); - } - } - cont->gaps = swayc_gap(cont); - if (method == SET) { - cont->gaps = amount; - } else if ((cont->gaps += amount) < 0) { - cont->gaps = 0; - } - arrange_windows(cont->parent, -1, -1); - } else if (inout == OUTER) { - //resize all workspace. - int i,j; - for (i = 0; i < root_container.children->length; ++i) { - swayc_t *op = root_container.children->items[i]; - for (j = 0; j < op->children->length; ++j) { - swayc_t *ws = op->children->items[j]; - if (method == SET) { - ws->gaps = amount; - } else if ((ws->gaps += amount) < 0) { - ws->gaps = 0; - } - } - } - arrange_windows(&root_container, -1, -1); - } else { - // Resize gaps for all views in workspace - swayc_t *top; - if (target == WORKSPACE) { - if ((top = swayc_active_workspace()) == NULL) { - return cmd_results_new(CMD_FAILURE, "gaps", "There's currently no active workspace."); - } - } else { - top = &root_container; - } - int top_gap = top->gaps; - container_map(top, method == SET ? set_gaps : add_gaps, &amount); - top->gaps = top_gap; - arrange_windows(top, -1, -1); - } - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/hide_edge_borders.c b/sway/commands/hide_edge_borders.c deleted file mode 100644 index ee2a2644..00000000 --- a/sway/commands/hide_edge_borders.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include -#include "sway/commands.h" - -struct cmd_results *cmd_hide_edge_borders(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "hide_edge_borders", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - if (strcasecmp(argv[0], "none") == 0) { - config->hide_edge_borders = E_NONE; - } else if (strcasecmp(argv[0], "vertical") == 0) { - config->hide_edge_borders = E_VERTICAL; - } else if (strcasecmp(argv[0], "horizontal") == 0) { - config->hide_edge_borders = E_HORIZONTAL; - } else if (strcasecmp(argv[0], "both") == 0) { - config->hide_edge_borders = E_BOTH; - } else if (strcasecmp(argv[0], "smart") == 0) { - config->hide_edge_borders = E_SMART; - } else { - return cmd_results_new(CMD_INVALID, "hide_edge_borders", - "Expected 'hide_edge_borders '"); - } - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/include.c b/sway/commands/include.c deleted file mode 100644 index 1ba9a10d..00000000 --- a/sway/commands/include.c +++ /dev/null @@ -1,15 +0,0 @@ -#include "sway/commands.h" -#include "sway/config.h" - -struct cmd_results *cmd_include(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "include", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - if (!load_include_configs(argv[0], config)) { - return cmd_results_new(CMD_INVALID, "include", "Failed to include sub configuration file: %s", argv[0]); - } - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/input.c b/sway/commands/input.c deleted file mode 100644 index ad53d272..00000000 --- a/sway/commands/input.c +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "sway/input.h" -#include "log.h" - -struct cmd_results *cmd_input(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "input", EXPECTED_AT_LEAST, 2))) { - return error; - } - - if (config->reading && strcmp("{", argv[1]) == 0) { - current_input_config = new_input_config(argv[0]); - sway_log(L_DEBUG, "entering input block: %s", current_input_config->identifier); - return cmd_results_new(CMD_BLOCK_INPUT, NULL, NULL); - } - - if (argc > 2) { - int argc_new = argc-2; - char **argv_new = argv+2; - - struct cmd_results *res; - current_input_config = new_input_config(argv[0]); - if (strcasecmp("accel_profile", argv[1]) == 0) { - res = input_cmd_accel_profile(argc_new, argv_new); - } else if (strcasecmp("click_method", argv[1]) == 0) { - res = input_cmd_click_method(argc_new, argv_new); - } else if (strcasecmp("drag_lock", argv[1]) == 0) { - res = input_cmd_drag_lock(argc_new, argv_new); - } else if (strcasecmp("dwt", argv[1]) == 0) { - res = input_cmd_dwt(argc_new, argv_new); - } else if (strcasecmp("events", argv[1]) == 0) { - res = input_cmd_events(argc_new, argv_new); - } else if (strcasecmp("left_handed", argv[1]) == 0) { - res = input_cmd_left_handed(argc_new, argv_new); - } else if (strcasecmp("middle_emulation", argv[1]) == 0) { - res = input_cmd_middle_emulation(argc_new, argv_new); - } else if (strcasecmp("natural_scroll", argv[1]) == 0) { - res = input_cmd_natural_scroll(argc_new, argv_new); - } else if (strcasecmp("pointer_accel", argv[1]) == 0) { - res = input_cmd_pointer_accel(argc_new, argv_new); - } else if (strcasecmp("scroll_method", argv[1]) == 0) { - res = input_cmd_scroll_method(argc_new, argv_new); - } else if (strcasecmp("tap", argv[1]) == 0) { - res = input_cmd_tap(argc_new, argv_new); - } else { - res = cmd_results_new(CMD_INVALID, "input ", "Unknown command %s", argv[1]); - } - current_input_config = NULL; - return res; - } - - return cmd_results_new(CMD_BLOCK_INPUT, NULL, NULL); -} diff --git a/sway/commands/input/accel_profile.c b/sway/commands/input/accel_profile.c deleted file mode 100644 index 8288c1ad..00000000 --- a/sway/commands/input/accel_profile.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "sway/input.h" - -struct cmd_results *input_cmd_accel_profile(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "accel_profile", EXPECTED_AT_LEAST, 1))) { - return error; - } - if (!current_input_config) { - return cmd_results_new(CMD_FAILURE, "accel_profile", "No input device defined."); - } - struct input_config *new_config = new_input_config(current_input_config->identifier); - - if (strcasecmp(argv[0], "adaptive") == 0) { - new_config->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE; - } else if (strcasecmp(argv[0], "flat") == 0) { - new_config->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT; - } else { - return cmd_results_new(CMD_INVALID, "accel_profile", - "Expected 'accel_profile '"); - } - - input_cmd_apply(new_config); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/input/click_method.c b/sway/commands/input/click_method.c deleted file mode 100644 index 5e9d3dcb..00000000 --- a/sway/commands/input/click_method.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "sway/input.h" -#include "log.h" - -struct cmd_results *input_cmd_click_method(int argc, char **argv) { - sway_log(L_DEBUG, "click_method for device: %d %s", current_input_config==NULL, current_input_config->identifier); - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "click_method", EXPECTED_AT_LEAST, 1))) { - return error; - } - if (!current_input_config) { - return cmd_results_new(CMD_FAILURE, "click_method", "No input device defined."); - } - struct input_config *new_config = new_input_config(current_input_config->identifier); - - if (strcasecmp(argv[0], "none") == 0) { - new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_NONE; - } else if (strcasecmp(argv[0], "button_areas") == 0) { - new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS; - } else if (strcasecmp(argv[0], "clickfinger") == 0) { - new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER; - } else { - return cmd_results_new(CMD_INVALID, "click_method", "Expected 'click_method -#include -#include "sway/commands.h" -#include "sway/input.h" - -struct cmd_results *input_cmd_drag_lock(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "drag_lock", EXPECTED_AT_LEAST, 1))) { - return error; - } - if (!current_input_config) { - return cmd_results_new(CMD_FAILURE, "drag_lock", "No input device defined."); - } - struct input_config *new_config = new_input_config(current_input_config->identifier); - - if (strcasecmp(argv[0], "enabled") == 0) { - new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED; - } else if (strcasecmp(argv[0], "disabled") == 0) { - new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_DISABLED; - } else { - return cmd_results_new(CMD_INVALID, "drag_lock", "Expected 'drag_lock '"); - } - - input_cmd_apply(new_config); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/input/dwt.c b/sway/commands/input/dwt.c deleted file mode 100644 index 557b2207..00000000 --- a/sway/commands/input/dwt.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "sway/input.h" - -struct cmd_results *input_cmd_dwt(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "dwt", EXPECTED_AT_LEAST, 1))) { - return error; - } - if (!current_input_config) { - return cmd_results_new(CMD_FAILURE, "dwt", "No input device defined."); - } - struct input_config *new_config = new_input_config(current_input_config->identifier); - - if (strcasecmp(argv[0], "enabled") == 0) { - new_config->dwt = LIBINPUT_CONFIG_DWT_ENABLED; - } else if (strcasecmp(argv[0], "disabled") == 0) { - new_config->dwt = LIBINPUT_CONFIG_DWT_DISABLED; - } else { - return cmd_results_new(CMD_INVALID, "dwt", "Expected 'dwt '"); - } - - input_cmd_apply(new_config); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/input/events.c b/sway/commands/input/events.c deleted file mode 100644 index 9d54287a..00000000 --- a/sway/commands/input/events.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "sway/input.h" -#include "log.h" - -struct cmd_results *input_cmd_events(int argc, char **argv) { - sway_log(L_DEBUG, "events for device: %s", current_input_config->identifier); - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "events", EXPECTED_AT_LEAST, 1))) { - return error; - } - if (!current_input_config) { - return cmd_results_new(CMD_FAILURE, "events", "No input device defined."); - } - struct input_config *new_config = new_input_config(current_input_config->identifier); - - if (strcasecmp(argv[0], "enabled") == 0) { - new_config->send_events = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; - } else if (strcasecmp(argv[0], "disabled") == 0) { - new_config->send_events = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED; - } else if (strcasecmp(argv[0], "disabled_on_external_mouse") == 0) { - new_config->send_events = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE; - } else { - return cmd_results_new(CMD_INVALID, "events", "Expected 'events '"); - } - - input_cmd_apply(new_config); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/input/left_handed.c b/sway/commands/input/left_handed.c deleted file mode 100644 index 6c913e70..00000000 --- a/sway/commands/input/left_handed.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "sway/input.h" - -struct cmd_results *input_cmd_left_handed(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "left_handed", EXPECTED_AT_LEAST, 1))) { - return error; - } - if (!current_input_config) { - return cmd_results_new(CMD_FAILURE, "left_handed", "No input device defined."); - } - struct input_config *new_config = new_input_config(current_input_config->identifier); - - if (strcasecmp(argv[0], "enabled") == 0) { - new_config->left_handed = 1; - } else if (strcasecmp(argv[0], "disabled") == 0) { - new_config->left_handed = 0; - } else { - return cmd_results_new(CMD_INVALID, "left_handed", "Expected 'left_handed '"); - } - - input_cmd_apply(new_config); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/input/middle_emulation.c b/sway/commands/input/middle_emulation.c deleted file mode 100644 index 33cdd7d6..00000000 --- a/sway/commands/input/middle_emulation.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "sway/input.h" - -struct cmd_results *input_cmd_middle_emulation(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "middle_emulation", EXPECTED_AT_LEAST, 1))) { - return error; - } - if (!current_input_config) { - return cmd_results_new(CMD_FAILURE, "middle_emulation", "No input device defined."); - } - struct input_config *new_config = new_input_config(current_input_config->identifier); - - if (strcasecmp(argv[0], "enabled") == 0) { - new_config->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED; - } else if (strcasecmp(argv[0], "disabled") == 0) { - new_config->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED; - } else { - return cmd_results_new(CMD_INVALID, "middle_emulation", "Expected 'middle_emulation '"); - } - - input_cmd_apply(new_config); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/input/natural_scroll.c b/sway/commands/input/natural_scroll.c deleted file mode 100644 index 7bc8b8d0..00000000 --- a/sway/commands/input/natural_scroll.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "sway/input.h" - -struct cmd_results *input_cmd_natural_scroll(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "natural_scroll", EXPECTED_AT_LEAST, 1))) { - return error; - } - if (!current_input_config) { - return cmd_results_new(CMD_FAILURE, "natural_scoll", "No input device defined."); - } - struct input_config *new_config = new_input_config(current_input_config->identifier); - - if (strcasecmp(argv[0], "enabled") == 0) { - new_config->natural_scroll = 1; - } else if (strcasecmp(argv[0], "disabled") == 0) { - new_config->natural_scroll = 0; - } else { - return cmd_results_new(CMD_INVALID, "natural_scroll", "Expected 'natural_scroll '"); - } - - input_cmd_apply(new_config); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/input/pointer_accel.c b/sway/commands/input/pointer_accel.c deleted file mode 100644 index 94f595d1..00000000 --- a/sway/commands/input/pointer_accel.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "sway/input.h" - -struct cmd_results *input_cmd_pointer_accel(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "pointer_accel", EXPECTED_AT_LEAST, 1))) { - return error; - } - if (!current_input_config) { - return cmd_results_new(CMD_FAILURE, "pointer_accel", "No input device defined."); - } - struct input_config *new_config = new_input_config(current_input_config->identifier); - - float pointer_accel = atof(argv[0]); - if (pointer_accel < -1 || pointer_accel > 1) { - return cmd_results_new(CMD_INVALID, "pointer_accel", "Input out of range [-1, 1]"); - } - new_config->pointer_accel = pointer_accel; - - input_cmd_apply(new_config); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/input/scroll_method.c b/sway/commands/input/scroll_method.c deleted file mode 100644 index 5c6c3d7a..00000000 --- a/sway/commands/input/scroll_method.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "sway/input.h" - -struct cmd_results *input_cmd_scroll_method(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "scroll_method", EXPECTED_AT_LEAST, 1))) { - return error; - } - if (!current_input_config) { - return cmd_results_new(CMD_FAILURE, "scroll_method", "No input device defined."); - } - struct input_config *new_config = new_input_config(current_input_config->identifier); - - if (strcasecmp(argv[0], "none") == 0) { - new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_NO_SCROLL; - } else if (strcasecmp(argv[0], "two_finger") == 0) { - new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_2FG; - } else if (strcasecmp(argv[0], "edge") == 0) { - new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_EDGE; - } else if (strcasecmp(argv[0], "on_button_down") == 0) { - new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN; - } else { - return cmd_results_new(CMD_INVALID, "scroll_method", "Expected 'scroll_method '"); - } - - input_cmd_apply(new_config); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/input/tap.c b/sway/commands/input/tap.c deleted file mode 100644 index 9e3ca2af..00000000 --- a/sway/commands/input/tap.c +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "sway/input.h" -#include "log.h" - -struct cmd_results *input_cmd_tap(int argc, char **argv) { - sway_log(L_DEBUG, "tap for device: %s", current_input_config->identifier); - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "tap", EXPECTED_AT_LEAST, 1))) { - return error; - } - if (!current_input_config) { - return cmd_results_new(CMD_FAILURE, "tap", "No input device defined."); - } - struct input_config *new_config = new_input_config(current_input_config->identifier); - - if (strcasecmp(argv[0], "enabled") == 0) { - new_config->tap = LIBINPUT_CONFIG_TAP_ENABLED; - } else if (strcasecmp(argv[0], "disabled") == 0) { - new_config->tap = LIBINPUT_CONFIG_TAP_DISABLED; - } else { - return cmd_results_new(CMD_INVALID, "tap", "Expected 'tap '"); - } - - sway_log(L_DEBUG, "apply-tap for device: %s", current_input_config->identifier); - input_cmd_apply(new_config); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/ipc.c b/sway/commands/ipc.c deleted file mode 100644 index 0c678961..00000000 --- a/sway/commands/ipc.c +++ /dev/null @@ -1,162 +0,0 @@ -#define _XOPEN_SOURCE 500 -#include -#include -#include "sway/security.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "ipc.h" -#include "log.h" -#include "util.h" - -static struct ipc_policy *current_policy = NULL; - -struct cmd_results *cmd_ipc(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "ipc", EXPECTED_EQUAL_TO, 2))) { - return error; - } - if ((error = check_security_config())) { - return error; - } - - char *program = NULL; - - if (!strcmp(argv[0], "*")) { - program = strdup(argv[0]); - } else if (!(program = resolve_path(argv[0]))) { - return cmd_results_new( - CMD_INVALID, "ipc", "Unable to resolve IPC Policy target."); - } - if (config->reading && strcmp("{", argv[1]) != 0) { - return cmd_results_new(CMD_INVALID, "ipc", - "Expected '{' at start of IPC config definition."); - } - - if (!config->reading) { - return cmd_results_new(CMD_FAILURE, "ipc", "Can only be used in config file."); - } - - current_policy = alloc_ipc_policy(program); - list_add(config->ipc_policies, current_policy); - - free(program); - return cmd_results_new(CMD_BLOCK_IPC, NULL, NULL); -} - -struct cmd_results *cmd_ipc_events(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "events", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - if (config->reading && strcmp("{", argv[0]) != 0) { - return cmd_results_new(CMD_INVALID, "events", - "Expected '{' at start of IPC event config definition."); - } - - if (!config->reading) { - return cmd_results_new(CMD_FAILURE, "events", "Can only be used in config file."); - } - - return cmd_results_new(CMD_BLOCK_IPC_EVENTS, NULL, NULL); -} - -struct cmd_results *cmd_ipc_cmd(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "ipc", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - bool enabled; - if (strcmp(argv[0], "enabled") == 0) { - enabled = true; - } else if (strcmp(argv[0], "disabled") == 0) { - enabled = false; - } else { - return cmd_results_new(CMD_INVALID, argv[-1], - "Argument must be one of 'enabled' or 'disabled'"); - } - - struct { - char *name; - enum ipc_feature type; - } types[] = { - { "*", IPC_FEATURE_ALL_COMMANDS }, - { "command", IPC_FEATURE_COMMAND }, - { "workspaces", IPC_FEATURE_GET_WORKSPACES }, - { "outputs", IPC_FEATURE_GET_OUTPUTS }, - { "tree", IPC_FEATURE_GET_TREE }, - { "marks", IPC_FEATURE_GET_MARKS }, - { "bar-config", IPC_FEATURE_GET_BAR_CONFIG }, - { "inputs", IPC_FEATURE_GET_INPUTS }, - { "clipboard", IPC_FEATURE_GET_CLIPBOARD }, - }; - - uint32_t type = 0; - - for (size_t i = 0; i < sizeof(types) / sizeof(types[0]); ++i) { - if (strcmp(types[i].name, argv[-1]) == 0) { - type = types[i].type; - break; - } - } - - if (enabled) { - current_policy->features |= type; - sway_log(L_DEBUG, "Enabled IPC %s feature", argv[-1]); - } else { - current_policy->features &= ~type; - sway_log(L_DEBUG, "Disabled IPC %s feature", argv[-1]); - } - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} - -struct cmd_results *cmd_ipc_event_cmd(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "ipc", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - bool enabled; - if (strcmp(argv[0], "enabled") == 0) { - enabled = true; - } else if (strcmp(argv[0], "disabled") == 0) { - enabled = false; - } else { - return cmd_results_new(CMD_INVALID, argv[-1], - "Argument must be one of 'enabled' or 'disabled'"); - } - - struct { - char *name; - enum ipc_feature type; - } types[] = { - { "*", IPC_FEATURE_ALL_EVENTS }, - { "workspace", IPC_FEATURE_EVENT_WORKSPACE }, - { "output", IPC_FEATURE_EVENT_OUTPUT }, - { "mode", IPC_FEATURE_EVENT_MODE }, - { "window", IPC_FEATURE_EVENT_WINDOW }, - { "binding", IPC_FEATURE_EVENT_BINDING }, - { "input", IPC_FEATURE_EVENT_INPUT }, - }; - - uint32_t type = 0; - - for (size_t i = 0; i < sizeof(types) / sizeof(types[0]); ++i) { - if (strcmp(types[i].name, argv[-1]) == 0) { - type = types[i].type; - break; - } - } - - if (enabled) { - current_policy->features |= type; - sway_log(L_DEBUG, "Enabled IPC %s event", argv[-1]); - } else { - current_policy->features &= ~type; - sway_log(L_DEBUG, "Disabled IPC %s event", argv[-1]); - } - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/kill.c b/sway/commands/kill.c deleted file mode 100644 index 742e2b86..00000000 --- a/sway/commands/kill.c +++ /dev/null @@ -1,12 +0,0 @@ -#include "sway/commands.h" -#include "sway/container.h" -#include "sway/focus.h" - -struct cmd_results *cmd_kill(int argc, char **argv) { - if (config->reading) return cmd_results_new(CMD_FAILURE, "kill", "Can't be used in config file."); - if (!config->active) return cmd_results_new(CMD_FAILURE, "kill", "Can only be used when sway is running."); - - swayc_t *container = current_container; - close_views(container); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/layout.c b/sway/commands/layout.c deleted file mode 100644 index 57a86565..00000000 --- a/sway/commands/layout.c +++ /dev/null @@ -1,196 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "sway/container.h" -#include "sway/layout.h" - -/** - * handle "layout auto" command group - */ -static struct cmd_results *cmd_layout_auto(swayc_t *container, int argc, char **argv); - -struct cmd_results *cmd_layout(int argc, char **argv) { - struct cmd_results *error = NULL; - if (config->reading) return cmd_results_new(CMD_FAILURE, "layout", "Can't be used in config file."); - if (!config->active) return cmd_results_new(CMD_FAILURE, "layout", "Can only be used when sway is running."); - if ((error = checkarg(argc, "layout", EXPECTED_MORE_THAN, 0))) { - return error; - } - swayc_t *parent = current_container; - if (parent->is_floating) { - return cmd_results_new(CMD_FAILURE, "layout", "Unable to change layout of floating windows"); - } - - while (parent->type == C_VIEW) { - parent = parent->parent; - } - - enum swayc_layouts old_layout = parent->layout; - - if (strcasecmp(argv[0], "default") == 0) { - swayc_change_layout(parent, parent->prev_layout); - if (parent->layout == L_NONE) { - swayc_t *output = swayc_parent_by_type(parent, C_OUTPUT); - swayc_change_layout(parent, default_layout(output)); - } - } else { - if (parent->layout != L_TABBED && parent->layout != L_STACKED) { - parent->prev_layout = parent->layout; - } - - if (strcasecmp(argv[0], "tabbed") == 0) { - if (parent->type != C_CONTAINER && !swayc_is_empty_workspace(parent)){ - parent = new_container(parent, L_TABBED); - } - - swayc_change_layout(parent, L_TABBED); - } else if (strcasecmp(argv[0], "stacking") == 0) { - if (parent->type != C_CONTAINER && !swayc_is_empty_workspace(parent)) { - parent = new_container(parent, L_STACKED); - } - - swayc_change_layout(parent, L_STACKED); - } else if (strcasecmp(argv[0], "splith") == 0) { - swayc_change_layout(parent, L_HORIZ); - } else if (strcasecmp(argv[0], "splitv") == 0) { - swayc_change_layout(parent, L_VERT); - } else if (strcasecmp(argv[0], "toggle") == 0 && argc == 2 && strcasecmp(argv[1], "split") == 0) { - if (parent->layout == L_HORIZ && (parent->workspace_layout == L_NONE - || parent->workspace_layout == L_HORIZ)) { - swayc_change_layout(parent, L_VERT); - } else { - swayc_change_layout(parent, L_HORIZ); - } - } else if (strcasecmp(argv[0], "auto") == 0) { - return cmd_layout_auto(parent, argc, argv); - } - } - - update_layout_geometry(parent, old_layout); - update_geometry(parent); - - arrange_windows(parent, parent->width, parent->height); - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} - -static struct cmd_results *cmd_layout_auto(swayc_t *container, int argc, char **argv) { - // called after checking that argv[0] is auto, so just continue parsing from there - struct cmd_results *error = NULL; - const char *cmd_name = "layout auto"; - const char *set_inc_cmd_name = "layout auto [master|ncol] [set|inc]"; - const char *err_msg = "Allowed arguments are "; - - bool need_layout_update = false; - enum swayc_layouts old_layout = container->layout; - enum swayc_layouts layout = old_layout; - - if ((error = checkarg(argc, "layout auto", EXPECTED_MORE_THAN, 1))) { - return error; - } - - if (strcasecmp(argv[1], "left") == 0) { - layout = L_AUTO_LEFT; - } else if (strcasecmp(argv[1], "right") == 0) { - layout = L_AUTO_RIGHT; - } else if (strcasecmp(argv[1], "top") == 0) { - layout = L_AUTO_TOP; - } else if (strcasecmp(argv[1], "bottom") == 0) { - layout = L_AUTO_BOTTOM; - } else if (strcasecmp(argv[1], "next") == 0) { - if (is_auto_layout(container->layout) && container->layout < L_AUTO_LAST) { - layout = container->layout + 1; - } else { - layout = L_AUTO_FIRST; - } - } else if (strcasecmp(argv[1], "prev") == 0) { - if (is_auto_layout(container->layout) && container->layout > L_AUTO_FIRST) { - layout = container->layout - 1; - } else { - layout = L_AUTO_LAST; - } - } else { - bool is_nmaster; - bool is_set; - if (strcasecmp(argv[1], "master") == 0) { - is_nmaster = true; - } else if (strcasecmp(argv[1], "ncol") == 0) { - is_nmaster = false; - } else { - return cmd_results_new(CMD_INVALID, cmd_name, "Invalid %s command. %s", - cmd_name, err_msg); - } - if ((error = checkarg(argc, "auto ", EXPECTED_EQUAL_TO, 4))) { - return error; - } - if (strcasecmp(argv[2], "set") == 0) { - is_set = true; - } else if (strcasecmp(argv[2], "inc") == 0) { - is_set = false; - } else { - return cmd_results_new(CMD_INVALID, set_inc_cmd_name, "Invalid %s command. %s, " - "Argument must be on of ", - set_inc_cmd_name); - } - char *end; - int n = (int)strtol(argv[3], &end, 10); - if (*end) { - return cmd_results_new(CMD_INVALID, set_inc_cmd_name, "Invalid %s command " - "(argument must be an integer)", set_inc_cmd_name); - } - if (is_auto_layout(container->layout)) { - int inc = 0; /* difference between current master/ncol and requested value */ - if (is_nmaster) { - if (is_set) { - if (n < 0) { - return cmd_results_new(CMD_INVALID, set_inc_cmd_name, "Invalid %s command " - "(master must be >= 0)", set_inc_cmd_name); - } - inc = n - (int)container->nb_master; - } else { /* inc command */ - if ((int)container->nb_master + n >= 0) { - inc = n; - } - } - if (inc) { - for (int i = container->nb_master; - i >= 0 && i < container->children->length - && i != (int)container->nb_master + inc;) { - ((swayc_t *)container->children->items[i])->height = -1; - ((swayc_t *)container->children->items[i])->width = -1; - i += inc > 0 ? 1 : -1; - } - container->nb_master += inc; - need_layout_update = true; - } - } else { /* ncol modification */ - if (is_set) { - if (n <= 0) { - return cmd_results_new(CMD_INVALID, set_inc_cmd_name, "Invalid %s command " - "(ncol must be > 0)", set_inc_cmd_name); - } - inc = n - (int)container->nb_slave_groups; - } else { /* inc command */ - if ((int)container->nb_slave_groups + n > 0) { - inc = n; - } - } - if (inc) { - container->nb_slave_groups += inc; - need_layout_update = true; - } - } - } - } - - if (layout != old_layout) { - swayc_change_layout(container, layout); - update_layout_geometry(container, old_layout); - need_layout_update = true; - } - if (need_layout_update) { - update_geometry(container); - arrange_windows(container, container->width, container->height); - } - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/log_colors.c b/sway/commands/log_colors.c deleted file mode 100644 index 815d1942..00000000 --- a/sway/commands/log_colors.c +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "log.h" - -struct cmd_results *cmd_log_colors(int argc, char **argv) { - struct cmd_results *error = NULL; - if (!config->reading) return cmd_results_new(CMD_FAILURE, "log_colors", "Can only be used in config file."); - if ((error = checkarg(argc, "log_colors", EXPECTED_EQUAL_TO, 1))) { - return error; - } - if (strcasecmp(argv[0], "no") == 0) { - sway_log_colors(0); - } else if (strcasecmp(argv[0], "yes") == 0) { - sway_log_colors(1); - } else { - error = cmd_results_new(CMD_FAILURE, "log_colors", - "Invalid log_colors command (expected `yes` or `no`, got '%s')", argv[0]); - return error; - } - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/mark.c b/sway/commands/mark.c deleted file mode 100644 index c1d959df..00000000 --- a/sway/commands/mark.c +++ /dev/null @@ -1,87 +0,0 @@ -#include -#include -#include -#include "sway/commands.h" -#include "list.h" -#include "stringop.h" - -static void find_marks_callback(swayc_t *container, void *_mark) { - char *mark = (char *)_mark; - - int index; - if (container->marks && ((index = list_seq_find(container->marks, (int (*)(const void *, const void *))strcmp, mark)) != -1)) { - list_del(container->marks, index); - } -} - -struct cmd_results *cmd_mark(int argc, char **argv) { - struct cmd_results *error = NULL; - if (config->reading) return cmd_results_new(CMD_FAILURE, "mark", "Can't be used in config file."); - if ((error = checkarg(argc, "mark", EXPECTED_AT_LEAST, 1))) { - return error; - } - - swayc_t *view = current_container; - bool add = false; - bool toggle = false; - - if (strcmp(argv[0], "--add") == 0) { - --argc; ++argv; - add = true; - } else if (strcmp(argv[0], "--replace") == 0) { - --argc; ++argv; - } - - if (argc && strcmp(argv[0], "--toggle") == 0) { - --argc; ++argv; - toggle = true; - } - - if (argc) { - char *mark = join_args(argv, argc); - - // Remove all existing marks of this type - container_map(&root_container, find_marks_callback, mark); - - if (view->marks) { - if (add) { - int index; - if ((index = list_seq_find(view->marks, (int (*)(const void *, const void *))strcmp, mark)) != -1) { - if (toggle) { - free(view->marks->items[index]); - list_del(view->marks, index); - - if (0 == view->marks->length) { - list_free(view->marks); - view->marks = NULL; - } - } - free(mark); - } else { - list_add(view->marks, mark); - } - } else { - if (toggle && list_seq_find(view->marks, (int (*)(const void *, const void *))strcmp, mark) != -1) { - // Delete the list - list_foreach(view->marks, free); - list_free(view->marks); - view->marks = NULL; - } else { - // Delete and replace with a new list - list_foreach(view->marks, free); - list_free(view->marks); - - view->marks = create_list(); - list_add(view->marks, mark); - } - } - } else { - view->marks = create_list(); - list_add(view->marks, mark); - } - } else { - return cmd_results_new(CMD_FAILURE, "mark", - "Expected 'mark [--add|--replace] [--toggle] '"); - } - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/mode.c b/sway/commands/mode.c deleted file mode 100644 index d2985c54..00000000 --- a/sway/commands/mode.c +++ /dev/null @@ -1,57 +0,0 @@ -#define _XOPEN_SOURCE 500 -#include -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/ipc-server.h" -#include "list.h" -#include "log.h" - -struct cmd_results *cmd_mode(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "mode", EXPECTED_AT_LEAST, 1))) { - return error; - } - - const char *mode_name = argv[0]; - bool mode_make = (argc == 2 && strcmp(argv[1], "{") == 0); - if (mode_make) { - if (!config->reading) - return cmd_results_new(CMD_FAILURE, "mode", "Can only be used in config file."); - } - struct sway_mode *mode = NULL; - // Find mode - int i, len = config->modes->length; - for (i = 0; i < len; ++i) { - struct sway_mode *find = config->modes->items[i]; - if (strcasecmp(find->name, mode_name) == 0) { - mode = find; - break; - } - } - // Create mode if it doesn't exist - if (!mode && mode_make) { - mode = malloc(sizeof(struct sway_mode)); - if (!mode) { - return cmd_results_new(CMD_FAILURE, "mode", "Unable to allocate mode"); - } - mode->name = strdup(mode_name); - mode->bindings = create_list(); - list_add(config->modes, mode); - } - if (!mode) { - error = cmd_results_new(CMD_INVALID, "mode", "Unknown mode `%s'", mode_name); - return error; - } - if ((config->reading && mode_make) || (!config->reading && !mode_make)) { - sway_log(L_DEBUG, "Switching to mode `%s'",mode->name); - } - // Set current mode - config->current_mode = mode; - if (!mode_make) { - // trigger IPC mode event - ipc_event_mode(config->current_mode->name); - } - return cmd_results_new(mode_make ? CMD_BLOCK_MODE : CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/mouse_warping.c b/sway/commands/mouse_warping.c deleted file mode 100644 index 5596d483..00000000 --- a/sway/commands/mouse_warping.c +++ /dev/null @@ -1,17 +0,0 @@ -#include -#include -#include "sway/commands.h" - -struct cmd_results *cmd_mouse_warping(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "mouse_warping", EXPECTED_EQUAL_TO, 1))) { - return error; - } else if (strcasecmp(argv[0], "output") == 0) { - config->mouse_warping = true; - } else if (strcasecmp(argv[0], "none") == 0) { - config->mouse_warping = false; - } else { - return cmd_results_new(CMD_FAILURE, "mouse_warping", "Expected 'mouse_warping output|none'"); - } - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/move.c b/sway/commands/move.c deleted file mode 100644 index 52c73e22..00000000 --- a/sway/commands/move.c +++ /dev/null @@ -1,189 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include "sway/commands.h" -#include "sway/container.h" -#include "sway/layout.h" -#include "sway/output.h" -#include "sway/workspace.h" -#include "list.h" -#include "stringop.h" - -struct cmd_results *cmd_move(int argc, char **argv) { - struct cmd_results *error = NULL; - int move_amt = 10; - - if (config->reading) return cmd_results_new(CMD_FAILURE, "move", "Can't be used in config file."); - if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) { - return error; - } - const char* expected_syntax = "Expected 'move <[px] px>' or " - "'move to workspace ' or " - "'move to output ' or " - "'move position mouse'"; - swayc_t *view = current_container; - - if (argc == 2 || (argc == 3 && strcasecmp(argv[2], "px") == 0 )) { - char *inv; - move_amt = (int)strtol(argv[1], &inv, 10); - if (*inv != '\0' && strcasecmp(inv, "px") != 0) { - move_amt = 10; - } - } - - if (strcasecmp(argv[0], "left") == 0) { - move_container(view, MOVE_LEFT, move_amt); - } else if (strcasecmp(argv[0], "right") == 0) { - move_container(view, MOVE_RIGHT, move_amt); - } else if (strcasecmp(argv[0], "up") == 0) { - move_container(view, MOVE_UP, move_amt); - } else if (strcasecmp(argv[0], "down") == 0) { - move_container(view, MOVE_DOWN, move_amt); - } else if (strcasecmp(argv[0], "next") == 0) { - move_container(view, MOVE_NEXT, move_amt); - } else if (strcasecmp(argv[0], "prev") == 0) { - move_container(view, MOVE_PREV, move_amt); - } else if (strcasecmp(argv[0], "first") == 0) { - move_container(view, MOVE_FIRST, move_amt); - } else if (strcasecmp(argv[0], "container") == 0 || strcasecmp(argv[0], "window") == 0) { - // "move container ... - if ((error = checkarg(argc, "move container/window", EXPECTED_AT_LEAST, 4))) { - return error; - } else if (strcasecmp(argv[1], "to") == 0 && strcasecmp(argv[2], "workspace") == 0) { - // move container to workspace x - if (view->type == C_WORKSPACE) { - if (!view->children || view->children->length == 0) { - return cmd_results_new(CMD_FAILURE, "move", "Cannot move an empty workspace"); - } - view = new_container(view, view->workspace_layout); - } if (view->type != C_CONTAINER && view->type != C_VIEW) { - return cmd_results_new(CMD_FAILURE, "move", "Can only move containers and views."); - } - - swayc_t *ws; - const char *num_name = NULL; - char *ws_name = NULL; - if (argc == 5 && strcasecmp(argv[3], "number") == 0) { - // move "container to workspace number x" - num_name = argv[4]; - ws = workspace_by_number(num_name); - } else { - ws_name = join_args(argv + 3, argc - 3); - ws = workspace_by_name(ws_name); - } - - if (ws == NULL) { - ws = workspace_create(ws_name ? ws_name : num_name); - } - if (ws_name) { - free(ws_name); - } - move_container_to(view, get_focused_container(ws)); - } else if (strcasecmp(argv[1], "to") == 0 && strcasecmp(argv[2], "output") == 0) { - // move container to output x - swayc_t *output = NULL; - struct wlc_point abs_pos; - get_absolute_center_position(view, &abs_pos); - if (view->type == C_WORKSPACE) { - if (!view->children || view->children->length == 0) { - return cmd_results_new(CMD_FAILURE, "move", "Cannot move an empty workspace"); - } - view = new_container(view, view->workspace_layout); - } else if (view->type != C_CONTAINER && view->type != C_VIEW) { - return cmd_results_new(CMD_FAILURE, "move", "Can only move containers and views."); - } else if (!(output = output_by_name(argv[3], &abs_pos))) { - return cmd_results_new(CMD_FAILURE, "move", - "Can't find output with name/direction '%s' @ (%i,%i)", argv[3], abs_pos.x, abs_pos.y); - } - - swayc_t *container = get_focused_container(output); - if (container->is_floating) { - move_container_to(view, container->parent); - } else { - move_container_to(view, container); - } - } else { - return cmd_results_new(CMD_INVALID, "move", expected_syntax); - } - } else if (strcasecmp(argv[0], "workspace") == 0) { - // move workspace (to output x) - swayc_t *output = NULL; - struct wlc_point abs_pos; - get_absolute_center_position(view, &abs_pos); - if ((error = checkarg(argc, "move workspace", EXPECTED_EQUAL_TO, 4))) { - return error; - } else if (strcasecmp(argv[1], "to") != 0 || strcasecmp(argv[2], "output") != 0) { - return cmd_results_new(CMD_INVALID, "move", expected_syntax); - } else if (!(output = output_by_name(argv[3], &abs_pos))) { - return cmd_results_new(CMD_FAILURE, "move workspace", - "Can't find output with name/direction '%s' @ (%i,%i)", argv[3], abs_pos.x, abs_pos.y); - } - if (view->type == C_WORKSPACE) { - // This probably means we're moving an empty workspace, but - // that's fine. - move_workspace_to(view, output); - } else { - swayc_t *workspace = swayc_parent_by_type(view, C_WORKSPACE); - move_workspace_to(workspace, output); - } - } else if (strcasecmp(argv[0], "scratchpad") == 0 || (strcasecmp(argv[0], "to") == 0 && strcasecmp(argv[1], "scratchpad") == 0)) { - // move scratchpad ... - if (view->type != C_CONTAINER && view->type != C_VIEW) { - return cmd_results_new(CMD_FAILURE, "move scratchpad", "Can only move containers and views."); - } - swayc_t *view = current_container; - int i; - for (i = 0; i < scratchpad->length; i++) { - if (scratchpad->items[i] == view) { - hide_view_in_scratchpad(view); - sp_view = NULL; - return cmd_results_new(CMD_SUCCESS, NULL, NULL); - } - } - list_add(scratchpad, view); - if (!view->is_floating) { - destroy_container(remove_child(view)); - } else { - remove_child(view); - } - wlc_view_set_mask(view->handle, 0); - arrange_windows(swayc_active_workspace(), -1, -1); - swayc_t *focused = container_under_pointer(); - if (focused == NULL) { - focused = swayc_active_workspace(); - } - set_focused_container(focused); - } else if (strcasecmp(argv[0], "position") == 0) { - if ((error = checkarg(argc, "move workspace", EXPECTED_EQUAL_TO, 2))) { - return error; - } - if (strcasecmp(argv[1], "mouse")) { - return cmd_results_new(CMD_INVALID, "move", expected_syntax); - } - - if (view->is_floating) { - swayc_t *output = swayc_parent_by_type(view, C_OUTPUT); - struct wlc_geometry g; - wlc_view_get_visible_geometry(view->handle, &g); - const struct wlc_size *size = wlc_output_get_resolution(output->handle); - - double x_pos, y_pos; - wlc_pointer_get_position_v2(&x_pos, &y_pos); - - int32_t x = x_pos - g.size.w / 2; - int32_t y = y_pos - g.size.h / 2; - - uint32_t w = size->w - g.size.w; - uint32_t h = size->h - g.size.h; - - view->x = g.origin.x = MIN((int32_t)w, MAX(x, 0)); - view->y = g.origin.y = MIN((int32_t)h, MAX(y, 0)); - - wlc_view_set_geometry(view->handle, 0, &g); - } - } else { - return cmd_results_new(CMD_INVALID, "move", expected_syntax); - } - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/new_float.c b/sway/commands/new_float.c deleted file mode 100644 index d0f96093..00000000 --- a/sway/commands/new_float.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "log.h" -#include "sway/commands.h" - -struct cmd_results *cmd_new_float(int argc, char **argv) { - sway_log(L_INFO, "`new_float` is deprecated and will be removed in the future. " - "Please use `default_floating_border` instead."); - return cmd_default_floating_border(argc, argv); -} diff --git a/sway/commands/new_window.c b/sway/commands/new_window.c deleted file mode 100644 index 574a4527..00000000 --- a/sway/commands/new_window.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "log.h" -#include "sway/commands.h" - -struct cmd_results *cmd_new_window(int argc, char **argv) { - sway_log(L_INFO, "`new_window` is deprecated and will be removed in the future. " - "Please use `default_border` instead."); - return cmd_default_border(argc, argv); -} diff --git a/sway/commands/no_focus.c b/sway/commands/no_focus.c deleted file mode 100644 index b3b88e5a..00000000 --- a/sway/commands/no_focus.c +++ /dev/null @@ -1,41 +0,0 @@ -#define _XOPEN_SOURCE 500 -#include -#include "sway/commands.h" -#include "sway/criteria.h" -#include "list.h" -#include "log.h" -#include "stringop.h" - -struct cmd_results *cmd_no_focus(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "no_focus", EXPECTED_EQUAL_TO, 1))) { - return error; - } - // add command to a criteria/command pair that is run against views when they appear. - char *criteria = argv[0]; - - struct criteria *crit = malloc(sizeof(struct criteria)); - if (!crit) { - return cmd_results_new(CMD_FAILURE, "no_focus", "Unable to allocate criteria"); - } - crit->crit_raw = strdup(criteria); - crit->tokens = create_list(); - crit->cmdlist = NULL; - char *err_str = extract_crit_tokens(crit->tokens, crit->crit_raw); - - if (err_str) { - error = cmd_results_new(CMD_INVALID, "no_focus", err_str); - free(err_str); - free_criteria(crit); - } else if (crit->tokens->length == 0) { - error = cmd_results_new(CMD_INVALID, "no_focus", "Found no name/value pairs in criteria"); - free_criteria(crit); - } else if (list_seq_find(config->no_focus, criteria_cmp, crit) != -1) { - sway_log(L_DEBUG, "no_focus: Duplicate, skipping."); - free_criteria(crit); - } else { - sway_log(L_DEBUG, "no_focus: '%s' added", crit->crit_raw); - list_add(config->no_focus, crit); - } - return error ? error : cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/orientation.c b/sway/commands/orientation.c deleted file mode 100644 index e54b60ee..00000000 --- a/sway/commands/orientation.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include -#include "sway/commands.h" - -struct cmd_results *cmd_orientation(int argc, char **argv) { - struct cmd_results *error = NULL; - if (!config->reading) return cmd_results_new(CMD_FAILURE, "orientation", "Can only be used in config file."); - if ((error = checkarg(argc, "orientation", EXPECTED_EQUAL_TO, 1))) { - return error; - } - if (strcasecmp(argv[0], "horizontal") == 0) { - config->default_orientation = L_HORIZ; - } else if (strcasecmp(argv[0], "vertical") == 0) { - config->default_orientation = L_VERT; - } else if (strcasecmp(argv[0], "auto") == 0) { - // Do nothing - } else { - return cmd_results_new(CMD_INVALID, "orientation", "Expected 'orientation '"); - } - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/output.c b/sway/commands/output.c deleted file mode 100644 index 911391d2..00000000 --- a/sway/commands/output.c +++ /dev/null @@ -1,219 +0,0 @@ -#define _XOPEN_SOURCE 500 -#include -#include -#include -#include -#include -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "list.h" -#include "log.h" -#include "stringop.h" - -static char *bg_options[] = { - "stretch", - "center", - "fill", - "fit", - "tile" -}; - -struct cmd_results *cmd_output(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "output", EXPECTED_AT_LEAST, 1))) { - return error; - } - const char *name = argv[0]; - - struct output_config *output = calloc(1, sizeof(struct output_config)); - if (!output) { - return cmd_results_new(CMD_FAILURE, "output", "Unable to allocate output config"); - } - output->x = output->y = output->width = output->height = -1; - output->name = strdup(name); - output->enabled = -1; - output->scale = 1; - - // TODO: atoi doesn't handle invalid numbers - - int i; - for (i = 1; i < argc; ++i) { - const char *command = argv[i]; - - if (strcasecmp(command, "disable") == 0) { - output->enabled = 0; - } else if (strcasecmp(command, "resolution") == 0 || strcasecmp(command, "res") == 0) { - if (++i >= argc) { - error = cmd_results_new(CMD_INVALID, "output", "Missing resolution argument."); - goto fail; - } - char *res = argv[i]; - char *x = strchr(res, 'x'); - int width = -1, height = -1; - if (x != NULL) { - // Format is 1234x4321 - *x = '\0'; - width = atoi(res); - height = atoi(x + 1); - *x = 'x'; - } else { - // Format is 1234 4321 - width = atoi(res); - if (++i >= argc) { - error = cmd_results_new(CMD_INVALID, "output", "Missing resolution argument (height)."); - goto fail; - } - res = argv[i]; - height = atoi(res); - } - output->width = width; - output->height = height; - } else if (strcasecmp(command, "position") == 0 || strcasecmp(command, "pos") == 0) { - if (++i >= argc) { - error = cmd_results_new(CMD_INVALID, "output", "Missing position argument."); - goto fail; - } - char *res = argv[i]; - char *c = strchr(res, ','); - int x = -1, y = -1; - if (c != NULL) { - // Format is 1234,4321 - *c = '\0'; - x = atoi(res); - y = atoi(c + 1); - *c = ','; - } else { - // Format is 1234 4321 - x = atoi(res); - if (++i >= argc) { - error = cmd_results_new(CMD_INVALID, "output", "Missing position argument (y)."); - goto fail; - } - res = argv[i]; - y = atoi(res); - } - output->x = x; - output->y = y; - } else if (strcasecmp(command, "scale") == 0) { - if (++i >= argc) { - error = cmd_results_new(CMD_INVALID, "output", "Missing scale parameter."); - goto fail; - } - output->scale = atoi(argv[i]); - } else if (strcasecmp(command, "background") == 0 || strcasecmp(command, "bg") == 0) { - wordexp_t p; - if (++i >= argc) { - error = cmd_results_new(CMD_INVALID, "output", "Missing background file or color specification."); - goto fail; - } - if (i + 1 >= argc) { - error = cmd_results_new(CMD_INVALID, "output", "Missing background scaling mode or `solid_color`."); - goto fail; - } - if (strcasecmp(argv[i + 1], "solid_color") == 0) { - output->background = strdup(argv[argc - 2]); - output->background_option = strdup("solid_color"); - } else { - // argv[i+j]=bg_option - bool valid = false; - char *mode; - size_t j; - for (j = 0; j < (size_t) (argc - i); ++j) { - mode = argv[i + j]; - for (size_t k = 0; k < sizeof(bg_options) / sizeof(char *); ++k) { - if (strcasecmp(mode, bg_options[k]) == 0) { - valid = true; - break; - } - } - if (valid) { - break; - } - } - if (!valid) { - error = cmd_results_new(CMD_INVALID, "output", "Missing background scaling mode."); - goto fail; - } - - char *src = join_args(argv + i, j); - if (wordexp(src, &p, 0) != 0 || p.we_wordv[0] == NULL) { - error = cmd_results_new(CMD_INVALID, "output", "Invalid syntax (%s)", src); - goto fail; - } - free(src); - src = p.we_wordv[0]; - if (config->reading && *src != '/') { - char *conf = strdup(config->current_config); - if (conf) { - char *conf_path = dirname(conf); - src = malloc(strlen(conf_path) + strlen(src) + 2); - if (src) { - sprintf(src, "%s/%s", conf_path, p.we_wordv[0]); - } else { - sway_log(L_ERROR, "Unable to allocate background source"); - } - free(conf); - } else { - sway_log(L_ERROR, "Unable to allocate background source"); - } - } - if (!src || access(src, F_OK) == -1) { - error = cmd_results_new(CMD_INVALID, "output", "Background file unreadable (%s)", src); - wordfree(&p); - goto fail; - } - - output->background = strdup(src); - output->background_option = strdup(mode); - if (src != p.we_wordv[0]) { - free(src); - } - wordfree(&p); - - i += j; - } - } - } - - i = list_seq_find(config->output_configs, output_name_cmp, name); - if (i >= 0) { - // merge existing config - struct output_config *oc = config->output_configs->items[i]; - merge_output_config(oc, output); - free_output_config(output); - output = oc; - } else { - list_add(config->output_configs, output); - } - - sway_log(L_DEBUG, "Config stored for output %s (enabled:%d) (%d x %d @ %d, %d scale %d) (bg %s %s)", - output->name, output->enabled, output->width, - output->height, output->x, output->y, output->scale, - output->background, output->background_option); - - if (output->name) { - // Try to find the output container and apply configuration now. If - // this is during startup then there will be no container and config - // will be applied during normal "new output" event from wlc. - swayc_t *cont = NULL; - for (int i = 0; i < root_container.children->length; ++i) { - cont = root_container.children->items[i]; - if (cont->name && ((strcmp(cont->name, output->name) == 0) || (strcmp(output->name, "*") == 0))) { - apply_output_config(output, cont); - - if (strcmp(output->name, "*") != 0) { - // stop looking if the output config isn't applicable to all outputs - break; - } - } - } - } - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); - -fail: - free_output_config(output); - return error; -} diff --git a/sway/commands/permit.c b/sway/commands/permit.c deleted file mode 100644 index 7a5e06f7..00000000 --- a/sway/commands/permit.c +++ /dev/null @@ -1,108 +0,0 @@ -#define _XOPEN_SOURCE 500 -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/security.h" -#include "util.h" -#include "log.h" - -static enum secure_feature get_features(int argc, char **argv, - struct cmd_results **error) { - enum secure_feature features = 0; - - struct { - char *name; - enum secure_feature feature; - } feature_names[] = { - { "lock", FEATURE_LOCK }, - { "panel", FEATURE_PANEL }, - { "background", FEATURE_BACKGROUND }, - { "screenshot", FEATURE_SCREENSHOT }, - { "fullscreen", FEATURE_FULLSCREEN }, - { "keyboard", FEATURE_KEYBOARD }, - { "mouse", FEATURE_MOUSE }, - }; - - for (int i = 1; i < argc; ++i) { - size_t j; - for (j = 0; j < sizeof(feature_names) / sizeof(feature_names[0]); ++j) { - if (strcmp(feature_names[j].name, argv[i]) == 0) { - break; - } - } - if (j == sizeof(feature_names) / sizeof(feature_names[0])) { - *error = cmd_results_new(CMD_INVALID, - "permit", "Invalid feature grant %s", argv[i]); - return 0; - } - features |= feature_names[j].feature; - } - return features; -} - -struct cmd_results *cmd_permit(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "permit", EXPECTED_MORE_THAN, 1))) { - return error; - } - if ((error = check_security_config())) { - return error; - } - - bool assign_perms = true; - char *program = NULL; - - if (!strcmp(argv[0], "*")) { - program = strdup(argv[0]); - } else { - program = resolve_path(argv[0]); - } - if (!program) { - sway_assert(program, "Unable to resolve IPC permit target '%s'." - " will issue empty policy", argv[0]); - assign_perms = false; - program = strdup(argv[0]); - } - - struct feature_policy *policy = get_feature_policy(program); - if (policy && assign_perms) { - policy->features |= get_features(argc, argv, &error); - sway_log(L_DEBUG, "Permissions granted to %s for features %d", - policy->program, policy->features); - } - - free(program); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} - -struct cmd_results *cmd_reject(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "reject", EXPECTED_MORE_THAN, 1))) { - return error; - } - if ((error = check_security_config())) { - return error; - } - - char *program = NULL; - if (!strcmp(argv[0], "*")) { - program = strdup(argv[0]); - } else { - program = resolve_path(argv[0]); - } - if (!program) { - // Punt - sway_log(L_INFO, "Unable to resolve IPC reject target '%s'." - " Will use provided path", argv[0]); - program = strdup(argv[0]); - } - - struct feature_policy *policy = get_feature_policy(program); - policy->features &= ~get_features(argc, argv, &error); - - sway_log(L_DEBUG, "Permissions granted to %s for features %d", - policy->program, policy->features); - - free(program); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/reload.c b/sway/commands/reload.c deleted file mode 100644 index 01fcc5ba..00000000 --- a/sway/commands/reload.c +++ /dev/null @@ -1,19 +0,0 @@ -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/layout.h" - -struct cmd_results *cmd_reload(int argc, char **argv) { - struct cmd_results *error = NULL; - if (config->reading) return cmd_results_new(CMD_FAILURE, "reload", "Can't be used in config file."); - if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) { - return error; - } - if (!load_main_config(config->current_config, true)) { - return cmd_results_new(CMD_FAILURE, "reload", "Error(s) reloading config."); - } - - load_swaybars(); - - arrange_windows(&root_container, -1, -1); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/resize.c b/sway/commands/resize.c deleted file mode 100644 index ef52bb07..00000000 --- a/sway/commands/resize.c +++ /dev/null @@ -1,375 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include "sway/commands.h" -#include "sway/layout.h" -#include "sway/focus.h" -#include "sway/input_state.h" -#include "sway/handlers.h" -#include "log.h" - -enum resize_dim_types { - RESIZE_DIM_PX, - RESIZE_DIM_PPT, - RESIZE_DIM_DEFAULT, -}; - -static bool set_size_floating(int new_dimension, bool use_width) { - swayc_t *view = current_container; - if (view) { - if (use_width) { - int current_width = view->width; - view->desired_width = new_dimension; - floating_view_sane_size(view); - - int new_x = view->x + (int)(((view->desired_width - current_width) / 2) * -1); - view->width = view->desired_width; - view->x = new_x; - - update_geometry(view); - } else { - int current_height = view->height; - view->desired_height = new_dimension; - floating_view_sane_size(view); - - int new_y = view->y + (int)(((view->desired_height - current_height) / 2) * -1); - view->height = view->desired_height; - view->y = new_y; - - update_geometry(view); - } - - return true; - } - - return false; -} - -static bool resize_floating(int amount, bool use_width) { - swayc_t *view = current_container; - - if (view) { - if (use_width) { - return set_size_floating(view->width + amount, true); - } else { - return set_size_floating(view->height + amount, false); - } - } - - return false; -} - -static bool resize_tiled(int amount, bool use_width) { - swayc_t *container = current_container; - swayc_t *parent = container->parent; - int idx_focused = 0; - bool use_major = false; - size_t nb_before = 0; - size_t nb_after = 0; - - // 1. Identify a container ancestor that will allow the focused child to grow in the requested - // direction. - while (container->parent) { - parent = container->parent; - if ((parent->children && parent->children->length > 1) - && (is_auto_layout(parent->layout) - || (use_width ? parent->layout == L_HORIZ : parent->layout == L_VERT))) { - // check if container has siblings that can provide/absorb the space needed for - // the resize operation. - use_major = use_width - ? parent->layout == L_AUTO_LEFT || parent->layout == L_AUTO_RIGHT - : parent->layout == L_AUTO_TOP || parent->layout == L_AUTO_BOTTOM; - // Note: use_major will be false for L_HORIZ and L_VERT - - idx_focused = index_child(container); - if (idx_focused < 0) { - sway_log(L_ERROR, "Something weird is happening, child container not " - "present in its parent's children list."); - continue; - } - if (use_major) { - nb_before = auto_group_index(parent, idx_focused); - nb_after = auto_group_count(parent) - nb_before - 1; - } else { - nb_before = idx_focused - auto_group_start_index(parent, idx_focused); - nb_after = auto_group_end_index(parent, idx_focused) - idx_focused - 1; - sway_log(L_DEBUG, "+++ focused: %d, start: %d, end: %d, before: %d, after: %d", - idx_focused, - (int)auto_group_start_index(parent, idx_focused), - (int)auto_group_end_index(parent, idx_focused), - (int)nb_before, (int)nb_after); - - } - if (nb_before || nb_after) { - break; - } - } - container = parent; /* continue up the tree to the next ancestor */ - } - if (parent == &root_container) { - return true; - } - sway_log(L_DEBUG, "Found the proper parent: %p. It has %zu before conts, " - "and %zu after conts", parent, nb_before, nb_after); - // 2. Ensure that the resize operation will not make one of the resized containers drop - // below the "sane" size threshold. - bool valid = true; - swayc_t *focused = parent->children->items[idx_focused]; - int start = use_major ? 0 : auto_group_start_index(parent, idx_focused); - int end = use_major ? parent->children->length : auto_group_end_index(parent, idx_focused); - sway_log(L_DEBUG, "Check children of container %p [%d,%d[", container, start, end); - for (int i = start; i < end; ) { - swayc_t *sibling = parent->children->items[i]; - double pixels = amount; - bool is_before = use_width ? sibling->x < focused->x : sibling->y < focused->y; - bool is_after = use_width ? sibling->x > focused->x : sibling->y > focused->y; - if (is_before || is_after) { - pixels = -pixels; - pixels /= is_before ? nb_before : nb_after; - if (nb_after != 0 && nb_before != 0) { - pixels /= 2; - } - } - sway_log(L_DEBUG, "Check container %p: width %g vs %d, height %g vs %d", sibling, sibling->width + pixels, min_sane_w, sibling->height + pixels, min_sane_h); - if (use_width ? - sibling->width + pixels < min_sane_w : - sibling->height + pixels < min_sane_h) { - valid = false; - sway_log(L_DEBUG, "Container size no longer sane"); - break; - } - i = use_major ? auto_group_end_index(parent, i) : (i + 1); - sway_log(L_DEBUG, "+++++ check %i", i); - } - // 3. Apply the size change - if (valid) { - for (int i = start; i < end; ) { - int next_i = use_major ? auto_group_end_index(parent, i) : (i + 1); - swayc_t *sibling = parent->children->items[i]; - double pixels = amount; - bool is_before = use_width ? sibling->x < focused->x : sibling->y < focused->y; - bool is_after = use_width ? sibling->x > focused->x : sibling->y > focused->y; - if (is_before || is_after) { - pixels = -pixels; - pixels /= is_before ? nb_before : nb_after; - if (nb_after != 0 && nb_before != 0) { - pixels /= 2; - } - sway_log(L_DEBUG, "%p: %s", sibling, is_before ? "before" : "after"); - if (use_major) { - for (int j = i; j < next_i; ++j) { - recursive_resize(parent->children->items[j], pixels, - use_width ? - (is_before ? WLC_RESIZE_EDGE_RIGHT : WLC_RESIZE_EDGE_LEFT) : - (is_before ? WLC_RESIZE_EDGE_BOTTOM : WLC_RESIZE_EDGE_TOP)); - } - } else { - recursive_resize(sibling, pixels, - use_width ? - (is_before ? WLC_RESIZE_EDGE_RIGHT : WLC_RESIZE_EDGE_LEFT) : - (is_before ? WLC_RESIZE_EDGE_BOTTOM : WLC_RESIZE_EDGE_TOP)); - } - } else { - if (use_major) { - for (int j = i; j < next_i; ++j) { - recursive_resize(parent->children->items[j], pixels / 2, - use_width ? WLC_RESIZE_EDGE_LEFT : WLC_RESIZE_EDGE_TOP); - recursive_resize(parent->children->items[j], pixels / 2, - use_width ? WLC_RESIZE_EDGE_RIGHT : WLC_RESIZE_EDGE_BOTTOM); - } - } else { - recursive_resize(sibling, pixels / 2, - use_width ? WLC_RESIZE_EDGE_LEFT : WLC_RESIZE_EDGE_TOP); - recursive_resize(sibling, pixels / 2, - use_width ? WLC_RESIZE_EDGE_RIGHT : WLC_RESIZE_EDGE_BOTTOM); - } - } - i = next_i; - } - // Recursive resize does not handle positions, let arrange_windows - // take care of that. - arrange_windows(swayc_active_workspace(), -1, -1); - } - return true; -} - -static bool set_size_tiled(int amount, bool use_width) { - int desired; - swayc_t *focused = current_container; - - if (use_width) { - desired = amount - focused->width; - } else { - desired = amount - focused->height; - } - - return resize_tiled(desired, use_width); -} - -static bool set_size(int dimension, bool use_width) { - swayc_t *focused = current_container; - - if (focused) { - if (focused->is_floating) { - return set_size_floating(dimension, use_width); - } else { - return set_size_tiled(dimension, use_width); - } - } - - return false; -} - -static bool resize(int dimension, bool use_width, enum resize_dim_types dim_type) { - swayc_t *focused = current_container; - - // translate "10 ppt" (10%) to appropriate # of pixels in case we need it - float ppt_dim = (float)dimension / 100; - - if (use_width) { - ppt_dim = focused->width * ppt_dim; - } else { - ppt_dim = focused->height * ppt_dim; - } - - if (focused) { - if (focused->is_floating) { - // floating view resize dimensions should default to px, so only - // use ppt if specified - if (dim_type == RESIZE_DIM_PPT) { - dimension = (int)ppt_dim; - } - - return resize_floating(dimension, use_width); - } else { - // tiled view resize dimensions should default to ppt, so only use - // px if specified - if (dim_type != RESIZE_DIM_PX) { - dimension = (int)ppt_dim; - } - - return resize_tiled(dimension, use_width); - } - } - - return false; -} - -static struct cmd_results *cmd_resize_set(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "resize set", EXPECTED_AT_LEAST, 2))) { - return error; - } - - if (strcasecmp(argv[0], "width") == 0 || strcasecmp(argv[0], "height") == 0) { - // handle `reset set width 100 px height 100 px` syntax, also allows - // specifying only one dimension for a `resize set` - int cmd_num = 0; - int dim; - - while ((cmd_num + 1) < argc) { - dim = (int)strtol(argv[cmd_num + 1], NULL, 10); - if (errno == ERANGE || dim == 0) { - errno = 0; - return cmd_results_new(CMD_INVALID, "resize set", - "Expected 'resize set [px] [ [px]]'"); - } - - if (strcasecmp(argv[cmd_num], "width") == 0) { - set_size(dim, true); - } else if (strcasecmp(argv[cmd_num], "height") == 0) { - set_size(dim, false); - } else { - return cmd_results_new(CMD_INVALID, "resize set", - "Expected 'resize set [px] [ [px]]'"); - } - - cmd_num += 2; - - if (cmd_num < argc && strcasecmp(argv[cmd_num], "px") == 0) { - // if this was `resize set width 400 px height 300 px`, disregard the `px` arg - cmd_num++; - } - } - } else { - // handle `reset set 100 px 100 px` syntax - int width = (int)strtol(argv[0], NULL, 10); - if (errno == ERANGE || width == 0) { - errno = 0; - return cmd_results_new(CMD_INVALID, "resize set", - "Expected 'resize set [px] [px]'"); - } - - int height_arg = 1; - if (strcasecmp(argv[1], "px") == 0) { - height_arg = 2; - } - - int height = (int)strtol(argv[height_arg], NULL, 10); - if (errno == ERANGE || height == 0) { - errno = 0; - return cmd_results_new(CMD_INVALID, "resize set", - "Expected 'resize set [px] [px]'"); - } - - set_size(width, true); - set_size(height, false); - } - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} - -struct cmd_results *cmd_resize(int argc, char **argv) { - struct cmd_results *error = NULL; - if (config->reading) return cmd_results_new(CMD_FAILURE, "resize", "Can't be used in config file."); - if (!config->active) return cmd_results_new(CMD_FAILURE, "resize", "Can only be used when sway is running."); - - if (strcasecmp(argv[0], "set") == 0) { - return cmd_resize_set(argc - 1, &argv[1]); - } - - if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) { - return error; - } - - int dim_arg = argc - 1; - - enum resize_dim_types dim_type = RESIZE_DIM_DEFAULT; - if (strcasecmp(argv[dim_arg], "ppt") == 0) { - dim_type = RESIZE_DIM_PPT; - dim_arg--; - } else if (strcasecmp(argv[dim_arg], "px") == 0) { - dim_type = RESIZE_DIM_PX; - dim_arg--; - } - - int amount = (int)strtol(argv[dim_arg], NULL, 10); - if (errno == ERANGE || amount == 0) { - errno = 0; - amount = 10; // this is the default resize dimension used by i3 for both px and ppt - sway_log(L_DEBUG, "Tried to get resize dimension out of '%s' but failed; setting dimension to default %d", - argv[dim_arg], amount); - } - - bool use_width = false; - if (strcasecmp(argv[1], "width") == 0) { - use_width = true; - } else if (strcasecmp(argv[1], "height") != 0) { - return cmd_results_new(CMD_INVALID, "resize", - "Expected 'resize [] [px|ppt]'"); - } - - if (strcasecmp(argv[0], "shrink") == 0) { - amount *= -1; - } else if (strcasecmp(argv[0], "grow") != 0) { - return cmd_results_new(CMD_INVALID, "resize", - "Expected 'resize [] [px|ppt]'"); - } - - resize(amount, use_width, dim_type); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/scratchpad.c b/sway/commands/scratchpad.c deleted file mode 100644 index 6c5c92df..00000000 --- a/sway/commands/scratchpad.c +++ /dev/null @@ -1,72 +0,0 @@ -#include -#include -#include -#include "sway/commands.h" -#include "sway/container.h" -#include "sway/focus.h" -#include "sway/layout.h" - -static swayc_t *fetch_view_from_scratchpad() { - sp_index = (sp_index + 1) % scratchpad->length; - swayc_t *view = scratchpad->items[sp_index]; - - if (wlc_view_get_output(view->handle) != swayc_active_output()->handle) { - wlc_view_set_output(view->handle, swayc_active_output()->handle); - } - if (!view->is_floating) { - view->width = swayc_active_workspace()->width * 0.5; - view->height = swayc_active_workspace()->height * 0.75; - view->x = (swayc_active_workspace()->width - view->width)/2; - view->y = (swayc_active_workspace()->height - view->height)/2; - } - if (swayc_active_workspace()->width < view->x + 20 || view->x + view->width < 20) { - view->x = (swayc_active_workspace()->width - view->width)/2; - } - if (swayc_active_workspace()->height < view->y + 20 || view->y + view->height < 20) { - view->y = (swayc_active_workspace()->height - view->height)/2; - } - - add_floating(swayc_active_workspace(), view); - wlc_view_set_mask(view->handle, VISIBLE); - view->visible = true; - arrange_windows(swayc_active_workspace(), -1, -1); - set_focused_container(view); - return view; -} - -struct cmd_results *cmd_scratchpad(int argc, char **argv) { - struct cmd_results *error = NULL; - if (config->reading) return cmd_results_new(CMD_FAILURE, "scratchpad", "Can't be used in config file."); - if (!config->active) return cmd_results_new(CMD_FAILURE, "scratchpad", "Can only be used when sway is running."); - if ((error = checkarg(argc, "scratchpad", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - if (strcasecmp(argv[0], "show") == 0 && scratchpad->length > 0) { - if (!sp_view) { - if (current_container) { - // Haxor the scratchpad index if criteria'd - for (int i = 0; i < scratchpad->length; ++i) { - if (scratchpad->items[i] == current_container) { - sp_index = (i - 1) % scratchpad->length; - } - } - } - sp_view = fetch_view_from_scratchpad(); - } else { - if (swayc_active_workspace() != sp_view->parent) { - hide_view_in_scratchpad(sp_view); - if (sp_index == 0) { - sp_index = scratchpad->length; - } - sp_index--; - sp_view = fetch_view_from_scratchpad(); - } else { - hide_view_in_scratchpad(sp_view); - sp_view = NULL; - } - } - return cmd_results_new(CMD_SUCCESS, NULL, NULL); - } - return cmd_results_new(CMD_FAILURE, "scratchpad", "Expected 'scratchpad show' when scratchpad is not empty."); -} diff --git a/sway/commands/seamless_mouse.c b/sway/commands/seamless_mouse.c deleted file mode 100644 index 7760e88d..00000000 --- a/sway/commands/seamless_mouse.c +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include -#include "sway/commands.h" - -struct cmd_results *cmd_seamless_mouse(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "seamless_mouse", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - config->seamless_mouse = (strcasecmp(argv[0], "on") == 0 || strcasecmp(argv[0], "yes") == 0); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/set.c b/sway/commands/set.c deleted file mode 100644 index 46fc6d38..00000000 --- a/sway/commands/set.c +++ /dev/null @@ -1,61 +0,0 @@ -#define _XOPEN_SOURCE 700 -#include -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "list.h" -#include "stringop.h" - -// sort in order of longest->shortest -static int compare_set_qsort(const void *_l, const void *_r) { - struct sway_variable const *l = *(void **)_l; - struct sway_variable const *r = *(void **)_r; - return strlen(r->name) - strlen(l->name); -} - -struct cmd_results *cmd_set(int argc, char **argv) { - char *tmp; - struct cmd_results *error = NULL; - if (!config->reading) return cmd_results_new(CMD_FAILURE, "set", "Can only be used in config file."); - if ((error = checkarg(argc, "set", EXPECTED_AT_LEAST, 2))) { - return error; - } - - if (argv[0][0] != '$') { - sway_log(L_INFO, "Warning: variable '%s' doesn't start with $", argv[0]); - - size_t size = snprintf(NULL, 0, "$%s", argv[0]); - tmp = malloc(size + 1); - if (!tmp) { - return cmd_results_new(CMD_FAILURE, "set", "Not possible to create variable $'%s'", argv[0]); - } - snprintf(tmp, size+1, "$%s", argv[0]); - - argv[0] = tmp; - } - - struct sway_variable *var = NULL; - // Find old variable if it exists - int i; - for (i = 0; i < config->symbols->length; ++i) { - var = config->symbols->items[i]; - if (strcmp(var->name, argv[0]) == 0) { - break; - } - var = NULL; - } - if (var) { - free(var->value); - } else { - var = malloc(sizeof(struct sway_variable)); - if (!var) { - return cmd_results_new(CMD_FAILURE, "set", "Unable to allocate variable"); - } - var->name = strdup(argv[0]); - list_add(config->symbols, var); - list_qsort(config->symbols, compare_set_qsort); - } - var->value = join_args(argv + 1, argc - 1); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/show_marks.c b/sway/commands/show_marks.c deleted file mode 100644 index ed56d9e5..00000000 --- a/sway/commands/show_marks.c +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include -#include "sway/commands.h" - -struct cmd_results *cmd_show_marks(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "show_marks", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - config->show_marks = !strcasecmp(argv[0], "on"); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/smart_gaps.c b/sway/commands/smart_gaps.c deleted file mode 100644 index 815fc501..00000000 --- a/sway/commands/smart_gaps.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include -#include "sway/commands.h" - -struct cmd_results *cmd_smart_gaps(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "smart_gaps", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - if (strcasecmp(argv[0], "on") == 0) { - config->smart_gaps = true; - } else if (strcasecmp(argv[0], "off") == 0) { - config->smart_gaps = false; - } else { - return cmd_results_new(CMD_INVALID, "smart_gaps", "Expected 'smart_gaps '"); - } - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/split.c b/sway/commands/split.c deleted file mode 100644 index e3045a4f..00000000 --- a/sway/commands/split.c +++ /dev/null @@ -1,98 +0,0 @@ -#include -#include -#include -#include "sway/border.h" -#include "sway/commands.h" -#include "sway/container.h" -#include "sway/focus.h" -#include "sway/layout.h" -#include "log.h" - -static struct cmd_results *_do_split(int argc, char **argv, int layout) { - char *name = layout == L_VERT ? "splitv" : - layout == L_HORIZ ? "splith" : "split"; - struct cmd_results *error = NULL; - if (config->reading) return cmd_results_new(CMD_FAILURE, name, "Can't be used in config file."); - if (!config->active) return cmd_results_new(CMD_FAILURE, name, "Can only be used when sway is running."); - if ((error = checkarg(argc, name, EXPECTED_EQUAL_TO, 0))) { - return error; - } - swayc_t *focused = current_container; - - // Case of floating window, don't split - if (focused->is_floating) { - return cmd_results_new(CMD_SUCCESS, NULL, NULL); - } - /* Case that focus is on an workspace with 0/1 children.change its layout */ - if (focused->type == C_WORKSPACE && focused->children->length <= 1) { - sway_log(L_DEBUG, "changing workspace layout"); - swayc_change_layout(focused, layout); - } else if (focused->type != C_WORKSPACE && focused->parent->children->length == 1) { - /* Case of no siblings. change parent layout */ - sway_log(L_DEBUG, "changing container layout"); - swayc_change_layout(focused->parent, layout); - } else { - /* regular case where new split container is build around focused container - * or in case of workspace, container inherits its children */ - sway_log(L_DEBUG, "Adding new container around current focused container"); - sway_log(L_INFO, "FOCUSED SIZE: %.f %.f", focused->width, focused->height); - swayc_t *parent = new_container(focused, layout); - set_focused_container(focused); - arrange_windows(parent, -1, -1); - } - - // update container every time - // if it is tabbed/stacked then the title must change - // if the indicator color is different then the border must change - update_container_border(focused); - swayc_t *output = swayc_parent_by_type(focused, C_OUTPUT); - // schedule render to make changes take effect right away, - // otherwise we would have to wait for the view to render, - // which is unpredictable. - wlc_output_schedule_render(output->handle); - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} - -struct cmd_results *cmd_split(int argc, char **argv) { - struct cmd_results *error = NULL; - if (config->reading) return cmd_results_new(CMD_FAILURE, "split", "Can't be used in config file."); - if (!config->active) return cmd_results_new(CMD_FAILURE, "split", "Can only be used when sway is running."); - if ((error = checkarg(argc, "split", EXPECTED_EQUAL_TO, 1))) { - return error; - } - if (strcasecmp(argv[0], "v") == 0 || strcasecmp(argv[0], "vertical") == 0) { - _do_split(argc - 1, argv + 1, L_VERT); - } else if (strcasecmp(argv[0], "h") == 0 || strcasecmp(argv[0], "horizontal") == 0) { - _do_split(argc - 1, argv + 1, L_HORIZ); - } else if (strcasecmp(argv[0], "t") == 0 || strcasecmp(argv[0], "toggle") == 0) { - swayc_t *focused = current_container; - if (focused->parent->layout == L_VERT) { - _do_split(argc - 1, argv + 1, L_HORIZ); - } else { - _do_split(argc - 1, argv + 1, L_VERT); - } - } else { - error = cmd_results_new(CMD_FAILURE, "split", - "Invalid split command (expected either horizontal or vertical)."); - return error; - } - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} - -struct cmd_results *cmd_splitv(int argc, char **argv) { - return _do_split(argc, argv, L_VERT); -} - -struct cmd_results *cmd_splith(int argc, char **argv) { - return _do_split(argc, argv, L_HORIZ); -} - -struct cmd_results *cmd_splitt(int argc, char **argv) { - swayc_t *focused = current_container; - if (focused->parent->layout == L_VERT) { - return _do_split(argc, argv, L_HORIZ); - } else { - return _do_split(argc, argv, L_VERT); - } -} diff --git a/sway/commands/sticky.c b/sway/commands/sticky.c deleted file mode 100644 index 4899e061..00000000 --- a/sway/commands/sticky.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/focus.h" - -struct cmd_results *cmd_sticky(int argc, char **argv) { - struct cmd_results *error = NULL; - if (config->reading) return cmd_results_new(CMD_FAILURE, "sticky", "Can't be used in config file."); - if (!config->active) return cmd_results_new(CMD_FAILURE, "sticky", "Can only be used when sway is running."); - if ((error = checkarg(argc, "sticky", EXPECTED_EQUAL_TO, 1))) { - return error; - } - char *action = argv[0]; - swayc_t *cont = get_focused_view(&root_container); - if (strcmp(action, "toggle") == 0) { - cont->sticky = !cont->sticky; - } else if (strcmp(action, "enable") == 0) { - cont->sticky = true; - } else if (strcmp(action, "disable") == 0) { - cont->sticky = false; - } else { - return cmd_results_new(CMD_FAILURE, "sticky", - "Expected 'sticky enable|disable|toggle'"); - } - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/unmark.c b/sway/commands/unmark.c deleted file mode 100644 index ac213261..00000000 --- a/sway/commands/unmark.c +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "list.h" -#include "stringop.h" - -struct cmd_results *cmd_unmark(int argc, char **argv) { - swayc_t *view = current_container; - - if (view->marks) { - if (argc) { - char *mark = join_args(argv, argc); - int index; - if ((index = list_seq_find(view->marks, (int (*)(const void *, const void *))strcmp, mark)) != -1) { - free(view->marks->items[index]); - list_del(view->marks, index); - - if (view->marks->length == 0) { - list_free(view->marks); - view->marks = NULL; - } - } - free(mark); - } else { - list_foreach(view->marks, free); - list_free(view->marks); - view->marks = NULL; - } - } - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c deleted file mode 100644 index a7839746..00000000 --- a/sway/commands/workspace.c +++ /dev/null @@ -1,92 +0,0 @@ -#define _XOPEN_SOURCE 500 -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/input_state.h" -#include "sway/workspace.h" -#include "list.h" -#include "log.h" -#include "stringop.h" - -struct cmd_results *cmd_workspace(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "workspace", EXPECTED_AT_LEAST, 1))) { - return error; - } - - int output_location = -1; - - for (int i = 0; i < argc; ++i) { - if (strcasecmp(argv[i], "output") == 0) { - output_location = i; - break; - } - } - if (output_location >= 0) { - if ((error = checkarg(argc, "workspace", EXPECTED_EQUAL_TO, output_location + 2))) { - return error; - } - struct workspace_output *wso = calloc(1, sizeof(struct workspace_output)); - if (!wso) { - return cmd_results_new(CMD_FAILURE, "workspace output", - "Unable to allocate workspace output"); - } - wso->workspace = join_args(argv, argc - 2); - wso->output = strdup(argv[output_location + 1]); - int i = -1; - if ((i = list_seq_find(config->workspace_outputs, workspace_output_cmp_workspace, wso)) != -1) { - struct workspace_output *old = config->workspace_outputs->items[i]; - free(old); // workspaces can only be assigned to a single output - list_del(config->workspace_outputs, i); - } - sway_log(L_DEBUG, "Assigning workspace %s to output %s", wso->workspace, wso->output); - list_add(config->workspace_outputs, wso); - } else { - if (config->reading || !config->active) { - return cmd_results_new(CMD_DEFER, "workspace", NULL); - } - swayc_t *ws = NULL; - if (strcasecmp(argv[0], "number") == 0) { - if (!(ws = workspace_by_number(argv[1]))) { - char *name = join_args(argv + 1, argc - 1); - ws = workspace_create(name); - free(name); - } - } else if (strcasecmp(argv[0], "next") == 0) { - ws = workspace_next(); - } else if (strcasecmp(argv[0], "prev") == 0) { - ws = workspace_prev(); - } else if (strcasecmp(argv[0], "next_on_output") == 0) { - ws = workspace_output_next(); - } else if (strcasecmp(argv[0], "prev_on_output") == 0) { - ws = workspace_output_prev(); - } else if (strcasecmp(argv[0], "back_and_forth") == 0) { - // if auto_back_and_forth is enabled, workspace_switch will swap - // the workspaces. If we created prev_workspace here, workspace_switch - // would put us back on original workspace. - if (config->auto_back_and_forth) { - ws = swayc_active_workspace(); - } else if (prev_workspace_name && !(ws = workspace_by_name(prev_workspace_name))) { - ws = workspace_create(prev_workspace_name); - } - } else { - char *name = join_args(argv, argc); - if (!(ws = workspace_by_name(name))) { - ws = workspace_create(name); - } - free(name); - } - swayc_t *old_output = swayc_active_output(); - workspace_switch(ws); - swayc_t *new_output = swayc_active_output(); - - if (config->mouse_warping && old_output != new_output) { - swayc_t *focused = get_focused_view(ws); - if (focused && focused->type == C_VIEW) { - center_pointer_on(focused); - } - } - } - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/workspace_auto_back_and_forth.c b/sway/commands/workspace_auto_back_and_forth.c deleted file mode 100644 index d58ae5c8..00000000 --- a/sway/commands/workspace_auto_back_and_forth.c +++ /dev/null @@ -1,18 +0,0 @@ -#include -#include -#include "sway/commands.h" - -struct cmd_results *cmd_ws_auto_back_and_forth(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "workspace_auto_back_and_forth", EXPECTED_EQUAL_TO, 1))) { - return error; - } - if (strcasecmp(argv[0], "yes") == 0) { - config->auto_back_and_forth = true; - } else if (strcasecmp(argv[0], "no") == 0) { - config->auto_back_and_forth = false; - } else { - return cmd_results_new(CMD_INVALID, "workspace_auto_back_and_forth", "Expected 'workspace_auto_back_and_forth '"); - } - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/workspace_layout.c b/sway/commands/workspace_layout.c deleted file mode 100644 index 9ac84be2..00000000 --- a/sway/commands/workspace_layout.c +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include -#include "sway/commands.h" - -struct cmd_results *cmd_workspace_layout(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "workspace_layout", EXPECTED_AT_LEAST, 1))) { - return error; - } - - if (strcasecmp(argv[0], "default") == 0) { - config->default_layout = L_NONE; - } else if (strcasecmp(argv[0], "stacking") == 0) { - config->default_layout = L_STACKED; - } else if (strcasecmp(argv[0], "tabbed") == 0) { - config->default_layout = L_TABBED; - } else if (strcasecmp(argv[0], "auto") == 0) { - if (argc == 1) { - config->default_layout = L_AUTO_FIRST; - } else { - if ((error = checkarg(argc, "workspace_layout auto", EXPECTED_EQUAL_TO, 2))) { - return error; - } - if (strcasecmp(argv[1], "left") == 0) { - config->default_layout = L_AUTO_LEFT; - } else if (strcasecmp(argv[1], "right") == 0) { - config->default_layout = L_AUTO_RIGHT; - } else if (strcasecmp(argv[1], "top") == 0) { - config->default_layout = L_AUTO_TOP; - } else if (strcasecmp(argv[1], "bottom") == 0) { - config->default_layout = L_AUTO_BOTTOM; - } else { - return cmd_results_new(CMD_INVALID, "workspace_layout auto", "Expected 'workspace_layout auto '"); - } - } - } else { - return cmd_results_new(CMD_INVALID, "workspace_layout", "Expected 'workspace_layout '"); - } - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/config.c b/sway/config.c deleted file mode 100644 index aa40c49a..00000000 --- a/sway/config.c +++ /dev/null @@ -1,1449 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#define _XOPEN_SOURCE 700 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "wayland-desktop-shell-server-protocol.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/layout.h" -#include "sway/input_state.h" -#include "sway/criteria.h" -#include "sway/input.h" -#include "sway/border.h" -#include "readline.h" -#include "stringop.h" -#include "list.h" -#include "log.h" - -struct sway_config *config = NULL; - -static void terminate_swaybar(pid_t pid); - -static void free_variable(struct sway_variable *var) { - if (!var) { - return; - } - free(var->name); - free(var->value); - free(var); -} - -static void free_binding(struct sway_binding *bind) { - if (!bind) { - return; - } - free_flat_list(bind->keys); - free(bind->command); - free(bind); -} - -static void free_mode(struct sway_mode *mode) { - if (!mode) { - return; - } - free(mode->name); - int i; - for (i = 0; mode->bindings && i < mode->bindings->length; ++i) { - free_binding(mode->bindings->items[i]); - } - list_free(mode->bindings); - free(mode); -} - -static void free_bar(struct bar_config *bar) { - if (!bar) { - return; - } - free(bar->mode); - free(bar->hidden_state); -#ifdef ENABLE_TRAY - free(bar->tray_output); - free(bar->icon_theme); -#endif - free(bar->status_command); - free(bar->font); - free(bar->separator_symbol); - int i; - for (i = 0; bar->bindings && i < bar->bindings->length; ++i) { - free_sway_mouse_binding(bar->bindings->items[i]); - } - list_free(bar->bindings); - - if (bar->outputs) { - free_flat_list(bar->outputs); - } - - if (bar->pid != 0) { - terminate_swaybar(bar->pid); - } - - free(bar->colors.background); - free(bar->colors.statusline); - free(bar->colors.separator); - free(bar->colors.focused_background); - free(bar->colors.focused_statusline); - free(bar->colors.focused_separator); - free(bar->colors.focused_workspace_border); - free(bar->colors.focused_workspace_bg); - free(bar->colors.focused_workspace_text); - free(bar->colors.active_workspace_border); - free(bar->colors.active_workspace_bg); - free(bar->colors.active_workspace_text); - free(bar->colors.inactive_workspace_border); - free(bar->colors.inactive_workspace_bg); - free(bar->colors.inactive_workspace_text); - free(bar->colors.urgent_workspace_border); - free(bar->colors.urgent_workspace_bg); - free(bar->colors.urgent_workspace_text); - free(bar->colors.binding_mode_border); - free(bar->colors.binding_mode_bg); - free(bar->colors.binding_mode_text); - - free(bar); -} - -void free_input_config(struct input_config *ic) { - if (!ic) { - return; - } - free(ic->identifier); - free(ic); -} - -void free_output_config(struct output_config *oc) { - if (!oc) { - return; - } - free(oc->name); - free(oc->background); - free(oc->background_option); - free(oc); -} - -static void free_workspace_output(struct workspace_output *wo) { - if (!wo) { - return; - } - free(wo->output); - free(wo->workspace); - free(wo); -} - -static void pid_workspace_cleanup() { - struct timespec ts; - struct pid_workspace *pw = NULL; - - clock_gettime(CLOCK_MONOTONIC, &ts); - - // work backwards through list and remove any entries - // older than PID_WORKSPACE_TIMEOUT - for (int i = config->pid_workspaces->length - 1; i > -1; i--) { - pw = config->pid_workspaces->items[i]; - - if (difftime(ts.tv_sec, *pw->time_added) >= PID_WORKSPACE_TIMEOUT) { - free_pid_workspace(config->pid_workspaces->items[i]); - list_del(config->pid_workspaces, i); - } - } -} - -// de-dupe pid_workspaces to ensure pid uniqueness -void pid_workspace_add(struct pid_workspace *pw) { - struct pid_workspace *list_pw = NULL; - struct timespec ts; - time_t *now = malloc(sizeof(time_t)); - if (!now) { - sway_log(L_ERROR, "Allocating time for pid_workspace failed"); - return; - } - - pid_workspace_cleanup(); - - // add current time to pw - clock_gettime(CLOCK_MONOTONIC, &ts); - *now = ts.tv_sec; - - pw->time_added = now; - - // work backwards through list and delete any entries that - // have the same pid as that in our new pid_workspace - for (int i = config->pid_workspaces->length - 1; i > -1; i--) { - list_pw = config->pid_workspaces->items[i]; - - if (pw->pid == list_pw->pid) { - free_pid_workspace(config->pid_workspaces->items[i]); - list_del(config->pid_workspaces, i); - } - } - - list_add(config->pid_workspaces, pw); -} - -void free_pid_workspace(struct pid_workspace *pw) { - if (!pw) { - return; - } - free(pw->pid); - free(pw->workspace); - free(pw->time_added); - free(pw); -} - -void free_command_policy(struct command_policy *policy) { - if (!policy) { - return; - } - free(policy->command); - free(policy); -} - -void free_feature_policy(struct feature_policy *policy) { - if (!policy) { - return; - } - free(policy->program); - free(policy); -} - -void free_config(struct sway_config *config) { - if (!config) { - return; - } - int i; - for (i = 0; config->symbols && i < config->symbols->length; ++i) { - free_variable(config->symbols->items[i]); - } - list_free(config->symbols); - - for (i = 0; config->modes && i < config->modes->length; ++i) { - free_mode(config->modes->items[i]); - } - list_free(config->modes); - - for (i = 0; config->bars && i < config->bars->length; ++i) { - free_bar(config->bars->items[i]); - } - list_free(config->bars); - - free_flat_list(config->cmd_queue); - - for (i = 0; config->workspace_outputs && i < config->workspace_outputs->length; ++i) { - free_workspace_output(config->workspace_outputs->items[i]); - } - list_free(config->workspace_outputs); - - for (i = 0; config->pid_workspaces && i < config->pid_workspaces->length; ++i) { - free_pid_workspace(config->pid_workspaces->items[i]); - } - list_free(config->pid_workspaces); - - for (i = 0; config->criteria && i < config->criteria->length; ++i) { - free_criteria(config->criteria->items[i]); - } - list_free(config->criteria); - - for (i = 0; config->no_focus && i < config->no_focus->length; ++i) { - free_criteria(config->no_focus->items[i]); - } - list_free(config->no_focus); - - for (i = 0; config->input_configs && i < config->input_configs->length; ++i) { - free_input_config(config->input_configs->items[i]); - } - list_free(config->input_configs); - - for (i = 0; config->output_configs && i < config->output_configs->length; ++i) { - free_output_config(config->output_configs->items[i]); - } - list_free(config->output_configs); - - for (i = 0; config->command_policies && i < config->command_policies->length; ++i) { - free_command_policy(config->command_policies->items[i]); - } - list_free(config->command_policies); - - for (i = 0; config->feature_policies && i < config->feature_policies->length; ++i) { - free_feature_policy(config->feature_policies->items[i]); - } - list_free(config->feature_policies); - - list_free(config->active_bar_modifiers); - free_flat_list(config->config_chain); - free(config->font); - free(config->floating_scroll_up_cmd); - free(config->floating_scroll_down_cmd); - free(config->floating_scroll_left_cmd); - free(config->floating_scroll_right_cmd); - free(config); -} - - -static bool file_exists(const char *path) { - return path && access(path, R_OK) != -1; -} - -static void config_defaults(struct sway_config *config) { - if (!(config->symbols = create_list())) goto cleanup; - if (!(config->modes = create_list())) goto cleanup; - if (!(config->bars = create_list())) goto cleanup; - if (!(config->workspace_outputs = create_list())) goto cleanup; - if (!(config->pid_workspaces = create_list())) goto cleanup; - if (!(config->criteria = create_list())) goto cleanup; - if (!(config->no_focus = create_list())) goto cleanup; - if (!(config->input_configs = create_list())) goto cleanup; - if (!(config->output_configs = create_list())) goto cleanup; - - if (!(config->cmd_queue = create_list())) goto cleanup; - - if (!(config->current_mode = malloc(sizeof(struct sway_mode)))) goto cleanup; - if (!(config->current_mode->name = malloc(sizeof("default")))) goto cleanup; - strcpy(config->current_mode->name, "default"); - if (!(config->current_mode->bindings = create_list())) goto cleanup; - list_add(config->modes, config->current_mode); - - config->floating_mod = 0; - config->dragging_key = M_LEFT_CLICK; - config->resizing_key = M_RIGHT_CLICK; - if (!(config->floating_scroll_up_cmd = strdup(""))) goto cleanup; - if (!(config->floating_scroll_down_cmd = strdup(""))) goto cleanup; - if (!(config->floating_scroll_left_cmd = strdup(""))) goto cleanup; - if (!(config->floating_scroll_right_cmd = strdup(""))) goto cleanup; - config->default_layout = L_NONE; - config->default_orientation = L_NONE; - if (!(config->font = strdup("monospace 10"))) goto cleanup; - config->font_height = get_font_text_height(config->font); - - // floating view - config->floating_maximum_width = 0; - config->floating_maximum_height = 0; - config->floating_minimum_width = 75; - config->floating_minimum_height = 50; - - // Flags - config->focus_follows_mouse = true; - config->mouse_warping = true; - config->reloading = false; - config->active = false; - config->failed = false; - config->auto_back_and_forth = false; - config->seamless_mouse = true; - config->reading = false; - config->show_marks = true; - - config->edge_gaps = true; - config->smart_gaps = false; - config->gaps_inner = 0; - config->gaps_outer = 0; - - if (!(config->active_bar_modifiers = create_list())) goto cleanup; - - if (!(config->config_chain = create_list())) goto cleanup; - config->current_config = NULL; - - // borders - config->border = B_NORMAL; - config->floating_border = B_NORMAL; - config->border_thickness = 2; - config->floating_border_thickness = 2; - config->hide_edge_borders = E_NONE; - - // border colors - config->border_colors.focused.border = 0x4C7899FF; - config->border_colors.focused.background = 0x285577FF; - config->border_colors.focused.text = 0xFFFFFFFF; - config->border_colors.focused.indicator = 0x2E9EF4FF; - config->border_colors.focused.child_border = 0x285577FF; - - config->border_colors.focused_inactive.border = 0x333333FF; - config->border_colors.focused_inactive.background = 0x5F676AFF; - config->border_colors.focused_inactive.text = 0xFFFFFFFF; - config->border_colors.focused_inactive.indicator = 0x484E50FF; - config->border_colors.focused_inactive.child_border = 0x5F676AFF; - - config->border_colors.unfocused.border = 0x333333FF; - config->border_colors.unfocused.background = 0x222222FF; - config->border_colors.unfocused.text = 0x888888FF; - config->border_colors.unfocused.indicator = 0x292D2EFF; - config->border_colors.unfocused.child_border = 0x222222FF; - - config->border_colors.urgent.border = 0x2F343AFF; - config->border_colors.urgent.background = 0x900000FF; - config->border_colors.urgent.text = 0xFFFFFFFF; - config->border_colors.urgent.indicator = 0x900000FF; - config->border_colors.urgent.child_border = 0x900000FF; - - config->border_colors.placeholder.border = 0x000000FF; - config->border_colors.placeholder.background = 0x0C0C0CFF; - config->border_colors.placeholder.text = 0xFFFFFFFF; - config->border_colors.placeholder.indicator = 0x000000FF; - config->border_colors.placeholder.child_border = 0x0C0C0CFF; - - config->border_colors.background = 0xFFFFFFFF; - - // Security - if (!(config->command_policies = create_list())) goto cleanup; - if (!(config->feature_policies = create_list())) goto cleanup; - if (!(config->ipc_policies = create_list())) goto cleanup; - - return; -cleanup: - sway_abort("Unable to allocate config structures"); -} - -static int compare_modifiers(const void *left, const void *right) { - uint32_t a = *(uint32_t *)left; - uint32_t b = *(uint32_t *)right; - - return a - b; -} - -void update_active_bar_modifiers() { - if (config->active_bar_modifiers->length > 0) { - list_free(config->active_bar_modifiers); - config->active_bar_modifiers = create_list(); - } - - struct bar_config *bar; - int i; - for (i = 0; i < config->bars->length; ++i) { - bar = config->bars->items[i]; - if (strcmp(bar->mode, "hide") == 0 && strcmp(bar->hidden_state, "hide") == 0) { - if (list_seq_find(config->active_bar_modifiers, compare_modifiers, &bar->modifier) < 0) { - list_add(config->active_bar_modifiers, &bar->modifier); - } - } - } -} - -static char *get_config_path(void) { - static const char *config_paths[] = { - "$HOME/.sway/config", - "$XDG_CONFIG_HOME/sway/config", - "$HOME/.i3/config", - "$XDG_CONFIG_HOME/i3/config", - SYSCONFDIR "/sway/config", - SYSCONFDIR "/i3/config", - }; - - if (!getenv("XDG_CONFIG_HOME")) { - char *home = getenv("HOME"); - char *config_home = malloc(strlen(home) + strlen("/.config") + 1); - if (!config_home) { - sway_log(L_ERROR, "Unable to allocate $HOME/.config"); - } else { - strcpy(config_home, home); - strcat(config_home, "/.config"); - setenv("XDG_CONFIG_HOME", config_home, 1); - sway_log(L_DEBUG, "Set XDG_CONFIG_HOME to %s", config_home); - free(config_home); - } - } - - wordexp_t p; - char *path; - - int i; - for (i = 0; i < (int)(sizeof(config_paths) / sizeof(char *)); ++i) { - if (wordexp(config_paths[i], &p, 0) == 0) { - path = strdup(p.we_wordv[0]); - wordfree(&p); - if (file_exists(path)) { - return path; - } - } - } - - return NULL; // Not reached -} - -const char *current_config_path; - -static bool load_config(const char *path, struct sway_config *config) { - sway_log(L_INFO, "Loading config from %s", path); - current_config_path = path; - - struct stat sb; - if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { - return false; - } - - if (path == NULL) { - sway_log(L_ERROR, "Unable to find a config file!"); - return false; - } - - FILE *f = fopen(path, "r"); - if (!f) { - sway_log(L_ERROR, "Unable to open %s for reading", path); - return false; - } - - bool config_load_success = read_config(f, config); - fclose(f); - - if (!config_load_success) { - sway_log(L_ERROR, "Error(s) loading config!"); - } - - current_config_path = NULL; - return true; -} - -static int qstrcmp(const void* a, const void* b) { - return strcmp(*((char**) a), *((char**) b)); -} - -bool load_main_config(const char *file, bool is_active) { - input_init(); - - char *path; - if (file != NULL) { - path = strdup(file); - } else { - path = get_config_path(); - } - - struct sway_config *old_config = config; - config = calloc(1, sizeof(struct sway_config)); - if (!config) { - sway_abort("Unable to allocate config"); - } - - config_defaults(config); - if (is_active) { - sway_log(L_DEBUG, "Performing configuration file reload"); - config->reloading = true; - config->active = true; - } - - config->current_config = path; - list_add(config->config_chain, path); - - config->reading = true; - - // Read security configs - bool success = true; - DIR *dir = opendir(SYSCONFDIR "/sway/security.d"); - if (!dir) { - sway_log(L_ERROR, "%s does not exist, sway will have no security configuration" - " and will probably be broken", SYSCONFDIR "/sway/security.d"); - } else { - list_t *secconfigs = create_list(); - char *base = SYSCONFDIR "/sway/security.d/"; - struct dirent *ent = readdir(dir); - struct stat s; - while (ent != NULL) { - char *_path = malloc(strlen(ent->d_name) + strlen(base) + 1); - strcpy(_path, base); - strcat(_path, ent->d_name); - lstat(_path, &s); - if (S_ISREG(s.st_mode) && ent->d_name[0] != '.') { - list_add(secconfigs, _path); - } - else { - free(_path); - } - ent = readdir(dir); - } - closedir(dir); - - list_qsort(secconfigs, qstrcmp); - for (int i = 0; i < secconfigs->length; ++i) { - char *_path = secconfigs->items[i]; - if (stat(_path, &s) || s.st_uid != 0 || s.st_gid != 0 || (((s.st_mode & 0777) != 0644) && (s.st_mode & 0777) != 0444)) { - sway_log(L_ERROR, "Refusing to load %s - it must be owned by root and mode 644 or 444", _path); - success = false; - } else { - success = success && load_config(_path, config); - } - } - - free_flat_list(secconfigs); - } - - success = success && load_config(path, config); - - if (is_active) { - config->reloading = false; - } - - if (old_config) { - free_config(old_config); - } - config->reading = false; - - if (success) { - update_active_bar_modifiers(); - } - - return success; -} - -static bool load_include_config(const char *path, const char *parent_dir, struct sway_config *config) { - // save parent config - const char *parent_config = config->current_config; - - char *full_path = strdup(path); - int len = strlen(path); - if (len >= 1 && path[0] != '/') { - len = len + strlen(parent_dir) + 2; - full_path = malloc(len * sizeof(char)); - if (!full_path) { - sway_log(L_ERROR, "Unable to allocate full path to included config"); - return false; - } - snprintf(full_path, len, "%s/%s", parent_dir, path); - } - - char *real_path = realpath(full_path, NULL); - free(full_path); - - if (real_path == NULL) { - sway_log(L_DEBUG, "%s not found.", path); - return false; - } - - // check if config has already been included - int j; - for (j = 0; j < config->config_chain->length; ++j) { - char *old_path = config->config_chain->items[j]; - if (strcmp(real_path, old_path) == 0) { - sway_log(L_DEBUG, "%s already included once, won't be included again.", real_path); - free(real_path); - return false; - } - } - - config->current_config = real_path; - list_add(config->config_chain, real_path); - int index = config->config_chain->length - 1; - - if (!load_config(real_path, config)) { - free(real_path); - config->current_config = parent_config; - list_del(config->config_chain, index); - return false; - } - - // restore current_config - config->current_config = parent_config; - return true; -} - -bool load_include_configs(const char *path, struct sway_config *config) { - char *wd = getcwd(NULL, 0); - char *parent_path = strdup(config->current_config); - const char *parent_dir = dirname(parent_path); - - if (chdir(parent_dir) < 0) { - free(parent_path); - free(wd); - return false; - } - - wordexp_t p; - - if (wordexp(path, &p, 0) < 0) { - free(parent_path); - free(wd); - return false; - } - - char **w = p.we_wordv; - size_t i; - for (i = 0; i < p.we_wordc; ++i) { - load_include_config(w[i], parent_dir, config); - } - free(parent_path); - wordfree(&p); - - // restore wd - if (chdir(wd) < 0) { - free(wd); - sway_log(L_ERROR, "failed to restore working directory"); - return false; - } - - free(wd); - return true; -} - -struct cmd_results *check_security_config() { - if (!current_config_path || strncmp(SYSCONFDIR "/sway/security.d/", current_config_path, - strlen(SYSCONFDIR "/sway/security.d/")) != 0) { - return cmd_results_new(CMD_INVALID, "permit", - "This command is only permitted to run from " SYSCONFDIR "/sway/security.d/*"); - } - return NULL; -} - -bool read_config(FILE *file, struct sway_config *config) { - bool success = true; - enum cmd_status block = CMD_BLOCK_END; - - int line_number = 0; - char *line; - while (!feof(file)) { - line = read_line(file); - if (!line) { - continue; - } - line_number++; - line = strip_whitespace(line); - if (line[0] == '#') { - free(line); - continue; - } - struct cmd_results *res; - if (block == CMD_BLOCK_COMMANDS) { - // Special case - res = config_commands_command(line); - } else { - res = config_command(line, block); - } - switch(res->status) { - case CMD_FAILURE: - case CMD_INVALID: - sway_log(L_ERROR, "Error on line %i '%s': %s (%s)", line_number, line, - res->error, config->current_config); - success = false; - break; - - case CMD_DEFER: - sway_log(L_DEBUG, "Defferring command `%s'", line); - list_add(config->cmd_queue, strdup(line)); - break; - - case CMD_BLOCK_MODE: - if (block == CMD_BLOCK_END) { - block = CMD_BLOCK_MODE; - } else { - sway_log(L_ERROR, "Invalid block '%s'", line); - } - break; - - case CMD_BLOCK_INPUT: - if (block == CMD_BLOCK_END) { - block = CMD_BLOCK_INPUT; - } else { - sway_log(L_ERROR, "Invalid block '%s'", line); - } - break; - - case CMD_BLOCK_BAR: - if (block == CMD_BLOCK_END) { - block = CMD_BLOCK_BAR; - } else { - sway_log(L_ERROR, "Invalid block '%s'", line); - } - break; - - case CMD_BLOCK_BAR_COLORS: - if (block == CMD_BLOCK_BAR) { - block = CMD_BLOCK_BAR_COLORS; - } else { - sway_log(L_ERROR, "Invalid block '%s'", line); - } - break; - - case CMD_BLOCK_COMMANDS: - if (block == CMD_BLOCK_END) { - block = CMD_BLOCK_COMMANDS; - } else { - sway_log(L_ERROR, "Invalid block '%s'", line); - } - break; - - case CMD_BLOCK_IPC: - if (block == CMD_BLOCK_END) { - block = CMD_BLOCK_IPC; - } else { - sway_log(L_ERROR, "Invalid block '%s'", line); - } - break; - - case CMD_BLOCK_IPC_EVENTS: - if (block == CMD_BLOCK_IPC) { - block = CMD_BLOCK_IPC_EVENTS; - } else { - sway_log(L_ERROR, "Invalid block '%s'", line); - } - break; - - case CMD_BLOCK_END: - switch(block) { - case CMD_BLOCK_MODE: - sway_log(L_DEBUG, "End of mode block"); - config->current_mode = config->modes->items[0]; - block = CMD_BLOCK_END; - break; - - case CMD_BLOCK_INPUT: - sway_log(L_DEBUG, "End of input block"); - current_input_config = NULL; - block = CMD_BLOCK_END; - break; - - case CMD_BLOCK_BAR: - sway_log(L_DEBUG, "End of bar block"); - config->current_bar = NULL; - block = CMD_BLOCK_END; - break; - - case CMD_BLOCK_BAR_COLORS: - sway_log(L_DEBUG, "End of bar colors block"); - block = CMD_BLOCK_BAR; - break; - - case CMD_BLOCK_COMMANDS: - sway_log(L_DEBUG, "End of commands block"); - block = CMD_BLOCK_END; - break; - - case CMD_BLOCK_IPC: - sway_log(L_DEBUG, "End of IPC block"); - block = CMD_BLOCK_END; - break; - - case CMD_BLOCK_IPC_EVENTS: - sway_log(L_DEBUG, "End of IPC events block"); - block = CMD_BLOCK_IPC; - break; - - case CMD_BLOCK_END: - sway_log(L_ERROR, "Unmatched }"); - break; - - default:; - } - default:; - } - free(line); - free_cmd_results(res); - } - - return success; -} - -int input_identifier_cmp(const void *item, const void *data) { - const struct input_config *ic = item; - const char *identifier = data; - return strcmp(ic->identifier, identifier); -} - -int output_name_cmp(const void *item, const void *data) { - const struct output_config *output = item; - const char *name = data; - - return strcmp(output->name, name); -} - -void merge_input_config(struct input_config *dst, struct input_config *src) { - if (src->identifier) { - if (dst->identifier) { - free(dst->identifier); - } - dst->identifier = strdup(src->identifier); - } - if (src->accel_profile != INT_MIN) { - dst->accel_profile = src->accel_profile; - } - if (src->click_method != INT_MIN) { - dst->click_method = src->click_method; - } - if (src->drag_lock != INT_MIN) { - dst->drag_lock = src->drag_lock; - } - if (src->dwt != INT_MIN) { - dst->dwt = src->dwt; - } - if (src->middle_emulation != INT_MIN) { - dst->middle_emulation = src->middle_emulation; - } - if (src->natural_scroll != INT_MIN) { - dst->natural_scroll = src->natural_scroll; - } - if (src->pointer_accel != FLT_MIN) { - dst->pointer_accel = src->pointer_accel; - } - if (src->scroll_method != INT_MIN) { - dst->scroll_method = src->scroll_method; - } - if (src->send_events != INT_MIN) { - dst->send_events = src->send_events; - } - if (src->tap != INT_MIN) { - dst->tap = src->tap; - } -} - -void merge_output_config(struct output_config *dst, struct output_config *src) { - if (src->name) { - if (dst->name) { - free(dst->name); - } - dst->name = strdup(src->name); - } - if (src->enabled != -1) { - dst->enabled = src->enabled; - } - if (src->width != -1) { - dst->width = src->width; - } - if (src->height != -1) { - dst->height = src->height; - } - if (src->x != -1) { - dst->x = src->x; - } - if (src->y != -1) { - dst->y = src->y; - } - if (src->scale != -1) { - dst->scale = src->scale; - } - if (src->background) { - if (dst->background) { - free(dst->background); - } - dst->background = strdup(src->background); - } - if (src->background_option) { - if (dst->background_option) { - free(dst->background_option); - } - dst->background_option = strdup(src->background_option); - } -} - -static void invoke_swaybar(struct bar_config *bar) { - return; // TODO WLR - sway_log(L_DEBUG, "Invoking swaybar for bar id '%s'", bar->id); - // Pipe to communicate errors - int filedes[2]; - if (pipe(filedes) == -1) { - sway_log(L_ERROR, "Pipe setup failed! Cannot fork into bar"); - return; - } - - bar->pid = fork(); - if (bar->pid == 0) { - close(filedes[0]); - if (!bar->swaybar_command) { - char *const cmd[] = { - "swaybar", - "-b", - bar->id, - NULL, - }; - - close(filedes[1]); - execvp(cmd[0], cmd); - _exit(EXIT_SUCCESS); - } else { - // run custom swaybar - int len = strlen(bar->swaybar_command) + strlen(bar->id) + 5; - char *command = malloc(len * sizeof(char)); - if (!command) { - const char msg[] = "Unable to allocate swaybar command string"; - int len = sizeof(msg); - if (write(filedes[1], &len, sizeof(int))) {}; - if (write(filedes[1], msg, len)) {}; - close(filedes[1]); - _exit(EXIT_FAILURE); - } - snprintf(command, len, "%s -b %s", bar->swaybar_command, bar->id); - - char *const cmd[] = { - "sh", - "-c", - command, - NULL, - }; - - close(filedes[1]); - execvp(cmd[0], cmd); - free(command); - _exit(EXIT_SUCCESS); - } - } - close(filedes[0]); - int len; - if(read(filedes[1], &len, sizeof(int)) == sizeof(int)) { - char *buf = malloc(len); - if(!buf) { - sway_log(L_ERROR, "Cannot allocate error string"); - return; - } - if(read(filedes[1], buf, len)) { - sway_log(L_ERROR, "%s", buf); - } - free(buf); - } - close(filedes[1]); -} - -static void terminate_swaybar(pid_t pid) { - int ret = kill(pid, SIGTERM); - if (ret != 0) { - sway_log(L_ERROR, "Unable to terminate swaybar [pid: %d]", pid); - } else { - int status; - waitpid(pid, &status, 0); - } -} - -void terminate_swaybg(pid_t pid) { - int ret = kill(pid, SIGTERM); - if (ret != 0) { - sway_log(L_ERROR, "Unable to terminate swaybg [pid: %d]", pid); - } else { - int status; - waitpid(pid, &status, 0); - } -} - -static bool active_output(const char *name) { - int i; - swayc_t *cont = NULL; - for (i = 0; i < root_container.children->length; ++i) { - cont = root_container.children->items[i]; - if (cont->type == C_OUTPUT && strcasecmp(name, cont->name) == 0) { - return true; - } - } - - return false; -} - -void load_swaybars() { - // Check for bars - list_t *bars = create_list(); - struct bar_config *bar = NULL; - int i; - for (i = 0; i < config->bars->length; ++i) { - bar = config->bars->items[i]; - bool apply = false; - if (bar->outputs) { - int j; - for (j = 0; j < bar->outputs->length; ++j) { - char *o = bar->outputs->items[j]; - if (!strcmp(o, "*") || active_output(o)) { - apply = true; - break; - } - } - } else { - apply = true; - } - if (apply) { - list_add(bars, bar); - } - } - - for (i = 0; i < bars->length; ++i) { - bar = bars->items[i]; - if (bar->pid != 0) { - terminate_swaybar(bar->pid); - } - invoke_swaybar(bar); - } - - list_free(bars); -} - -void apply_input_config(struct input_config *ic, struct libinput_device *dev) { - if (!ic) { - return; - } - - sway_log(L_DEBUG, "apply_input_config(%s)", ic->identifier); - - if (ic->accel_profile != INT_MIN) { - sway_log(L_DEBUG, "apply_input_config(%s) accel_set_profile(%d)", ic->identifier, ic->accel_profile); - libinput_device_config_accel_set_profile(dev, ic->accel_profile); - } - if (ic->click_method != INT_MIN) { - sway_log(L_DEBUG, "apply_input_config(%s) click_set_method(%d)", ic->identifier, ic->click_method); - libinput_device_config_click_set_method(dev, ic->click_method); - } - if (ic->drag_lock != INT_MIN) { - sway_log(L_DEBUG, "apply_input_config(%s) tap_set_drag_lock_enabled(%d)", ic->identifier, ic->click_method); - libinput_device_config_tap_set_drag_lock_enabled(dev, ic->drag_lock); - } - if (ic->dwt != INT_MIN) { - sway_log(L_DEBUG, "apply_input_config(%s) dwt_set_enabled(%d)", ic->identifier, ic->dwt); - libinput_device_config_dwt_set_enabled(dev, ic->dwt); - } - if (ic->left_handed != INT_MIN) { - sway_log(L_DEBUG, "apply_input_config(%s) left_handed_set_enabled(%d)", ic->identifier, ic->left_handed); - libinput_device_config_left_handed_set(dev, ic->left_handed); - } - if (ic->middle_emulation != INT_MIN) { - sway_log(L_DEBUG, "apply_input_config(%s) middle_emulation_set_enabled(%d)", ic->identifier, ic->middle_emulation); - libinput_device_config_middle_emulation_set_enabled(dev, ic->middle_emulation); - } - if (ic->natural_scroll != INT_MIN) { - sway_log(L_DEBUG, "apply_input_config(%s) natural_scroll_set_enabled(%d)", ic->identifier, ic->natural_scroll); - libinput_device_config_scroll_set_natural_scroll_enabled(dev, ic->natural_scroll); - } - if (ic->pointer_accel != FLT_MIN) { - sway_log(L_DEBUG, "apply_input_config(%s) accel_set_speed(%f)", ic->identifier, ic->pointer_accel); - libinput_device_config_accel_set_speed(dev, ic->pointer_accel); - } - if (ic->scroll_method != INT_MIN) { - sway_log(L_DEBUG, "apply_input_config(%s) scroll_set_method(%d)", ic->identifier, ic->scroll_method); - libinput_device_config_scroll_set_method(dev, ic->scroll_method); - } - if (ic->send_events != INT_MIN) { - sway_log(L_DEBUG, "apply_input_config(%s) send_events_set_mode(%d)", ic->identifier, ic->send_events); - libinput_device_config_send_events_set_mode(dev, ic->send_events); - } - if (ic->tap != INT_MIN) { - sway_log(L_DEBUG, "apply_input_config(%s) tap_set_enabled(%d)", ic->identifier, ic->tap); - libinput_device_config_tap_set_enabled(dev, ic->tap); - } -} - -void apply_output_config(struct output_config *oc, swayc_t *output) { - if (oc && oc->enabled == 0) { - destroy_output(output); - return; - } - - if (oc && oc->width > 0 && oc->height > 0) { - output->width = oc->width; - output->height = oc->height; - - sway_log(L_DEBUG, "Set %s size to %ix%i (%d)", oc->name, oc->width, oc->height, oc->scale); - // TODO WLR: modes - //struct wlc_size new_size = { .w = oc->width, .h = oc->height }; - //wlc_output_set_resolution(output->handle, &new_size, (uint32_t)oc->scale); - } else if (oc) { - //const struct wlc_size *new_size = wlc_output_get_resolution(output->handle); - //wlc_output_set_resolution(output->handle, new_size, (uint32_t)oc->scale); - } - - // TODO WLR: wlr_output_layout - // Find position for it - if (oc && oc->x != -1 && oc->y != -1) { - sway_log(L_DEBUG, "Set %s position to %d, %d", oc->name, oc->x, oc->y); - output->x = oc->x; - output->y = oc->y; - } else { - int x = 0; - for (int i = 0; i < root_container.children->length; ++i) { - swayc_t *c = root_container.children->items[i]; - if (c->type == C_OUTPUT) { - if (c->width + c->x > x) { - x = c->width + c->x; - } - } - } - output->x = x; - } - - if (!oc || !oc->background) { - // Look for a * config for background - int i = list_seq_find(config->output_configs, output_name_cmp, "*"); - if (i >= 0) { - oc = config->output_configs->items[i]; - } else { - oc = NULL; - } - } - - int output_i; - for (output_i = 0; output_i < root_container.children->length; ++output_i) { - if (root_container.children->items[output_i] == output) { - break; - } - } - - /* TODO WLR - if (oc && oc->background) { - if (output->bg_pid != 0) { - terminate_swaybg(output->bg_pid); - } - - sway_log(L_DEBUG, "Setting background for output %d to %s", output_i, oc->background); - - size_t bufsize = 12; - char output_id[bufsize]; - snprintf(output_id, bufsize, "%d", output_i); - output_id[bufsize-1] = 0; - - char *const cmd[] = { - "swaybg", - output_id, - oc->background, - oc->background_option, - NULL, - }; - - output->bg_pid = fork(); - if (output->bg_pid == 0) { - execvp(cmd[0], cmd); - } - } - */ -} - -char *do_var_replacement(char *str) { - int i; - char *find = str; - while ((find = strchr(find, '$'))) { - // Skip if escaped. - if (find > str && find[-1] == '\\') { - if (find == str + 1 || !(find > str + 1 && find[-2] == '\\')) { - ++find; - continue; - } - } - // Find matching variable - for (i = 0; i < config->symbols->length; ++i) { - struct sway_variable *var = config->symbols->items[i]; - int vnlen = strlen(var->name); - if (strncmp(find, var->name, vnlen) == 0) { - int vvlen = strlen(var->value); - char *newstr = malloc(strlen(str) - vnlen + vvlen + 1); - if (!newstr) { - sway_log(L_ERROR, - "Unable to allocate replacement during variable expansion"); - break; - } - char *newptr = newstr; - int offset = find - str; - strncpy(newptr, str, offset); - newptr += offset; - strncpy(newptr, var->value, vvlen); - newptr += vvlen; - strcpy(newptr, find + vnlen); - free(str); - str = newstr; - find = str + offset + vvlen; - break; - } - } - if (i == config->symbols->length) { - ++find; - } - } - return str; -} - -// the naming is intentional (albeit long): a workspace_output_cmp function -// would compare two structs in full, while this method only compares the -// workspace. -int workspace_output_cmp_workspace(const void *a, const void *b) { - const struct workspace_output *wsa = a, *wsb = b; - return lenient_strcmp(wsa->workspace, wsb->workspace); -} - -int sway_binding_cmp_keys(const void *a, const void *b) { - const struct sway_binding *binda = a, *bindb = b; - - // Count keys pressed for this binding. important so we check long before - // short ones. for example mod+a+b before mod+a - unsigned int moda = 0, modb = 0, i; - - // Count how any modifiers are pressed - for (i = 0; i < 8 * sizeof(binda->modifiers); ++i) { - moda += (binda->modifiers & 1 << i) != 0; - modb += (bindb->modifiers & 1 << i) != 0; - } - if (bindb->keys->length + modb != binda->keys->length + moda) { - return (bindb->keys->length + modb) - (binda->keys->length + moda); - } - - // Otherwise compare keys - if (binda->modifiers > bindb->modifiers) { - return 1; - } else if (binda->modifiers < bindb->modifiers) { - return -1; - } - struct wlc_modifiers no_mods = { 0, 0 }; - for (int i = 0; i < binda->keys->length; i++) { - xkb_keysym_t ka = *(xkb_keysym_t *)binda->keys->items[i], - kb = *(xkb_keysym_t *)bindb->keys->items[i]; - if (binda->bindcode) { - uint32_t *keycode = binda->keys->items[i]; - ka = wlc_keyboard_get_keysym_for_key(*keycode, &no_mods); - } - - if (bindb->bindcode) { - uint32_t *keycode = bindb->keys->items[i]; - kb = wlc_keyboard_get_keysym_for_key(*keycode, &no_mods); - } - - if (ka > kb) { - return 1; - } else if (ka < kb) { - return -1; - } - } - - return 0; -} - -int sway_binding_cmp(const void *a, const void *b) { - int cmp = 0; - if ((cmp = sway_binding_cmp_keys(a, b)) != 0) { - return cmp; - } - const struct sway_binding *binda = a, *bindb = b; - return lenient_strcmp(binda->command, bindb->command); -} - -int sway_binding_cmp_qsort(const void *a, const void *b) { - return sway_binding_cmp(*(void **)a, *(void **)b); -} - -void free_sway_binding(struct sway_binding *binding) { - if (binding->keys) { - for (int i = 0; i < binding->keys->length; i++) { - free(binding->keys->items[i]); - } - list_free(binding->keys); - } - if (binding->command) { - free(binding->command); - } - free(binding); -} - -int sway_mouse_binding_cmp_buttons(const void *a, const void *b) { - const struct sway_mouse_binding *binda = a, *bindb = b; - if (binda->button > bindb->button) { - return 1; - } - if (binda->button < bindb->button) { - return -1; - } - return 0; -} - -int sway_mouse_binding_cmp(const void *a, const void *b) { - int cmp = 0; - if ((cmp = sway_binding_cmp_keys(a, b)) != 0) { - return cmp; - } - const struct sway_mouse_binding *binda = a, *bindb = b; - return lenient_strcmp(binda->command, bindb->command); -} - -int sway_mouse_binding_cmp_qsort(const void *a, const void *b) { - return sway_mouse_binding_cmp(*(void **)a, *(void **)b); -} - -void free_sway_mouse_binding(struct sway_mouse_binding *binding) { - if (binding->command) { - free(binding->command); - } - free(binding); -} - -struct sway_binding *sway_binding_dup(struct sway_binding *sb) { - struct sway_binding *new_sb = malloc(sizeof(struct sway_binding)); - if (!new_sb) { - return NULL; - } - - new_sb->order = sb->order; - new_sb->modifiers = sb->modifiers; - new_sb->command = strdup(sb->command); - - new_sb->keys = create_list(); - int i; - for (i = 0; i < sb->keys->length; ++i) { - xkb_keysym_t *key = malloc(sizeof(xkb_keysym_t)); - if (!key) { - free_sway_binding(new_sb); - return NULL; - } - *key = *(xkb_keysym_t *)sb->keys->items[i]; - list_add(new_sb->keys, key); - } - - return new_sb; -} - -struct bar_config *default_bar_config(void) { - struct bar_config *bar = NULL; - bar = malloc(sizeof(struct bar_config)); - if (!bar) { - return NULL; - } - if (!(bar->mode = strdup("dock"))) goto cleanup; - if (!(bar->hidden_state = strdup("hide"))) goto cleanup; - bar->modifier = WLC_BIT_MOD_LOGO; - bar->outputs = NULL; - bar->position = DESKTOP_SHELL_PANEL_POSITION_BOTTOM; - if (!(bar->bindings = create_list())) goto cleanup; - if (!(bar->status_command = strdup("while :; do date +'%Y-%m-%d %l:%M:%S %p'; sleep 1; done"))) goto cleanup; - bar->pango_markup = false; - bar->swaybar_command = NULL; - bar->font = NULL; - bar->height = -1; - bar->workspace_buttons = true; - bar->wrap_scroll = false; - bar->separator_symbol = NULL; - bar->strip_workspace_numbers = false; - bar->binding_mode_indicator = true; -#ifdef ENABLE_TRAY - bar->tray_output = NULL; - bar->icon_theme = NULL; - bar->tray_padding = 2; - bar->activate_button = 0x110; /* BTN_LEFT */ - bar->context_button = 0x111; /* BTN_RIGHT */ - bar->secondary_button = 0x112; /* BTN_MIDDLE */ -#endif - bar->verbose = false; - bar->pid = 0; - // set default colors - if (!(bar->colors.background = strndup("#000000ff", 9))) goto cleanup; - if (!(bar->colors.statusline = strndup("#ffffffff", 9))) goto cleanup; - if (!(bar->colors.separator = strndup("#666666ff", 9))) goto cleanup; - if (!(bar->colors.focused_workspace_border = strndup("#4c7899ff", 9))) goto cleanup; - if (!(bar->colors.focused_workspace_bg = strndup("#285577ff", 9))) goto cleanup; - if (!(bar->colors.focused_workspace_text = strndup("#ffffffff", 9))) goto cleanup; - if (!(bar->colors.active_workspace_border = strndup("#333333ff", 9))) goto cleanup; - if (!(bar->colors.active_workspace_bg = strndup("#5f676aff", 9))) goto cleanup; - if (!(bar->colors.active_workspace_text = strndup("#ffffffff", 9))) goto cleanup; - if (!(bar->colors.inactive_workspace_border = strndup("#333333ff", 9))) goto cleanup; - if (!(bar->colors.inactive_workspace_bg = strndup("#222222ff", 9))) goto cleanup; - if (!(bar->colors.inactive_workspace_text = strndup("#888888ff", 9))) goto cleanup; - if (!(bar->colors.urgent_workspace_border = strndup("#2f343aff", 9))) goto cleanup; - if (!(bar->colors.urgent_workspace_bg = strndup("#900000ff", 9))) goto cleanup; - if (!(bar->colors.urgent_workspace_text = strndup("#ffffffff", 9))) goto cleanup; - // if the following colors stay undefined, they fall back to background, - // statusline, separator and urgent_workspace_*. - bar->colors.focused_background = NULL; - bar->colors.focused_statusline = NULL; - bar->colors.focused_separator = NULL; - bar->colors.binding_mode_border = NULL; - bar->colors.binding_mode_bg = NULL; - bar->colors.binding_mode_text = NULL; - - list_add(config->bars, bar); - - return bar; - -cleanup: - free_bar(bar); - return NULL; -} diff --git a/sway/debug_log.c b/sway/debug_log.c deleted file mode 100644 index d1eafae8..00000000 --- a/sway/debug_log.c +++ /dev/null @@ -1,103 +0,0 @@ -#include "log.h" -#include "sway.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sway/workspace.h" - -/* XXX:DEBUG:XXX */ -static void container_log(const swayc_t *c, int depth) { - fprintf(stderr, "focus:%c", - c == get_focused_view(&root_container) ? 'K': - c == get_focused_container(&root_container) ? 'F' : // Focused - c == swayc_active_workspace() ? 'W' : // active workspace - c == &root_container ? 'R' : // root - 'X');// not any others - for (int i = 6; i > depth; i--) { fprintf(stderr, " "); } - fprintf(stderr,"|(%p)",c); - fprintf(stderr,"(p:%-8p)",c->parent); - fprintf(stderr,"(f:%-8p)",c->focused); - fprintf(stderr,"(h:%2" PRIuPTR ")",c->handle); - fprintf(stderr,"Type:%-4s|", - c->type == C_ROOT ? "root" : - c->type == C_OUTPUT ? "op" : - c->type == C_WORKSPACE ? "ws" : - c->type == C_CONTAINER ? "cont" : - c->type == C_VIEW ? "view" : "?"); - fprintf(stderr,"layout:%-5s|", - c->layout == L_NONE ? "-" : - c->layout == L_HORIZ ? "Horiz": - c->layout == L_VERT ? "Vert": - c->layout == L_STACKED ? "Stack": - c->layout == L_TABBED ? "Tab": - c->layout == L_FLOATING ? "Float": - c->layout == L_AUTO_LEFT ? "A_lft": - c->layout == L_AUTO_RIGHT ? "A_rgt": - c->layout == L_AUTO_TOP ? "A_top": - c->layout == L_AUTO_BOTTOM ? "A_bot": - "Unknown"); - fprintf(stderr, "w:%4.f|h:%4.f|", c->width, c->height); - fprintf(stderr, "x:%4.f|y:%4.f|", c->x, c->y); - fprintf(stderr, "g:%3d|",c->gaps); - fprintf(stderr, "vis:%c|", c->visible?'t':'f'); - fprintf(stderr, "children:%2d|",c->children?c->children->length:0); - fprintf(stderr, "name:%.16s\n", c->name); -} -void layout_log(const swayc_t *c, int depth) { - if (L_DEBUG > get_log_level()) return; - int i, d; - int e = c->children ? c->children->length : 0; - container_log(c, depth); - if (e) { - for (i = 0; i < e; ++i) { - fputc('|',stderr); - for (d = 0; d < depth; ++d) fputc('-', stderr); - layout_log(c->children->items[i], depth + 1); - } - } - if (c->type == C_WORKSPACE) { - e = c->floating?c->floating->length:0; - if (e) { - for (i = 0; i < e; ++i) { - fputc('|',stderr); - for (d = 0; d < depth; ++d) fputc('=', stderr); - layout_log(c->floating->items[i], depth + 1); - } - } - } -} - -const char *swayc_type_string(enum swayc_types type) { - return type == C_ROOT ? "ROOT" : - type == C_OUTPUT ? "OUTPUT" : - type == C_WORKSPACE ? "WORKSPACE" : - type == C_CONTAINER ? "CONTAINER" : - type == C_VIEW ? "VIEW" : - "UNKNOWN"; -} - -// Like sway_log, but also appends some info about given container to log output. -void swayc_log(log_importance_t verbosity, swayc_t *cont, const char* format, ...) { - sway_assert(cont, "swayc_log: no container ..."); - va_list args; - va_start(args, format); - char *txt = malloc(128); - vsprintf(txt, format, args); - va_end(args); - - char *debug_txt = malloc(32); - snprintf(debug_txt, 32, "%s '%s'", swayc_type_string(cont->type), cont->name); - - sway_log(verbosity, "%s (%s)", txt, debug_txt); - free(txt); - free(debug_txt); -} - -/* XXX:DEBUG:XXX */ diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 6d0bebc5..6ddcac3b 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -4,11 +4,9 @@ #include #include #include -#include "sway/server.h" -#include "sway/container.h" -#include "sway/workspace.h" -#include "sway/output.h" #include "log.h" +#include "sway/output.h" +#include "sway/server.h" static void output_frame_notify(struct wl_listener *listener, void *data) { struct sway_output *soutput = wl_container_of( @@ -37,19 +35,10 @@ void output_add_notify(struct wl_listener *listener, void *data) { output->wlr_output = wlr_output; output->server = server; - swayc_t *node = new_output(output); - if (!sway_assert(node, "Failed to allocate output")) { - return; - } - - // Switch to workspace if we need to - if (swayc_active_workspace() == NULL) { - swayc_t *ws = node->children->items[0]; - workspace_switch(ws); - } - output->frame.notify = output_frame_notify; wl_signal_add(&wlr_output->events.frame, &output->frame); + + // TODO: Add to tree } void output_remove_notify(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index e29b46d7..04f3f42c 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -1,49 +1,10 @@ #include #include #include -#include "sway/commands.h" -#include "sway/container.h" -#include "sway/focus.h" -#include "sway/ipc-server.h" #include "sway/server.h" #include "sway/view.h" #include "log.h" -// TODO: move elsewhere -static void temp_ws_cleanup() { - swayc_t *op, *ws; - int i = 0, j; - if (!root_container.children) - return; - while (i < root_container.children->length) { - op = root_container.children->items[i++]; - if (!op->children) - continue; - j = 0; - while (j < op->children->length) { - ws = op->children->items[j++]; - if (ws->children->length == 0 && ws->floating->length == 0 && ws != op->focused) { - if (destroy_workspace(ws)) { - j--; - } - } - } - } -} - -// TODO: move elsewhere -static swayc_t *move_focus_to_tiling(swayc_t *focused) { - if (focused->is_floating) { - if (focused->parent->children->length == 0) { - return focused->parent; - } - // TODO find a better way of doing this - // Or to focused container - return get_focused_container(focused->parent->children->items[0]); - } - return focused; -} - static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) { if (!sway_assert(view->type == SWAY_XDG_SHELL_V6_VIEW, "xdg get_prop for non-xdg view!")) { @@ -88,30 +49,10 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { sway_surface->view = sway_view; // TODO: - // - Consolodate common logic between shells + // - Add to tree // - Wire up listeners // - Handle popups // - Look up pid and open on appropriate workspace // - Set new view to maximized so it behaves nicely // - Criteria - - suspend_workspace_cleanup = true; - //swayc_t *current_ws = swayc_active_workspace(); - swayc_t *prev_focus = get_focused_container(&root_container); - swayc_t *focused = move_focus_to_tiling(prev_focus); - - // TODO: fix new_view - swayc_t *view = new_view(focused, sway_view); - ipc_event_window(view, "new"); - set_focused_container(view); - - swayc_t *output = swayc_parent_by_type(view, C_OUTPUT); - arrange_windows(output, -1, -1); - - swayc_t *workspace = swayc_parent_by_type(focused, C_WORKSPACE); - if (workspace && workspace->fullscreen) { - set_focused_container(workspace->fullscreen); - } - suspend_workspace_cleanup = false; - temp_ws_cleanup(); } diff --git a/sway/handlers.c b/sway/handlers.c deleted file mode 100644 index 33e75d6b..00000000 --- a/sway/handlers.c +++ /dev/null @@ -1,1143 +0,0 @@ -#define _XOPEN_SOURCE 500 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sway/handlers.h" -#include "sway/border.h" -#include "sway/layout.h" -#include "sway/config.h" -#include "sway/commands.h" -#include "sway/workspace.h" -#include "sway/container.h" -#include "sway/output.h" -#include "sway/focus.h" -#include "sway/input_state.h" -#include "sway/extensions.h" -#include "sway/criteria.h" -#include "sway/ipc-server.h" -#include "sway/input.h" -#include "sway/security.h" -#include "list.h" -#include "stringop.h" -#include "log.h" - -// Event should be sent to client -#define EVENT_PASSTHROUGH false - -// Event handled by sway and should not be sent to client -#define EVENT_HANDLED true - -static struct panel_config *if_panel_find_config(struct wl_client *client) { - int i; - for (i = 0; i < desktop_shell.panels->length; i++) { - struct panel_config *config = desktop_shell.panels->items[i]; - if (config->client == client) { - return config; - } - } - return NULL; -} - -static struct background_config *if_background_find_config(struct wl_client *client) { - int i; - for (i = 0; i < desktop_shell.backgrounds->length; i++) { - struct background_config *config = desktop_shell.backgrounds->items[i]; - if (config->client == client) { - return config; - } - } - return NULL; -} - -static struct wlc_geometry compute_panel_geometry(struct panel_config *config) { - struct wlc_size resolution; - output_get_scaled_size(config->output, &resolution); - const struct wlc_geometry *old = wlc_view_get_geometry(config->handle); - struct wlc_geometry new; - - switch (config->panel_position) { - case DESKTOP_SHELL_PANEL_POSITION_TOP: - new.origin.x = 0; - new.origin.y = 0; - new.size.w = resolution.w; - new.size.h = old->size.h; - break; - case DESKTOP_SHELL_PANEL_POSITION_BOTTOM: - new.origin.x = 0; - new.origin.y = resolution.h - old->size.h; - new.size.w = resolution.w; - new.size.h = old->size.h; - break; - case DESKTOP_SHELL_PANEL_POSITION_LEFT: - new.origin.x = 0; - new.origin.y = 0; - new.size.w = old->size.w; - new.size.h = resolution.h; - break; - case DESKTOP_SHELL_PANEL_POSITION_RIGHT: - new.origin.x = resolution.w - old->size.w; - new.origin.y = 0; - new.size.w = old->size.w; - new.size.h = resolution.h; - break; - } - - return new; -} - -static void update_panel_geometry(struct panel_config *config) { - struct wlc_geometry geometry = compute_panel_geometry(config); - wlc_view_set_geometry(config->handle, 0, &geometry); -} - -static void update_panel_geometries(wlc_handle output) { - for (int i = 0; i < desktop_shell.panels->length; i++) { - struct panel_config *config = desktop_shell.panels->items[i]; - if (config->output == output) { - update_panel_geometry(config); - } - } -} - -static void update_background_geometry(struct background_config *config) { - struct wlc_geometry geometry = wlc_geometry_zero; - output_get_scaled_size(config->output, &geometry.size); - wlc_view_set_geometry(config->handle, 0, &geometry); -} - -static void update_background_geometries(wlc_handle output) { - for (int i = 0; i < desktop_shell.backgrounds->length; i++) { - struct background_config *config = desktop_shell.backgrounds->items[i]; - if (config->output == output) { - update_background_geometry(config); - } - } -} - -/* Handles */ - -static bool handle_input_created(struct libinput_device *device) { - const char *identifier = libinput_dev_unique_id(device); - if (!identifier) { - sway_log(L_ERROR, "Unable to allocate unique name for input device %p", - device); - return true; - } - sway_log(L_INFO, "Found input device (%s)", identifier); - - list_add(input_devices, device); - - struct input_config *ic = NULL; - int i; - for (i = 0; i < config->input_configs->length; ++i) { - struct input_config *cur = config->input_configs->items[i]; - if (strcasecmp(identifier, cur->identifier) == 0) { - sway_log(L_DEBUG, "Matched input config for %s", - identifier); - ic = cur; - break; - } - if (strcasecmp("*", cur->identifier) == 0) { - sway_log(L_DEBUG, "Matched wildcard input config for %s", - identifier); - ic = cur; - break; - } - } - - apply_input_config(ic, device); - return true; -} - -static void handle_input_destroyed(struct libinput_device *device) { - int i; - list_t *list = input_devices; - for (i = 0; i < list->length; ++i) { - if(((struct libinput_device *)list->items[i]) == device) { - list_del(list, i); - break; - } - } -} - -static bool handle_output_created(wlc_handle output) { - swayc_t *op = new_output(output); - - // Visibility mask to be able to make view invisible - wlc_output_set_mask(output, VISIBLE); - - if (!op) { - return false; - } - - // Switch to workspace if we need to - if (swayc_active_workspace() == NULL) { - swayc_t *ws = op->children->items[0]; - workspace_switch(ws); - } - - // Fixes issues with backgrounds and wlc - wlc_handle prev = wlc_get_focused_output(); - wlc_output_focus(output); - wlc_output_focus(prev); - return true; -} - -static void handle_output_destroyed(wlc_handle output) { - int i; - list_t *list = root_container.children; - for (i = 0; i < list->length; ++i) { - if (((swayc_t *)list->items[i])->handle == output) { - break; - } - } - if (i < list->length) { - destroy_output(list->items[i]); - } else { - return; - } - if (list->length > 0) { - // switch to other outputs active workspace - workspace_switch(((swayc_t *)root_container.children->items[0])->focused); - } -} - -static void handle_output_post_render(wlc_handle output) { - ipc_get_pixels(output); -} - -static void handle_view_pre_render(wlc_handle view) { - render_view_borders(view); -} - -static void handle_output_resolution_change(wlc_handle output, const struct wlc_size *from, const struct wlc_size *to) { - sway_log(L_DEBUG, "Output %u resolution changed to %d x %d", (unsigned int)output, to->w, to->h); - - swayc_t *c = swayc_by_handle(output); - if (!c) { - return; - } - c->width = to->w; - c->height = to->h; - - update_panel_geometries(output); - update_background_geometries(output); - - arrange_windows(&root_container, -1, -1); -} - -static void handle_output_focused(wlc_handle output, bool focus) { - swayc_t *c = swayc_by_handle(output); - // if for some reason this output doesn't exist, create it. - if (!c) { - handle_output_created(output); - } - if (focus) { - set_focused_container(get_focused_container(c)); - } -} - -static void ws_cleanup() { - swayc_t *op, *ws; - int i = 0, j; - if (!root_container.children) - return; - while (i < root_container.children->length) { - op = root_container.children->items[i++]; - if (!op->children) - continue; - j = 0; - while (j < op->children->length) { - ws = op->children->items[j++]; - if (ws->children->length == 0 && ws->floating->length == 0 && ws != op->focused) { - if (destroy_workspace(ws)) { - j--; - } - } - } - } -} - -static void positioner_place_window(wlc_handle handle) { - const struct wlc_geometry *anchor = wlc_view_positioner_get_anchor_rect(handle); - const struct wlc_size *sr = wlc_view_positioner_get_size(handle); - // a positioner is required to have a non-null anchor and a non-negative size - if (!anchor || !sr || - sr->w <= 0 || sr->h <= 0 || - anchor->size.w <= 0 || anchor->size.h <= 0) { - return; - } - const struct wlc_point offset = *wlc_view_positioner_get_offset(handle); - enum wlc_positioner_anchor_bit anchors = wlc_view_positioner_get_anchor(handle); - enum wlc_positioner_gravity_bit gravity = wlc_view_positioner_get_gravity(handle); - struct wlc_geometry geo = { - .origin = offset, - .size = *sr - }; - - if (anchors & WLC_BIT_ANCHOR_TOP) { - geo.origin.y += anchor->origin.y; - } else if (anchors & WLC_BIT_ANCHOR_BOTTOM) { - geo.origin.y += anchor->origin.y + anchor->size.h; - } else { - geo.origin.y += anchor->origin.y + anchor->size.h / 2; - } - if (anchors & WLC_BIT_ANCHOR_LEFT) { - geo.origin.x += anchor->origin.x; - } else if (anchors & WLC_BIT_ANCHOR_RIGHT) { - geo.origin.x += anchor->origin.x + anchor->size.w; - } else { - geo.origin.x += anchor->origin.x + anchor->size.w / 2; - } - - if (gravity & WLC_BIT_GRAVITY_TOP) { - geo.origin.y -= geo.size.h; - } else if (gravity & WLC_BIT_GRAVITY_BOTTOM) { - /* default */ - } else { - geo.origin.y -= geo.size.h / 2; - } - if (gravity & WLC_BIT_GRAVITY_LEFT) { - geo.origin.x -= geo.size.w; - } else if (gravity & WLC_BIT_GRAVITY_RIGHT) { - /* default */ - } else { - geo.origin.x -= geo.size.w / 2; - } - - sway_log(L_DEBUG, "xdg-positioner: placing window %" PRIuPTR " " - "sized (%u,%u) offset by (%d,%d), " - "anchor rectangle sized (%u,%u) at (%d,%d), " - "anchor edges: %s %s, gravity: %s %s", - handle, - sr->w, sr->h, offset.x, offset.y, - anchor->size.w, anchor->size.h, anchor->origin.x, anchor->origin.y, - anchors & WLC_BIT_ANCHOR_TOP ? "top" : - (anchors & WLC_BIT_ANCHOR_BOTTOM ? "bottom" : "middle"), - anchors & WLC_BIT_ANCHOR_LEFT ? "left" : - (anchors & WLC_BIT_ANCHOR_RIGHT ? "right" : "center"), - gravity & WLC_BIT_GRAVITY_TOP ? "top" : - (gravity & WLC_BIT_GRAVITY_BOTTOM ? "bottom" : "middle"), - gravity & WLC_BIT_GRAVITY_LEFT ? "left" : - (gravity & WLC_BIT_GRAVITY_RIGHT ? "right" : "center")); - - wlc_handle parent = wlc_view_get_parent(handle); - if (parent) { - const struct wlc_geometry *pg = wlc_view_get_geometry(parent); - geo.origin.x += pg->origin.x; - geo.origin.y += pg->origin.y; - } - wlc_view_set_geometry(handle, 0, &geo); -} - -static bool handle_view_created(wlc_handle handle) { - // if view is child of another view, the use that as focused container - wlc_handle parent = wlc_view_get_parent(handle); - swayc_t *focused = NULL; - swayc_t *newview = NULL; - swayc_t *current_ws = swayc_active_workspace(); - bool return_to_workspace = false; - struct wl_client *client = wlc_view_get_wl_client(handle); - struct wl_resource *resource = wlc_surface_get_wl_resource( - wlc_view_get_surface(handle)); - pid_t pid; - struct panel_config *panel_config = NULL; - struct background_config *background_config = NULL; - - panel_config = if_panel_find_config(client); - if (panel_config) { - panel_config->handle = handle; - update_panel_geometry(panel_config); - wlc_view_set_mask(handle, VISIBLE); - wlc_view_set_output(handle, panel_config->output); - wlc_view_bring_to_front(handle); - arrange_windows(&root_container, -1, -1); - return true; - } - - background_config = if_background_find_config(client); - if (background_config) { - background_config->handle = handle; - update_background_geometry(background_config); - wlc_view_set_mask(handle, VISIBLE); - wlc_view_set_output(handle, background_config->output); - wlc_view_send_to_back(handle); - return true; - } - - // Get parent container, to add view in - if (parent) { - focused = swayc_by_handle(parent); - } - - if (client) { - pid = wlc_view_get_pid(handle); - - if (pid) { - // using newview as a temp storage location here, - // rather than adding yet another workspace var - newview = workspace_for_pid(pid); - if (newview) { - focused = get_focused_container(newview); - return_to_workspace = true; - } - newview = NULL; - } - } - - swayc_t *prev_focus = get_focused_container(&root_container); - - if (!focused || focused->type == C_OUTPUT) { - focused = prev_focus; - // Move focus from floating view - if (focused->is_floating) { - // To workspace if there are no children - if (focused->parent->children->length == 0) { - focused = focused->parent; - } - // TODO find a better way of doing this - // Or to focused container - else { - focused = get_focused_container(focused->parent->children->items[0]); - } - } - } - - positioner_place_window(handle); - - sway_log(L_DEBUG, "handle:%" PRIuPTR " type:%x state:%x parent:%" PRIuPTR " " - "mask:%d (x:%d y:%d w:%d h:%d) title:%s " - "class:%s appid:%s", - handle, wlc_view_get_type(handle), wlc_view_get_state(handle), parent, - wlc_view_get_mask(handle), wlc_view_get_geometry(handle)->origin.x, - wlc_view_get_geometry(handle)->origin.y,wlc_view_get_geometry(handle)->size.w, - wlc_view_get_geometry(handle)->size.h, wlc_view_get_title(handle), - wlc_view_get_class(handle), wlc_view_get_app_id(handle)); - - // TODO properly figure out how each window should be handled. - switch (wlc_view_get_type(handle)) { - // regular view created regularly - case 0: - if (parent) { - newview = new_floating_view(handle); - } else { - newview = new_view(focused, handle); - wlc_view_set_state(handle, WLC_BIT_MAXIMIZED, true); - } - break; - - // Dmenu keeps viewfocus, but others with this flag don't, for now simulate - // dmenu - case WLC_BIT_OVERRIDE_REDIRECT: - wlc_view_focus(handle); - wlc_view_set_state(handle, WLC_BIT_ACTIVATED, true); - wlc_view_bring_to_front(handle); - break; - - // Firefox popups have this flag set. - case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED: - wlc_view_bring_to_front(handle); - locked_container_focus = true; - break; - - // Modals, get focus, popups do not - case WLC_BIT_MODAL: - wlc_view_focus(handle); - wlc_view_bring_to_front(handle); - newview = new_floating_view(handle); - /* fallthrough */ - case WLC_BIT_POPUP: - wlc_view_bring_to_front(handle); - break; - } - - // Prevent current ws from being destroyed, if empty - suspend_workspace_cleanup = true; - - if (newview) { - ipc_event_window(newview, "new"); - set_focused_container(newview); - wlc_view_set_mask(handle, VISIBLE); - swayc_t *output = swayc_parent_by_type(newview, C_OUTPUT); - arrange_windows(output, -1, -1); - // check if it matches for_window in config and execute if so - list_t *criteria = criteria_for(newview); - for (int i = 0; i < criteria->length; i++) { - struct criteria *crit = criteria->items[i]; - sway_log(L_DEBUG, "for_window '%s' matches new view %p, cmd: '%s'", - crit->crit_raw, newview, crit->cmdlist); - struct cmd_results *res = handle_command(crit->cmdlist, CONTEXT_CRITERIA); - if (res->status != CMD_SUCCESS) { - sway_log(L_ERROR, "Command '%s' failed: %s", res->input, res->error); - } - free_cmd_results(res); - // view must be focused for commands to affect it, so always - // refocus in-between command lists - set_focused_container(newview); - } - swayc_t *workspace = swayc_parent_by_type(focused, C_WORKSPACE); - if (workspace && workspace->fullscreen) { - set_focused_container(workspace->fullscreen); - } - for (int i = 0; i < decoration_state.csd_resources->length; ++i) { - struct wl_resource *res = decoration_state.csd_resources->items[i]; - if (res == resource) { - list_del(decoration_state.csd_resources, i); - server_decoration_enable_csd(handle); - break; - } - } - } else { - swayc_t *output = swayc_parent_by_type(focused, C_OUTPUT); - wlc_handle *h = malloc(sizeof(wlc_handle)); - if (!h) { - sway_log(L_ERROR, "Unable to allocate window handle, view handler bailing out"); - return true; - } - *h = handle; - sway_log(L_DEBUG, "Adding unmanaged window %p to %p", h, output->unmanaged); - list_add(output->unmanaged, h); - wlc_view_set_mask(handle, VISIBLE); - } - - if (return_to_workspace && current_ws != swayc_active_workspace()) { - // we were on one workspace, switched to another to add this view, - // now let's return to where we were - workspace_switch(current_ws); - set_focused_container(get_focused_container(current_ws)); - } - if (prev_focus && prev_focus->type == C_VIEW - && newview && criteria_any(newview, config->no_focus)) { - // Restore focus - swayc_t *ws = swayc_parent_by_type(newview, C_WORKSPACE); - if (!ws || ws != newview->parent - || ws->children->length + ws->floating->length != 1) { - sway_log(L_DEBUG, "no_focus: restoring focus to %s", prev_focus->name); - set_focused_container(prev_focus); - } - } - - suspend_workspace_cleanup = false; - ws_cleanup(); - return true; -} - -static void handle_view_destroyed(wlc_handle handle) { - sway_log(L_DEBUG, "Destroying window %" PRIuPTR, handle); - swayc_t *view = swayc_by_handle(handle); - - // destroy views by type - switch (wlc_view_get_type(handle)) { - // regular view created regularly - case 0: - case WLC_BIT_MODAL: - case WLC_BIT_POPUP: - break; - // DMENU has this flag, and takes view_focus, but other things with this - // flag don't - case WLC_BIT_OVERRIDE_REDIRECT: - break; - case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED: - locked_container_focus = false; - break; - } - - if (view) { - bool fullscreen = swayc_is_fullscreen(view); - remove_view_from_scratchpad(view); - swayc_t *parent = destroy_view(view), *iter = NULL; - if (parent) { - ipc_event_window(parent, "close"); - - // Destroy empty workspaces - if (parent->type == C_WORKSPACE && - parent->children->length == 0 && - parent->floating->length == 0 && - swayc_active_workspace() != parent && - !parent->visible) { - parent = destroy_workspace(parent); - } - - if (fullscreen) { - iter = parent; - while (iter) { - if (iter->fullscreen) { - iter->fullscreen = NULL; - break; - } - iter = iter->parent; - } - } - - - arrange_windows(iter ? iter : parent, -1, -1); - } - } else { - // Is it unmanaged? - int i; - for (i = 0; i < root_container.children->length; ++i) { - swayc_t *output = root_container.children->items[i]; - int j; - for (j = 0; j < output->unmanaged->length; ++j) { - wlc_handle *_handle = output->unmanaged->items[j]; - if (*_handle == handle) { - list_del(output->unmanaged, j); - free(_handle); - break; - } - } - } - // Is it in the scratchpad? - for (i = 0; i < scratchpad->length; ++i) { - swayc_t *item = scratchpad->items[i]; - if (item->handle == handle) { - list_del(scratchpad, i); - destroy_view(item); - break; - } - } - } - set_focused_container(get_focused_view(&root_container)); -} - -static void handle_view_focus(wlc_handle view, bool focus) { - return; -} - -static void handle_view_geometry_request(wlc_handle handle, const struct wlc_geometry *geometry) { - sway_log(L_DEBUG, "geometry request for %" PRIuPTR " %dx%d @ %d,%d", handle, - geometry->size.w, geometry->size.h, geometry->origin.x, geometry->origin.y); - // If the view is floating, then apply the geometry. - // Otherwise save the desired width/height for the view. - // This will not do anything for the time being as WLC improperly sends geometry requests - swayc_t *view = swayc_by_handle(handle); - if (view) { - view->desired_width = geometry->size.w; - view->desired_height = geometry->size.h; - - if (view->is_floating) { - floating_view_sane_size(view); - view->width = view->desired_width; - view->height = view->desired_height; - view->x = geometry->origin.x; - view->y = geometry->origin.y; - update_geometry(view); - } - } else { - wlc_view_set_geometry(handle, 0, geometry); - } -} - -static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit state, bool toggle) { - swayc_t *c = swayc_by_handle(view); - pid_t pid = wlc_view_get_pid(view); - switch (state) { - case WLC_BIT_FULLSCREEN: - if (!(get_feature_policy_mask(pid) & FEATURE_FULLSCREEN)) { - sway_log(L_INFO, "Denying fullscreen to %d (%s)", pid, c->name); - break; - } - // i3 just lets it become fullscreen - wlc_view_set_state(view, state, toggle); - if (c) { - sway_log(L_DEBUG, "setting view %" PRIuPTR " %s, fullscreen %d", view, c->name, toggle); - arrange_windows(c->parent, -1, -1); - // Set it as focused window for that workspace if its going fullscreen - swayc_t *ws = swayc_parent_by_type(c, C_WORKSPACE); - if (toggle) { - // Set ws focus to c - set_focused_container_for(ws, c); - ws->fullscreen = c; - } else { - ws->fullscreen = NULL; - } - } - break; - case WLC_BIT_MAXIMIZED: - case WLC_BIT_RESIZING: - case WLC_BIT_MOVING: - break; - case WLC_BIT_ACTIVATED: - sway_log(L_DEBUG, "View %p requested to be activated", c); - break; - } - return; -} - -static void handle_view_properties_updated(wlc_handle view, uint32_t mask) { - if (mask == WLC_BIT_PROPERTY_TITLE) { - swayc_t *c = swayc_by_handle(view); - if (!c) { - return; - } - - // update window title - const char *new_name = wlc_view_get_title(view); - - if (new_name) { - if (!c->name || strcmp(c->name, new_name) != 0) { - free(c->name); - c->name = strdup(new_name); - swayc_t *p = swayc_tabbed_stacked_ancestor(c); - if (p) { - // TODO: we only got the topmost tabbed/stacked container, update borders of all containers on the path - update_container_border(get_focused_view(p)); - } else if (c->border_type == B_NORMAL) { - update_container_border(c); - } - ipc_event_window(c, "title"); - } - } - } -} - -static void handle_binding_command(struct sway_binding *binding) { - struct sway_binding *binding_copy = binding; - bool reload = false; - // if this is a reload command we need to make a duplicate of the - // binding since it will be gone after the reload has completed. - if (strcasecmp(binding->command, "reload") == 0) { - binding_copy = sway_binding_dup(binding); - if (!binding_copy) { - sway_log(L_ERROR, "Unable to duplicate binding during reload"); - return; - } - reload = true; - } - - struct cmd_results *res = handle_command(binding->command, CONTEXT_BINDING); - if (res->status != CMD_SUCCESS) { - sway_log(L_ERROR, "Command '%s' failed: %s", res->input, res->error); - } - ipc_event_binding_keyboard(binding_copy); - - if (reload) { // free the binding if we made a copy - free_sway_binding(binding_copy); - } - - free_cmd_results(res); -} - -static bool handle_bindsym(struct sway_binding *binding, uint32_t keysym, uint32_t keycode) { - int i; - for (i = 0; i < binding->keys->length; ++i) { - if (binding->bindcode) { - xkb_keycode_t *key = binding->keys->items[i]; - if (keycode == *key) { - handle_binding_command(binding); - return true; - } - } else { - xkb_keysym_t *key = binding->keys->items[i]; - if (keysym == *key) { - handle_binding_command(binding); - return true; - } - } - } - - return false; -} - -static bool valid_bindsym(struct sway_binding *binding) { - bool match = false; - int i; - for (i = 0; i < binding->keys->length; ++i) { - if (binding->bindcode) { - xkb_keycode_t *key = binding->keys->items[i]; - if ((match = check_key(0, *key)) == false) { - break; - } - } else { - xkb_keysym_t *key = binding->keys->items[i]; - if ((match = check_key(*key, 0)) == false) { - break; - } - } - } - - return match; -} - -static bool handle_bindsym_release(struct sway_binding *binding) { - if (binding->keys->length == 1) { - xkb_keysym_t *key = binding->keys->items[0]; - if (check_released_key(*key)) { - handle_binding_command(binding); - return true; - } - } - - return false; -} - -static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers, - uint32_t key, enum wlc_key_state state) { - - if (desktop_shell.is_locked) { - return EVENT_PASSTHROUGH; - } - - // reset pointer mode on keypress - if (state == WLC_KEY_STATE_PRESSED && pointer_state.mode) { - pointer_mode_reset(); - } - - struct sway_mode *mode = config->current_mode; - - struct wlc_modifiers no_mods = { 0, 0 }; - uint32_t sym = tolower(wlc_keyboard_get_keysym_for_key(key, &no_mods)); - - int i; - - if (state == WLC_KEY_STATE_PRESSED) { - press_key(sym, key); - } else { // WLC_KEY_STATE_RELEASED - release_key(sym, key); - } - - // handle bar modifiers pressed/released - uint32_t modifier; - for (i = 0; i < config->active_bar_modifiers->length; ++i) { - modifier = *(uint32_t *)config->active_bar_modifiers->items[i]; - - switch (modifier_state_changed(modifiers->mods, modifier)) { - case MOD_STATE_PRESSED: - ipc_event_modifier(modifier, "pressed"); - break; - case MOD_STATE_RELEASED: - ipc_event_modifier(modifier, "released"); - break; - } - } - // update modifiers state - modifiers_state_update(modifiers->mods); - - // handle bindings - list_t *candidates = create_list(); - for (i = 0; i < mode->bindings->length; ++i) { - struct sway_binding *binding = mode->bindings->items[i]; - if ((modifiers->mods ^ binding->modifiers) == 0) { - switch (state) { - case WLC_KEY_STATE_PRESSED: - if (!binding->release && valid_bindsym(binding)) { - list_add(candidates, binding); - } - break; - case WLC_KEY_STATE_RELEASED: - if (binding->release && handle_bindsym_release(binding)) { - list_free(candidates); - return EVENT_HANDLED; - } - break; - } - } - } - - for (i = 0; i < candidates->length; ++i) { - struct sway_binding *binding = candidates->items[i]; - if (state == WLC_KEY_STATE_PRESSED) { - if (!binding->release && handle_bindsym(binding, sym, key)) { - list_free(candidates); - return EVENT_HANDLED; - } - } - } - - list_free(candidates); - - swayc_t *focused = get_focused_container(&root_container); - if (focused->type == C_VIEW) { - pid_t pid = wlc_view_get_pid(focused->handle); - if (!(get_feature_policy_mask(pid) & FEATURE_KEYBOARD)) { - return EVENT_HANDLED; - } - } - return EVENT_PASSTHROUGH; -} - -static bool handle_pointer_motion(wlc_handle handle, uint32_t time, double x, double y) { - if (desktop_shell.is_locked) { - return EVENT_PASSTHROUGH; - } - - double new_x = x; - double new_y = y; - // Switch to adjacent output if touching output edge. - // - // Since this doesn't currently support moving windows between outputs we - // don't do the switch if the pointer is in a mode. - if (config->seamless_mouse && !pointer_state.mode && - !pointer_state.left.held && !pointer_state.right.held && !pointer_state.scroll.held) { - - swayc_t *output = swayc_active_output(), *adjacent = NULL; - struct wlc_point abs_pos = { .x = x + output->x, .y = y + output->y }; - if (x <= 0) { // Left edge - if ((adjacent = swayc_adjacent_output(output, MOVE_LEFT, &abs_pos, false))) { - if (workspace_switch(swayc_active_workspace_for(adjacent))) { - new_x = adjacent->width; - // adjust for differently aligned outputs (well, this is - // only correct when the two outputs have the same - // resolution or the same dpi I guess, it should take - // physical attributes into account) - new_y += (output->y - adjacent->y); - } - } - } else if (x >= output->width) { // Right edge - if ((adjacent = swayc_adjacent_output(output, MOVE_RIGHT, &abs_pos, false))) { - if (workspace_switch(swayc_active_workspace_for(adjacent))) { - new_x = 0; - new_y += (output->y - adjacent->y); - } - } - } else if (y <= 0) { // Top edge - if ((adjacent = swayc_adjacent_output(output, MOVE_UP, &abs_pos, false))) { - if (workspace_switch(swayc_active_workspace_for(adjacent))) { - new_y = adjacent->height; - new_x += (output->x - adjacent->x); - } - } - } else if (y >= output->height) { // Bottom edge - if ((adjacent = swayc_adjacent_output(output, MOVE_DOWN, &abs_pos, false))) { - if (workspace_switch(swayc_active_workspace_for(adjacent))) { - new_y = 0; - new_x += (output->x - adjacent->x); - } - } - } - } - - pointer_position_set(new_x, new_y, false); - - swayc_t *focused = get_focused_container(&root_container); - if (focused->type == C_VIEW) { - pid_t pid = wlc_view_get_pid(focused->handle); - if (!(get_feature_policy_mask(pid) & FEATURE_MOUSE)) { - return EVENT_HANDLED; - } - } - - return EVENT_PASSTHROUGH; -} - -static bool swayc_border_check(swayc_t *c, const void *_origin) { - const struct wlc_point *origin = _origin; - const struct wlc_geometry title_bar = c->title_bar_geometry; - - if (c->border_type != B_NORMAL) { - return false; - } - - if (origin->x >= title_bar.origin.x && origin->y >= title_bar.origin.y - && origin->x < title_bar.origin.x + (int32_t)title_bar.size.w - && origin->y < title_bar.origin.y + (int32_t)title_bar.size.h) { - return true; - } - return false; -} - -static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers, - uint32_t button, enum wlc_button_state state, const struct wlc_point *origin) { - - // Update view pointer is on - pointer_state.view = container_under_pointer(); - - struct sway_mode *mode = config->current_mode; - // handle bindings - for (int i = 0; i < mode->bindings->length; ++i) { - struct sway_binding *binding = mode->bindings->items[i]; - if ((modifiers->mods ^ binding->modifiers) == 0) { - switch (state) { - case WLC_BUTTON_STATE_PRESSED: - if (!binding->release && handle_bindsym(binding, button, 0)) { - return EVENT_HANDLED; - } - break; - case WLC_BUTTON_STATE_RELEASED: - if (binding->release && handle_bindsym(binding, button, 0)) { - return EVENT_HANDLED; - } - break; - } - } - } - - // Update pointer_state - switch (button) { - case M_LEFT_CLICK: - if (state == WLC_BUTTON_STATE_PRESSED) { - pointer_state.left.held = true; - pointer_state.left.x = origin->x; - pointer_state.left.y = origin->y; - pointer_state.left.view = pointer_state.view; - } else { - pointer_state.left.held = false; - } - break; - - case M_RIGHT_CLICK: - if (state == WLC_BUTTON_STATE_PRESSED) { - pointer_state.right.held = true; - pointer_state.right.x = origin->x; - pointer_state.right.y = origin->y; - pointer_state.right.view = pointer_state.view; - } else { - pointer_state.right.held = false; - } - break; - - case M_SCROLL_CLICK: - if (state == WLC_BUTTON_STATE_PRESSED) { - pointer_state.scroll.held = true; - pointer_state.scroll.x = origin->x; - pointer_state.scroll.y = origin->y; - pointer_state.scroll.view = pointer_state.view; - } else { - pointer_state.scroll.held = false; - } - break; - - //TODO scrolling behavior - case M_SCROLL_UP: - case M_SCROLL_DOWN: - break; - } - - // get focused window and check if to change focus on mouse click - swayc_t *focused = get_focused_container(&root_container); - - // don't change focus or mode if fullscreen - if (swayc_is_fullscreen(focused)) { - if (focused->type == C_VIEW) { - pid_t pid = wlc_view_get_pid(focused->handle); - if (!(get_feature_policy_mask(pid) & FEATURE_MOUSE)) { - return EVENT_HANDLED; - } - } - return EVENT_PASSTHROUGH; - } - - // set pointer mode only if floating mod has been set - if (config->floating_mod) { - pointer_mode_set(button, !(modifiers->mods ^ config->floating_mod)); - } - - // Check whether to change focus - swayc_t *pointer = pointer_state.view; - if (pointer) { - swayc_t *ws = swayc_parent_by_type(focused, C_WORKSPACE); - if (ws != NULL) { - swayc_t *find = container_find(ws, &swayc_border_check, origin); - if (find != NULL) { - set_focused_container(find); - return EVENT_HANDLED; - } - } - - if (focused != pointer) { - set_focused_container(pointer_state.view); - } - // Send to front if floating - if (pointer->is_floating) { - int i; - for (i = 0; i < pointer->parent->floating->length; i++) { - if (pointer->parent->floating->items[i] == pointer) { - list_del(pointer->parent->floating, i); - list_add(pointer->parent->floating, pointer); - break; - } - } - wlc_view_bring_to_front(pointer->handle); - } - } - - // Return if mode has been set - if (pointer_state.mode) { - return EVENT_HANDLED; - } - - if (focused->type == C_VIEW) { - pid_t pid = wlc_view_get_pid(focused->handle); - if (!(get_feature_policy_mask(pid) & FEATURE_MOUSE)) { - return EVENT_HANDLED; - } - } - - // Always send mouse release - if (state == WLC_BUTTON_STATE_RELEASED) { - return EVENT_PASSTHROUGH; - } - - // Finally send click - return EVENT_PASSTHROUGH; -} - -bool handle_pointer_scroll(wlc_handle view, uint32_t time, const struct wlc_modifiers* modifiers, - uint8_t axis_bits, double _amount[2]) { - if (!(modifiers->mods ^ config->floating_mod)) { - int x_amount = (int)_amount[0]; - int y_amount = (int)_amount[1]; - - if (x_amount > 0 && strcmp(config->floating_scroll_up_cmd, "")) { - handle_command(config->floating_scroll_up_cmd, CONTEXT_BINDING); - return EVENT_HANDLED; - } else if (x_amount < 0 && strcmp(config->floating_scroll_down_cmd, "")) { - handle_command(config->floating_scroll_down_cmd, CONTEXT_BINDING); - return EVENT_HANDLED; - } - - if (y_amount > 0 && strcmp(config->floating_scroll_right_cmd, "")) { - handle_command(config->floating_scroll_right_cmd, CONTEXT_BINDING); - return EVENT_HANDLED; - } else if (y_amount < 0 && strcmp(config->floating_scroll_left_cmd, "")) { - handle_command(config->floating_scroll_left_cmd, CONTEXT_BINDING); - return EVENT_HANDLED; - } - } - return EVENT_PASSTHROUGH; -} - -static void handle_wlc_ready(void) { - sway_log(L_DEBUG, "Compositor is ready, executing cmds in queue"); - // Execute commands until there are none left - config->active = true; - while (config->cmd_queue->length) { - char *line = config->cmd_queue->items[0]; - struct cmd_results *res = handle_command(line, CONTEXT_CONFIG); - if (res->status != CMD_SUCCESS) { - sway_log(L_ERROR, "Error on line '%s': %s", line, res->error); - } - free_cmd_results(res); - free(line); - list_del(config->cmd_queue, 0); - } -} - -void register_wlc_handlers() { - wlc_set_output_created_cb(handle_output_created); - wlc_set_output_destroyed_cb(handle_output_destroyed); - wlc_set_output_resolution_cb(handle_output_resolution_change); - wlc_set_output_focus_cb(handle_output_focused); - wlc_set_output_render_post_cb(handle_output_post_render); - wlc_set_view_created_cb(handle_view_created); - wlc_set_view_destroyed_cb(handle_view_destroyed); - wlc_set_view_focus_cb(handle_view_focus); - wlc_set_view_render_pre_cb(handle_view_pre_render); - wlc_set_view_request_geometry_cb(handle_view_geometry_request); - wlc_set_view_request_state_cb(handle_view_state_request); - wlc_set_view_properties_updated_cb(handle_view_properties_updated); - wlc_set_keyboard_key_cb(handle_key); - wlc_set_pointer_motion_cb_v2(handle_pointer_motion); - wlc_set_pointer_button_cb(handle_pointer_button); - wlc_set_pointer_scroll_cb(handle_pointer_scroll); - wlc_set_compositor_ready_cb(handle_wlc_ready); - wlc_set_input_created_cb(handle_input_created); - wlc_set_input_destroyed_cb(handle_input_destroyed); -} diff --git a/sway/input_state.c b/sway/input_state.c deleted file mode 100644 index 04aafd37..00000000 --- a/sway/input_state.c +++ /dev/null @@ -1,490 +0,0 @@ -#include -#include -#include -#include "sway/input_state.h" -#include "sway/config.h" -#include "log.h" - -#define KEY_STATE_MAX_LENGTH 64 - -struct key_state { - /* - * Aims to store state regardless of modifiers. - * If you press a key, then hold shift, then release the key, we'll - * get two different key syms, but the same key code. This handles - * that scenario and makes sure we can use the right bindings. - */ - uint32_t key_sym; - uint32_t alt_sym; - uint32_t key_code; -}; - -static struct key_state key_state_array[KEY_STATE_MAX_LENGTH]; - -static struct key_state last_released; - -static uint32_t modifiers_state; - -void input_init(void) { - int i; - for (i = 0; i < KEY_STATE_MAX_LENGTH; ++i) { - struct key_state none = { 0, 0, 0 }; - key_state_array[i] = none; - } - - struct key_state none = { 0, 0, 0 }; - last_released = none; - - modifiers_state = 0; -} - -uint32_t modifier_state_changed(uint32_t new_state, uint32_t mod) { - if ((new_state & mod) != 0) { // pressed - if ((modifiers_state & mod) != 0) { // already pressed - return MOD_STATE_UNCHANGED; - } else { // pressed - return MOD_STATE_PRESSED; - } - } else { // not pressed - if ((modifiers_state & mod) != 0) { // released - return MOD_STATE_RELEASED; - } else { // already released - return MOD_STATE_UNCHANGED; - } - } -} - -void modifiers_state_update(uint32_t new_state) { - modifiers_state = new_state; -} - -static uint8_t find_key(uint32_t key_sym, uint32_t key_code, bool update) { - int i; - for (i = 0; i < KEY_STATE_MAX_LENGTH; ++i) { - if (0 == key_sym && 0 == key_code && key_state_array[i].key_sym == 0) { - break; - } - if (key_sym != 0 && (key_state_array[i].key_sym == key_sym - || key_state_array[i].alt_sym == key_sym)) { - break; - } - if (update && key_state_array[i].key_code == key_code) { - key_state_array[i].alt_sym = key_sym; - break; - } - if (key_sym == 0 && key_code != 0 && key_state_array[i].key_code == key_code) { - break; - } - } - return i; -} - -bool check_key(uint32_t key_sym, uint32_t key_code) { - return find_key(key_sym, key_code, false) < KEY_STATE_MAX_LENGTH; -} - -bool check_released_key(uint32_t key_sym) { - return (key_sym != 0 - && (last_released.key_sym == key_sym - || last_released.alt_sym == key_sym)); -} - -void press_key(uint32_t key_sym, uint32_t key_code) { - if (key_code == 0) { - return; - } - // Check if key exists - if (!check_key(key_sym, key_code)) { - // Check that we don't exceed buffer length - int insert = find_key(0, 0, true); - if (insert < KEY_STATE_MAX_LENGTH) { - key_state_array[insert].key_sym = key_sym; - key_state_array[insert].key_code = key_code; - } - } -} - -void release_key(uint32_t key_sym, uint32_t key_code) { - uint8_t index = find_key(key_sym, key_code, true); - if (index < KEY_STATE_MAX_LENGTH) { - last_released.key_sym = key_state_array[index].key_sym; - last_released.alt_sym = key_state_array[index].alt_sym; - last_released.key_code = key_state_array[index].key_code; - struct key_state none = { 0, 0, 0 }; - key_state_array[index] = none; - } -} - -// Pointer state and mode - -struct pointer_state pointer_state; - -static struct mode_state { - // initial view state - double x, y, w, h; - swayc_t *ptr; - // Containers used for resizing horizontally - struct { - double w; - swayc_t *ptr; - struct { - double w; - swayc_t *ptr; - } parent; - } horiz; - // Containers used for resizing vertically - struct { - double h; - swayc_t *ptr; - struct { - double h; - swayc_t *ptr; - } parent; - } vert; -} initial; - -static struct { - bool left; - bool top; -} lock; - -// initial set/unset - -static void set_initial_view(swayc_t *view) { - initial.ptr = view; - initial.x = view->x; - initial.y = view->y; - initial.w = view->width; - initial.h = view->height; -} - -static void set_initial_sibling(void) { - bool reset = true; - swayc_t *ws = swayc_active_workspace_for(initial.ptr); - if ((initial.horiz.ptr = get_swayc_in_direction_under(initial.ptr, - lock.left ? MOVE_RIGHT: MOVE_LEFT, ws))) { - initial.horiz.w = initial.horiz.ptr->width; - initial.horiz.parent.ptr = get_swayc_in_direction_under(initial.horiz.ptr, - lock.left ? MOVE_LEFT : MOVE_RIGHT, ws); - initial.horiz.parent.w = initial.horiz.parent.ptr->width; - reset = false; - } - if ((initial.vert.ptr = get_swayc_in_direction_under(initial.ptr, - lock.top ? MOVE_DOWN: MOVE_UP, ws))) { - initial.vert.h = initial.vert.ptr->height; - initial.vert.parent.ptr = get_swayc_in_direction_under(initial.vert.ptr, - lock.top ? MOVE_UP : MOVE_DOWN, ws); - initial.vert.parent.h = initial.vert.parent.ptr->height; - reset = false; - } - // If nothing will change just undo the mode - if (reset) { - pointer_state.mode = 0; - } -} - -static void reset_initial_view(void) { - initial.ptr->x = initial.x; - initial.ptr->y = initial.y; - initial.ptr->width = initial.w; - initial.ptr->height = initial.h; - arrange_windows(initial.ptr, -1, -1); - pointer_state.mode = 0; -} - -static void reset_initial_sibling(void) { - initial.horiz.ptr->width = initial.horiz.w; - initial.horiz.parent.ptr->width = initial.horiz.parent.w; - initial.vert.ptr->height = initial.vert.h; - initial.vert.parent.ptr->height = initial.vert.parent.h; - arrange_windows(initial.horiz.ptr->parent, -1, -1); - arrange_windows(initial.vert.ptr->parent, -1, -1); - pointer_state.mode = 0; -} - -void pointer_position_set(double new_x, double new_y, bool force_focus) { - double x, y; - wlc_pointer_get_position_v2(&x, &y); - pointer_state.delta.x = new_x - x; - pointer_state.delta.y = new_y - y; - - wlc_pointer_set_position_v2(new_x, new_y); - - // Update view under pointer - swayc_t *prev_view = pointer_state.view; - pointer_state.view = container_under_pointer(); - - // If pointer is in a mode, update it - if (pointer_state.mode) { - pointer_mode_update(); - // Otherwise change focus if config is set - } else if (force_focus || (prev_view != pointer_state.view && config->focus_follows_mouse)) { - if (pointer_state.view && pointer_state.view->type == C_VIEW) { - set_focused_container(pointer_state.view); - } - } -} - -void center_pointer_on(swayc_t *view) { - pointer_position_set(view->x + view->width/2, view->y + view->height/2, true); -} - -// Mode set left/right click - -static void pointer_mode_set_dragging(void) { - switch (config->dragging_key) { - case M_LEFT_CLICK: - set_initial_view(pointer_state.left.view); - break; - case M_RIGHT_CLICK: - set_initial_view(pointer_state.right.view); - break; - } - - if (initial.ptr->is_floating) { - pointer_state.mode = M_DRAGGING | M_FLOATING; - } else { - pointer_state.mode = M_DRAGGING | M_TILING; - // unset mode if we can't drag tile - if (initial.ptr->parent->type == C_WORKSPACE && - initial.ptr->parent->children->length == 1) { - pointer_state.mode = 0; - } - } -} - -static void pointer_mode_set_resizing(void) { - switch (config->resizing_key) { - case M_LEFT_CLICK: - set_initial_view(pointer_state.left.view); - break; - case M_RIGHT_CLICK: - set_initial_view(pointer_state.right.view); - break; - } - // Setup locking information - int midway_x = initial.ptr->x + initial.ptr->width/2; - int midway_y = initial.ptr->y + initial.ptr->height/2; - - double x, y; - wlc_pointer_get_position_v2(&x, &y); - lock.left = x > midway_x; - lock.top = y > midway_y; - - if (initial.ptr->is_floating) { - pointer_state.mode = M_RESIZING | M_FLOATING; - } else { - pointer_state.mode = M_RESIZING | M_TILING; - set_initial_sibling(); - } -} - -// Mode set/update/reset - -void pointer_mode_set(uint32_t button, bool condition) { - // switch on drag/resize mode - switch (pointer_state.mode & (M_DRAGGING | M_RESIZING)) { - case M_DRAGGING: - // end drag mode when 'dragging' click is unpressed - if (config->dragging_key == M_LEFT_CLICK && !pointer_state.left.held) { - pointer_state.mode = 0; - } else if (config->dragging_key == M_RIGHT_CLICK && !pointer_state.right.held) { - pointer_state.mode = 0; - } - break; - - case M_RESIZING: - // end resize mode when 'resizing' click is unpressed - if (config->resizing_key == M_LEFT_CLICK && !pointer_state.left.held) { - pointer_state.mode = 0; - } else if (config->resizing_key == M_RIGHT_CLICK && !pointer_state.right.held) { - pointer_state.mode = 0; - } - break; - - // No mode case - default: - // return if failed condition, or no view - if (!condition || !pointer_state.view) { - break; - } - - // Set mode depending on current button press - switch (button) { - // Start left-click mode - case M_LEFT_CLICK: - // if button release don't do anything - if (pointer_state.left.held) { - if (config->dragging_key == M_LEFT_CLICK) { - pointer_mode_set_dragging(); - } else if (config->resizing_key == M_LEFT_CLICK) { - pointer_mode_set_resizing(); - } - } - break; - - // Start right-click mode - case M_RIGHT_CLICK: - // if button release don't do anyhting - if (pointer_state.right.held) { - if (config->dragging_key == M_RIGHT_CLICK) { - pointer_mode_set_dragging(); - } else if (config->resizing_key == M_RIGHT_CLICK) { - pointer_mode_set_resizing(); - } - } - break; - } - } -} - -void pointer_mode_update(void) { - if (initial.ptr->type != C_VIEW) { - pointer_state.mode = 0; - return; - } - double x, y; - wlc_pointer_get_position_v2(&x, &y); - int dx = x; - int dy = y; - - switch (pointer_state.mode) { - case M_FLOATING | M_DRAGGING: - // Update position - switch (config->dragging_key) { - case M_LEFT_CLICK: - dx -= pointer_state.left.x; - dy -= pointer_state.left.y; - break; - case M_RIGHT_CLICK: - dx -= pointer_state.right.x; - dy -= pointer_state.right.y; - break; - } - - if (initial.x + dx != initial.ptr->x) { - initial.ptr->x = initial.x + dx; - } - if (initial.y + dy != initial.ptr->y) { - initial.ptr->y = initial.y + dy; - } - update_geometry(initial.ptr); - break; - - case M_FLOATING | M_RESIZING: - switch (config->resizing_key) { - case M_LEFT_CLICK: - dx -= pointer_state.left.x; - dy -= pointer_state.left.y; - initial.ptr = pointer_state.left.view; - break; - case M_RIGHT_CLICK: - dx -= pointer_state.right.x; - dy -= pointer_state.right.y; - initial.ptr = pointer_state.right.view; - break; - } - - if (lock.left) { - if (initial.w + dx > min_sane_w) { - initial.ptr->width = initial.w + dx; - } - } else { // lock.right - if (initial.w - dx > min_sane_w) { - initial.ptr->width = initial.w - dx; - initial.ptr->x = initial.x + dx; - } - } - if (lock.top) { - if (initial.h + dy > min_sane_h) { - initial.ptr->height = initial.h + dy; - } - } else { // lock.bottom - if (initial.h - dy > min_sane_h) { - initial.ptr->height = initial.h - dy; - initial.ptr->y = initial.y + dy; - } - } - update_geometry(initial.ptr); - break; - - case M_TILING | M_DRAGGING: - // swap current view under pointer with dragged view - if (pointer_state.view && pointer_state.view->type == C_VIEW - && pointer_state.view != initial.ptr - && !pointer_state.view->is_floating) { - // Swap them around - swap_container(pointer_state.view, initial.ptr); - swap_geometry(pointer_state.view, initial.ptr); - update_geometry(pointer_state.view); - update_geometry(initial.ptr); - // Set focus back to initial view - set_focused_container(initial.ptr); - // Arrange the windows - arrange_windows(&root_container, -1, -1); - } - break; - - case M_TILING | M_RESIZING: - switch (config->resizing_key) { - case M_LEFT_CLICK: - dx -= pointer_state.left.x; - dy -= pointer_state.left.y; - break; - case M_RIGHT_CLICK: - dx -= pointer_state.right.x; - dy -= pointer_state.right.y; - break; - } - - // resize if we can - if (initial.horiz.ptr) { - if (lock.left) { - // Check whether its fine to resize - if (initial.w + dx > min_sane_w && initial.horiz.w - dx > min_sane_w) { - initial.horiz.ptr->width = initial.horiz.w - dx; - initial.horiz.parent.ptr->width = initial.horiz.parent.w + dx; - } - } else { // lock.right - if (initial.w - dx > min_sane_w && initial.horiz.w + dx > min_sane_w) { - initial.horiz.ptr->width = initial.horiz.w + dx; - initial.horiz.parent.ptr->width = initial.horiz.parent.w - dx; - } - } - arrange_windows(initial.horiz.ptr->parent, -1, -1); - } - if (initial.vert.ptr) { - if (lock.top) { - if (initial.h + dy > min_sane_h && initial.vert.h - dy > min_sane_h) { - initial.vert.ptr->height = initial.vert.h - dy; - initial.vert.parent.ptr->height = initial.vert.parent.h + dy; - } - } else { // lock.bottom - if (initial.h - dy > min_sane_h && initial.vert.h + dy > min_sane_h) { - initial.vert.ptr->height = initial.vert.h + dy; - initial.vert.parent.ptr->height = initial.vert.parent.h - dy; - } - } - arrange_windows(initial.vert.ptr->parent, -1, -1); - } - default: - return; - } -} - -void pointer_mode_reset(void) { - switch (pointer_state.mode) { - case M_FLOATING | M_RESIZING: - case M_FLOATING | M_DRAGGING: - reset_initial_view(); - break; - - case M_TILING | M_RESIZING: - (void) reset_initial_sibling; - break; - - case M_TILING | M_DRAGGING: - default: - break; - } -} diff --git a/sway/ipc-json.c b/sway/ipc-json.c deleted file mode 100644 index 1579a2d9..00000000 --- a/sway/ipc-json.c +++ /dev/null @@ -1,521 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include -#include "sway/output.h" -#include "sway/container.h" -#include "sway/input.h" -#include "sway/ipc-json.h" -#include "util.h" - -static json_object *ipc_json_create_rect(swayc_t *c) { - json_object *rect = json_object_new_object(); - - json_object_object_add(rect, "x", json_object_new_int((int32_t)c->x)); - json_object_object_add(rect, "y", json_object_new_int((int32_t)c->y)); - - struct wlr_box box; - if (c->type == C_OUTPUT) { - wlr_output_effective_resolution(c->_handle.output->wlr_output, - &box.width, &box.height); - } else { - box.width = c->width; - box.width = c->height; - } - - json_object_object_add(rect, "width", - json_object_new_int((int32_t)box.width)); - json_object_object_add(rect, "height", - json_object_new_int((int32_t)box.height)); - - return rect; -} - -static json_object *ipc_json_create_rect_from_geometry(struct wlc_geometry g) { - json_object *rect = json_object_new_object(); - - json_object_object_add(rect, "x", json_object_new_int(g.origin.x)); - json_object_object_add(rect, "y", json_object_new_int(g.origin.y)); - json_object_object_add(rect, "width", json_object_new_int(g.size.w)); - json_object_object_add(rect, "height", json_object_new_int(g.size.h)); - - return rect; -} - -static const char *ipc_json_border_description(swayc_t *c) { - const char *border; - - switch (c->border_type) { - case B_PIXEL: - border = "1pixel"; - break; - - case B_NORMAL: - border = "normal"; - break; - - case B_NONE: // fallthrough - default: - border = "none"; - break; - } - - return border; -} - -static const char *ipc_json_layout_description(enum swayc_layouts l) { - const char *layout; - - switch (l) { - case L_VERT: - layout = "splitv"; - break; - - case L_HORIZ: - layout = "splith"; - break; - - case L_TABBED: - layout = "tabbed"; - break; - - case L_STACKED: - layout = "stacked"; - break; - - case L_FLOATING: - layout = "floating"; - break; - - case L_NONE: // fallthrough - case L_LAYOUTS: // fallthrough; this should never happen, I'm just trying to silence compiler warnings - default: - layout = "null"; - break; - } - - return layout; -} - -static float ipc_json_child_percentage(swayc_t *c) { - float percent = 0; - swayc_t *parent = c->parent; - - if (parent) { - switch (parent->layout) { - case L_VERT: - percent = c->height / parent->height; - break; - - case L_HORIZ: - percent = c->width / parent->width; - break; - - case L_STACKED: // fallthrough - case L_TABBED: // fallthrough - percent = 1.0; - break; - - default: - break; - } - } - - return percent; -} - -static void ipc_json_describe_output(swayc_t *output, json_object *object) { - uint32_t scale = wlc_output_get_scale(output->handle); - json_object_object_add(object, "active", json_object_new_boolean(true)); - json_object_object_add(object, "primary", json_object_new_boolean(false)); - json_object_object_add(object, "layout", json_object_new_string("output")); - json_object_object_add(object, "type", json_object_new_string("output")); - json_object_object_add(object, "current_workspace", - (output->focused) ? json_object_new_string(output->focused->name) : NULL); - json_object_object_add(object, "scale", json_object_new_int(scale)); -} - -static void ipc_json_describe_workspace(swayc_t *workspace, json_object *object) { - int num = (isdigit(workspace->name[0])) ? atoi(workspace->name) : -1; - const char *layout = ipc_json_layout_description(workspace->workspace_layout); - - json_object_object_add(object, "num", json_object_new_int(num)); - json_object_object_add(object, "output", (workspace->parent) ? json_object_new_string(workspace->parent->name) : NULL); - json_object_object_add(object, "type", json_object_new_string("workspace")); - json_object_object_add(object, "layout", (strcmp(layout, "null") == 0) ? NULL : json_object_new_string(layout)); -} - -// window is in the scratchpad ? changed : none -static const char *ipc_json_get_scratchpad_state(swayc_t *c) { - int i; - for (i = 0; i < scratchpad->length; i++) { - if (scratchpad->items[i] == c) { - return "changed"; - } - } - return "none"; // we ignore the fresh value -} - -static void ipc_json_describe_view(swayc_t *c, json_object *object) { - json_object *props = json_object_new_object(); - json_object_object_add(object, "type", json_object_new_string((c->is_floating) ? "floating_con" : "con")); - - wlc_handle parent = wlc_view_get_parent(c->handle); - json_object_object_add(object, "scratchpad_state", - json_object_new_string(ipc_json_get_scratchpad_state(c))); - - json_object_object_add(object, "name", (c->name) ? json_object_new_string(c->name) : NULL); - - json_object_object_add(props, "class", c->class ? json_object_new_string(c->class) : - c->app_id ? json_object_new_string(c->app_id) : NULL); - json_object_object_add(props, "instance", c->instance ? json_object_new_string(c->instance) : - c->app_id ? json_object_new_string(c->app_id) : NULL); - json_object_object_add(props, "title", (c->name) ? json_object_new_string(c->name) : NULL); - json_object_object_add(props, "transient_for", parent ? json_object_new_int(parent) : NULL); - json_object_object_add(object, "window_properties", props); - - json_object_object_add(object, "fullscreen_mode", - json_object_new_int(swayc_is_fullscreen(c) ? 1 : 0)); - json_object_object_add(object, "sticky", json_object_new_boolean(c->sticky)); - json_object_object_add(object, "floating", json_object_new_string( - c->is_floating ? "auto_on" : "auto_off")); // we can't state the cause - - json_object_object_add(object, "app_id", c->app_id ? json_object_new_string(c->app_id) : NULL); - - if (c->parent) { - const char *layout = (c->parent->type == C_CONTAINER) ? - ipc_json_layout_description(c->parent->layout) : "none"; - const char *last_layout = (c->parent->type == C_CONTAINER) ? - ipc_json_layout_description(c->parent->prev_layout) : "none"; - json_object_object_add(object, "layout", - (strcmp(layout, "null") == 0) ? NULL : json_object_new_string(layout)); - json_object_object_add(object, "last_split_layout", - (strcmp(last_layout, "null") == 0) ? NULL : json_object_new_string(last_layout)); - json_object_object_add(object, "workspace_layout", - json_object_new_string(ipc_json_layout_description(swayc_parent_by_type(c, C_WORKSPACE)->workspace_layout))); - } -} - -static void ipc_json_describe_root(swayc_t *c, json_object *object) { - json_object_object_add(object, "type", json_object_new_string("root")); - json_object_object_add(object, "layout", json_object_new_string("splith")); -} - -json_object *ipc_json_describe_container(swayc_t *c) { - float percent = ipc_json_child_percentage(c); - - if (!(sway_assert(c, "Container must not be null."))) { - return NULL; - } - - json_object *object = json_object_new_object(); - - json_object_object_add(object, "id", json_object_new_int((int)c->id)); - json_object_object_add(object, "name", (c->name) ? json_object_new_string(c->name) : NULL); - json_object_object_add(object, "rect", ipc_json_create_rect(c)); - json_object_object_add(object, "visible", json_object_new_boolean(c->visible)); - json_object_object_add(object, "focused", json_object_new_boolean(c == current_focus)); - - json_object_object_add(object, "border", json_object_new_string(ipc_json_border_description(c))); - json_object_object_add(object, "window_rect", ipc_json_create_rect_from_geometry(c->actual_geometry)); - json_object_object_add(object, "deco_rect", ipc_json_create_rect_from_geometry(c->title_bar_geometry)); - json_object_object_add(object, "geometry", ipc_json_create_rect_from_geometry(c->cached_geometry)); - json_object_object_add(object, "percent", (percent > 0) ? json_object_new_double(percent) : NULL); - json_object_object_add(object, "window", json_object_new_int(c->handle)); // for the sake of i3 compat - // TODO: make urgency actually work once Sway supports it - json_object_object_add(object, "urgent", json_object_new_boolean(false)); - json_object_object_add(object, "current_border_width", json_object_new_int(c->border_thickness)); - - switch (c->type) { - case C_ROOT: - ipc_json_describe_root(c, object); - break; - - case C_OUTPUT: - ipc_json_describe_output(c, object); - break; - - case C_CONTAINER: // fallthrough - case C_VIEW: - ipc_json_describe_view(c, object); - break; - - case C_WORKSPACE: - ipc_json_describe_workspace(c, object); - break; - - case C_TYPES: // fallthrough; this should never happen, I'm just trying to silence compiler warnings - default: - break; - } - - return object; -} - -json_object *ipc_json_describe_input(struct libinput_device *device) { - char* identifier = libinput_dev_unique_id(device); - int vendor = libinput_device_get_id_vendor(device); - int product = libinput_device_get_id_product(device); - const char *name = libinput_device_get_name(device); - double width = -1, height = -1; - int has_size = libinput_device_get_size(device, &width, &height); - - json_object *device_object = json_object_new_object(); - json_object_object_add(device_object,"identifier", - identifier ? json_object_new_string(identifier) : NULL); - json_object_object_add(device_object, - "vendor", json_object_new_int(vendor)); - json_object_object_add(device_object, - "product", json_object_new_int(product)); - json_object_object_add(device_object, - "name", json_object_new_string(name)); - if (has_size == 0) { - json_object *size_object = json_object_new_object(); - json_object_object_add(size_object, - "width", json_object_new_double(width)); - json_object_object_add(size_object, - "height", json_object_new_double(height)); - } else { - json_object_object_add(device_object, "size", NULL); - } - - struct { - enum libinput_device_capability cap; - const char *name; - // If anyone feels like implementing device-specific IPC output, - // be my guest - json_object *(*describe)(struct libinput_device *); - } caps[] = { - { LIBINPUT_DEVICE_CAP_KEYBOARD, "keyboard", NULL }, - { LIBINPUT_DEVICE_CAP_POINTER, "pointer", NULL }, - { LIBINPUT_DEVICE_CAP_TOUCH, "touch", NULL }, - { LIBINPUT_DEVICE_CAP_TABLET_TOOL, "tablet_tool", NULL }, - { LIBINPUT_DEVICE_CAP_TABLET_PAD, "tablet_pad", NULL }, - { LIBINPUT_DEVICE_CAP_GESTURE, "gesture", NULL }, -#ifdef LIBINPUT_DEVICE_CAP_SWITCH // libinput 1.7.0+ - { LIBINPUT_DEVICE_CAP_SWITCH, "switch", NULL }, -#endif - }; - - json_object *_caps = json_object_new_array(); - for (size_t i = 0; i < sizeof(caps) / sizeof(caps[0]); ++i) { - if (libinput_device_has_capability(device, caps[i].cap)) { - json_object_array_add(_caps, json_object_new_string(caps[i].name)); - if (caps[i].describe) { - json_object *desc = caps[i].describe(device); - json_object_object_add(device_object, caps[i].name, desc); - } - } - } - json_object_object_add(device_object, "capabilities", _caps); - - free(identifier); - return device_object; -} - -json_object *ipc_json_get_version() { - int major = 0, minor = 0, patch = 0; - json_object *version = json_object_new_object(); - - sscanf(SWAY_VERSION, "%u.%u.%u", &major, &minor, &patch); - - json_object_object_add(version, "human_readable", json_object_new_string(SWAY_VERSION)); - json_object_object_add(version, "variant", json_object_new_string("sway")); - json_object_object_add(version, "major", json_object_new_int(major)); - json_object_object_add(version, "minor", json_object_new_int(minor)); - json_object_object_add(version, "patch", json_object_new_int(patch)); - - return version; -} - -json_object *ipc_json_describe_bar_config(struct bar_config *bar) { - if (!sway_assert(bar, "Bar must not be NULL")) { - return NULL; - } - - json_object *json = json_object_new_object(); - json_object_object_add(json, "id", json_object_new_string(bar->id)); -#ifdef ENABLE_TRAY - if (bar->tray_output) { - json_object_object_add(json, "tray_output", json_object_new_string(bar->tray_output)); - } else { - json_object_object_add(json, "tray_output", NULL); - } - if (bar->icon_theme) { - json_object_object_add(json, "icon_theme", json_object_new_string(bar->icon_theme)); - } else { - json_object_object_add(json, "icon_theme", NULL); - } - json_object_object_add(json, "tray_padding", json_object_new_int(bar->tray_padding)); - json_object_object_add(json, "activate_button", json_object_new_int(bar->activate_button)); - json_object_object_add(json, "context_button", json_object_new_int(bar->context_button)); - json_object_object_add(json, "secondary_button", json_object_new_int(bar->secondary_button)); -#endif - json_object_object_add(json, "mode", json_object_new_string(bar->mode)); - json_object_object_add(json, "hidden_state", json_object_new_string(bar->hidden_state)); - json_object_object_add(json, "modifier", json_object_new_string(get_modifier_name_by_mask(bar->modifier))); - switch (bar->position) { - case DESKTOP_SHELL_PANEL_POSITION_TOP: - json_object_object_add(json, "position", json_object_new_string("top")); - break; - case DESKTOP_SHELL_PANEL_POSITION_BOTTOM: - json_object_object_add(json, "position", json_object_new_string("bottom")); - break; - case DESKTOP_SHELL_PANEL_POSITION_LEFT: - json_object_object_add(json, "position", json_object_new_string("left")); - break; - case DESKTOP_SHELL_PANEL_POSITION_RIGHT: - json_object_object_add(json, "position", json_object_new_string("right")); - break; - } - json_object_object_add(json, "status_command", json_object_new_string(bar->status_command)); - json_object_object_add(json, "font", json_object_new_string((bar->font) ? bar->font : config->font)); - if (bar->separator_symbol) { - json_object_object_add(json, "separator_symbol", json_object_new_string(bar->separator_symbol)); - } - json_object_object_add(json, "bar_height", json_object_new_int(bar->height)); - json_object_object_add(json, "wrap_scroll", json_object_new_boolean(bar->wrap_scroll)); - json_object_object_add(json, "workspace_buttons", json_object_new_boolean(bar->workspace_buttons)); - json_object_object_add(json, "strip_workspace_numbers", json_object_new_boolean(bar->strip_workspace_numbers)); - json_object_object_add(json, "binding_mode_indicator", json_object_new_boolean(bar->binding_mode_indicator)); - json_object_object_add(json, "verbose", json_object_new_boolean(bar->verbose)); - json_object_object_add(json, "pango_markup", json_object_new_boolean(bar->pango_markup)); - - json_object *colors = json_object_new_object(); - json_object_object_add(colors, "background", json_object_new_string(bar->colors.background)); - json_object_object_add(colors, "statusline", json_object_new_string(bar->colors.statusline)); - json_object_object_add(colors, "separator", json_object_new_string(bar->colors.separator)); - - if (bar->colors.focused_background) { - json_object_object_add(colors, "focused_background", json_object_new_string(bar->colors.focused_background)); - } else { - json_object_object_add(colors, "focused_background", json_object_new_string(bar->colors.background)); - } - - if (bar->colors.focused_statusline) { - json_object_object_add(colors, "focused_statusline", json_object_new_string(bar->colors.focused_statusline)); - } else { - json_object_object_add(colors, "focused_statusline", json_object_new_string(bar->colors.statusline)); - } - - if (bar->colors.focused_separator) { - json_object_object_add(colors, "focused_separator", json_object_new_string(bar->colors.focused_separator)); - } else { - json_object_object_add(colors, "focused_separator", json_object_new_string(bar->colors.separator)); - } - - json_object_object_add(colors, "focused_workspace_border", json_object_new_string(bar->colors.focused_workspace_border)); - json_object_object_add(colors, "focused_workspace_bg", json_object_new_string(bar->colors.focused_workspace_bg)); - json_object_object_add(colors, "focused_workspace_text", json_object_new_string(bar->colors.focused_workspace_text)); - - json_object_object_add(colors, "inactive_workspace_border", json_object_new_string(bar->colors.inactive_workspace_border)); - json_object_object_add(colors, "inactive_workspace_bg", json_object_new_string(bar->colors.inactive_workspace_bg)); - json_object_object_add(colors, "inactive_workspace_text", json_object_new_string(bar->colors.inactive_workspace_text)); - - json_object_object_add(colors, "active_workspace_border", json_object_new_string(bar->colors.active_workspace_border)); - json_object_object_add(colors, "active_workspace_bg", json_object_new_string(bar->colors.active_workspace_bg)); - json_object_object_add(colors, "active_workspace_text", json_object_new_string(bar->colors.active_workspace_text)); - - json_object_object_add(colors, "urgent_workspace_border", json_object_new_string(bar->colors.urgent_workspace_border)); - json_object_object_add(colors, "urgent_workspace_bg", json_object_new_string(bar->colors.urgent_workspace_bg)); - json_object_object_add(colors, "urgent_workspace_text", json_object_new_string(bar->colors.urgent_workspace_text)); - - if (bar->colors.binding_mode_border) { - json_object_object_add(colors, "binding_mode_border", json_object_new_string(bar->colors.binding_mode_border)); - } else { - json_object_object_add(colors, "binding_mode_border", json_object_new_string(bar->colors.urgent_workspace_border)); - } - - if (bar->colors.binding_mode_bg) { - json_object_object_add(colors, "binding_mode_bg", json_object_new_string(bar->colors.binding_mode_bg)); - } else { - json_object_object_add(colors, "binding_mode_bg", json_object_new_string(bar->colors.urgent_workspace_bg)); - } - - if (bar->colors.binding_mode_text) { - json_object_object_add(colors, "binding_mode_text", json_object_new_string(bar->colors.binding_mode_text)); - } else { - json_object_object_add(colors, "binding_mode_text", json_object_new_string(bar->colors.urgent_workspace_text)); - } - - json_object_object_add(json, "colors", colors); - - // Add outputs if defined - if (bar->outputs && bar->outputs->length > 0) { - json_object *outputs = json_object_new_array(); - int i; - for (i = 0; i < bar->outputs->length; ++i) { - const char *name = bar->outputs->items[i]; - json_object_array_add(outputs, json_object_new_string(name)); - } - json_object_object_add(json, "outputs", outputs); - } - - return json; -} - -json_object *ipc_json_describe_container_recursive(swayc_t *c) { - json_object *object = ipc_json_describe_container(c); - int i; - - json_object *floating = json_object_new_array(); - if (c->type != C_VIEW && c->floating) { - for (i = 0; i < c->floating->length; ++i) { - swayc_t *item = c->floating->items[i]; - json_object_array_add(floating, ipc_json_describe_container_recursive(item)); - } - } - json_object_object_add(object, "floating_nodes", floating); - - json_object *children = json_object_new_array(); - if (c->type != C_VIEW && c->children) { - for (i = 0; i < c->children->length; ++i) { - json_object_array_add(children, ipc_json_describe_container_recursive(c->children->items[i])); - } - } - json_object_object_add(object, "nodes", children); - - json_object *focus = json_object_new_array(); - if (c->type != C_VIEW) { - if (c->focused) { - json_object_array_add(focus, json_object_new_double(c->focused->id)); - } - if (c->floating) { - for (i = 0; i < c->floating->length; ++i) { - swayc_t *item = c->floating->items[i]; - if (item == c->focused) { - continue; - } - - json_object_array_add(focus, json_object_new_double(item->id)); - } - } - if (c->children) { - for (i = 0; i < c->children->length; ++i) { - swayc_t *item = c->children->items[i]; - if (item == c->focused) { - continue; - } - - json_object_array_add(focus, json_object_new_double(item->id)); - } - } - } - json_object_object_add(object, "focus", focus); - - if (c->type == C_ROOT) { - json_object *scratchpad_json = json_object_new_array(); - if (scratchpad->length > 0) { - for (i = 0; i < scratchpad->length; ++i) { - json_object_array_add(scratchpad_json, ipc_json_describe_container_recursive(scratchpad->items[i])); - } - } - json_object_object_add(object, "scratchpad", scratchpad_json); - } - - return object; -} diff --git a/sway/ipc-server.c b/sway/ipc-server.c deleted file mode 100644 index d4db4e7a..00000000 --- a/sway/ipc-server.c +++ /dev/null @@ -1,845 +0,0 @@ -// See https://i3wm.org/docs/ipc.html for protocol information - -#ifndef __FreeBSD__ -// Any value will hide SOCK_CLOEXEC on FreeBSD (__BSD_VISIBLE=0) -#define _XOPEN_SOURCE 700 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef __linux__ -struct ucred { - pid_t pid; - uid_t uid; - gid_t gid; -}; -#endif -#include "sway/ipc-json.h" -#include "sway/ipc-server.h" -#include "sway/security.h" -#include "sway/config.h" -#include "sway/commands.h" -#include "sway/input.h" -#include "sway/server.h" -#include "stringop.h" -#include "log.h" -#include "list.h" -#include "util.h" - -static int ipc_socket = -1; -static struct wl_event_source *ipc_event_source = NULL; -static struct sockaddr_un *ipc_sockaddr = NULL; -static list_t *ipc_client_list = NULL; - -static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'}; - -struct ipc_client { - struct wl_event_source *event_source; - struct wl_event_source *writable_event_source; - int fd; - uint32_t payload_length; - uint32_t security_policy; - enum ipc_command_type current_command; - enum ipc_command_type subscribed_events; - size_t write_buffer_len; - size_t write_buffer_size; - char *write_buffer; -}; - -static list_t *ipc_get_pixel_requests = NULL; - -struct sockaddr_un *ipc_user_sockaddr(void); -int ipc_handle_connection(int fd, uint32_t mask, void *data); -int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data); -int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data); -void ipc_client_disconnect(struct ipc_client *client); -void ipc_client_handle_command(struct ipc_client *client); -bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length); -void ipc_get_workspaces_callback(swayc_t *workspace, void *data); -void ipc_get_outputs_callback(swayc_t *container, void *data); -static void ipc_get_marks_callback(swayc_t *container, void *data); - -void ipc_init(void) { - ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); - if (ipc_socket == -1) { - sway_abort("Unable to create IPC socket"); - } - - ipc_sockaddr = ipc_user_sockaddr(); - - // We want to use socket name set by user, not existing socket from another sway instance. - if (getenv("SWAYSOCK") != NULL && access(getenv("SWAYSOCK"), F_OK) == -1) { - strncpy(ipc_sockaddr->sun_path, getenv("SWAYSOCK"), sizeof(ipc_sockaddr->sun_path)); - ipc_sockaddr->sun_path[sizeof(ipc_sockaddr->sun_path) - 1] = 0; - } - - unlink(ipc_sockaddr->sun_path); - if (bind(ipc_socket, (struct sockaddr *)ipc_sockaddr, sizeof(*ipc_sockaddr)) == -1) { - sway_abort("Unable to bind IPC socket"); - } - - if (listen(ipc_socket, 3) == -1) { - sway_abort("Unable to listen on IPC socket"); - } - - // Set i3 IPC socket path so that i3-msg works out of the box - setenv("I3SOCK", ipc_sockaddr->sun_path, 1); - setenv("SWAYSOCK", ipc_sockaddr->sun_path, 1); - - ipc_client_list = create_list(); - ipc_get_pixel_requests = create_list(); - - ipc_event_source = wl_event_loop_add_fd(server.wl_event_loop, ipc_socket, - WL_EVENT_READABLE, ipc_handle_connection, NULL); -} - -void ipc_terminate(void) { - if (ipc_event_source) { - wl_event_source_remove(ipc_event_source); - } - close(ipc_socket); - unlink(ipc_sockaddr->sun_path); - - list_free(ipc_client_list); - - if (ipc_sockaddr) { - free(ipc_sockaddr); - } -} - -struct sockaddr_un *ipc_user_sockaddr(void) { - struct sockaddr_un *ipc_sockaddr = malloc(sizeof(struct sockaddr_un)); - if (ipc_sockaddr == NULL) { - sway_abort("Can't allocate ipc_sockaddr"); - } - - ipc_sockaddr->sun_family = AF_UNIX; - int path_size = sizeof(ipc_sockaddr->sun_path); - - // Env var typically set by logind, e.g. "/run/user/" - const char *dir = getenv("XDG_RUNTIME_DIR"); - if (!dir) { - dir = "/tmp"; - } - if (path_size <= snprintf(ipc_sockaddr->sun_path, path_size, - "%s/sway-ipc.%i.%i.sock", dir, getuid(), getpid())) { - sway_abort("Socket path won't fit into ipc_sockaddr->sun_path"); - } - - return ipc_sockaddr; -} - -static pid_t get_client_pid(int client_fd) { -// FreeBSD supports getting uid/gid, but not pid -#ifdef __linux__ - struct ucred ucred; - socklen_t len = sizeof(struct ucred); - - if (getsockopt(client_fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1) { - return -1; - } - - return ucred.pid; -#else - return -1; -#endif -} - -int ipc_handle_connection(int fd, uint32_t mask, void *data) { - (void) fd; (void) data; - sway_log(L_DEBUG, "Event on IPC listening socket"); - assert(mask == WL_EVENT_READABLE); - - int client_fd = accept(ipc_socket, NULL, NULL); - if (client_fd == -1) { - sway_log_errno(L_ERROR, "Unable to accept IPC client connection"); - return 0; - } - - int flags; - if ((flags = fcntl(client_fd, F_GETFD)) == -1 - || fcntl(client_fd, F_SETFD, flags|FD_CLOEXEC) == -1) { - sway_log_errno(L_ERROR, "Unable to set CLOEXEC on IPC client socket"); - close(client_fd); - return 0; - } - if ((flags = fcntl(client_fd, F_GETFL)) == -1 - || fcntl(client_fd, F_SETFL, flags|O_NONBLOCK) == -1) { - sway_log_errno(L_ERROR, "Unable to set NONBLOCK on IPC client socket"); - close(client_fd); - return 0; - } - - struct ipc_client* client = malloc(sizeof(struct ipc_client)); - if (!client) { - sway_log(L_ERROR, "Unable to allocate ipc client"); - close(client_fd); - return 0; - } - client->payload_length = 0; - client->fd = client_fd; - client->subscribed_events = 0; - client->event_source = wl_event_loop_add_fd(server.wl_event_loop, client_fd, - WL_EVENT_READABLE, ipc_client_handle_readable, client); - client->writable_event_source = NULL; - - client->write_buffer_size = 128; - client->write_buffer_len = 0; - client->write_buffer = malloc(client->write_buffer_size); - if (!client->write_buffer) { - sway_log(L_ERROR, "Unable to allocate ipc client write buffer"); - close(client_fd); - return 0; - } - - pid_t pid = get_client_pid(client->fd); - client->security_policy = get_ipc_policy_mask(pid); - - sway_log(L_DEBUG, "New client: fd %d, pid %d", client_fd, pid); - - list_add(ipc_client_list, client); - - return 0; -} - -static const int ipc_header_size = sizeof(ipc_magic)+8; - -int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) { - struct ipc_client *client = data; - - if (mask & WL_EVENT_ERROR) { - sway_log(L_ERROR, "IPC Client socket error, removing client"); - ipc_client_disconnect(client); - return 0; - } - - if (mask & WL_EVENT_HANGUP) { - sway_log(L_DEBUG, "Client %d hung up", client->fd); - ipc_client_disconnect(client); - return 0; - } - - sway_log(L_DEBUG, "Client %d readable", client->fd); - - int read_available; - if (ioctl(client_fd, FIONREAD, &read_available) == -1) { - sway_log_errno(L_INFO, "Unable to read IPC socket buffer size"); - ipc_client_disconnect(client); - return 0; - } - - // Wait for the rest of the command payload in case the header has already been read - if (client->payload_length > 0) { - if ((uint32_t)read_available >= client->payload_length) { - ipc_client_handle_command(client); - } - return 0; - } - - if (read_available < ipc_header_size) { - return 0; - } - - uint8_t buf[ipc_header_size]; - uint32_t *buf32 = (uint32_t*)(buf + sizeof(ipc_magic)); - // Should be fully available, because read_available >= ipc_header_size - ssize_t received = recv(client_fd, buf, ipc_header_size, 0); - if (received == -1) { - sway_log_errno(L_INFO, "Unable to receive header from IPC client"); - ipc_client_disconnect(client); - return 0; - } - - if (memcmp(buf, ipc_magic, sizeof(ipc_magic)) != 0) { - sway_log(L_DEBUG, "IPC header check failed"); - ipc_client_disconnect(client); - return 0; - } - - client->payload_length = buf32[0]; - client->current_command = (enum ipc_command_type)buf32[1]; - - if (read_available - received >= (long)client->payload_length) { - ipc_client_handle_command(client); - } - - return 0; -} - -int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) { - struct ipc_client *client = data; - - if (mask & WL_EVENT_ERROR) { - sway_log(L_ERROR, "IPC Client socket error, removing client"); - ipc_client_disconnect(client); - return 0; - } - - if (mask & WL_EVENT_HANGUP) { - sway_log(L_DEBUG, "Client %d hung up", client->fd); - ipc_client_disconnect(client); - return 0; - } - - if (client->write_buffer_len <= 0) { - return 0; - } - - sway_log(L_DEBUG, "Client %d writable", client->fd); - - ssize_t written = write(client->fd, client->write_buffer, client->write_buffer_len); - - if (written == -1 && errno == EAGAIN) { - return 0; - } else if (written == -1) { - sway_log_errno(L_INFO, "Unable to send data from queue to IPC client"); - ipc_client_disconnect(client); - return 0; - } - - memmove(client->write_buffer, client->write_buffer + written, client->write_buffer_len - written); - client->write_buffer_len -= written; - - if (client->write_buffer_len == 0 && client->writable_event_source) { - wl_event_source_remove(client->writable_event_source); - client->writable_event_source = NULL; - } - - return 0; -} - -void ipc_client_disconnect(struct ipc_client *client) { - if (!sway_assert(client != NULL, "client != NULL")) { - return; - } - - if (client->fd != -1) { - shutdown(client->fd, SHUT_RDWR); - } - - sway_log(L_INFO, "IPC Client %d disconnected", client->fd); - wl_event_source_remove(client->event_source); - if (client->writable_event_source) { - wl_event_source_remove(client->writable_event_source); - } - int i = 0; - while (i < ipc_client_list->length && ipc_client_list->items[i] != client) i++; - list_del(ipc_client_list, i); - free(client->write_buffer); - close(client->fd); - free(client); -} - -bool output_by_name_test(swayc_t *view, void *data) { - char *name = (char *)data; - if (view->type != C_OUTPUT) { - return false; - } - return !strcmp(name, view->name); -} - -// greedy wildcard (only "*") matching -bool mime_type_matches(const char *mime_type, const char *pattern) { - const char *wildcard = NULL; - while (*mime_type && *pattern) { - if (*pattern == '*' && !wildcard) { - wildcard = pattern; - ++pattern; - } - - if (*mime_type != *pattern) { - if (!wildcard) - return false; - - pattern = wildcard; - ++mime_type; - continue; - } - - ++mime_type; - ++pattern; - } - - while (*pattern == '*') { - ++pattern; - } - - return (*mime_type == *pattern); -} - -void ipc_client_handle_command(struct ipc_client *client) { - if (!sway_assert(client != NULL, "client != NULL")) { - return; - } - - char *buf = malloc(client->payload_length + 1); - if (!buf) { - sway_log_errno(L_INFO, "Unable to allocate IPC payload"); - ipc_client_disconnect(client); - return; - } - if (client->payload_length > 0) { - // Payload should be fully available - ssize_t received = recv(client->fd, buf, client->payload_length, 0); - if (received == -1) - { - sway_log_errno(L_INFO, "Unable to receive payload from IPC client"); - ipc_client_disconnect(client); - free(buf); - return; - } - } - buf[client->payload_length] = '\0'; - - const char *error_denied = "{ \"success\": false, \"error\": \"Permission denied\" }"; - - switch (client->current_command) { - case IPC_COMMAND: - { - if (!(client->security_policy & IPC_FEATURE_COMMAND)) { - goto exit_denied; - } - struct cmd_results *results = handle_command(buf, CONTEXT_IPC); - const char *json = cmd_results_to_json(results); - char reply[256]; - int length = snprintf(reply, sizeof(reply), "%s", json); - ipc_send_reply(client, reply, (uint32_t) length); - free_cmd_results(results); - goto exit_cleanup; - } - - case IPC_SUBSCRIBE: - { - // TODO: Check if they're permitted to use these events - struct json_object *request = json_tokener_parse(buf); - if (request == NULL) { - ipc_send_reply(client, "{\"success\": false}", 18); - sway_log_errno(L_INFO, "Failed to read request"); - goto exit_cleanup; - } - - // parse requested event types - for (int i = 0; i < json_object_array_length(request); i++) { - const char *event_type = json_object_get_string(json_object_array_get_idx(request, i)); - if (strcmp(event_type, "workspace") == 0) { - client->subscribed_events |= event_mask(IPC_EVENT_WORKSPACE); - } else if (strcmp(event_type, "barconfig_update") == 0) { - client->subscribed_events |= event_mask(IPC_EVENT_BARCONFIG_UPDATE); - } else if (strcmp(event_type, "mode") == 0) { - client->subscribed_events |= event_mask(IPC_EVENT_MODE); - } else if (strcmp(event_type, "window") == 0) { - client->subscribed_events |= event_mask(IPC_EVENT_WINDOW); - } else if (strcmp(event_type, "modifier") == 0) { - client->subscribed_events |= event_mask(IPC_EVENT_MODIFIER); - } else if (strcmp(event_type, "binding") == 0) { - client->subscribed_events |= event_mask(IPC_EVENT_BINDING); - } else { - ipc_send_reply(client, "{\"success\": false}", 18); - json_object_put(request); - sway_log_errno(L_INFO, "Failed to parse request"); - goto exit_cleanup; - } - } - - json_object_put(request); - - ipc_send_reply(client, "{\"success\": true}", 17); - goto exit_cleanup; - } - - case IPC_GET_WORKSPACES: - { - if (!(client->security_policy & IPC_FEATURE_GET_WORKSPACES)) { - goto exit_denied; - } - json_object *workspaces = json_object_new_array(); - container_map(&root_container, ipc_get_workspaces_callback, workspaces); - const char *json_string = json_object_to_json_string(workspaces); - ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); - json_object_put(workspaces); // free - goto exit_cleanup; - } - - case IPC_GET_INPUTS: - { - if (!(client->security_policy & IPC_FEATURE_GET_INPUTS)) { - goto exit_denied; - } - json_object *inputs = json_object_new_array(); - /* TODO WLR - if (input_devices) { - for(int i = 0; ilength; i++) { - struct libinput_device *device = input_devices->items[i]; - json_object_array_add(inputs, ipc_json_describe_input(device)); - } - } - */ - const char *json_string = json_object_to_json_string(inputs); - ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); - json_object_put(inputs); - goto exit_cleanup; - } - - case IPC_GET_OUTPUTS: - { - if (!(client->security_policy & IPC_FEATURE_GET_OUTPUTS)) { - goto exit_denied; - } - json_object *outputs = json_object_new_array(); - container_map(&root_container, ipc_get_outputs_callback, outputs); - const char *json_string = json_object_to_json_string(outputs); - ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); - json_object_put(outputs); // free - goto exit_cleanup; - } - - case IPC_GET_TREE: - { - if (!(client->security_policy & IPC_FEATURE_GET_TREE)) { - goto exit_denied; - } - json_object *tree = ipc_json_describe_container_recursive(&root_container); - const char *json_string = json_object_to_json_string(tree); - ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); - json_object_put(tree); - goto exit_cleanup; - } - - case IPC_GET_MARKS: - { - if (!(client->security_policy & IPC_FEATURE_GET_MARKS)) { - goto exit_denied; - } - json_object *marks = json_object_new_array(); - container_map(&root_container, ipc_get_marks_callback, marks); - const char *json_string = json_object_to_json_string(marks); - ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); - json_object_put(marks); - goto exit_cleanup; - } - - case IPC_GET_VERSION: - { - json_object *version = ipc_json_get_version(); - const char *json_string = json_object_to_json_string(version); - ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); - json_object_put(version); // free - goto exit_cleanup; - } - - case IPC_GET_BAR_CONFIG: - { - if (!(client->security_policy & IPC_FEATURE_GET_BAR_CONFIG)) { - goto exit_denied; - } - if (!buf[0]) { - // Send list of configured bar IDs - json_object *bars = json_object_new_array(); - int i; - for (i = 0; i < config->bars->length; ++i) { - struct bar_config *bar = config->bars->items[i]; - json_object_array_add(bars, json_object_new_string(bar->id)); - } - const char *json_string = json_object_to_json_string(bars); - ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); - json_object_put(bars); // free - } else { - // Send particular bar's details - struct bar_config *bar = NULL; - int i; - for (i = 0; i < config->bars->length; ++i) { - bar = config->bars->items[i]; - if (strcmp(buf, bar->id) == 0) { - break; - } - bar = NULL; - } - if (!bar) { - const char *error = "{ \"success\": false, \"error\": \"No bar with that ID\" }"; - ipc_send_reply(client, error, (uint32_t)strlen(error)); - goto exit_cleanup; - } - json_object *json = ipc_json_describe_bar_config(bar); - const char *json_string = json_object_to_json_string(json); - ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); - json_object_put(json); // free - } - goto exit_cleanup; - } - - case IPC_GET_CLIPBOARD: - // TODO WLR - break; - - default: - sway_log(L_INFO, "Unknown IPC command type %i", client->current_command); - goto exit_cleanup; - } - -exit_denied: - ipc_send_reply(client, error_denied, (uint32_t)strlen(error_denied)); - sway_log(L_DEBUG, "Denied IPC client access to %i", client->current_command); - -exit_cleanup: - client->payload_length = 0; - free(buf); - return; -} - -bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length) { - assert(payload); - - char data[ipc_header_size]; - uint32_t *data32 = (uint32_t*)(data + sizeof(ipc_magic)); - - memcpy(data, ipc_magic, sizeof(ipc_magic)); - data32[0] = payload_length; - data32[1] = client->current_command; - - while (client->write_buffer_len + ipc_header_size + payload_length >= - client->write_buffer_size) { - client->write_buffer_size *= 2; - } - - // TODO: reduce the limit back to 4 MB when screenshooter is implemented - if (client->write_buffer_size > (1 << 28)) { // 256 MB - sway_log(L_ERROR, "Client write buffer too big, disconnecting client"); - ipc_client_disconnect(client); - return false; - } - - char *new_buffer = realloc(client->write_buffer, client->write_buffer_size); - if (!new_buffer) { - sway_log(L_ERROR, "Unable to reallocate ipc client write buffer"); - ipc_client_disconnect(client); - return false; - } - client->write_buffer = new_buffer; - - memcpy(client->write_buffer + client->write_buffer_len, data, ipc_header_size); - client->write_buffer_len += ipc_header_size; - memcpy(client->write_buffer + client->write_buffer_len, payload, payload_length); - client->write_buffer_len += payload_length; - - if (!client->writable_event_source) { - client->writable_event_source = wl_event_loop_add_fd( - server.wl_event_loop, client->fd, WL_EVENT_WRITABLE, - ipc_client_handle_writable, client); - } - - sway_log(L_DEBUG, "Added IPC reply to client %d queue: %s", client->fd, payload); - - return true; -} - -void ipc_get_workspaces_callback(swayc_t *workspace, void *data) { - if (workspace->type == C_WORKSPACE) { - json_object *workspace_json = ipc_json_describe_container(workspace); - // override the default focused indicator because - // it's set differently for the get_workspaces reply - bool focused = root_container.focused == workspace->parent && workspace->parent->focused == workspace; - json_object_object_del(workspace_json, "focused"); - json_object_object_add(workspace_json, "focused", json_object_new_boolean(focused)); - json_object_array_add((json_object *)data, workspace_json); - } -} - -void ipc_get_outputs_callback(swayc_t *container, void *data) { - if (container->type == C_OUTPUT) { - json_object_array_add((json_object *)data, ipc_json_describe_container(container)); - } -} - -static void ipc_get_marks_callback(swayc_t *container, void *data) { - json_object *object = (json_object *)data; - if (container->marks) { - for (int i = 0; i < container->marks->length; ++i) { - char *mark = (char *)container->marks->items[i]; - json_object_array_add(object, json_object_new_string(mark)); - } - } -} - -void ipc_send_event(const char *json_string, enum ipc_command_type event) { - static struct { - enum ipc_command_type event; - enum ipc_feature feature; - } security_mappings[] = { - { IPC_EVENT_WORKSPACE, IPC_FEATURE_EVENT_WORKSPACE }, - { IPC_EVENT_OUTPUT, IPC_FEATURE_EVENT_OUTPUT }, - { IPC_EVENT_MODE, IPC_FEATURE_EVENT_MODE }, - { IPC_EVENT_WINDOW, IPC_FEATURE_EVENT_WINDOW }, - { IPC_EVENT_BINDING, IPC_FEATURE_EVENT_BINDING }, - { IPC_EVENT_INPUT, IPC_FEATURE_EVENT_INPUT } - }; - - uint32_t security_mask = 0; - for (size_t i = 0; i < sizeof(security_mappings) / sizeof(security_mappings[0]); ++i) { - if (security_mappings[i].event == event) { - security_mask = security_mappings[i].feature; - break; - } - } - - int i; - struct ipc_client *client; - for (i = 0; i < ipc_client_list->length; i++) { - client = ipc_client_list->items[i]; - if (!(client->security_policy & security_mask)) { - continue; - } - if ((client->subscribed_events & event_mask(event)) == 0) { - continue; - } - client->current_command = event; - if (!ipc_send_reply(client, json_string, (uint32_t) strlen(json_string))) { - sway_log_errno(L_INFO, "Unable to send reply to IPC client"); - ipc_client_disconnect(client); - } - } -} - -void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change) { - sway_log(L_DEBUG, "Sending workspace::%s event", change); - json_object *obj = json_object_new_object(); - json_object_object_add(obj, "change", json_object_new_string(change)); - if (strcmp("focus", change) == 0) { - if (old) { - json_object_object_add(obj, "old", ipc_json_describe_container_recursive(old)); - } else { - json_object_object_add(obj, "old", NULL); - } - } - - if (new) { - json_object_object_add(obj, "current", ipc_json_describe_container_recursive(new)); - } else { - json_object_object_add(obj, "current", NULL); - } - - const char *json_string = json_object_to_json_string(obj); - ipc_send_event(json_string, IPC_EVENT_WORKSPACE); - - json_object_put(obj); // free -} - -void ipc_event_window(swayc_t *window, const char *change) { - sway_log(L_DEBUG, "Sending window::%s event", change); - json_object *obj = json_object_new_object(); - json_object_object_add(obj, "change", json_object_new_string(change)); - json_object_object_add(obj, "container", ipc_json_describe_container_recursive(window)); - - const char *json_string = json_object_to_json_string(obj); - ipc_send_event(json_string, IPC_EVENT_WINDOW); - - json_object_put(obj); // free -} - -void ipc_event_barconfig_update(struct bar_config *bar) { - sway_log(L_DEBUG, "Sending barconfig_update event"); - json_object *json = ipc_json_describe_bar_config(bar); - const char *json_string = json_object_to_json_string(json); - ipc_send_event(json_string, IPC_EVENT_BARCONFIG_UPDATE); - - json_object_put(json); // free -} - -void ipc_event_mode(const char *mode) { - sway_log(L_DEBUG, "Sending mode::%s event", mode); - json_object *obj = json_object_new_object(); - json_object_object_add(obj, "change", json_object_new_string(mode)); - - const char *json_string = json_object_to_json_string(obj); - ipc_send_event(json_string, IPC_EVENT_MODE); - - json_object_put(obj); // free -} - -void ipc_event_modifier(uint32_t modifier, const char *state) { - sway_log(L_DEBUG, "Sending modifier::%s event", state); - json_object *obj = json_object_new_object(); - json_object_object_add(obj, "change", json_object_new_string(state)); - - const char *modifier_name = get_modifier_name_by_mask(modifier); - json_object_object_add(obj, "modifier", json_object_new_string(modifier_name)); - - const char *json_string = json_object_to_json_string(obj); - ipc_send_event(json_string, IPC_EVENT_MODIFIER); - - json_object_put(obj); // free -} - -static void ipc_event_binding(json_object *sb_obj) { - sway_log(L_DEBUG, "Sending binding::run event"); - json_object *obj = json_object_new_object(); - json_object_object_add(obj, "change", json_object_new_string("run")); - json_object_object_add(obj, "binding", sb_obj); - - const char *json_string = json_object_to_json_string(obj); - ipc_send_event(json_string, IPC_EVENT_BINDING); - - json_object_put(obj); // free -} - -void ipc_event_binding_keyboard(struct sway_binding *sb) { - json_object *sb_obj = json_object_new_object(); - json_object_object_add(sb_obj, "command", json_object_new_string(sb->command)); - - const char *names[10]; - - int len = get_modifier_names(names, sb->modifiers); - int i; - json_object *modifiers = json_object_new_array(); - for (i = 0; i < len; ++i) { - json_object_array_add(modifiers, json_object_new_string(names[i])); - } - - json_object_object_add(sb_obj, "event_state_mask", modifiers); - - json_object *input_codes = json_object_new_array(); - int input_code = 0; - json_object *symbols = json_object_new_array(); - json_object *symbol = NULL; - - if (sb->bindcode) { // bindcode: populate input_codes - uint32_t keycode; - for (i = 0; i < sb->keys->length; ++i) { - keycode = *(uint32_t *)sb->keys->items[i]; - json_object_array_add(input_codes, json_object_new_int(keycode)); - if (i == 0) { - input_code = keycode; - } - } - } else { // bindsym: populate symbols - uint32_t keysym; - char buffer[64]; - for (i = 0; i < sb->keys->length; ++i) { - keysym = *(uint32_t *)sb->keys->items[i]; - if (xkb_keysym_get_name(keysym, buffer, 64) > 0) { - json_object *str = json_object_new_string(buffer); - json_object_array_add(symbols, str); - if (i == 0) { - symbol = str; - } - } - } - } - - json_object_object_add(sb_obj, "input_codes", input_codes); - json_object_object_add(sb_obj, "input_code", json_object_new_int(input_code)); - json_object_object_add(sb_obj, "symbols", symbols); - json_object_object_add(sb_obj, "symbol", symbol); - json_object_object_add(sb_obj, "input_type", json_object_new_string("keyboard")); - - ipc_event_binding(sb_obj); -} diff --git a/sway/main.c b/sway/main.c index 7d6f2873..5710a099 100644 --- a/sway/main.c +++ b/sway/main.c @@ -1,30 +1,24 @@ #define _XOPEN_SOURCE 700 #define _POSIX_C_SOURCE 200112L -#include -#include +#include +#include #include -#include -#include +#include +#include +#include #include +#include +#include #include -#include #include -#include #ifdef __linux__ #include #include #endif -#include "sway/layout.h" -#include "sway/config.h" -#include "sway/security.h" -#include "sway/handlers.h" -#include "sway/input.h" -#include "sway/ipc-server.h" #include "sway/server.h" #include "ipc-client.h" #include "readline.h" #include "stringop.h" -#include "sway.h" #include "log.h" #include "util.h" @@ -39,7 +33,7 @@ void sway_terminate(int exit_code) { } void sig_handler(int signal) { - close_views(&root_container); + //close_views(&root_container); sway_terminate(EXIT_SUCCESS); } @@ -442,17 +436,17 @@ int main(int argc, char **argv) { return 1; } - init_layout(); - ipc_init(); + //init_layout(); + //ipc_init(); - if (validate) { - bool valid = load_main_config(config_path, false); - return valid ? 0 : 1; - } + //if (validate) { + // bool valid = load_main_config(config_path, false); + // return valid ? 0 : 1; + //} - if (!load_main_config(config_path, false)) { - sway_terminate(EXIT_FAILURE); - } + //if (!load_main_config(config_path, false)) { + // sway_terminate(EXIT_FAILURE); + //} if (config_path) { free(config_path); @@ -466,11 +460,11 @@ int main(int argc, char **argv) { server_fini(&server); - ipc_terminate(); + //ipc_terminate(); - if (config) { - free_config(config); - } + //if (config) { + // free_config(config); + //} return exit_value; } diff --git a/sway/old/border.c b/sway/old/border.c new file mode 100644 index 00000000..df0022ce --- /dev/null +++ b/sway/old/border.c @@ -0,0 +1,510 @@ +#define _XOPEN_SOURCE 700 +#include +#include +#include +#include +#include +#include +#include +#include +#include "sway/border.h" +#include "sway/container.h" +#include "sway/config.h" +#include "client/pango.h" + +void cairo_set_source_u32(cairo_t *cairo, uint32_t color) { + color = htonl(color); + + cairo_set_source_rgba(cairo, + (color >> (2*8) & 0xFF) / 255.0, + (color >> (1*8) & 0xFF) / 255.0, + (color >> (0*8) & 0xFF) / 255.0, + (color >> (3*8) & 0xFF) / 255.0); +} + +void border_clear(struct border *border) { + if (border && border->buffer) { + free(border->buffer); + border->buffer = NULL; + } +} + +static cairo_t *create_border_buffer(swayc_t *view, struct wlc_geometry g, cairo_surface_t **surface) { + if (view->border == NULL) { + view->border = malloc(sizeof(struct border)); + if (!view->border) { + sway_log(L_ERROR, "Unable to allocate window border information"); + return NULL; + } + } + cairo_t *cr; + int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, g.size.w); + view->border->buffer = calloc(stride * g.size.h, sizeof(unsigned char)); + view->border->geometry = g; + if (!view->border->buffer) { + sway_log(L_ERROR, "Unable to allocate window border buffer"); + return NULL; + } + *surface = cairo_image_surface_create_for_data(view->border->buffer, + CAIRO_FORMAT_ARGB32, g.size.w, g.size.h, stride); + if (cairo_surface_status(*surface) != CAIRO_STATUS_SUCCESS) { + border_clear(view->border); + sway_log(L_ERROR, "Unable to allocate window border surface"); + return NULL; + } + cr = cairo_create(*surface); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + if (cairo_status(cr) != CAIRO_STATUS_SUCCESS) { + cairo_surface_destroy(*surface); + border_clear(view->border); + sway_log(L_ERROR, "Unable to create cairo context"); + return NULL; + } + return cr; +} + +// TODO: move to client/cairo.h when local set_source_u32 is fixed. +/** + * Renders a sharp line of any width and height. + * + * The line is drawn from (x,y) to (x+width,y+height) where width/height is 0 + * if the line has a width/height of one pixel, respectively. + */ +static void render_sharp_line(cairo_t *cairo, uint32_t color, double x, double y, double width, double height) { + cairo_set_source_u32(cairo, color); + + if (width > 1 && height > 1) { + cairo_rectangle(cairo, x, y, width, height); + cairo_fill(cairo); + } else { + if (width == 1) { + x += 0.5; + height += y; + width = x; + } + + if (height == 1) { + y += 0.5; + width += x; + height = y; + } + + cairo_move_to(cairo, x, y); + cairo_set_line_width(cairo, 1.0); + cairo_line_to(cairo, width, height); + cairo_stroke(cairo); + } +} + +int get_font_text_height(const char *font) { + cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 200, 200); + cairo_t *cr = cairo_create(surface); + int width, height; + get_text_size(cr, font, &width, &height, 1, false, "Gg"); + cairo_surface_destroy(surface); + cairo_destroy(cr); + return height; +} + +static void render_borders(swayc_t *view, cairo_t *cr, struct border_colors *colors, bool top) { + struct wlc_geometry *g = &view->border->geometry; + struct wlc_geometry *b = &view->border_geometry; + struct wlc_geometry *v = &view->actual_geometry; + enum swayc_layouts layout = view->parent->layout; + uint32_t color; + + int x = b->origin.x - g->origin.x; + int y = b->origin.y - g->origin.y; + + // draw vertical/horizontal indicator if container is the only child of its parent container + bool is_only_child = view->parent && view->parent->children && view->parent->children->length == 1; + + // left border + int left_border = v->origin.x - b->origin.x; + if (left_border > 0) { + render_sharp_line(cr, + colors->child_border, + x, y, + left_border, + b->size.h); + } + + // right border + int right_border = b->size.w - v->size.w - left_border; + if (right_border > 0) { + if (is_only_child && layout == L_HORIZ && !view->is_floating) { + color = colors->indicator; + } else { + color = colors->child_border; + } + render_sharp_line(cr, + color, + x + b->size.w - right_border, + y, + right_border, + b->size.h); + } + + // top border + int top_border = v->origin.y - b->origin.y; + if (top && top_border > 0) { + render_sharp_line(cr, + colors->child_border, + x, y, + b->size.w, + top_border); + } + + // bottom border + int bottom_border = b->size.h - (top_border + v->size.h); + if (bottom_border > 0) { + if (is_only_child && layout == L_VERT && !view->is_floating) { + color = colors->indicator; + } else { + color = colors->child_border; + } + render_sharp_line(cr, + color, + x, + y + b->size.h - bottom_border, + b->size.w, + bottom_border); + } +} + +static void render_title_bar(swayc_t *view, cairo_t *cr, struct wlc_geometry *b, struct border_colors *colors) { + struct wlc_geometry *tb = &view->title_bar_geometry; + int x = MIN(tb->origin.x, tb->origin.x - b->origin.x); + int y = MIN(tb->origin.y, tb->origin.y - b->origin.y); + + // title bar background + cairo_set_source_u32(cr, colors->background); + cairo_rectangle(cr, x, y, tb->size.w, tb->size.h); + cairo_fill(cr); + + // header top line + render_sharp_line(cr, colors->border, x, y, tb->size.w, 1); + + // text + if (view->name) { + int width, height; + get_text_size(cr, config->font, &width, &height, 1, false, "%s", view->name); + cairo_move_to(cr, x + 2, y + 2); + cairo_set_source_u32(cr, colors->text); + pango_printf(cr, config->font, 1, false, "%s", view->name); + } + // Marks + if (config->show_marks && view->marks) { + int total_len = 0; + + for(int i = view->marks->length - 1; i >= 0; --i) { + char *mark = (char *)view->marks->items[i]; + if (*mark != '_') { + int width, height; + get_text_size(cr, config->font, &width, &height, 1, false, "[%s]", mark); + total_len += width; + if ((int)tb->size.w + x - (total_len + 2) < x + 2) { + break; + } else { + cairo_move_to(cr, (int)tb->size.w + x - (total_len + 2), y + 2); + cairo_set_source_u32(cr, colors->text); + pango_printf(cr, config->font, 1, false, "[%s]", mark); + } + } + } + } + + // titlebars has a border all around for tabbed layouts + if (view->parent->layout == L_TABBED) { + // header bottom line + render_sharp_line(cr, colors->border, x, y + tb->size.h - 1, + tb->size.w, 1); + + // left border + render_sharp_line(cr, colors->border, x, y, 1, tb->size.h); + + // right border + render_sharp_line(cr, colors->border, x + tb->size.w - 1, y, + 1, tb->size.h); + + return; + } + + if ((uint32_t)(view->actual_geometry.origin.y - tb->origin.y) == tb->size.h) { + // header bottom line + render_sharp_line(cr, colors->border, + x + view->actual_geometry.origin.x - tb->origin.x, + y + tb->size.h - 1, + view->actual_geometry.size.w, 1); + } else { + // header bottom line + render_sharp_line(cr, colors->border, x, + y + tb->size.h - 1, + tb->size.w, 1); + } +} + +/** + * Generate nested container title for tabbed/stacked layouts + */ +static char *generate_container_title(swayc_t *container) { + char layout = 'H'; + char *name, *prev_name = NULL; + switch (container->layout) { + case L_TABBED: + layout = 'T'; + break; + case L_STACKED: + layout = 'S'; + break; + case L_VERT: + layout = 'V'; + break; + default: + layout = 'H'; + } + int len = 9; + name = malloc(len * sizeof(char)); + if (!name) { + sway_log(L_ERROR, "Unable to allocate container title"); + return NULL; + } + snprintf(name, len, "sway: %c[", layout); + + int i; + for (i = 0; i < container->children->length; ++i) { + prev_name = name; + swayc_t* child = container->children->items[i]; + const char *title = NULL; + if (child->type == C_VIEW) { + title = child->app_id ? child->app_id : + (child->instance ? child->instance : + (child->class ? child->class :"(null)")); + } else { //child->type == C_CONTAINER + title = generate_container_title(child); + } + + len = strlen(name) + strlen(title) + 1; + if (i < container->children->length-1) { + len++; + } + + name = malloc(len * sizeof(char)); + if (!name) { + free(prev_name); + sway_log(L_ERROR, "Unable to allocate container title"); + return NULL; + } + if (i < container->children->length-1) { + snprintf(name, len, "%s%s ", prev_name, title); + } else { + snprintf(name, len, "%s%s", prev_name, title); + } + free(prev_name); + } + + prev_name = name; + len = strlen(name) + 2; + name = malloc(len * sizeof(char)); + if (!name) { + free(prev_name); + sway_log(L_ERROR, "Unable to allocate container title"); + return NULL; + } + snprintf(name, len, "%s]", prev_name); + free(prev_name); + free(container->name); + container->name = name; + return container->name + 6; // don't include "sway: " +} + +void update_tabbed_stacked_titlebars(swayc_t *c, cairo_t *cr, struct wlc_geometry *g, swayc_t *focused, swayc_t *focused_inactive) { + if (c->type == C_CONTAINER) { + if (c->parent->focused == c) { + render_title_bar(c, cr, g, &config->border_colors.focused_inactive); + } else { + render_title_bar(c, cr, g, &config->border_colors.unfocused); + } + + if (!c->visible) { + return; + } + + int i; + for (i = 0; i < c->children->length; ++i) { + swayc_t *child = c->children->items[i]; + update_tabbed_stacked_titlebars(child, cr, g, focused, focused_inactive); + } + } else { + bool is_child_of_focused = swayc_is_child_of(c, get_focused_container(&root_container)); + + if (focused == c || is_child_of_focused) { + render_title_bar(c, cr, g, &config->border_colors.focused); + } else if (focused_inactive == c) { + render_title_bar(c, cr, g, &config->border_colors.focused_inactive); + } else { + render_title_bar(c, cr, g, &config->border_colors.unfocused); + } + } +} + +static void update_view_border(swayc_t *view) { + if (!view->visible) { + return; + } + + cairo_t *cr = NULL; + cairo_surface_t *surface = NULL; + + // clear previous border buffer. + border_clear(view->border); + + // get focused and focused_inactive views + swayc_t *focused = get_focused_view(&root_container); + swayc_t *container = swayc_parent_by_type(view, C_CONTAINER); + swayc_t *focused_inactive = NULL; + + bool is_child_of_focused = swayc_is_parent_of(get_focused_container(&root_container), view); + + if (container) { + focused_inactive = swayc_focus_by_type(container, C_VIEW); + } else { + container = swayc_parent_by_type(view, C_WORKSPACE); + if (container) { + focused_inactive = swayc_focus_by_type(container, C_VIEW); + } + } + + // for tabbed/stacked layouts the focused view has to draw all the + // titlebars of the hidden views. + swayc_t *p = NULL; + if (view->parent->focused == view && (p = swayc_tabbed_stacked_ancestor(view))) { + struct wlc_geometry g = { + .origin = { + .x = p->x, + .y = p->y + }, + .size = { + .w = p->width, + .h = p->height + } + }; + cr = create_border_buffer(view, g, &surface); + if (!cr) { + goto cleanup; + } + + bool render_top = !should_hide_top_border(view, view->y); + if (view == focused || is_child_of_focused) { + render_borders(view, cr, &config->border_colors.focused, render_top); + } else { + render_borders(view, cr, &config->border_colors.focused_inactive, render_top); + } + + // generate container titles + int i; + for (i = 0; i < p->children->length; ++i) { + swayc_t *child = p->children->items[i]; + if (child->type == C_CONTAINER) { + generate_container_title(child); + } + } + + update_tabbed_stacked_titlebars(p, cr, &g, focused, focused_inactive); + } else { + switch (view->border_type) { + case B_NONE: + break; + case B_PIXEL: + cr = create_border_buffer(view, view->border_geometry, &surface); + if (!cr) { + break; + } + + if (focused == view || is_child_of_focused) { + render_borders(view, cr, &config->border_colors.focused, true); + } else if (focused_inactive == view) { + render_borders(view, cr, &config->border_colors.focused_inactive, true); + } else { + render_borders(view, cr, &config->border_colors.unfocused, true); + } + + break; + case B_NORMAL: + cr = create_border_buffer(view, view->border_geometry, &surface); + if (!cr) { + break; + } + + if (focused == view || is_child_of_focused) { + render_borders(view, cr, &config->border_colors.focused, false); + render_title_bar(view, cr, &view->border_geometry, + &config->border_colors.focused); + } else if (focused_inactive == view) { + render_borders(view, cr, &config->border_colors.focused_inactive, false); + render_title_bar(view, cr, &view->border_geometry, + &config->border_colors.focused_inactive); + } else { + render_borders(view, cr, &config->border_colors.unfocused, false); + render_title_bar(view, cr, &view->border_geometry, + &config->border_colors.unfocused); + } + + break; + } + } + +cleanup: + + if (surface) { + cairo_surface_flush(surface); + cairo_surface_destroy(surface); + } + + if (cr) { + cairo_destroy(cr); + } +} + +void update_container_border(swayc_t *container) { + if (container->type == C_VIEW) { + update_view_border(container); + return; + } else { + for (int i = 0; i < container->children->length; ++i) { + update_container_border(container->children->items[i]); + } + } +} + +void render_view_borders(wlc_handle view) { + swayc_t *c = swayc_by_handle(view); + + + // emulate i3 behavior for drawing borders for tabbed and stacked layouts: + // if we are not the only child in the container, always draw borders, + // regardless of the border setting on the individual view + if (!c || (c->border_type == B_NONE + && !((c->parent->layout == L_TABBED || c->parent->layout == L_STACKED) + && c->parent->children->length > 1))) { + return; + } + + if (c->border && c->border->buffer) { + wlc_pixels_write(WLC_RGBA8888, &c->border->geometry, c->border->buffer); + } +} + +bool should_hide_top_border(swayc_t *con, double y) { + // returns true if container is child of tabbed/stacked layout and is + // sharing top border with tabbed titlebar + swayc_t *par = con->parent; + while (par->type != C_WORKSPACE) { + if (par->layout == L_TABBED || par->layout == L_STACKED) { + return con->y == y; + } + con = par; + par = par->parent; + } + return false; +} diff --git a/sway/old/commands.c b/sway/old/commands.c new file mode 100644 index 00000000..e1181893 --- /dev/null +++ b/sway/old/commands.c @@ -0,0 +1,686 @@ +#define _XOPEN_SOURCE 700 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sway/layout.h" +#include "sway/focus.h" +#include "sway/workspace.h" +#include "sway/commands.h" +#include "sway/container.h" +#include "sway/output.h" +#include "sway/handlers.h" +#include "sway/input_state.h" +#include "sway/criteria.h" +#include "sway/ipc-server.h" +#include "sway/security.h" +#include "sway/input.h" +#include "sway/border.h" +#include "stringop.h" +#include "sway.h" +#include "util.h" +#include "list.h" +#include "log.h" + +struct cmd_handler { + char *command; + sway_cmd *handle; +}; + +int sp_index = 0; + +swayc_t *current_container = NULL; + +// Returns error object, or NULL if check succeeds. +struct cmd_results *checkarg(int argc, const char *name, enum expected_args type, int val) { + struct cmd_results *error = NULL; + switch (type) { + case EXPECTED_MORE_THAN: + if (argc > val) { + return NULL; + } + error = cmd_results_new(CMD_INVALID, name, "Invalid %s command " + "(expected more than %d argument%s, got %d)", + name, val, (char*[2]){"s", ""}[argc==1], argc); + break; + case EXPECTED_AT_LEAST: + if (argc >= val) { + return NULL; + } + error = cmd_results_new(CMD_INVALID, name, "Invalid %s command " + "(expected at least %d argument%s, got %d)", + name, val, (char*[2]){"s", ""}[argc==1], argc); + break; + case EXPECTED_LESS_THAN: + if (argc < val) { + return NULL; + }; + error = cmd_results_new(CMD_INVALID, name, "Invalid %s command " + "(expected less than %d argument%s, got %d)", + name, val, (char*[2]){"s", ""}[argc==1], argc); + break; + case EXPECTED_EQUAL_TO: + if (argc == val) { + return NULL; + }; + error = cmd_results_new(CMD_INVALID, name, "Invalid %s command " + "(expected %d arguments, got %d)", name, val, argc); + break; + } + return error; +} + +void hide_view_in_scratchpad(swayc_t *sp_view) { + if (sp_view == NULL) { + return; + } + + wlc_view_set_mask(sp_view->handle, 0); + sp_view->visible = false; + swayc_t *ws = sp_view->parent; + remove_child(sp_view); + if (swayc_active_workspace() != ws && ws->floating->length == 0 && ws->children->length == 0) { + destroy_workspace(ws); + } else { + arrange_windows(ws, -1, -1); + } + set_focused_container(container_under_pointer()); +} + +void input_cmd_apply(struct input_config *input) { + int i; + i = list_seq_find(config->input_configs, input_identifier_cmp, input->identifier); + if (i >= 0) { + // merge existing config + struct input_config *ic = config->input_configs->items[i]; + merge_input_config(ic, input); + free_input_config(input); + input = ic; + } else { + list_add(config->input_configs, input); + } + + current_input_config = input; + + if (input->identifier) { + // Try to find the input device and apply configuration now. If + // this is during startup then there will be no container and config + // will be applied during normal "new input" event from wlc. + /* TODO WLR + struct libinput_device *device = NULL; + for (int i = 0; i < input_devices->length; ++i) { + device = input_devices->items[i]; + char* dev_identifier = libinput_dev_unique_id(device); + if (!dev_identifier) { + break; + } + int match = dev_identifier && strcmp(dev_identifier, input->identifier) == 0; + free(dev_identifier); + if (match) { + apply_input_config(input, device); + break; + } + } + */ + } +} + +void remove_view_from_scratchpad(swayc_t *view) { + int i; + for (i = 0; i < scratchpad->length; i++) { + if (scratchpad->items[i] == view) { + if (sp_index == 0) { + sp_index = scratchpad->length - 1; + } else { + sp_index--; + } + list_del(scratchpad, sp_index); + sp_view = NULL; + } + } +} + +/* Keep alphabetized */ +static struct cmd_handler handlers[] = { + { "assign", cmd_assign }, + { "bar", cmd_bar }, + { "bindcode", cmd_bindcode }, + { "bindsym", cmd_bindsym }, + { "border", cmd_border }, + { "client.background", cmd_client_background }, + { "client.focused", cmd_client_focused }, + { "client.focused_inactive", cmd_client_focused_inactive }, + { "client.placeholder", cmd_client_placeholder }, + { "client.unfocused", cmd_client_unfocused }, + { "client.urgent", cmd_client_urgent }, + { "clipboard", cmd_clipboard }, + { "commands", cmd_commands }, + { "debuglog", cmd_debuglog }, + { "default_border", cmd_default_border }, + { "default_floating_border", cmd_default_floating_border }, + { "default_orientation", cmd_orientation }, + { "exec", cmd_exec }, + { "exec_always", cmd_exec_always }, + { "exit", cmd_exit }, + { "floating", cmd_floating }, + { "floating_maximum_size", cmd_floating_maximum_size }, + { "floating_minimum_size", cmd_floating_minimum_size }, + { "floating_modifier", cmd_floating_mod }, + { "floating_scroll", cmd_floating_scroll }, + { "focus", cmd_focus }, + { "focus_follows_mouse", cmd_focus_follows_mouse }, + { "font", cmd_font }, + { "for_window", cmd_for_window }, + { "force_focus_wrapping", cmd_force_focus_wrapping }, + { "fullscreen", cmd_fullscreen }, + { "gaps", cmd_gaps }, + { "hide_edge_borders", cmd_hide_edge_borders }, + { "include", cmd_include }, + { "input", cmd_input }, + { "ipc", cmd_ipc }, + { "kill", cmd_kill }, + { "layout", cmd_layout }, + { "log_colors", cmd_log_colors }, + { "mark", cmd_mark }, + { "mode", cmd_mode }, + { "mouse_warping", cmd_mouse_warping }, + { "move", cmd_move }, + { "new_float", cmd_new_float }, + { "new_window", cmd_new_window }, + { "no_focus", cmd_no_focus }, + { "output", cmd_output }, + { "permit", cmd_permit }, + { "reject", cmd_reject }, + { "reload", cmd_reload }, + { "resize", cmd_resize }, + { "scratchpad", cmd_scratchpad }, + { "seamless_mouse", cmd_seamless_mouse }, + { "set", cmd_set }, + { "show_marks", cmd_show_marks }, + { "smart_gaps", cmd_smart_gaps }, + { "split", cmd_split }, + { "splith", cmd_splith }, + { "splitt", cmd_splitt }, + { "splitv", cmd_splitv }, + { "sticky", cmd_sticky }, + { "unmark", cmd_unmark }, + { "workspace", cmd_workspace }, + { "workspace_auto_back_and_forth", cmd_ws_auto_back_and_forth }, + { "workspace_layout", cmd_workspace_layout }, +}; + +static struct cmd_handler bar_handlers[] = { + { "activate_button", bar_cmd_activate_button }, + { "binding_mode_indicator", bar_cmd_binding_mode_indicator }, + { "bindsym", bar_cmd_bindsym }, + { "colors", bar_cmd_colors }, + { "context_button", bar_cmd_context_button }, + { "font", bar_cmd_font }, + { "height", bar_cmd_height }, + { "hidden_state", bar_cmd_hidden_state }, + { "icon_theme", bar_cmd_icon_theme }, + { "id", bar_cmd_id }, + { "mode", bar_cmd_mode }, + { "modifier", bar_cmd_modifier }, + { "output", bar_cmd_output }, + { "pango_markup", bar_cmd_pango_markup }, + { "position", bar_cmd_position }, + { "secondary_button", bar_cmd_secondary_button }, + { "separator_symbol", bar_cmd_separator_symbol }, + { "status_command", bar_cmd_status_command }, + { "strip_workspace_numbers", bar_cmd_strip_workspace_numbers }, + { "swaybar_command", bar_cmd_swaybar_command }, + { "tray_output", bar_cmd_tray_output }, + { "tray_padding", bar_cmd_tray_padding }, + { "workspace_buttons", bar_cmd_workspace_buttons }, + { "wrap_scroll", bar_cmd_wrap_scroll }, +}; + +/** + * Check and add color to buffer. + * + * return error object, or NULL if color is valid. + */ +struct cmd_results *add_color(const char *name, char *buffer, const char *color) { + int len = strlen(color); + if (len != 7 && len != 9) { + return cmd_results_new(CMD_INVALID, name, "Invalid color definition %s", color); + } + + if (color[0] != '#') { + return cmd_results_new(CMD_INVALID, name, "Invalid color definition %s", color); + } + + int i; + for (i = 1; i < len; ++i) { + if (!isxdigit(color[i])) { + return cmd_results_new(CMD_INVALID, name, "Invalid color definition %s", color); + } + } + + // copy color to buffer + strncpy(buffer, color, len); + // add default alpha channel if color was defined without it + if (len == 7) { + buffer[7] = 'f'; + buffer[8] = 'f'; + } + buffer[9] = '\0'; + + return NULL; +} + +static struct cmd_handler input_handlers[] = { + { "accel_profile", input_cmd_accel_profile }, + { "click_method", input_cmd_click_method }, + { "drag_lock", input_cmd_drag_lock }, + { "dwt", input_cmd_dwt }, + { "events", input_cmd_events }, + { "left_handed", input_cmd_left_handed }, + { "middle_emulation", input_cmd_middle_emulation }, + { "natural_scroll", input_cmd_natural_scroll }, + { "pointer_accel", input_cmd_pointer_accel }, + { "scroll_method", input_cmd_scroll_method }, + { "tap", input_cmd_tap }, +}; + +static struct cmd_handler bar_colors_handlers[] = { + { "active_workspace", bar_colors_cmd_active_workspace }, + { "background", bar_colors_cmd_background }, + { "binding_mode", bar_colors_cmd_binding_mode }, + { "focused_background", bar_colors_cmd_focused_background }, + { "focused_separator", bar_colors_cmd_focused_separator }, + { "focused_statusline", bar_colors_cmd_focused_statusline }, + { "focused_workspace", bar_colors_cmd_focused_workspace }, + { "inactive_workspace", bar_colors_cmd_inactive_workspace }, + { "separator", bar_colors_cmd_separator }, + { "statusline", bar_colors_cmd_statusline }, + { "urgent_workspace", bar_colors_cmd_urgent_workspace }, +}; + +static struct cmd_handler ipc_handlers[] = { + { "*", cmd_ipc_cmd }, + { "bar-config", cmd_ipc_cmd }, + { "command", cmd_ipc_cmd }, + { "events", cmd_ipc_events }, + { "inputs", cmd_ipc_cmd }, + { "marks", cmd_ipc_cmd }, + { "outputs", cmd_ipc_cmd }, + { "tree", cmd_ipc_cmd }, + { "workspaces", cmd_ipc_cmd }, +}; + +static struct cmd_handler ipc_event_handlers[] = { + { "*", cmd_ipc_event_cmd }, + { "binding", cmd_ipc_event_cmd }, + { "input", cmd_ipc_event_cmd }, + { "mode", cmd_ipc_event_cmd }, + { "output", cmd_ipc_event_cmd }, + { "window", cmd_ipc_event_cmd }, + { "workspace", cmd_ipc_event_cmd }, +}; + +static int handler_compare(const void *_a, const void *_b) { + const struct cmd_handler *a = _a; + const struct cmd_handler *b = _b; + return strcasecmp(a->command, b->command); +} + +static struct cmd_handler *find_handler(char *line, enum cmd_status block) { + struct cmd_handler d = { .command=line }; + struct cmd_handler *res = NULL; + sway_log(L_DEBUG, "find_handler(%s) %d", line, block == CMD_BLOCK_INPUT); + if (block == CMD_BLOCK_BAR) { + res = bsearch(&d, bar_handlers, + sizeof(bar_handlers) / sizeof(struct cmd_handler), + sizeof(struct cmd_handler), handler_compare); + } else if (block == CMD_BLOCK_BAR_COLORS){ + res = bsearch(&d, bar_colors_handlers, + sizeof(bar_colors_handlers) / sizeof(struct cmd_handler), + sizeof(struct cmd_handler), handler_compare); + } else if (block == CMD_BLOCK_INPUT) { + res = bsearch(&d, input_handlers, + sizeof(input_handlers) / sizeof(struct cmd_handler), + sizeof(struct cmd_handler), handler_compare); + } else if (block == CMD_BLOCK_IPC) { + res = bsearch(&d, ipc_handlers, + sizeof(ipc_handlers) / sizeof(struct cmd_handler), + sizeof(struct cmd_handler), handler_compare); + } else if (block == CMD_BLOCK_IPC_EVENTS) { + res = bsearch(&d, ipc_event_handlers, + sizeof(ipc_event_handlers) / sizeof(struct cmd_handler), + sizeof(struct cmd_handler), handler_compare); + } else { + res = bsearch(&d, handlers, + sizeof(handlers) / sizeof(struct cmd_handler), + sizeof(struct cmd_handler), handler_compare); + } + return res; +} + +struct cmd_results *handle_command(char *_exec, enum command_context context) { + // Even though this function will process multiple commands we will only + // return the last error, if any (for now). (Since we have access to an + // error string we could e.g. concatonate all errors there.) + struct cmd_results *results = NULL; + char *exec = strdup(_exec); + char *head = exec; + char *cmdlist; + char *cmd; + list_t *containers = NULL; + + head = exec; + do { + // Extract criteria (valid for this command list only). + if (*head == '[') { + ++head; + char *criteria_string = argsep(&head, "]"); + if (head) { + ++head; + list_t *tokens = create_list(); + char *error; + + if ((error = extract_crit_tokens(tokens, criteria_string))) { + results = cmd_results_new(CMD_INVALID, criteria_string, + "Can't parse criteria string: %s", error); + free(error); + free(tokens); + goto cleanup; + } + containers = container_for(tokens); + + free(tokens); + } else { + if (!results) { + results = cmd_results_new(CMD_INVALID, criteria_string, "Unmatched ["); + } + goto cleanup; + } + // Skip leading whitespace + head += strspn(head, whitespace); + } + // Split command list + cmdlist = argsep(&head, ";"); + cmdlist += strspn(cmdlist, whitespace); + do { + // Split commands + cmd = argsep(&cmdlist, ","); + cmd += strspn(cmd, whitespace); + if (strcmp(cmd, "") == 0) { + sway_log(L_INFO, "Ignoring empty command."); + continue; + } + sway_log(L_INFO, "Handling command '%s'", cmd); + //TODO better handling of argv + int argc; + char **argv = split_args(cmd, &argc); + if (strcmp(argv[0], "exec") != 0) { + int i; + for (i = 1; i < argc; ++i) { + if (*argv[i] == '\"' || *argv[i] == '\'') { + strip_quotes(argv[i]); + } + } + } + struct cmd_handler *handler = find_handler(argv[0], CMD_BLOCK_END); + if (!handler) { + if (results) { + free_cmd_results(results); + } + results = cmd_results_new(CMD_INVALID, cmd, "Unknown/invalid command"); + free_argv(argc, argv); + goto cleanup; + } + if (!(get_command_policy_mask(argv[0]) & context)) { + if (results) { + free_cmd_results(results); + } + results = cmd_results_new(CMD_INVALID, cmd, + "Permission denied for %s via %s", cmd, + command_policy_str(context)); + free_argv(argc, argv); + goto cleanup; + } + int i = 0; + do { + if (!containers) { + current_container = get_focused_container(&root_container); + } else if (containers->length == 0) { + if (results) { + free_cmd_results(results); + } + results = cmd_results_new(CMD_FAILURE, argv[0], "No matching container"); + goto cleanup; + } else { + current_container = (swayc_t *)containers->items[i]; + } + sway_log(L_INFO, "Running on container '%s'", current_container->name); + + struct cmd_results *res = handler->handle(argc-1, argv+1); + if (res->status != CMD_SUCCESS) { + free_argv(argc, argv); + if (results) { + free_cmd_results(results); + } + results = res; + goto cleanup; + } + free_cmd_results(res); + ++i; + } while(containers && i < containers->length); + + free_argv(argc, argv); + } while(cmdlist); + + if (containers) { + list_free(containers); + containers = NULL; + } + } while(head); + cleanup: + free(exec); + if (containers) { + free(containers); + } + if (!results) { + results = cmd_results_new(CMD_SUCCESS, NULL, NULL); + } + return results; +} + +// this is like handle_command above, except: +// 1) it ignores empty commands (empty lines) +// 2) it does variable substitution +// 3) it doesn't split commands (because the multiple commands are supposed to +// be chained together) +// 4) handle_command handles all state internally while config_command has some +// state handled outside (notably the block mode, in read_config) +struct cmd_results *config_command(char *exec, enum cmd_status block) { + struct cmd_results *results = NULL; + int argc; + char **argv = split_args(exec, &argc); + if (!argc) { + results = cmd_results_new(CMD_SUCCESS, NULL, NULL); + goto cleanup; + } + + sway_log(L_INFO, "handling config command '%s'", exec); + // Endblock + if (**argv == '}') { + results = cmd_results_new(CMD_BLOCK_END, NULL, NULL); + goto cleanup; + } + struct cmd_handler *handler = find_handler(argv[0], block); + if (!handler) { + char *input = argv[0] ? argv[0] : "(empty)"; + results = cmd_results_new(CMD_INVALID, input, "Unknown/invalid command"); + goto cleanup; + } + int i; + // Var replacement, for all but first argument of set + for (i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) { + argv[i] = do_var_replacement(argv[i]); + unescape_string(argv[i]); + } + /* Strip quotes for first argument. + * TODO This part needs to be handled much better */ + if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) { + strip_quotes(argv[1]); + } + if (handler->handle) { + results = handler->handle(argc-1, argv+1); + } else { + results = cmd_results_new(CMD_INVALID, argv[0], "This command is shimmed, but unimplemented"); + } + +cleanup: + free_argv(argc, argv); + return results; +} + +struct cmd_results *config_commands_command(char *exec) { + struct cmd_results *results = NULL; + int argc; + char **argv = split_args(exec, &argc); + if (!argc) { + results = cmd_results_new(CMD_SUCCESS, NULL, NULL); + goto cleanup; + } + + // Find handler for the command this is setting a policy for + char *cmd = argv[0]; + + if (strcmp(cmd, "}") == 0) { + results = cmd_results_new(CMD_BLOCK_END, NULL, NULL); + goto cleanup; + } + + struct cmd_handler *handler = find_handler(cmd, CMD_BLOCK_END); + if (!handler && strcmp(cmd, "*") != 0) { + char *input = cmd ? cmd : "(empty)"; + results = cmd_results_new(CMD_INVALID, input, "Unknown/invalid command"); + goto cleanup; + } + + enum command_context context = 0; + + struct { + char *name; + enum command_context context; + } context_names[] = { + { "config", CONTEXT_CONFIG }, + { "binding", CONTEXT_BINDING }, + { "ipc", CONTEXT_IPC }, + { "criteria", CONTEXT_CRITERIA }, + { "all", CONTEXT_ALL }, + }; + + for (int i = 1; i < argc; ++i) { + size_t j; + for (j = 0; j < sizeof(context_names) / sizeof(context_names[0]); ++j) { + if (strcmp(context_names[j].name, argv[i]) == 0) { + break; + } + } + if (j == sizeof(context_names) / sizeof(context_names[0])) { + results = cmd_results_new(CMD_INVALID, cmd, + "Invalid command context %s", argv[i]); + goto cleanup; + } + context |= context_names[j].context; + } + + struct command_policy *policy = NULL; + for (int i = 0; i < config->command_policies->length; ++i) { + struct command_policy *p = config->command_policies->items[i]; + if (strcmp(p->command, cmd) == 0) { + policy = p; + break; + } + } + if (!policy) { + policy = alloc_command_policy(cmd); + sway_assert(policy, "Unable to allocate security policy"); + if (policy) { + list_add(config->command_policies, policy); + } + } + policy->context = context; + + sway_log(L_INFO, "Set command policy for %s to %d", + policy->command, policy->context); + + results = cmd_results_new(CMD_SUCCESS, NULL, NULL); + +cleanup: + free_argv(argc, argv); + return results; +} + +struct cmd_results *cmd_results_new(enum cmd_status status, const char* input, const char *format, ...) { + struct cmd_results *results = malloc(sizeof(struct cmd_results)); + if (!results) { + sway_log(L_ERROR, "Unable to allocate command results"); + return NULL; + } + results->status = status; + if (input) { + results->input = strdup(input); // input is the command name + } else { + results->input = NULL; + } + if (format) { + char *error = malloc(256); + va_list args; + va_start(args, format); + if (error) { + vsnprintf(error, 256, format, args); + } + va_end(args); + results->error = error; + } else { + results->error = NULL; + } + return results; +} + +void free_cmd_results(struct cmd_results *results) { + if (results->input) { + free(results->input); + } + if (results->error) { + free(results->error); + } + free(results); +} + +const char *cmd_results_to_json(struct cmd_results *results) { + json_object *result_array = json_object_new_array(); + json_object *root = json_object_new_object(); + json_object_object_add(root, "success", json_object_new_boolean(results->status == CMD_SUCCESS)); + if (results->input) { + json_object_object_add(root, "input", json_object_new_string(results->input)); + } + if (results->error) { + json_object_object_add(root, "error", json_object_new_string(results->error)); + } + json_object_array_add(result_array, root); + const char *json = json_object_to_json_string(result_array); + free(result_array); + free(root); + return json; +} diff --git a/sway/old/commands/assign.c b/sway/old/commands/assign.c new file mode 100644 index 00000000..c3b03bbc --- /dev/null +++ b/sway/old/commands/assign.c @@ -0,0 +1,57 @@ +#define _XOPEN_SOURCE 700 +#include +#include +#include "sway/commands.h" +#include "sway/criteria.h" +#include "list.h" +#include "log.h" + +struct cmd_results *cmd_assign(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "assign", EXPECTED_AT_LEAST, 2))) { + return error; + } + + char *criteria = *argv++; + + if (strncmp(*argv, "→", strlen("→")) == 0) { + if (argc < 3) { + return cmd_results_new(CMD_INVALID, "assign", "Missing workspace"); + } + argv++; + } + + char *movecmd = "move container to workspace "; + int arglen = strlen(movecmd) + strlen(*argv) + 1; + char *cmdlist = calloc(1, arglen); + if (!cmdlist) { + return cmd_results_new(CMD_FAILURE, "assign", "Unable to allocate command list"); + } + snprintf(cmdlist, arglen, "%s%s", movecmd, *argv); + + struct criteria *crit = malloc(sizeof(struct criteria)); + if (!crit) { + free(cmdlist); + return cmd_results_new(CMD_FAILURE, "assign", "Unable to allocate criteria"); + } + crit->crit_raw = strdup(criteria); + crit->cmdlist = cmdlist; + crit->tokens = create_list(); + char *err_str = extract_crit_tokens(crit->tokens, crit->crit_raw); + + if (err_str) { + error = cmd_results_new(CMD_INVALID, "assign", err_str); + free(err_str); + free_criteria(crit); + } else if (crit->tokens->length == 0) { + error = cmd_results_new(CMD_INVALID, "assign", "Found no name/value pairs in criteria"); + free_criteria(crit); + } else if (list_seq_find(config->criteria, criteria_cmp, crit) != -1) { + sway_log(L_DEBUG, "assign: Duplicate, skipping."); + free_criteria(crit); + } else { + sway_log(L_DEBUG, "assign: '%s' -> '%s' added", crit->crit_raw, crit->cmdlist); + list_add(config->criteria, crit); + } + return error ? error : cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/bar.c b/sway/old/commands/bar.c new file mode 100644 index 00000000..04745a6e --- /dev/null +++ b/sway/old/commands/bar.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "log.h" +#include "util.h" + +struct cmd_results *cmd_bar(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "bar", EXPECTED_AT_LEAST, 1))) { + return error; + } + + if (config->reading && strcmp("{", argv[0]) != 0) { + return cmd_results_new(CMD_INVALID, "bar", + "Expected '{' at start of bar config definition."); + } + + if (!config->reading) { + if (argc > 1) { + if (strcasecmp("mode", argv[0]) == 0) { + return bar_cmd_mode(argc-1, argv + 1); + } + + if (strcasecmp("hidden_state", argv[0]) == 0) { + return bar_cmd_hidden_state(argc-1, argv + 1); + } + } + + return cmd_results_new(CMD_FAILURE, "bar", "Can only be used in config file."); + } + + // Create new bar with default values + struct bar_config *bar = default_bar_config(); + if (!bar) { + return cmd_results_new(CMD_FAILURE, "bar", "Unable to allocate bar state"); + } + + // set bar id + int i; + for (i = 0; i < config->bars->length; ++i) { + if (bar == config->bars->items[i]) { + const int len = 5 + numlen(i); // "bar-" + i + \0 + bar->id = malloc(len * sizeof(char)); + if (bar->id) { + snprintf(bar->id, len, "bar-%d", i); + } else { + return cmd_results_new(CMD_FAILURE, "bar", "Unable to allocate bar ID"); + } + break; + } + } + + // Set current bar + config->current_bar = bar; + sway_log(L_DEBUG, "Configuring bar %s", bar->id); + return cmd_results_new(CMD_BLOCK_BAR, NULL, NULL); +} diff --git a/sway/old/commands/bar/activate_button.c b/sway/old/commands/bar/activate_button.c new file mode 100644 index 00000000..32a1d3e5 --- /dev/null +++ b/sway/old/commands/bar/activate_button.c @@ -0,0 +1,26 @@ +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_activate_button(int argc, char **argv) { + const char *cmd_name = "activate_button"; +#ifndef ENABLE_TRAY + return cmd_results_new(CMD_INVALID, cmd_name, "Invalid %s command " + "%s called, but sway was compiled without tray support", + cmd_name, cmd_name); +#else + struct cmd_results *error = NULL; + if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, cmd_name, "No bar defined."); + } + + // User should be able to prefix with 0x or whatever they want + config->current_bar->secondary_button = strtoul(argv[0], NULL, 0); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +#endif +} diff --git a/sway/old/commands/bar/binding_mode_indicator.c b/sway/old/commands/bar/binding_mode_indicator.c new file mode 100644 index 00000000..64f5b84f --- /dev/null +++ b/sway/old/commands/bar/binding_mode_indicator.c @@ -0,0 +1,27 @@ +#include +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_binding_mode_indicator(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "binding_mode_indicator", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, "binding_mode_indicator", "No bar defined."); + } + + if (strcasecmp("yes", argv[0]) == 0) { + config->current_bar->binding_mode_indicator = true; + sway_log(L_DEBUG, "Enabling binding mode indicator on bar: %s", config->current_bar->id); + } else if (strcasecmp("no", argv[0]) == 0) { + config->current_bar->binding_mode_indicator = false; + sway_log(L_DEBUG, "Disabling binding mode indicator on bar: %s", config->current_bar->id); + } else { + error = cmd_results_new(CMD_INVALID, "binding_mode_indicator", "Invalid value %s", argv[0]); + return error; + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/bar/bindsym.c b/sway/old/commands/bar/bindsym.c new file mode 100644 index 00000000..5f90b51a --- /dev/null +++ b/sway/old/commands/bar/bindsym.c @@ -0,0 +1,48 @@ +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "list.h" +#include "log.h" +#include "stringop.h" + +struct cmd_results *bar_cmd_bindsym(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1))) { + return error; + } else if (!config->reading) { + return cmd_results_new(CMD_FAILURE, "bindsym", "Can only be used in config file."); + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, "bindsym", "No bar defined."); + } + + if (strlen(argv[1]) != 7) { + return cmd_results_new(CMD_INVALID, "bindsym", "Invalid mouse binding %s", argv[1]); + } + uint32_t numbutton = (uint32_t)atoi(argv[1] + 6); + if (numbutton < 1 || numbutton > 5 || strncmp(argv[1], "button", 6) != 0) { + return cmd_results_new(CMD_INVALID, "bindsym", "Invalid mouse binding %s", argv[1]); + } + struct sway_mouse_binding *binding = malloc(sizeof(struct sway_mouse_binding)); + if (!binding) { + return cmd_results_new(CMD_FAILURE, "bindsym", "Unable to allocate binding"); + } + binding->button = numbutton; + binding->command = join_args(argv + 1, argc - 1); + + struct bar_config *bar = config->current_bar; + int i = list_seq_find(bar->bindings, sway_mouse_binding_cmp_buttons, binding); + if (i > -1) { + sway_log(L_DEBUG, "bindsym - '%s' for swaybar already exists, overwriting", argv[0]); + struct sway_mouse_binding *dup = bar->bindings->items[i]; + free_sway_mouse_binding(dup); + list_del(bar->bindings, i); + } + list_add(bar->bindings, binding); + list_qsort(bar->bindings, sway_mouse_binding_cmp_qsort); + + sway_log(L_DEBUG, "bindsym - Bound %s to command %s when clicking swaybar", argv[0], binding->command); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/bar/colors.c b/sway/old/commands/bar/colors.c new file mode 100644 index 00000000..8b3b0aac --- /dev/null +++ b/sway/old/commands/bar/colors.c @@ -0,0 +1,129 @@ +#include +#include "sway/commands.h" + +static struct cmd_results *parse_single_color(char **color, const char *cmd_name, int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!*color) { + *color = malloc(10); + if (!*color) { + return cmd_results_new(CMD_FAILURE, cmd_name, "Unable to allocate color"); + } + } + + error = add_color(cmd_name, *color, argv[0]); + if (error) { + return error; + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +static struct cmd_results *parse_three_colors(char ***colors, const char *cmd_name, int argc, char **argv) { + struct cmd_results *error = NULL; + if (argc != 3) { + return cmd_results_new(CMD_INVALID, cmd_name, "Requires exactly three color values"); + } + + int i; + for (i = 0; i < 3; i++) { + if (!*colors[i]) { + *(colors[i]) = malloc(10); + if (!*(colors[i])) { + return cmd_results_new(CMD_FAILURE, cmd_name, "Unable to allocate color"); + } + } + error = add_color(cmd_name, *(colors[i]), argv[i]); + if (error) { + return error; + } + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +struct cmd_results *bar_cmd_colors(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "colors", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (strcmp("{", argv[0]) != 0) { + return cmd_results_new(CMD_INVALID, "colors", + "Expected '{' at the start of colors config definition."); + } + + return cmd_results_new(CMD_BLOCK_BAR_COLORS, NULL, NULL); +} + +struct cmd_results *bar_colors_cmd_active_workspace(int argc, char **argv) { + char **colors[3] = { + &(config->current_bar->colors.active_workspace_border), + &(config->current_bar->colors.active_workspace_bg), + &(config->current_bar->colors.active_workspace_text) + }; + return parse_three_colors(colors, "active_workspace", argc, argv); +} + +struct cmd_results *bar_colors_cmd_background(int argc, char **argv) { + return parse_single_color(&(config->current_bar->colors.background), "background", argc, argv); +} + +struct cmd_results *bar_colors_cmd_focused_background(int argc, char **argv) { + return parse_single_color(&(config->current_bar->colors.focused_background), "focused_background", argc, argv); +} + +struct cmd_results *bar_colors_cmd_binding_mode(int argc, char **argv) { + char **colors[3] = { + &(config->current_bar->colors.binding_mode_border), + &(config->current_bar->colors.binding_mode_bg), + &(config->current_bar->colors.binding_mode_text) + }; + return parse_three_colors(colors, "binding_mode", argc, argv); +} + +struct cmd_results *bar_colors_cmd_focused_workspace(int argc, char **argv) { + char **colors[3] = { + &(config->current_bar->colors.focused_workspace_border), + &(config->current_bar->colors.focused_workspace_bg), + &(config->current_bar->colors.focused_workspace_text) + }; + return parse_three_colors(colors, "focused_workspace", argc, argv); +} + +struct cmd_results *bar_colors_cmd_inactive_workspace(int argc, char **argv) { + char **colors[3] = { + &(config->current_bar->colors.inactive_workspace_border), + &(config->current_bar->colors.inactive_workspace_bg), + &(config->current_bar->colors.inactive_workspace_text) + }; + return parse_three_colors(colors, "inactive_workspace", argc, argv); +} + +struct cmd_results *bar_colors_cmd_separator(int argc, char **argv) { + return parse_single_color(&(config->current_bar->colors.separator), "separator", argc, argv); +} + +struct cmd_results *bar_colors_cmd_focused_separator(int argc, char **argv) { + return parse_single_color(&(config->current_bar->colors.focused_separator), "focused_separator", argc, argv); +} + +struct cmd_results *bar_colors_cmd_statusline(int argc, char **argv) { + return parse_single_color(&(config->current_bar->colors.statusline), "statusline", argc, argv); +} + +struct cmd_results *bar_colors_cmd_focused_statusline(int argc, char **argv) { + return parse_single_color(&(config->current_bar->colors.focused_separator), "focused_separator", argc, argv); +} + +struct cmd_results *bar_colors_cmd_urgent_workspace(int argc, char **argv) { + char **colors[3] = { + &(config->current_bar->colors.urgent_workspace_border), + &(config->current_bar->colors.urgent_workspace_bg), + &(config->current_bar->colors.urgent_workspace_text) + }; + return parse_three_colors(colors, "urgent_workspace", argc, argv); +} diff --git a/sway/old/commands/bar/context_button.c b/sway/old/commands/bar/context_button.c new file mode 100644 index 00000000..6d7d7aec --- /dev/null +++ b/sway/old/commands/bar/context_button.c @@ -0,0 +1,26 @@ +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_context_button(int argc, char **argv) { + const char *cmd_name = "context_button"; +#ifndef ENABLE_TRAY + return cmd_results_new(CMD_INVALID, cmd_name, "Invalid %s command " + "%s called, but sway was compiled without tray support", + cmd_name, cmd_name); +#else + struct cmd_results *error = NULL; + if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, cmd_name, "No bar defined."); + } + + // User should be able to prefix with 0x or whatever they want + config->current_bar->context_button = strtoul(argv[0], NULL, 0); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +#endif +} diff --git a/sway/old/commands/bar/font.c b/sway/old/commands/bar/font.c new file mode 100644 index 00000000..c586c5bc --- /dev/null +++ b/sway/old/commands/bar/font.c @@ -0,0 +1,26 @@ +#include +#include "sway/commands.h" +#include "log.h" +#include "stringop.h" + +struct cmd_results *bar_cmd_font(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "font", EXPECTED_AT_LEAST, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, "font", "No bar defined."); + } + + char *font = join_args(argv, argc); + free(config->current_bar->font); + if (strlen(font) > 6 && strncmp("pango:", font, 6) == 0) { + config->current_bar->font = font; + } else { + config->current_bar->font = font; + } + + sway_log(L_DEBUG, "Settings font '%s' for bar: %s", config->current_bar->font, config->current_bar->id); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/bar/height.c b/sway/old/commands/bar/height.c new file mode 100644 index 00000000..eb576ab3 --- /dev/null +++ b/sway/old/commands/bar/height.c @@ -0,0 +1,21 @@ +#include +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_height(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "height", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + int height = atoi(argv[0]); + if (height < 0) { + return cmd_results_new(CMD_INVALID, "height", + "Invalid height value: %s", argv[0]); + } + + config->current_bar->height = height; + sway_log(L_DEBUG, "Setting bar height to %d on bar: %s", height, config->current_bar->id); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/bar/hidden_state.c b/sway/old/commands/bar/hidden_state.c new file mode 100644 index 00000000..0b49aa6b --- /dev/null +++ b/sway/old/commands/bar/hidden_state.c @@ -0,0 +1,79 @@ +#define _XOPEN_SOURCE 500 +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/ipc-server.h" +#include "log.h" + +static struct cmd_results *bar_set_hidden_state(struct bar_config *bar, const char *hidden_state) { + char *old_state = bar->hidden_state; + if (strcasecmp("toggle", hidden_state) == 0 && !config->reading) { + if (strcasecmp("hide", bar->hidden_state) == 0) { + bar->hidden_state = strdup("show"); + } else if (strcasecmp("show", bar->hidden_state) == 0) { + bar->hidden_state = strdup("hide"); + } + } else if (strcasecmp("hide", hidden_state) == 0) { + bar->hidden_state = strdup("hide"); + } else if (strcasecmp("show", hidden_state) == 0) { + bar->hidden_state = strdup("show"); + } else { + return cmd_results_new(CMD_INVALID, "hidden_state", "Invalid value %s", hidden_state); + } + + if (strcmp(old_state, bar->hidden_state) != 0) { + if (!config->reading) { + ipc_event_barconfig_update(bar); + } + sway_log(L_DEBUG, "Setting hidden_state: '%s' for bar: %s", bar->hidden_state, bar->id); + } + + // free old mode + free(old_state); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +struct cmd_results *bar_cmd_hidden_state(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "hidden_state", EXPECTED_AT_LEAST, 1))) { + return error; + } + if ((error = checkarg(argc, "hidden_state", EXPECTED_LESS_THAN, 3))) { + return error; + } + + if (config->reading && argc > 1) { + return cmd_results_new(CMD_INVALID, "hidden_state", "Unexpected value %s in config mode", argv[1]); + } + + const char *state = argv[0]; + + if (config->reading) { + return bar_set_hidden_state(config->current_bar, state); + } + + const char *id = NULL; + if (argc == 2) { + id = argv[1]; + } + + int i; + struct bar_config *bar; + for (i = 0; i < config->bars->length; ++i) { + bar = config->bars->items[i]; + if (id && strcmp(id, bar->id) == 0) { + return bar_set_hidden_state(bar, state); + } + + error = bar_set_hidden_state(bar, state); + if (error) { + return error; + } + } + + // active bar modifiers might have changed. + update_active_bar_modifiers(); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/bar/icon_theme.c b/sway/old/commands/bar/icon_theme.c new file mode 100644 index 00000000..cbfc0be5 --- /dev/null +++ b/sway/old/commands/bar/icon_theme.c @@ -0,0 +1,25 @@ +#define _XOPEN_SOURCE 500 +#include +#include "sway/commands.h" + +struct cmd_results *bar_cmd_icon_theme(int argc, char **argv) { + const char *cmd_name = "tray_output"; +#ifndef ENABLE_TRAY + return cmd_results_new(CMD_INVALID, cmd_name, "Invalid %s command " + "%s called, but sway was compiled without tray support", + cmd_name, cmd_name); +#else + struct cmd_results *error = NULL; + if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, cmd_name, "No bar defined."); + } + + config->current_bar->icon_theme = strdup(argv[0]); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +#endif +} diff --git a/sway/old/commands/bar/id.c b/sway/old/commands/bar/id.c new file mode 100644 index 00000000..1221ebf6 --- /dev/null +++ b/sway/old/commands/bar/id.c @@ -0,0 +1,33 @@ +#define _XOPEN_SOURCE 500 +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_id(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "id", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + const char *name = argv[0]; + const char *oldname = config->current_bar->id; + + // check if id is used by a previously defined bar + int i; + for (i = 0; i < config->bars->length; ++i) { + struct bar_config *find = config->bars->items[i]; + if (strcmp(name, find->id) == 0 && config->current_bar != find) { + return cmd_results_new(CMD_FAILURE, "id", + "Id '%s' already defined for another bar. Id unchanged (%s).", + name, oldname); + } + } + + sway_log(L_DEBUG, "Renaming bar: '%s' to '%s'", oldname, name); + + // free old bar id + free(config->current_bar->id); + + config->current_bar->id = strdup(name); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/bar/mode.c b/sway/old/commands/bar/mode.c new file mode 100644 index 00000000..36816b93 --- /dev/null +++ b/sway/old/commands/bar/mode.c @@ -0,0 +1,81 @@ +#define _XOPEN_SOURCE 500 +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/ipc-server.h" +#include "log.h" + +static struct cmd_results *bar_set_mode(struct bar_config *bar, const char *mode) { + char *old_mode = bar->mode; + if (strcasecmp("toggle", mode) == 0 && !config->reading) { + if (strcasecmp("dock", bar->mode) == 0) { + bar->mode = strdup("hide"); + } else if (strcasecmp("hide", bar->mode) == 0) { + bar->mode = strdup("dock"); + } + } else if (strcasecmp("dock", mode) == 0) { + bar->mode = strdup("dock"); + } else if (strcasecmp("hide", mode) == 0) { + bar->mode = strdup("hide"); + } else if (strcasecmp("invisible", mode) == 0) { + bar->mode = strdup("invisible"); + } else { + return cmd_results_new(CMD_INVALID, "mode", "Invalid value %s", mode); + } + + if (strcmp(old_mode, bar->mode) != 0) { + if (!config->reading) { + ipc_event_barconfig_update(bar); + + // active bar modifiers might have changed. + update_active_bar_modifiers(); + } + sway_log(L_DEBUG, "Setting mode: '%s' for bar: %s", bar->mode, bar->id); + } + + // free old mode + free(old_mode); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +struct cmd_results *bar_cmd_mode(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "mode", EXPECTED_AT_LEAST, 1))) { + return error; + } + if ((error = checkarg(argc, "mode", EXPECTED_LESS_THAN, 3))) { + return error; + } + + if (config->reading && argc > 1) { + return cmd_results_new(CMD_INVALID, "mode", "Unexpected value %s in config mode", argv[1]); + } + + const char *mode = argv[0]; + + if (config->reading) { + return bar_set_mode(config->current_bar, mode); + } + + const char *id = NULL; + if (argc == 2) { + id = argv[1]; + } + + int i; + struct bar_config *bar; + for (i = 0; i < config->bars->length; ++i) { + bar = config->bars->items[i]; + if (id && strcmp(id, bar->id) == 0) { + return bar_set_mode(bar, mode); + } + + error = bar_set_mode(bar, mode); + if (error) { + return error; + } + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/bar/modifier.c b/sway/old/commands/bar/modifier.c new file mode 100644 index 00000000..153d87e6 --- /dev/null +++ b/sway/old/commands/bar/modifier.c @@ -0,0 +1,35 @@ +#include +#include "sway/commands.h" +#include "log.h" +#include "stringop.h" +#include "util.h" + +struct cmd_results *bar_cmd_modifier(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "modifier", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, "modifier", "No bar defined."); + } + + uint32_t mod = 0; + + list_t *split = split_string(argv[0], "+"); + for (int i = 0; i < split->length; ++i) { + uint32_t tmp_mod; + if ((tmp_mod = get_modifier_mask_by_name(split->items[i])) > 0) { + mod |= tmp_mod; + continue; + } else { + free_flat_list(split); + return cmd_results_new(CMD_INVALID, "modifier", "Unknown modifier '%s'", split->items[i]); + } + } + free_flat_list(split); + + config->current_bar->modifier = mod; + sway_log(L_DEBUG, "Show/Hide the bar when pressing '%s' in hide mode.", argv[0]); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/bar/output.c b/sway/old/commands/bar/output.c new file mode 100644 index 00000000..a5710bc0 --- /dev/null +++ b/sway/old/commands/bar/output.c @@ -0,0 +1,50 @@ +#define _XOPEN_SOURCE 500 +#include +#include "sway/commands.h" +#include "list.h" +#include "log.h" + +struct cmd_results *bar_cmd_output(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "output", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, "output", "No bar defined."); + } + + const char *output = argv[0]; + list_t *outputs = config->current_bar->outputs; + if (!outputs) { + outputs = create_list(); + config->current_bar->outputs = outputs; + } + + int i; + int add_output = 1; + if (strcmp("*", output) == 0) { + // remove all previous defined outputs and replace with '*' + for (i = 0; i < outputs->length; ++i) { + free(outputs->items[i]); + list_del(outputs, i); + } + } else { + // only add output if not already defined with either the same + // name or as '*' + for (i = 0; i < outputs->length; ++i) { + const char *find = outputs->items[i]; + if (strcmp("*", find) == 0 || strcmp(output, find) == 0) { + add_output = 0; + break; + } + } + } + + if (add_output) { + list_add(outputs, strdup(output)); + sway_log(L_DEBUG, "Adding bar: '%s' to output '%s'", config->current_bar->id, output); + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/bar/pango_markup.c b/sway/old/commands/bar/pango_markup.c new file mode 100644 index 00000000..f69e882f --- /dev/null +++ b/sway/old/commands/bar/pango_markup.c @@ -0,0 +1,27 @@ +#include +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_pango_markup(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "pango_markup", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, "pango_markup", "No bar defined."); + } + + if (strcasecmp("enabled", argv[0]) == 0) { + config->current_bar->pango_markup = true; + sway_log(L_DEBUG, "Enabling pango markup for bar: %s", config->current_bar->id); + } else if (strcasecmp("disabled", argv[0]) == 0) { + config->current_bar->pango_markup = false; + sway_log(L_DEBUG, "Disabling pango markup for bar: %s", config->current_bar->id); + } else { + error = cmd_results_new(CMD_INVALID, "pango_markup", "Invalid value %s", argv[0]); + return error; + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/bar/position.c b/sway/old/commands/bar/position.c new file mode 100644 index 00000000..50de58e2 --- /dev/null +++ b/sway/old/commands/bar/position.c @@ -0,0 +1,33 @@ +#include +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_position(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "position", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, "position", "No bar defined."); + } + + if (strcasecmp("top", argv[0]) == 0) { + config->current_bar->position = DESKTOP_SHELL_PANEL_POSITION_TOP; + } else if (strcasecmp("bottom", argv[0]) == 0) { + config->current_bar->position = DESKTOP_SHELL_PANEL_POSITION_BOTTOM; + } else if (strcasecmp("left", argv[0]) == 0) { + sway_log(L_INFO, "Warning: swaybar currently only supports top and bottom positioning. YMMV"); + config->current_bar->position = DESKTOP_SHELL_PANEL_POSITION_LEFT; + } else if (strcasecmp("right", argv[0]) == 0) { + sway_log(L_INFO, "Warning: swaybar currently only supports top and bottom positioning. YMMV"); + config->current_bar->position = DESKTOP_SHELL_PANEL_POSITION_RIGHT; + } else { + error = cmd_results_new(CMD_INVALID, "position", "Invalid value %s", argv[0]); + return error; + } + + sway_log(L_DEBUG, "Setting bar position '%s' for bar: %s", argv[0], config->current_bar->id); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/bar/secondary_button.c b/sway/old/commands/bar/secondary_button.c new file mode 100644 index 00000000..745045c5 --- /dev/null +++ b/sway/old/commands/bar/secondary_button.c @@ -0,0 +1,26 @@ +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_secondary_button(int argc, char **argv) { + const char *cmd_name = "secondary_button"; +#ifndef ENABLE_TRAY + return cmd_results_new(CMD_INVALID, cmd_name, "Invalid %s command " + "%s called, but sway was compiled without tray support", + cmd_name, cmd_name); +#else + struct cmd_results *error = NULL; + if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, cmd_name, "No bar defined."); + } + + // User should be able to prefix with 0x or whatever they want + config->current_bar->secondary_button = strtoul(argv[0], NULL, 0); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +#endif +} diff --git a/sway/old/commands/bar/separator_symbol.c b/sway/old/commands/bar/separator_symbol.c new file mode 100644 index 00000000..2766d8a2 --- /dev/null +++ b/sway/old/commands/bar/separator_symbol.c @@ -0,0 +1,21 @@ +#define _XOPEN_SOURCE 500 +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_separator_symbol(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "separator_symbol", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, "separator_symbol", "No bar defined."); + } + + free(config->current_bar->separator_symbol); + config->current_bar->separator_symbol = strdup(argv[0]); + sway_log(L_DEBUG, "Settings separator_symbol '%s' for bar: %s", config->current_bar->separator_symbol, config->current_bar->id); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/bar/status_command.c b/sway/old/commands/bar/status_command.c new file mode 100644 index 00000000..b227ac47 --- /dev/null +++ b/sway/old/commands/bar/status_command.c @@ -0,0 +1,21 @@ +#include +#include "sway/commands.h" +#include "log.h" +#include "stringop.h" + +struct cmd_results *bar_cmd_status_command(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "status_command", EXPECTED_AT_LEAST, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, "status_command", "No bar defined."); + } + + free(config->current_bar->status_command); + config->current_bar->status_command = join_args(argv, argc); + sway_log(L_DEBUG, "Feeding bar with status command: %s", config->current_bar->status_command); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/bar/strip_workspace_numbers.c b/sway/old/commands/bar/strip_workspace_numbers.c new file mode 100644 index 00000000..9ac32482 --- /dev/null +++ b/sway/old/commands/bar/strip_workspace_numbers.c @@ -0,0 +1,27 @@ +#include +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_strip_workspace_numbers(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "strip_workspace_numbers", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, "strip_workspace_numbers", "No bar defined."); + } + + if (strcasecmp("yes", argv[0]) == 0) { + config->current_bar->strip_workspace_numbers = true; + sway_log(L_DEBUG, "Stripping workspace numbers on bar: %s", config->current_bar->id); + } else if (strcasecmp("no", argv[0]) == 0) { + config->current_bar->strip_workspace_numbers = false; + sway_log(L_DEBUG, "Enabling workspace numbers on bar: %s", config->current_bar->id); + } else { + error = cmd_results_new(CMD_INVALID, "strip_workspace_numbers", "Invalid value %s", argv[0]); + return error; + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/bar/swaybar_command.c b/sway/old/commands/bar/swaybar_command.c new file mode 100644 index 00000000..452e2df5 --- /dev/null +++ b/sway/old/commands/bar/swaybar_command.c @@ -0,0 +1,21 @@ +#include +#include "sway/commands.h" +#include "log.h" +#include "stringop.h" + +struct cmd_results *bar_cmd_swaybar_command(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "swaybar_command", EXPECTED_AT_LEAST, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, "swaybar_command", "No bar defined."); + } + + free(config->current_bar->swaybar_command); + config->current_bar->swaybar_command = join_args(argv, argc); + sway_log(L_DEBUG, "Using custom swaybar command: %s", config->current_bar->swaybar_command); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/bar/tray_output.c b/sway/old/commands/bar/tray_output.c new file mode 100644 index 00000000..012304a9 --- /dev/null +++ b/sway/old/commands/bar/tray_output.c @@ -0,0 +1,29 @@ +#define _XOPEN_SOURCE 500 +#include +#include "sway/commands.h" + +struct cmd_results *bar_cmd_tray_output(int argc, char **argv) { + const char *cmd_name = "tray_output"; +#ifndef ENABLE_TRAY + return cmd_results_new(CMD_INVALID, cmd_name, "Invalid %s command " + "%s called, but sway was compiled without tray support", + cmd_name, cmd_name); +#else + struct cmd_results *error = NULL; + if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, cmd_name, "No bar defined."); + } + + if (strcmp(argv[0], "all") == 0) { + // Default behaviour + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } + config->current_bar->tray_output = strdup(argv[0]); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +#endif +} diff --git a/sway/old/commands/bar/tray_padding.c b/sway/old/commands/bar/tray_padding.c new file mode 100644 index 00000000..ac0572ce --- /dev/null +++ b/sway/old/commands/bar/tray_padding.c @@ -0,0 +1,34 @@ +#include +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_tray_padding(int argc, char **argv) { + const char *cmd_name = "tray_padding"; +#ifndef ENABLE_TRAY + return cmd_results_new(CMD_INVALID, cmd_name, "Invalid %s command" + "%s called, but sway was compiled without tray support", + cmd_name, cmd_name); +#else + struct cmd_results *error = NULL; + if ((error = checkarg(argc, cmd_name, EXPECTED_AT_LEAST, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, cmd_name, "No bar defined."); + } + + if (argc == 1 || (argc == 2 && strcasecmp("px", argv[1]) == 0)) { + char *inv; + uint32_t padding = strtoul(argv[0], &inv, 10); + if (*inv == '\0' || strcasecmp(inv, "px") == 0) { + config->current_bar->tray_padding = padding; + sway_log(L_DEBUG, "Enabling tray padding of %d px on bar: %s", padding, config->current_bar->id); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } + } + return cmd_results_new(CMD_FAILURE, cmd_name, + "Expected 'tray_padding [px]'"); +#endif +} diff --git a/sway/old/commands/bar/workspace_buttons.c b/sway/old/commands/bar/workspace_buttons.c new file mode 100644 index 00000000..67dd2d31 --- /dev/null +++ b/sway/old/commands/bar/workspace_buttons.c @@ -0,0 +1,27 @@ +#include +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_workspace_buttons(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "workspace_buttons", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, "workspace_buttons", "No bar defined."); + } + + if (strcasecmp("yes", argv[0]) == 0) { + config->current_bar->workspace_buttons = true; + sway_log(L_DEBUG, "Enabling workspace buttons on bar: %s", config->current_bar->id); + } else if (strcasecmp("no", argv[0]) == 0) { + config->current_bar->workspace_buttons = false; + sway_log(L_DEBUG, "Disabling workspace buttons on bar: %s", config->current_bar->id); + } else { + error = cmd_results_new(CMD_INVALID, "workspace_buttons", "Invalid value %s", argv[0]); + return error; + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/bar/wrap_scroll.c b/sway/old/commands/bar/wrap_scroll.c new file mode 100644 index 00000000..4ed1f12a --- /dev/null +++ b/sway/old/commands/bar/wrap_scroll.c @@ -0,0 +1,27 @@ +#include +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_wrap_scroll(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "wrap_scroll", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, "wrap_scroll", "No bar defined."); + } + + if (strcasecmp("yes", argv[0]) == 0) { + config->current_bar->wrap_scroll = true; + sway_log(L_DEBUG, "Enabling wrap scroll on bar: %s", config->current_bar->id); + } else if (strcasecmp("no", argv[0]) == 0) { + config->current_bar->wrap_scroll = false; + sway_log(L_DEBUG, "Disabling wrap scroll on bar: %s", config->current_bar->id); + } else { + error = cmd_results_new(CMD_INVALID, "wrap_scroll", "Invalid value %s", argv[0]); + return error; + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/bind.c b/sway/old/commands/bind.c new file mode 100644 index 00000000..d9ea37b7 --- /dev/null +++ b/sway/old/commands/bind.c @@ -0,0 +1,170 @@ +#include +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/input_state.h" +#include "list.h" +#include "log.h" +#include "stringop.h" +#include "util.h" + +int binding_order = 0; + +struct cmd_results *cmd_bindsym(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1))) { + return error; + } + + struct sway_binding *binding = malloc(sizeof(struct sway_binding)); + if (!binding) { + return cmd_results_new(CMD_FAILURE, "bindsym", + "Unable to allocate binding"); + } + binding->keys = create_list(); + binding->modifiers = 0; + binding->release = false; + binding->bindcode = false; + + // Handle --release + if (strcmp("--release", argv[0]) == 0) { + if (argc >= 3) { + binding->release = true; + argv++; + argc--; + } else { + free_sway_binding(binding); + return cmd_results_new(CMD_FAILURE, "bindsym", + "Invalid bindsym command " + "(expected more than 2 arguments, got %d)", argc); + } + } + + binding->command = join_args(argv + 1, argc - 1); + + list_t *split = split_string(argv[0], "+"); + for (int i = 0; i < split->length; ++i) { + // Check for a modifier key + uint32_t mod; + if ((mod = get_modifier_mask_by_name(split->items[i])) > 0) { + binding->modifiers |= mod; + continue; + } + // Check for xkb key + xkb_keysym_t sym = xkb_keysym_from_name(split->items[i], + XKB_KEYSYM_CASE_INSENSITIVE); + + // Check for mouse binding + if (strncasecmp(split->items[i], "button", strlen("button")) == 0 && + strlen(split->items[i]) == strlen("button0")) { + sym = ((char *)split->items[i])[strlen("button")] - '1' + M_LEFT_CLICK; + } + if (!sym) { + struct cmd_results *ret = cmd_results_new(CMD_INVALID, "bindsym", + "Unknown key '%s'", (char *)split->items[i]); + free_sway_binding(binding); + free_flat_list(split); + return ret; + } + xkb_keysym_t *key = malloc(sizeof(xkb_keysym_t)); + if (!key) { + free_sway_binding(binding); + free_flat_list(split); + return cmd_results_new(CMD_FAILURE, "bindsym", + "Unable to allocate binding"); + } + *key = sym; + list_add(binding->keys, key); + } + free_flat_list(split); + + struct sway_mode *mode = config->current_mode; + int i = list_seq_find(mode->bindings, sway_binding_cmp_keys, binding); + if (i > -1) { + sway_log(L_DEBUG, "bindsym - '%s' already exists, overwriting", argv[0]); + struct sway_binding *dup = mode->bindings->items[i]; + free_sway_binding(dup); + list_del(mode->bindings, i); + } + binding->order = binding_order++; + list_add(mode->bindings, binding); + list_qsort(mode->bindings, sway_binding_cmp_qsort); + + sway_log(L_DEBUG, "bindsym - Bound %s to command %s", argv[0], binding->command); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +struct cmd_results *cmd_bindcode(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "bindcode", EXPECTED_MORE_THAN, 1))) { + return error; + } + + struct sway_binding *binding = malloc(sizeof(struct sway_binding)); + if (!binding) { + return cmd_results_new(CMD_FAILURE, "bindsym", + "Unable to allocate binding"); + } + binding->keys = create_list(); + binding->modifiers = 0; + binding->release = false; + binding->bindcode = true; + + // Handle --release + if (strcmp("--release", argv[0]) == 0) { + if (argc >= 3) { + binding->release = true; + argv++; + argc--; + } else { + free_sway_binding(binding); + return cmd_results_new(CMD_FAILURE, "bindcode", + "Invalid bindcode command " + "(expected more than 2 arguments, got %d)", argc); + } + } + + binding->command = join_args(argv + 1, argc - 1); + + list_t *split = split_string(argv[0], "+"); + for (int i = 0; i < split->length; ++i) { + // Check for a modifier key + uint32_t mod; + if ((mod = get_modifier_mask_by_name(split->items[i])) > 0) { + binding->modifiers |= mod; + continue; + } + // parse keycode + xkb_keycode_t keycode = (int)strtol(split->items[i], NULL, 10); + if (!xkb_keycode_is_legal_ext(keycode)) { + error = cmd_results_new(CMD_INVALID, "bindcode", "Invalid keycode '%s'", (char *)split->items[i]); + free_sway_binding(binding); + list_free(split); + return error; + } + xkb_keycode_t *key = malloc(sizeof(xkb_keycode_t)); + *key = keycode - 8; + list_add(binding->keys, key); + } + free_flat_list(split); + + struct sway_mode *mode = config->current_mode; + int i = list_seq_find(mode->bindings, sway_binding_cmp_keys, binding); + if (i > -1) { + struct sway_binding *dup = mode->bindings->items[i]; + if (dup->bindcode) { + sway_log(L_DEBUG, "bindcode - '%s' already exists, overwriting", argv[0]); + } else { + sway_log(L_DEBUG, "bindcode - '%s' already exists as bindsym, overwriting", argv[0]); + } + free_sway_binding(dup); + list_del(mode->bindings, i); + } + binding->order = binding_order++; + list_add(mode->bindings, binding); + list_qsort(mode->bindings, sway_binding_cmp_qsort); + + sway_log(L_DEBUG, "bindcode - Bound %s to command %s", argv[0], binding->command); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/border.c b/sway/old/commands/border.c new file mode 100644 index 00000000..c888622e --- /dev/null +++ b/sway/old/commands/border.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include "sway/commands.h" +#include "sway/container.h" +#include "sway/focus.h" + +struct cmd_results *cmd_border(int argc, char **argv) { + struct cmd_results *error = NULL; + if (!config->active) { + return cmd_results_new(CMD_FAILURE, "border", "Can only be used when sway is running."); + } + if ((error = checkarg(argc, "border", EXPECTED_AT_LEAST, 1))) { + return error; + } + + if (argc > 2) { + return cmd_results_new(CMD_INVALID, "border", + "Expected 'border []"); + } + + swayc_t *view = current_container; + enum swayc_border_types border = view->border_type; + int thickness = view->border_thickness; + + if (strcasecmp(argv[0], "none") == 0) { + border = B_NONE; + } else if (strcasecmp(argv[0], "normal") == 0) { + border = B_NORMAL; + } else if (strcasecmp(argv[0], "pixel") == 0) { + border = B_PIXEL; + } else if (strcasecmp(argv[0], "toggle") == 0) { + switch (border) { + case B_NONE: + border = B_PIXEL; + break; + case B_NORMAL: + border = B_NONE; + break; + case B_PIXEL: + border = B_NORMAL; + break; + } + } else { + return cmd_results_new(CMD_INVALID, "border", + "Expected 'border "); + } + + if (argc == 2 && (border == B_NORMAL || border == B_PIXEL)) { + thickness = (int)strtol(argv[1], NULL, 10); + if (errno == ERANGE || thickness < 0) { + errno = 0; + return cmd_results_new(CMD_INVALID, "border", "Number is out of range."); + } + } + + if (view) { + view->border_type = border; + view->border_thickness = thickness; + update_geometry(view); + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/client.c b/sway/old/commands/client.c new file mode 100644 index 00000000..f3d879cd --- /dev/null +++ b/sway/old/commands/client.c @@ -0,0 +1,72 @@ +#include +#include +#include "sway/commands.h" + +static struct cmd_results *parse_border_color(struct border_colors *border_colors, const char *cmd_name, int argc, char **argv) { + struct cmd_results *error = NULL; + if (argc < 3 || argc > 5) { + return cmd_results_new(CMD_INVALID, cmd_name, "Requires between three and five color values"); + } + + uint32_t *colors[5] = { + &border_colors->border, + &border_colors->background, + &border_colors->text, + &border_colors->indicator, + &border_colors->child_border + }; + int i; + for (i = 0; i < argc; i++) { + char buffer[10]; + error = add_color(cmd_name, buffer, argv[i]); + if (error) { + return error; + } + *colors[i] = strtoul(buffer + 1, NULL, 16); + } + + if (argc < 5) { + border_colors->child_border = border_colors->background; + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +struct cmd_results *cmd_client_focused(int argc, char **argv) { + return parse_border_color(&config->border_colors.focused, "client.focused", argc, argv); +} + +struct cmd_results *cmd_client_focused_inactive(int argc, char **argv) { + return parse_border_color(&config->border_colors.focused_inactive, "client.focused_inactive", argc, argv); +} + +struct cmd_results *cmd_client_unfocused(int argc, char **argv) { + return parse_border_color(&config->border_colors.unfocused, "client.unfocused", argc, argv); +} + +struct cmd_results *cmd_client_urgent(int argc, char **argv) { + return parse_border_color(&config->border_colors.urgent, "client.urgent", argc, argv); +} + +struct cmd_results *cmd_client_placeholder(int argc, char **argv) { + return parse_border_color(&config->border_colors.placeholder, "client.placeholder", argc, argv); +} + +struct cmd_results *cmd_client_background(int argc, char **argv) { + char buffer[10]; + struct cmd_results *error = NULL; + uint32_t background; + + if (argc != 1) { + return cmd_results_new(CMD_INVALID, "client.background", "Requires exactly one color value"); + } + + error = add_color("client.background", buffer, argv[0]); + if (error) { + return error; + } + + background = strtoul(buffer+1, NULL, 16); + config->border_colors.background = background; + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/clipboard.c b/sway/old/commands/clipboard.c new file mode 100644 index 00000000..95514e78 --- /dev/null +++ b/sway/old/commands/clipboard.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include "sway/commands.h" +#include "stringop.h" + +static void send_clipboard(void *data, const char *type, int fd) { + if (strcmp(type, "text/plain") != 0 + && strcmp(type, "text/plain;charset=utf-8") != 0) { + close(fd); + return; + } + + const char *str = data; + write(fd, str, strlen(str)); + close(fd); +} + +struct cmd_results *cmd_clipboard(int argc, char **argv) { + static char *current_data = NULL; + + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "clipboard", EXPECTED_AT_LEAST, 1))) { + return error; + } + + static const char *types[2] = { + "text/plain", + "text/plain;charset=utf-8" + }; + + char *str = join_args(argv, argc); + wlc_set_selection(str, types, 2, &send_clipboard); + + free(current_data); + current_data = str; + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/commands.c b/sway/old/commands/commands.c new file mode 100644 index 00000000..0c64970c --- /dev/null +++ b/sway/old/commands/commands.c @@ -0,0 +1,26 @@ +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "list.h" +#include "log.h" + +struct cmd_results *cmd_commands(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "commands", EXPECTED_EQUAL_TO, 1))) { + return error; + } + if ((error = check_security_config())) { + return error; + } + + if (strcmp(argv[0], "{") != 0) { + return cmd_results_new(CMD_FAILURE, "commands", "Expected block declaration"); + } + + if (!config->reading) { + return cmd_results_new(CMD_FAILURE, "commands", "Can only be used in config file."); + } + + return cmd_results_new(CMD_BLOCK_COMMANDS, NULL, NULL); +} diff --git a/sway/old/commands/debuglog.c b/sway/old/commands/debuglog.c new file mode 100644 index 00000000..658d6165 --- /dev/null +++ b/sway/old/commands/debuglog.c @@ -0,0 +1,27 @@ +#include +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *cmd_debuglog(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "debuglog", EXPECTED_EQUAL_TO, 1))) { + return error; + } else if (strcasecmp(argv[0], "toggle") == 0) { + if (config->reading) { + return cmd_results_new(CMD_FAILURE, "debuglog toggle", "Can't be used in config file."); + } + if (toggle_debug_logging()) { + sway_log(L_DEBUG, "Debuglog turned on."); + } + } else if (strcasecmp(argv[0], "on") == 0) { + set_log_level(L_DEBUG); + sway_log(L_DEBUG, "Debuglog turned on."); + } else if (strcasecmp(argv[0], "off") == 0) { + reset_log_level(); + } else { + return cmd_results_new(CMD_FAILURE, "debuglog", "Expected 'debuglog on|off|toggle'"); + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + diff --git a/sway/old/commands/default_border.c b/sway/old/commands/default_border.c new file mode 100644 index 00000000..8fbe8d19 --- /dev/null +++ b/sway/old/commands/default_border.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include "sway/commands.h" +#include "sway/container.h" + +struct cmd_results *cmd_default_border(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "default_border", EXPECTED_AT_LEAST, 1))) { + return error; + } + + if (argc > 2) { + return cmd_results_new(CMD_INVALID, "default_border", + "Expected 'default_border []"); + } + + enum swayc_border_types border = config->border; + int thickness = config->border_thickness; + + if (strcasecmp(argv[0], "none") == 0) { + border = B_NONE; + } else if (strcasecmp(argv[0], "normal") == 0) { + border = B_NORMAL; + } else if (strcasecmp(argv[0], "pixel") == 0) { + border = B_PIXEL; + } else { + return cmd_results_new(CMD_INVALID, "default_border", + "Expected 'default_border []"); + } + + if (argc == 2 && (border == B_NORMAL || border == B_PIXEL)) { + thickness = (int)strtol(argv[1], NULL, 10); + if (errno == ERANGE || thickness < 0) { + errno = 0; + return cmd_results_new(CMD_INVALID, "default_border", "Number is out out of range."); + } + } + + config->border = border; + config->border_thickness = thickness; + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/default_floating_border.c b/sway/old/commands/default_floating_border.c new file mode 100644 index 00000000..fb48c1c0 --- /dev/null +++ b/sway/old/commands/default_floating_border.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include "sway/commands.h" +#include "sway/container.h" + +struct cmd_results *cmd_default_floating_border(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "default_floating_border", EXPECTED_AT_LEAST, 1))) { + return error; + } + + if (argc > 2) { + return cmd_results_new(CMD_INVALID, "default_floating_border", + "Expected 'default_floating_border []"); + } + + enum swayc_border_types border = config->floating_border; + int thickness = config->floating_border_thickness; + + if (strcasecmp(argv[0], "none") == 0) { + border = B_NONE; + } else if (strcasecmp(argv[0], "normal") == 0) { + border = B_NORMAL; + } else if (strcasecmp(argv[0], "pixel") == 0) { + border = B_PIXEL; + } else { + return cmd_results_new(CMD_INVALID, "default_floating_border", + "Expected 'default_floating_border []"); + } + + if (argc == 2 && (border == B_NORMAL || border == B_PIXEL)) { + thickness = (int)strtol(argv[1], NULL, 10); + if (errno == ERANGE || thickness < 0) { + errno = 0; + return cmd_results_new(CMD_INVALID, "default_floating_border", + "Number is out out of range."); + } + } + + config->floating_border = border; + config->floating_border_thickness = thickness; + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/exec.c b/sway/old/commands/exec.c new file mode 100644 index 00000000..58ef5f94 --- /dev/null +++ b/sway/old/commands/exec.c @@ -0,0 +1,16 @@ +#include +#include "sway/commands.h" +#include "log.h" +#include "stringop.h" + +struct cmd_results *cmd_exec(int argc, char **argv) { + if (!config->active) return cmd_results_new(CMD_DEFER, "exec", NULL); + if (config->reloading) { + char *args = join_args(argv, argc); + sway_log(L_DEBUG, "Ignoring 'exec %s' due to reload", args); + free(args); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } + return cmd_exec_always(argc, argv); +} + diff --git a/sway/old/commands/exec_always.c b/sway/old/commands/exec_always.c new file mode 100644 index 00000000..ab2d8622 --- /dev/null +++ b/sway/old/commands/exec_always.c @@ -0,0 +1,85 @@ +#define _XOPEN_SOURCE 500 +#include +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "log.h" +#include "stringop.h" + +struct cmd_results *cmd_exec_always(int argc, char **argv) { + struct cmd_results *error = NULL; + if (!config->active) return cmd_results_new(CMD_DEFER, NULL, NULL); + if ((error = checkarg(argc, "exec_always", EXPECTED_MORE_THAN, 0))) { + return error; + } + + char *tmp = NULL; + if (strcmp((char*)*argv, "--no-startup-id") == 0) { + sway_log(L_INFO, "exec switch '--no-startup-id' not supported, ignored."); + if ((error = checkarg(argc - 1, "exec_always", EXPECTED_MORE_THAN, 0))) { + return error; + } + + tmp = join_args(argv + 1, argc - 1); + } else { + tmp = join_args(argv, argc); + } + + // Put argument into cmd array + char cmd[4096]; + strncpy(cmd, tmp, sizeof(cmd)); + cmd[sizeof(cmd) - 1] = 0; + free(tmp); + sway_log(L_DEBUG, "Executing %s", cmd); + + int fd[2]; + if (pipe(fd) != 0) { + sway_log(L_ERROR, "Unable to create pipe for fork"); + } + + pid_t pid; + pid_t *child = malloc(sizeof(pid_t)); // malloc'd so that Linux can avoid copying the process space + if (!child) { + return cmd_results_new(CMD_FAILURE, "exec_always", "Unable to allocate child pid"); + } + // Fork process + if ((pid = fork()) == 0) { + // Fork child process again + setsid(); + if ((*child = fork()) == 0) { + execl("/bin/sh", "/bin/sh", "-c", cmd, (void *)NULL); + /* Not reached */ + } + close(fd[0]); + ssize_t s = 0; + while ((size_t)s < sizeof(pid_t)) { + s += write(fd[1], ((uint8_t *)child) + s, sizeof(pid_t) - s); + } + close(fd[1]); + _exit(0); // Close child process + } else if (pid < 0) { + free(child); + return cmd_results_new(CMD_FAILURE, "exec_always", "fork() failed"); + } + close(fd[1]); // close write + ssize_t s = 0; + while ((size_t)s < sizeof(pid_t)) { + s += read(fd[0], ((uint8_t *)child) + s, sizeof(pid_t) - s); + } + close(fd[0]); + // cleanup child process + wait(0); + swayc_t *ws = swayc_active_workspace(); + if (*child > 0 && ws) { + sway_log(L_DEBUG, "Child process created with pid %d for workspace %s", *child, ws->name); + struct pid_workspace *pw = malloc(sizeof(struct pid_workspace)); + pw->pid = child; + pw->workspace = strdup(ws->name); + pid_workspace_add(pw); + } else { + free(child); + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/exit.c b/sway/old/commands/exit.c new file mode 100644 index 00000000..f192f86a --- /dev/null +++ b/sway/old/commands/exit.c @@ -0,0 +1,17 @@ +#include "sway/commands.h" +#include "sway/container.h" + +void sway_terminate(int exit_code); + +struct cmd_results *cmd_exit(int argc, char **argv) { + struct cmd_results *error = NULL; + if (config->reading) return cmd_results_new(CMD_FAILURE, "exit", "Can't be used in config file."); + if ((error = checkarg(argc, "exit", EXPECTED_EQUAL_TO, 0))) { + return error; + } + // Close all views + close_views(&root_container); + sway_terminate(EXIT_SUCCESS); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + diff --git a/sway/old/commands/floating.c b/sway/old/commands/floating.c new file mode 100644 index 00000000..ccfde532 --- /dev/null +++ b/sway/old/commands/floating.c @@ -0,0 +1,81 @@ +#include +#include +#include "sway/commands.h" +#include "sway/container.h" +#include "sway/ipc-server.h" +#include "sway/layout.h" +#include "list.h" +#include "log.h" + +struct cmd_results *cmd_floating(int argc, char **argv) { + struct cmd_results *error = NULL; + if (config->reading) return cmd_results_new(CMD_FAILURE, "floating", "Can't be used in config file."); + if ((error = checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1))) { + return error; + } + swayc_t *view = current_container; + bool wants_floating; + if (strcasecmp(argv[0], "enable") == 0) { + wants_floating = true; + } else if (strcasecmp(argv[0], "disable") == 0) { + wants_floating = false; + } else if (strcasecmp(argv[0], "toggle") == 0) { + wants_floating = !view->is_floating; + } else { + return cmd_results_new(CMD_FAILURE, "floating", + "Expected 'floating "); + } + + // Prevent running floating commands on things like workspaces + if (view->type != C_VIEW) { + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } + + // Change from nonfloating to floating + if (!view->is_floating && wants_floating) { + // Remove view from its current location + destroy_container(remove_child(view)); + + // and move it into workspace floating + add_floating(swayc_active_workspace(), view); + view->x = (swayc_active_workspace()->width - view->width)/2; + view->y = (swayc_active_workspace()->height - view->height)/2; + if (view->desired_width != -1) { + view->width = view->desired_width; + } + if (view->desired_height != -1) { + view->height = view->desired_height; + } + arrange_windows(swayc_active_workspace(), -1, -1); + + } else if (view->is_floating && !wants_floating) { + // Delete the view from the floating list and unset its is_floating flag + remove_child(view); + view->is_floating = false; + // Get the properly focused container, and add in the view there + swayc_t *focused = container_under_pointer(); + // If focused is null, it's because the currently focused container is a workspace + if (focused == NULL || focused->is_floating) { + focused = swayc_active_workspace(); + } + set_focused_container(focused); + + sway_log(L_DEBUG, "Non-floating focused container is %p", focused); + + // Case of focused workspace, just create as child of it + if (focused->type == C_WORKSPACE) { + add_child(focused, view); + } + // Regular case, create as sibling of current container + else { + add_sibling(focused, view); + } + // Refocus on the view once its been put back into the layout + view->width = view->height = 0; + arrange_windows(swayc_active_workspace(), -1, -1); + remove_view_from_scratchpad(view); + ipc_event_window(view, "floating"); + } + set_focused_container(view); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/floating_maximum_size.c b/sway/old/commands/floating_maximum_size.c new file mode 100644 index 00000000..5bca4d7c --- /dev/null +++ b/sway/old/commands/floating_maximum_size.c @@ -0,0 +1,38 @@ +#include +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *cmd_floating_maximum_size(int argc, char **argv) { + struct cmd_results *error = NULL; + int32_t width; + int32_t height; + char *ptr; + + if ((error = checkarg(argc, "floating_maximum_size", EXPECTED_EQUAL_TO, 3))) { + return error; + } + width = strtol(argv[0], &ptr, 10); + height = strtol(argv[2], &ptr, 10); + + if (width < -1) { + sway_log(L_DEBUG, "floating_maximum_size invalid width value: '%s'", argv[0]); + + } else { + config->floating_maximum_width = width; + + } + + if (height < -1) { + sway_log(L_DEBUG, "floating_maximum_size invalid height value: '%s'", argv[2]); + } + else { + config->floating_maximum_height = height; + + } + + sway_log(L_DEBUG, "New floating_maximum_size: '%d' x '%d'", config->floating_maximum_width, + config->floating_maximum_height); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/floating_minimum_size.c b/sway/old/commands/floating_minimum_size.c new file mode 100644 index 00000000..ba72454c --- /dev/null +++ b/sway/old/commands/floating_minimum_size.c @@ -0,0 +1,38 @@ +#include +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *cmd_floating_minimum_size(int argc, char **argv) { + struct cmd_results *error = NULL; + int32_t width; + int32_t height; + char *ptr; + + if ((error = checkarg(argc, "floating_minimum_size", EXPECTED_EQUAL_TO, 3))) { + return error; + } + width = strtol(argv[0], &ptr, 10); + height = strtol(argv[2], &ptr, 10); + + if (width <= 0) { + sway_log(L_DEBUG, "floating_minimum_size invalid width value: '%s'", argv[0]); + + } else { + config->floating_minimum_width = width; + + } + + if (height <= 0) { + sway_log(L_DEBUG, "floating_minimum_size invalid height value: '%s'", argv[2]); + } + else { + config->floating_minimum_height = height; + + } + + sway_log(L_DEBUG, "New floating_minimum_size: '%d' x '%d'", config->floating_minimum_width, + config->floating_minimum_height); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/floating_mod.c b/sway/old/commands/floating_mod.c new file mode 100644 index 00000000..b8e81ab9 --- /dev/null +++ b/sway/old/commands/floating_mod.c @@ -0,0 +1,42 @@ +#include +#include +#include "sway/commands.h" +#include "sway/input_state.h" +#include "list.h" +#include "log.h" +#include "stringop.h" +#include "util.h" + +struct cmd_results *cmd_floating_mod(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "floating_modifier", EXPECTED_AT_LEAST, 1))) { + return error; + } + int i; + list_t *split = split_string(argv[0], "+"); + config->floating_mod = 0; + + // set modifier keys + for (i = 0; i < split->length; ++i) { + config->floating_mod |= get_modifier_mask_by_name(split->items[i]); + } + free_flat_list(split); + if (!config->floating_mod) { + error = cmd_results_new(CMD_INVALID, "floating_modifier", "Unknown keys %s", argv[0]); + return error; + } + + if (argc >= 2) { + if (strcasecmp("inverse", argv[1]) == 0) { + config->dragging_key = M_RIGHT_CLICK; + config->resizing_key = M_LEFT_CLICK; + } else if (strcasecmp("normal", argv[1]) == 0) { + config->dragging_key = M_LEFT_CLICK; + config->resizing_key = M_RIGHT_CLICK; + } else { + error = cmd_results_new(CMD_INVALID, "floating_modifier", "Invalid definition %s", argv[1]); + return error; + } + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/floating_scroll.c b/sway/old/commands/floating_scroll.c new file mode 100644 index 00000000..8c50c5bd --- /dev/null +++ b/sway/old/commands/floating_scroll.c @@ -0,0 +1,46 @@ +#define _XOPEN_SOURCE 500 +#include +#include +#include "sway/commands.h" +#include "log.h" +#include "stringop.h" + +struct cmd_results *cmd_floating_scroll(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "floating_scroll", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!strcasecmp("up", argv[0])) { + free(config->floating_scroll_up_cmd); + if (argc < 2) { + config->floating_scroll_up_cmd = strdup(""); + } else { + config->floating_scroll_up_cmd = join_args(argv + 1, argc - 1); + } + } else if (!strcasecmp("down", argv[0])) { + free(config->floating_scroll_down_cmd); + if (argc < 2) { + config->floating_scroll_down_cmd = strdup(""); + } else { + config->floating_scroll_down_cmd = join_args(argv + 1, argc - 1); + } + } else if (!strcasecmp("left", argv[0])) { + free(config->floating_scroll_left_cmd); + if (argc < 2) { + config->floating_scroll_left_cmd = strdup(""); + } else { + config->floating_scroll_left_cmd = join_args(argv + 1, argc - 1); + } + } else if (!strcasecmp("right", argv[0])) { + free(config->floating_scroll_right_cmd); + if (argc < 2) { + config->floating_scroll_right_cmd = strdup(""); + } else { + config->floating_scroll_right_cmd = join_args(argv + 1, argc - 1); + } + } else { + error = cmd_results_new(CMD_INVALID, "floating_scroll", "Unknown command: '%s'", argv[0]); + return error; + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/focus.c b/sway/old/commands/focus.c new file mode 100644 index 00000000..c83157b8 --- /dev/null +++ b/sway/old/commands/focus.c @@ -0,0 +1,100 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include "sway/commands.h" +#include "sway/container.h" +#include "sway/focus.h" +#include "sway/input_state.h" +#include "sway/output.h" +#include "sway/workspace.h" + +struct cmd_results *cmd_focus(int argc, char **argv) { + if (config->reading) return cmd_results_new(CMD_FAILURE, "focus", "Can't be used in config file."); + struct cmd_results *error = NULL; + if (argc > 0 && strcasecmp(argv[0], "output") == 0) { + swayc_t *output = NULL; + struct wlc_point abs_pos; + get_absolute_center_position(get_focused_container(&root_container), &abs_pos); + if ((error = checkarg(argc, "focus", EXPECTED_EQUAL_TO, 2))) { + return error; + } else if (!(output = output_by_name(argv[1], &abs_pos))) { + return cmd_results_new(CMD_FAILURE, "focus output", + "Can't find output with name/at direction '%s' @ (%i,%i)", argv[1], abs_pos.x, abs_pos.y); + } else if (!workspace_switch(swayc_active_workspace_for(output))) { + return cmd_results_new(CMD_FAILURE, "focus output", + "Switching to workspace on output '%s' was blocked", argv[1]); + } else if (config->mouse_warping) { + swayc_t *focused = get_focused_view(output); + if (focused && focused->type == C_VIEW) { + center_pointer_on(focused); + } + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } else if (argc == 0) { + set_focused_container(current_container); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } else if ((error = checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1))) { + return error; + } + static int floating_toggled_index = 0; + static int tiled_toggled_index = 0; + if (strcasecmp(argv[0], "left") == 0) { + move_focus(MOVE_LEFT); + } else if (strcasecmp(argv[0], "right") == 0) { + move_focus(MOVE_RIGHT); + } else if (strcasecmp(argv[0], "up") == 0) { + move_focus(MOVE_UP); + } else if (strcasecmp(argv[0], "down") == 0) { + move_focus(MOVE_DOWN); + } else if (strcasecmp(argv[0], "parent") == 0) { + move_focus(MOVE_PARENT); + } else if (strcasecmp(argv[0], "child") == 0) { + move_focus(MOVE_CHILD); + } else if (strcasecmp(argv[0], "next") == 0) { + move_focus(MOVE_NEXT); + } else if (strcasecmp(argv[0], "prev") == 0) { + move_focus(MOVE_PREV); + } else if (strcasecmp(argv[0], "mode_toggle") == 0) { + int i; + swayc_t *workspace = swayc_active_workspace(); + swayc_t *focused = get_focused_view(workspace); + if (focused->is_floating) { + if (workspace->children->length > 0) { + for (i = 0;i < workspace->floating->length; i++) { + if (workspace->floating->items[i] == focused) { + floating_toggled_index = i; + break; + } + } + if (workspace->children->length > tiled_toggled_index) { + set_focused_container(get_focused_view(workspace->children->items[tiled_toggled_index])); + } else { + set_focused_container(get_focused_view(workspace->children->items[0])); + tiled_toggled_index = 0; + } + } + } else { + if (workspace->floating->length > 0) { + for (i = 0;i < workspace->children->length; i++) { + if (workspace->children->items[i] == focused) { + tiled_toggled_index = i; + break; + } + } + if (workspace->floating->length > floating_toggled_index) { + swayc_t *floating = workspace->floating->items[floating_toggled_index]; + set_focused_container(get_focused_view(floating)); + } else { + swayc_t *floating = workspace->floating->items[workspace->floating->length - 1]; + set_focused_container(get_focused_view(floating)); + tiled_toggled_index = workspace->floating->length - 1; + } + } + } + } else { + return cmd_results_new(CMD_INVALID, "focus", + "Expected 'focus ' or 'focus output '"); + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/focus_follows_mouse.c b/sway/old/commands/focus_follows_mouse.c new file mode 100644 index 00000000..7c9c2b13 --- /dev/null +++ b/sway/old/commands/focus_follows_mouse.c @@ -0,0 +1,13 @@ +#include +#include +#include "sway/commands.h" + +struct cmd_results *cmd_focus_follows_mouse(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + config->focus_follows_mouse = !strcasecmp(argv[0], "yes"); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/font.c b/sway/old/commands/font.c new file mode 100644 index 00000000..32994f8a --- /dev/null +++ b/sway/old/commands/font.c @@ -0,0 +1,27 @@ +#define _XOPEN_SOURCE 500 +#include +#include "sway/border.h" +#include "sway/commands.h" +#include "log.h" +#include "stringop.h" + +struct cmd_results *cmd_font(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "font", EXPECTED_AT_LEAST, 1))) { + return error; + } + + char *font = join_args(argv, argc); + free(config->font); + if (strlen(font) > 6 && strncmp("pango:", font, 6) == 0) { + config->font = strdup(font + 6); + free(font); + } else { + config->font = font; + } + + config->font_height = get_font_text_height(config->font); + + sway_log(L_DEBUG, "Settings font %s", config->font); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/for_window.c b/sway/old/commands/for_window.c new file mode 100644 index 00000000..d1fd1641 --- /dev/null +++ b/sway/old/commands/for_window.c @@ -0,0 +1,41 @@ +#define _XOPEN_SOURCE 500 +#include +#include "sway/commands.h" +#include "sway/criteria.h" +#include "list.h" +#include "log.h" +#include "stringop.h" + +struct cmd_results *cmd_for_window(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "for_window", EXPECTED_AT_LEAST, 2))) { + return error; + } + // add command to a criteria/command pair that is run against views when they appear. + char *criteria = argv[0], *cmdlist = join_args(argv + 1, argc - 1); + + struct criteria *crit = malloc(sizeof(struct criteria)); + if (!crit) { + return cmd_results_new(CMD_FAILURE, "for_window", "Unable to allocate criteria"); + } + crit->crit_raw = strdup(criteria); + crit->cmdlist = cmdlist; + crit->tokens = create_list(); + char *err_str = extract_crit_tokens(crit->tokens, crit->crit_raw); + + if (err_str) { + error = cmd_results_new(CMD_INVALID, "for_window", err_str); + free(err_str); + free_criteria(crit); + } else if (crit->tokens->length == 0) { + error = cmd_results_new(CMD_INVALID, "for_window", "Found no name/value pairs in criteria"); + free_criteria(crit); + } else if (list_seq_find(config->criteria, criteria_cmp, crit) != -1) { + sway_log(L_DEBUG, "for_window: Duplicate, skipping."); + free_criteria(crit); + } else { + sway_log(L_DEBUG, "for_window: '%s' -> '%s' added", crit->crit_raw, crit->cmdlist); + list_add(config->criteria, crit); + } + return error ? error : cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/force_focus_wrapping.c b/sway/old/commands/force_focus_wrapping.c new file mode 100644 index 00000000..f19dd163 --- /dev/null +++ b/sway/old/commands/force_focus_wrapping.c @@ -0,0 +1,13 @@ +#include +#include +#include "sway/commands.h" + +struct cmd_results *cmd_force_focus_wrapping(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "force_focus_wrapping", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + config->force_focus_wrapping = !strcasecmp(argv[0], "yes"); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/fullscreen.c b/sway/old/commands/fullscreen.c new file mode 100644 index 00000000..bfff82f9 --- /dev/null +++ b/sway/old/commands/fullscreen.c @@ -0,0 +1,60 @@ +#include +#include +#include +#include "sway/commands.h" +#include "sway/container.h" +#include "sway/focus.h" +#include "sway/ipc-server.h" +#include "sway/layout.h" + +struct cmd_results *cmd_fullscreen(int argc, char **argv) { + struct cmd_results *error = NULL; + if (config->reading) return cmd_results_new(CMD_FAILURE, "fullscreen", "Can't be used in config file."); + if (!config->active) return cmd_results_new(CMD_FAILURE, "fullscreen", "Can only be used when sway is running."); + if ((error = checkarg(argc, "fullscreen", EXPECTED_AT_LEAST, 0))) { + return error; + } + swayc_t *container = current_container; + if(container->type != C_VIEW){ + return cmd_results_new(CMD_INVALID, "fullscreen", "Only views can fullscreen"); + } + swayc_t *workspace = swayc_parent_by_type(container, C_WORKSPACE); + bool current = swayc_is_fullscreen(container); + wlc_view_set_state(container->handle, WLC_BIT_FULLSCREEN, !current); + + if (container->is_floating) { + if (current) { + // set dimensions back to what they were before we fullscreened this + container->x = container->cached_geometry.origin.x; + container->y = container->cached_geometry.origin.y; + container->width = container->cached_geometry.size.w; + container->height = container->cached_geometry.size.h; + } else { + // cache dimensions so we can reset them after we "unfullscreen" this + struct wlc_geometry geo = { + .origin = { + .x = container->x, + .y = container->y + }, + .size = { + .w = container->width, + .h = container->height + } + }; + container->cached_geometry = geo; + } + } + + // Resize workspace if going from fullscreen -> notfullscreen + // otherwise just resize container + if (!current) { + arrange_windows(workspace, -1, -1); + workspace->fullscreen = container; + } else { + arrange_windows(container, -1, -1); + workspace->fullscreen = NULL; + } + ipc_event_window(container, "fullscreen_mode"); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/gaps.c b/sway/old/commands/gaps.c new file mode 100644 index 00000000..0a48592d --- /dev/null +++ b/sway/old/commands/gaps.c @@ -0,0 +1,166 @@ +#include +#include +#include +#include +#include +#include "sway/commands.h" +#include "sway/container.h" +#include "sway/focus.h" +#include "sway/layout.h" + +struct cmd_results *cmd_gaps(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 1))) { + return error; + } + const char *expected_syntax = + "Expected 'gaps edge_gaps ' or " + "'gaps '"; + const char *amount_str = argv[0]; + // gaps amount + if (argc >= 1 && isdigit(*amount_str)) { + int amount = (int)strtol(amount_str, NULL, 10); + if (errno == ERANGE) { + errno = 0; + return cmd_results_new(CMD_INVALID, "gaps", "Number is out out of range."); + } + config->gaps_inner = config->gaps_outer = amount; + arrange_windows(&root_container, -1, -1); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } + // gaps inner|outer n + else if (argc >= 2 && isdigit((amount_str = argv[1])[0])) { + int amount = (int)strtol(amount_str, NULL, 10); + if (errno == ERANGE) { + errno = 0; + return cmd_results_new(CMD_INVALID, "gaps", "Number is out out of range."); + } + const char *target_str = argv[0]; + if (strcasecmp(target_str, "inner") == 0) { + config->gaps_inner = amount; + } else if (strcasecmp(target_str, "outer") == 0) { + config->gaps_outer = amount; + } + arrange_windows(&root_container, -1, -1); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } else if (argc == 2 && strcasecmp(argv[0], "edge_gaps") == 0) { + // gaps edge_gaps + if (strcasecmp(argv[1], "toggle") == 0) { + if (config->reading) { + return cmd_results_new(CMD_FAILURE, "gaps edge_gaps toggle", + "Can't be used in config file."); + } + config->edge_gaps = !config->edge_gaps; + } else { + config->edge_gaps = + (strcasecmp(argv[1], "yes") == 0 || strcasecmp(argv[1], "on") == 0); + } + arrange_windows(&root_container, -1, -1); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } + // gaps inner|outer current|all set|plus|minus n + if (argc < 4 || config->reading) { + return cmd_results_new(CMD_INVALID, "gaps", expected_syntax); + } + // gaps inner|outer ... + const char *inout_str = argv[0]; + enum {INNER, OUTER} inout; + if (strcasecmp(inout_str, "inner") == 0) { + inout = INNER; + } else if (strcasecmp(inout_str, "outer") == 0) { + inout = OUTER; + } else { + return cmd_results_new(CMD_INVALID, "gaps", expected_syntax); + } + + // gaps ... current|all ... + const char *target_str = argv[1]; + enum {CURRENT, WORKSPACE, ALL} target; + if (strcasecmp(target_str, "current") == 0) { + target = CURRENT; + } else if (strcasecmp(target_str, "all") == 0) { + target = ALL; + } else if (strcasecmp(target_str, "workspace") == 0) { + if (inout == OUTER) { + target = CURRENT; + } else { + // Set gap for views in workspace + target = WORKSPACE; + } + } else { + return cmd_results_new(CMD_INVALID, "gaps", expected_syntax); + } + + // gaps ... n + amount_str = argv[3]; + int amount = (int)strtol(amount_str, NULL, 10); + if (errno == ERANGE) { + errno = 0; + return cmd_results_new(CMD_INVALID, "gaps", "Number is out out of range."); + } + + // gaps ... set|plus|minus ... + const char *method_str = argv[2]; + enum {SET, ADD} method; + if (strcasecmp(method_str, "set") == 0) { + method = SET; + } else if (strcasecmp(method_str, "plus") == 0) { + method = ADD; + } else if (strcasecmp(method_str, "minus") == 0) { + method = ADD; + amount *= -1; + } else { + return cmd_results_new(CMD_INVALID, "gaps", expected_syntax); + } + + if (target == CURRENT) { + swayc_t *cont; + if (inout == OUTER) { + if ((cont = swayc_active_workspace()) == NULL) { + return cmd_results_new(CMD_FAILURE, "gaps", "There's no active workspace."); + } + } else { + if ((cont = get_focused_view(&root_container))->type != C_VIEW) { + return cmd_results_new(CMD_FAILURE, "gaps", "Currently focused item is not a view."); + } + } + cont->gaps = swayc_gap(cont); + if (method == SET) { + cont->gaps = amount; + } else if ((cont->gaps += amount) < 0) { + cont->gaps = 0; + } + arrange_windows(cont->parent, -1, -1); + } else if (inout == OUTER) { + //resize all workspace. + int i,j; + for (i = 0; i < root_container.children->length; ++i) { + swayc_t *op = root_container.children->items[i]; + for (j = 0; j < op->children->length; ++j) { + swayc_t *ws = op->children->items[j]; + if (method == SET) { + ws->gaps = amount; + } else if ((ws->gaps += amount) < 0) { + ws->gaps = 0; + } + } + } + arrange_windows(&root_container, -1, -1); + } else { + // Resize gaps for all views in workspace + swayc_t *top; + if (target == WORKSPACE) { + if ((top = swayc_active_workspace()) == NULL) { + return cmd_results_new(CMD_FAILURE, "gaps", "There's currently no active workspace."); + } + } else { + top = &root_container; + } + int top_gap = top->gaps; + container_map(top, method == SET ? set_gaps : add_gaps, &amount); + top->gaps = top_gap; + arrange_windows(top, -1, -1); + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/hide_edge_borders.c b/sway/old/commands/hide_edge_borders.c new file mode 100644 index 00000000..ee2a2644 --- /dev/null +++ b/sway/old/commands/hide_edge_borders.c @@ -0,0 +1,27 @@ +#include +#include +#include "sway/commands.h" + +struct cmd_results *cmd_hide_edge_borders(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "hide_edge_borders", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (strcasecmp(argv[0], "none") == 0) { + config->hide_edge_borders = E_NONE; + } else if (strcasecmp(argv[0], "vertical") == 0) { + config->hide_edge_borders = E_VERTICAL; + } else if (strcasecmp(argv[0], "horizontal") == 0) { + config->hide_edge_borders = E_HORIZONTAL; + } else if (strcasecmp(argv[0], "both") == 0) { + config->hide_edge_borders = E_BOTH; + } else if (strcasecmp(argv[0], "smart") == 0) { + config->hide_edge_borders = E_SMART; + } else { + return cmd_results_new(CMD_INVALID, "hide_edge_borders", + "Expected 'hide_edge_borders '"); + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/include.c b/sway/old/commands/include.c new file mode 100644 index 00000000..1ba9a10d --- /dev/null +++ b/sway/old/commands/include.c @@ -0,0 +1,15 @@ +#include "sway/commands.h" +#include "sway/config.h" + +struct cmd_results *cmd_include(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "include", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!load_include_configs(argv[0], config)) { + return cmd_results_new(CMD_INVALID, "include", "Failed to include sub configuration file: %s", argv[0]); + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/input.c b/sway/old/commands/input.c new file mode 100644 index 00000000..ad53d272 --- /dev/null +++ b/sway/old/commands/input.c @@ -0,0 +1,55 @@ +#include +#include +#include "sway/commands.h" +#include "sway/input.h" +#include "log.h" + +struct cmd_results *cmd_input(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "input", EXPECTED_AT_LEAST, 2))) { + return error; + } + + if (config->reading && strcmp("{", argv[1]) == 0) { + current_input_config = new_input_config(argv[0]); + sway_log(L_DEBUG, "entering input block: %s", current_input_config->identifier); + return cmd_results_new(CMD_BLOCK_INPUT, NULL, NULL); + } + + if (argc > 2) { + int argc_new = argc-2; + char **argv_new = argv+2; + + struct cmd_results *res; + current_input_config = new_input_config(argv[0]); + if (strcasecmp("accel_profile", argv[1]) == 0) { + res = input_cmd_accel_profile(argc_new, argv_new); + } else if (strcasecmp("click_method", argv[1]) == 0) { + res = input_cmd_click_method(argc_new, argv_new); + } else if (strcasecmp("drag_lock", argv[1]) == 0) { + res = input_cmd_drag_lock(argc_new, argv_new); + } else if (strcasecmp("dwt", argv[1]) == 0) { + res = input_cmd_dwt(argc_new, argv_new); + } else if (strcasecmp("events", argv[1]) == 0) { + res = input_cmd_events(argc_new, argv_new); + } else if (strcasecmp("left_handed", argv[1]) == 0) { + res = input_cmd_left_handed(argc_new, argv_new); + } else if (strcasecmp("middle_emulation", argv[1]) == 0) { + res = input_cmd_middle_emulation(argc_new, argv_new); + } else if (strcasecmp("natural_scroll", argv[1]) == 0) { + res = input_cmd_natural_scroll(argc_new, argv_new); + } else if (strcasecmp("pointer_accel", argv[1]) == 0) { + res = input_cmd_pointer_accel(argc_new, argv_new); + } else if (strcasecmp("scroll_method", argv[1]) == 0) { + res = input_cmd_scroll_method(argc_new, argv_new); + } else if (strcasecmp("tap", argv[1]) == 0) { + res = input_cmd_tap(argc_new, argv_new); + } else { + res = cmd_results_new(CMD_INVALID, "input ", "Unknown command %s", argv[1]); + } + current_input_config = NULL; + return res; + } + + return cmd_results_new(CMD_BLOCK_INPUT, NULL, NULL); +} diff --git a/sway/old/commands/input/accel_profile.c b/sway/old/commands/input/accel_profile.c new file mode 100644 index 00000000..8288c1ad --- /dev/null +++ b/sway/old/commands/input/accel_profile.c @@ -0,0 +1,27 @@ +#include +#include +#include "sway/commands.h" +#include "sway/input.h" + +struct cmd_results *input_cmd_accel_profile(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "accel_profile", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "accel_profile", "No input device defined."); + } + struct input_config *new_config = new_input_config(current_input_config->identifier); + + if (strcasecmp(argv[0], "adaptive") == 0) { + new_config->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE; + } else if (strcasecmp(argv[0], "flat") == 0) { + new_config->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT; + } else { + return cmd_results_new(CMD_INVALID, "accel_profile", + "Expected 'accel_profile '"); + } + + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/input/click_method.c b/sway/old/commands/input/click_method.c new file mode 100644 index 00000000..5e9d3dcb --- /dev/null +++ b/sway/old/commands/input/click_method.c @@ -0,0 +1,30 @@ +#include +#include +#include "sway/commands.h" +#include "sway/input.h" +#include "log.h" + +struct cmd_results *input_cmd_click_method(int argc, char **argv) { + sway_log(L_DEBUG, "click_method for device: %d %s", current_input_config==NULL, current_input_config->identifier); + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "click_method", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "click_method", "No input device defined."); + } + struct input_config *new_config = new_input_config(current_input_config->identifier); + + if (strcasecmp(argv[0], "none") == 0) { + new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_NONE; + } else if (strcasecmp(argv[0], "button_areas") == 0) { + new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS; + } else if (strcasecmp(argv[0], "clickfinger") == 0) { + new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER; + } else { + return cmd_results_new(CMD_INVALID, "click_method", "Expected 'click_method +#include +#include "sway/commands.h" +#include "sway/input.h" + +struct cmd_results *input_cmd_drag_lock(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "drag_lock", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "drag_lock", "No input device defined."); + } + struct input_config *new_config = new_input_config(current_input_config->identifier); + + if (strcasecmp(argv[0], "enabled") == 0) { + new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED; + } else if (strcasecmp(argv[0], "disabled") == 0) { + new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_DISABLED; + } else { + return cmd_results_new(CMD_INVALID, "drag_lock", "Expected 'drag_lock '"); + } + + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/input/dwt.c b/sway/old/commands/input/dwt.c new file mode 100644 index 00000000..557b2207 --- /dev/null +++ b/sway/old/commands/input/dwt.c @@ -0,0 +1,26 @@ +#include +#include +#include "sway/commands.h" +#include "sway/input.h" + +struct cmd_results *input_cmd_dwt(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "dwt", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "dwt", "No input device defined."); + } + struct input_config *new_config = new_input_config(current_input_config->identifier); + + if (strcasecmp(argv[0], "enabled") == 0) { + new_config->dwt = LIBINPUT_CONFIG_DWT_ENABLED; + } else if (strcasecmp(argv[0], "disabled") == 0) { + new_config->dwt = LIBINPUT_CONFIG_DWT_DISABLED; + } else { + return cmd_results_new(CMD_INVALID, "dwt", "Expected 'dwt '"); + } + + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/input/events.c b/sway/old/commands/input/events.c new file mode 100644 index 00000000..9d54287a --- /dev/null +++ b/sway/old/commands/input/events.c @@ -0,0 +1,30 @@ +#include +#include +#include "sway/commands.h" +#include "sway/input.h" +#include "log.h" + +struct cmd_results *input_cmd_events(int argc, char **argv) { + sway_log(L_DEBUG, "events for device: %s", current_input_config->identifier); + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "events", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "events", "No input device defined."); + } + struct input_config *new_config = new_input_config(current_input_config->identifier); + + if (strcasecmp(argv[0], "enabled") == 0) { + new_config->send_events = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; + } else if (strcasecmp(argv[0], "disabled") == 0) { + new_config->send_events = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED; + } else if (strcasecmp(argv[0], "disabled_on_external_mouse") == 0) { + new_config->send_events = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE; + } else { + return cmd_results_new(CMD_INVALID, "events", "Expected 'events '"); + } + + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/input/left_handed.c b/sway/old/commands/input/left_handed.c new file mode 100644 index 00000000..6c913e70 --- /dev/null +++ b/sway/old/commands/input/left_handed.c @@ -0,0 +1,26 @@ +#include +#include +#include "sway/commands.h" +#include "sway/input.h" + +struct cmd_results *input_cmd_left_handed(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "left_handed", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "left_handed", "No input device defined."); + } + struct input_config *new_config = new_input_config(current_input_config->identifier); + + if (strcasecmp(argv[0], "enabled") == 0) { + new_config->left_handed = 1; + } else if (strcasecmp(argv[0], "disabled") == 0) { + new_config->left_handed = 0; + } else { + return cmd_results_new(CMD_INVALID, "left_handed", "Expected 'left_handed '"); + } + + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/input/middle_emulation.c b/sway/old/commands/input/middle_emulation.c new file mode 100644 index 00000000..33cdd7d6 --- /dev/null +++ b/sway/old/commands/input/middle_emulation.c @@ -0,0 +1,26 @@ +#include +#include +#include "sway/commands.h" +#include "sway/input.h" + +struct cmd_results *input_cmd_middle_emulation(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "middle_emulation", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "middle_emulation", "No input device defined."); + } + struct input_config *new_config = new_input_config(current_input_config->identifier); + + if (strcasecmp(argv[0], "enabled") == 0) { + new_config->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED; + } else if (strcasecmp(argv[0], "disabled") == 0) { + new_config->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED; + } else { + return cmd_results_new(CMD_INVALID, "middle_emulation", "Expected 'middle_emulation '"); + } + + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/input/natural_scroll.c b/sway/old/commands/input/natural_scroll.c new file mode 100644 index 00000000..7bc8b8d0 --- /dev/null +++ b/sway/old/commands/input/natural_scroll.c @@ -0,0 +1,26 @@ +#include +#include +#include "sway/commands.h" +#include "sway/input.h" + +struct cmd_results *input_cmd_natural_scroll(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "natural_scroll", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "natural_scoll", "No input device defined."); + } + struct input_config *new_config = new_input_config(current_input_config->identifier); + + if (strcasecmp(argv[0], "enabled") == 0) { + new_config->natural_scroll = 1; + } else if (strcasecmp(argv[0], "disabled") == 0) { + new_config->natural_scroll = 0; + } else { + return cmd_results_new(CMD_INVALID, "natural_scroll", "Expected 'natural_scroll '"); + } + + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/input/pointer_accel.c b/sway/old/commands/input/pointer_accel.c new file mode 100644 index 00000000..94f595d1 --- /dev/null +++ b/sway/old/commands/input/pointer_accel.c @@ -0,0 +1,24 @@ +#include +#include +#include "sway/commands.h" +#include "sway/input.h" + +struct cmd_results *input_cmd_pointer_accel(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "pointer_accel", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "pointer_accel", "No input device defined."); + } + struct input_config *new_config = new_input_config(current_input_config->identifier); + + float pointer_accel = atof(argv[0]); + if (pointer_accel < -1 || pointer_accel > 1) { + return cmd_results_new(CMD_INVALID, "pointer_accel", "Input out of range [-1, 1]"); + } + new_config->pointer_accel = pointer_accel; + + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/input/scroll_method.c b/sway/old/commands/input/scroll_method.c new file mode 100644 index 00000000..5c6c3d7a --- /dev/null +++ b/sway/old/commands/input/scroll_method.c @@ -0,0 +1,30 @@ +#include +#include +#include "sway/commands.h" +#include "sway/input.h" + +struct cmd_results *input_cmd_scroll_method(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "scroll_method", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "scroll_method", "No input device defined."); + } + struct input_config *new_config = new_input_config(current_input_config->identifier); + + if (strcasecmp(argv[0], "none") == 0) { + new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_NO_SCROLL; + } else if (strcasecmp(argv[0], "two_finger") == 0) { + new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_2FG; + } else if (strcasecmp(argv[0], "edge") == 0) { + new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_EDGE; + } else if (strcasecmp(argv[0], "on_button_down") == 0) { + new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN; + } else { + return cmd_results_new(CMD_INVALID, "scroll_method", "Expected 'scroll_method '"); + } + + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/input/tap.c b/sway/old/commands/input/tap.c new file mode 100644 index 00000000..9e3ca2af --- /dev/null +++ b/sway/old/commands/input/tap.c @@ -0,0 +1,29 @@ +#include +#include +#include "sway/commands.h" +#include "sway/input.h" +#include "log.h" + +struct cmd_results *input_cmd_tap(int argc, char **argv) { + sway_log(L_DEBUG, "tap for device: %s", current_input_config->identifier); + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "tap", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "tap", "No input device defined."); + } + struct input_config *new_config = new_input_config(current_input_config->identifier); + + if (strcasecmp(argv[0], "enabled") == 0) { + new_config->tap = LIBINPUT_CONFIG_TAP_ENABLED; + } else if (strcasecmp(argv[0], "disabled") == 0) { + new_config->tap = LIBINPUT_CONFIG_TAP_DISABLED; + } else { + return cmd_results_new(CMD_INVALID, "tap", "Expected 'tap '"); + } + + sway_log(L_DEBUG, "apply-tap for device: %s", current_input_config->identifier); + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/ipc.c b/sway/old/commands/ipc.c new file mode 100644 index 00000000..0c678961 --- /dev/null +++ b/sway/old/commands/ipc.c @@ -0,0 +1,162 @@ +#define _XOPEN_SOURCE 500 +#include +#include +#include "sway/security.h" +#include "sway/commands.h" +#include "sway/config.h" +#include "ipc.h" +#include "log.h" +#include "util.h" + +static struct ipc_policy *current_policy = NULL; + +struct cmd_results *cmd_ipc(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "ipc", EXPECTED_EQUAL_TO, 2))) { + return error; + } + if ((error = check_security_config())) { + return error; + } + + char *program = NULL; + + if (!strcmp(argv[0], "*")) { + program = strdup(argv[0]); + } else if (!(program = resolve_path(argv[0]))) { + return cmd_results_new( + CMD_INVALID, "ipc", "Unable to resolve IPC Policy target."); + } + if (config->reading && strcmp("{", argv[1]) != 0) { + return cmd_results_new(CMD_INVALID, "ipc", + "Expected '{' at start of IPC config definition."); + } + + if (!config->reading) { + return cmd_results_new(CMD_FAILURE, "ipc", "Can only be used in config file."); + } + + current_policy = alloc_ipc_policy(program); + list_add(config->ipc_policies, current_policy); + + free(program); + return cmd_results_new(CMD_BLOCK_IPC, NULL, NULL); +} + +struct cmd_results *cmd_ipc_events(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "events", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (config->reading && strcmp("{", argv[0]) != 0) { + return cmd_results_new(CMD_INVALID, "events", + "Expected '{' at start of IPC event config definition."); + } + + if (!config->reading) { + return cmd_results_new(CMD_FAILURE, "events", "Can only be used in config file."); + } + + return cmd_results_new(CMD_BLOCK_IPC_EVENTS, NULL, NULL); +} + +struct cmd_results *cmd_ipc_cmd(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "ipc", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + bool enabled; + if (strcmp(argv[0], "enabled") == 0) { + enabled = true; + } else if (strcmp(argv[0], "disabled") == 0) { + enabled = false; + } else { + return cmd_results_new(CMD_INVALID, argv[-1], + "Argument must be one of 'enabled' or 'disabled'"); + } + + struct { + char *name; + enum ipc_feature type; + } types[] = { + { "*", IPC_FEATURE_ALL_COMMANDS }, + { "command", IPC_FEATURE_COMMAND }, + { "workspaces", IPC_FEATURE_GET_WORKSPACES }, + { "outputs", IPC_FEATURE_GET_OUTPUTS }, + { "tree", IPC_FEATURE_GET_TREE }, + { "marks", IPC_FEATURE_GET_MARKS }, + { "bar-config", IPC_FEATURE_GET_BAR_CONFIG }, + { "inputs", IPC_FEATURE_GET_INPUTS }, + { "clipboard", IPC_FEATURE_GET_CLIPBOARD }, + }; + + uint32_t type = 0; + + for (size_t i = 0; i < sizeof(types) / sizeof(types[0]); ++i) { + if (strcmp(types[i].name, argv[-1]) == 0) { + type = types[i].type; + break; + } + } + + if (enabled) { + current_policy->features |= type; + sway_log(L_DEBUG, "Enabled IPC %s feature", argv[-1]); + } else { + current_policy->features &= ~type; + sway_log(L_DEBUG, "Disabled IPC %s feature", argv[-1]); + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +struct cmd_results *cmd_ipc_event_cmd(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "ipc", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + bool enabled; + if (strcmp(argv[0], "enabled") == 0) { + enabled = true; + } else if (strcmp(argv[0], "disabled") == 0) { + enabled = false; + } else { + return cmd_results_new(CMD_INVALID, argv[-1], + "Argument must be one of 'enabled' or 'disabled'"); + } + + struct { + char *name; + enum ipc_feature type; + } types[] = { + { "*", IPC_FEATURE_ALL_EVENTS }, + { "workspace", IPC_FEATURE_EVENT_WORKSPACE }, + { "output", IPC_FEATURE_EVENT_OUTPUT }, + { "mode", IPC_FEATURE_EVENT_MODE }, + { "window", IPC_FEATURE_EVENT_WINDOW }, + { "binding", IPC_FEATURE_EVENT_BINDING }, + { "input", IPC_FEATURE_EVENT_INPUT }, + }; + + uint32_t type = 0; + + for (size_t i = 0; i < sizeof(types) / sizeof(types[0]); ++i) { + if (strcmp(types[i].name, argv[-1]) == 0) { + type = types[i].type; + break; + } + } + + if (enabled) { + current_policy->features |= type; + sway_log(L_DEBUG, "Enabled IPC %s event", argv[-1]); + } else { + current_policy->features &= ~type; + sway_log(L_DEBUG, "Disabled IPC %s event", argv[-1]); + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/kill.c b/sway/old/commands/kill.c new file mode 100644 index 00000000..742e2b86 --- /dev/null +++ b/sway/old/commands/kill.c @@ -0,0 +1,12 @@ +#include "sway/commands.h" +#include "sway/container.h" +#include "sway/focus.h" + +struct cmd_results *cmd_kill(int argc, char **argv) { + if (config->reading) return cmd_results_new(CMD_FAILURE, "kill", "Can't be used in config file."); + if (!config->active) return cmd_results_new(CMD_FAILURE, "kill", "Can only be used when sway is running."); + + swayc_t *container = current_container; + close_views(container); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/layout.c b/sway/old/commands/layout.c new file mode 100644 index 00000000..57a86565 --- /dev/null +++ b/sway/old/commands/layout.c @@ -0,0 +1,196 @@ +#include +#include +#include "sway/commands.h" +#include "sway/container.h" +#include "sway/layout.h" + +/** + * handle "layout auto" command group + */ +static struct cmd_results *cmd_layout_auto(swayc_t *container, int argc, char **argv); + +struct cmd_results *cmd_layout(int argc, char **argv) { + struct cmd_results *error = NULL; + if (config->reading) return cmd_results_new(CMD_FAILURE, "layout", "Can't be used in config file."); + if (!config->active) return cmd_results_new(CMD_FAILURE, "layout", "Can only be used when sway is running."); + if ((error = checkarg(argc, "layout", EXPECTED_MORE_THAN, 0))) { + return error; + } + swayc_t *parent = current_container; + if (parent->is_floating) { + return cmd_results_new(CMD_FAILURE, "layout", "Unable to change layout of floating windows"); + } + + while (parent->type == C_VIEW) { + parent = parent->parent; + } + + enum swayc_layouts old_layout = parent->layout; + + if (strcasecmp(argv[0], "default") == 0) { + swayc_change_layout(parent, parent->prev_layout); + if (parent->layout == L_NONE) { + swayc_t *output = swayc_parent_by_type(parent, C_OUTPUT); + swayc_change_layout(parent, default_layout(output)); + } + } else { + if (parent->layout != L_TABBED && parent->layout != L_STACKED) { + parent->prev_layout = parent->layout; + } + + if (strcasecmp(argv[0], "tabbed") == 0) { + if (parent->type != C_CONTAINER && !swayc_is_empty_workspace(parent)){ + parent = new_container(parent, L_TABBED); + } + + swayc_change_layout(parent, L_TABBED); + } else if (strcasecmp(argv[0], "stacking") == 0) { + if (parent->type != C_CONTAINER && !swayc_is_empty_workspace(parent)) { + parent = new_container(parent, L_STACKED); + } + + swayc_change_layout(parent, L_STACKED); + } else if (strcasecmp(argv[0], "splith") == 0) { + swayc_change_layout(parent, L_HORIZ); + } else if (strcasecmp(argv[0], "splitv") == 0) { + swayc_change_layout(parent, L_VERT); + } else if (strcasecmp(argv[0], "toggle") == 0 && argc == 2 && strcasecmp(argv[1], "split") == 0) { + if (parent->layout == L_HORIZ && (parent->workspace_layout == L_NONE + || parent->workspace_layout == L_HORIZ)) { + swayc_change_layout(parent, L_VERT); + } else { + swayc_change_layout(parent, L_HORIZ); + } + } else if (strcasecmp(argv[0], "auto") == 0) { + return cmd_layout_auto(parent, argc, argv); + } + } + + update_layout_geometry(parent, old_layout); + update_geometry(parent); + + arrange_windows(parent, parent->width, parent->height); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +static struct cmd_results *cmd_layout_auto(swayc_t *container, int argc, char **argv) { + // called after checking that argv[0] is auto, so just continue parsing from there + struct cmd_results *error = NULL; + const char *cmd_name = "layout auto"; + const char *set_inc_cmd_name = "layout auto [master|ncol] [set|inc]"; + const char *err_msg = "Allowed arguments are "; + + bool need_layout_update = false; + enum swayc_layouts old_layout = container->layout; + enum swayc_layouts layout = old_layout; + + if ((error = checkarg(argc, "layout auto", EXPECTED_MORE_THAN, 1))) { + return error; + } + + if (strcasecmp(argv[1], "left") == 0) { + layout = L_AUTO_LEFT; + } else if (strcasecmp(argv[1], "right") == 0) { + layout = L_AUTO_RIGHT; + } else if (strcasecmp(argv[1], "top") == 0) { + layout = L_AUTO_TOP; + } else if (strcasecmp(argv[1], "bottom") == 0) { + layout = L_AUTO_BOTTOM; + } else if (strcasecmp(argv[1], "next") == 0) { + if (is_auto_layout(container->layout) && container->layout < L_AUTO_LAST) { + layout = container->layout + 1; + } else { + layout = L_AUTO_FIRST; + } + } else if (strcasecmp(argv[1], "prev") == 0) { + if (is_auto_layout(container->layout) && container->layout > L_AUTO_FIRST) { + layout = container->layout - 1; + } else { + layout = L_AUTO_LAST; + } + } else { + bool is_nmaster; + bool is_set; + if (strcasecmp(argv[1], "master") == 0) { + is_nmaster = true; + } else if (strcasecmp(argv[1], "ncol") == 0) { + is_nmaster = false; + } else { + return cmd_results_new(CMD_INVALID, cmd_name, "Invalid %s command. %s", + cmd_name, err_msg); + } + if ((error = checkarg(argc, "auto ", EXPECTED_EQUAL_TO, 4))) { + return error; + } + if (strcasecmp(argv[2], "set") == 0) { + is_set = true; + } else if (strcasecmp(argv[2], "inc") == 0) { + is_set = false; + } else { + return cmd_results_new(CMD_INVALID, set_inc_cmd_name, "Invalid %s command. %s, " + "Argument must be on of ", + set_inc_cmd_name); + } + char *end; + int n = (int)strtol(argv[3], &end, 10); + if (*end) { + return cmd_results_new(CMD_INVALID, set_inc_cmd_name, "Invalid %s command " + "(argument must be an integer)", set_inc_cmd_name); + } + if (is_auto_layout(container->layout)) { + int inc = 0; /* difference between current master/ncol and requested value */ + if (is_nmaster) { + if (is_set) { + if (n < 0) { + return cmd_results_new(CMD_INVALID, set_inc_cmd_name, "Invalid %s command " + "(master must be >= 0)", set_inc_cmd_name); + } + inc = n - (int)container->nb_master; + } else { /* inc command */ + if ((int)container->nb_master + n >= 0) { + inc = n; + } + } + if (inc) { + for (int i = container->nb_master; + i >= 0 && i < container->children->length + && i != (int)container->nb_master + inc;) { + ((swayc_t *)container->children->items[i])->height = -1; + ((swayc_t *)container->children->items[i])->width = -1; + i += inc > 0 ? 1 : -1; + } + container->nb_master += inc; + need_layout_update = true; + } + } else { /* ncol modification */ + if (is_set) { + if (n <= 0) { + return cmd_results_new(CMD_INVALID, set_inc_cmd_name, "Invalid %s command " + "(ncol must be > 0)", set_inc_cmd_name); + } + inc = n - (int)container->nb_slave_groups; + } else { /* inc command */ + if ((int)container->nb_slave_groups + n > 0) { + inc = n; + } + } + if (inc) { + container->nb_slave_groups += inc; + need_layout_update = true; + } + } + } + } + + if (layout != old_layout) { + swayc_change_layout(container, layout); + update_layout_geometry(container, old_layout); + need_layout_update = true; + } + if (need_layout_update) { + update_geometry(container); + arrange_windows(container, container->width, container->height); + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/log_colors.c b/sway/old/commands/log_colors.c new file mode 100644 index 00000000..815d1942 --- /dev/null +++ b/sway/old/commands/log_colors.c @@ -0,0 +1,22 @@ +#include +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *cmd_log_colors(int argc, char **argv) { + struct cmd_results *error = NULL; + if (!config->reading) return cmd_results_new(CMD_FAILURE, "log_colors", "Can only be used in config file."); + if ((error = checkarg(argc, "log_colors", EXPECTED_EQUAL_TO, 1))) { + return error; + } + if (strcasecmp(argv[0], "no") == 0) { + sway_log_colors(0); + } else if (strcasecmp(argv[0], "yes") == 0) { + sway_log_colors(1); + } else { + error = cmd_results_new(CMD_FAILURE, "log_colors", + "Invalid log_colors command (expected `yes` or `no`, got '%s')", argv[0]); + return error; + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/mark.c b/sway/old/commands/mark.c new file mode 100644 index 00000000..c1d959df --- /dev/null +++ b/sway/old/commands/mark.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include "sway/commands.h" +#include "list.h" +#include "stringop.h" + +static void find_marks_callback(swayc_t *container, void *_mark) { + char *mark = (char *)_mark; + + int index; + if (container->marks && ((index = list_seq_find(container->marks, (int (*)(const void *, const void *))strcmp, mark)) != -1)) { + list_del(container->marks, index); + } +} + +struct cmd_results *cmd_mark(int argc, char **argv) { + struct cmd_results *error = NULL; + if (config->reading) return cmd_results_new(CMD_FAILURE, "mark", "Can't be used in config file."); + if ((error = checkarg(argc, "mark", EXPECTED_AT_LEAST, 1))) { + return error; + } + + swayc_t *view = current_container; + bool add = false; + bool toggle = false; + + if (strcmp(argv[0], "--add") == 0) { + --argc; ++argv; + add = true; + } else if (strcmp(argv[0], "--replace") == 0) { + --argc; ++argv; + } + + if (argc && strcmp(argv[0], "--toggle") == 0) { + --argc; ++argv; + toggle = true; + } + + if (argc) { + char *mark = join_args(argv, argc); + + // Remove all existing marks of this type + container_map(&root_container, find_marks_callback, mark); + + if (view->marks) { + if (add) { + int index; + if ((index = list_seq_find(view->marks, (int (*)(const void *, const void *))strcmp, mark)) != -1) { + if (toggle) { + free(view->marks->items[index]); + list_del(view->marks, index); + + if (0 == view->marks->length) { + list_free(view->marks); + view->marks = NULL; + } + } + free(mark); + } else { + list_add(view->marks, mark); + } + } else { + if (toggle && list_seq_find(view->marks, (int (*)(const void *, const void *))strcmp, mark) != -1) { + // Delete the list + list_foreach(view->marks, free); + list_free(view->marks); + view->marks = NULL; + } else { + // Delete and replace with a new list + list_foreach(view->marks, free); + list_free(view->marks); + + view->marks = create_list(); + list_add(view->marks, mark); + } + } + } else { + view->marks = create_list(); + list_add(view->marks, mark); + } + } else { + return cmd_results_new(CMD_FAILURE, "mark", + "Expected 'mark [--add|--replace] [--toggle] '"); + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/mode.c b/sway/old/commands/mode.c new file mode 100644 index 00000000..d2985c54 --- /dev/null +++ b/sway/old/commands/mode.c @@ -0,0 +1,57 @@ +#define _XOPEN_SOURCE 500 +#include +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/ipc-server.h" +#include "list.h" +#include "log.h" + +struct cmd_results *cmd_mode(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "mode", EXPECTED_AT_LEAST, 1))) { + return error; + } + + const char *mode_name = argv[0]; + bool mode_make = (argc == 2 && strcmp(argv[1], "{") == 0); + if (mode_make) { + if (!config->reading) + return cmd_results_new(CMD_FAILURE, "mode", "Can only be used in config file."); + } + struct sway_mode *mode = NULL; + // Find mode + int i, len = config->modes->length; + for (i = 0; i < len; ++i) { + struct sway_mode *find = config->modes->items[i]; + if (strcasecmp(find->name, mode_name) == 0) { + mode = find; + break; + } + } + // Create mode if it doesn't exist + if (!mode && mode_make) { + mode = malloc(sizeof(struct sway_mode)); + if (!mode) { + return cmd_results_new(CMD_FAILURE, "mode", "Unable to allocate mode"); + } + mode->name = strdup(mode_name); + mode->bindings = create_list(); + list_add(config->modes, mode); + } + if (!mode) { + error = cmd_results_new(CMD_INVALID, "mode", "Unknown mode `%s'", mode_name); + return error; + } + if ((config->reading && mode_make) || (!config->reading && !mode_make)) { + sway_log(L_DEBUG, "Switching to mode `%s'",mode->name); + } + // Set current mode + config->current_mode = mode; + if (!mode_make) { + // trigger IPC mode event + ipc_event_mode(config->current_mode->name); + } + return cmd_results_new(mode_make ? CMD_BLOCK_MODE : CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/mouse_warping.c b/sway/old/commands/mouse_warping.c new file mode 100644 index 00000000..5596d483 --- /dev/null +++ b/sway/old/commands/mouse_warping.c @@ -0,0 +1,17 @@ +#include +#include +#include "sway/commands.h" + +struct cmd_results *cmd_mouse_warping(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "mouse_warping", EXPECTED_EQUAL_TO, 1))) { + return error; + } else if (strcasecmp(argv[0], "output") == 0) { + config->mouse_warping = true; + } else if (strcasecmp(argv[0], "none") == 0) { + config->mouse_warping = false; + } else { + return cmd_results_new(CMD_FAILURE, "mouse_warping", "Expected 'mouse_warping output|none'"); + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/move.c b/sway/old/commands/move.c new file mode 100644 index 00000000..52c73e22 --- /dev/null +++ b/sway/old/commands/move.c @@ -0,0 +1,189 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include "sway/commands.h" +#include "sway/container.h" +#include "sway/layout.h" +#include "sway/output.h" +#include "sway/workspace.h" +#include "list.h" +#include "stringop.h" + +struct cmd_results *cmd_move(int argc, char **argv) { + struct cmd_results *error = NULL; + int move_amt = 10; + + if (config->reading) return cmd_results_new(CMD_FAILURE, "move", "Can't be used in config file."); + if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) { + return error; + } + const char* expected_syntax = "Expected 'move <[px] px>' or " + "'move to workspace ' or " + "'move to output ' or " + "'move position mouse'"; + swayc_t *view = current_container; + + if (argc == 2 || (argc == 3 && strcasecmp(argv[2], "px") == 0 )) { + char *inv; + move_amt = (int)strtol(argv[1], &inv, 10); + if (*inv != '\0' && strcasecmp(inv, "px") != 0) { + move_amt = 10; + } + } + + if (strcasecmp(argv[0], "left") == 0) { + move_container(view, MOVE_LEFT, move_amt); + } else if (strcasecmp(argv[0], "right") == 0) { + move_container(view, MOVE_RIGHT, move_amt); + } else if (strcasecmp(argv[0], "up") == 0) { + move_container(view, MOVE_UP, move_amt); + } else if (strcasecmp(argv[0], "down") == 0) { + move_container(view, MOVE_DOWN, move_amt); + } else if (strcasecmp(argv[0], "next") == 0) { + move_container(view, MOVE_NEXT, move_amt); + } else if (strcasecmp(argv[0], "prev") == 0) { + move_container(view, MOVE_PREV, move_amt); + } else if (strcasecmp(argv[0], "first") == 0) { + move_container(view, MOVE_FIRST, move_amt); + } else if (strcasecmp(argv[0], "container") == 0 || strcasecmp(argv[0], "window") == 0) { + // "move container ... + if ((error = checkarg(argc, "move container/window", EXPECTED_AT_LEAST, 4))) { + return error; + } else if (strcasecmp(argv[1], "to") == 0 && strcasecmp(argv[2], "workspace") == 0) { + // move container to workspace x + if (view->type == C_WORKSPACE) { + if (!view->children || view->children->length == 0) { + return cmd_results_new(CMD_FAILURE, "move", "Cannot move an empty workspace"); + } + view = new_container(view, view->workspace_layout); + } if (view->type != C_CONTAINER && view->type != C_VIEW) { + return cmd_results_new(CMD_FAILURE, "move", "Can only move containers and views."); + } + + swayc_t *ws; + const char *num_name = NULL; + char *ws_name = NULL; + if (argc == 5 && strcasecmp(argv[3], "number") == 0) { + // move "container to workspace number x" + num_name = argv[4]; + ws = workspace_by_number(num_name); + } else { + ws_name = join_args(argv + 3, argc - 3); + ws = workspace_by_name(ws_name); + } + + if (ws == NULL) { + ws = workspace_create(ws_name ? ws_name : num_name); + } + if (ws_name) { + free(ws_name); + } + move_container_to(view, get_focused_container(ws)); + } else if (strcasecmp(argv[1], "to") == 0 && strcasecmp(argv[2], "output") == 0) { + // move container to output x + swayc_t *output = NULL; + struct wlc_point abs_pos; + get_absolute_center_position(view, &abs_pos); + if (view->type == C_WORKSPACE) { + if (!view->children || view->children->length == 0) { + return cmd_results_new(CMD_FAILURE, "move", "Cannot move an empty workspace"); + } + view = new_container(view, view->workspace_layout); + } else if (view->type != C_CONTAINER && view->type != C_VIEW) { + return cmd_results_new(CMD_FAILURE, "move", "Can only move containers and views."); + } else if (!(output = output_by_name(argv[3], &abs_pos))) { + return cmd_results_new(CMD_FAILURE, "move", + "Can't find output with name/direction '%s' @ (%i,%i)", argv[3], abs_pos.x, abs_pos.y); + } + + swayc_t *container = get_focused_container(output); + if (container->is_floating) { + move_container_to(view, container->parent); + } else { + move_container_to(view, container); + } + } else { + return cmd_results_new(CMD_INVALID, "move", expected_syntax); + } + } else if (strcasecmp(argv[0], "workspace") == 0) { + // move workspace (to output x) + swayc_t *output = NULL; + struct wlc_point abs_pos; + get_absolute_center_position(view, &abs_pos); + if ((error = checkarg(argc, "move workspace", EXPECTED_EQUAL_TO, 4))) { + return error; + } else if (strcasecmp(argv[1], "to") != 0 || strcasecmp(argv[2], "output") != 0) { + return cmd_results_new(CMD_INVALID, "move", expected_syntax); + } else if (!(output = output_by_name(argv[3], &abs_pos))) { + return cmd_results_new(CMD_FAILURE, "move workspace", + "Can't find output with name/direction '%s' @ (%i,%i)", argv[3], abs_pos.x, abs_pos.y); + } + if (view->type == C_WORKSPACE) { + // This probably means we're moving an empty workspace, but + // that's fine. + move_workspace_to(view, output); + } else { + swayc_t *workspace = swayc_parent_by_type(view, C_WORKSPACE); + move_workspace_to(workspace, output); + } + } else if (strcasecmp(argv[0], "scratchpad") == 0 || (strcasecmp(argv[0], "to") == 0 && strcasecmp(argv[1], "scratchpad") == 0)) { + // move scratchpad ... + if (view->type != C_CONTAINER && view->type != C_VIEW) { + return cmd_results_new(CMD_FAILURE, "move scratchpad", "Can only move containers and views."); + } + swayc_t *view = current_container; + int i; + for (i = 0; i < scratchpad->length; i++) { + if (scratchpad->items[i] == view) { + hide_view_in_scratchpad(view); + sp_view = NULL; + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } + } + list_add(scratchpad, view); + if (!view->is_floating) { + destroy_container(remove_child(view)); + } else { + remove_child(view); + } + wlc_view_set_mask(view->handle, 0); + arrange_windows(swayc_active_workspace(), -1, -1); + swayc_t *focused = container_under_pointer(); + if (focused == NULL) { + focused = swayc_active_workspace(); + } + set_focused_container(focused); + } else if (strcasecmp(argv[0], "position") == 0) { + if ((error = checkarg(argc, "move workspace", EXPECTED_EQUAL_TO, 2))) { + return error; + } + if (strcasecmp(argv[1], "mouse")) { + return cmd_results_new(CMD_INVALID, "move", expected_syntax); + } + + if (view->is_floating) { + swayc_t *output = swayc_parent_by_type(view, C_OUTPUT); + struct wlc_geometry g; + wlc_view_get_visible_geometry(view->handle, &g); + const struct wlc_size *size = wlc_output_get_resolution(output->handle); + + double x_pos, y_pos; + wlc_pointer_get_position_v2(&x_pos, &y_pos); + + int32_t x = x_pos - g.size.w / 2; + int32_t y = y_pos - g.size.h / 2; + + uint32_t w = size->w - g.size.w; + uint32_t h = size->h - g.size.h; + + view->x = g.origin.x = MIN((int32_t)w, MAX(x, 0)); + view->y = g.origin.y = MIN((int32_t)h, MAX(y, 0)); + + wlc_view_set_geometry(view->handle, 0, &g); + } + } else { + return cmd_results_new(CMD_INVALID, "move", expected_syntax); + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/new_float.c b/sway/old/commands/new_float.c new file mode 100644 index 00000000..d0f96093 --- /dev/null +++ b/sway/old/commands/new_float.c @@ -0,0 +1,8 @@ +#include "log.h" +#include "sway/commands.h" + +struct cmd_results *cmd_new_float(int argc, char **argv) { + sway_log(L_INFO, "`new_float` is deprecated and will be removed in the future. " + "Please use `default_floating_border` instead."); + return cmd_default_floating_border(argc, argv); +} diff --git a/sway/old/commands/new_window.c b/sway/old/commands/new_window.c new file mode 100644 index 00000000..574a4527 --- /dev/null +++ b/sway/old/commands/new_window.c @@ -0,0 +1,8 @@ +#include "log.h" +#include "sway/commands.h" + +struct cmd_results *cmd_new_window(int argc, char **argv) { + sway_log(L_INFO, "`new_window` is deprecated and will be removed in the future. " + "Please use `default_border` instead."); + return cmd_default_border(argc, argv); +} diff --git a/sway/old/commands/no_focus.c b/sway/old/commands/no_focus.c new file mode 100644 index 00000000..b3b88e5a --- /dev/null +++ b/sway/old/commands/no_focus.c @@ -0,0 +1,41 @@ +#define _XOPEN_SOURCE 500 +#include +#include "sway/commands.h" +#include "sway/criteria.h" +#include "list.h" +#include "log.h" +#include "stringop.h" + +struct cmd_results *cmd_no_focus(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "no_focus", EXPECTED_EQUAL_TO, 1))) { + return error; + } + // add command to a criteria/command pair that is run against views when they appear. + char *criteria = argv[0]; + + struct criteria *crit = malloc(sizeof(struct criteria)); + if (!crit) { + return cmd_results_new(CMD_FAILURE, "no_focus", "Unable to allocate criteria"); + } + crit->crit_raw = strdup(criteria); + crit->tokens = create_list(); + crit->cmdlist = NULL; + char *err_str = extract_crit_tokens(crit->tokens, crit->crit_raw); + + if (err_str) { + error = cmd_results_new(CMD_INVALID, "no_focus", err_str); + free(err_str); + free_criteria(crit); + } else if (crit->tokens->length == 0) { + error = cmd_results_new(CMD_INVALID, "no_focus", "Found no name/value pairs in criteria"); + free_criteria(crit); + } else if (list_seq_find(config->no_focus, criteria_cmp, crit) != -1) { + sway_log(L_DEBUG, "no_focus: Duplicate, skipping."); + free_criteria(crit); + } else { + sway_log(L_DEBUG, "no_focus: '%s' added", crit->crit_raw); + list_add(config->no_focus, crit); + } + return error ? error : cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/orientation.c b/sway/old/commands/orientation.c new file mode 100644 index 00000000..e54b60ee --- /dev/null +++ b/sway/old/commands/orientation.c @@ -0,0 +1,21 @@ +#include +#include +#include "sway/commands.h" + +struct cmd_results *cmd_orientation(int argc, char **argv) { + struct cmd_results *error = NULL; + if (!config->reading) return cmd_results_new(CMD_FAILURE, "orientation", "Can only be used in config file."); + if ((error = checkarg(argc, "orientation", EXPECTED_EQUAL_TO, 1))) { + return error; + } + if (strcasecmp(argv[0], "horizontal") == 0) { + config->default_orientation = L_HORIZ; + } else if (strcasecmp(argv[0], "vertical") == 0) { + config->default_orientation = L_VERT; + } else if (strcasecmp(argv[0], "auto") == 0) { + // Do nothing + } else { + return cmd_results_new(CMD_INVALID, "orientation", "Expected 'orientation '"); + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/output.c b/sway/old/commands/output.c new file mode 100644 index 00000000..911391d2 --- /dev/null +++ b/sway/old/commands/output.c @@ -0,0 +1,219 @@ +#define _XOPEN_SOURCE 500 +#include +#include +#include +#include +#include +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "list.h" +#include "log.h" +#include "stringop.h" + +static char *bg_options[] = { + "stretch", + "center", + "fill", + "fit", + "tile" +}; + +struct cmd_results *cmd_output(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "output", EXPECTED_AT_LEAST, 1))) { + return error; + } + const char *name = argv[0]; + + struct output_config *output = calloc(1, sizeof(struct output_config)); + if (!output) { + return cmd_results_new(CMD_FAILURE, "output", "Unable to allocate output config"); + } + output->x = output->y = output->width = output->height = -1; + output->name = strdup(name); + output->enabled = -1; + output->scale = 1; + + // TODO: atoi doesn't handle invalid numbers + + int i; + for (i = 1; i < argc; ++i) { + const char *command = argv[i]; + + if (strcasecmp(command, "disable") == 0) { + output->enabled = 0; + } else if (strcasecmp(command, "resolution") == 0 || strcasecmp(command, "res") == 0) { + if (++i >= argc) { + error = cmd_results_new(CMD_INVALID, "output", "Missing resolution argument."); + goto fail; + } + char *res = argv[i]; + char *x = strchr(res, 'x'); + int width = -1, height = -1; + if (x != NULL) { + // Format is 1234x4321 + *x = '\0'; + width = atoi(res); + height = atoi(x + 1); + *x = 'x'; + } else { + // Format is 1234 4321 + width = atoi(res); + if (++i >= argc) { + error = cmd_results_new(CMD_INVALID, "output", "Missing resolution argument (height)."); + goto fail; + } + res = argv[i]; + height = atoi(res); + } + output->width = width; + output->height = height; + } else if (strcasecmp(command, "position") == 0 || strcasecmp(command, "pos") == 0) { + if (++i >= argc) { + error = cmd_results_new(CMD_INVALID, "output", "Missing position argument."); + goto fail; + } + char *res = argv[i]; + char *c = strchr(res, ','); + int x = -1, y = -1; + if (c != NULL) { + // Format is 1234,4321 + *c = '\0'; + x = atoi(res); + y = atoi(c + 1); + *c = ','; + } else { + // Format is 1234 4321 + x = atoi(res); + if (++i >= argc) { + error = cmd_results_new(CMD_INVALID, "output", "Missing position argument (y)."); + goto fail; + } + res = argv[i]; + y = atoi(res); + } + output->x = x; + output->y = y; + } else if (strcasecmp(command, "scale") == 0) { + if (++i >= argc) { + error = cmd_results_new(CMD_INVALID, "output", "Missing scale parameter."); + goto fail; + } + output->scale = atoi(argv[i]); + } else if (strcasecmp(command, "background") == 0 || strcasecmp(command, "bg") == 0) { + wordexp_t p; + if (++i >= argc) { + error = cmd_results_new(CMD_INVALID, "output", "Missing background file or color specification."); + goto fail; + } + if (i + 1 >= argc) { + error = cmd_results_new(CMD_INVALID, "output", "Missing background scaling mode or `solid_color`."); + goto fail; + } + if (strcasecmp(argv[i + 1], "solid_color") == 0) { + output->background = strdup(argv[argc - 2]); + output->background_option = strdup("solid_color"); + } else { + // argv[i+j]=bg_option + bool valid = false; + char *mode; + size_t j; + for (j = 0; j < (size_t) (argc - i); ++j) { + mode = argv[i + j]; + for (size_t k = 0; k < sizeof(bg_options) / sizeof(char *); ++k) { + if (strcasecmp(mode, bg_options[k]) == 0) { + valid = true; + break; + } + } + if (valid) { + break; + } + } + if (!valid) { + error = cmd_results_new(CMD_INVALID, "output", "Missing background scaling mode."); + goto fail; + } + + char *src = join_args(argv + i, j); + if (wordexp(src, &p, 0) != 0 || p.we_wordv[0] == NULL) { + error = cmd_results_new(CMD_INVALID, "output", "Invalid syntax (%s)", src); + goto fail; + } + free(src); + src = p.we_wordv[0]; + if (config->reading && *src != '/') { + char *conf = strdup(config->current_config); + if (conf) { + char *conf_path = dirname(conf); + src = malloc(strlen(conf_path) + strlen(src) + 2); + if (src) { + sprintf(src, "%s/%s", conf_path, p.we_wordv[0]); + } else { + sway_log(L_ERROR, "Unable to allocate background source"); + } + free(conf); + } else { + sway_log(L_ERROR, "Unable to allocate background source"); + } + } + if (!src || access(src, F_OK) == -1) { + error = cmd_results_new(CMD_INVALID, "output", "Background file unreadable (%s)", src); + wordfree(&p); + goto fail; + } + + output->background = strdup(src); + output->background_option = strdup(mode); + if (src != p.we_wordv[0]) { + free(src); + } + wordfree(&p); + + i += j; + } + } + } + + i = list_seq_find(config->output_configs, output_name_cmp, name); + if (i >= 0) { + // merge existing config + struct output_config *oc = config->output_configs->items[i]; + merge_output_config(oc, output); + free_output_config(output); + output = oc; + } else { + list_add(config->output_configs, output); + } + + sway_log(L_DEBUG, "Config stored for output %s (enabled:%d) (%d x %d @ %d, %d scale %d) (bg %s %s)", + output->name, output->enabled, output->width, + output->height, output->x, output->y, output->scale, + output->background, output->background_option); + + if (output->name) { + // Try to find the output container and apply configuration now. If + // this is during startup then there will be no container and config + // will be applied during normal "new output" event from wlc. + swayc_t *cont = NULL; + for (int i = 0; i < root_container.children->length; ++i) { + cont = root_container.children->items[i]; + if (cont->name && ((strcmp(cont->name, output->name) == 0) || (strcmp(output->name, "*") == 0))) { + apply_output_config(output, cont); + + if (strcmp(output->name, "*") != 0) { + // stop looking if the output config isn't applicable to all outputs + break; + } + } + } + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + +fail: + free_output_config(output); + return error; +} diff --git a/sway/old/commands/permit.c b/sway/old/commands/permit.c new file mode 100644 index 00000000..7a5e06f7 --- /dev/null +++ b/sway/old/commands/permit.c @@ -0,0 +1,108 @@ +#define _XOPEN_SOURCE 500 +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/security.h" +#include "util.h" +#include "log.h" + +static enum secure_feature get_features(int argc, char **argv, + struct cmd_results **error) { + enum secure_feature features = 0; + + struct { + char *name; + enum secure_feature feature; + } feature_names[] = { + { "lock", FEATURE_LOCK }, + { "panel", FEATURE_PANEL }, + { "background", FEATURE_BACKGROUND }, + { "screenshot", FEATURE_SCREENSHOT }, + { "fullscreen", FEATURE_FULLSCREEN }, + { "keyboard", FEATURE_KEYBOARD }, + { "mouse", FEATURE_MOUSE }, + }; + + for (int i = 1; i < argc; ++i) { + size_t j; + for (j = 0; j < sizeof(feature_names) / sizeof(feature_names[0]); ++j) { + if (strcmp(feature_names[j].name, argv[i]) == 0) { + break; + } + } + if (j == sizeof(feature_names) / sizeof(feature_names[0])) { + *error = cmd_results_new(CMD_INVALID, + "permit", "Invalid feature grant %s", argv[i]); + return 0; + } + features |= feature_names[j].feature; + } + return features; +} + +struct cmd_results *cmd_permit(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "permit", EXPECTED_MORE_THAN, 1))) { + return error; + } + if ((error = check_security_config())) { + return error; + } + + bool assign_perms = true; + char *program = NULL; + + if (!strcmp(argv[0], "*")) { + program = strdup(argv[0]); + } else { + program = resolve_path(argv[0]); + } + if (!program) { + sway_assert(program, "Unable to resolve IPC permit target '%s'." + " will issue empty policy", argv[0]); + assign_perms = false; + program = strdup(argv[0]); + } + + struct feature_policy *policy = get_feature_policy(program); + if (policy && assign_perms) { + policy->features |= get_features(argc, argv, &error); + sway_log(L_DEBUG, "Permissions granted to %s for features %d", + policy->program, policy->features); + } + + free(program); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +struct cmd_results *cmd_reject(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "reject", EXPECTED_MORE_THAN, 1))) { + return error; + } + if ((error = check_security_config())) { + return error; + } + + char *program = NULL; + if (!strcmp(argv[0], "*")) { + program = strdup(argv[0]); + } else { + program = resolve_path(argv[0]); + } + if (!program) { + // Punt + sway_log(L_INFO, "Unable to resolve IPC reject target '%s'." + " Will use provided path", argv[0]); + program = strdup(argv[0]); + } + + struct feature_policy *policy = get_feature_policy(program); + policy->features &= ~get_features(argc, argv, &error); + + sway_log(L_DEBUG, "Permissions granted to %s for features %d", + policy->program, policy->features); + + free(program); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/reload.c b/sway/old/commands/reload.c new file mode 100644 index 00000000..01fcc5ba --- /dev/null +++ b/sway/old/commands/reload.c @@ -0,0 +1,19 @@ +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/layout.h" + +struct cmd_results *cmd_reload(int argc, char **argv) { + struct cmd_results *error = NULL; + if (config->reading) return cmd_results_new(CMD_FAILURE, "reload", "Can't be used in config file."); + if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) { + return error; + } + if (!load_main_config(config->current_config, true)) { + return cmd_results_new(CMD_FAILURE, "reload", "Error(s) reloading config."); + } + + load_swaybars(); + + arrange_windows(&root_container, -1, -1); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/resize.c b/sway/old/commands/resize.c new file mode 100644 index 00000000..ef52bb07 --- /dev/null +++ b/sway/old/commands/resize.c @@ -0,0 +1,375 @@ +#include +#include +#include +#include +#include +#include +#include +#include "sway/commands.h" +#include "sway/layout.h" +#include "sway/focus.h" +#include "sway/input_state.h" +#include "sway/handlers.h" +#include "log.h" + +enum resize_dim_types { + RESIZE_DIM_PX, + RESIZE_DIM_PPT, + RESIZE_DIM_DEFAULT, +}; + +static bool set_size_floating(int new_dimension, bool use_width) { + swayc_t *view = current_container; + if (view) { + if (use_width) { + int current_width = view->width; + view->desired_width = new_dimension; + floating_view_sane_size(view); + + int new_x = view->x + (int)(((view->desired_width - current_width) / 2) * -1); + view->width = view->desired_width; + view->x = new_x; + + update_geometry(view); + } else { + int current_height = view->height; + view->desired_height = new_dimension; + floating_view_sane_size(view); + + int new_y = view->y + (int)(((view->desired_height - current_height) / 2) * -1); + view->height = view->desired_height; + view->y = new_y; + + update_geometry(view); + } + + return true; + } + + return false; +} + +static bool resize_floating(int amount, bool use_width) { + swayc_t *view = current_container; + + if (view) { + if (use_width) { + return set_size_floating(view->width + amount, true); + } else { + return set_size_floating(view->height + amount, false); + } + } + + return false; +} + +static bool resize_tiled(int amount, bool use_width) { + swayc_t *container = current_container; + swayc_t *parent = container->parent; + int idx_focused = 0; + bool use_major = false; + size_t nb_before = 0; + size_t nb_after = 0; + + // 1. Identify a container ancestor that will allow the focused child to grow in the requested + // direction. + while (container->parent) { + parent = container->parent; + if ((parent->children && parent->children->length > 1) + && (is_auto_layout(parent->layout) + || (use_width ? parent->layout == L_HORIZ : parent->layout == L_VERT))) { + // check if container has siblings that can provide/absorb the space needed for + // the resize operation. + use_major = use_width + ? parent->layout == L_AUTO_LEFT || parent->layout == L_AUTO_RIGHT + : parent->layout == L_AUTO_TOP || parent->layout == L_AUTO_BOTTOM; + // Note: use_major will be false for L_HORIZ and L_VERT + + idx_focused = index_child(container); + if (idx_focused < 0) { + sway_log(L_ERROR, "Something weird is happening, child container not " + "present in its parent's children list."); + continue; + } + if (use_major) { + nb_before = auto_group_index(parent, idx_focused); + nb_after = auto_group_count(parent) - nb_before - 1; + } else { + nb_before = idx_focused - auto_group_start_index(parent, idx_focused); + nb_after = auto_group_end_index(parent, idx_focused) - idx_focused - 1; + sway_log(L_DEBUG, "+++ focused: %d, start: %d, end: %d, before: %d, after: %d", + idx_focused, + (int)auto_group_start_index(parent, idx_focused), + (int)auto_group_end_index(parent, idx_focused), + (int)nb_before, (int)nb_after); + + } + if (nb_before || nb_after) { + break; + } + } + container = parent; /* continue up the tree to the next ancestor */ + } + if (parent == &root_container) { + return true; + } + sway_log(L_DEBUG, "Found the proper parent: %p. It has %zu before conts, " + "and %zu after conts", parent, nb_before, nb_after); + // 2. Ensure that the resize operation will not make one of the resized containers drop + // below the "sane" size threshold. + bool valid = true; + swayc_t *focused = parent->children->items[idx_focused]; + int start = use_major ? 0 : auto_group_start_index(parent, idx_focused); + int end = use_major ? parent->children->length : auto_group_end_index(parent, idx_focused); + sway_log(L_DEBUG, "Check children of container %p [%d,%d[", container, start, end); + for (int i = start; i < end; ) { + swayc_t *sibling = parent->children->items[i]; + double pixels = amount; + bool is_before = use_width ? sibling->x < focused->x : sibling->y < focused->y; + bool is_after = use_width ? sibling->x > focused->x : sibling->y > focused->y; + if (is_before || is_after) { + pixels = -pixels; + pixels /= is_before ? nb_before : nb_after; + if (nb_after != 0 && nb_before != 0) { + pixels /= 2; + } + } + sway_log(L_DEBUG, "Check container %p: width %g vs %d, height %g vs %d", sibling, sibling->width + pixels, min_sane_w, sibling->height + pixels, min_sane_h); + if (use_width ? + sibling->width + pixels < min_sane_w : + sibling->height + pixels < min_sane_h) { + valid = false; + sway_log(L_DEBUG, "Container size no longer sane"); + break; + } + i = use_major ? auto_group_end_index(parent, i) : (i + 1); + sway_log(L_DEBUG, "+++++ check %i", i); + } + // 3. Apply the size change + if (valid) { + for (int i = start; i < end; ) { + int next_i = use_major ? auto_group_end_index(parent, i) : (i + 1); + swayc_t *sibling = parent->children->items[i]; + double pixels = amount; + bool is_before = use_width ? sibling->x < focused->x : sibling->y < focused->y; + bool is_after = use_width ? sibling->x > focused->x : sibling->y > focused->y; + if (is_before || is_after) { + pixels = -pixels; + pixels /= is_before ? nb_before : nb_after; + if (nb_after != 0 && nb_before != 0) { + pixels /= 2; + } + sway_log(L_DEBUG, "%p: %s", sibling, is_before ? "before" : "after"); + if (use_major) { + for (int j = i; j < next_i; ++j) { + recursive_resize(parent->children->items[j], pixels, + use_width ? + (is_before ? WLC_RESIZE_EDGE_RIGHT : WLC_RESIZE_EDGE_LEFT) : + (is_before ? WLC_RESIZE_EDGE_BOTTOM : WLC_RESIZE_EDGE_TOP)); + } + } else { + recursive_resize(sibling, pixels, + use_width ? + (is_before ? WLC_RESIZE_EDGE_RIGHT : WLC_RESIZE_EDGE_LEFT) : + (is_before ? WLC_RESIZE_EDGE_BOTTOM : WLC_RESIZE_EDGE_TOP)); + } + } else { + if (use_major) { + for (int j = i; j < next_i; ++j) { + recursive_resize(parent->children->items[j], pixels / 2, + use_width ? WLC_RESIZE_EDGE_LEFT : WLC_RESIZE_EDGE_TOP); + recursive_resize(parent->children->items[j], pixels / 2, + use_width ? WLC_RESIZE_EDGE_RIGHT : WLC_RESIZE_EDGE_BOTTOM); + } + } else { + recursive_resize(sibling, pixels / 2, + use_width ? WLC_RESIZE_EDGE_LEFT : WLC_RESIZE_EDGE_TOP); + recursive_resize(sibling, pixels / 2, + use_width ? WLC_RESIZE_EDGE_RIGHT : WLC_RESIZE_EDGE_BOTTOM); + } + } + i = next_i; + } + // Recursive resize does not handle positions, let arrange_windows + // take care of that. + arrange_windows(swayc_active_workspace(), -1, -1); + } + return true; +} + +static bool set_size_tiled(int amount, bool use_width) { + int desired; + swayc_t *focused = current_container; + + if (use_width) { + desired = amount - focused->width; + } else { + desired = amount - focused->height; + } + + return resize_tiled(desired, use_width); +} + +static bool set_size(int dimension, bool use_width) { + swayc_t *focused = current_container; + + if (focused) { + if (focused->is_floating) { + return set_size_floating(dimension, use_width); + } else { + return set_size_tiled(dimension, use_width); + } + } + + return false; +} + +static bool resize(int dimension, bool use_width, enum resize_dim_types dim_type) { + swayc_t *focused = current_container; + + // translate "10 ppt" (10%) to appropriate # of pixels in case we need it + float ppt_dim = (float)dimension / 100; + + if (use_width) { + ppt_dim = focused->width * ppt_dim; + } else { + ppt_dim = focused->height * ppt_dim; + } + + if (focused) { + if (focused->is_floating) { + // floating view resize dimensions should default to px, so only + // use ppt if specified + if (dim_type == RESIZE_DIM_PPT) { + dimension = (int)ppt_dim; + } + + return resize_floating(dimension, use_width); + } else { + // tiled view resize dimensions should default to ppt, so only use + // px if specified + if (dim_type != RESIZE_DIM_PX) { + dimension = (int)ppt_dim; + } + + return resize_tiled(dimension, use_width); + } + } + + return false; +} + +static struct cmd_results *cmd_resize_set(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "resize set", EXPECTED_AT_LEAST, 2))) { + return error; + } + + if (strcasecmp(argv[0], "width") == 0 || strcasecmp(argv[0], "height") == 0) { + // handle `reset set width 100 px height 100 px` syntax, also allows + // specifying only one dimension for a `resize set` + int cmd_num = 0; + int dim; + + while ((cmd_num + 1) < argc) { + dim = (int)strtol(argv[cmd_num + 1], NULL, 10); + if (errno == ERANGE || dim == 0) { + errno = 0; + return cmd_results_new(CMD_INVALID, "resize set", + "Expected 'resize set [px] [ [px]]'"); + } + + if (strcasecmp(argv[cmd_num], "width") == 0) { + set_size(dim, true); + } else if (strcasecmp(argv[cmd_num], "height") == 0) { + set_size(dim, false); + } else { + return cmd_results_new(CMD_INVALID, "resize set", + "Expected 'resize set [px] [ [px]]'"); + } + + cmd_num += 2; + + if (cmd_num < argc && strcasecmp(argv[cmd_num], "px") == 0) { + // if this was `resize set width 400 px height 300 px`, disregard the `px` arg + cmd_num++; + } + } + } else { + // handle `reset set 100 px 100 px` syntax + int width = (int)strtol(argv[0], NULL, 10); + if (errno == ERANGE || width == 0) { + errno = 0; + return cmd_results_new(CMD_INVALID, "resize set", + "Expected 'resize set [px] [px]'"); + } + + int height_arg = 1; + if (strcasecmp(argv[1], "px") == 0) { + height_arg = 2; + } + + int height = (int)strtol(argv[height_arg], NULL, 10); + if (errno == ERANGE || height == 0) { + errno = 0; + return cmd_results_new(CMD_INVALID, "resize set", + "Expected 'resize set [px] [px]'"); + } + + set_size(width, true); + set_size(height, false); + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +struct cmd_results *cmd_resize(int argc, char **argv) { + struct cmd_results *error = NULL; + if (config->reading) return cmd_results_new(CMD_FAILURE, "resize", "Can't be used in config file."); + if (!config->active) return cmd_results_new(CMD_FAILURE, "resize", "Can only be used when sway is running."); + + if (strcasecmp(argv[0], "set") == 0) { + return cmd_resize_set(argc - 1, &argv[1]); + } + + if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) { + return error; + } + + int dim_arg = argc - 1; + + enum resize_dim_types dim_type = RESIZE_DIM_DEFAULT; + if (strcasecmp(argv[dim_arg], "ppt") == 0) { + dim_type = RESIZE_DIM_PPT; + dim_arg--; + } else if (strcasecmp(argv[dim_arg], "px") == 0) { + dim_type = RESIZE_DIM_PX; + dim_arg--; + } + + int amount = (int)strtol(argv[dim_arg], NULL, 10); + if (errno == ERANGE || amount == 0) { + errno = 0; + amount = 10; // this is the default resize dimension used by i3 for both px and ppt + sway_log(L_DEBUG, "Tried to get resize dimension out of '%s' but failed; setting dimension to default %d", + argv[dim_arg], amount); + } + + bool use_width = false; + if (strcasecmp(argv[1], "width") == 0) { + use_width = true; + } else if (strcasecmp(argv[1], "height") != 0) { + return cmd_results_new(CMD_INVALID, "resize", + "Expected 'resize [] [px|ppt]'"); + } + + if (strcasecmp(argv[0], "shrink") == 0) { + amount *= -1; + } else if (strcasecmp(argv[0], "grow") != 0) { + return cmd_results_new(CMD_INVALID, "resize", + "Expected 'resize [] [px|ppt]'"); + } + + resize(amount, use_width, dim_type); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/scratchpad.c b/sway/old/commands/scratchpad.c new file mode 100644 index 00000000..6c5c92df --- /dev/null +++ b/sway/old/commands/scratchpad.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include "sway/commands.h" +#include "sway/container.h" +#include "sway/focus.h" +#include "sway/layout.h" + +static swayc_t *fetch_view_from_scratchpad() { + sp_index = (sp_index + 1) % scratchpad->length; + swayc_t *view = scratchpad->items[sp_index]; + + if (wlc_view_get_output(view->handle) != swayc_active_output()->handle) { + wlc_view_set_output(view->handle, swayc_active_output()->handle); + } + if (!view->is_floating) { + view->width = swayc_active_workspace()->width * 0.5; + view->height = swayc_active_workspace()->height * 0.75; + view->x = (swayc_active_workspace()->width - view->width)/2; + view->y = (swayc_active_workspace()->height - view->height)/2; + } + if (swayc_active_workspace()->width < view->x + 20 || view->x + view->width < 20) { + view->x = (swayc_active_workspace()->width - view->width)/2; + } + if (swayc_active_workspace()->height < view->y + 20 || view->y + view->height < 20) { + view->y = (swayc_active_workspace()->height - view->height)/2; + } + + add_floating(swayc_active_workspace(), view); + wlc_view_set_mask(view->handle, VISIBLE); + view->visible = true; + arrange_windows(swayc_active_workspace(), -1, -1); + set_focused_container(view); + return view; +} + +struct cmd_results *cmd_scratchpad(int argc, char **argv) { + struct cmd_results *error = NULL; + if (config->reading) return cmd_results_new(CMD_FAILURE, "scratchpad", "Can't be used in config file."); + if (!config->active) return cmd_results_new(CMD_FAILURE, "scratchpad", "Can only be used when sway is running."); + if ((error = checkarg(argc, "scratchpad", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (strcasecmp(argv[0], "show") == 0 && scratchpad->length > 0) { + if (!sp_view) { + if (current_container) { + // Haxor the scratchpad index if criteria'd + for (int i = 0; i < scratchpad->length; ++i) { + if (scratchpad->items[i] == current_container) { + sp_index = (i - 1) % scratchpad->length; + } + } + } + sp_view = fetch_view_from_scratchpad(); + } else { + if (swayc_active_workspace() != sp_view->parent) { + hide_view_in_scratchpad(sp_view); + if (sp_index == 0) { + sp_index = scratchpad->length; + } + sp_index--; + sp_view = fetch_view_from_scratchpad(); + } else { + hide_view_in_scratchpad(sp_view); + sp_view = NULL; + } + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } + return cmd_results_new(CMD_FAILURE, "scratchpad", "Expected 'scratchpad show' when scratchpad is not empty."); +} diff --git a/sway/old/commands/seamless_mouse.c b/sway/old/commands/seamless_mouse.c new file mode 100644 index 00000000..7760e88d --- /dev/null +++ b/sway/old/commands/seamless_mouse.c @@ -0,0 +1,13 @@ +#include +#include +#include "sway/commands.h" + +struct cmd_results *cmd_seamless_mouse(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "seamless_mouse", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + config->seamless_mouse = (strcasecmp(argv[0], "on") == 0 || strcasecmp(argv[0], "yes") == 0); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/set.c b/sway/old/commands/set.c new file mode 100644 index 00000000..46fc6d38 --- /dev/null +++ b/sway/old/commands/set.c @@ -0,0 +1,61 @@ +#define _XOPEN_SOURCE 700 +#include +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "list.h" +#include "stringop.h" + +// sort in order of longest->shortest +static int compare_set_qsort(const void *_l, const void *_r) { + struct sway_variable const *l = *(void **)_l; + struct sway_variable const *r = *(void **)_r; + return strlen(r->name) - strlen(l->name); +} + +struct cmd_results *cmd_set(int argc, char **argv) { + char *tmp; + struct cmd_results *error = NULL; + if (!config->reading) return cmd_results_new(CMD_FAILURE, "set", "Can only be used in config file."); + if ((error = checkarg(argc, "set", EXPECTED_AT_LEAST, 2))) { + return error; + } + + if (argv[0][0] != '$') { + sway_log(L_INFO, "Warning: variable '%s' doesn't start with $", argv[0]); + + size_t size = snprintf(NULL, 0, "$%s", argv[0]); + tmp = malloc(size + 1); + if (!tmp) { + return cmd_results_new(CMD_FAILURE, "set", "Not possible to create variable $'%s'", argv[0]); + } + snprintf(tmp, size+1, "$%s", argv[0]); + + argv[0] = tmp; + } + + struct sway_variable *var = NULL; + // Find old variable if it exists + int i; + for (i = 0; i < config->symbols->length; ++i) { + var = config->symbols->items[i]; + if (strcmp(var->name, argv[0]) == 0) { + break; + } + var = NULL; + } + if (var) { + free(var->value); + } else { + var = malloc(sizeof(struct sway_variable)); + if (!var) { + return cmd_results_new(CMD_FAILURE, "set", "Unable to allocate variable"); + } + var->name = strdup(argv[0]); + list_add(config->symbols, var); + list_qsort(config->symbols, compare_set_qsort); + } + var->value = join_args(argv + 1, argc - 1); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/show_marks.c b/sway/old/commands/show_marks.c new file mode 100644 index 00000000..ed56d9e5 --- /dev/null +++ b/sway/old/commands/show_marks.c @@ -0,0 +1,13 @@ +#include +#include +#include "sway/commands.h" + +struct cmd_results *cmd_show_marks(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "show_marks", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + config->show_marks = !strcasecmp(argv[0], "on"); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/smart_gaps.c b/sway/old/commands/smart_gaps.c new file mode 100644 index 00000000..815fc501 --- /dev/null +++ b/sway/old/commands/smart_gaps.c @@ -0,0 +1,20 @@ +#include +#include +#include "sway/commands.h" + +struct cmd_results *cmd_smart_gaps(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "smart_gaps", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (strcasecmp(argv[0], "on") == 0) { + config->smart_gaps = true; + } else if (strcasecmp(argv[0], "off") == 0) { + config->smart_gaps = false; + } else { + return cmd_results_new(CMD_INVALID, "smart_gaps", "Expected 'smart_gaps '"); + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/split.c b/sway/old/commands/split.c new file mode 100644 index 00000000..e3045a4f --- /dev/null +++ b/sway/old/commands/split.c @@ -0,0 +1,98 @@ +#include +#include +#include +#include "sway/border.h" +#include "sway/commands.h" +#include "sway/container.h" +#include "sway/focus.h" +#include "sway/layout.h" +#include "log.h" + +static struct cmd_results *_do_split(int argc, char **argv, int layout) { + char *name = layout == L_VERT ? "splitv" : + layout == L_HORIZ ? "splith" : "split"; + struct cmd_results *error = NULL; + if (config->reading) return cmd_results_new(CMD_FAILURE, name, "Can't be used in config file."); + if (!config->active) return cmd_results_new(CMD_FAILURE, name, "Can only be used when sway is running."); + if ((error = checkarg(argc, name, EXPECTED_EQUAL_TO, 0))) { + return error; + } + swayc_t *focused = current_container; + + // Case of floating window, don't split + if (focused->is_floating) { + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } + /* Case that focus is on an workspace with 0/1 children.change its layout */ + if (focused->type == C_WORKSPACE && focused->children->length <= 1) { + sway_log(L_DEBUG, "changing workspace layout"); + swayc_change_layout(focused, layout); + } else if (focused->type != C_WORKSPACE && focused->parent->children->length == 1) { + /* Case of no siblings. change parent layout */ + sway_log(L_DEBUG, "changing container layout"); + swayc_change_layout(focused->parent, layout); + } else { + /* regular case where new split container is build around focused container + * or in case of workspace, container inherits its children */ + sway_log(L_DEBUG, "Adding new container around current focused container"); + sway_log(L_INFO, "FOCUSED SIZE: %.f %.f", focused->width, focused->height); + swayc_t *parent = new_container(focused, layout); + set_focused_container(focused); + arrange_windows(parent, -1, -1); + } + + // update container every time + // if it is tabbed/stacked then the title must change + // if the indicator color is different then the border must change + update_container_border(focused); + swayc_t *output = swayc_parent_by_type(focused, C_OUTPUT); + // schedule render to make changes take effect right away, + // otherwise we would have to wait for the view to render, + // which is unpredictable. + wlc_output_schedule_render(output->handle); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +struct cmd_results *cmd_split(int argc, char **argv) { + struct cmd_results *error = NULL; + if (config->reading) return cmd_results_new(CMD_FAILURE, "split", "Can't be used in config file."); + if (!config->active) return cmd_results_new(CMD_FAILURE, "split", "Can only be used when sway is running."); + if ((error = checkarg(argc, "split", EXPECTED_EQUAL_TO, 1))) { + return error; + } + if (strcasecmp(argv[0], "v") == 0 || strcasecmp(argv[0], "vertical") == 0) { + _do_split(argc - 1, argv + 1, L_VERT); + } else if (strcasecmp(argv[0], "h") == 0 || strcasecmp(argv[0], "horizontal") == 0) { + _do_split(argc - 1, argv + 1, L_HORIZ); + } else if (strcasecmp(argv[0], "t") == 0 || strcasecmp(argv[0], "toggle") == 0) { + swayc_t *focused = current_container; + if (focused->parent->layout == L_VERT) { + _do_split(argc - 1, argv + 1, L_HORIZ); + } else { + _do_split(argc - 1, argv + 1, L_VERT); + } + } else { + error = cmd_results_new(CMD_FAILURE, "split", + "Invalid split command (expected either horizontal or vertical)."); + return error; + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +struct cmd_results *cmd_splitv(int argc, char **argv) { + return _do_split(argc, argv, L_VERT); +} + +struct cmd_results *cmd_splith(int argc, char **argv) { + return _do_split(argc, argv, L_HORIZ); +} + +struct cmd_results *cmd_splitt(int argc, char **argv) { + swayc_t *focused = current_container; + if (focused->parent->layout == L_VERT) { + return _do_split(argc, argv, L_HORIZ); + } else { + return _do_split(argc, argv, L_VERT); + } +} diff --git a/sway/old/commands/sticky.c b/sway/old/commands/sticky.c new file mode 100644 index 00000000..4899e061 --- /dev/null +++ b/sway/old/commands/sticky.c @@ -0,0 +1,25 @@ +#include +#include "sway/commands.h" +#include "sway/focus.h" + +struct cmd_results *cmd_sticky(int argc, char **argv) { + struct cmd_results *error = NULL; + if (config->reading) return cmd_results_new(CMD_FAILURE, "sticky", "Can't be used in config file."); + if (!config->active) return cmd_results_new(CMD_FAILURE, "sticky", "Can only be used when sway is running."); + if ((error = checkarg(argc, "sticky", EXPECTED_EQUAL_TO, 1))) { + return error; + } + char *action = argv[0]; + swayc_t *cont = get_focused_view(&root_container); + if (strcmp(action, "toggle") == 0) { + cont->sticky = !cont->sticky; + } else if (strcmp(action, "enable") == 0) { + cont->sticky = true; + } else if (strcmp(action, "disable") == 0) { + cont->sticky = false; + } else { + return cmd_results_new(CMD_FAILURE, "sticky", + "Expected 'sticky enable|disable|toggle'"); + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/unmark.c b/sway/old/commands/unmark.c new file mode 100644 index 00000000..ac213261 --- /dev/null +++ b/sway/old/commands/unmark.c @@ -0,0 +1,31 @@ +#include +#include +#include "sway/commands.h" +#include "list.h" +#include "stringop.h" + +struct cmd_results *cmd_unmark(int argc, char **argv) { + swayc_t *view = current_container; + + if (view->marks) { + if (argc) { + char *mark = join_args(argv, argc); + int index; + if ((index = list_seq_find(view->marks, (int (*)(const void *, const void *))strcmp, mark)) != -1) { + free(view->marks->items[index]); + list_del(view->marks, index); + + if (view->marks->length == 0) { + list_free(view->marks); + view->marks = NULL; + } + } + free(mark); + } else { + list_foreach(view->marks, free); + list_free(view->marks); + view->marks = NULL; + } + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/workspace.c b/sway/old/commands/workspace.c new file mode 100644 index 00000000..a7839746 --- /dev/null +++ b/sway/old/commands/workspace.c @@ -0,0 +1,92 @@ +#define _XOPEN_SOURCE 500 +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/input_state.h" +#include "sway/workspace.h" +#include "list.h" +#include "log.h" +#include "stringop.h" + +struct cmd_results *cmd_workspace(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "workspace", EXPECTED_AT_LEAST, 1))) { + return error; + } + + int output_location = -1; + + for (int i = 0; i < argc; ++i) { + if (strcasecmp(argv[i], "output") == 0) { + output_location = i; + break; + } + } + if (output_location >= 0) { + if ((error = checkarg(argc, "workspace", EXPECTED_EQUAL_TO, output_location + 2))) { + return error; + } + struct workspace_output *wso = calloc(1, sizeof(struct workspace_output)); + if (!wso) { + return cmd_results_new(CMD_FAILURE, "workspace output", + "Unable to allocate workspace output"); + } + wso->workspace = join_args(argv, argc - 2); + wso->output = strdup(argv[output_location + 1]); + int i = -1; + if ((i = list_seq_find(config->workspace_outputs, workspace_output_cmp_workspace, wso)) != -1) { + struct workspace_output *old = config->workspace_outputs->items[i]; + free(old); // workspaces can only be assigned to a single output + list_del(config->workspace_outputs, i); + } + sway_log(L_DEBUG, "Assigning workspace %s to output %s", wso->workspace, wso->output); + list_add(config->workspace_outputs, wso); + } else { + if (config->reading || !config->active) { + return cmd_results_new(CMD_DEFER, "workspace", NULL); + } + swayc_t *ws = NULL; + if (strcasecmp(argv[0], "number") == 0) { + if (!(ws = workspace_by_number(argv[1]))) { + char *name = join_args(argv + 1, argc - 1); + ws = workspace_create(name); + free(name); + } + } else if (strcasecmp(argv[0], "next") == 0) { + ws = workspace_next(); + } else if (strcasecmp(argv[0], "prev") == 0) { + ws = workspace_prev(); + } else if (strcasecmp(argv[0], "next_on_output") == 0) { + ws = workspace_output_next(); + } else if (strcasecmp(argv[0], "prev_on_output") == 0) { + ws = workspace_output_prev(); + } else if (strcasecmp(argv[0], "back_and_forth") == 0) { + // if auto_back_and_forth is enabled, workspace_switch will swap + // the workspaces. If we created prev_workspace here, workspace_switch + // would put us back on original workspace. + if (config->auto_back_and_forth) { + ws = swayc_active_workspace(); + } else if (prev_workspace_name && !(ws = workspace_by_name(prev_workspace_name))) { + ws = workspace_create(prev_workspace_name); + } + } else { + char *name = join_args(argv, argc); + if (!(ws = workspace_by_name(name))) { + ws = workspace_create(name); + } + free(name); + } + swayc_t *old_output = swayc_active_output(); + workspace_switch(ws); + swayc_t *new_output = swayc_active_output(); + + if (config->mouse_warping && old_output != new_output) { + swayc_t *focused = get_focused_view(ws); + if (focused && focused->type == C_VIEW) { + center_pointer_on(focused); + } + } + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/workspace_auto_back_and_forth.c b/sway/old/commands/workspace_auto_back_and_forth.c new file mode 100644 index 00000000..d58ae5c8 --- /dev/null +++ b/sway/old/commands/workspace_auto_back_and_forth.c @@ -0,0 +1,18 @@ +#include +#include +#include "sway/commands.h" + +struct cmd_results *cmd_ws_auto_back_and_forth(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "workspace_auto_back_and_forth", EXPECTED_EQUAL_TO, 1))) { + return error; + } + if (strcasecmp(argv[0], "yes") == 0) { + config->auto_back_and_forth = true; + } else if (strcasecmp(argv[0], "no") == 0) { + config->auto_back_and_forth = false; + } else { + return cmd_results_new(CMD_INVALID, "workspace_auto_back_and_forth", "Expected 'workspace_auto_back_and_forth '"); + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/commands/workspace_layout.c b/sway/old/commands/workspace_layout.c new file mode 100644 index 00000000..9ac84be2 --- /dev/null +++ b/sway/old/commands/workspace_layout.c @@ -0,0 +1,40 @@ +#include +#include +#include "sway/commands.h" + +struct cmd_results *cmd_workspace_layout(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "workspace_layout", EXPECTED_AT_LEAST, 1))) { + return error; + } + + if (strcasecmp(argv[0], "default") == 0) { + config->default_layout = L_NONE; + } else if (strcasecmp(argv[0], "stacking") == 0) { + config->default_layout = L_STACKED; + } else if (strcasecmp(argv[0], "tabbed") == 0) { + config->default_layout = L_TABBED; + } else if (strcasecmp(argv[0], "auto") == 0) { + if (argc == 1) { + config->default_layout = L_AUTO_FIRST; + } else { + if ((error = checkarg(argc, "workspace_layout auto", EXPECTED_EQUAL_TO, 2))) { + return error; + } + if (strcasecmp(argv[1], "left") == 0) { + config->default_layout = L_AUTO_LEFT; + } else if (strcasecmp(argv[1], "right") == 0) { + config->default_layout = L_AUTO_RIGHT; + } else if (strcasecmp(argv[1], "top") == 0) { + config->default_layout = L_AUTO_TOP; + } else if (strcasecmp(argv[1], "bottom") == 0) { + config->default_layout = L_AUTO_BOTTOM; + } else { + return cmd_results_new(CMD_INVALID, "workspace_layout auto", "Expected 'workspace_layout auto '"); + } + } + } else { + return cmd_results_new(CMD_INVALID, "workspace_layout", "Expected 'workspace_layout '"); + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/old/config.c b/sway/old/config.c new file mode 100644 index 00000000..d14653e3 --- /dev/null +++ b/sway/old/config.c @@ -0,0 +1,1313 @@ +#define _POSIX_C_SOURCE 200809L +#define _XOPEN_SOURCE 700 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wayland-desktop-shell-server-protocol.h" +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/layout.h" +#include "sway/input_state.h" +#include "sway/criteria.h" +#include "sway/input.h" +#include "sway/border.h" +#include "readline.h" +#include "stringop.h" +#include "list.h" +#include "log.h" + +struct sway_config *config = NULL; + +static void terminate_swaybar(pid_t pid); + +static void free_variable(struct sway_variable *var) { + if (!var) { + return; + } + free(var->name); + free(var->value); + free(var); +} + +static void free_binding(struct sway_binding *bind) { + if (!bind) { + return; + } + free_flat_list(bind->keys); + free(bind->command); + free(bind); +} + +static void free_mode(struct sway_mode *mode) { + if (!mode) { + return; + } + free(mode->name); + int i; + for (i = 0; mode->bindings && i < mode->bindings->length; ++i) { + free_binding(mode->bindings->items[i]); + } + list_free(mode->bindings); + free(mode); +} + +static void free_bar(struct bar_config *bar) { + if (!bar) { + return; + } + free(bar->mode); + free(bar->hidden_state); +#ifdef ENABLE_TRAY + free(bar->tray_output); + free(bar->icon_theme); +#endif + free(bar->status_command); + free(bar->font); + free(bar->separator_symbol); + int i; + for (i = 0; bar->bindings && i < bar->bindings->length; ++i) { + free_sway_mouse_binding(bar->bindings->items[i]); + } + list_free(bar->bindings); + + if (bar->outputs) { + free_flat_list(bar->outputs); + } + + if (bar->pid != 0) { + terminate_swaybar(bar->pid); + } + + free(bar->colors.background); + free(bar->colors.statusline); + free(bar->colors.separator); + free(bar->colors.focused_background); + free(bar->colors.focused_statusline); + free(bar->colors.focused_separator); + free(bar->colors.focused_workspace_border); + free(bar->colors.focused_workspace_bg); + free(bar->colors.focused_workspace_text); + free(bar->colors.active_workspace_border); + free(bar->colors.active_workspace_bg); + free(bar->colors.active_workspace_text); + free(bar->colors.inactive_workspace_border); + free(bar->colors.inactive_workspace_bg); + free(bar->colors.inactive_workspace_text); + free(bar->colors.urgent_workspace_border); + free(bar->colors.urgent_workspace_bg); + free(bar->colors.urgent_workspace_text); + free(bar->colors.binding_mode_border); + free(bar->colors.binding_mode_bg); + free(bar->colors.binding_mode_text); + + free(bar); +} + +void free_input_config(struct input_config *ic) { + if (!ic) { + return; + } + free(ic->identifier); + free(ic); +} + +void free_output_config(struct output_config *oc) { + if (!oc) { + return; + } + free(oc->name); + free(oc->background); + free(oc->background_option); + free(oc); +} + +static void free_workspace_output(struct workspace_output *wo) { + if (!wo) { + return; + } + free(wo->output); + free(wo->workspace); + free(wo); +} + +static void pid_workspace_cleanup() { + struct timespec ts; + struct pid_workspace *pw = NULL; + + clock_gettime(CLOCK_MONOTONIC, &ts); + + // work backwards through list and remove any entries + // older than PID_WORKSPACE_TIMEOUT + for (int i = config->pid_workspaces->length - 1; i > -1; i--) { + pw = config->pid_workspaces->items[i]; + + if (difftime(ts.tv_sec, *pw->time_added) >= PID_WORKSPACE_TIMEOUT) { + free_pid_workspace(config->pid_workspaces->items[i]); + list_del(config->pid_workspaces, i); + } + } +} + +// de-dupe pid_workspaces to ensure pid uniqueness +void pid_workspace_add(struct pid_workspace *pw) { + struct pid_workspace *list_pw = NULL; + struct timespec ts; + time_t *now = malloc(sizeof(time_t)); + if (!now) { + sway_log(L_ERROR, "Allocating time for pid_workspace failed"); + return; + } + + pid_workspace_cleanup(); + + // add current time to pw + clock_gettime(CLOCK_MONOTONIC, &ts); + *now = ts.tv_sec; + + pw->time_added = now; + + // work backwards through list and delete any entries that + // have the same pid as that in our new pid_workspace + for (int i = config->pid_workspaces->length - 1; i > -1; i--) { + list_pw = config->pid_workspaces->items[i]; + + if (pw->pid == list_pw->pid) { + free_pid_workspace(config->pid_workspaces->items[i]); + list_del(config->pid_workspaces, i); + } + } + + list_add(config->pid_workspaces, pw); +} + +void free_pid_workspace(struct pid_workspace *pw) { + if (!pw) { + return; + } + free(pw->pid); + free(pw->workspace); + free(pw->time_added); + free(pw); +} + +void free_command_policy(struct command_policy *policy) { + if (!policy) { + return; + } + free(policy->command); + free(policy); +} + +void free_feature_policy(struct feature_policy *policy) { + if (!policy) { + return; + } + free(policy->program); + free(policy); +} + +void free_config(struct sway_config *config) { + if (!config) { + return; + } + int i; + for (i = 0; config->symbols && i < config->symbols->length; ++i) { + free_variable(config->symbols->items[i]); + } + list_free(config->symbols); + + for (i = 0; config->modes && i < config->modes->length; ++i) { + free_mode(config->modes->items[i]); + } + list_free(config->modes); + + for (i = 0; config->bars && i < config->bars->length; ++i) { + free_bar(config->bars->items[i]); + } + list_free(config->bars); + + free_flat_list(config->cmd_queue); + + for (i = 0; config->workspace_outputs && i < config->workspace_outputs->length; ++i) { + free_workspace_output(config->workspace_outputs->items[i]); + } + list_free(config->workspace_outputs); + + for (i = 0; config->pid_workspaces && i < config->pid_workspaces->length; ++i) { + free_pid_workspace(config->pid_workspaces->items[i]); + } + list_free(config->pid_workspaces); + + for (i = 0; config->criteria && i < config->criteria->length; ++i) { + free_criteria(config->criteria->items[i]); + } + list_free(config->criteria); + + for (i = 0; config->no_focus && i < config->no_focus->length; ++i) { + free_criteria(config->no_focus->items[i]); + } + list_free(config->no_focus); + + for (i = 0; config->input_configs && i < config->input_configs->length; ++i) { + free_input_config(config->input_configs->items[i]); + } + list_free(config->input_configs); + + for (i = 0; config->output_configs && i < config->output_configs->length; ++i) { + free_output_config(config->output_configs->items[i]); + } + list_free(config->output_configs); + + for (i = 0; config->command_policies && i < config->command_policies->length; ++i) { + free_command_policy(config->command_policies->items[i]); + } + list_free(config->command_policies); + + for (i = 0; config->feature_policies && i < config->feature_policies->length; ++i) { + free_feature_policy(config->feature_policies->items[i]); + } + list_free(config->feature_policies); + + list_free(config->active_bar_modifiers); + free_flat_list(config->config_chain); + free(config->font); + free(config->floating_scroll_up_cmd); + free(config->floating_scroll_down_cmd); + free(config->floating_scroll_left_cmd); + free(config->floating_scroll_right_cmd); + free(config); +} + + +static bool file_exists(const char *path) { + return path && access(path, R_OK) != -1; +} + +static void config_defaults(struct sway_config *config) { + if (!(config->symbols = create_list())) goto cleanup; + if (!(config->modes = create_list())) goto cleanup; + if (!(config->bars = create_list())) goto cleanup; + if (!(config->workspace_outputs = create_list())) goto cleanup; + if (!(config->pid_workspaces = create_list())) goto cleanup; + if (!(config->criteria = create_list())) goto cleanup; + if (!(config->no_focus = create_list())) goto cleanup; + if (!(config->input_configs = create_list())) goto cleanup; + if (!(config->output_configs = create_list())) goto cleanup; + + if (!(config->cmd_queue = create_list())) goto cleanup; + + if (!(config->current_mode = malloc(sizeof(struct sway_mode)))) goto cleanup; + if (!(config->current_mode->name = malloc(sizeof("default")))) goto cleanup; + strcpy(config->current_mode->name, "default"); + if (!(config->current_mode->bindings = create_list())) goto cleanup; + list_add(config->modes, config->current_mode); + + config->floating_mod = 0; + config->dragging_key = M_LEFT_CLICK; + config->resizing_key = M_RIGHT_CLICK; + if (!(config->floating_scroll_up_cmd = strdup(""))) goto cleanup; + if (!(config->floating_scroll_down_cmd = strdup(""))) goto cleanup; + if (!(config->floating_scroll_left_cmd = strdup(""))) goto cleanup; + if (!(config->floating_scroll_right_cmd = strdup(""))) goto cleanup; + config->default_layout = L_NONE; + config->default_orientation = L_NONE; + if (!(config->font = strdup("monospace 10"))) goto cleanup; + config->font_height = get_font_text_height(config->font); + + // floating view + config->floating_maximum_width = 0; + config->floating_maximum_height = 0; + config->floating_minimum_width = 75; + config->floating_minimum_height = 50; + + // Flags + config->focus_follows_mouse = true; + config->mouse_warping = true; + config->reloading = false; + config->active = false; + config->failed = false; + config->auto_back_and_forth = false; + config->seamless_mouse = true; + config->reading = false; + config->show_marks = true; + + config->edge_gaps = true; + config->smart_gaps = false; + config->gaps_inner = 0; + config->gaps_outer = 0; + + if (!(config->active_bar_modifiers = create_list())) goto cleanup; + + if (!(config->config_chain = create_list())) goto cleanup; + config->current_config = NULL; + + // borders + config->border = B_NORMAL; + config->floating_border = B_NORMAL; + config->border_thickness = 2; + config->floating_border_thickness = 2; + config->hide_edge_borders = E_NONE; + + // border colors + config->border_colors.focused.border = 0x4C7899FF; + config->border_colors.focused.background = 0x285577FF; + config->border_colors.focused.text = 0xFFFFFFFF; + config->border_colors.focused.indicator = 0x2E9EF4FF; + config->border_colors.focused.child_border = 0x285577FF; + + config->border_colors.focused_inactive.border = 0x333333FF; + config->border_colors.focused_inactive.background = 0x5F676AFF; + config->border_colors.focused_inactive.text = 0xFFFFFFFF; + config->border_colors.focused_inactive.indicator = 0x484E50FF; + config->border_colors.focused_inactive.child_border = 0x5F676AFF; + + config->border_colors.unfocused.border = 0x333333FF; + config->border_colors.unfocused.background = 0x222222FF; + config->border_colors.unfocused.text = 0x888888FF; + config->border_colors.unfocused.indicator = 0x292D2EFF; + config->border_colors.unfocused.child_border = 0x222222FF; + + config->border_colors.urgent.border = 0x2F343AFF; + config->border_colors.urgent.background = 0x900000FF; + config->border_colors.urgent.text = 0xFFFFFFFF; + config->border_colors.urgent.indicator = 0x900000FF; + config->border_colors.urgent.child_border = 0x900000FF; + + config->border_colors.placeholder.border = 0x000000FF; + config->border_colors.placeholder.background = 0x0C0C0CFF; + config->border_colors.placeholder.text = 0xFFFFFFFF; + config->border_colors.placeholder.indicator = 0x000000FF; + config->border_colors.placeholder.child_border = 0x0C0C0CFF; + + config->border_colors.background = 0xFFFFFFFF; + + // Security + if (!(config->command_policies = create_list())) goto cleanup; + if (!(config->feature_policies = create_list())) goto cleanup; + if (!(config->ipc_policies = create_list())) goto cleanup; + + return; +cleanup: + sway_abort("Unable to allocate config structures"); +} + +static int compare_modifiers(const void *left, const void *right) { + uint32_t a = *(uint32_t *)left; + uint32_t b = *(uint32_t *)right; + + return a - b; +} + +void update_active_bar_modifiers() { + if (config->active_bar_modifiers->length > 0) { + list_free(config->active_bar_modifiers); + config->active_bar_modifiers = create_list(); + } + + struct bar_config *bar; + int i; + for (i = 0; i < config->bars->length; ++i) { + bar = config->bars->items[i]; + if (strcmp(bar->mode, "hide") == 0 && strcmp(bar->hidden_state, "hide") == 0) { + if (list_seq_find(config->active_bar_modifiers, compare_modifiers, &bar->modifier) < 0) { + list_add(config->active_bar_modifiers, &bar->modifier); + } + } + } +} + +static char *get_config_path(void) { + static const char *config_paths[] = { + "$HOME/.sway/config", + "$XDG_CONFIG_HOME/sway/config", + "$HOME/.i3/config", + "$XDG_CONFIG_HOME/i3/config", + SYSCONFDIR "/sway/config", + SYSCONFDIR "/i3/config", + }; + + if (!getenv("XDG_CONFIG_HOME")) { + char *home = getenv("HOME"); + char *config_home = malloc(strlen(home) + strlen("/.config") + 1); + if (!config_home) { + sway_log(L_ERROR, "Unable to allocate $HOME/.config"); + } else { + strcpy(config_home, home); + strcat(config_home, "/.config"); + setenv("XDG_CONFIG_HOME", config_home, 1); + sway_log(L_DEBUG, "Set XDG_CONFIG_HOME to %s", config_home); + free(config_home); + } + } + + wordexp_t p; + char *path; + + int i; + for (i = 0; i < (int)(sizeof(config_paths) / sizeof(char *)); ++i) { + if (wordexp(config_paths[i], &p, 0) == 0) { + path = strdup(p.we_wordv[0]); + wordfree(&p); + if (file_exists(path)) { + return path; + } + } + } + + return NULL; // Not reached +} + +const char *current_config_path; + +static bool load_config(const char *path, struct sway_config *config) { + sway_log(L_INFO, "Loading config from %s", path); + current_config_path = path; + + struct stat sb; + if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { + return false; + } + + if (path == NULL) { + sway_log(L_ERROR, "Unable to find a config file!"); + return false; + } + + FILE *f = fopen(path, "r"); + if (!f) { + sway_log(L_ERROR, "Unable to open %s for reading", path); + return false; + } + + bool config_load_success = read_config(f, config); + fclose(f); + + if (!config_load_success) { + sway_log(L_ERROR, "Error(s) loading config!"); + } + + current_config_path = NULL; + return true; +} + +static int qstrcmp(const void* a, const void* b) { + return strcmp(*((char**) a), *((char**) b)); +} + +bool load_main_config(const char *file, bool is_active) { + input_init(); + + char *path; + if (file != NULL) { + path = strdup(file); + } else { + path = get_config_path(); + } + + struct sway_config *old_config = config; + config = calloc(1, sizeof(struct sway_config)); + if (!config) { + sway_abort("Unable to allocate config"); + } + + config_defaults(config); + if (is_active) { + sway_log(L_DEBUG, "Performing configuration file reload"); + config->reloading = true; + config->active = true; + } + + config->current_config = path; + list_add(config->config_chain, path); + + config->reading = true; + + // Read security configs + bool success = true; + DIR *dir = opendir(SYSCONFDIR "/sway/security.d"); + if (!dir) { + sway_log(L_ERROR, "%s does not exist, sway will have no security configuration" + " and will probably be broken", SYSCONFDIR "/sway/security.d"); + } else { + list_t *secconfigs = create_list(); + char *base = SYSCONFDIR "/sway/security.d/"; + struct dirent *ent = readdir(dir); + struct stat s; + while (ent != NULL) { + char *_path = malloc(strlen(ent->d_name) + strlen(base) + 1); + strcpy(_path, base); + strcat(_path, ent->d_name); + lstat(_path, &s); + if (S_ISREG(s.st_mode) && ent->d_name[0] != '.') { + list_add(secconfigs, _path); + } + else { + free(_path); + } + ent = readdir(dir); + } + closedir(dir); + + list_qsort(secconfigs, qstrcmp); + for (int i = 0; i < secconfigs->length; ++i) { + char *_path = secconfigs->items[i]; + if (stat(_path, &s) || s.st_uid != 0 || s.st_gid != 0 || (((s.st_mode & 0777) != 0644) && (s.st_mode & 0777) != 0444)) { + sway_log(L_ERROR, "Refusing to load %s - it must be owned by root and mode 644 or 444", _path); + success = false; + } else { + success = success && load_config(_path, config); + } + } + + free_flat_list(secconfigs); + } + + success = success && load_config(path, config); + + if (is_active) { + config->reloading = false; + } + + if (old_config) { + free_config(old_config); + } + config->reading = false; + + if (success) { + update_active_bar_modifiers(); + } + + return success; +} + +static bool load_include_config(const char *path, const char *parent_dir, struct sway_config *config) { + // save parent config + const char *parent_config = config->current_config; + + char *full_path = strdup(path); + int len = strlen(path); + if (len >= 1 && path[0] != '/') { + len = len + strlen(parent_dir) + 2; + full_path = malloc(len * sizeof(char)); + if (!full_path) { + sway_log(L_ERROR, "Unable to allocate full path to included config"); + return false; + } + snprintf(full_path, len, "%s/%s", parent_dir, path); + } + + char *real_path = realpath(full_path, NULL); + free(full_path); + + if (real_path == NULL) { + sway_log(L_DEBUG, "%s not found.", path); + return false; + } + + // check if config has already been included + int j; + for (j = 0; j < config->config_chain->length; ++j) { + char *old_path = config->config_chain->items[j]; + if (strcmp(real_path, old_path) == 0) { + sway_log(L_DEBUG, "%s already included once, won't be included again.", real_path); + free(real_path); + return false; + } + } + + config->current_config = real_path; + list_add(config->config_chain, real_path); + int index = config->config_chain->length - 1; + + if (!load_config(real_path, config)) { + free(real_path); + config->current_config = parent_config; + list_del(config->config_chain, index); + return false; + } + + // restore current_config + config->current_config = parent_config; + return true; +} + +bool load_include_configs(const char *path, struct sway_config *config) { + char *wd = getcwd(NULL, 0); + char *parent_path = strdup(config->current_config); + const char *parent_dir = dirname(parent_path); + + if (chdir(parent_dir) < 0) { + free(parent_path); + free(wd); + return false; + } + + wordexp_t p; + + if (wordexp(path, &p, 0) < 0) { + free(parent_path); + free(wd); + return false; + } + + char **w = p.we_wordv; + size_t i; + for (i = 0; i < p.we_wordc; ++i) { + load_include_config(w[i], parent_dir, config); + } + free(parent_path); + wordfree(&p); + + // restore wd + if (chdir(wd) < 0) { + free(wd); + sway_log(L_ERROR, "failed to restore working directory"); + return false; + } + + free(wd); + return true; +} + +struct cmd_results *check_security_config() { + if (!current_config_path || strncmp(SYSCONFDIR "/sway/security.d/", current_config_path, + strlen(SYSCONFDIR "/sway/security.d/")) != 0) { + return cmd_results_new(CMD_INVALID, "permit", + "This command is only permitted to run from " SYSCONFDIR "/sway/security.d/*"); + } + return NULL; +} + +bool read_config(FILE *file, struct sway_config *config) { + bool success = true; + enum cmd_status block = CMD_BLOCK_END; + + int line_number = 0; + char *line; + while (!feof(file)) { + line = read_line(file); + if (!line) { + continue; + } + line_number++; + line = strip_whitespace(line); + if (line[0] == '#') { + free(line); + continue; + } + struct cmd_results *res; + if (block == CMD_BLOCK_COMMANDS) { + // Special case + res = config_commands_command(line); + } else { + res = config_command(line, block); + } + switch(res->status) { + case CMD_FAILURE: + case CMD_INVALID: + sway_log(L_ERROR, "Error on line %i '%s': %s (%s)", line_number, line, + res->error, config->current_config); + success = false; + break; + + case CMD_DEFER: + sway_log(L_DEBUG, "Defferring command `%s'", line); + list_add(config->cmd_queue, strdup(line)); + break; + + case CMD_BLOCK_MODE: + if (block == CMD_BLOCK_END) { + block = CMD_BLOCK_MODE; + } else { + sway_log(L_ERROR, "Invalid block '%s'", line); + } + break; + + case CMD_BLOCK_INPUT: + if (block == CMD_BLOCK_END) { + block = CMD_BLOCK_INPUT; + } else { + sway_log(L_ERROR, "Invalid block '%s'", line); + } + break; + + case CMD_BLOCK_BAR: + if (block == CMD_BLOCK_END) { + block = CMD_BLOCK_BAR; + } else { + sway_log(L_ERROR, "Invalid block '%s'", line); + } + break; + + case CMD_BLOCK_BAR_COLORS: + if (block == CMD_BLOCK_BAR) { + block = CMD_BLOCK_BAR_COLORS; + } else { + sway_log(L_ERROR, "Invalid block '%s'", line); + } + break; + + case CMD_BLOCK_COMMANDS: + if (block == CMD_BLOCK_END) { + block = CMD_BLOCK_COMMANDS; + } else { + sway_log(L_ERROR, "Invalid block '%s'", line); + } + break; + + case CMD_BLOCK_IPC: + if (block == CMD_BLOCK_END) { + block = CMD_BLOCK_IPC; + } else { + sway_log(L_ERROR, "Invalid block '%s'", line); + } + break; + + case CMD_BLOCK_IPC_EVENTS: + if (block == CMD_BLOCK_IPC) { + block = CMD_BLOCK_IPC_EVENTS; + } else { + sway_log(L_ERROR, "Invalid block '%s'", line); + } + break; + + case CMD_BLOCK_END: + switch(block) { + case CMD_BLOCK_MODE: + sway_log(L_DEBUG, "End of mode block"); + config->current_mode = config->modes->items[0]; + block = CMD_BLOCK_END; + break; + + case CMD_BLOCK_INPUT: + sway_log(L_DEBUG, "End of input block"); + current_input_config = NULL; + block = CMD_BLOCK_END; + break; + + case CMD_BLOCK_BAR: + sway_log(L_DEBUG, "End of bar block"); + config->current_bar = NULL; + block = CMD_BLOCK_END; + break; + + case CMD_BLOCK_BAR_COLORS: + sway_log(L_DEBUG, "End of bar colors block"); + block = CMD_BLOCK_BAR; + break; + + case CMD_BLOCK_COMMANDS: + sway_log(L_DEBUG, "End of commands block"); + block = CMD_BLOCK_END; + break; + + case CMD_BLOCK_IPC: + sway_log(L_DEBUG, "End of IPC block"); + block = CMD_BLOCK_END; + break; + + case CMD_BLOCK_IPC_EVENTS: + sway_log(L_DEBUG, "End of IPC events block"); + block = CMD_BLOCK_IPC; + break; + + case CMD_BLOCK_END: + sway_log(L_ERROR, "Unmatched }"); + break; + + default:; + } + default:; + } + free(line); + free_cmd_results(res); + } + + return success; +} + +int input_identifier_cmp(const void *item, const void *data) { + const struct input_config *ic = item; + const char *identifier = data; + return strcmp(ic->identifier, identifier); +} + +int output_name_cmp(const void *item, const void *data) { + const struct output_config *output = item; + const char *name = data; + + return strcmp(output->name, name); +} + +void merge_input_config(struct input_config *dst, struct input_config *src) { + if (src->identifier) { + if (dst->identifier) { + free(dst->identifier); + } + dst->identifier = strdup(src->identifier); + } + if (src->accel_profile != INT_MIN) { + dst->accel_profile = src->accel_profile; + } + if (src->click_method != INT_MIN) { + dst->click_method = src->click_method; + } + if (src->drag_lock != INT_MIN) { + dst->drag_lock = src->drag_lock; + } + if (src->dwt != INT_MIN) { + dst->dwt = src->dwt; + } + if (src->middle_emulation != INT_MIN) { + dst->middle_emulation = src->middle_emulation; + } + if (src->natural_scroll != INT_MIN) { + dst->natural_scroll = src->natural_scroll; + } + if (src->pointer_accel != FLT_MIN) { + dst->pointer_accel = src->pointer_accel; + } + if (src->scroll_method != INT_MIN) { + dst->scroll_method = src->scroll_method; + } + if (src->send_events != INT_MIN) { + dst->send_events = src->send_events; + } + if (src->tap != INT_MIN) { + dst->tap = src->tap; + } +} + +void merge_output_config(struct output_config *dst, struct output_config *src) { + if (src->name) { + if (dst->name) { + free(dst->name); + } + dst->name = strdup(src->name); + } + if (src->enabled != -1) { + dst->enabled = src->enabled; + } + if (src->width != -1) { + dst->width = src->width; + } + if (src->height != -1) { + dst->height = src->height; + } + if (src->x != -1) { + dst->x = src->x; + } + if (src->y != -1) { + dst->y = src->y; + } + if (src->scale != -1) { + dst->scale = src->scale; + } + if (src->background) { + if (dst->background) { + free(dst->background); + } + dst->background = strdup(src->background); + } + if (src->background_option) { + if (dst->background_option) { + free(dst->background_option); + } + dst->background_option = strdup(src->background_option); + } +} + +static void invoke_swaybar(struct bar_config *bar) { + return; // TODO WLR + sway_log(L_DEBUG, "Invoking swaybar for bar id '%s'", bar->id); + // Pipe to communicate errors + int filedes[2]; + if (pipe(filedes) == -1) { + sway_log(L_ERROR, "Pipe setup failed! Cannot fork into bar"); + return; + } + + bar->pid = fork(); + if (bar->pid == 0) { + close(filedes[0]); + if (!bar->swaybar_command) { + char *const cmd[] = { + "swaybar", + "-b", + bar->id, + NULL, + }; + + close(filedes[1]); + execvp(cmd[0], cmd); + _exit(EXIT_SUCCESS); + } else { + // run custom swaybar + int len = strlen(bar->swaybar_command) + strlen(bar->id) + 5; + char *command = malloc(len * sizeof(char)); + if (!command) { + const char msg[] = "Unable to allocate swaybar command string"; + int len = sizeof(msg); + if (write(filedes[1], &len, sizeof(int))) {}; + if (write(filedes[1], msg, len)) {}; + close(filedes[1]); + _exit(EXIT_FAILURE); + } + snprintf(command, len, "%s -b %s", bar->swaybar_command, bar->id); + + char *const cmd[] = { + "sh", + "-c", + command, + NULL, + }; + + close(filedes[1]); + execvp(cmd[0], cmd); + free(command); + _exit(EXIT_SUCCESS); + } + } + close(filedes[0]); + int len; + if(read(filedes[1], &len, sizeof(int)) == sizeof(int)) { + char *buf = malloc(len); + if(!buf) { + sway_log(L_ERROR, "Cannot allocate error string"); + return; + } + if(read(filedes[1], buf, len)) { + sway_log(L_ERROR, "%s", buf); + } + free(buf); + } + close(filedes[1]); +} + +static void terminate_swaybar(pid_t pid) { + return; // TODO WLR + int ret = kill(pid, SIGTERM); + if (ret != 0) { + sway_log(L_ERROR, "Unable to terminate swaybar [pid: %d]", pid); + } else { + int status; + waitpid(pid, &status, 0); + } +} + +void terminate_swaybg(pid_t pid) { + int ret = kill(pid, SIGTERM); + if (ret != 0) { + sway_log(L_ERROR, "Unable to terminate swaybg [pid: %d]", pid); + } else { + int status; + waitpid(pid, &status, 0); + } +} + +static bool active_output(const char *name) { + int i; + swayc_t *cont = NULL; + for (i = 0; i < root_container.children->length; ++i) { + cont = root_container.children->items[i]; + if (cont->type == C_OUTPUT && strcasecmp(name, cont->name) == 0) { + return true; + } + } + + return false; +} + +void load_swaybars() { + // Check for bars + list_t *bars = create_list(); + struct bar_config *bar = NULL; + int i; + for (i = 0; i < config->bars->length; ++i) { + bar = config->bars->items[i]; + bool apply = false; + if (bar->outputs) { + int j; + for (j = 0; j < bar->outputs->length; ++j) { + char *o = bar->outputs->items[j]; + if (!strcmp(o, "*") || active_output(o)) { + apply = true; + break; + } + } + } else { + apply = true; + } + if (apply) { + list_add(bars, bar); + } + } + + for (i = 0; i < bars->length; ++i) { + bar = bars->items[i]; + if (bar->pid != 0) { + terminate_swaybar(bar->pid); + } + invoke_swaybar(bar); + } + + list_free(bars); +} + +char *do_var_replacement(char *str) { + int i; + char *find = str; + while ((find = strchr(find, '$'))) { + // Skip if escaped. + if (find > str && find[-1] == '\\') { + if (find == str + 1 || !(find > str + 1 && find[-2] == '\\')) { + ++find; + continue; + } + } + // Find matching variable + for (i = 0; i < config->symbols->length; ++i) { + struct sway_variable *var = config->symbols->items[i]; + int vnlen = strlen(var->name); + if (strncmp(find, var->name, vnlen) == 0) { + int vvlen = strlen(var->value); + char *newstr = malloc(strlen(str) - vnlen + vvlen + 1); + if (!newstr) { + sway_log(L_ERROR, + "Unable to allocate replacement during variable expansion"); + break; + } + char *newptr = newstr; + int offset = find - str; + strncpy(newptr, str, offset); + newptr += offset; + strncpy(newptr, var->value, vvlen); + newptr += vvlen; + strcpy(newptr, find + vnlen); + free(str); + str = newstr; + find = str + offset + vvlen; + break; + } + } + if (i == config->symbols->length) { + ++find; + } + } + return str; +} + +// the naming is intentional (albeit long): a workspace_output_cmp function +// would compare two structs in full, while this method only compares the +// workspace. +int workspace_output_cmp_workspace(const void *a, const void *b) { + const struct workspace_output *wsa = a, *wsb = b; + return lenient_strcmp(wsa->workspace, wsb->workspace); +} + +int sway_binding_cmp_keys(const void *a, const void *b) { + const struct sway_binding *binda = a, *bindb = b; + + // Count keys pressed for this binding. important so we check long before + // short ones. for example mod+a+b before mod+a + unsigned int moda = 0, modb = 0, i; + + // Count how any modifiers are pressed + for (i = 0; i < 8 * sizeof(binda->modifiers); ++i) { + moda += (binda->modifiers & 1 << i) != 0; + modb += (bindb->modifiers & 1 << i) != 0; + } + if (bindb->keys->length + modb != binda->keys->length + moda) { + return (bindb->keys->length + modb) - (binda->keys->length + moda); + } + + // Otherwise compare keys + if (binda->modifiers > bindb->modifiers) { + return 1; + } else if (binda->modifiers < bindb->modifiers) { + return -1; + } + struct wlc_modifiers no_mods = { 0, 0 }; + for (int i = 0; i < binda->keys->length; i++) { + xkb_keysym_t ka = *(xkb_keysym_t *)binda->keys->items[i], + kb = *(xkb_keysym_t *)bindb->keys->items[i]; + if (binda->bindcode) { + uint32_t *keycode = binda->keys->items[i]; + ka = wlc_keyboard_get_keysym_for_key(*keycode, &no_mods); + } + + if (bindb->bindcode) { + uint32_t *keycode = bindb->keys->items[i]; + kb = wlc_keyboard_get_keysym_for_key(*keycode, &no_mods); + } + + if (ka > kb) { + return 1; + } else if (ka < kb) { + return -1; + } + } + + return 0; +} + +int sway_binding_cmp(const void *a, const void *b) { + int cmp = 0; + if ((cmp = sway_binding_cmp_keys(a, b)) != 0) { + return cmp; + } + const struct sway_binding *binda = a, *bindb = b; + return lenient_strcmp(binda->command, bindb->command); +} + +int sway_binding_cmp_qsort(const void *a, const void *b) { + return sway_binding_cmp(*(void **)a, *(void **)b); +} + +void free_sway_binding(struct sway_binding *binding) { + if (binding->keys) { + for (int i = 0; i < binding->keys->length; i++) { + free(binding->keys->items[i]); + } + list_free(binding->keys); + } + if (binding->command) { + free(binding->command); + } + free(binding); +} + +int sway_mouse_binding_cmp_buttons(const void *a, const void *b) { + const struct sway_mouse_binding *binda = a, *bindb = b; + if (binda->button > bindb->button) { + return 1; + } + if (binda->button < bindb->button) { + return -1; + } + return 0; +} + +int sway_mouse_binding_cmp(const void *a, const void *b) { + int cmp = 0; + if ((cmp = sway_binding_cmp_keys(a, b)) != 0) { + return cmp; + } + const struct sway_mouse_binding *binda = a, *bindb = b; + return lenient_strcmp(binda->command, bindb->command); +} + +int sway_mouse_binding_cmp_qsort(const void *a, const void *b) { + return sway_mouse_binding_cmp(*(void **)a, *(void **)b); +} + +void free_sway_mouse_binding(struct sway_mouse_binding *binding) { + if (binding->command) { + free(binding->command); + } + free(binding); +} + +struct sway_binding *sway_binding_dup(struct sway_binding *sb) { + struct sway_binding *new_sb = malloc(sizeof(struct sway_binding)); + if (!new_sb) { + return NULL; + } + + new_sb->order = sb->order; + new_sb->modifiers = sb->modifiers; + new_sb->command = strdup(sb->command); + + new_sb->keys = create_list(); + int i; + for (i = 0; i < sb->keys->length; ++i) { + xkb_keysym_t *key = malloc(sizeof(xkb_keysym_t)); + if (!key) { + free_sway_binding(new_sb); + return NULL; + } + *key = *(xkb_keysym_t *)sb->keys->items[i]; + list_add(new_sb->keys, key); + } + + return new_sb; +} + +struct bar_config *default_bar_config(void) { + struct bar_config *bar = NULL; + bar = malloc(sizeof(struct bar_config)); + if (!bar) { + return NULL; + } + if (!(bar->mode = strdup("dock"))) goto cleanup; + if (!(bar->hidden_state = strdup("hide"))) goto cleanup; + bar->modifier = WLC_BIT_MOD_LOGO; + bar->outputs = NULL; + bar->position = DESKTOP_SHELL_PANEL_POSITION_BOTTOM; + if (!(bar->bindings = create_list())) goto cleanup; + if (!(bar->status_command = strdup("while :; do date +'%Y-%m-%d %l:%M:%S %p'; sleep 1; done"))) goto cleanup; + bar->pango_markup = false; + bar->swaybar_command = NULL; + bar->font = NULL; + bar->height = -1; + bar->workspace_buttons = true; + bar->wrap_scroll = false; + bar->separator_symbol = NULL; + bar->strip_workspace_numbers = false; + bar->binding_mode_indicator = true; +#ifdef ENABLE_TRAY + bar->tray_output = NULL; + bar->icon_theme = NULL; + bar->tray_padding = 2; + bar->activate_button = 0x110; /* BTN_LEFT */ + bar->context_button = 0x111; /* BTN_RIGHT */ + bar->secondary_button = 0x112; /* BTN_MIDDLE */ +#endif + bar->verbose = false; + bar->pid = 0; + // set default colors + if (!(bar->colors.background = strndup("#000000ff", 9))) goto cleanup; + if (!(bar->colors.statusline = strndup("#ffffffff", 9))) goto cleanup; + if (!(bar->colors.separator = strndup("#666666ff", 9))) goto cleanup; + if (!(bar->colors.focused_workspace_border = strndup("#4c7899ff", 9))) goto cleanup; + if (!(bar->colors.focused_workspace_bg = strndup("#285577ff", 9))) goto cleanup; + if (!(bar->colors.focused_workspace_text = strndup("#ffffffff", 9))) goto cleanup; + if (!(bar->colors.active_workspace_border = strndup("#333333ff", 9))) goto cleanup; + if (!(bar->colors.active_workspace_bg = strndup("#5f676aff", 9))) goto cleanup; + if (!(bar->colors.active_workspace_text = strndup("#ffffffff", 9))) goto cleanup; + if (!(bar->colors.inactive_workspace_border = strndup("#333333ff", 9))) goto cleanup; + if (!(bar->colors.inactive_workspace_bg = strndup("#222222ff", 9))) goto cleanup; + if (!(bar->colors.inactive_workspace_text = strndup("#888888ff", 9))) goto cleanup; + if (!(bar->colors.urgent_workspace_border = strndup("#2f343aff", 9))) goto cleanup; + if (!(bar->colors.urgent_workspace_bg = strndup("#900000ff", 9))) goto cleanup; + if (!(bar->colors.urgent_workspace_text = strndup("#ffffffff", 9))) goto cleanup; + // if the following colors stay undefined, they fall back to background, + // statusline, separator and urgent_workspace_*. + bar->colors.focused_background = NULL; + bar->colors.focused_statusline = NULL; + bar->colors.focused_separator = NULL; + bar->colors.binding_mode_border = NULL; + bar->colors.binding_mode_bg = NULL; + bar->colors.binding_mode_text = NULL; + + list_add(config->bars, bar); + + return bar; + +cleanup: + free_bar(bar); + return NULL; +} diff --git a/sway/old/container.c b/sway/old/container.c new file mode 100644 index 00000000..82c0d877 --- /dev/null +++ b/sway/old/container.c @@ -0,0 +1,1024 @@ +#define _XOPEN_SOURCE 500 +#include +#include +#include +#include +#include +#include +#include +#include "sway/config.h" +#include "sway/container.h" +#include "sway/workspace.h" +#include "sway/focus.h" +#include "sway/border.h" +#include "sway/layout.h" +#include "sway/input_state.h" +#include "sway/ipc-server.h" +#include "sway/output.h" +#include "sway/view.h" +#include "log.h" +#include "stringop.h" + +#define ASSERT_NONNULL(PTR) \ + sway_assert (PTR, #PTR "must be non-null") + +static swayc_t *new_swayc(enum swayc_types type) { + // next id starts at 1 because 0 is assigned to root_container in layout.c + static size_t next_id = 1; + swayc_t *c = calloc(1, sizeof(swayc_t)); + if (!c) { + return NULL; + } + c->id = next_id++; + c->handle = -1; + c->gaps = -1; + c->layout = L_NONE; + c->workspace_layout = L_NONE; + c->type = type; + c->nb_master = 1; + c->nb_slave_groups = 1; + if (type != C_VIEW) { + c->children = create_list(); + } + return c; +} + +static void free_swayc(swayc_t *cont) { + if (!ASSERT_NONNULL(cont)) { + return; + } + if (cont->children) { + // remove children until there are no more, free_swayc calls + // remove_child, which removes child from this container + while (cont->children->length) { + free_swayc(cont->children->items[0]); + } + list_free(cont->children); + } + if (cont->unmanaged) { + list_free(cont->unmanaged); + } + if (cont->floating) { + while (cont->floating->length) { + free_swayc(cont->floating->items[0]); + } + list_free(cont->floating); + } + if (cont->marks) { + list_foreach(cont->marks, free); + list_free(cont->marks); + } + if (cont->parent) { + remove_child(cont); + } + if (cont->name) { + free(cont->name); + } + if (cont->class) { + free(cont->class); + } + if (cont->instance) { + free(cont->instance); + } + if (cont->app_id) { + free(cont->app_id); + } + if (cont->bg_pid != 0) { + terminate_swaybg(cont->bg_pid); + } + if (cont->border) { + if (cont->border->buffer) { + free(cont->border->buffer); + } + free(cont->border); + } + free(cont); +} + +static void update_root_geometry() { + int width = 0; + int height = 0; + swayc_t *child; + int child_width; + int child_height; + + for (int i = 0; i < root_container.children->length; ++i) { + child = root_container.children->items[i]; + child_width = child->width + child->x; + child_height = child->height + child->y; + if (child_width > width) { + width = child_width; + } + + if (child_height > height) { + height = child_height; + } + } + + root_container.width = width; + root_container.height = height; +} + +// New containers + +swayc_t *new_output(struct sway_output *sway_output) { + struct wlr_box size; + wlr_output_effective_resolution(sway_output->wlr_output, + &size.width, &size.height); + const char *name = sway_output->wlr_output->name; + // Find current outputs to see if this already exists + { + int i, len = root_container.children->length; + for (i = 0; i < len; ++i) { + swayc_t *op = root_container.children->items[i]; + const char *op_name = op->name; + if (op_name && name && strcmp(op_name, name) == 0) { + sway_log(L_DEBUG, "restoring output %p: %s", + sway_output, op_name); + return op; + } + } + } + + struct output_config *oc = NULL, *all = NULL; + int i; + for (i = 0; i < config->output_configs->length; ++i) { + struct output_config *cur = config->output_configs->items[i]; + if (strcasecmp(name, cur->name) == 0) { + sway_log(L_DEBUG, "Matched output config for %s", name); + oc = cur; + } + if (strcasecmp("*", cur->name) == 0) { + sway_log(L_DEBUG, "Matched wildcard output config for %s", name); + all = cur; + } + + if (oc && all) { + break; + } + } + + if (!oc) { + oc = all; + } + + if (oc && !oc->enabled) { + return NULL; + } + + swayc_t *output = new_swayc(C_OUTPUT); + output->_handle.output = sway_output; + output->name = name ? strdup(name) : NULL; + output->width = size.width; + output->height = size.width; + output->unmanaged = create_list(); + output->bg_pid = 0; + + apply_output_config(oc, output); + add_child(&root_container, output); + load_swaybars(); + + // Create workspace + char *ws_name = NULL; + swayc_t *ws = NULL; + + if (name) { + for (i = 0; i < config->workspace_outputs->length; ++i) { + struct workspace_output *wso = config->workspace_outputs->items[i]; + if (strcasecmp(wso->output, name) == 0) { + sway_log(L_DEBUG, "Matched workspace to output: %s for %s", wso->workspace, wso->output); + // Check if any other workspaces are using this name + if ((ws = workspace_by_name(wso->workspace))) { + // if yes, move those to this output, because they should be here + move_workspace_to(ws, output); + } else if (!ws_name) { + // set a workspace name in case we need to create a default one + ws_name = strdup(wso->workspace); + } + } + } + } + + if (output->children->length == 0) { + if (!ws_name) { + ws_name = workspace_next_name(output->name); + } + // create and initialize default workspace + sway_log(L_DEBUG, "Creating default workspace %s", ws_name); + ws = new_workspace(output, ws_name); + ws->is_focused = true; + } else { + sort_workspaces(output); + set_focused_container(output->children->items[0]); + } + + free(ws_name); + update_root_geometry(); + return output; +} + +swayc_t *new_workspace(swayc_t *output, const char *name) { + if (!ASSERT_NONNULL(output)) { + return NULL; + } + sway_log(L_DEBUG, "Added workspace %s for output %u", name, (unsigned int)output->handle); + swayc_t *workspace = new_swayc(C_WORKSPACE); + + workspace->prev_layout = L_NONE; + workspace->layout = default_layout(output); + workspace->workspace_layout = default_layout(output); + + workspace->x = output->x; + workspace->y = output->y; + workspace->width = output->width; + workspace->height = output->height; + workspace->name = !name ? NULL : strdup(name); + workspace->visible = false; + workspace->floating = create_list(); + + add_child(output, workspace); + sort_workspaces(output); + + return workspace; +} + +swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) { + if (!ASSERT_NONNULL(child) + && !sway_assert(!child->is_floating, "cannot create container around floating window")) { + return NULL; + } + swayc_t *cont = new_swayc(C_CONTAINER); + + sway_log(L_DEBUG, "creating container %p around %p", cont, child); + + cont->prev_layout = L_NONE; + cont->layout = layout; + cont->width = child->width; + cont->height = child->height; + cont->x = child->x; + cont->y = child->y; + cont->visible = child->visible; + cont->cached_geometry = child->cached_geometry; + cont->gaps = child->gaps; + + /* Container inherits all of workspaces children, layout and whatnot */ + if (child->type == C_WORKSPACE) { + swayc_t *workspace = child; + // reorder focus + cont->focused = workspace->focused; + workspace->focused = cont; + // set all children focu to container + int i; + for (i = 0; i < workspace->children->length; ++i) { + ((swayc_t *)workspace->children->items[i])->parent = cont; + } + // Swap children + list_t *tmp_list = workspace->children; + workspace->children = cont->children; + cont->children = tmp_list; + // add container to workspace chidren + add_child(workspace, cont); + // give them proper layouts + cont->layout = workspace->workspace_layout; + cont->prev_layout = workspace->prev_layout; + /* TODO: might break shit in move_container!!! workspace->layout = layout; */ + set_focused_container_for(workspace, get_focused_view(workspace)); + } else { // Or is built around container + swayc_t *parent = replace_child(child, cont); + if (parent) { + add_child(cont, child); + } + } + return cont; +} + +swayc_t *new_view(swayc_t *sibling, struct sway_view *view) { + if (!ASSERT_NONNULL(sibling)) { + return NULL; + } + const char *title = view->iface.get_prop(view, VIEW_PROP_TITLE); + swayc_t *swayc = new_swayc(C_VIEW); + sway_log(L_DEBUG, "Adding new view %p:%s to container %p %d", + swayc, title, sibling, sibling ? sibling->type : 0); + // Setup values + swayc->_handle.view = view; + + swayc->name = title ? strdup(title) : NULL; + + const char *class = view->iface.get_prop(view, VIEW_PROP_CLASS); + swayc->class = class ? strdup(class) : NULL; + + const char *instance = view->iface.get_prop(view, VIEW_PROP_INSTANCE); + swayc->instance = instance ? strdup(instance) : NULL; + + const char *app_id = view->iface.get_prop(view, VIEW_PROP_APP_ID); + swayc->app_id = app_id ? strdup(app_id) : NULL; + + swayc->visible = true; + swayc->is_focused = true; + swayc->sticky = false; + swayc->width = 0; + swayc->height = 0; + swayc->desired_width = -1; + swayc->desired_height = -1; + // setup border + swayc->border_type = config->border; + swayc->border_thickness = config->border_thickness; + + swayc->is_floating = false; + + if (sibling->type == C_WORKSPACE) { + // Case of focused workspace, just create as child of it + add_child(sibling, swayc); + } else { + // Regular case, create as sibling of current container + add_sibling(sibling, swayc); + } + return swayc; +} + +swayc_t *new_floating_view(wlc_handle handle) { + if (swayc_active_workspace() == NULL) { + return NULL; + } + const char *title = wlc_view_get_title(handle); + swayc_t *view = new_swayc(C_VIEW); + sway_log(L_DEBUG, "Adding new view %" PRIuPTR ":%x:%s as a floating view", + handle, wlc_view_get_type(handle), title); + // Setup values + view->handle = handle; + view->name = title ? strdup(title) : NULL; + const char *class = wlc_view_get_class(handle); + view->class = class ? strdup(class) : NULL; + const char *instance = wlc_view_get_instance(handle); + view->instance = instance ? strdup(instance) : NULL; + const char *app_id = wlc_view_get_app_id(handle); + view->app_id = app_id ? strdup(app_id) : NULL; + view->visible = true; + view->sticky = false; + + // Set the geometry of the floating view + const struct wlc_geometry *geometry = wlc_view_get_geometry(handle); + + // give it requested geometry, but place in center if possible + // in top left otherwise + if (geometry->size.w != 0) { + view->x = (swayc_active_workspace()->width - geometry->size.w) / 2; + } else { + view->x = 0; + } + if (geometry->size.h != 0) { + view->y = (swayc_active_workspace()->height - geometry->size.h) / 2; + } else { + view->y = 0; + } + + view->width = geometry->size.w; + view->height = geometry->size.h; + + view->desired_width = view->width; + view->desired_height = view->height; + + // setup border + view->border_type = config->floating_border; + view->border_thickness = config->floating_border_thickness; + + view->is_floating = true; + + // Case of focused workspace, just create as child of it + list_add(swayc_active_workspace()->floating, view); + view->parent = swayc_active_workspace(); + if (swayc_active_workspace()->focused == NULL) { + set_focused_container_for(swayc_active_workspace(), view); + } + return view; +} + +void floating_view_sane_size(swayc_t *view) { + // floating_minimum is used as sane value. + // floating_maximum has priority in case of conflict + // TODO: implement total_outputs_dimensions() + if (config->floating_minimum_height != -1 && + view->desired_height < config->floating_minimum_height) { + view->desired_height = config->floating_minimum_height; + } + if (config->floating_minimum_width != -1 && + view->desired_width < config->floating_minimum_width) { + view->desired_width = config->floating_minimum_width; + } + + // if 0 do not resize, only enforce max value + if (config->floating_maximum_height == 0) { + // Missing total_outputs_dimensions() using swayc_active_workspace() + config->floating_maximum_height = swayc_active_workspace()->height; + + } else if (config->floating_maximum_height != -1 && + view->desired_height > config->floating_maximum_height) { + view->desired_height = config->floating_maximum_height; + } + + // if 0 do not resize, only enforce max value + if (config->floating_maximum_width == 0) { + // Missing total_outputs_dimensions() using swayc_active_workspace() + config->floating_maximum_width = swayc_active_workspace()->width; + + } else if (config->floating_maximum_width != -1 && + view->desired_width > config->floating_maximum_width) { + view->desired_width = config->floating_maximum_width; + } + + sway_log(L_DEBUG, "Sane values for view to %d x %d @ %.f, %.f", + view->desired_width, view->desired_height, view->x, view->y); + + return; +} + + +// Destroy container + +swayc_t *destroy_output(swayc_t *output) { + if (!ASSERT_NONNULL(output)) { + return NULL; + } + if (output->children->length > 0) { + // TODO save workspaces when there are no outputs. + // TODO also check if there will ever be no outputs except for exiting + // program + if (root_container.children->length > 1) { + int p = root_container.children->items[0] == output; + // Move workspace from this output to another output + while (output->children->length) { + swayc_t *child = output->children->items[0]; + remove_child(child); + add_child(root_container.children->items[p], child); + } + sort_workspaces(root_container.children->items[p]); + update_visibility(root_container.children->items[p]); + arrange_windows(root_container.children->items[p], -1, -1); + } + } + sway_log(L_DEBUG, "OUTPUT: Destroying output '%" PRIuPTR "'", output->handle); + free_swayc(output); + update_root_geometry(); + return &root_container; +} + +swayc_t *destroy_workspace(swayc_t *workspace) { + if (!ASSERT_NONNULL(workspace)) { + return NULL; + } + + // Do not destroy this if it's the last workspace on this output + swayc_t *output = swayc_parent_by_type(workspace, C_OUTPUT); + if (output && output->children->length == 1) { + return NULL; + } + + swayc_t *parent = workspace->parent; + // destroy the WS if there are no children + if (workspace->children->length == 0 && workspace->floating->length == 0) { + sway_log(L_DEBUG, "destroying workspace '%s'", workspace->name); + ipc_event_workspace(workspace, NULL, "empty"); + } else { + // Move children to a different workspace on this output + swayc_t *new_workspace = NULL; + int i; + for(i = 0; i < output->children->length; i++) { + if(output->children->items[i] != workspace) { + break; + } + } + new_workspace = output->children->items[i]; + + sway_log(L_DEBUG, "moving children to different workspace '%s' -> '%s'", + workspace->name, new_workspace->name); + + for(i = 0; i < workspace->children->length; i++) { + move_container_to(workspace->children->items[i], new_workspace); + } + + for(i = 0; i < workspace->floating->length; i++) { + move_container_to(workspace->floating->items[i], new_workspace); + } + } + + free_swayc(workspace); + return parent; +} + +swayc_t *destroy_container(swayc_t *container) { + if (!ASSERT_NONNULL(container)) { + return NULL; + } + while (container->children->length == 0 && container->type == C_CONTAINER) { + sway_log(L_DEBUG, "Container: Destroying container '%p'", container); + swayc_t *parent = container->parent; + free_swayc(container); + container = parent; + } + return container; +} + +swayc_t *destroy_view(swayc_t *view) { + if (!ASSERT_NONNULL(view)) { + return NULL; + } + sway_log(L_DEBUG, "Destroying view '%p'", view); + swayc_t *parent = view->parent; + free_swayc(view); + + // Destroy empty containers + if (parent && parent->type == C_CONTAINER) { + return destroy_container(parent); + } + return parent; +} + +// Container lookup + + +swayc_t *swayc_by_test(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data) { + if (!container->children) { + return NULL; + } + // Special case for checking floating stuff + int i; + if (container->type == C_WORKSPACE) { + for (i = 0; i < container->floating->length; ++i) { + swayc_t *child = container->floating->items[i]; + if (test(child, data)) { + return child; + } + } + } + for (i = 0; i < container->children->length; ++i) { + swayc_t *child = container->children->items[i]; + if (test(child, data)) { + return child; + } else { + swayc_t *res = swayc_by_test(child, test, data); + if (res) { + return res; + } + } + } + return NULL; +} + +static bool test_name(swayc_t *view, void *data) { + if (!view || !view->name) { + return false; + } + return strcmp(view->name, data) == 0; +} + +swayc_t *swayc_by_name(const char *name) { + return swayc_by_test(&root_container, test_name, (void *)name); +} + +swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type) { + if (!ASSERT_NONNULL(container)) { + return NULL; + } + if (!sway_assert(type < C_TYPES && type >= C_ROOT, "invalid type")) { + return NULL; + } + do { + container = container->parent; + } while (container && container->type != type); + return container; +} + +swayc_t *swayc_parent_by_layout(swayc_t *container, enum swayc_layouts layout) { + if (!ASSERT_NONNULL(container)) { + return NULL; + } + if (!sway_assert(layout < L_LAYOUTS && layout >= L_NONE, "invalid layout")) { + return NULL; + } + do { + container = container->parent; + } while (container && container->layout != layout); + return container; +} + +swayc_t *swayc_focus_by_type(swayc_t *container, enum swayc_types type) { + if (!ASSERT_NONNULL(container)) { + return NULL; + } + if (!sway_assert(type < C_TYPES && type >= C_ROOT, "invalid type")) { + return NULL; + } + do { + container = container->focused; + } while (container && container->type != type); + return container; +} + +swayc_t *swayc_focus_by_layout(swayc_t *container, enum swayc_layouts layout) { + if (!ASSERT_NONNULL(container)) { + return NULL; + } + if (!sway_assert(layout < L_LAYOUTS && layout >= L_NONE, "invalid layout")) { + return NULL; + } + do { + container = container->focused; + } while (container && container->layout != layout); + return container; +} + + +static swayc_t *_swayc_by_handle_helper(wlc_handle handle, swayc_t *parent) { + if (!parent || !parent->children) { + return NULL; + } + int i, len; + swayc_t **child; + if (parent->type == C_WORKSPACE) { + len = parent->floating->length; + child = (swayc_t **)parent->floating->items; + for (i = 0; i < len; ++i, ++child) { + if ((*child)->handle == handle) { + return *child; + } + } + } + + len = parent->children->length; + child = (swayc_t**)parent->children->items; + for (i = 0; i < len; ++i, ++child) { + if ((*child)->handle == handle) { + return *child; + } else { + swayc_t *res; + if ((res = _swayc_by_handle_helper(handle, *child))) { + return res; + } + } + } + return NULL; +} + +swayc_t *swayc_by_handle(wlc_handle handle) { + return _swayc_by_handle_helper(handle, &root_container); +} + +swayc_t *swayc_active_output(void) { + return root_container.focused; +} + +swayc_t *swayc_active_workspace(void) { + return root_container.focused ? root_container.focused->focused : NULL; +} + +swayc_t *swayc_active_workspace_for(swayc_t *cont) { + if (!cont) { + return NULL; + } + switch (cont->type) { + case C_ROOT: + cont = cont->focused; + /* Fallthrough */ + + case C_OUTPUT: + cont = cont ? cont->focused : NULL; + /* Fallthrough */ + + case C_WORKSPACE: + return cont; + + default: + return swayc_parent_by_type(cont, C_WORKSPACE); + } +} + +static bool pointer_test(swayc_t *view, void *_origin) { + const struct wlc_point *origin = _origin; + // Determine the output that the view is under + swayc_t *parent = swayc_parent_by_type(view, C_OUTPUT); + if (origin->x >= view->x && origin->y >= view->y + && origin->x < view->x + view->width && origin->y < view->y + view->height + && view->visible && parent == root_container.focused) { + return true; + } + return false; +} + +swayc_t *container_under_pointer(void) { + // root.output->workspace + if (!root_container.focused) { + return NULL; + } + swayc_t *lookup = root_container.focused; + // Case of empty workspace + if (lookup->children && !lookup->unmanaged) { + return NULL; + } + double x, y; + wlc_pointer_get_position_v2(&x, &y); + struct wlc_point origin = { .x = x, .y = y }; + + while (lookup && lookup->type != C_VIEW) { + int i; + int len; + for (int _i = 0; lookup->unmanaged && _i < lookup->unmanaged->length; ++_i) { + wlc_handle *handle = lookup->unmanaged->items[_i]; + const struct wlc_geometry *geo = wlc_view_get_geometry(*handle); + if (origin.x >= geo->origin.x && origin.y >= geo->origin.y + && origin.x < geo->origin.x + (int)geo->size.w + && origin.y < geo->origin.y + (int)geo->size.h) { + // Hack: we force focus upon unmanaged views here + wlc_view_focus(*handle); + return NULL; + } + } + // if tabbed/stacked go directly to focused container, otherwise search + // children + if (lookup->layout == L_TABBED || lookup->layout == L_STACKED) { + lookup = lookup->focused; + continue; + } + // if workspace, search floating + if (lookup->type == C_WORKSPACE) { + i = len = lookup->floating->length; + bool got_floating = false; + while (--i > -1) { + if (pointer_test(lookup->floating->items[i], &origin)) { + lookup = lookup->floating->items[i]; + got_floating = true; + break; + } + } + if (got_floating) { + continue; + } + } + // search children + len = lookup->children->length; + for (i = 0; i < len; ++i) { + if (pointer_test(lookup->children->items[i], &origin)) { + lookup = lookup->children->items[i]; + break; + } + } + // when border and titles are done, this could happen + if (i == len) { + break; + } + } + return lookup; +} + +swayc_t *container_find(swayc_t *container, bool (*f)(swayc_t *, const void *), const void *data) { + if (container->children == NULL || container->children->length == 0) { + return NULL; + } + + swayc_t *con; + if (container->type == C_WORKSPACE) { + for (int i = 0; i < container->floating->length; ++i) { + con = container->floating->items[i]; + if (f(con, data)) { + return con; + } + con = container_find(con, f, data); + if (con != NULL) { + return con; + } + } + } + + for (int i = 0; i < container->children->length; ++i) { + con = container->children->items[i]; + if (f(con, data)) { + return con; + } + + con = container_find(con, f, data); + if (con != NULL) { + return con; + } + } + + return NULL; +} + +// Container information + +bool swayc_is_fullscreen(swayc_t *view) { + return view && view->type == C_VIEW && (wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN); +} + +bool swayc_is_active(swayc_t *view) { + return view && view->type == C_VIEW && (wlc_view_get_state(view->handle) & WLC_BIT_ACTIVATED); +} + +bool swayc_is_parent_of(swayc_t *parent, swayc_t *child) { + while (child != &root_container) { + child = child->parent; + if (child == parent) { + return true; + } + } + return false; +} + +bool swayc_is_child_of(swayc_t *child, swayc_t *parent) { + return swayc_is_parent_of(parent, child); +} + +bool swayc_is_empty_workspace(swayc_t *container) { + return container->type == C_WORKSPACE && container->children->length == 0; +} + +int swayc_gap(swayc_t *container) { + if (container->type == C_VIEW || container->type == C_CONTAINER) { + return container->gaps >= 0 ? container->gaps : config->gaps_inner; + } else if (container->type == C_WORKSPACE) { + int base = container->gaps >= 0 ? container->gaps : config->gaps_outer; + if (config->edge_gaps && !(config->smart_gaps && container->children->length == 1)) { + // the inner gap is created via a margin around each window which + // is half the gap size, so the workspace also needs half a gap + // size to make the outermost gap the same size (excluding the + // actual "outer gap" size which is handled independently) + return base + config->gaps_inner / 2; + } else if (config->smart_gaps && container->children->length == 1) { + return 0; + } else { + return base; + } + } else { + return 0; + } +} + +// Mapping + +void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), void *data) { + if (container) { + int i; + if (container->children) { + for (i = 0; i < container->children->length; ++i) { + swayc_t *child = container->children->items[i]; + container_map(child, f, data); + } + } + if (container->floating) { + for (i = 0; i < container->floating->length; ++i) { + swayc_t *child = container->floating->items[i]; + container_map(child, f, data); + } + } + f(container, data); + } +} + +void update_visibility_output(swayc_t *container, wlc_handle output) { + // Inherit visibility + swayc_t *parent = container->parent; + container->visible = parent->visible; + // special cases where visibility depends on focus + if (parent->type == C_OUTPUT || parent->layout == L_TABBED || + parent->layout == L_STACKED) { + container->visible = parent->focused == container && parent->visible; + } + // Set visibility and output for view + if (container->type == C_VIEW) { + wlc_view_set_output(container->handle, output); + wlc_view_set_mask(container->handle, container->visible ? VISIBLE : 0); + } + // Update visibility for children + else { + if (container->children) { + int i, len = container->children->length; + for (i = 0; i < len; ++i) { + update_visibility_output(container->children->items[i], output); + } + } + if (container->floating) { + int i, len = container->floating->length; + for (i = 0; i < len; ++i) { + update_visibility_output(container->floating->items[i], output); + } + } + } +} + +void update_visibility(swayc_t *container) { + if (!container) return; + switch (container->type) { + case C_ROOT: + container->visible = true; + if (container->children) { + int i, len = container->children->length; + for (i = 0; i < len; ++i) { + update_visibility(container->children->items[i]); + } + } + return; + + case C_OUTPUT: + container->visible = true; + if (container->children) { + int i, len = container->children->length; + for (i = 0; i < len; ++i) { + update_visibility_output(container->children->items[i], container->handle); + } + } + return; + + default: + { + swayc_t *op = swayc_parent_by_type(container, C_OUTPUT); + update_visibility_output(container, op->handle); + } + } +} + +void set_gaps(swayc_t *view, void *_data) { + int *data = _data; + if (!ASSERT_NONNULL(view)) { + return; + } + if (view->type == C_WORKSPACE || view->type == C_VIEW) { + view->gaps = *data; + } +} + +void add_gaps(swayc_t *view, void *_data) { + int *data = _data; + if (!ASSERT_NONNULL(view)) { + return; + } + if (view->type == C_WORKSPACE || view->type == C_VIEW) { + if ((view->gaps += *data) < 0) { + view->gaps = 0; + } + } +} + +static void close_view(swayc_t *container, void *data) { + if (container->type == C_VIEW) { + wlc_view_close(container->handle); + } +} + +void close_views(swayc_t *container) { + container_map(container, close_view, NULL); +} + +swayc_t *swayc_tabbed_stacked_ancestor(swayc_t *view) { + swayc_t *parent = NULL; + if (!ASSERT_NONNULL(view)) { + return NULL; + } + while (view->type != C_WORKSPACE && view->parent && view->parent->type != C_WORKSPACE) { + view = view->parent; + if (view->layout == L_TABBED || view->layout == L_STACKED) { + parent = view; + } + } + + return parent; +} + +swayc_t *swayc_tabbed_stacked_parent(swayc_t *con) { + if (!ASSERT_NONNULL(con)) { + return NULL; + } + if (con->parent && (con->parent->layout == L_TABBED || con->parent->layout == L_STACKED)) { + return con->parent; + } + return NULL; +} + +swayc_t *swayc_change_layout(swayc_t *container, enum swayc_layouts layout) { + // if layout change modifies the auto layout's major axis, swap width and height + // to preserve current ratios. + if (is_auto_layout(layout) && is_auto_layout(container->layout)) { + enum swayc_layouts prev_major = + container->layout == L_AUTO_LEFT || container->layout == L_AUTO_RIGHT + ? L_HORIZ : L_VERT; + enum swayc_layouts new_major = + layout == L_AUTO_LEFT || layout == L_AUTO_RIGHT + ? L_HORIZ : L_VERT; + if (new_major != prev_major) { + for (int i = 0; i < container->children->length; ++i) { + swayc_t *child = container->children->items[i]; + double h = child->height; + child->height = child->width; + child->width = h; + } + } + } + if (container->type == C_WORKSPACE) { + container->workspace_layout = layout; + if (layout == L_HORIZ || layout == L_VERT || is_auto_layout(layout)) { + container->layout = layout; + } + } else { + container->layout = layout; + } + return container; +} diff --git a/sway/old/criteria.c b/sway/old/criteria.c new file mode 100644 index 00000000..e8978ebe --- /dev/null +++ b/sway/old/criteria.c @@ -0,0 +1,451 @@ +#define _XOPEN_SOURCE 700 +#include +#include +#include +#include +#include "sway/criteria.h" +#include "sway/container.h" +#include "sway/config.h" +#include "stringop.h" +#include "list.h" +#include "log.h" + +enum criteria_type { // *must* keep in sync with criteria_strings[] + CRIT_CLASS, + CRIT_CON_ID, + CRIT_CON_MARK, + CRIT_FLOATING, + CRIT_ID, + CRIT_INSTANCE, + CRIT_TILING, + CRIT_TITLE, + CRIT_URGENT, + CRIT_WINDOW_ROLE, + CRIT_WINDOW_TYPE, + CRIT_WORKSPACE, + CRIT_LAST +}; + +static const char * const criteria_strings[CRIT_LAST] = { + [CRIT_CLASS] = "class", + [CRIT_CON_ID] = "con_id", + [CRIT_CON_MARK] = "con_mark", + [CRIT_FLOATING] = "floating", + [CRIT_ID] = "id", + [CRIT_INSTANCE] = "instance", + [CRIT_TILING] = "tiling", + [CRIT_TITLE] = "title", + [CRIT_URGENT] = "urgent", // either "latest" or "oldest" ... + [CRIT_WINDOW_ROLE] = "window_role", + [CRIT_WINDOW_TYPE] = "window_type", + [CRIT_WORKSPACE] = "workspace" +}; + +/** + * A single criteria token (ie. value/regex pair), + * e.g. 'class="some class regex"'. + */ +struct crit_token { + enum criteria_type type; + pcre *regex; + char *raw; +}; + +static void free_crit_token(struct crit_token *crit) { + pcre_free(crit->regex); + free(crit->raw); + free(crit); +} + +static void free_crit_tokens(list_t *crit_tokens) { + for (int i = 0; i < crit_tokens->length; i++) { + free_crit_token(crit_tokens->items[i]); + } + list_free(crit_tokens); +} + +// Extracts criteria string from its brackets. Returns new (duplicate) +// substring. +static char *criteria_from(const char *arg) { + char *criteria = NULL; + if (*arg == '[') { + criteria = strdup(arg + 1); + } else { + criteria = strdup(arg); + } + + int last = strlen(criteria) - 1; + if (criteria[last] == ']') { + criteria[last] = '\0'; + } + return criteria; +} + +// Return instances of c found in str. +static int countchr(char *str, char c) { + int found = 0; + for (int i = 0; str[i]; i++) { + if (str[i] == c) { + ++found; + } + } + return found; +} + +// criteria_str is e.g. '[class="some class regex" instance="instance name"]'. +// +// Will create array of pointers in buf, where first is duplicate of given +// string (must be freed) and the rest are pointers to names and values in the +// base string (every other, naturally). argc will be populated with the length +// of buf. +// +// Returns error string or NULL if successful. +static char *crit_tokens(int *argc, char ***buf, const char * const criteria_str) { + sway_log(L_DEBUG, "Parsing criteria: '%s'", criteria_str); + char *base = criteria_from(criteria_str); + char *head = base; + char *namep = head; // start of criteria name + char *valp = NULL; // start of value + + // We're going to place EOS markers where we need to and fill up an array + // of pointers to the start of each token (either name or value). + int pairs = countchr(base, '='); + int max_tokens = pairs * 2 + 1; // this gives us at least enough slots + + char **argv = *buf = calloc(max_tokens, sizeof(char*)); + argv[0] = base; // this needs to be freed by caller + bool quoted = true; + + *argc = 1; // uneven = name, even = value + while (*head && *argc < max_tokens) { + if (namep != head && *(head - 1) == '\\') { + // escaped character: don't try to parse this + } else if (*head == '=' && namep != head) { + if (*argc % 2 != 1) { + // we're not expecting a name + return strdup("Unable to parse criteria: " + "Found out of place equal sign"); + } else { + // name ends here + char *end = head; // don't want to rewind the head + while (*(end - 1) == ' ') { + --end; + } + *end = '\0'; + if (*(namep) == ' ') { + namep = strrchr(namep, ' ') + 1; + } + argv[*argc] = namep; + *argc += 1; + } + } else if (*head == '"') { + if (*argc % 2 != 0) { + // we're not expecting a value + return strdup("Unable to parse criteria: " + "Found quoted value where it was not expected"); + } else if (!valp) { // value starts here + valp = head + 1; + quoted = true; + } else { + // value ends here + argv[*argc] = valp; + *argc += 1; + *head = '\0'; + valp = NULL; + namep = head + 1; + } + } else if (*argc % 2 == 0 && *head != ' ') { + // parse unquoted values + if (!valp) { + quoted = false; + valp = head; // value starts here + } + } else if (valp && !quoted && *head == ' ') { + // value ends here + argv[*argc] = valp; + *argc += 1; + *head = '\0'; + valp = NULL; + namep = head + 1; + } + head++; + } + + // catch last unquoted value if needed + if (valp && !quoted && !*head) { + argv[*argc] = valp; + *argc += 1; + } + + return NULL; +} + +// Returns error string on failure or NULL otherwise. +static char *parse_criteria_name(enum criteria_type *type, char *name) { + *type = CRIT_LAST; + for (int i = 0; i < CRIT_LAST; i++) { + if (strcmp(criteria_strings[i], name) == 0) { + *type = (enum criteria_type) i; + break; + } + } + if (*type == CRIT_LAST) { + const char *fmt = "Criteria type '%s' is invalid or unsupported."; + int len = strlen(name) + strlen(fmt) - 1; + char *error = malloc(len); + snprintf(error, len, fmt, name); + return error; + } else if (*type == CRIT_URGENT || *type == CRIT_WINDOW_ROLE || + *type == CRIT_WINDOW_TYPE) { + // (we're just being helpful here) + const char *fmt = "\"%s\" criteria currently unsupported, " + "no window will match this"; + int len = strlen(fmt) + strlen(name) - 1; + char *error = malloc(len); + snprintf(error, len, fmt, name); + return error; + } + return NULL; +} + +// Returns error string on failure or NULL otherwise. +static char *generate_regex(pcre **regex, char *value) { + const char *reg_err; + int offset; + + *regex = pcre_compile(value, PCRE_UTF8 | PCRE_UCP, ®_err, &offset, NULL); + + if (!*regex) { + const char *fmt = "Regex compilation (for '%s') failed: %s"; + int len = strlen(fmt) + strlen(value) + strlen(reg_err) - 3; + char *error = malloc(len); + snprintf(error, len, fmt, value, reg_err); + return error; + } + return NULL; +} + +// Test whether the criterion corresponds to the currently focused window +static bool crit_is_focused(const char *value) { + return !strcmp(value, "focused") || !strcmp(value, "__focused__"); +} + +// Populate list with crit_tokens extracted from criteria string, returns error +// string or NULL if successful. +char *extract_crit_tokens(list_t *tokens, const char * const criteria) { + int argc; + char **argv = NULL, *error = NULL; + if ((error = crit_tokens(&argc, &argv, criteria))) { + goto ect_cleanup; + } + for (int i = 1; i + 1 < argc; i += 2) { + char* name = argv[i], *value = argv[i + 1]; + struct crit_token *token = calloc(1, sizeof(struct crit_token)); + token->raw = strdup(value); + + if ((error = parse_criteria_name(&token->type, name))) { + free_crit_token(token); + goto ect_cleanup; + } else if (token->type == CRIT_URGENT || crit_is_focused(value)) { + sway_log(L_DEBUG, "%s -> \"%s\"", name, value); + list_add(tokens, token); + } else if((error = generate_regex(&token->regex, value))) { + free_crit_token(token); + goto ect_cleanup; + } else { + sway_log(L_DEBUG, "%s -> /%s/", name, value); + list_add(tokens, token); + } + } +ect_cleanup: + free(argv[0]); // base string + free(argv); + return error; +} + +static int regex_cmp(const char *item, const pcre *regex) { + return pcre_exec(regex, NULL, item, strlen(item), 0, 0, NULL, 0); +} + +// test a single view if it matches list of criteria tokens (all of them). +static bool criteria_test(swayc_t *cont, list_t *tokens) { + if (cont->type != C_VIEW) { + return false; + } + int matches = 0; + for (int i = 0; i < tokens->length; i++) { + struct crit_token *crit = tokens->items[i]; + switch (crit->type) { + case CRIT_CLASS: + if (!cont->class) { + // ignore + } else if (crit_is_focused(crit->raw)) { + swayc_t *focused = get_focused_view(&root_container); + if (focused->class && strcmp(cont->class, focused->class) == 0) { + matches++; + } + } else if (crit->regex && regex_cmp(cont->class, crit->regex) == 0) { + matches++; + } + break; + case CRIT_CON_ID: { + char *endptr; + size_t crit_id = strtoul(crit->raw, &endptr, 10); + + if (*endptr == 0 && cont->id == crit_id) { + ++matches; + } + break; + } + case CRIT_CON_MARK: + if (crit->regex && cont->marks && (list_seq_find(cont->marks, (int (*)(const void *, const void *))regex_cmp, crit->regex) != -1)) { + // Make sure it isn't matching the NUL string + if ((strcmp(crit->raw, "") == 0) == (list_seq_find(cont->marks, (int (*)(const void *, const void *))strcmp, "") != -1)) { + ++matches; + } + } + break; + case CRIT_FLOATING: + if (cont->is_floating) { + matches++; + } + break; + case CRIT_ID: + if (!cont->app_id) { + // ignore + } else if (crit->regex && regex_cmp(cont->app_id, crit->regex) == 0) { + matches++; + } + break; + case CRIT_INSTANCE: + if (!cont->instance) { + // ignore + } else if (crit_is_focused(crit->raw)) { + swayc_t *focused = get_focused_view(&root_container); + if (focused->instance && strcmp(cont->instance, focused->instance) == 0) { + matches++; + } + } else if (crit->regex && regex_cmp(cont->instance, crit->regex) == 0) { + matches++; + } + break; + case CRIT_TILING: + if (!cont->is_floating) { + matches++; + } + break; + case CRIT_TITLE: + if (!cont->name) { + // ignore + } else if (crit_is_focused(crit->raw)) { + swayc_t *focused = get_focused_view(&root_container); + if (focused->name && strcmp(cont->name, focused->name) == 0) { + matches++; + } + } else if (crit->regex && regex_cmp(cont->name, crit->regex) == 0) { + matches++; + } + break; + case CRIT_URGENT: // "latest" or "oldest" + break; + case CRIT_WINDOW_ROLE: + break; + case CRIT_WINDOW_TYPE: + // TODO wlc indeed exposes this information + break; + case CRIT_WORKSPACE: ; + swayc_t *cont_ws = swayc_parent_by_type(cont, C_WORKSPACE); + if (!cont_ws || !cont_ws->name) { + // ignore + } else if (crit_is_focused(crit->raw)) { + swayc_t *focused_ws = swayc_active_workspace(); + if (focused_ws->name && strcmp(cont_ws->name, focused_ws->name) == 0) { + matches++; + } + } else if (crit->regex && regex_cmp(cont_ws->name, crit->regex) == 0) { + matches++; + } + break; + default: + sway_abort("Invalid criteria type (%i)", crit->type); + break; + } + } + return matches == tokens->length; +} + +int criteria_cmp(const void *a, const void *b) { + if (a == b) { + return 0; + } else if (!a) { + return -1; + } else if (!b) { + return 1; + } + const struct criteria *crit_a = a, *crit_b = b; + int cmp = lenient_strcmp(crit_a->cmdlist, crit_b->cmdlist); + if (cmp != 0) { + return cmp; + } + return lenient_strcmp(crit_a->crit_raw, crit_b->crit_raw); +} + +void free_criteria(struct criteria *crit) { + if (crit->tokens) { + free_crit_tokens(crit->tokens); + } + if (crit->cmdlist) { + free(crit->cmdlist); + } + if (crit->crit_raw) { + free(crit->crit_raw); + } + free(crit); +} + +bool criteria_any(swayc_t *cont, list_t *criteria) { + for (int i = 0; i < criteria->length; i++) { + struct criteria *bc = criteria->items[i]; + if (criteria_test(cont, bc->tokens)) { + return true; + } + } + return false; +} + +list_t *criteria_for(swayc_t *cont) { + list_t *criteria = config->criteria, *matches = create_list(); + for (int i = 0; i < criteria->length; i++) { + struct criteria *bc = criteria->items[i]; + if (criteria_test(cont, bc->tokens)) { + list_add(matches, bc); + } + } + return matches; +} + +struct list_tokens { + list_t *list; + list_t *tokens; +}; + +static void container_match_add(swayc_t *container, struct list_tokens *list_tokens) { + if (criteria_test(container, list_tokens->tokens)) { + list_add(list_tokens->list, container); + } +} + +list_t *container_for(list_t *tokens) { + struct list_tokens list_tokens = (struct list_tokens){create_list(), tokens}; + + container_map(&root_container, (void (*)(swayc_t *, void *))container_match_add, &list_tokens); + + for (int i = 0; i < scratchpad->length; ++i) { + swayc_t *c = scratchpad->items[i]; + if (criteria_test(c, tokens)) { + list_add(list_tokens.list, c); + } + } + + return list_tokens.list; +} diff --git a/sway/old/focus.c b/sway/old/focus.c new file mode 100644 index 00000000..66f7ee17 --- /dev/null +++ b/sway/old/focus.c @@ -0,0 +1,278 @@ +#include "stdbool.h" +#include +#include "sway/focus.h" +#include "sway/workspace.h" +#include "sway/layout.h" +#include "sway/config.h" +#include "sway/input_state.h" +#include "sway/ipc-server.h" +#include "sway/border.h" +#include "log.h" + +bool locked_container_focus = false; +bool suspend_workspace_cleanup = false; + +// switches parent focus to c. will switch it accordingly +static void update_focus(swayc_t *c) { + // Handle if focus switches + swayc_t *parent = c->parent; + if (!parent) return; + if (parent->focused != c) { + // Get previous focus + swayc_t *prev = parent->focused; + // Set new focus + parent->focused = c; + + switch (c->type) { + // Shouldn't happen + case C_ROOT: return; + + // Case where output changes + case C_OUTPUT: + wlc_output_focus(c->handle); + break; + + // Case where workspace changes + case C_WORKSPACE: + if (prev) { + ipc_event_workspace(prev, c, "focus"); + + // if the old workspace has no children, destroy it + if(prev->children->length == 0 && prev->floating->length == 0 && !suspend_workspace_cleanup) { + destroy_workspace(prev); + } else { + // update visibility of old workspace + update_visibility(prev); + } + } + // Update visibility of newly focused workspace + update_visibility(c); + break; + + default: + case C_VIEW: + case C_CONTAINER: + break; + } + } +} + +bool move_focus(enum movement_direction direction) { + swayc_t *old_view = get_focused_container(&root_container); + swayc_t *new_view = get_swayc_in_direction(old_view, direction); + if (!new_view) { + return false; + } else if (new_view->type == C_ROOT) { + sway_log(L_DEBUG, "Not setting focus above the workspace level"); + return false; + } else if (new_view->type == C_OUTPUT) { + return set_focused_container(swayc_active_workspace_for(new_view)); + } else if (direction == MOVE_PARENT || direction == MOVE_CHILD) { + return set_focused_container(new_view); + } else if (config->mouse_warping) { + swayc_t *old_op = old_view->type == C_OUTPUT ? + old_view : swayc_parent_by_type(old_view, C_OUTPUT); + swayc_t *focused = get_focused_view(new_view); + if (set_focused_container(focused)) { + if (old_op != swayc_active_output() && focused && focused->type == C_VIEW) { + center_pointer_on(focused); + } + return true; + } + } else { + return set_focused_container(get_focused_view(new_view)); + } + return false; +} + +swayc_t *get_focused_container(swayc_t *parent) { + if (!parent) { + return swayc_active_workspace(); + } + while (!parent->is_focused && parent->focused) { + parent = parent->focused; + } + return parent; +} + +bool set_focused_container(swayc_t *c) { + if (locked_container_focus || !c || !c->parent) { + return false; + } + + // current ("old") workspace for sending workspace change event later + swayc_t *old_ws = swayc_active_workspace(); + // keep track of child count so we can determine if it gets destroyed + int old_ws_child_count = 0; + if (old_ws) { + old_ws_child_count = old_ws->children->length + old_ws->floating->length; + } + + // current ("old") focused container + swayc_t *old_focus = get_focused_container(&root_container); + // if old_focus is a workspace, then it's the same workspace as + // old_ws, and we'll need to null its pointer too, since it will + // be destroyed in the update_focus() call + bool old_focus_was_ws = (old_focus->type == C_WORKSPACE); + + // workspace of new focused container + swayc_t *workspace = swayc_active_workspace_for(c); + + if (swayc_is_fullscreen(get_focused_container(workspace))) { + // if switching to a workspace with a fullscreen view, + // focus on the fullscreen view + c = get_focused_container(workspace); + } + + swayc_log(L_DEBUG, c, "Setting focus to %p:%" PRIuPTR, c, c->handle); + + if (c->type == C_VIEW) { + // dispatch a window event + ipc_event_window(c, "focus"); + } + + // update the global pointer + current_focus = c; + + // update container focus from here to root, making necessary changes along + // the way + swayc_t *p = c; + if (p->type != C_OUTPUT && p->type != C_ROOT) { + p->is_focused = true; + } + while (p != &root_container) { + update_focus(p); + p = p->parent; + p->is_focused = false; + } + + if (old_focus_was_ws && old_ws_child_count == 0) { + // this workspace was destroyed in update_focus(), so null the pointers + old_focus = NULL; + old_ws = NULL; + } + + if (!(wlc_view_get_type(p->handle) & WLC_BIT_POPUP)) { + if (old_focus) { + if (old_focus->type == C_VIEW) { + wlc_view_set_state(old_focus->handle, WLC_BIT_ACTIVATED, false); + } + update_container_border(old_focus); + } + if (c->type == C_VIEW) { + wlc_view_set_state(c->handle, WLC_BIT_ACTIVATED, true); + } + /* TODO WLR + if (!desktop_shell.is_locked) { + // If the system is locked, we do everything _but_ actually setting + // focus. This includes making our internals think that this view is + // focused. + wlc_view_focus(c->handle); + } + */ + if (c->parent->layout != L_TABBED && c->parent->layout != L_STACKED) { + update_container_border(c); + } + + swayc_t *parent = swayc_tabbed_stacked_ancestor(c); + if (parent != NULL) { + arrange_backgrounds(); + arrange_windows(parent, -1, -1); + } + } + + if (old_ws != workspace) { + // old_ws might be NULL here but that's ok + ipc_event_workspace(old_ws, workspace, "focus"); + } + + return true; +} + +bool set_focused_container_for(swayc_t *a, swayc_t *c) { + if (locked_container_focus || !c) { + return false; + } + swayc_t *find = c; + while (find != a && (find = find->parent)) { + if (find == &root_container) { + return false; + } + } + + // Get workspace for c, get that workspaces current focused container. + swayc_t *workspace = swayc_active_workspace_for(c); + swayc_t *focused = get_focused_view(workspace); + // if the workspace we are changing focus to has a fullscreen view return + if (swayc_is_fullscreen(focused) && c != focused) { + return false; + } + + // Check if we are changing a parent container that will see change + bool effective = true; + while (find != &root_container) { + if (find->parent->focused != find) { + effective = false; + } + find = find->parent; + } + if (effective) { + // Go to set_focused_container + return set_focused_container(c); + } + + sway_log(L_DEBUG, "Setting focus for %p:%" PRIuPTR " to %p:%" PRIuPTR, + a, a->handle, c, c->handle); + + c->is_focused = true; + swayc_t *p = c; + while (p != a) { + update_focus(p); + p = p->parent; + p->is_focused = false; + } + return true; +} + +swayc_t *get_focused_view(swayc_t *parent) { + swayc_t *c = parent; + while (c && c->type != C_VIEW) { + if (c->type == C_WORKSPACE && c->focused == NULL) { + return c; + } + c = c->focused; + } + if (c == NULL) { + c = swayc_active_workspace_for(parent); + } + return c; +} + +swayc_t *get_focused_float(swayc_t *ws) { + if(!sway_assert(ws->type == C_WORKSPACE, "must be of workspace type")) { + ws = swayc_active_workspace(); + } + if (ws->floating->length) { + return ws->floating->items[ws->floating->length - 1]; + } + return NULL; +} + +swayc_t *get_focused_view_include_floating(swayc_t *parent) { + swayc_t *c = parent; + swayc_t *f = NULL; + + while (c && c->type != C_VIEW) { + if (c->type == C_WORKSPACE && c->focused == NULL) { + return ((f = get_focused_float(c))) ? f : c; + } + + c = c->focused; + } + + if (c == NULL) { + c = swayc_active_workspace_for(parent); + } + + return c; +} diff --git a/sway/old/handlers.c b/sway/old/handlers.c new file mode 100644 index 00000000..33e75d6b --- /dev/null +++ b/sway/old/handlers.c @@ -0,0 +1,1143 @@ +#define _XOPEN_SOURCE 500 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sway/handlers.h" +#include "sway/border.h" +#include "sway/layout.h" +#include "sway/config.h" +#include "sway/commands.h" +#include "sway/workspace.h" +#include "sway/container.h" +#include "sway/output.h" +#include "sway/focus.h" +#include "sway/input_state.h" +#include "sway/extensions.h" +#include "sway/criteria.h" +#include "sway/ipc-server.h" +#include "sway/input.h" +#include "sway/security.h" +#include "list.h" +#include "stringop.h" +#include "log.h" + +// Event should be sent to client +#define EVENT_PASSTHROUGH false + +// Event handled by sway and should not be sent to client +#define EVENT_HANDLED true + +static struct panel_config *if_panel_find_config(struct wl_client *client) { + int i; + for (i = 0; i < desktop_shell.panels->length; i++) { + struct panel_config *config = desktop_shell.panels->items[i]; + if (config->client == client) { + return config; + } + } + return NULL; +} + +static struct background_config *if_background_find_config(struct wl_client *client) { + int i; + for (i = 0; i < desktop_shell.backgrounds->length; i++) { + struct background_config *config = desktop_shell.backgrounds->items[i]; + if (config->client == client) { + return config; + } + } + return NULL; +} + +static struct wlc_geometry compute_panel_geometry(struct panel_config *config) { + struct wlc_size resolution; + output_get_scaled_size(config->output, &resolution); + const struct wlc_geometry *old = wlc_view_get_geometry(config->handle); + struct wlc_geometry new; + + switch (config->panel_position) { + case DESKTOP_SHELL_PANEL_POSITION_TOP: + new.origin.x = 0; + new.origin.y = 0; + new.size.w = resolution.w; + new.size.h = old->size.h; + break; + case DESKTOP_SHELL_PANEL_POSITION_BOTTOM: + new.origin.x = 0; + new.origin.y = resolution.h - old->size.h; + new.size.w = resolution.w; + new.size.h = old->size.h; + break; + case DESKTOP_SHELL_PANEL_POSITION_LEFT: + new.origin.x = 0; + new.origin.y = 0; + new.size.w = old->size.w; + new.size.h = resolution.h; + break; + case DESKTOP_SHELL_PANEL_POSITION_RIGHT: + new.origin.x = resolution.w - old->size.w; + new.origin.y = 0; + new.size.w = old->size.w; + new.size.h = resolution.h; + break; + } + + return new; +} + +static void update_panel_geometry(struct panel_config *config) { + struct wlc_geometry geometry = compute_panel_geometry(config); + wlc_view_set_geometry(config->handle, 0, &geometry); +} + +static void update_panel_geometries(wlc_handle output) { + for (int i = 0; i < desktop_shell.panels->length; i++) { + struct panel_config *config = desktop_shell.panels->items[i]; + if (config->output == output) { + update_panel_geometry(config); + } + } +} + +static void update_background_geometry(struct background_config *config) { + struct wlc_geometry geometry = wlc_geometry_zero; + output_get_scaled_size(config->output, &geometry.size); + wlc_view_set_geometry(config->handle, 0, &geometry); +} + +static void update_background_geometries(wlc_handle output) { + for (int i = 0; i < desktop_shell.backgrounds->length; i++) { + struct background_config *config = desktop_shell.backgrounds->items[i]; + if (config->output == output) { + update_background_geometry(config); + } + } +} + +/* Handles */ + +static bool handle_input_created(struct libinput_device *device) { + const char *identifier = libinput_dev_unique_id(device); + if (!identifier) { + sway_log(L_ERROR, "Unable to allocate unique name for input device %p", + device); + return true; + } + sway_log(L_INFO, "Found input device (%s)", identifier); + + list_add(input_devices, device); + + struct input_config *ic = NULL; + int i; + for (i = 0; i < config->input_configs->length; ++i) { + struct input_config *cur = config->input_configs->items[i]; + if (strcasecmp(identifier, cur->identifier) == 0) { + sway_log(L_DEBUG, "Matched input config for %s", + identifier); + ic = cur; + break; + } + if (strcasecmp("*", cur->identifier) == 0) { + sway_log(L_DEBUG, "Matched wildcard input config for %s", + identifier); + ic = cur; + break; + } + } + + apply_input_config(ic, device); + return true; +} + +static void handle_input_destroyed(struct libinput_device *device) { + int i; + list_t *list = input_devices; + for (i = 0; i < list->length; ++i) { + if(((struct libinput_device *)list->items[i]) == device) { + list_del(list, i); + break; + } + } +} + +static bool handle_output_created(wlc_handle output) { + swayc_t *op = new_output(output); + + // Visibility mask to be able to make view invisible + wlc_output_set_mask(output, VISIBLE); + + if (!op) { + return false; + } + + // Switch to workspace if we need to + if (swayc_active_workspace() == NULL) { + swayc_t *ws = op->children->items[0]; + workspace_switch(ws); + } + + // Fixes issues with backgrounds and wlc + wlc_handle prev = wlc_get_focused_output(); + wlc_output_focus(output); + wlc_output_focus(prev); + return true; +} + +static void handle_output_destroyed(wlc_handle output) { + int i; + list_t *list = root_container.children; + for (i = 0; i < list->length; ++i) { + if (((swayc_t *)list->items[i])->handle == output) { + break; + } + } + if (i < list->length) { + destroy_output(list->items[i]); + } else { + return; + } + if (list->length > 0) { + // switch to other outputs active workspace + workspace_switch(((swayc_t *)root_container.children->items[0])->focused); + } +} + +static void handle_output_post_render(wlc_handle output) { + ipc_get_pixels(output); +} + +static void handle_view_pre_render(wlc_handle view) { + render_view_borders(view); +} + +static void handle_output_resolution_change(wlc_handle output, const struct wlc_size *from, const struct wlc_size *to) { + sway_log(L_DEBUG, "Output %u resolution changed to %d x %d", (unsigned int)output, to->w, to->h); + + swayc_t *c = swayc_by_handle(output); + if (!c) { + return; + } + c->width = to->w; + c->height = to->h; + + update_panel_geometries(output); + update_background_geometries(output); + + arrange_windows(&root_container, -1, -1); +} + +static void handle_output_focused(wlc_handle output, bool focus) { + swayc_t *c = swayc_by_handle(output); + // if for some reason this output doesn't exist, create it. + if (!c) { + handle_output_created(output); + } + if (focus) { + set_focused_container(get_focused_container(c)); + } +} + +static void ws_cleanup() { + swayc_t *op, *ws; + int i = 0, j; + if (!root_container.children) + return; + while (i < root_container.children->length) { + op = root_container.children->items[i++]; + if (!op->children) + continue; + j = 0; + while (j < op->children->length) { + ws = op->children->items[j++]; + if (ws->children->length == 0 && ws->floating->length == 0 && ws != op->focused) { + if (destroy_workspace(ws)) { + j--; + } + } + } + } +} + +static void positioner_place_window(wlc_handle handle) { + const struct wlc_geometry *anchor = wlc_view_positioner_get_anchor_rect(handle); + const struct wlc_size *sr = wlc_view_positioner_get_size(handle); + // a positioner is required to have a non-null anchor and a non-negative size + if (!anchor || !sr || + sr->w <= 0 || sr->h <= 0 || + anchor->size.w <= 0 || anchor->size.h <= 0) { + return; + } + const struct wlc_point offset = *wlc_view_positioner_get_offset(handle); + enum wlc_positioner_anchor_bit anchors = wlc_view_positioner_get_anchor(handle); + enum wlc_positioner_gravity_bit gravity = wlc_view_positioner_get_gravity(handle); + struct wlc_geometry geo = { + .origin = offset, + .size = *sr + }; + + if (anchors & WLC_BIT_ANCHOR_TOP) { + geo.origin.y += anchor->origin.y; + } else if (anchors & WLC_BIT_ANCHOR_BOTTOM) { + geo.origin.y += anchor->origin.y + anchor->size.h; + } else { + geo.origin.y += anchor->origin.y + anchor->size.h / 2; + } + if (anchors & WLC_BIT_ANCHOR_LEFT) { + geo.origin.x += anchor->origin.x; + } else if (anchors & WLC_BIT_ANCHOR_RIGHT) { + geo.origin.x += anchor->origin.x + anchor->size.w; + } else { + geo.origin.x += anchor->origin.x + anchor->size.w / 2; + } + + if (gravity & WLC_BIT_GRAVITY_TOP) { + geo.origin.y -= geo.size.h; + } else if (gravity & WLC_BIT_GRAVITY_BOTTOM) { + /* default */ + } else { + geo.origin.y -= geo.size.h / 2; + } + if (gravity & WLC_BIT_GRAVITY_LEFT) { + geo.origin.x -= geo.size.w; + } else if (gravity & WLC_BIT_GRAVITY_RIGHT) { + /* default */ + } else { + geo.origin.x -= geo.size.w / 2; + } + + sway_log(L_DEBUG, "xdg-positioner: placing window %" PRIuPTR " " + "sized (%u,%u) offset by (%d,%d), " + "anchor rectangle sized (%u,%u) at (%d,%d), " + "anchor edges: %s %s, gravity: %s %s", + handle, + sr->w, sr->h, offset.x, offset.y, + anchor->size.w, anchor->size.h, anchor->origin.x, anchor->origin.y, + anchors & WLC_BIT_ANCHOR_TOP ? "top" : + (anchors & WLC_BIT_ANCHOR_BOTTOM ? "bottom" : "middle"), + anchors & WLC_BIT_ANCHOR_LEFT ? "left" : + (anchors & WLC_BIT_ANCHOR_RIGHT ? "right" : "center"), + gravity & WLC_BIT_GRAVITY_TOP ? "top" : + (gravity & WLC_BIT_GRAVITY_BOTTOM ? "bottom" : "middle"), + gravity & WLC_BIT_GRAVITY_LEFT ? "left" : + (gravity & WLC_BIT_GRAVITY_RIGHT ? "right" : "center")); + + wlc_handle parent = wlc_view_get_parent(handle); + if (parent) { + const struct wlc_geometry *pg = wlc_view_get_geometry(parent); + geo.origin.x += pg->origin.x; + geo.origin.y += pg->origin.y; + } + wlc_view_set_geometry(handle, 0, &geo); +} + +static bool handle_view_created(wlc_handle handle) { + // if view is child of another view, the use that as focused container + wlc_handle parent = wlc_view_get_parent(handle); + swayc_t *focused = NULL; + swayc_t *newview = NULL; + swayc_t *current_ws = swayc_active_workspace(); + bool return_to_workspace = false; + struct wl_client *client = wlc_view_get_wl_client(handle); + struct wl_resource *resource = wlc_surface_get_wl_resource( + wlc_view_get_surface(handle)); + pid_t pid; + struct panel_config *panel_config = NULL; + struct background_config *background_config = NULL; + + panel_config = if_panel_find_config(client); + if (panel_config) { + panel_config->handle = handle; + update_panel_geometry(panel_config); + wlc_view_set_mask(handle, VISIBLE); + wlc_view_set_output(handle, panel_config->output); + wlc_view_bring_to_front(handle); + arrange_windows(&root_container, -1, -1); + return true; + } + + background_config = if_background_find_config(client); + if (background_config) { + background_config->handle = handle; + update_background_geometry(background_config); + wlc_view_set_mask(handle, VISIBLE); + wlc_view_set_output(handle, background_config->output); + wlc_view_send_to_back(handle); + return true; + } + + // Get parent container, to add view in + if (parent) { + focused = swayc_by_handle(parent); + } + + if (client) { + pid = wlc_view_get_pid(handle); + + if (pid) { + // using newview as a temp storage location here, + // rather than adding yet another workspace var + newview = workspace_for_pid(pid); + if (newview) { + focused = get_focused_container(newview); + return_to_workspace = true; + } + newview = NULL; + } + } + + swayc_t *prev_focus = get_focused_container(&root_container); + + if (!focused || focused->type == C_OUTPUT) { + focused = prev_focus; + // Move focus from floating view + if (focused->is_floating) { + // To workspace if there are no children + if (focused->parent->children->length == 0) { + focused = focused->parent; + } + // TODO find a better way of doing this + // Or to focused container + else { + focused = get_focused_container(focused->parent->children->items[0]); + } + } + } + + positioner_place_window(handle); + + sway_log(L_DEBUG, "handle:%" PRIuPTR " type:%x state:%x parent:%" PRIuPTR " " + "mask:%d (x:%d y:%d w:%d h:%d) title:%s " + "class:%s appid:%s", + handle, wlc_view_get_type(handle), wlc_view_get_state(handle), parent, + wlc_view_get_mask(handle), wlc_view_get_geometry(handle)->origin.x, + wlc_view_get_geometry(handle)->origin.y,wlc_view_get_geometry(handle)->size.w, + wlc_view_get_geometry(handle)->size.h, wlc_view_get_title(handle), + wlc_view_get_class(handle), wlc_view_get_app_id(handle)); + + // TODO properly figure out how each window should be handled. + switch (wlc_view_get_type(handle)) { + // regular view created regularly + case 0: + if (parent) { + newview = new_floating_view(handle); + } else { + newview = new_view(focused, handle); + wlc_view_set_state(handle, WLC_BIT_MAXIMIZED, true); + } + break; + + // Dmenu keeps viewfocus, but others with this flag don't, for now simulate + // dmenu + case WLC_BIT_OVERRIDE_REDIRECT: + wlc_view_focus(handle); + wlc_view_set_state(handle, WLC_BIT_ACTIVATED, true); + wlc_view_bring_to_front(handle); + break; + + // Firefox popups have this flag set. + case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED: + wlc_view_bring_to_front(handle); + locked_container_focus = true; + break; + + // Modals, get focus, popups do not + case WLC_BIT_MODAL: + wlc_view_focus(handle); + wlc_view_bring_to_front(handle); + newview = new_floating_view(handle); + /* fallthrough */ + case WLC_BIT_POPUP: + wlc_view_bring_to_front(handle); + break; + } + + // Prevent current ws from being destroyed, if empty + suspend_workspace_cleanup = true; + + if (newview) { + ipc_event_window(newview, "new"); + set_focused_container(newview); + wlc_view_set_mask(handle, VISIBLE); + swayc_t *output = swayc_parent_by_type(newview, C_OUTPUT); + arrange_windows(output, -1, -1); + // check if it matches for_window in config and execute if so + list_t *criteria = criteria_for(newview); + for (int i = 0; i < criteria->length; i++) { + struct criteria *crit = criteria->items[i]; + sway_log(L_DEBUG, "for_window '%s' matches new view %p, cmd: '%s'", + crit->crit_raw, newview, crit->cmdlist); + struct cmd_results *res = handle_command(crit->cmdlist, CONTEXT_CRITERIA); + if (res->status != CMD_SUCCESS) { + sway_log(L_ERROR, "Command '%s' failed: %s", res->input, res->error); + } + free_cmd_results(res); + // view must be focused for commands to affect it, so always + // refocus in-between command lists + set_focused_container(newview); + } + swayc_t *workspace = swayc_parent_by_type(focused, C_WORKSPACE); + if (workspace && workspace->fullscreen) { + set_focused_container(workspace->fullscreen); + } + for (int i = 0; i < decoration_state.csd_resources->length; ++i) { + struct wl_resource *res = decoration_state.csd_resources->items[i]; + if (res == resource) { + list_del(decoration_state.csd_resources, i); + server_decoration_enable_csd(handle); + break; + } + } + } else { + swayc_t *output = swayc_parent_by_type(focused, C_OUTPUT); + wlc_handle *h = malloc(sizeof(wlc_handle)); + if (!h) { + sway_log(L_ERROR, "Unable to allocate window handle, view handler bailing out"); + return true; + } + *h = handle; + sway_log(L_DEBUG, "Adding unmanaged window %p to %p", h, output->unmanaged); + list_add(output->unmanaged, h); + wlc_view_set_mask(handle, VISIBLE); + } + + if (return_to_workspace && current_ws != swayc_active_workspace()) { + // we were on one workspace, switched to another to add this view, + // now let's return to where we were + workspace_switch(current_ws); + set_focused_container(get_focused_container(current_ws)); + } + if (prev_focus && prev_focus->type == C_VIEW + && newview && criteria_any(newview, config->no_focus)) { + // Restore focus + swayc_t *ws = swayc_parent_by_type(newview, C_WORKSPACE); + if (!ws || ws != newview->parent + || ws->children->length + ws->floating->length != 1) { + sway_log(L_DEBUG, "no_focus: restoring focus to %s", prev_focus->name); + set_focused_container(prev_focus); + } + } + + suspend_workspace_cleanup = false; + ws_cleanup(); + return true; +} + +static void handle_view_destroyed(wlc_handle handle) { + sway_log(L_DEBUG, "Destroying window %" PRIuPTR, handle); + swayc_t *view = swayc_by_handle(handle); + + // destroy views by type + switch (wlc_view_get_type(handle)) { + // regular view created regularly + case 0: + case WLC_BIT_MODAL: + case WLC_BIT_POPUP: + break; + // DMENU has this flag, and takes view_focus, but other things with this + // flag don't + case WLC_BIT_OVERRIDE_REDIRECT: + break; + case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED: + locked_container_focus = false; + break; + } + + if (view) { + bool fullscreen = swayc_is_fullscreen(view); + remove_view_from_scratchpad(view); + swayc_t *parent = destroy_view(view), *iter = NULL; + if (parent) { + ipc_event_window(parent, "close"); + + // Destroy empty workspaces + if (parent->type == C_WORKSPACE && + parent->children->length == 0 && + parent->floating->length == 0 && + swayc_active_workspace() != parent && + !parent->visible) { + parent = destroy_workspace(parent); + } + + if (fullscreen) { + iter = parent; + while (iter) { + if (iter->fullscreen) { + iter->fullscreen = NULL; + break; + } + iter = iter->parent; + } + } + + + arrange_windows(iter ? iter : parent, -1, -1); + } + } else { + // Is it unmanaged? + int i; + for (i = 0; i < root_container.children->length; ++i) { + swayc_t *output = root_container.children->items[i]; + int j; + for (j = 0; j < output->unmanaged->length; ++j) { + wlc_handle *_handle = output->unmanaged->items[j]; + if (*_handle == handle) { + list_del(output->unmanaged, j); + free(_handle); + break; + } + } + } + // Is it in the scratchpad? + for (i = 0; i < scratchpad->length; ++i) { + swayc_t *item = scratchpad->items[i]; + if (item->handle == handle) { + list_del(scratchpad, i); + destroy_view(item); + break; + } + } + } + set_focused_container(get_focused_view(&root_container)); +} + +static void handle_view_focus(wlc_handle view, bool focus) { + return; +} + +static void handle_view_geometry_request(wlc_handle handle, const struct wlc_geometry *geometry) { + sway_log(L_DEBUG, "geometry request for %" PRIuPTR " %dx%d @ %d,%d", handle, + geometry->size.w, geometry->size.h, geometry->origin.x, geometry->origin.y); + // If the view is floating, then apply the geometry. + // Otherwise save the desired width/height for the view. + // This will not do anything for the time being as WLC improperly sends geometry requests + swayc_t *view = swayc_by_handle(handle); + if (view) { + view->desired_width = geometry->size.w; + view->desired_height = geometry->size.h; + + if (view->is_floating) { + floating_view_sane_size(view); + view->width = view->desired_width; + view->height = view->desired_height; + view->x = geometry->origin.x; + view->y = geometry->origin.y; + update_geometry(view); + } + } else { + wlc_view_set_geometry(handle, 0, geometry); + } +} + +static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit state, bool toggle) { + swayc_t *c = swayc_by_handle(view); + pid_t pid = wlc_view_get_pid(view); + switch (state) { + case WLC_BIT_FULLSCREEN: + if (!(get_feature_policy_mask(pid) & FEATURE_FULLSCREEN)) { + sway_log(L_INFO, "Denying fullscreen to %d (%s)", pid, c->name); + break; + } + // i3 just lets it become fullscreen + wlc_view_set_state(view, state, toggle); + if (c) { + sway_log(L_DEBUG, "setting view %" PRIuPTR " %s, fullscreen %d", view, c->name, toggle); + arrange_windows(c->parent, -1, -1); + // Set it as focused window for that workspace if its going fullscreen + swayc_t *ws = swayc_parent_by_type(c, C_WORKSPACE); + if (toggle) { + // Set ws focus to c + set_focused_container_for(ws, c); + ws->fullscreen = c; + } else { + ws->fullscreen = NULL; + } + } + break; + case WLC_BIT_MAXIMIZED: + case WLC_BIT_RESIZING: + case WLC_BIT_MOVING: + break; + case WLC_BIT_ACTIVATED: + sway_log(L_DEBUG, "View %p requested to be activated", c); + break; + } + return; +} + +static void handle_view_properties_updated(wlc_handle view, uint32_t mask) { + if (mask == WLC_BIT_PROPERTY_TITLE) { + swayc_t *c = swayc_by_handle(view); + if (!c) { + return; + } + + // update window title + const char *new_name = wlc_view_get_title(view); + + if (new_name) { + if (!c->name || strcmp(c->name, new_name) != 0) { + free(c->name); + c->name = strdup(new_name); + swayc_t *p = swayc_tabbed_stacked_ancestor(c); + if (p) { + // TODO: we only got the topmost tabbed/stacked container, update borders of all containers on the path + update_container_border(get_focused_view(p)); + } else if (c->border_type == B_NORMAL) { + update_container_border(c); + } + ipc_event_window(c, "title"); + } + } + } +} + +static void handle_binding_command(struct sway_binding *binding) { + struct sway_binding *binding_copy = binding; + bool reload = false; + // if this is a reload command we need to make a duplicate of the + // binding since it will be gone after the reload has completed. + if (strcasecmp(binding->command, "reload") == 0) { + binding_copy = sway_binding_dup(binding); + if (!binding_copy) { + sway_log(L_ERROR, "Unable to duplicate binding during reload"); + return; + } + reload = true; + } + + struct cmd_results *res = handle_command(binding->command, CONTEXT_BINDING); + if (res->status != CMD_SUCCESS) { + sway_log(L_ERROR, "Command '%s' failed: %s", res->input, res->error); + } + ipc_event_binding_keyboard(binding_copy); + + if (reload) { // free the binding if we made a copy + free_sway_binding(binding_copy); + } + + free_cmd_results(res); +} + +static bool handle_bindsym(struct sway_binding *binding, uint32_t keysym, uint32_t keycode) { + int i; + for (i = 0; i < binding->keys->length; ++i) { + if (binding->bindcode) { + xkb_keycode_t *key = binding->keys->items[i]; + if (keycode == *key) { + handle_binding_command(binding); + return true; + } + } else { + xkb_keysym_t *key = binding->keys->items[i]; + if (keysym == *key) { + handle_binding_command(binding); + return true; + } + } + } + + return false; +} + +static bool valid_bindsym(struct sway_binding *binding) { + bool match = false; + int i; + for (i = 0; i < binding->keys->length; ++i) { + if (binding->bindcode) { + xkb_keycode_t *key = binding->keys->items[i]; + if ((match = check_key(0, *key)) == false) { + break; + } + } else { + xkb_keysym_t *key = binding->keys->items[i]; + if ((match = check_key(*key, 0)) == false) { + break; + } + } + } + + return match; +} + +static bool handle_bindsym_release(struct sway_binding *binding) { + if (binding->keys->length == 1) { + xkb_keysym_t *key = binding->keys->items[0]; + if (check_released_key(*key)) { + handle_binding_command(binding); + return true; + } + } + + return false; +} + +static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers, + uint32_t key, enum wlc_key_state state) { + + if (desktop_shell.is_locked) { + return EVENT_PASSTHROUGH; + } + + // reset pointer mode on keypress + if (state == WLC_KEY_STATE_PRESSED && pointer_state.mode) { + pointer_mode_reset(); + } + + struct sway_mode *mode = config->current_mode; + + struct wlc_modifiers no_mods = { 0, 0 }; + uint32_t sym = tolower(wlc_keyboard_get_keysym_for_key(key, &no_mods)); + + int i; + + if (state == WLC_KEY_STATE_PRESSED) { + press_key(sym, key); + } else { // WLC_KEY_STATE_RELEASED + release_key(sym, key); + } + + // handle bar modifiers pressed/released + uint32_t modifier; + for (i = 0; i < config->active_bar_modifiers->length; ++i) { + modifier = *(uint32_t *)config->active_bar_modifiers->items[i]; + + switch (modifier_state_changed(modifiers->mods, modifier)) { + case MOD_STATE_PRESSED: + ipc_event_modifier(modifier, "pressed"); + break; + case MOD_STATE_RELEASED: + ipc_event_modifier(modifier, "released"); + break; + } + } + // update modifiers state + modifiers_state_update(modifiers->mods); + + // handle bindings + list_t *candidates = create_list(); + for (i = 0; i < mode->bindings->length; ++i) { + struct sway_binding *binding = mode->bindings->items[i]; + if ((modifiers->mods ^ binding->modifiers) == 0) { + switch (state) { + case WLC_KEY_STATE_PRESSED: + if (!binding->release && valid_bindsym(binding)) { + list_add(candidates, binding); + } + break; + case WLC_KEY_STATE_RELEASED: + if (binding->release && handle_bindsym_release(binding)) { + list_free(candidates); + return EVENT_HANDLED; + } + break; + } + } + } + + for (i = 0; i < candidates->length; ++i) { + struct sway_binding *binding = candidates->items[i]; + if (state == WLC_KEY_STATE_PRESSED) { + if (!binding->release && handle_bindsym(binding, sym, key)) { + list_free(candidates); + return EVENT_HANDLED; + } + } + } + + list_free(candidates); + + swayc_t *focused = get_focused_container(&root_container); + if (focused->type == C_VIEW) { + pid_t pid = wlc_view_get_pid(focused->handle); + if (!(get_feature_policy_mask(pid) & FEATURE_KEYBOARD)) { + return EVENT_HANDLED; + } + } + return EVENT_PASSTHROUGH; +} + +static bool handle_pointer_motion(wlc_handle handle, uint32_t time, double x, double y) { + if (desktop_shell.is_locked) { + return EVENT_PASSTHROUGH; + } + + double new_x = x; + double new_y = y; + // Switch to adjacent output if touching output edge. + // + // Since this doesn't currently support moving windows between outputs we + // don't do the switch if the pointer is in a mode. + if (config->seamless_mouse && !pointer_state.mode && + !pointer_state.left.held && !pointer_state.right.held && !pointer_state.scroll.held) { + + swayc_t *output = swayc_active_output(), *adjacent = NULL; + struct wlc_point abs_pos = { .x = x + output->x, .y = y + output->y }; + if (x <= 0) { // Left edge + if ((adjacent = swayc_adjacent_output(output, MOVE_LEFT, &abs_pos, false))) { + if (workspace_switch(swayc_active_workspace_for(adjacent))) { + new_x = adjacent->width; + // adjust for differently aligned outputs (well, this is + // only correct when the two outputs have the same + // resolution or the same dpi I guess, it should take + // physical attributes into account) + new_y += (output->y - adjacent->y); + } + } + } else if (x >= output->width) { // Right edge + if ((adjacent = swayc_adjacent_output(output, MOVE_RIGHT, &abs_pos, false))) { + if (workspace_switch(swayc_active_workspace_for(adjacent))) { + new_x = 0; + new_y += (output->y - adjacent->y); + } + } + } else if (y <= 0) { // Top edge + if ((adjacent = swayc_adjacent_output(output, MOVE_UP, &abs_pos, false))) { + if (workspace_switch(swayc_active_workspace_for(adjacent))) { + new_y = adjacent->height; + new_x += (output->x - adjacent->x); + } + } + } else if (y >= output->height) { // Bottom edge + if ((adjacent = swayc_adjacent_output(output, MOVE_DOWN, &abs_pos, false))) { + if (workspace_switch(swayc_active_workspace_for(adjacent))) { + new_y = 0; + new_x += (output->x - adjacent->x); + } + } + } + } + + pointer_position_set(new_x, new_y, false); + + swayc_t *focused = get_focused_container(&root_container); + if (focused->type == C_VIEW) { + pid_t pid = wlc_view_get_pid(focused->handle); + if (!(get_feature_policy_mask(pid) & FEATURE_MOUSE)) { + return EVENT_HANDLED; + } + } + + return EVENT_PASSTHROUGH; +} + +static bool swayc_border_check(swayc_t *c, const void *_origin) { + const struct wlc_point *origin = _origin; + const struct wlc_geometry title_bar = c->title_bar_geometry; + + if (c->border_type != B_NORMAL) { + return false; + } + + if (origin->x >= title_bar.origin.x && origin->y >= title_bar.origin.y + && origin->x < title_bar.origin.x + (int32_t)title_bar.size.w + && origin->y < title_bar.origin.y + (int32_t)title_bar.size.h) { + return true; + } + return false; +} + +static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers, + uint32_t button, enum wlc_button_state state, const struct wlc_point *origin) { + + // Update view pointer is on + pointer_state.view = container_under_pointer(); + + struct sway_mode *mode = config->current_mode; + // handle bindings + for (int i = 0; i < mode->bindings->length; ++i) { + struct sway_binding *binding = mode->bindings->items[i]; + if ((modifiers->mods ^ binding->modifiers) == 0) { + switch (state) { + case WLC_BUTTON_STATE_PRESSED: + if (!binding->release && handle_bindsym(binding, button, 0)) { + return EVENT_HANDLED; + } + break; + case WLC_BUTTON_STATE_RELEASED: + if (binding->release && handle_bindsym(binding, button, 0)) { + return EVENT_HANDLED; + } + break; + } + } + } + + // Update pointer_state + switch (button) { + case M_LEFT_CLICK: + if (state == WLC_BUTTON_STATE_PRESSED) { + pointer_state.left.held = true; + pointer_state.left.x = origin->x; + pointer_state.left.y = origin->y; + pointer_state.left.view = pointer_state.view; + } else { + pointer_state.left.held = false; + } + break; + + case M_RIGHT_CLICK: + if (state == WLC_BUTTON_STATE_PRESSED) { + pointer_state.right.held = true; + pointer_state.right.x = origin->x; + pointer_state.right.y = origin->y; + pointer_state.right.view = pointer_state.view; + } else { + pointer_state.right.held = false; + } + break; + + case M_SCROLL_CLICK: + if (state == WLC_BUTTON_STATE_PRESSED) { + pointer_state.scroll.held = true; + pointer_state.scroll.x = origin->x; + pointer_state.scroll.y = origin->y; + pointer_state.scroll.view = pointer_state.view; + } else { + pointer_state.scroll.held = false; + } + break; + + //TODO scrolling behavior + case M_SCROLL_UP: + case M_SCROLL_DOWN: + break; + } + + // get focused window and check if to change focus on mouse click + swayc_t *focused = get_focused_container(&root_container); + + // don't change focus or mode if fullscreen + if (swayc_is_fullscreen(focused)) { + if (focused->type == C_VIEW) { + pid_t pid = wlc_view_get_pid(focused->handle); + if (!(get_feature_policy_mask(pid) & FEATURE_MOUSE)) { + return EVENT_HANDLED; + } + } + return EVENT_PASSTHROUGH; + } + + // set pointer mode only if floating mod has been set + if (config->floating_mod) { + pointer_mode_set(button, !(modifiers->mods ^ config->floating_mod)); + } + + // Check whether to change focus + swayc_t *pointer = pointer_state.view; + if (pointer) { + swayc_t *ws = swayc_parent_by_type(focused, C_WORKSPACE); + if (ws != NULL) { + swayc_t *find = container_find(ws, &swayc_border_check, origin); + if (find != NULL) { + set_focused_container(find); + return EVENT_HANDLED; + } + } + + if (focused != pointer) { + set_focused_container(pointer_state.view); + } + // Send to front if floating + if (pointer->is_floating) { + int i; + for (i = 0; i < pointer->parent->floating->length; i++) { + if (pointer->parent->floating->items[i] == pointer) { + list_del(pointer->parent->floating, i); + list_add(pointer->parent->floating, pointer); + break; + } + } + wlc_view_bring_to_front(pointer->handle); + } + } + + // Return if mode has been set + if (pointer_state.mode) { + return EVENT_HANDLED; + } + + if (focused->type == C_VIEW) { + pid_t pid = wlc_view_get_pid(focused->handle); + if (!(get_feature_policy_mask(pid) & FEATURE_MOUSE)) { + return EVENT_HANDLED; + } + } + + // Always send mouse release + if (state == WLC_BUTTON_STATE_RELEASED) { + return EVENT_PASSTHROUGH; + } + + // Finally send click + return EVENT_PASSTHROUGH; +} + +bool handle_pointer_scroll(wlc_handle view, uint32_t time, const struct wlc_modifiers* modifiers, + uint8_t axis_bits, double _amount[2]) { + if (!(modifiers->mods ^ config->floating_mod)) { + int x_amount = (int)_amount[0]; + int y_amount = (int)_amount[1]; + + if (x_amount > 0 && strcmp(config->floating_scroll_up_cmd, "")) { + handle_command(config->floating_scroll_up_cmd, CONTEXT_BINDING); + return EVENT_HANDLED; + } else if (x_amount < 0 && strcmp(config->floating_scroll_down_cmd, "")) { + handle_command(config->floating_scroll_down_cmd, CONTEXT_BINDING); + return EVENT_HANDLED; + } + + if (y_amount > 0 && strcmp(config->floating_scroll_right_cmd, "")) { + handle_command(config->floating_scroll_right_cmd, CONTEXT_BINDING); + return EVENT_HANDLED; + } else if (y_amount < 0 && strcmp(config->floating_scroll_left_cmd, "")) { + handle_command(config->floating_scroll_left_cmd, CONTEXT_BINDING); + return EVENT_HANDLED; + } + } + return EVENT_PASSTHROUGH; +} + +static void handle_wlc_ready(void) { + sway_log(L_DEBUG, "Compositor is ready, executing cmds in queue"); + // Execute commands until there are none left + config->active = true; + while (config->cmd_queue->length) { + char *line = config->cmd_queue->items[0]; + struct cmd_results *res = handle_command(line, CONTEXT_CONFIG); + if (res->status != CMD_SUCCESS) { + sway_log(L_ERROR, "Error on line '%s': %s", line, res->error); + } + free_cmd_results(res); + free(line); + list_del(config->cmd_queue, 0); + } +} + +void register_wlc_handlers() { + wlc_set_output_created_cb(handle_output_created); + wlc_set_output_destroyed_cb(handle_output_destroyed); + wlc_set_output_resolution_cb(handle_output_resolution_change); + wlc_set_output_focus_cb(handle_output_focused); + wlc_set_output_render_post_cb(handle_output_post_render); + wlc_set_view_created_cb(handle_view_created); + wlc_set_view_destroyed_cb(handle_view_destroyed); + wlc_set_view_focus_cb(handle_view_focus); + wlc_set_view_render_pre_cb(handle_view_pre_render); + wlc_set_view_request_geometry_cb(handle_view_geometry_request); + wlc_set_view_request_state_cb(handle_view_state_request); + wlc_set_view_properties_updated_cb(handle_view_properties_updated); + wlc_set_keyboard_key_cb(handle_key); + wlc_set_pointer_motion_cb_v2(handle_pointer_motion); + wlc_set_pointer_button_cb(handle_pointer_button); + wlc_set_pointer_scroll_cb(handle_pointer_scroll); + wlc_set_compositor_ready_cb(handle_wlc_ready); + wlc_set_input_created_cb(handle_input_created); + wlc_set_input_destroyed_cb(handle_input_destroyed); +} diff --git a/sway/old/input_state.c b/sway/old/input_state.c new file mode 100644 index 00000000..04aafd37 --- /dev/null +++ b/sway/old/input_state.c @@ -0,0 +1,490 @@ +#include +#include +#include +#include "sway/input_state.h" +#include "sway/config.h" +#include "log.h" + +#define KEY_STATE_MAX_LENGTH 64 + +struct key_state { + /* + * Aims to store state regardless of modifiers. + * If you press a key, then hold shift, then release the key, we'll + * get two different key syms, but the same key code. This handles + * that scenario and makes sure we can use the right bindings. + */ + uint32_t key_sym; + uint32_t alt_sym; + uint32_t key_code; +}; + +static struct key_state key_state_array[KEY_STATE_MAX_LENGTH]; + +static struct key_state last_released; + +static uint32_t modifiers_state; + +void input_init(void) { + int i; + for (i = 0; i < KEY_STATE_MAX_LENGTH; ++i) { + struct key_state none = { 0, 0, 0 }; + key_state_array[i] = none; + } + + struct key_state none = { 0, 0, 0 }; + last_released = none; + + modifiers_state = 0; +} + +uint32_t modifier_state_changed(uint32_t new_state, uint32_t mod) { + if ((new_state & mod) != 0) { // pressed + if ((modifiers_state & mod) != 0) { // already pressed + return MOD_STATE_UNCHANGED; + } else { // pressed + return MOD_STATE_PRESSED; + } + } else { // not pressed + if ((modifiers_state & mod) != 0) { // released + return MOD_STATE_RELEASED; + } else { // already released + return MOD_STATE_UNCHANGED; + } + } +} + +void modifiers_state_update(uint32_t new_state) { + modifiers_state = new_state; +} + +static uint8_t find_key(uint32_t key_sym, uint32_t key_code, bool update) { + int i; + for (i = 0; i < KEY_STATE_MAX_LENGTH; ++i) { + if (0 == key_sym && 0 == key_code && key_state_array[i].key_sym == 0) { + break; + } + if (key_sym != 0 && (key_state_array[i].key_sym == key_sym + || key_state_array[i].alt_sym == key_sym)) { + break; + } + if (update && key_state_array[i].key_code == key_code) { + key_state_array[i].alt_sym = key_sym; + break; + } + if (key_sym == 0 && key_code != 0 && key_state_array[i].key_code == key_code) { + break; + } + } + return i; +} + +bool check_key(uint32_t key_sym, uint32_t key_code) { + return find_key(key_sym, key_code, false) < KEY_STATE_MAX_LENGTH; +} + +bool check_released_key(uint32_t key_sym) { + return (key_sym != 0 + && (last_released.key_sym == key_sym + || last_released.alt_sym == key_sym)); +} + +void press_key(uint32_t key_sym, uint32_t key_code) { + if (key_code == 0) { + return; + } + // Check if key exists + if (!check_key(key_sym, key_code)) { + // Check that we don't exceed buffer length + int insert = find_key(0, 0, true); + if (insert < KEY_STATE_MAX_LENGTH) { + key_state_array[insert].key_sym = key_sym; + key_state_array[insert].key_code = key_code; + } + } +} + +void release_key(uint32_t key_sym, uint32_t key_code) { + uint8_t index = find_key(key_sym, key_code, true); + if (index < KEY_STATE_MAX_LENGTH) { + last_released.key_sym = key_state_array[index].key_sym; + last_released.alt_sym = key_state_array[index].alt_sym; + last_released.key_code = key_state_array[index].key_code; + struct key_state none = { 0, 0, 0 }; + key_state_array[index] = none; + } +} + +// Pointer state and mode + +struct pointer_state pointer_state; + +static struct mode_state { + // initial view state + double x, y, w, h; + swayc_t *ptr; + // Containers used for resizing horizontally + struct { + double w; + swayc_t *ptr; + struct { + double w; + swayc_t *ptr; + } parent; + } horiz; + // Containers used for resizing vertically + struct { + double h; + swayc_t *ptr; + struct { + double h; + swayc_t *ptr; + } parent; + } vert; +} initial; + +static struct { + bool left; + bool top; +} lock; + +// initial set/unset + +static void set_initial_view(swayc_t *view) { + initial.ptr = view; + initial.x = view->x; + initial.y = view->y; + initial.w = view->width; + initial.h = view->height; +} + +static void set_initial_sibling(void) { + bool reset = true; + swayc_t *ws = swayc_active_workspace_for(initial.ptr); + if ((initial.horiz.ptr = get_swayc_in_direction_under(initial.ptr, + lock.left ? MOVE_RIGHT: MOVE_LEFT, ws))) { + initial.horiz.w = initial.horiz.ptr->width; + initial.horiz.parent.ptr = get_swayc_in_direction_under(initial.horiz.ptr, + lock.left ? MOVE_LEFT : MOVE_RIGHT, ws); + initial.horiz.parent.w = initial.horiz.parent.ptr->width; + reset = false; + } + if ((initial.vert.ptr = get_swayc_in_direction_under(initial.ptr, + lock.top ? MOVE_DOWN: MOVE_UP, ws))) { + initial.vert.h = initial.vert.ptr->height; + initial.vert.parent.ptr = get_swayc_in_direction_under(initial.vert.ptr, + lock.top ? MOVE_UP : MOVE_DOWN, ws); + initial.vert.parent.h = initial.vert.parent.ptr->height; + reset = false; + } + // If nothing will change just undo the mode + if (reset) { + pointer_state.mode = 0; + } +} + +static void reset_initial_view(void) { + initial.ptr->x = initial.x; + initial.ptr->y = initial.y; + initial.ptr->width = initial.w; + initial.ptr->height = initial.h; + arrange_windows(initial.ptr, -1, -1); + pointer_state.mode = 0; +} + +static void reset_initial_sibling(void) { + initial.horiz.ptr->width = initial.horiz.w; + initial.horiz.parent.ptr->width = initial.horiz.parent.w; + initial.vert.ptr->height = initial.vert.h; + initial.vert.parent.ptr->height = initial.vert.parent.h; + arrange_windows(initial.horiz.ptr->parent, -1, -1); + arrange_windows(initial.vert.ptr->parent, -1, -1); + pointer_state.mode = 0; +} + +void pointer_position_set(double new_x, double new_y, bool force_focus) { + double x, y; + wlc_pointer_get_position_v2(&x, &y); + pointer_state.delta.x = new_x - x; + pointer_state.delta.y = new_y - y; + + wlc_pointer_set_position_v2(new_x, new_y); + + // Update view under pointer + swayc_t *prev_view = pointer_state.view; + pointer_state.view = container_under_pointer(); + + // If pointer is in a mode, update it + if (pointer_state.mode) { + pointer_mode_update(); + // Otherwise change focus if config is set + } else if (force_focus || (prev_view != pointer_state.view && config->focus_follows_mouse)) { + if (pointer_state.view && pointer_state.view->type == C_VIEW) { + set_focused_container(pointer_state.view); + } + } +} + +void center_pointer_on(swayc_t *view) { + pointer_position_set(view->x + view->width/2, view->y + view->height/2, true); +} + +// Mode set left/right click + +static void pointer_mode_set_dragging(void) { + switch (config->dragging_key) { + case M_LEFT_CLICK: + set_initial_view(pointer_state.left.view); + break; + case M_RIGHT_CLICK: + set_initial_view(pointer_state.right.view); + break; + } + + if (initial.ptr->is_floating) { + pointer_state.mode = M_DRAGGING | M_FLOATING; + } else { + pointer_state.mode = M_DRAGGING | M_TILING; + // unset mode if we can't drag tile + if (initial.ptr->parent->type == C_WORKSPACE && + initial.ptr->parent->children->length == 1) { + pointer_state.mode = 0; + } + } +} + +static void pointer_mode_set_resizing(void) { + switch (config->resizing_key) { + case M_LEFT_CLICK: + set_initial_view(pointer_state.left.view); + break; + case M_RIGHT_CLICK: + set_initial_view(pointer_state.right.view); + break; + } + // Setup locking information + int midway_x = initial.ptr->x + initial.ptr->width/2; + int midway_y = initial.ptr->y + initial.ptr->height/2; + + double x, y; + wlc_pointer_get_position_v2(&x, &y); + lock.left = x > midway_x; + lock.top = y > midway_y; + + if (initial.ptr->is_floating) { + pointer_state.mode = M_RESIZING | M_FLOATING; + } else { + pointer_state.mode = M_RESIZING | M_TILING; + set_initial_sibling(); + } +} + +// Mode set/update/reset + +void pointer_mode_set(uint32_t button, bool condition) { + // switch on drag/resize mode + switch (pointer_state.mode & (M_DRAGGING | M_RESIZING)) { + case M_DRAGGING: + // end drag mode when 'dragging' click is unpressed + if (config->dragging_key == M_LEFT_CLICK && !pointer_state.left.held) { + pointer_state.mode = 0; + } else if (config->dragging_key == M_RIGHT_CLICK && !pointer_state.right.held) { + pointer_state.mode = 0; + } + break; + + case M_RESIZING: + // end resize mode when 'resizing' click is unpressed + if (config->resizing_key == M_LEFT_CLICK && !pointer_state.left.held) { + pointer_state.mode = 0; + } else if (config->resizing_key == M_RIGHT_CLICK && !pointer_state.right.held) { + pointer_state.mode = 0; + } + break; + + // No mode case + default: + // return if failed condition, or no view + if (!condition || !pointer_state.view) { + break; + } + + // Set mode depending on current button press + switch (button) { + // Start left-click mode + case M_LEFT_CLICK: + // if button release don't do anything + if (pointer_state.left.held) { + if (config->dragging_key == M_LEFT_CLICK) { + pointer_mode_set_dragging(); + } else if (config->resizing_key == M_LEFT_CLICK) { + pointer_mode_set_resizing(); + } + } + break; + + // Start right-click mode + case M_RIGHT_CLICK: + // if button release don't do anyhting + if (pointer_state.right.held) { + if (config->dragging_key == M_RIGHT_CLICK) { + pointer_mode_set_dragging(); + } else if (config->resizing_key == M_RIGHT_CLICK) { + pointer_mode_set_resizing(); + } + } + break; + } + } +} + +void pointer_mode_update(void) { + if (initial.ptr->type != C_VIEW) { + pointer_state.mode = 0; + return; + } + double x, y; + wlc_pointer_get_position_v2(&x, &y); + int dx = x; + int dy = y; + + switch (pointer_state.mode) { + case M_FLOATING | M_DRAGGING: + // Update position + switch (config->dragging_key) { + case M_LEFT_CLICK: + dx -= pointer_state.left.x; + dy -= pointer_state.left.y; + break; + case M_RIGHT_CLICK: + dx -= pointer_state.right.x; + dy -= pointer_state.right.y; + break; + } + + if (initial.x + dx != initial.ptr->x) { + initial.ptr->x = initial.x + dx; + } + if (initial.y + dy != initial.ptr->y) { + initial.ptr->y = initial.y + dy; + } + update_geometry(initial.ptr); + break; + + case M_FLOATING | M_RESIZING: + switch (config->resizing_key) { + case M_LEFT_CLICK: + dx -= pointer_state.left.x; + dy -= pointer_state.left.y; + initial.ptr = pointer_state.left.view; + break; + case M_RIGHT_CLICK: + dx -= pointer_state.right.x; + dy -= pointer_state.right.y; + initial.ptr = pointer_state.right.view; + break; + } + + if (lock.left) { + if (initial.w + dx > min_sane_w) { + initial.ptr->width = initial.w + dx; + } + } else { // lock.right + if (initial.w - dx > min_sane_w) { + initial.ptr->width = initial.w - dx; + initial.ptr->x = initial.x + dx; + } + } + if (lock.top) { + if (initial.h + dy > min_sane_h) { + initial.ptr->height = initial.h + dy; + } + } else { // lock.bottom + if (initial.h - dy > min_sane_h) { + initial.ptr->height = initial.h - dy; + initial.ptr->y = initial.y + dy; + } + } + update_geometry(initial.ptr); + break; + + case M_TILING | M_DRAGGING: + // swap current view under pointer with dragged view + if (pointer_state.view && pointer_state.view->type == C_VIEW + && pointer_state.view != initial.ptr + && !pointer_state.view->is_floating) { + // Swap them around + swap_container(pointer_state.view, initial.ptr); + swap_geometry(pointer_state.view, initial.ptr); + update_geometry(pointer_state.view); + update_geometry(initial.ptr); + // Set focus back to initial view + set_focused_container(initial.ptr); + // Arrange the windows + arrange_windows(&root_container, -1, -1); + } + break; + + case M_TILING | M_RESIZING: + switch (config->resizing_key) { + case M_LEFT_CLICK: + dx -= pointer_state.left.x; + dy -= pointer_state.left.y; + break; + case M_RIGHT_CLICK: + dx -= pointer_state.right.x; + dy -= pointer_state.right.y; + break; + } + + // resize if we can + if (initial.horiz.ptr) { + if (lock.left) { + // Check whether its fine to resize + if (initial.w + dx > min_sane_w && initial.horiz.w - dx > min_sane_w) { + initial.horiz.ptr->width = initial.horiz.w - dx; + initial.horiz.parent.ptr->width = initial.horiz.parent.w + dx; + } + } else { // lock.right + if (initial.w - dx > min_sane_w && initial.horiz.w + dx > min_sane_w) { + initial.horiz.ptr->width = initial.horiz.w + dx; + initial.horiz.parent.ptr->width = initial.horiz.parent.w - dx; + } + } + arrange_windows(initial.horiz.ptr->parent, -1, -1); + } + if (initial.vert.ptr) { + if (lock.top) { + if (initial.h + dy > min_sane_h && initial.vert.h - dy > min_sane_h) { + initial.vert.ptr->height = initial.vert.h - dy; + initial.vert.parent.ptr->height = initial.vert.parent.h + dy; + } + } else { // lock.bottom + if (initial.h - dy > min_sane_h && initial.vert.h + dy > min_sane_h) { + initial.vert.ptr->height = initial.vert.h + dy; + initial.vert.parent.ptr->height = initial.vert.parent.h - dy; + } + } + arrange_windows(initial.vert.ptr->parent, -1, -1); + } + default: + return; + } +} + +void pointer_mode_reset(void) { + switch (pointer_state.mode) { + case M_FLOATING | M_RESIZING: + case M_FLOATING | M_DRAGGING: + reset_initial_view(); + break; + + case M_TILING | M_RESIZING: + (void) reset_initial_sibling; + break; + + case M_TILING | M_DRAGGING: + default: + break; + } +} diff --git a/sway/old/ipc-json.c b/sway/old/ipc-json.c new file mode 100644 index 00000000..1579a2d9 --- /dev/null +++ b/sway/old/ipc-json.c @@ -0,0 +1,521 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include "sway/output.h" +#include "sway/container.h" +#include "sway/input.h" +#include "sway/ipc-json.h" +#include "util.h" + +static json_object *ipc_json_create_rect(swayc_t *c) { + json_object *rect = json_object_new_object(); + + json_object_object_add(rect, "x", json_object_new_int((int32_t)c->x)); + json_object_object_add(rect, "y", json_object_new_int((int32_t)c->y)); + + struct wlr_box box; + if (c->type == C_OUTPUT) { + wlr_output_effective_resolution(c->_handle.output->wlr_output, + &box.width, &box.height); + } else { + box.width = c->width; + box.width = c->height; + } + + json_object_object_add(rect, "width", + json_object_new_int((int32_t)box.width)); + json_object_object_add(rect, "height", + json_object_new_int((int32_t)box.height)); + + return rect; +} + +static json_object *ipc_json_create_rect_from_geometry(struct wlc_geometry g) { + json_object *rect = json_object_new_object(); + + json_object_object_add(rect, "x", json_object_new_int(g.origin.x)); + json_object_object_add(rect, "y", json_object_new_int(g.origin.y)); + json_object_object_add(rect, "width", json_object_new_int(g.size.w)); + json_object_object_add(rect, "height", json_object_new_int(g.size.h)); + + return rect; +} + +static const char *ipc_json_border_description(swayc_t *c) { + const char *border; + + switch (c->border_type) { + case B_PIXEL: + border = "1pixel"; + break; + + case B_NORMAL: + border = "normal"; + break; + + case B_NONE: // fallthrough + default: + border = "none"; + break; + } + + return border; +} + +static const char *ipc_json_layout_description(enum swayc_layouts l) { + const char *layout; + + switch (l) { + case L_VERT: + layout = "splitv"; + break; + + case L_HORIZ: + layout = "splith"; + break; + + case L_TABBED: + layout = "tabbed"; + break; + + case L_STACKED: + layout = "stacked"; + break; + + case L_FLOATING: + layout = "floating"; + break; + + case L_NONE: // fallthrough + case L_LAYOUTS: // fallthrough; this should never happen, I'm just trying to silence compiler warnings + default: + layout = "null"; + break; + } + + return layout; +} + +static float ipc_json_child_percentage(swayc_t *c) { + float percent = 0; + swayc_t *parent = c->parent; + + if (parent) { + switch (parent->layout) { + case L_VERT: + percent = c->height / parent->height; + break; + + case L_HORIZ: + percent = c->width / parent->width; + break; + + case L_STACKED: // fallthrough + case L_TABBED: // fallthrough + percent = 1.0; + break; + + default: + break; + } + } + + return percent; +} + +static void ipc_json_describe_output(swayc_t *output, json_object *object) { + uint32_t scale = wlc_output_get_scale(output->handle); + json_object_object_add(object, "active", json_object_new_boolean(true)); + json_object_object_add(object, "primary", json_object_new_boolean(false)); + json_object_object_add(object, "layout", json_object_new_string("output")); + json_object_object_add(object, "type", json_object_new_string("output")); + json_object_object_add(object, "current_workspace", + (output->focused) ? json_object_new_string(output->focused->name) : NULL); + json_object_object_add(object, "scale", json_object_new_int(scale)); +} + +static void ipc_json_describe_workspace(swayc_t *workspace, json_object *object) { + int num = (isdigit(workspace->name[0])) ? atoi(workspace->name) : -1; + const char *layout = ipc_json_layout_description(workspace->workspace_layout); + + json_object_object_add(object, "num", json_object_new_int(num)); + json_object_object_add(object, "output", (workspace->parent) ? json_object_new_string(workspace->parent->name) : NULL); + json_object_object_add(object, "type", json_object_new_string("workspace")); + json_object_object_add(object, "layout", (strcmp(layout, "null") == 0) ? NULL : json_object_new_string(layout)); +} + +// window is in the scratchpad ? changed : none +static const char *ipc_json_get_scratchpad_state(swayc_t *c) { + int i; + for (i = 0; i < scratchpad->length; i++) { + if (scratchpad->items[i] == c) { + return "changed"; + } + } + return "none"; // we ignore the fresh value +} + +static void ipc_json_describe_view(swayc_t *c, json_object *object) { + json_object *props = json_object_new_object(); + json_object_object_add(object, "type", json_object_new_string((c->is_floating) ? "floating_con" : "con")); + + wlc_handle parent = wlc_view_get_parent(c->handle); + json_object_object_add(object, "scratchpad_state", + json_object_new_string(ipc_json_get_scratchpad_state(c))); + + json_object_object_add(object, "name", (c->name) ? json_object_new_string(c->name) : NULL); + + json_object_object_add(props, "class", c->class ? json_object_new_string(c->class) : + c->app_id ? json_object_new_string(c->app_id) : NULL); + json_object_object_add(props, "instance", c->instance ? json_object_new_string(c->instance) : + c->app_id ? json_object_new_string(c->app_id) : NULL); + json_object_object_add(props, "title", (c->name) ? json_object_new_string(c->name) : NULL); + json_object_object_add(props, "transient_for", parent ? json_object_new_int(parent) : NULL); + json_object_object_add(object, "window_properties", props); + + json_object_object_add(object, "fullscreen_mode", + json_object_new_int(swayc_is_fullscreen(c) ? 1 : 0)); + json_object_object_add(object, "sticky", json_object_new_boolean(c->sticky)); + json_object_object_add(object, "floating", json_object_new_string( + c->is_floating ? "auto_on" : "auto_off")); // we can't state the cause + + json_object_object_add(object, "app_id", c->app_id ? json_object_new_string(c->app_id) : NULL); + + if (c->parent) { + const char *layout = (c->parent->type == C_CONTAINER) ? + ipc_json_layout_description(c->parent->layout) : "none"; + const char *last_layout = (c->parent->type == C_CONTAINER) ? + ipc_json_layout_description(c->parent->prev_layout) : "none"; + json_object_object_add(object, "layout", + (strcmp(layout, "null") == 0) ? NULL : json_object_new_string(layout)); + json_object_object_add(object, "last_split_layout", + (strcmp(last_layout, "null") == 0) ? NULL : json_object_new_string(last_layout)); + json_object_object_add(object, "workspace_layout", + json_object_new_string(ipc_json_layout_description(swayc_parent_by_type(c, C_WORKSPACE)->workspace_layout))); + } +} + +static void ipc_json_describe_root(swayc_t *c, json_object *object) { + json_object_object_add(object, "type", json_object_new_string("root")); + json_object_object_add(object, "layout", json_object_new_string("splith")); +} + +json_object *ipc_json_describe_container(swayc_t *c) { + float percent = ipc_json_child_percentage(c); + + if (!(sway_assert(c, "Container must not be null."))) { + return NULL; + } + + json_object *object = json_object_new_object(); + + json_object_object_add(object, "id", json_object_new_int((int)c->id)); + json_object_object_add(object, "name", (c->name) ? json_object_new_string(c->name) : NULL); + json_object_object_add(object, "rect", ipc_json_create_rect(c)); + json_object_object_add(object, "visible", json_object_new_boolean(c->visible)); + json_object_object_add(object, "focused", json_object_new_boolean(c == current_focus)); + + json_object_object_add(object, "border", json_object_new_string(ipc_json_border_description(c))); + json_object_object_add(object, "window_rect", ipc_json_create_rect_from_geometry(c->actual_geometry)); + json_object_object_add(object, "deco_rect", ipc_json_create_rect_from_geometry(c->title_bar_geometry)); + json_object_object_add(object, "geometry", ipc_json_create_rect_from_geometry(c->cached_geometry)); + json_object_object_add(object, "percent", (percent > 0) ? json_object_new_double(percent) : NULL); + json_object_object_add(object, "window", json_object_new_int(c->handle)); // for the sake of i3 compat + // TODO: make urgency actually work once Sway supports it + json_object_object_add(object, "urgent", json_object_new_boolean(false)); + json_object_object_add(object, "current_border_width", json_object_new_int(c->border_thickness)); + + switch (c->type) { + case C_ROOT: + ipc_json_describe_root(c, object); + break; + + case C_OUTPUT: + ipc_json_describe_output(c, object); + break; + + case C_CONTAINER: // fallthrough + case C_VIEW: + ipc_json_describe_view(c, object); + break; + + case C_WORKSPACE: + ipc_json_describe_workspace(c, object); + break; + + case C_TYPES: // fallthrough; this should never happen, I'm just trying to silence compiler warnings + default: + break; + } + + return object; +} + +json_object *ipc_json_describe_input(struct libinput_device *device) { + char* identifier = libinput_dev_unique_id(device); + int vendor = libinput_device_get_id_vendor(device); + int product = libinput_device_get_id_product(device); + const char *name = libinput_device_get_name(device); + double width = -1, height = -1; + int has_size = libinput_device_get_size(device, &width, &height); + + json_object *device_object = json_object_new_object(); + json_object_object_add(device_object,"identifier", + identifier ? json_object_new_string(identifier) : NULL); + json_object_object_add(device_object, + "vendor", json_object_new_int(vendor)); + json_object_object_add(device_object, + "product", json_object_new_int(product)); + json_object_object_add(device_object, + "name", json_object_new_string(name)); + if (has_size == 0) { + json_object *size_object = json_object_new_object(); + json_object_object_add(size_object, + "width", json_object_new_double(width)); + json_object_object_add(size_object, + "height", json_object_new_double(height)); + } else { + json_object_object_add(device_object, "size", NULL); + } + + struct { + enum libinput_device_capability cap; + const char *name; + // If anyone feels like implementing device-specific IPC output, + // be my guest + json_object *(*describe)(struct libinput_device *); + } caps[] = { + { LIBINPUT_DEVICE_CAP_KEYBOARD, "keyboard", NULL }, + { LIBINPUT_DEVICE_CAP_POINTER, "pointer", NULL }, + { LIBINPUT_DEVICE_CAP_TOUCH, "touch", NULL }, + { LIBINPUT_DEVICE_CAP_TABLET_TOOL, "tablet_tool", NULL }, + { LIBINPUT_DEVICE_CAP_TABLET_PAD, "tablet_pad", NULL }, + { LIBINPUT_DEVICE_CAP_GESTURE, "gesture", NULL }, +#ifdef LIBINPUT_DEVICE_CAP_SWITCH // libinput 1.7.0+ + { LIBINPUT_DEVICE_CAP_SWITCH, "switch", NULL }, +#endif + }; + + json_object *_caps = json_object_new_array(); + for (size_t i = 0; i < sizeof(caps) / sizeof(caps[0]); ++i) { + if (libinput_device_has_capability(device, caps[i].cap)) { + json_object_array_add(_caps, json_object_new_string(caps[i].name)); + if (caps[i].describe) { + json_object *desc = caps[i].describe(device); + json_object_object_add(device_object, caps[i].name, desc); + } + } + } + json_object_object_add(device_object, "capabilities", _caps); + + free(identifier); + return device_object; +} + +json_object *ipc_json_get_version() { + int major = 0, minor = 0, patch = 0; + json_object *version = json_object_new_object(); + + sscanf(SWAY_VERSION, "%u.%u.%u", &major, &minor, &patch); + + json_object_object_add(version, "human_readable", json_object_new_string(SWAY_VERSION)); + json_object_object_add(version, "variant", json_object_new_string("sway")); + json_object_object_add(version, "major", json_object_new_int(major)); + json_object_object_add(version, "minor", json_object_new_int(minor)); + json_object_object_add(version, "patch", json_object_new_int(patch)); + + return version; +} + +json_object *ipc_json_describe_bar_config(struct bar_config *bar) { + if (!sway_assert(bar, "Bar must not be NULL")) { + return NULL; + } + + json_object *json = json_object_new_object(); + json_object_object_add(json, "id", json_object_new_string(bar->id)); +#ifdef ENABLE_TRAY + if (bar->tray_output) { + json_object_object_add(json, "tray_output", json_object_new_string(bar->tray_output)); + } else { + json_object_object_add(json, "tray_output", NULL); + } + if (bar->icon_theme) { + json_object_object_add(json, "icon_theme", json_object_new_string(bar->icon_theme)); + } else { + json_object_object_add(json, "icon_theme", NULL); + } + json_object_object_add(json, "tray_padding", json_object_new_int(bar->tray_padding)); + json_object_object_add(json, "activate_button", json_object_new_int(bar->activate_button)); + json_object_object_add(json, "context_button", json_object_new_int(bar->context_button)); + json_object_object_add(json, "secondary_button", json_object_new_int(bar->secondary_button)); +#endif + json_object_object_add(json, "mode", json_object_new_string(bar->mode)); + json_object_object_add(json, "hidden_state", json_object_new_string(bar->hidden_state)); + json_object_object_add(json, "modifier", json_object_new_string(get_modifier_name_by_mask(bar->modifier))); + switch (bar->position) { + case DESKTOP_SHELL_PANEL_POSITION_TOP: + json_object_object_add(json, "position", json_object_new_string("top")); + break; + case DESKTOP_SHELL_PANEL_POSITION_BOTTOM: + json_object_object_add(json, "position", json_object_new_string("bottom")); + break; + case DESKTOP_SHELL_PANEL_POSITION_LEFT: + json_object_object_add(json, "position", json_object_new_string("left")); + break; + case DESKTOP_SHELL_PANEL_POSITION_RIGHT: + json_object_object_add(json, "position", json_object_new_string("right")); + break; + } + json_object_object_add(json, "status_command", json_object_new_string(bar->status_command)); + json_object_object_add(json, "font", json_object_new_string((bar->font) ? bar->font : config->font)); + if (bar->separator_symbol) { + json_object_object_add(json, "separator_symbol", json_object_new_string(bar->separator_symbol)); + } + json_object_object_add(json, "bar_height", json_object_new_int(bar->height)); + json_object_object_add(json, "wrap_scroll", json_object_new_boolean(bar->wrap_scroll)); + json_object_object_add(json, "workspace_buttons", json_object_new_boolean(bar->workspace_buttons)); + json_object_object_add(json, "strip_workspace_numbers", json_object_new_boolean(bar->strip_workspace_numbers)); + json_object_object_add(json, "binding_mode_indicator", json_object_new_boolean(bar->binding_mode_indicator)); + json_object_object_add(json, "verbose", json_object_new_boolean(bar->verbose)); + json_object_object_add(json, "pango_markup", json_object_new_boolean(bar->pango_markup)); + + json_object *colors = json_object_new_object(); + json_object_object_add(colors, "background", json_object_new_string(bar->colors.background)); + json_object_object_add(colors, "statusline", json_object_new_string(bar->colors.statusline)); + json_object_object_add(colors, "separator", json_object_new_string(bar->colors.separator)); + + if (bar->colors.focused_background) { + json_object_object_add(colors, "focused_background", json_object_new_string(bar->colors.focused_background)); + } else { + json_object_object_add(colors, "focused_background", json_object_new_string(bar->colors.background)); + } + + if (bar->colors.focused_statusline) { + json_object_object_add(colors, "focused_statusline", json_object_new_string(bar->colors.focused_statusline)); + } else { + json_object_object_add(colors, "focused_statusline", json_object_new_string(bar->colors.statusline)); + } + + if (bar->colors.focused_separator) { + json_object_object_add(colors, "focused_separator", json_object_new_string(bar->colors.focused_separator)); + } else { + json_object_object_add(colors, "focused_separator", json_object_new_string(bar->colors.separator)); + } + + json_object_object_add(colors, "focused_workspace_border", json_object_new_string(bar->colors.focused_workspace_border)); + json_object_object_add(colors, "focused_workspace_bg", json_object_new_string(bar->colors.focused_workspace_bg)); + json_object_object_add(colors, "focused_workspace_text", json_object_new_string(bar->colors.focused_workspace_text)); + + json_object_object_add(colors, "inactive_workspace_border", json_object_new_string(bar->colors.inactive_workspace_border)); + json_object_object_add(colors, "inactive_workspace_bg", json_object_new_string(bar->colors.inactive_workspace_bg)); + json_object_object_add(colors, "inactive_workspace_text", json_object_new_string(bar->colors.inactive_workspace_text)); + + json_object_object_add(colors, "active_workspace_border", json_object_new_string(bar->colors.active_workspace_border)); + json_object_object_add(colors, "active_workspace_bg", json_object_new_string(bar->colors.active_workspace_bg)); + json_object_object_add(colors, "active_workspace_text", json_object_new_string(bar->colors.active_workspace_text)); + + json_object_object_add(colors, "urgent_workspace_border", json_object_new_string(bar->colors.urgent_workspace_border)); + json_object_object_add(colors, "urgent_workspace_bg", json_object_new_string(bar->colors.urgent_workspace_bg)); + json_object_object_add(colors, "urgent_workspace_text", json_object_new_string(bar->colors.urgent_workspace_text)); + + if (bar->colors.binding_mode_border) { + json_object_object_add(colors, "binding_mode_border", json_object_new_string(bar->colors.binding_mode_border)); + } else { + json_object_object_add(colors, "binding_mode_border", json_object_new_string(bar->colors.urgent_workspace_border)); + } + + if (bar->colors.binding_mode_bg) { + json_object_object_add(colors, "binding_mode_bg", json_object_new_string(bar->colors.binding_mode_bg)); + } else { + json_object_object_add(colors, "binding_mode_bg", json_object_new_string(bar->colors.urgent_workspace_bg)); + } + + if (bar->colors.binding_mode_text) { + json_object_object_add(colors, "binding_mode_text", json_object_new_string(bar->colors.binding_mode_text)); + } else { + json_object_object_add(colors, "binding_mode_text", json_object_new_string(bar->colors.urgent_workspace_text)); + } + + json_object_object_add(json, "colors", colors); + + // Add outputs if defined + if (bar->outputs && bar->outputs->length > 0) { + json_object *outputs = json_object_new_array(); + int i; + for (i = 0; i < bar->outputs->length; ++i) { + const char *name = bar->outputs->items[i]; + json_object_array_add(outputs, json_object_new_string(name)); + } + json_object_object_add(json, "outputs", outputs); + } + + return json; +} + +json_object *ipc_json_describe_container_recursive(swayc_t *c) { + json_object *object = ipc_json_describe_container(c); + int i; + + json_object *floating = json_object_new_array(); + if (c->type != C_VIEW && c->floating) { + for (i = 0; i < c->floating->length; ++i) { + swayc_t *item = c->floating->items[i]; + json_object_array_add(floating, ipc_json_describe_container_recursive(item)); + } + } + json_object_object_add(object, "floating_nodes", floating); + + json_object *children = json_object_new_array(); + if (c->type != C_VIEW && c->children) { + for (i = 0; i < c->children->length; ++i) { + json_object_array_add(children, ipc_json_describe_container_recursive(c->children->items[i])); + } + } + json_object_object_add(object, "nodes", children); + + json_object *focus = json_object_new_array(); + if (c->type != C_VIEW) { + if (c->focused) { + json_object_array_add(focus, json_object_new_double(c->focused->id)); + } + if (c->floating) { + for (i = 0; i < c->floating->length; ++i) { + swayc_t *item = c->floating->items[i]; + if (item == c->focused) { + continue; + } + + json_object_array_add(focus, json_object_new_double(item->id)); + } + } + if (c->children) { + for (i = 0; i < c->children->length; ++i) { + swayc_t *item = c->children->items[i]; + if (item == c->focused) { + continue; + } + + json_object_array_add(focus, json_object_new_double(item->id)); + } + } + } + json_object_object_add(object, "focus", focus); + + if (c->type == C_ROOT) { + json_object *scratchpad_json = json_object_new_array(); + if (scratchpad->length > 0) { + for (i = 0; i < scratchpad->length; ++i) { + json_object_array_add(scratchpad_json, ipc_json_describe_container_recursive(scratchpad->items[i])); + } + } + json_object_object_add(object, "scratchpad", scratchpad_json); + } + + return object; +} diff --git a/sway/old/ipc-server.c b/sway/old/ipc-server.c new file mode 100644 index 00000000..fd64e81b --- /dev/null +++ b/sway/old/ipc-server.c @@ -0,0 +1,840 @@ +// See https://i3wm.org/docs/ipc.html for protocol information +#ifndef __FreeBSD__ +// Any value will hide SOCK_CLOEXEC on FreeBSD (__BSD_VISIBLE=0) +#define _XOPEN_SOURCE 700 +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __linux__ +struct ucred { + pid_t pid; + uid_t uid; + gid_t gid; +}; +#endif +#include "sway/ipc-json.h" +#include "sway/ipc-server.h" +#include "sway/security.h" +#include "sway/config.h" +#include "sway/commands.h" +#include "sway/input.h" +#include "sway/server.h" +#include "stringop.h" +#include "log.h" +#include "list.h" +#include "util.h" + +static int ipc_socket = -1; +static struct wl_event_source *ipc_event_source = NULL; +static struct sockaddr_un *ipc_sockaddr = NULL; +static list_t *ipc_client_list = NULL; + +static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'}; + +struct ipc_client { + struct wl_event_source *event_source; + struct wl_event_source *writable_event_source; + int fd; + uint32_t payload_length; + uint32_t security_policy; + enum ipc_command_type current_command; + enum ipc_command_type subscribed_events; + size_t write_buffer_len; + size_t write_buffer_size; + char *write_buffer; +}; + +struct sockaddr_un *ipc_user_sockaddr(void); +int ipc_handle_connection(int fd, uint32_t mask, void *data); +int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data); +int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data); +void ipc_client_disconnect(struct ipc_client *client); +void ipc_client_handle_command(struct ipc_client *client); +bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length); +void ipc_get_workspaces_callback(swayc_t *workspace, void *data); +void ipc_get_outputs_callback(swayc_t *container, void *data); +static void ipc_get_marks_callback(swayc_t *container, void *data); + +void ipc_init(void) { + ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); + if (ipc_socket == -1) { + sway_abort("Unable to create IPC socket"); + } + + ipc_sockaddr = ipc_user_sockaddr(); + + // We want to use socket name set by user, not existing socket from another sway instance. + if (getenv("SWAYSOCK") != NULL && access(getenv("SWAYSOCK"), F_OK) == -1) { + strncpy(ipc_sockaddr->sun_path, getenv("SWAYSOCK"), sizeof(ipc_sockaddr->sun_path)); + ipc_sockaddr->sun_path[sizeof(ipc_sockaddr->sun_path) - 1] = 0; + } + + unlink(ipc_sockaddr->sun_path); + if (bind(ipc_socket, (struct sockaddr *)ipc_sockaddr, sizeof(*ipc_sockaddr)) == -1) { + sway_abort("Unable to bind IPC socket"); + } + + if (listen(ipc_socket, 3) == -1) { + sway_abort("Unable to listen on IPC socket"); + } + + // Set i3 IPC socket path so that i3-msg works out of the box + setenv("I3SOCK", ipc_sockaddr->sun_path, 1); + setenv("SWAYSOCK", ipc_sockaddr->sun_path, 1); + + ipc_client_list = create_list(); + + ipc_event_source = wl_event_loop_add_fd(server.wl_event_loop, ipc_socket, + WL_EVENT_READABLE, ipc_handle_connection, NULL); +} + +void ipc_terminate(void) { + if (ipc_event_source) { + wl_event_source_remove(ipc_event_source); + } + close(ipc_socket); + unlink(ipc_sockaddr->sun_path); + + list_free(ipc_client_list); + + if (ipc_sockaddr) { + free(ipc_sockaddr); + } +} + +struct sockaddr_un *ipc_user_sockaddr(void) { + struct sockaddr_un *ipc_sockaddr = malloc(sizeof(struct sockaddr_un)); + if (ipc_sockaddr == NULL) { + sway_abort("Can't allocate ipc_sockaddr"); + } + + ipc_sockaddr->sun_family = AF_UNIX; + int path_size = sizeof(ipc_sockaddr->sun_path); + + // Env var typically set by logind, e.g. "/run/user/" + const char *dir = getenv("XDG_RUNTIME_DIR"); + if (!dir) { + dir = "/tmp"; + } + if (path_size <= snprintf(ipc_sockaddr->sun_path, path_size, + "%s/sway-ipc.%i.%i.sock", dir, getuid(), getpid())) { + sway_abort("Socket path won't fit into ipc_sockaddr->sun_path"); + } + + return ipc_sockaddr; +} + +static pid_t get_client_pid(int client_fd) { +// FreeBSD supports getting uid/gid, but not pid +#ifdef __linux__ + struct ucred ucred; + socklen_t len = sizeof(struct ucred); + + if (getsockopt(client_fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1) { + return -1; + } + + return ucred.pid; +#else + return -1; +#endif +} + +int ipc_handle_connection(int fd, uint32_t mask, void *data) { + (void) fd; (void) data; + sway_log(L_DEBUG, "Event on IPC listening socket"); + assert(mask == WL_EVENT_READABLE); + + int client_fd = accept(ipc_socket, NULL, NULL); + if (client_fd == -1) { + sway_log_errno(L_ERROR, "Unable to accept IPC client connection"); + return 0; + } + + int flags; + if ((flags = fcntl(client_fd, F_GETFD)) == -1 + || fcntl(client_fd, F_SETFD, flags|FD_CLOEXEC) == -1) { + sway_log_errno(L_ERROR, "Unable to set CLOEXEC on IPC client socket"); + close(client_fd); + return 0; + } + if ((flags = fcntl(client_fd, F_GETFL)) == -1 + || fcntl(client_fd, F_SETFL, flags|O_NONBLOCK) == -1) { + sway_log_errno(L_ERROR, "Unable to set NONBLOCK on IPC client socket"); + close(client_fd); + return 0; + } + + struct ipc_client* client = malloc(sizeof(struct ipc_client)); + if (!client) { + sway_log(L_ERROR, "Unable to allocate ipc client"); + close(client_fd); + return 0; + } + client->payload_length = 0; + client->fd = client_fd; + client->subscribed_events = 0; + client->event_source = wl_event_loop_add_fd(server.wl_event_loop, client_fd, + WL_EVENT_READABLE, ipc_client_handle_readable, client); + client->writable_event_source = NULL; + + client->write_buffer_size = 128; + client->write_buffer_len = 0; + client->write_buffer = malloc(client->write_buffer_size); + if (!client->write_buffer) { + sway_log(L_ERROR, "Unable to allocate ipc client write buffer"); + close(client_fd); + return 0; + } + + pid_t pid = get_client_pid(client->fd); + client->security_policy = get_ipc_policy_mask(pid); + + sway_log(L_DEBUG, "New client: fd %d, pid %d", client_fd, pid); + + list_add(ipc_client_list, client); + + return 0; +} + +static const int ipc_header_size = sizeof(ipc_magic)+8; + +int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) { + struct ipc_client *client = data; + + if (mask & WL_EVENT_ERROR) { + sway_log(L_ERROR, "IPC Client socket error, removing client"); + ipc_client_disconnect(client); + return 0; + } + + if (mask & WL_EVENT_HANGUP) { + sway_log(L_DEBUG, "Client %d hung up", client->fd); + ipc_client_disconnect(client); + return 0; + } + + sway_log(L_DEBUG, "Client %d readable", client->fd); + + int read_available; + if (ioctl(client_fd, FIONREAD, &read_available) == -1) { + sway_log_errno(L_INFO, "Unable to read IPC socket buffer size"); + ipc_client_disconnect(client); + return 0; + } + + // Wait for the rest of the command payload in case the header has already been read + if (client->payload_length > 0) { + if ((uint32_t)read_available >= client->payload_length) { + ipc_client_handle_command(client); + } + return 0; + } + + if (read_available < ipc_header_size) { + return 0; + } + + uint8_t buf[ipc_header_size]; + uint32_t *buf32 = (uint32_t*)(buf + sizeof(ipc_magic)); + // Should be fully available, because read_available >= ipc_header_size + ssize_t received = recv(client_fd, buf, ipc_header_size, 0); + if (received == -1) { + sway_log_errno(L_INFO, "Unable to receive header from IPC client"); + ipc_client_disconnect(client); + return 0; + } + + if (memcmp(buf, ipc_magic, sizeof(ipc_magic)) != 0) { + sway_log(L_DEBUG, "IPC header check failed"); + ipc_client_disconnect(client); + return 0; + } + + client->payload_length = buf32[0]; + client->current_command = (enum ipc_command_type)buf32[1]; + + if (read_available - received >= (long)client->payload_length) { + ipc_client_handle_command(client); + } + + return 0; +} + +int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) { + struct ipc_client *client = data; + + if (mask & WL_EVENT_ERROR) { + sway_log(L_ERROR, "IPC Client socket error, removing client"); + ipc_client_disconnect(client); + return 0; + } + + if (mask & WL_EVENT_HANGUP) { + sway_log(L_DEBUG, "Client %d hung up", client->fd); + ipc_client_disconnect(client); + return 0; + } + + if (client->write_buffer_len <= 0) { + return 0; + } + + sway_log(L_DEBUG, "Client %d writable", client->fd); + + ssize_t written = write(client->fd, client->write_buffer, client->write_buffer_len); + + if (written == -1 && errno == EAGAIN) { + return 0; + } else if (written == -1) { + sway_log_errno(L_INFO, "Unable to send data from queue to IPC client"); + ipc_client_disconnect(client); + return 0; + } + + memmove(client->write_buffer, client->write_buffer + written, client->write_buffer_len - written); + client->write_buffer_len -= written; + + if (client->write_buffer_len == 0 && client->writable_event_source) { + wl_event_source_remove(client->writable_event_source); + client->writable_event_source = NULL; + } + + return 0; +} + +void ipc_client_disconnect(struct ipc_client *client) { + if (!sway_assert(client != NULL, "client != NULL")) { + return; + } + + if (client->fd != -1) { + shutdown(client->fd, SHUT_RDWR); + } + + sway_log(L_INFO, "IPC Client %d disconnected", client->fd); + wl_event_source_remove(client->event_source); + if (client->writable_event_source) { + wl_event_source_remove(client->writable_event_source); + } + int i = 0; + while (i < ipc_client_list->length && ipc_client_list->items[i] != client) i++; + list_del(ipc_client_list, i); + free(client->write_buffer); + close(client->fd); + free(client); +} + +bool output_by_name_test(swayc_t *view, void *data) { + char *name = (char *)data; + if (view->type != C_OUTPUT) { + return false; + } + return !strcmp(name, view->name); +} + +// greedy wildcard (only "*") matching +bool mime_type_matches(const char *mime_type, const char *pattern) { + const char *wildcard = NULL; + while (*mime_type && *pattern) { + if (*pattern == '*' && !wildcard) { + wildcard = pattern; + ++pattern; + } + + if (*mime_type != *pattern) { + if (!wildcard) + return false; + + pattern = wildcard; + ++mime_type; + continue; + } + + ++mime_type; + ++pattern; + } + + while (*pattern == '*') { + ++pattern; + } + + return (*mime_type == *pattern); +} + +void ipc_client_handle_command(struct ipc_client *client) { + if (!sway_assert(client != NULL, "client != NULL")) { + return; + } + + char *buf = malloc(client->payload_length + 1); + if (!buf) { + sway_log_errno(L_INFO, "Unable to allocate IPC payload"); + ipc_client_disconnect(client); + return; + } + if (client->payload_length > 0) { + // Payload should be fully available + ssize_t received = recv(client->fd, buf, client->payload_length, 0); + if (received == -1) + { + sway_log_errno(L_INFO, "Unable to receive payload from IPC client"); + ipc_client_disconnect(client); + free(buf); + return; + } + } + buf[client->payload_length] = '\0'; + + const char *error_denied = "{ \"success\": false, \"error\": \"Permission denied\" }"; + + switch (client->current_command) { + case IPC_COMMAND: + { + if (!(client->security_policy & IPC_FEATURE_COMMAND)) { + goto exit_denied; + } + struct cmd_results *results = handle_command(buf, CONTEXT_IPC); + const char *json = cmd_results_to_json(results); + char reply[256]; + int length = snprintf(reply, sizeof(reply), "%s", json); + ipc_send_reply(client, reply, (uint32_t) length); + free_cmd_results(results); + goto exit_cleanup; + } + + case IPC_SUBSCRIBE: + { + // TODO: Check if they're permitted to use these events + struct json_object *request = json_tokener_parse(buf); + if (request == NULL) { + ipc_send_reply(client, "{\"success\": false}", 18); + sway_log_errno(L_INFO, "Failed to read request"); + goto exit_cleanup; + } + + // parse requested event types + for (int i = 0; i < json_object_array_length(request); i++) { + const char *event_type = json_object_get_string(json_object_array_get_idx(request, i)); + if (strcmp(event_type, "workspace") == 0) { + client->subscribed_events |= event_mask(IPC_EVENT_WORKSPACE); + } else if (strcmp(event_type, "barconfig_update") == 0) { + client->subscribed_events |= event_mask(IPC_EVENT_BARCONFIG_UPDATE); + } else if (strcmp(event_type, "mode") == 0) { + client->subscribed_events |= event_mask(IPC_EVENT_MODE); + } else if (strcmp(event_type, "window") == 0) { + client->subscribed_events |= event_mask(IPC_EVENT_WINDOW); + } else if (strcmp(event_type, "modifier") == 0) { + client->subscribed_events |= event_mask(IPC_EVENT_MODIFIER); + } else if (strcmp(event_type, "binding") == 0) { + client->subscribed_events |= event_mask(IPC_EVENT_BINDING); + } else { + ipc_send_reply(client, "{\"success\": false}", 18); + json_object_put(request); + sway_log_errno(L_INFO, "Failed to parse request"); + goto exit_cleanup; + } + } + + json_object_put(request); + + ipc_send_reply(client, "{\"success\": true}", 17); + goto exit_cleanup; + } + + case IPC_GET_WORKSPACES: + { + if (!(client->security_policy & IPC_FEATURE_GET_WORKSPACES)) { + goto exit_denied; + } + json_object *workspaces = json_object_new_array(); + container_map(&root_container, ipc_get_workspaces_callback, workspaces); + const char *json_string = json_object_to_json_string(workspaces); + ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); + json_object_put(workspaces); // free + goto exit_cleanup; + } + + case IPC_GET_INPUTS: + { + if (!(client->security_policy & IPC_FEATURE_GET_INPUTS)) { + goto exit_denied; + } + json_object *inputs = json_object_new_array(); + /* TODO WLR + if (input_devices) { + for(int i = 0; ilength; i++) { + struct libinput_device *device = input_devices->items[i]; + json_object_array_add(inputs, ipc_json_describe_input(device)); + } + } + */ + const char *json_string = json_object_to_json_string(inputs); + ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); + json_object_put(inputs); + goto exit_cleanup; + } + + case IPC_GET_OUTPUTS: + { + if (!(client->security_policy & IPC_FEATURE_GET_OUTPUTS)) { + goto exit_denied; + } + json_object *outputs = json_object_new_array(); + container_map(&root_container, ipc_get_outputs_callback, outputs); + const char *json_string = json_object_to_json_string(outputs); + ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); + json_object_put(outputs); // free + goto exit_cleanup; + } + + case IPC_GET_TREE: + { + if (!(client->security_policy & IPC_FEATURE_GET_TREE)) { + goto exit_denied; + } + json_object *tree = ipc_json_describe_container_recursive(&root_container); + const char *json_string = json_object_to_json_string(tree); + ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); + json_object_put(tree); + goto exit_cleanup; + } + + case IPC_GET_MARKS: + { + if (!(client->security_policy & IPC_FEATURE_GET_MARKS)) { + goto exit_denied; + } + json_object *marks = json_object_new_array(); + container_map(&root_container, ipc_get_marks_callback, marks); + const char *json_string = json_object_to_json_string(marks); + ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); + json_object_put(marks); + goto exit_cleanup; + } + + case IPC_GET_VERSION: + { + json_object *version = ipc_json_get_version(); + const char *json_string = json_object_to_json_string(version); + ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); + json_object_put(version); // free + goto exit_cleanup; + } + + case IPC_GET_BAR_CONFIG: + { + if (!(client->security_policy & IPC_FEATURE_GET_BAR_CONFIG)) { + goto exit_denied; + } + if (!buf[0]) { + // Send list of configured bar IDs + json_object *bars = json_object_new_array(); + int i; + for (i = 0; i < config->bars->length; ++i) { + struct bar_config *bar = config->bars->items[i]; + json_object_array_add(bars, json_object_new_string(bar->id)); + } + const char *json_string = json_object_to_json_string(bars); + ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); + json_object_put(bars); // free + } else { + // Send particular bar's details + struct bar_config *bar = NULL; + int i; + for (i = 0; i < config->bars->length; ++i) { + bar = config->bars->items[i]; + if (strcmp(buf, bar->id) == 0) { + break; + } + bar = NULL; + } + if (!bar) { + const char *error = "{ \"success\": false, \"error\": \"No bar with that ID\" }"; + ipc_send_reply(client, error, (uint32_t)strlen(error)); + goto exit_cleanup; + } + json_object *json = ipc_json_describe_bar_config(bar); + const char *json_string = json_object_to_json_string(json); + ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); + json_object_put(json); // free + } + goto exit_cleanup; + } + + case IPC_GET_CLIPBOARD: + // TODO WLR + break; + + default: + sway_log(L_INFO, "Unknown IPC command type %i", client->current_command); + goto exit_cleanup; + } + +exit_denied: + ipc_send_reply(client, error_denied, (uint32_t)strlen(error_denied)); + sway_log(L_DEBUG, "Denied IPC client access to %i", client->current_command); + +exit_cleanup: + client->payload_length = 0; + free(buf); + return; +} + +bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length) { + assert(payload); + + char data[ipc_header_size]; + uint32_t *data32 = (uint32_t*)(data + sizeof(ipc_magic)); + + memcpy(data, ipc_magic, sizeof(ipc_magic)); + data32[0] = payload_length; + data32[1] = client->current_command; + + while (client->write_buffer_len + ipc_header_size + payload_length >= + client->write_buffer_size) { + client->write_buffer_size *= 2; + } + + // TODO: reduce the limit back to 4 MB when screenshooter is implemented + if (client->write_buffer_size > (1 << 28)) { // 256 MB + sway_log(L_ERROR, "Client write buffer too big, disconnecting client"); + ipc_client_disconnect(client); + return false; + } + + char *new_buffer = realloc(client->write_buffer, client->write_buffer_size); + if (!new_buffer) { + sway_log(L_ERROR, "Unable to reallocate ipc client write buffer"); + ipc_client_disconnect(client); + return false; + } + client->write_buffer = new_buffer; + + memcpy(client->write_buffer + client->write_buffer_len, data, ipc_header_size); + client->write_buffer_len += ipc_header_size; + memcpy(client->write_buffer + client->write_buffer_len, payload, payload_length); + client->write_buffer_len += payload_length; + + if (!client->writable_event_source) { + client->writable_event_source = wl_event_loop_add_fd( + server.wl_event_loop, client->fd, WL_EVENT_WRITABLE, + ipc_client_handle_writable, client); + } + + sway_log(L_DEBUG, "Added IPC reply to client %d queue: %s", client->fd, payload); + + return true; +} + +void ipc_get_workspaces_callback(swayc_t *workspace, void *data) { + if (workspace->type == C_WORKSPACE) { + json_object *workspace_json = ipc_json_describe_container(workspace); + // override the default focused indicator because + // it's set differently for the get_workspaces reply + bool focused = root_container.focused == workspace->parent && workspace->parent->focused == workspace; + json_object_object_del(workspace_json, "focused"); + json_object_object_add(workspace_json, "focused", json_object_new_boolean(focused)); + json_object_array_add((json_object *)data, workspace_json); + } +} + +void ipc_get_outputs_callback(swayc_t *container, void *data) { + if (container->type == C_OUTPUT) { + json_object_array_add((json_object *)data, ipc_json_describe_container(container)); + } +} + +static void ipc_get_marks_callback(swayc_t *container, void *data) { + json_object *object = (json_object *)data; + if (container->marks) { + for (int i = 0; i < container->marks->length; ++i) { + char *mark = (char *)container->marks->items[i]; + json_object_array_add(object, json_object_new_string(mark)); + } + } +} + +void ipc_send_event(const char *json_string, enum ipc_command_type event) { + static struct { + enum ipc_command_type event; + enum ipc_feature feature; + } security_mappings[] = { + { IPC_EVENT_WORKSPACE, IPC_FEATURE_EVENT_WORKSPACE }, + { IPC_EVENT_OUTPUT, IPC_FEATURE_EVENT_OUTPUT }, + { IPC_EVENT_MODE, IPC_FEATURE_EVENT_MODE }, + { IPC_EVENT_WINDOW, IPC_FEATURE_EVENT_WINDOW }, + { IPC_EVENT_BINDING, IPC_FEATURE_EVENT_BINDING }, + { IPC_EVENT_INPUT, IPC_FEATURE_EVENT_INPUT } + }; + + uint32_t security_mask = 0; + for (size_t i = 0; i < sizeof(security_mappings) / sizeof(security_mappings[0]); ++i) { + if (security_mappings[i].event == event) { + security_mask = security_mappings[i].feature; + break; + } + } + + int i; + struct ipc_client *client; + for (i = 0; i < ipc_client_list->length; i++) { + client = ipc_client_list->items[i]; + if (!(client->security_policy & security_mask)) { + continue; + } + if ((client->subscribed_events & event_mask(event)) == 0) { + continue; + } + client->current_command = event; + if (!ipc_send_reply(client, json_string, (uint32_t) strlen(json_string))) { + sway_log_errno(L_INFO, "Unable to send reply to IPC client"); + ipc_client_disconnect(client); + } + } +} + +void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change) { + sway_log(L_DEBUG, "Sending workspace::%s event", change); + json_object *obj = json_object_new_object(); + json_object_object_add(obj, "change", json_object_new_string(change)); + if (strcmp("focus", change) == 0) { + if (old) { + json_object_object_add(obj, "old", ipc_json_describe_container_recursive(old)); + } else { + json_object_object_add(obj, "old", NULL); + } + } + + if (new) { + json_object_object_add(obj, "current", ipc_json_describe_container_recursive(new)); + } else { + json_object_object_add(obj, "current", NULL); + } + + const char *json_string = json_object_to_json_string(obj); + ipc_send_event(json_string, IPC_EVENT_WORKSPACE); + + json_object_put(obj); // free +} + +void ipc_event_window(swayc_t *window, const char *change) { + sway_log(L_DEBUG, "Sending window::%s event", change); + json_object *obj = json_object_new_object(); + json_object_object_add(obj, "change", json_object_new_string(change)); + json_object_object_add(obj, "container", ipc_json_describe_container_recursive(window)); + + const char *json_string = json_object_to_json_string(obj); + ipc_send_event(json_string, IPC_EVENT_WINDOW); + + json_object_put(obj); // free +} + +void ipc_event_barconfig_update(struct bar_config *bar) { + sway_log(L_DEBUG, "Sending barconfig_update event"); + json_object *json = ipc_json_describe_bar_config(bar); + const char *json_string = json_object_to_json_string(json); + ipc_send_event(json_string, IPC_EVENT_BARCONFIG_UPDATE); + + json_object_put(json); // free +} + +void ipc_event_mode(const char *mode) { + sway_log(L_DEBUG, "Sending mode::%s event", mode); + json_object *obj = json_object_new_object(); + json_object_object_add(obj, "change", json_object_new_string(mode)); + + const char *json_string = json_object_to_json_string(obj); + ipc_send_event(json_string, IPC_EVENT_MODE); + + json_object_put(obj); // free +} + +void ipc_event_modifier(uint32_t modifier, const char *state) { + sway_log(L_DEBUG, "Sending modifier::%s event", state); + json_object *obj = json_object_new_object(); + json_object_object_add(obj, "change", json_object_new_string(state)); + + const char *modifier_name = get_modifier_name_by_mask(modifier); + json_object_object_add(obj, "modifier", json_object_new_string(modifier_name)); + + const char *json_string = json_object_to_json_string(obj); + ipc_send_event(json_string, IPC_EVENT_MODIFIER); + + json_object_put(obj); // free +} + +static void ipc_event_binding(json_object *sb_obj) { + sway_log(L_DEBUG, "Sending binding::run event"); + json_object *obj = json_object_new_object(); + json_object_object_add(obj, "change", json_object_new_string("run")); + json_object_object_add(obj, "binding", sb_obj); + + const char *json_string = json_object_to_json_string(obj); + ipc_send_event(json_string, IPC_EVENT_BINDING); + + json_object_put(obj); // free +} + +void ipc_event_binding_keyboard(struct sway_binding *sb) { + json_object *sb_obj = json_object_new_object(); + json_object_object_add(sb_obj, "command", json_object_new_string(sb->command)); + + const char *names[10]; + + int len = get_modifier_names(names, sb->modifiers); + int i; + json_object *modifiers = json_object_new_array(); + for (i = 0; i < len; ++i) { + json_object_array_add(modifiers, json_object_new_string(names[i])); + } + + json_object_object_add(sb_obj, "event_state_mask", modifiers); + + json_object *input_codes = json_object_new_array(); + int input_code = 0; + json_object *symbols = json_object_new_array(); + json_object *symbol = NULL; + + if (sb->bindcode) { // bindcode: populate input_codes + uint32_t keycode; + for (i = 0; i < sb->keys->length; ++i) { + keycode = *(uint32_t *)sb->keys->items[i]; + json_object_array_add(input_codes, json_object_new_int(keycode)); + if (i == 0) { + input_code = keycode; + } + } + } else { // bindsym: populate symbols + uint32_t keysym; + char buffer[64]; + for (i = 0; i < sb->keys->length; ++i) { + keysym = *(uint32_t *)sb->keys->items[i]; + if (xkb_keysym_get_name(keysym, buffer, 64) > 0) { + json_object *str = json_object_new_string(buffer); + json_object_array_add(symbols, str); + if (i == 0) { + symbol = str; + } + } + } + } + + json_object_object_add(sb_obj, "input_codes", input_codes); + json_object_object_add(sb_obj, "input_code", json_object_new_int(input_code)); + json_object_object_add(sb_obj, "symbols", symbols); + json_object_object_add(sb_obj, "symbol", symbol); + json_object_object_add(sb_obj, "input_type", json_object_new_string("keyboard")); + + ipc_event_binding(sb_obj); +} diff --git a/sway/old/layout.c b/sway/old/layout.c new file mode 100644 index 00000000..22f81688 --- /dev/null +++ b/sway/old/layout.c @@ -0,0 +1,1773 @@ +#define _XOPEN_SOURCE 500 +#include +#include +#include +#include +#include "sway/config.h" +#include "sway/container.h" +#include "sway/workspace.h" +#include "sway/focus.h" +#include "sway/output.h" +#include "sway/ipc-server.h" +#include "sway/border.h" +#include "sway/layout.h" +#include "list.h" +#include "log.h" + +swayc_t root_container; +swayc_t *current_focus; +list_t *scratchpad; + +int min_sane_h = 60; +int min_sane_w = 100; + +void init_layout(void) { + root_container.id = 0; // normally assigned in new_swayc() + root_container.type = C_ROOT; + root_container.layout = L_NONE; + root_container.name = strdup("root"); + root_container.children = create_list(); + root_container.handle = -1; + root_container.visible = true; + current_focus = &root_container; + scratchpad = create_list(); +} + +int index_child(const swayc_t *child) { + swayc_t *parent = child->parent; + int i, len; + if (!child->is_floating) { + len = parent->children->length; + for (i = 0; i < len; ++i) { + if (parent->children->items[i] == child) { + break; + } + } + } else { + len = parent->floating->length; + for (i = 0; i < len; ++i) { + if (parent->floating->items[i] == child) { + break; + } + } + } + if (!sway_assert(i < len, "Stray container")) { + return -1; + } + return i; +} + +void add_child(swayc_t *parent, swayc_t *child) { + sway_log(L_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)", child, child->type, + child->width, child->height, parent, parent->type, parent->width, parent->height); + list_add(parent->children, child); + child->parent = parent; + // set focus for this container + if (!parent->focused) { + parent->focused = child; + } + if (parent->type == C_WORKSPACE && child->type == C_VIEW && (parent->workspace_layout == L_TABBED || parent->workspace_layout == L_STACKED)) { + child = new_container(child, parent->workspace_layout); + } +} + +static double *get_height(swayc_t *cont) { + return &cont->height; +} + +static double *get_width(swayc_t *cont) { + return &cont->width; +} + +void insert_child(swayc_t *parent, swayc_t *child, int index) { + if (index > parent->children->length) { + index = parent->children->length; + } + if (index < 0) { + index = 0; + } + list_insert(parent->children, index, child); + child->parent = parent; + if (!parent->focused) { + parent->focused = child; + } + if (parent->type == C_WORKSPACE && child->type == C_VIEW && (parent->workspace_layout == L_TABBED || parent->workspace_layout == L_STACKED)) { + child = new_container(child, parent->workspace_layout); + } + if (is_auto_layout(parent->layout)) { + /* go through each group, adjust the size of the first child of each group */ + double *(*get_maj_dim)(swayc_t *cont); + double *(*get_min_dim)(swayc_t *cont); + if (parent->layout == L_AUTO_LEFT || parent->layout == L_AUTO_RIGHT) { + get_maj_dim = get_width; + get_min_dim = get_height; + } else { + get_maj_dim = get_height; + get_min_dim = get_width; + } + for (int i = index; i < parent->children->length;) { + int start = auto_group_start_index(parent, i); + int end = auto_group_end_index(parent, i); + swayc_t *first = parent->children->items[start]; + if (start + 1 < parent->children->length) { + /* preserve the group's dimension along major axis */ + *get_maj_dim(first) = *get_maj_dim(parent->children->items[start + 1]); + } else { + /* new group, let the apply_layout handle it */ + first->height = first->width = 0; + break; + } + double remaining = *get_min_dim(parent); + for (int j = end - 1; j > start; --j) { + swayc_t *sibling = parent->children->items[j]; + if (sibling == child) { + /* the inserted child won't yet have its minor + dimension set */ + remaining -= *get_min_dim(parent) / (end - start); + } else { + remaining -= *get_min_dim(sibling); + } + } + *get_min_dim(first) = remaining; + i = end; + } + } +} + +void add_floating(swayc_t *ws, swayc_t *child) { + sway_log(L_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)", child, child->type, + child->width, child->height, ws, ws->type, ws->width, ws->height); + if (!sway_assert(ws->type == C_WORKSPACE, "Must be of workspace type")) { + return; + } + list_add(ws->floating, child); + child->parent = ws; + child->is_floating = true; + if (!ws->focused) { + ws->focused = child; + } + ipc_event_window(child, "floating"); +} + +swayc_t *add_sibling(swayc_t *fixed, swayc_t *active) { + swayc_t *parent = fixed->parent; + if (fixed->is_floating) { + if (active->is_floating) { + int i = index_child(fixed); + list_insert(parent->floating, i + 1, active); + } else { + list_add(parent->children, active); + } + } else { + if (active->is_floating) { + list_add(parent->floating, active); + } else { + int i = index_child(fixed); + if (is_auto_layout(parent->layout)) { + list_add(parent->children, active); + } else { + list_insert(parent->children, i + 1, active); + } + } + } + active->parent = parent; + // focus new child + parent->focused = active; + return active->parent; +} + +swayc_t *replace_child(swayc_t *child, swayc_t *new_child) { + swayc_t *parent = child->parent; + if (parent == NULL) { + return NULL; + } + int i = index_child(child); + if (child->is_floating) { + parent->floating->items[i] = new_child; + } else { + parent->children->items[i] = new_child; + } + // Set parent and focus for new_child + new_child->parent = child->parent; + if (child->parent->focused == child) { + child->parent->focused = new_child; + } + child->parent = NULL; + + // Set geometry for new child + new_child->x = child->x; + new_child->y = child->y; + new_child->width = child->width; + new_child->height = child->height; + + // reset geometry for child + child->width = 0; + child->height = 0; + + // deactivate child + if (child->type == C_VIEW) { + wlc_view_set_state(child->handle, WLC_BIT_ACTIVATED, false); + } + return parent; +} + +swayc_t *remove_child(swayc_t *child) { + int i; + swayc_t *parent = child->parent; + if (child->is_floating) { + // Special case for floating views + for (i = 0; i < parent->floating->length; ++i) { + if (parent->floating->items[i] == child) { + list_del(parent->floating, i); + break; + } + } + i = 0; + } else { + for (i = 0; i < parent->children->length; ++i) { + if (parent->children->items[i] == child) { + list_del(parent->children, i); + break; + } + } + if (is_auto_layout(parent->layout) && parent->children->length) { + /* go through each group, adjust the size of the last child of each group */ + double *(*get_maj_dim)(swayc_t *cont); + double *(*get_min_dim)(swayc_t *cont); + if (parent->layout == L_AUTO_LEFT || parent->layout == L_AUTO_RIGHT) { + get_maj_dim = get_width; + get_min_dim = get_height; + } else { + get_maj_dim = get_height; + get_min_dim = get_width; + } + for (int j = parent->children->length - 1; j >= i;) { + int start = auto_group_start_index(parent, j); + int end = auto_group_end_index(parent, j); + swayc_t *first = parent->children->items[start]; + if (i == start) { + /* removed element was first child in the current group, + use its size along the major axis */ + *get_maj_dim(first) = *get_maj_dim(child); + } else if (start > i) { + /* preserve the group's dimension along major axis */ + *get_maj_dim(first) = *get_maj_dim(parent->children->items[start - 1]); + } + if (end != parent->children->length) { + double remaining = *get_min_dim(parent); + for (int k = start; k < end - 1; ++k) { + swayc_t *sibling = parent->children->items[k]; + remaining -= *get_min_dim(sibling); + } + /* last element of the group gets remaining size, elements + that don't change groups keep their ratio */ + *get_min_dim((swayc_t *) parent->children->items[end - 1]) = remaining; + } /* else last group, let apply_layout handle it */ + j = start - 1; + } + } + } + // Set focused to new container + if (parent->focused == child) { + if (parent->children->length > 0) { + parent->focused = parent->children->items[i ? i-1:0]; + } else if (parent->floating && parent->floating->length) { + parent->focused = parent->floating->items[parent->floating->length - 1]; + } else { + parent->focused = NULL; + } + } + child->parent = NULL; + // deactivate view + if (child->type == C_VIEW) { + wlc_view_set_state(child->handle, WLC_BIT_ACTIVATED, false); + } + return parent; +} + +void swap_container(swayc_t *a, swayc_t *b) { + if (!sway_assert(a&&b, "parameters must be non null") || + !sway_assert(a->parent && b->parent, "containers must have parents")) { + return; + } + size_t a_index = index_child(a); + size_t b_index = index_child(b); + swayc_t *a_parent = a->parent; + swayc_t *b_parent = b->parent; + // Swap the pointers + if (a->is_floating) { + a_parent->floating->items[a_index] = b; + } else { + a_parent->children->items[a_index] = b; + } + if (b->is_floating) { + b_parent->floating->items[b_index] = a; + } else { + b_parent->children->items[b_index] = a; + } + a->parent = b_parent; + b->parent = a_parent; + if (a_parent->focused == a) { + a_parent->focused = b; + } + // don't want to double switch + if (b_parent->focused == b && a_parent != b_parent) { + b_parent->focused = a; + } +} + +void swap_geometry(swayc_t *a, swayc_t *b) { + double x = a->x; + double y = a->y; + double w = a->width; + double h = a->height; + a->x = b->x; + a->y = b->y; + a->width = b->width; + a->height = b->height; + b->x = x; + b->y = y; + b->width = w; + b->height = h; +} + +static void swap_children(swayc_t *container, int a, int b) { + if (a >= 0 && b >= 0 && a < container->children->length + && b < container->children->length + && a != b) { + swayc_t *pa = (swayc_t *)container->children->items[a]; + swayc_t *pb = (swayc_t *)container->children->items[b]; + container->children->items[a] = container->children->items[b]; + container->children->items[b] = pa; + if (is_auto_layout(container->layout)) { + size_t ga = auto_group_index(container, a); + size_t gb = auto_group_index(container, b); + if (ga != gb) { + swap_geometry(pa, pb); + } + } + } +} + +void move_container(swayc_t *container, enum movement_direction dir, int move_amt) { + enum swayc_layouts layout = L_NONE; + swayc_t *parent = container->parent; + if (container->is_floating) { + swayc_t *output = swayc_parent_by_type(container, C_OUTPUT); + switch(dir) { + case MOVE_LEFT: + container->x = MAX(0, container->x - move_amt); + break; + case MOVE_RIGHT: + container->x = MIN(output->width - container->width, container->x + move_amt); + break; + case MOVE_UP: + container->y = MAX(0, container->y - move_amt); + break; + case MOVE_DOWN: + container->y = MIN(output->height - container->height, container->y + move_amt); + break; + default: + break; + } + update_geometry(container); + return; + } + if (container->type != C_VIEW && container->type != C_CONTAINER) { + return; + } + if (dir == MOVE_UP || dir == MOVE_DOWN) { + layout = L_VERT; + } else if (dir == MOVE_LEFT || dir == MOVE_RIGHT) { + layout = L_HORIZ; + } else if (dir == MOVE_FIRST) { + // swap first child in auto layout with currently focused child + if (is_auto_layout(parent->layout)) { + int focused_idx = index_child(container); + swayc_t *first = parent->children->items[0]; + if (focused_idx > 0) { + list_swap(parent->children, 0, focused_idx); + swap_geometry(first, container); + } + arrange_windows(parent->parent, -1, -1); + ipc_event_window(container, "move"); + set_focused_container_for(parent->parent, container); + } + return; + } else if (! (dir == MOVE_NEXT || dir == MOVE_PREV)) { + return; + } + swayc_t *child = container; + bool ascended = false; + + // View is wrapped in intermediate container which is needed for displaying + // the titlebar. Moving only the view outside of its parent container would just + // wrap it again under worspace. There would effectively be no movement, + // just a change of wrapping container. + if (child->type == C_VIEW && + parent->type == C_CONTAINER && + parent->children->length == 1 && + parent->parent->type == C_WORKSPACE) { + child = parent; + parent = parent->parent; + } + + while (true) { + sway_log(L_DEBUG, "container:%p, parent:%p, child %p,", + container,parent,child); + if (parent->layout == layout + || (layout == L_NONE && (parent->type == C_CONTAINER || parent->type == C_WORKSPACE)) /* accept any layout for next/prev direction */ + || (parent->layout == L_TABBED && layout == L_HORIZ) + || (parent->layout == L_STACKED && layout == L_VERT) + || is_auto_layout(parent->layout)) { + int diff; + // If it has ascended (parent has moved up), no container is removed + // so insert it at index, or index+1. + // if it has not, the moved container is removed, so it needs to be + // inserted at index-1, or index+1 + if (ascended) { + diff = dir == MOVE_LEFT || dir == MOVE_UP || dir == MOVE_PREV ? 0 : 1; + } else { + diff = dir == MOVE_LEFT || dir == MOVE_UP || dir == MOVE_PREV ? -1 : 1; + } + int idx = index_child(child); + int desired = idx + diff; + if (dir == MOVE_NEXT || dir == MOVE_PREV) { + // Next/Prev always wrap. + if (desired < 0) { + desired += parent->children->length; + } else if (desired >= parent->children->length) { + desired = 0; + } + } + // when it has ascended, legal insertion position is 0:len + // when it has not, legal insertion position is 0:len-1 + if (desired >= 0 && desired - ascended < parent->children->length) { + if (!ascended) { + child = parent->children->items[desired]; + // Move container into sibling container + if (child->type == C_CONTAINER) { + parent = child; + // Insert it in first/last if matching layout, otherwise + // insert it next to focused container + if (parent->layout == layout + || (parent->layout == L_TABBED && layout == L_HORIZ) + || (parent->layout == L_STACKED && layout == L_VERT) + || is_auto_layout(parent->layout)) { + desired = (diff < 0) * parent->children->length; + } else { + desired = index_child(child->focused) + 1; + } + //reset geometry + container->width = container->height = 0; + } + } + if (container->parent == parent) { + swap_children(parent, idx, desired); + } else { + swayc_t *old_parent = remove_child(container); + insert_child(parent, container, desired); + destroy_container(old_parent); + sway_log(L_DEBUG,"Moving to %p %d", parent, desired); + } + break; + } + } + // Change parent layout if we need to + if (parent->children->length == 1 && parent->layout != layout && layout != L_NONE) { + /* swayc_change_layout(parent, layout); */ + parent->layout = layout; + continue; + } + if (parent->type == C_WORKSPACE) { + // If moving to an adjacent output we need a starting position (since this + // output might border to multiple outputs). + struct wlc_point abs_pos; + get_absolute_center_position(container, &abs_pos); + + swayc_t *output = swayc_adjacent_output(parent->parent, dir, &abs_pos, true); + + if (output) { + sway_log(L_DEBUG, "Moving between outputs"); + swayc_t *old_parent = remove_child(container); + destroy_container(old_parent); + + swayc_t *dest = output->focused; + switch (dir) { + case MOVE_LEFT: + case MOVE_UP: + // reset container geometry + container->width = container->height = 0; + add_child(dest, container); + break; + case MOVE_RIGHT: + case MOVE_DOWN: + // reset container geometry + container->width = container->height = 0; + insert_child(dest, container, 0); + break; + default: + break; + } + // arrange new workspace + arrange_windows(dest, -1, -1); + set_focused_container(container); + break; + } + + // We simply cannot move any further. + if (parent->layout == layout) { + break; + } + // Create container around workspace to insert child into + parent = new_container(parent, layout); + // Previous line set the resulting container's layout to + // workspace_layout. It should have been just layout. + parent->layout = parent->parent->layout; + } + ascended = true; + child = parent; + parent = child->parent; + } + arrange_windows(parent->parent, -1, -1); + ipc_event_window(container, "move"); + set_focused_container_for(parent->parent, container); +} + +void move_container_to(swayc_t* container, swayc_t* destination) { + if (container == destination || swayc_is_parent_of(container, destination)) { + return; + } + swayc_t *parent = remove_child(container); + // Send to new destination + if (container->is_floating) { + swayc_t *ws = swayc_active_workspace_for(destination); + add_floating(ws, container); + + // If the workspace only has one child after adding one, it + // means that the workspace was just initialized. + if (ws->children->length + ws->floating->length == 1) { + ipc_event_workspace(NULL, ws, "init"); + } + } else if (destination->type == C_WORKSPACE) { + // reset container geometry + container->width = container->height = 0; + add_child(destination, container); + + // If the workspace only has one child after adding one, it + // means that the workspace was just initialized. + if (destination->children->length + destination->floating->length == 1) { + ipc_event_workspace(NULL, destination, "init"); + } + } else { + // reset container geometry + container->width = container->height = 0; + add_sibling(destination, container); + } + // Destroy old container if we need to + parent = destroy_container(parent); + // Refocus + swayc_t *op1 = swayc_parent_by_type(destination, C_OUTPUT); + swayc_t *op2 = swayc_parent_by_type(parent, C_OUTPUT); + set_focused_container(get_focused_view(op1)); + arrange_windows(op1, -1, -1); + update_visibility(op1); + if (op1 != op2) { + set_focused_container(get_focused_view(op2)); + arrange_windows(op2, -1, -1); + update_visibility(op2); + } +} + +void move_workspace_to(swayc_t* workspace, swayc_t* destination) { + if (workspace == destination || swayc_is_parent_of(workspace, destination)) { + return; + } + swayc_t *src_op = remove_child(workspace); + // reset container geometry + workspace->width = workspace->height = 0; + add_child(destination, workspace); + sort_workspaces(destination); + // Refocus destination (change to new workspace) + set_focused_container(get_focused_view(workspace)); + arrange_windows(destination, -1, -1); + update_visibility(destination); + + // make sure source output has a workspace + if (src_op->children->length == 0) { + char *ws_name = workspace_next_name(src_op->name); + swayc_t *ws = new_workspace(src_op, ws_name); + ws->is_focused = true; + free(ws_name); + } + set_focused_container(get_focused_view(src_op)); + update_visibility(src_op); +} + +static void adjust_border_geometry(swayc_t *c, struct wlc_geometry *g, + const struct wlc_size *res, int left, int right, int top, int bottom) { + + g->size.w += left + right; + if (g->origin.x - left < 0) { + g->size.w += g->origin.x - left; + } else if (g->origin.x + g->size.w - right > res->w) { + g->size.w = res->w - g->origin.x + right; + } + + g->size.h += top + bottom; + if (g->origin.y - top < 0) { + g->size.h += g->origin.y - top; + } else if (g->origin.y + g->size.h - top > res->h) { + g->size.h = res->h - g->origin.y + top; + } + + g->origin.x = MIN((uint32_t)MAX(g->origin.x - left, 0), res->w); + g->origin.y = MIN((uint32_t)MAX(g->origin.y - top, 0), res->h); + +} + +static void update_border_geometry_floating(swayc_t *c, struct wlc_geometry *geometry) { + struct wlc_geometry g = *geometry; + c->actual_geometry = g; + + swayc_t *output = swayc_parent_by_type(c, C_OUTPUT); + struct wlc_size res; + output_get_scaled_size(output->handle, &res); + + switch (c->border_type) { + case B_NONE: + break; + case B_PIXEL: + adjust_border_geometry(c, &g, &res, c->border_thickness, + c->border_thickness, c->border_thickness, c->border_thickness); + break; + case B_NORMAL: + { + int title_bar_height = config->font_height + 4; // borders + padding + + adjust_border_geometry(c, &g, &res, c->border_thickness, + c->border_thickness, title_bar_height, c->border_thickness); + + struct wlc_geometry title_bar = { + .origin = { + .x = c->actual_geometry.origin.x - c->border_thickness, + .y = c->actual_geometry.origin.y - title_bar_height + }, + .size = { + .w = c->actual_geometry.size.w + (2 * c->border_thickness), + .h = title_bar_height + } + }; + c->title_bar_geometry = title_bar; + break; + } + } + + c->border_geometry = g; + *geometry = c->actual_geometry; + + update_container_border(c); +} + +void update_layout_geometry(swayc_t *parent, enum swayc_layouts prev_layout) { + switch (parent->layout) { + case L_TABBED: + case L_STACKED: + if (prev_layout != L_TABBED && prev_layout != L_STACKED) { + // cache current geometry for all non-float children + int i; + for (i = 0; i < parent->children->length; ++i) { + swayc_t *child = parent->children->items[i]; + child->cached_geometry.origin.x = child->x; + child->cached_geometry.origin.y = child->y; + child->cached_geometry.size.w = child->width; + child->cached_geometry.size.h = child->height; + } + } + break; + default: + if (prev_layout == L_TABBED || prev_layout == L_STACKED) { + // recover cached geometry for all non-float children + int i; + for (i = 0; i < parent->children->length; ++i) { + swayc_t *child = parent->children->items[i]; + // only recoverer cached geometry if non-zero + if (!wlc_geometry_equals(&child->cached_geometry, &wlc_geometry_zero)) { + child->x = child->cached_geometry.origin.x; + child->y = child->cached_geometry.origin.y; + child->width = child->cached_geometry.size.w; + child->height = child->cached_geometry.size.h; + } + } + } + break; + } +} + +static int update_gap_geometry(swayc_t *container, struct wlc_geometry *g) { + swayc_t *ws = swayc_parent_by_type(container, C_WORKSPACE); + swayc_t *op = ws->parent; + int gap = container->is_floating ? 0 : swayc_gap(container); + if (gap % 2 != 0) { + // because gaps are implemented as "half sized margins" it's currently + // not possible to align views properly with odd sized gaps. + gap -= 1; + } + + g->origin.x = container->x + gap/2 < op->width ? container->x + gap/2 : op->width-1; + g->origin.y = container->y + gap/2 < op->height ? container->y + gap/2 : op->height-1; + g->size.w = container->width > gap ? container->width - gap : 1; + g->size.h = container->height > gap ? container->height - gap : 1; + + if ((!config->edge_gaps && gap > 0) || (config->smart_gaps && ws->children->length == 1)) { + // Remove gap against the workspace edges. Because a pixel is not + // divisable, depending on gap size and the number of siblings our view + // might be at the workspace edge without being exactly so (thus test + // with gap, and align correctly). + if (container->x - gap <= ws->x) { + g->origin.x = ws->x; + g->size.w = container->width - gap/2; + } + if (container->y - gap <= ws->y) { + g->origin.y = ws->y; + g->size.h = container->height - gap/2; + } + if (container->x + container->width + gap >= ws->x + ws->width) { + g->size.w = ws->x + ws->width - g->origin.x; + } + if (container->y + container->height + gap >= ws->y + ws->height) { + g->size.h = ws->y + ws->height - g->origin.y; + } + } + + return gap; +} + +void update_geometry(swayc_t *container) { + if (container->type != C_VIEW && container->type != C_CONTAINER) { + return; + } + + swayc_t *workspace = swayc_parent_by_type(container, C_WORKSPACE); + swayc_t *op = workspace->parent; + swayc_t *parent = container->parent; + + struct wlc_geometry geometry = { + .origin = { + .x = container->x < op->width ? container->x : op->width-1, + .y = container->y < op->height ? container->y : op->height-1 + }, + .size = { + .w = container->width, + .h = container->height, + } + }; + + int gap = 0; + + // apply inner gaps to non-tabbed/stacked containers + swayc_t *p = swayc_tabbed_stacked_ancestor(container); + if (p == NULL) { + gap = update_gap_geometry(container, &geometry); + } + + swayc_t *output = swayc_parent_by_type(container, C_OUTPUT); + struct wlc_size size; + output_get_scaled_size(output->handle, &size); + + if (swayc_is_fullscreen(container)) { + geometry.origin.x = 0; + geometry.origin.y = 0; + geometry.size.w = size.w; + geometry.size.h = size.h; + if (op->focused == workspace) { + wlc_view_bring_to_front(container->handle); + } + + container->border_geometry = wlc_geometry_zero; + container->title_bar_geometry = wlc_geometry_zero; + border_clear(container->border); + } else if (container->is_floating) { // allocate border for floating window + update_border_geometry_floating(container, &geometry); + } else if (!container->is_floating) { // allocate border for titled window + container->border_geometry = geometry; + + int border_top = container->border_thickness; + int border_bottom = container->border_thickness; + int border_left = container->border_thickness; + int border_right = container->border_thickness; + + // handle hide_edge_borders + if (config->hide_edge_borders != E_NONE && (gap <= 0 || (config->smart_gaps && workspace->children->length == 1))) { + if (config->hide_edge_borders == E_VERTICAL || config->hide_edge_borders == E_BOTH) { + if (geometry.origin.x == workspace->x) { + border_left = 0; + } + + if (geometry.origin.x + geometry.size.w == workspace->x + workspace->width) { + border_right = 0; + } + } + + if (config->hide_edge_borders == E_HORIZONTAL || config->hide_edge_borders == E_BOTH) { + if (geometry.origin.y == workspace->y || should_hide_top_border(container, geometry.origin.y)) { + border_top = 0; + } + + if (geometry.origin.y + geometry.size.h == workspace->y + workspace->height) { + border_bottom = 0; + } + } + + if (config->hide_edge_borders == E_SMART && workspace->children->length == 1) { + border_top = 0; + border_bottom = 0; + border_left = 0; + border_right = 0; + } + } + + int title_bar_height = config->font_height + 4; //borders + padding + + if (parent->layout == L_TABBED && parent->children->length > 1) { + int i, x = 0, w, l, r; + l = parent->children->length; + w = geometry.size.w / l; + r = geometry.size.w % l; + for (i = 0; i < parent->children->length; ++i) { + swayc_t *view = parent->children->items[i]; + if (view == container) { + x = w * i; + if (i == l - 1) { + w += r; + } + break; + } + } + + struct wlc_geometry title_bar = { + .origin = { + .x = container->border_geometry.origin.x + x, + .y = container->border_geometry.origin.y + }, + .size = { + .w = w, + .h = title_bar_height + } + }; + geometry.origin.x += border_left; + geometry.origin.y += title_bar.size.h; + geometry.size.w -= (border_left + border_right); + geometry.size.h -= (border_bottom + title_bar.size.h); + container->title_bar_geometry = title_bar; + } else if (parent->layout == L_STACKED && parent->children->length > 1) { + int i, y = 0; + for (i = 0; i < parent->children->length; ++i) { + swayc_t *view = parent->children->items[i]; + if (view == container) { + y = title_bar_height * i; + } + } + + struct wlc_geometry title_bar = { + .origin = { + .x = container->border_geometry.origin.x, + .y = container->border_geometry.origin.y + y + }, + .size = { + .w = container->border_geometry.size.w, + .h = title_bar_height + } + }; + title_bar_height = title_bar_height * parent->children->length; + geometry.origin.x += border_left; + geometry.origin.y += title_bar_height; + geometry.size.w -= (border_left + border_right); + geometry.size.h -= (border_bottom + title_bar_height); + container->title_bar_geometry = title_bar; + } else { + switch (container->border_type) { + case B_NONE: + break; + case B_PIXEL: + geometry.origin.x += border_left; + geometry.origin.y += border_top; + geometry.size.w -= (border_left + border_right); + geometry.size.h -= (border_top + border_bottom); + break; + case B_NORMAL: + { + struct wlc_geometry title_bar = { + .origin = { + .x = container->border_geometry.origin.x, + .y = container->border_geometry.origin.y + }, + .size = { + .w = container->border_geometry.size.w, + .h = title_bar_height + } + }; + geometry.origin.x += border_left; + geometry.origin.y += title_bar.size.h; + geometry.size.w -= (border_left + border_right); + geometry.size.h -= (border_bottom + title_bar.size.h); + container->title_bar_geometry = title_bar; + break; + } + } + } + + container->actual_geometry = geometry; + + if (container->type == C_VIEW) { + update_container_border(container); + } + } + + if (container->type == C_VIEW) { + wlc_view_set_geometry(container->handle, 0, &geometry); + } +} + +/** + * Layout application prototypes + */ +static void apply_horiz_layout(swayc_t *container, const double x, + const double y, const double width, + const double height, const int start, + const int end); +static void apply_vert_layout(swayc_t *container, const double x, + const double y, const double width, + const double height, const int start, + const int end); +static void apply_tabbed_or_stacked_layout(swayc_t *container, double x, + double y, double width, + double height); + +static void apply_auto_layout(swayc_t *container, const double x, const double y, + const double width, const double height, + enum swayc_layouts group_layout, + bool master_first); + +static void arrange_windows_r(swayc_t *container, double width, double height) { + int i; + if (width == -1 || height == -1) { + swayc_log(L_DEBUG, container, "Arranging layout for %p", container); + width = container->width; + height = container->height; + } + // pixels are indivisible. if we don't round the pixels, then the view + // calculations will be off (e.g. 50.5 + 50.5 = 101, but in reality it's + // 50 + 50 = 100). doing it here cascades properly to all width/height/x/y. + width = floor(width); + height = floor(height); + + sway_log(L_DEBUG, "Arranging layout for %p %s %fx%f+%f,%f", container, + container->name, container->width, container->height, container->x, + container->y); + + double x = 0, y = 0; + switch (container->type) { + case C_ROOT: + for (i = 0; i < container->children->length; ++i) { + swayc_t *output = container->children->items[i]; + sway_log(L_DEBUG, "Arranging output '%s' at %f,%f", output->name, output->x, output->y); + arrange_windows_r(output, -1, -1); + } + return; + case C_OUTPUT: + { + struct wlc_size resolution; + output_get_scaled_size(container->handle, &resolution); + width = resolution.w; height = resolution.h; + // output must have correct size due to e.g. seamless mouse, + // but a workspace might be smaller depending on panels. + container->width = width; + container->height = height; + } + // arrange all workspaces: + for (i = 0; i < container->children->length; ++i) { + swayc_t *child = container->children->items[i]; + arrange_windows_r(child, -1, -1); + } + // Bring all unmanaged views to the front + for (i = 0; i < container->unmanaged->length; ++i) { + wlc_handle *handle = container->unmanaged->items[i]; + wlc_view_bring_to_front(*handle); + } + return; + case C_WORKSPACE: + { + swayc_t *output = swayc_parent_by_type(container, C_OUTPUT); + width = output->width, height = output->height; + /* TODO WLR + for (i = 0; i < desktop_shell.panels->length; ++i) { + struct panel_config *config = desktop_shell.panels->items[i]; + if (config->output == output->handle) { + struct wlc_size size = *wlc_surface_get_size(config->surface); + sway_log(L_DEBUG, "-> Found panel for this workspace: %ux%u, position: %u", size.w, size.h, config->panel_position); + switch (config->panel_position) { + case DESKTOP_SHELL_PANEL_POSITION_TOP: + y += size.h; height -= size.h; + break; + case DESKTOP_SHELL_PANEL_POSITION_BOTTOM: + height -= size.h; + break; + case DESKTOP_SHELL_PANEL_POSITION_LEFT: + x += size.w; width -= size.w; + break; + case DESKTOP_SHELL_PANEL_POSITION_RIGHT: + width -= size.w; + break; + } + } + } + */ + int gap = swayc_gap(container); + x = container->x = x + gap; + y = container->y = y + gap; + width = container->width = width - gap * 2; + height = container->height = height - gap * 2; + sway_log(L_DEBUG, "Arranging workspace '%s' at %f, %f", container->name, container->x, container->y); + } + // children are properly handled below + break; + case C_VIEW: + { + container->width = width; + container->height = height; + update_geometry(container); + sway_log(L_DEBUG, "Set view to %.f x %.f @ %.f, %.f", container->width, + container->height, container->x, container->y); + } + return; + default: + container->width = width; + container->height = height; + x = container->x; + y = container->y; + + // add gaps to top level tapped/stacked container + if (container->parent->type == C_WORKSPACE && + (container->layout == L_TABBED || container->layout == L_STACKED)) { + update_geometry(container); + width = container->border_geometry.size.w; + height = container->border_geometry.size.h; + x = container->border_geometry.origin.x; + y = container->border_geometry.origin.y; + } + + // update container size if it's a direct child in a tabbed/stacked layout + // if parent is a workspace, its actual_geometry won't be initialized + if (swayc_tabbed_stacked_parent(container) != NULL && + container->parent->type != C_WORKSPACE) { + // Use parent actual_geometry as a base for calculating + // container geometry + container->width = container->parent->actual_geometry.size.w; + container->height = container->parent->actual_geometry.size.h; + container->x = container->parent->actual_geometry.origin.x; + container->y = container->parent->actual_geometry.origin.y; + + update_geometry(container); + width = container->width = container->actual_geometry.size.w; + height = container->height = container->actual_geometry.size.h; + x = container->x = container->actual_geometry.origin.x; + y = container->y = container->actual_geometry.origin.y; + } + + break; + } + + switch (container->layout) { + case L_HORIZ: + default: + apply_horiz_layout(container, x, y, width, height, 0, + container->children->length); + break; + case L_VERT: + apply_vert_layout(container, x, y, width, height, 0, + container->children->length); + break; + case L_TABBED: + case L_STACKED: + apply_tabbed_or_stacked_layout(container, x, y, width, height); + break; + case L_AUTO_LEFT: + apply_auto_layout(container, x, y, width, height, L_VERT, true); + break; + case L_AUTO_RIGHT: + apply_auto_layout(container, x, y, width, height, L_VERT, false); + break; + case L_AUTO_TOP: + apply_auto_layout(container, x, y, width, height, L_HORIZ, true); + break; + case L_AUTO_BOTTOM: + apply_auto_layout(container, x, y, width, height, L_HORIZ, false); + break; + } + + // Arrage floating layouts for workspaces last + if (container->type == C_WORKSPACE) { + for (int i = 0; i < container->floating->length; ++i) { + swayc_t *view = container->floating->items[i]; + if (view->type == C_VIEW) { + update_geometry(view); + sway_log(L_DEBUG, "Set floating view to %.f x %.f @ %.f, %.f", + view->width, view->height, view->x, view->y); + if (swayc_is_fullscreen(view)) { + wlc_view_bring_to_front(view->handle); + } else if (!container->focused || + !swayc_is_fullscreen(container->focused)) { + wlc_view_bring_to_front(view->handle); + } + } + } + } +} + +void apply_horiz_layout(swayc_t *container, const double x, const double y, + const double width, const double height, + const int start, const int end) { + double scale = 0; + // Calculate total width + for (int i = start; i < end; ++i) { + double *old_width = &((swayc_t *)container->children->items[i])->width; + if (*old_width <= 0) { + if (end - start > 1) { + *old_width = width / (end - start - 1); + } else { + *old_width = width; + } + } + scale += *old_width; + } + scale = width / scale; + + // Resize windows + double child_x = x; + if (scale > 0.1) { + sway_log(L_DEBUG, "Arranging %p horizontally", container); + swayc_t *focused = NULL; + for (int i = start; i < end; ++i) { + swayc_t *child = container->children->items[i]; + sway_log(L_DEBUG, + "Calculating arrangement for %p:%d (will scale %f by %f)", child, + child->type, width, scale); + child->x = child_x; + child->y = y; + + if (child == container->focused) { + focused = child; + } + + if (i == end - 1) { + double remaining_width = x + width - child_x; + arrange_windows_r(child, remaining_width, height); + } else { + arrange_windows_r(child, child->width * scale, height); + } + child_x += child->width; + } + + // update focused view border last because it may + // depend on the title bar geometry of its siblings. + if (focused && container->children->length > 1) { + update_container_border(focused); + } + } +} + +void apply_vert_layout(swayc_t *container, const double x, const double y, + const double width, const double height, const int start, + const int end) { + int i; + double scale = 0; + // Calculate total height + for (i = start; i < end; ++i) { + double *old_height = &((swayc_t *)container->children->items[i])->height; + if (*old_height <= 0) { + if (end - start > 1) { + *old_height = height / (end - start - 1); + } else { + *old_height = height; + } + } + scale += *old_height; + } + scale = height / scale; + + // Resize + double child_y = y; + if (scale > 0.1) { + sway_log(L_DEBUG, "Arranging %p vertically", container); + swayc_t *focused = NULL; + for (i = start; i < end; ++i) { + swayc_t *child = container->children->items[i]; + sway_log(L_DEBUG, + "Calculating arrangement for %p:%d (will scale %f by %f)", child, + child->type, height, scale); + child->x = x; + child->y = child_y; + + if (child == container->focused) { + focused = child; + } + + if (i == end - 1) { + double remaining_height = y + height - child_y; + arrange_windows_r(child, width, remaining_height); + } else { + arrange_windows_r(child, width, child->height * scale); + } + child_y += child->height; + } + + // update focused view border last because it may + // depend on the title bar geometry of its siblings. + if (focused && container->children->length > 1) { + update_container_border(focused); + } + } +} + +void apply_tabbed_or_stacked_layout(swayc_t *container, double x, double y, + double width, double height) { + int i; + swayc_t *focused = NULL; + for (i = 0; i < container->children->length; ++i) { + swayc_t *child = container->children->items[i]; + child->x = x; + child->y = y; + if (child == container->focused) { + focused = child; + } else { + arrange_windows_r(child, width, height); + } + } + + if (focused) { + arrange_windows_r(focused, width, height); + } +} + +void apply_auto_layout(swayc_t *container, const double x, const double y, + const double width, const double height, + enum swayc_layouts group_layout, + bool master_first) { + // Auto layout "container" in width x height @ x, y + // using "group_layout" for each of the groups in the container. + // There is one "master" group, plus container->nb_slave_groups. + // Each group is layed out side by side following the "major" axis. + // The direction of the layout used for groups is the "minor" axis. + // Example: + // + // ---- major axis --> + // +---------+-----------+ + // | | | | + // | master | slave 1 | | + // | +-----------+ | minor axis (direction of group_layout) + // | | | | + // | | slave 2 | V + // +---------+-----------+ + // + // container with three children (one master and two slaves) and + // a single slave group (containing slave 1 and 2). The master + // group and slave group are layed out using L_VERT. + + size_t nb_groups = auto_group_count(container); + + // the target dimension of the container along the "major" axis, each + // group in the container will be layed out using "group_layout" along + // the "minor" axis. + double dim_maj; + double pos_maj; + + // x and y coords for the next group to be laid out. + const double *group_x, *group_y; + + // pos of the next group to layout along the major axis + double pos; + + // size of the next group along the major axis. + double group_dim; + + // height and width of next group to be laid out. + const double *group_h, *group_w; + + switch (group_layout) { + default: + sway_log(L_DEBUG, "Unknown layout type (%d) used in %s()", + group_layout, __func__); + /* fall through */ + case L_VERT: + dim_maj = width; + pos_maj = x; + + group_x = &pos; + group_y = &y; + group_w = &group_dim; + group_h = &height; + break; + case L_HORIZ: + dim_maj = height; + pos_maj = y; + + group_x = &x; + group_y = &pos; + group_w = &width; + group_h = &group_dim; + break; + } + + /* Determine the dimension of each of the groups in the layout. + * Dimension will be width for a VERT layout and height for a HORIZ + * layout. */ + double old_group_dim[nb_groups]; + double old_dim = 0; + for (size_t group = 0; group < nb_groups; ++group) { + int idx; + if (auto_group_bounds(container, group, &idx, NULL)) { + swayc_t *child = container->children->items[idx]; + double *dim = group_layout == L_HORIZ ? &child->height : &child->width; + if (*dim <= 0) { + // New child with uninitialized dimension + *dim = dim_maj; + if (nb_groups > 1) { + // child gets a dimension proportional to existing groups, + // it will be later scaled based on to the available size + // in the major axis. + *dim /= (nb_groups - 1); + } + } + old_dim += *dim; + old_group_dim[group] = *dim; + } + } + double scale = dim_maj / old_dim; + + /* Apply layout to each group */ + pos = pos_maj; + + for (size_t group = 0; group < nb_groups; ++group) { + int start, end; // index of first (inclusive) and last (exclusive) child in the group + if (auto_group_bounds(container, group, &start, &end)) { + // adjusted size of the group + group_dim = old_group_dim[group] * scale; + if (group == nb_groups - 1) { + group_dim = pos_maj + dim_maj - pos; // remaining width + } + sway_log(L_DEBUG, "Arranging container %p column %zu, children [%d,%d[ (%fx%f+%f,%f)", + container, group, start, end, *group_w, *group_h, *group_x, *group_y); + switch (group_layout) { + default: + case L_VERT: + apply_vert_layout(container, *group_x, *group_y, *group_w, *group_h, start, end); + break; + case L_HORIZ: + apply_horiz_layout(container, *group_x, *group_y, *group_w, *group_h, start, end); + break; + } + + /* update position for next group */ + pos += group_dim; + } + } +} + +void arrange_windows(swayc_t *container, double width, double height) { + update_visibility(container); + arrange_windows_r(container, width, height); + layout_log(&root_container, 0); +} + +void arrange_backgrounds(void) { + /* TODO WLR + struct background_config *bg; + for (int i = 0; i < desktop_shell.backgrounds->length; ++i) { + bg = desktop_shell.backgrounds->items[i]; + wlc_view_send_to_back(bg->handle); + } + */ +} + +/** + * Get swayc in the direction of newly entered output. + */ +static swayc_t *get_swayc_in_output_direction(swayc_t *output, enum movement_direction dir) { + if (!output) { + return NULL; + } + + swayc_t *ws = swayc_focus_by_type(output, C_WORKSPACE); + if (ws && ws->children->length > 0) { + switch (dir) { + case MOVE_LEFT: + // get most right child of new output + return ws->children->items[ws->children->length-1]; + case MOVE_RIGHT: + // get most left child of new output + return ws->children->items[0]; + case MOVE_UP: + case MOVE_DOWN: + { + swayc_t *focused_view = swayc_focus_by_type(ws, C_VIEW); + if (focused_view && focused_view->parent) { + swayc_t *parent = focused_view->parent; + if (parent->layout == L_VERT) { + if (dir == MOVE_UP) { + // get child furthest down on new output + return parent->children->items[parent->children->length-1]; + } else if (dir == MOVE_DOWN) { + // get child furthest up on new output + return parent->children->items[0]; + } + } + return focused_view; + } + break; + } + default: + break; + } + } + + return output; +} + +swayc_t *get_swayc_in_direction_under(swayc_t *container, enum movement_direction dir, swayc_t *limit) { + if (dir == MOVE_CHILD) { + return container->focused; + } + + swayc_t *parent = container->parent; + if (dir == MOVE_PARENT) { + if (parent->type == C_OUTPUT) { + return NULL; + } else { + return parent; + } + } + + if (dir == MOVE_PREV || dir == MOVE_NEXT) { + int focused_idx = index_child(container); + if (focused_idx == -1) { + return NULL; + } else { + int desired = (focused_idx + (dir == MOVE_NEXT ? 1 : -1)) % + parent->children->length; + if (desired < 0) { + desired += parent->children->length; + } + return parent->children->items[desired]; + } + } + + // If moving to an adjacent output we need a starting position (since this + // output might border to multiple outputs). + struct wlc_point abs_pos; + get_absolute_center_position(container, &abs_pos); + + if (container->type == C_VIEW && swayc_is_fullscreen(container)) { + sway_log(L_DEBUG, "Moving from fullscreen view, skipping to output"); + container = swayc_parent_by_type(container, C_OUTPUT); + get_absolute_center_position(container, &abs_pos); + swayc_t *output = swayc_adjacent_output(container, dir, &abs_pos, true); + return get_swayc_in_output_direction(output, dir); + } + + if (container->type == C_WORKSPACE && container->fullscreen) { + sway_log(L_DEBUG, "Moving to fullscreen view"); + return container->fullscreen; + } + + swayc_t *wrap_candidate = NULL; + while (true) { + // Test if we can even make a difference here + bool can_move = false; + int desired; + int idx = index_child(container); + if (parent->type == C_ROOT) { + swayc_t *output = swayc_adjacent_output(container, dir, &abs_pos, true); + if (!output || output == container) { + return wrap_candidate; + } + sway_log(L_DEBUG, "Moving between outputs"); + return get_swayc_in_output_direction(output, dir); + } else { + if (is_auto_layout(parent->layout)) { + bool is_major = parent->layout == L_AUTO_LEFT || parent->layout == L_AUTO_RIGHT + ? dir == MOVE_LEFT || dir == MOVE_RIGHT + : dir == MOVE_DOWN || dir == MOVE_UP; + size_t gidx = auto_group_index(parent, idx); + if (is_major) { + size_t desired_grp = gidx + (dir == MOVE_RIGHT || dir == MOVE_DOWN ? 1 : -1); + can_move = auto_group_bounds(parent, desired_grp, &desired, NULL); + } else { + desired = idx + (dir == MOVE_RIGHT || dir == MOVE_DOWN ? 1 : -1); + int start, end; + can_move = auto_group_bounds(parent, gidx, &start, &end) + && desired >= start && desired < end; + } + } else { + if (dir == MOVE_LEFT || dir == MOVE_RIGHT) { + if (parent->layout == L_HORIZ || parent->layout == L_TABBED) { + can_move = true; + desired = idx + (dir == MOVE_LEFT ? -1 : 1); + } + } else { + if (parent->layout == L_VERT || parent->layout == L_STACKED) { + can_move = true; + desired = idx + (dir == MOVE_UP ? -1 : 1); + } + } + } + } + + if (can_move) { + if (container->is_floating) { + if (desired < 0) { + wrap_candidate = parent->floating->items[parent->floating->length-1]; + } else if (desired >= parent->floating->length){ + wrap_candidate = parent->floating->items[0]; + } else { + wrap_candidate = parent->floating->items[desired]; + } + if (wrap_candidate) { + wlc_view_bring_to_front(wrap_candidate->handle); + } + return wrap_candidate; + } else if (desired < 0 || desired >= parent->children->length) { + can_move = false; + int len = parent->children->length; + if (!wrap_candidate && len > 1) { + if (desired < 0) { + wrap_candidate = parent->children->items[len-1]; + } else { + wrap_candidate = parent->children->items[0]; + } + if (config->force_focus_wrapping) { + return wrap_candidate; + } + } + } else { + sway_log(L_DEBUG, "%s cont %d-%p dir %i sibling %d: %p", __func__, + idx, container, dir, desired, parent->children->items[desired]); + return parent->children->items[desired]; + } + } + if (!can_move) { + container = parent; + parent = parent->parent; + if (!parent || container == limit) { + // wrapping is the last chance + return wrap_candidate; + } + } + } +} + +swayc_t *get_swayc_in_direction(swayc_t *container, enum movement_direction dir) { + return get_swayc_in_direction_under(container, dir, NULL); +} + +void recursive_resize(swayc_t *container, double amount, enum wlc_resize_edge edge) { + int i; + bool layout_match = true; + sway_log(L_DEBUG, "Resizing %p with amount: %f", container, amount); + if (edge == WLC_RESIZE_EDGE_LEFT || edge == WLC_RESIZE_EDGE_RIGHT) { + container->width += amount; + layout_match = container->layout == L_HORIZ; + } else if (edge == WLC_RESIZE_EDGE_TOP || edge == WLC_RESIZE_EDGE_BOTTOM) { + container->height += amount; + layout_match = container->layout == L_VERT; + } + if (container->type == C_VIEW) { + update_geometry(container); + return; + } + if (layout_match) { + for (i = 0; i < container->children->length; i++) { + recursive_resize(container->children->items[i], amount/container->children->length, edge); + } + } else { + for (i = 0; i < container->children->length; i++) { + recursive_resize(container->children->items[i], amount, edge); + } + } +} + +enum swayc_layouts default_layout(swayc_t *output) { + if (config->default_layout != L_NONE) { + return config->default_layout; + } else if (config->default_orientation != L_NONE) { + return config->default_orientation; + } else if (output->width >= output->height) { + return L_HORIZ; + } else { + return L_VERT; + } +} + +bool is_auto_layout(enum swayc_layouts layout) { + return (layout >= L_AUTO_FIRST) && (layout <= L_AUTO_LAST); +} + +/** + * Return the number of master elements in a container + */ +static inline size_t auto_master_count(const swayc_t *container) { + sway_assert(container->children->length >= 0, "Container %p has (negative) children %d", + container, container->children->length); + return MIN(container->nb_master, (size_t)container->children->length); +} + +/** + * Return the number of children in the slave groups. This corresponds to the children + * that are not members of the master group. + */ +static inline size_t auto_slave_count(const swayc_t *container) { + return container->children->length - auto_master_count(container); +} + +/** + * Return the number of slave groups in the container. + */ +size_t auto_slave_group_count(const swayc_t *container) { + return MIN(container->nb_slave_groups, auto_slave_count(container)); +} + +/** + * Return the combined number of master and slave groups in the container. + */ +size_t auto_group_count(const swayc_t *container) { + return auto_slave_group_count(container) + + (container->children->length && container->nb_master ? 1 : 0); +} + +/** + * given the index of a container's child, return the index of the first child of the group + * which index is a member of. + */ +int auto_group_start_index(const swayc_t *container, int index) { + if (index < 0 || ! is_auto_layout(container->layout) + || (size_t)index < container->nb_master) { + return 0; + } else { + size_t nb_slaves = auto_slave_count(container); + size_t nb_slave_grp = auto_slave_group_count(container); + size_t grp_sz = nb_slaves / nb_slave_grp; + size_t remainder = nb_slaves % nb_slave_grp; + int idx2 = (nb_slave_grp - remainder) * grp_sz + container->nb_master; + int start_idx; + if (index < idx2) { + start_idx = ((index - container->nb_master) / grp_sz) * grp_sz + container->nb_master; + } else { + start_idx = idx2 + ((index - idx2) / (grp_sz + 1)) * (grp_sz + 1); + } + return MIN(start_idx, container->children->length); + } +} + +/** + * given the index of a container's child, return the index of the first child of the group + * that follows the one which index is a member of. + * This makes the function usable to walk through the groups in a container. + */ +int auto_group_end_index(const swayc_t *container, int index) { + if (index < 0 || ! is_auto_layout(container->layout)) { + return container->children->length; + } else { + int nxt_idx; + if ((size_t)index < container->nb_master) { + nxt_idx = auto_master_count(container); + } else { + size_t nb_slaves = auto_slave_count(container); + size_t nb_slave_grp = auto_slave_group_count(container); + size_t grp_sz = nb_slaves / nb_slave_grp; + size_t remainder = nb_slaves % nb_slave_grp; + int idx2 = (nb_slave_grp - remainder) * grp_sz + container->nb_master; + if (index < idx2) { + nxt_idx = ((index - container->nb_master) / grp_sz + 1) * grp_sz + container->nb_master; + } else { + nxt_idx = idx2 + ((index - idx2) / (grp_sz + 1) + 1) * (grp_sz + 1); + } + } + return MIN(nxt_idx, container->children->length); + } +} + +/** + * return the index of the Group containing th child of . + * The index is the order of the group along the container's major axis (starting at 0). + */ +size_t auto_group_index(const swayc_t *container, int index) { + if (index < 0) { + return 0; + } + bool master_first = (container->layout == L_AUTO_LEFT || container->layout == L_AUTO_TOP); + size_t nb_slaves = auto_slave_count(container); + if ((size_t)index < container->nb_master) { + if (master_first || nb_slaves <= 0) { + return 0; + } else { + return auto_slave_group_count(container); + } + } else { + size_t nb_slave_grp = auto_slave_group_count(container); + size_t grp_sz = nb_slaves / nb_slave_grp; + size_t remainder = nb_slaves % nb_slave_grp; + int idx2 = (nb_slave_grp - remainder) * grp_sz + container->nb_master; + size_t grp_idx; + if (index < idx2) { + grp_idx = (index - container->nb_master) / grp_sz; + } else { + grp_idx = (nb_slave_grp - remainder) + (index - idx2) / (grp_sz + 1) ; + } + return grp_idx + (master_first && container-> nb_master ? 1 : 0); + } +} + +/** + * Return the first index (inclusive) and last index (exclusive) of the elements of a group in + * an auto layout. + * If the bounds of the given group can be calculated, they are returned in the start/end + * parameters (int pointers) and the return value will be true. + * The indexes are passed by reference and can be NULL. + */ +bool auto_group_bounds(const swayc_t *container, size_t group_index, int *start, int *end) { + size_t nb_grp = auto_group_count(container); + if (group_index >= nb_grp) { + return false; + } + bool master_first = (container->layout == L_AUTO_LEFT || container->layout == L_AUTO_TOP); + size_t nb_master = auto_master_count(container); + size_t nb_slave_grp = auto_slave_group_count(container); + int g_start, g_end; + if (nb_master && (master_first ? group_index == 0 : group_index == nb_grp - 1)) { + g_start = 0; + g_end = nb_master; + } else { + size_t nb_slaves = auto_slave_count(container); + size_t grp_sz = nb_slaves / nb_slave_grp; + size_t remainder = nb_slaves % nb_slave_grp; + size_t g0 = master_first && container->nb_master ? 1 : 0; + size_t g1 = g0 + nb_slave_grp - remainder; + if (group_index < g1) { + g_start = container->nb_master + (group_index - g0) * grp_sz; + g_end = g_start + grp_sz; + } else { + size_t g2 = group_index - g1; + g_start = container->nb_master + + (nb_slave_grp - remainder) * grp_sz + + g2 * (grp_sz + 1); + g_end = g_start + grp_sz + 1; + } + } + if (start) { + *start = g_start; + } + if (end) { + *end = g_end; + } + return true; +} diff --git a/sway/old/output.c b/sway/old/output.c new file mode 100644 index 00000000..edfcac98 --- /dev/null +++ b/sway/old/output.c @@ -0,0 +1,278 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include "sway/output.h" +#include "log.h" +#include "list.h" + +void output_get_scaled_size(wlc_handle handle, struct wlc_size *size) { + *size = *wlc_output_get_resolution(handle); + uint32_t scale = wlc_output_get_scale(handle); + size->w /= scale; + size->h /= scale; +} + +swayc_t *output_by_name(const char* name, const struct wlc_point *abs_pos) { + swayc_t *output = NULL; + // If there is no output directly next to the current one, use + // swayc_opposite_output to wrap. + if (strcasecmp(name, "left") == 0) { + output = swayc_adjacent_output(NULL, MOVE_LEFT, abs_pos, true); + if (!output) { + output = swayc_opposite_output(MOVE_RIGHT, abs_pos); + } + } else if (strcasecmp(name, "right") == 0) { + output = swayc_adjacent_output(NULL, MOVE_RIGHT, abs_pos, true); + if (!output) { + output = swayc_opposite_output(MOVE_LEFT, abs_pos); + } + } else if (strcasecmp(name, "up") == 0) { + output = swayc_adjacent_output(NULL, MOVE_UP, abs_pos, true); + if (!output) { + output = swayc_opposite_output(MOVE_DOWN, abs_pos); + } + } else if (strcasecmp(name, "down") == 0) { + output = swayc_adjacent_output(NULL, MOVE_DOWN, abs_pos, true); + if (!output) { + output = swayc_opposite_output(MOVE_UP, abs_pos); + } + } else { + for(int i = 0; i < root_container.children->length; ++i) { + swayc_t *c = root_container.children->items[i]; + if (c->type == C_OUTPUT && strcasecmp(c->name, name) == 0) { + return c; + } + } + } + return output; +} + +swayc_t *swayc_opposite_output(enum movement_direction dir, + const struct wlc_point *abs_pos) { + + // Search through all the outputs and pick the output whose edge covers the + // given position, and is at leftmost/rightmost/upmost/downmost side of the + // screen (decided by the direction given). + swayc_t *opposite = NULL; + char *dir_text = NULL; + switch(dir) { + case MOVE_LEFT: + case MOVE_RIGHT: ; + for (int i = 0; i < root_container.children->length; ++i) { + swayc_t *c = root_container.children->items[i]; + if (abs_pos->y >= c->y && abs_pos->y <= c->y + c->height) { + if (!opposite) { + opposite = c; + } else if ((dir == MOVE_LEFT && c->x < opposite->x) + || (dir == MOVE_RIGHT && c->x > opposite->x)) { + opposite = c; + } + } + } + dir_text = dir == MOVE_LEFT ? "leftmost" : "rightmost"; + break; + case MOVE_UP: + case MOVE_DOWN: ; + for (int i = 0; i < root_container.children->length; ++i) { + swayc_t *c = root_container.children->items[i]; + if (abs_pos->x >= c->x && abs_pos->x <= c->x + c->width) { + if (!opposite) { + opposite = c; + } else if ((dir == MOVE_UP && c->y < opposite->y) + || (dir == MOVE_DOWN && c->y > opposite->y)) { + opposite = c; + } + } + } + dir_text = dir == MOVE_UP ? "upmost" : "downmost"; + break; + default: + sway_abort("Function called with invalid argument."); + break; + } + if (opposite) { + sway_log(L_DEBUG, "%s (%.0fx%.0f+%.0f+%.0f) is %s from y-position %i", + opposite->name, opposite->width, opposite->height, opposite->x, opposite->y, + dir_text, abs_pos->y); + } + return opposite; +} + +// Position is where on the edge (as absolute position) the adjacent output should be searched for. +swayc_t *swayc_adjacent_output(swayc_t *output, enum movement_direction dir, + const struct wlc_point *abs_pos, bool pick_closest) { + + if (!output) { + output = swayc_active_output(); + } + // In order to find adjacent outputs we need to test that the outputs are + // aligned on one axis (decided by the direction given) and that the given + // position is within the edge of the adjacent output. If no such output + // exists we pick the adjacent output within the edge that is closest to + // the given position, if any. + swayc_t *adjacent = NULL; + char *dir_text = NULL; + switch(dir) { + case MOVE_LEFT: + case MOVE_RIGHT: ; + double delta_y = 0; + for(int i = 0; i < root_container.children->length; ++i) { + swayc_t *c = root_container.children->items[i]; + if (c == output || c->type != C_OUTPUT) { + continue; + } + bool x_aligned = dir == MOVE_LEFT ? + c->x + c->width == output->x : + c->x == output->x + output->width; + if (!x_aligned) { + continue; + } + if (abs_pos->y >= c->y && abs_pos->y <= c->y + c->height) { + delta_y = 0; + adjacent = c; + break; + } else if (pick_closest) { + // track closest adjacent output + double top_y = c->y, bottom_y = c->y + c->height; + if (top_y >= output->y && top_y <= output->y + output->height) { + double delta = top_y - abs_pos->y; + if (delta < 0) delta = -delta; + if (delta < delta_y || !adjacent) { + delta_y = delta; + adjacent = c; + } + } + // we check both points and pick the closest + if (bottom_y >= output->y && bottom_y <= output->y + output->height) { + double delta = bottom_y - abs_pos->y; + if (delta < 0) delta = -delta; + if (delta < delta_y || !adjacent) { + delta_y = delta; + adjacent = c; + } + } + } + } + dir_text = dir == MOVE_LEFT ? "left of" : "right of"; + if (adjacent && delta_y == 0) { + sway_log(L_DEBUG, "%s (%.0fx%.0f+%.0f+%.0f) is %s current output %s (y-position %i)", + adjacent->name, adjacent->width, adjacent->height, adjacent->x, adjacent->y, + dir_text, output->name, abs_pos->y); + } else if (adjacent) { + // so we end up picking the closest adjacent output because + // there is no directly adjacent to the given position + sway_log(L_DEBUG, "%s (%.0fx%.0f+%.0f+%.0f) is %s current output %s (y-position %i, delta: %.0f)", + adjacent->name, adjacent->width, adjacent->height, adjacent->x, adjacent->y, + dir_text, output->name, abs_pos->y, delta_y); + } + break; + case MOVE_UP: + case MOVE_DOWN: ; + double delta_x = 0; + for(int i = 0; i < root_container.children->length; ++i) { + swayc_t *c = root_container.children->items[i]; + if (c == output || c->type != C_OUTPUT) { + continue; + } + bool y_aligned = dir == MOVE_UP ? + c->y + c->height == output->y : + c->y == output->y + output->height; + if (!y_aligned) { + continue; + } + if (abs_pos->x >= c->x && abs_pos->x <= c->x + c->width) { + delta_x = 0; + adjacent = c; + break; + } else if (pick_closest) { + // track closest adjacent output + double left_x = c->x, right_x = c->x + c->width; + if (left_x >= output->x && left_x <= output->x + output->width) { + double delta = left_x - abs_pos->x; + if (delta < 0) delta = -delta; + if (delta < delta_x || !adjacent) { + delta_x = delta; + adjacent = c; + } + } + // we check both points and pick the closest + if (right_x >= output->x && right_x <= output->x + output->width) { + double delta = right_x - abs_pos->x; + if (delta < 0) delta = -delta; + if (delta < delta_x || !adjacent) { + delta_x = delta; + adjacent = c; + } + } + } + } + dir_text = dir == MOVE_UP ? "above" : "below"; + if (adjacent && delta_x == 0) { + sway_log(L_DEBUG, "%s (%.0fx%.0f+%.0f+%.0f) is %s current output %s (x-position %i)", + adjacent->name, adjacent->width, adjacent->height, adjacent->x, adjacent->y, + dir_text, output->name, abs_pos->x); + } else if (adjacent) { + // so we end up picking the closest adjacent output because + // there is no directly adjacent to the given position + sway_log(L_DEBUG, "%s (%.0fx%.0f+%.0f+%.0f) is %s current output %s (x-position %i, delta: %.0f)", + adjacent->name, adjacent->width, adjacent->height, adjacent->x, adjacent->y, + dir_text, output->name, abs_pos->x, delta_x); + } + break; + default: + sway_abort("Function called with invalid argument."); + break; + } + return adjacent; +} + +void get_absolute_position(swayc_t *container, struct wlc_point *point) { + if (!container || !point) + sway_abort("Need container and wlc_point (was %p, %p).", container, point); + + if (container->type == C_OUTPUT) { + // Coordinates are already absolute. + point->x = container->x; + point->y = container->y; + } else { + swayc_t *output = swayc_parent_by_type(container, C_OUTPUT); + if (container->type == C_WORKSPACE) { + // Workspace coordinates are actually wrong/arbitrary, but should + // be same as output. + point->x = output->x; + point->y = output->y; + } else { + point->x = output->x + container->x; + point->y = output->y + container->y; + } + } +} + +void get_absolute_center_position(swayc_t *container, struct wlc_point *point) { + get_absolute_position(container, point); + point->x += container->width/2; + point->y += container->height/2; +} + +static int sort_workspace_cmp_qsort(const void *_a, const void *_b) { + swayc_t *a = *(void **)_a; + swayc_t *b = *(void **)_b; + int retval = 0; + + if (isdigit(a->name[0]) && isdigit(b->name[0])) { + int a_num = strtol(a->name, NULL, 10); + int b_num = strtol(b->name, NULL, 10); + retval = (a_num < b_num) ? -1 : (a_num > b_num); + } else if (isdigit(a->name[0])) { + retval = -1; + } else if (isdigit(b->name[0])) { + retval = 1; + } + + return retval; +} + +void sort_workspaces(swayc_t *output) { + list_stable_sort(output->children, sort_workspace_cmp_qsort); +} diff --git a/sway/old/security.c b/sway/old/security.c new file mode 100644 index 00000000..fcd70f9d --- /dev/null +++ b/sway/old/security.c @@ -0,0 +1,228 @@ +#define _XOPEN_SOURCE 700 +#include +#include +#include +#include +#include +#include "sway/config.h" +#include "sway/security.h" +#include "log.h" + +static bool validate_ipc_target(const char *program) { + struct stat sb; + + sway_log(L_DEBUG, "Validating IPC target '%s'", program); + + if (!strcmp(program, "*")) { + return true; + } + if (lstat(program, &sb) == -1) { + return false; + } + if (!S_ISREG(sb.st_mode)) { + sway_log(L_ERROR, + "IPC target '%s' MUST be/point at an existing regular file", + program); + return false; + } + if (sb.st_uid != 0) { +#ifdef NDEBUG + sway_log(L_ERROR, "IPC target '%s' MUST be owned by root", program); + return false; +#else + sway_log(L_INFO, "IPC target '%s' MUST be owned by root (waived for debug build)", program); + return true; +#endif + } + if (sb.st_mode & S_IWOTH) { + sway_log(L_ERROR, "IPC target '%s' MUST NOT be world writable", program); + return false; + } + + return true; +} + +struct feature_policy *alloc_feature_policy(const char *program) { + uint32_t default_policy = 0; + + if (!validate_ipc_target(program)) { + return NULL; + } + for (int i = 0; i < config->feature_policies->length; ++i) { + struct feature_policy *policy = config->feature_policies->items[i]; + if (strcmp(policy->program, "*") == 0) { + default_policy = policy->features; + break; + } + } + + struct feature_policy *policy = malloc(sizeof(struct feature_policy)); + if (!policy) { + return NULL; + } + policy->program = strdup(program); + if (!policy->program) { + free(policy); + return NULL; + } + policy->features = default_policy; + + return policy; +} + +struct ipc_policy *alloc_ipc_policy(const char *program) { + uint32_t default_policy = 0; + + if (!validate_ipc_target(program)) { + return NULL; + } + for (int i = 0; i < config->ipc_policies->length; ++i) { + struct ipc_policy *policy = config->ipc_policies->items[i]; + if (strcmp(policy->program, "*") == 0) { + default_policy = policy->features; + break; + } + } + + struct ipc_policy *policy = malloc(sizeof(struct ipc_policy)); + if (!policy) { + return NULL; + } + policy->program = strdup(program); + if (!policy->program) { + free(policy); + return NULL; + } + policy->features = default_policy; + + return policy; +} + +struct command_policy *alloc_command_policy(const char *command) { + struct command_policy *policy = malloc(sizeof(struct command_policy)); + if (!policy) { + return NULL; + } + policy->command = strdup(command); + if (!policy->command) { + free(policy); + return NULL; + } + policy->context = 0; + return policy; +} + +static const char *get_pid_exe(pid_t pid) { +#ifdef __FreeBSD__ + const char *fmt = "/proc/%d/file"; +#else + const char *fmt = "/proc/%d/exe"; +#endif + int pathlen = snprintf(NULL, 0, fmt, pid); + char *path = malloc(pathlen + 1); + if (path) { + snprintf(path, pathlen + 1, fmt, pid); + } + + static char link[2048]; + + ssize_t len = !path ? -1 : readlink(path, link, sizeof(link)); + if (len < 0) { + sway_log(L_INFO, + "WARNING: unable to read %s for security check. Using default policy.", + path); + strcpy(link, "*"); + } else { + link[len] = '\0'; + } + free(path); + + return link; +} + +struct feature_policy *get_feature_policy(const char *name) { + struct feature_policy *policy = NULL; + + for (int i = 0; i < config->feature_policies->length; ++i) { + struct feature_policy *p = config->feature_policies->items[i]; + if (strcmp(p->program, name) == 0) { + policy = p; + break; + } + } + if (!policy) { + policy = alloc_feature_policy(name); + sway_assert(policy, "Unable to allocate security policy"); + if (policy) { + list_add(config->feature_policies, policy); + } + } + return policy; +} + +uint32_t get_feature_policy_mask(pid_t pid) { + uint32_t default_policy = 0; + const char *link = get_pid_exe(pid); + + for (int i = 0; i < config->feature_policies->length; ++i) { + struct feature_policy *policy = config->feature_policies->items[i]; + if (strcmp(policy->program, "*") == 0) { + default_policy = policy->features; + } + if (strcmp(policy->program, link) == 0) { + return policy->features; + } + } + + return default_policy; +} + +uint32_t get_ipc_policy_mask(pid_t pid) { + uint32_t default_policy = 0; + const char *link = get_pid_exe(pid); + + for (int i = 0; i < config->ipc_policies->length; ++i) { + struct ipc_policy *policy = config->ipc_policies->items[i]; + if (strcmp(policy->program, "*") == 0) { + default_policy = policy->features; + } + if (strcmp(policy->program, link) == 0) { + return policy->features; + } + } + + return default_policy; +} + +uint32_t get_command_policy_mask(const char *cmd) { + uint32_t default_policy = 0; + + for (int i = 0; i < config->command_policies->length; ++i) { + struct command_policy *policy = config->command_policies->items[i]; + if (strcmp(policy->command, "*") == 0) { + default_policy = policy->context; + } + if (strcmp(policy->command, cmd) == 0) { + return policy->context; + } + } + + return default_policy; +} + +const char *command_policy_str(enum command_context context) { + switch (context) { + case CONTEXT_ALL: + return "all"; + case CONTEXT_CONFIG: + return "config"; + case CONTEXT_BINDING: + return "binding"; + case CONTEXT_IPC: + return "IPC"; + case CONTEXT_CRITERIA: + return "criteria"; + default: + return "unknown"; + } +} diff --git a/sway/old/workspace.c b/sway/old/workspace.c new file mode 100644 index 00000000..14cde146 --- /dev/null +++ b/sway/old/workspace.c @@ -0,0 +1,373 @@ +#define _XOPEN_SOURCE 500 +#include +#include +#include +#include +#include +#include +#include +#include +#include "sway/ipc-server.h" +#include "sway/workspace.h" +#include "sway/layout.h" +#include "sway/container.h" +#include "sway/handlers.h" +#include "sway/config.h" +#include "sway/focus.h" +#include "stringop.h" +#include "util.h" +#include "list.h" +#include "log.h" +#include "ipc.h" + +char *prev_workspace_name = NULL; +struct workspace_by_number_data { + int len; + const char *cset; + const char *name; +}; + +static bool workspace_valid_on_output(const char *output_name, const char *ws_name) { + int i; + for (i = 0; i < config->workspace_outputs->length; ++i) { + struct workspace_output *wso = config->workspace_outputs->items[i]; + if (strcasecmp(wso->workspace, ws_name) == 0) { + if (strcasecmp(wso->output, output_name) != 0) { + return false; + } + } + } + + return true; +} + +char *workspace_next_name(const char *output_name) { + sway_log(L_DEBUG, "Workspace: Generating new workspace name for output %s", output_name); + int i; + int l = 1; + // Scan all workspace bindings to find the next available workspace name, + // if none are found/available then default to a number + struct sway_mode *mode = config->current_mode; + + int order = INT_MAX; + char *target = NULL; + for (i = 0; i < mode->bindings->length; ++i) { + struct sway_binding *binding = mode->bindings->items[i]; + char *cmdlist = strdup(binding->command); + char *dup = cmdlist; + char *name = NULL; + + // workspace n + char *cmd = argsep(&cmdlist, " "); + if (cmdlist) { + name = argsep(&cmdlist, ",;"); + } + + if (strcmp("workspace", cmd) == 0 && name) { + sway_log(L_DEBUG, "Got valid workspace command for target: '%s'", name); + char *_target = strdup(name); + strip_quotes(_target); + while (isspace(*_target)) + _target++; + + // Make sure that the command references an actual workspace + // not a command about workspaces + if (strcmp(_target, "next") == 0 || + strcmp(_target, "prev") == 0 || + strcmp(_target, "next_on_output") == 0 || + strcmp(_target, "prev_on_output") == 0 || + strcmp(_target, "number") == 0 || + strcmp(_target, "back_and_forth") == 0 || + strcmp(_target, "current") == 0) + { + free(_target); + free(dup); + continue; + } + + // Make sure that the workspace doesn't already exist + if (workspace_by_name(_target)) { + free(_target); + free(dup); + continue; + } + + // make sure that the workspace can appear on the given + // output + if (!workspace_valid_on_output(output_name, _target)) { + free(_target); + free(dup); + continue; + } + + if (binding->order < order) { + order = binding->order; + free(target); + target = _target; + sway_log(L_DEBUG, "Workspace: Found free name %s", _target); + } + } + free(dup); + } + if (target != NULL) { + return target; + } + // As a fall back, get the current number of active workspaces + // and return that + 1 for the next workspace's name + int ws_num = root_container.children->length; + if (ws_num >= 10) { + l = 2; + } else if (ws_num >= 100) { + l = 3; + } + char *name = malloc(l + 1); + if (!name) { + sway_log(L_ERROR, "Could not allocate workspace name"); + return NULL; + } + sprintf(name, "%d", ws_num++); + return name; +} + +swayc_t *workspace_create(const char* name) { + swayc_t *parent; + // Search for workspace<->output pair + int i, e = config->workspace_outputs->length; + for (i = 0; i < e; ++i) { + struct workspace_output *wso = config->workspace_outputs->items[i]; + if (strcasecmp(wso->workspace, name) == 0) + { + // Find output to use if it exists + e = root_container.children->length; + for (i = 0; i < e; ++i) { + parent = root_container.children->items[i]; + if (strcmp(parent->name, wso->output) == 0) { + return new_workspace(parent, name); + } + } + break; + } + } + // Otherwise create a new one + parent = get_focused_container(&root_container); + parent = swayc_parent_by_type(parent, C_OUTPUT); + return new_workspace(parent, name); +} + +static bool _workspace_by_name(swayc_t *view, void *data) { + return (view->type == C_WORKSPACE) && + (strcasecmp(view->name, (char *) data) == 0); +} + +swayc_t *workspace_by_name(const char* name) { + if (strcmp(name, "prev") == 0) { + return workspace_prev(); + } + else if (strcmp(name, "prev_on_output") == 0) { + return workspace_output_prev(); + } + else if (strcmp(name, "next") == 0) { + return workspace_next(); + } + else if (strcmp(name, "next_on_output") == 0) { + return workspace_output_next(); + } + else if (strcmp(name, "current") == 0) { + return swayc_active_workspace(); + } + else { + return swayc_by_test(&root_container, _workspace_by_name, (void *) name); + } +} + +static bool _workspace_by_number(swayc_t *view, void *data) { + if (view->type != C_WORKSPACE) { + return false; + } + struct workspace_by_number_data *wbnd = data; + int a = strspn(view->name, wbnd->cset); + return a == wbnd->len && strncmp(view->name, wbnd->name, a) == 0; +} +swayc_t *workspace_by_number(const char* name) { + struct workspace_by_number_data wbnd = {0, "1234567890", name}; + wbnd.len = strspn(name, wbnd.cset); + if (wbnd.len <= 0) { + return NULL; + } + return swayc_by_test(&root_container, _workspace_by_number, (void *) &wbnd); +} + +/** + * Get the previous or next workspace on the specified output. + * Wraps around at the end and beginning. + * If next is false, the previous workspace is returned, otherwise the next one is returned. + */ +swayc_t *workspace_output_prev_next_impl(swayc_t *output, bool next) { + if (!sway_assert(output->type == C_OUTPUT, "Argument must be an output, is %d", output->type)) { + return NULL; + } + + int i; + for (i = 0; i < output->children->length; i++) { + if (output->children->items[i] == output->focused) { + return output->children->items[wrap(i + (next ? 1 : -1), output->children->length)]; + } + } + + // Doesn't happen, at worst the for loop returns the previously active workspace + return NULL; +} + +/** + * Get the previous or next workspace. If the first/last workspace on an output is active, + * proceed to the previous/next output's previous/next workspace. + * If next is false, the previous workspace is returned, otherwise the next one is returned. + */ +swayc_t *workspace_prev_next_impl(swayc_t *workspace, bool next) { + if (!sway_assert(workspace->type == C_WORKSPACE, "Argument must be a workspace, is %d", workspace->type)) { + return NULL; + } + + swayc_t *current_output = workspace->parent; + int offset = next ? 1 : -1; + int start = next ? 0 : 1; + int end = next ? (current_output->children->length) - 1 : current_output->children->length; + int i; + for (i = start; i < end; i++) { + if (current_output->children->items[i] == workspace) { + return current_output->children->items[i + offset]; + } + } + + // Given workspace is the first/last on the output, jump to the previous/next output + int num_outputs = root_container.children->length; + for (i = 0; i < num_outputs; i++) { + if (root_container.children->items[i] == current_output) { + swayc_t *next_output = root_container.children->items[wrap(i + offset, num_outputs)]; + return workspace_output_prev_next_impl(next_output, next); + } + } + + // Doesn't happen, at worst the for loop returns the previously active workspace on the active output + return NULL; +} + +swayc_t *workspace_output_next() { + return workspace_output_prev_next_impl(swayc_active_output(), true); +} + +swayc_t *workspace_next() { + return workspace_prev_next_impl(swayc_active_workspace(), true); +} + +swayc_t *workspace_output_prev() { + return workspace_output_prev_next_impl(swayc_active_output(), false); +} + +swayc_t *workspace_prev() { + return workspace_prev_next_impl(swayc_active_workspace(), false); +} + +bool workspace_switch(swayc_t *workspace) { + if (!workspace) { + return false; + } + swayc_t *active_ws = swayc_active_workspace(); + if (config->auto_back_and_forth && active_ws == workspace && prev_workspace_name) { + swayc_t *new_ws = workspace_by_name(prev_workspace_name); + workspace = new_ws ? new_ws : workspace_create(prev_workspace_name); + } + + if (!prev_workspace_name + || (strcmp(prev_workspace_name, active_ws->name) + && active_ws != workspace)) { + free(prev_workspace_name); + prev_workspace_name = malloc(strlen(active_ws->name) + 1); + if (!prev_workspace_name) { + sway_log(L_ERROR, "Unable to allocate previous workspace name"); + return false; + } + strcpy(prev_workspace_name, active_ws->name); + } + + // move sticky containers + if (swayc_parent_by_type(active_ws, C_OUTPUT) == swayc_parent_by_type(workspace, C_OUTPUT)) { + // don't change list while traversing it, use intermediate list instead + list_t *stickies = create_list(); + for (int i = 0; i < active_ws->floating->length; i++) { + swayc_t *cont = active_ws->floating->items[i]; + if (cont->sticky) { + list_add(stickies, cont); + } + } + for (int i = 0; i < stickies->length; i++) { + swayc_t *cont = stickies->items[i]; + sway_log(L_DEBUG, "Moving sticky container %p to %p:%s", + cont, workspace, workspace->name); + swayc_t *parent = remove_child(cont); + add_floating(workspace, cont); + // Destroy old container if we need to + destroy_container(parent); + } + list_free(stickies); + } + sway_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name); + if (!set_focused_container(get_focused_view(workspace))) { + return false; + } + swayc_t *output = swayc_parent_by_type(workspace, C_OUTPUT); + arrange_backgrounds(); + arrange_windows(output, -1, -1); + return true; +} + +swayc_t *workspace_for_pid(pid_t pid) { + int i; + swayc_t *ws = NULL; + struct pid_workspace *pw = NULL; + + sway_log(L_DEBUG, "looking for workspace for pid %d", pid); + + // leaving this here as it's useful for debugging + // sway_log(L_DEBUG, "all pid_workspaces"); + // for (int k = 0; k < config->pid_workspaces->length; k++) { + // pw = config->pid_workspaces->items[k]; + // sway_log(L_DEBUG, "pid %d workspace %s time_added %li", *pw->pid, pw->workspace, *pw->time_added); + // } + + do { + for (i = 0; i < config->pid_workspaces->length; i++) { + pw = config->pid_workspaces->items[i]; + pid_t *pw_pid = pw->pid; + + if (pid == *pw_pid) { + sway_log(L_DEBUG, "found pid_workspace for pid %d, workspace %s", pid, pw->workspace); + break; // out of for loop + } + + pw = NULL; + } + + if (pw) { + break; // out of do-while loop + } + + pid = get_parent_pid(pid); + // no sense in looking for matches for pid 0. + // also, if pid == getpid(), that is the compositor's + // pid, which definitely isn't helpful + } while (pid > 0 && pid != getpid()); + + if (pw) { + ws = workspace_by_name(pw->workspace); + + if (!ws) { + sway_log(L_DEBUG, "Creating workspace %s for pid %d because it disappeared", pw->workspace, pid); + ws = workspace_create(pw->workspace); + } + + list_del(config->pid_workspaces, i); + } + + return ws; +} diff --git a/sway/security.c b/sway/security.c deleted file mode 100644 index fcd70f9d..00000000 --- a/sway/security.c +++ /dev/null @@ -1,228 +0,0 @@ -#define _XOPEN_SOURCE 700 -#include -#include -#include -#include -#include -#include "sway/config.h" -#include "sway/security.h" -#include "log.h" - -static bool validate_ipc_target(const char *program) { - struct stat sb; - - sway_log(L_DEBUG, "Validating IPC target '%s'", program); - - if (!strcmp(program, "*")) { - return true; - } - if (lstat(program, &sb) == -1) { - return false; - } - if (!S_ISREG(sb.st_mode)) { - sway_log(L_ERROR, - "IPC target '%s' MUST be/point at an existing regular file", - program); - return false; - } - if (sb.st_uid != 0) { -#ifdef NDEBUG - sway_log(L_ERROR, "IPC target '%s' MUST be owned by root", program); - return false; -#else - sway_log(L_INFO, "IPC target '%s' MUST be owned by root (waived for debug build)", program); - return true; -#endif - } - if (sb.st_mode & S_IWOTH) { - sway_log(L_ERROR, "IPC target '%s' MUST NOT be world writable", program); - return false; - } - - return true; -} - -struct feature_policy *alloc_feature_policy(const char *program) { - uint32_t default_policy = 0; - - if (!validate_ipc_target(program)) { - return NULL; - } - for (int i = 0; i < config->feature_policies->length; ++i) { - struct feature_policy *policy = config->feature_policies->items[i]; - if (strcmp(policy->program, "*") == 0) { - default_policy = policy->features; - break; - } - } - - struct feature_policy *policy = malloc(sizeof(struct feature_policy)); - if (!policy) { - return NULL; - } - policy->program = strdup(program); - if (!policy->program) { - free(policy); - return NULL; - } - policy->features = default_policy; - - return policy; -} - -struct ipc_policy *alloc_ipc_policy(const char *program) { - uint32_t default_policy = 0; - - if (!validate_ipc_target(program)) { - return NULL; - } - for (int i = 0; i < config->ipc_policies->length; ++i) { - struct ipc_policy *policy = config->ipc_policies->items[i]; - if (strcmp(policy->program, "*") == 0) { - default_policy = policy->features; - break; - } - } - - struct ipc_policy *policy = malloc(sizeof(struct ipc_policy)); - if (!policy) { - return NULL; - } - policy->program = strdup(program); - if (!policy->program) { - free(policy); - return NULL; - } - policy->features = default_policy; - - return policy; -} - -struct command_policy *alloc_command_policy(const char *command) { - struct command_policy *policy = malloc(sizeof(struct command_policy)); - if (!policy) { - return NULL; - } - policy->command = strdup(command); - if (!policy->command) { - free(policy); - return NULL; - } - policy->context = 0; - return policy; -} - -static const char *get_pid_exe(pid_t pid) { -#ifdef __FreeBSD__ - const char *fmt = "/proc/%d/file"; -#else - const char *fmt = "/proc/%d/exe"; -#endif - int pathlen = snprintf(NULL, 0, fmt, pid); - char *path = malloc(pathlen + 1); - if (path) { - snprintf(path, pathlen + 1, fmt, pid); - } - - static char link[2048]; - - ssize_t len = !path ? -1 : readlink(path, link, sizeof(link)); - if (len < 0) { - sway_log(L_INFO, - "WARNING: unable to read %s for security check. Using default policy.", - path); - strcpy(link, "*"); - } else { - link[len] = '\0'; - } - free(path); - - return link; -} - -struct feature_policy *get_feature_policy(const char *name) { - struct feature_policy *policy = NULL; - - for (int i = 0; i < config->feature_policies->length; ++i) { - struct feature_policy *p = config->feature_policies->items[i]; - if (strcmp(p->program, name) == 0) { - policy = p; - break; - } - } - if (!policy) { - policy = alloc_feature_policy(name); - sway_assert(policy, "Unable to allocate security policy"); - if (policy) { - list_add(config->feature_policies, policy); - } - } - return policy; -} - -uint32_t get_feature_policy_mask(pid_t pid) { - uint32_t default_policy = 0; - const char *link = get_pid_exe(pid); - - for (int i = 0; i < config->feature_policies->length; ++i) { - struct feature_policy *policy = config->feature_policies->items[i]; - if (strcmp(policy->program, "*") == 0) { - default_policy = policy->features; - } - if (strcmp(policy->program, link) == 0) { - return policy->features; - } - } - - return default_policy; -} - -uint32_t get_ipc_policy_mask(pid_t pid) { - uint32_t default_policy = 0; - const char *link = get_pid_exe(pid); - - for (int i = 0; i < config->ipc_policies->length; ++i) { - struct ipc_policy *policy = config->ipc_policies->items[i]; - if (strcmp(policy->program, "*") == 0) { - default_policy = policy->features; - } - if (strcmp(policy->program, link) == 0) { - return policy->features; - } - } - - return default_policy; -} - -uint32_t get_command_policy_mask(const char *cmd) { - uint32_t default_policy = 0; - - for (int i = 0; i < config->command_policies->length; ++i) { - struct command_policy *policy = config->command_policies->items[i]; - if (strcmp(policy->command, "*") == 0) { - default_policy = policy->context; - } - if (strcmp(policy->command, cmd) == 0) { - return policy->context; - } - } - - return default_policy; -} - -const char *command_policy_str(enum command_context context) { - switch (context) { - case CONTEXT_ALL: - return "all"; - case CONTEXT_CONFIG: - return "config"; - case CONTEXT_BINDING: - return "binding"; - case CONTEXT_IPC: - return "IPC"; - case CONTEXT_CRITERIA: - return "criteria"; - default: - return "unknown"; - } -} diff --git a/sway/server.c b/sway/server.c index 940f28b3..8892b917 100644 --- a/sway/server.c +++ b/sway/server.c @@ -10,7 +10,6 @@ // TODO WLR: make Xwayland optional #include #include "sway/server.h" -#include "sway/input.h" #include "log.h" bool server_init(struct sway_server *server) { @@ -23,7 +22,6 @@ bool server_init(struct sway_server *server) { server->renderer = wlr_gles2_renderer_create(server->backend); wl_display_init_shm(server->wl_display); - server->input = sway_input_create(server); server->data_device_manager = wlr_data_device_manager_create(server->wl_display); diff --git a/sway/tree/container.c b/sway/tree/container.c deleted file mode 100644 index 82c0d877..00000000 --- a/sway/tree/container.c +++ /dev/null @@ -1,1024 +0,0 @@ -#define _XOPEN_SOURCE 500 -#include -#include -#include -#include -#include -#include -#include -#include "sway/config.h" -#include "sway/container.h" -#include "sway/workspace.h" -#include "sway/focus.h" -#include "sway/border.h" -#include "sway/layout.h" -#include "sway/input_state.h" -#include "sway/ipc-server.h" -#include "sway/output.h" -#include "sway/view.h" -#include "log.h" -#include "stringop.h" - -#define ASSERT_NONNULL(PTR) \ - sway_assert (PTR, #PTR "must be non-null") - -static swayc_t *new_swayc(enum swayc_types type) { - // next id starts at 1 because 0 is assigned to root_container in layout.c - static size_t next_id = 1; - swayc_t *c = calloc(1, sizeof(swayc_t)); - if (!c) { - return NULL; - } - c->id = next_id++; - c->handle = -1; - c->gaps = -1; - c->layout = L_NONE; - c->workspace_layout = L_NONE; - c->type = type; - c->nb_master = 1; - c->nb_slave_groups = 1; - if (type != C_VIEW) { - c->children = create_list(); - } - return c; -} - -static void free_swayc(swayc_t *cont) { - if (!ASSERT_NONNULL(cont)) { - return; - } - if (cont->children) { - // remove children until there are no more, free_swayc calls - // remove_child, which removes child from this container - while (cont->children->length) { - free_swayc(cont->children->items[0]); - } - list_free(cont->children); - } - if (cont->unmanaged) { - list_free(cont->unmanaged); - } - if (cont->floating) { - while (cont->floating->length) { - free_swayc(cont->floating->items[0]); - } - list_free(cont->floating); - } - if (cont->marks) { - list_foreach(cont->marks, free); - list_free(cont->marks); - } - if (cont->parent) { - remove_child(cont); - } - if (cont->name) { - free(cont->name); - } - if (cont->class) { - free(cont->class); - } - if (cont->instance) { - free(cont->instance); - } - if (cont->app_id) { - free(cont->app_id); - } - if (cont->bg_pid != 0) { - terminate_swaybg(cont->bg_pid); - } - if (cont->border) { - if (cont->border->buffer) { - free(cont->border->buffer); - } - free(cont->border); - } - free(cont); -} - -static void update_root_geometry() { - int width = 0; - int height = 0; - swayc_t *child; - int child_width; - int child_height; - - for (int i = 0; i < root_container.children->length; ++i) { - child = root_container.children->items[i]; - child_width = child->width + child->x; - child_height = child->height + child->y; - if (child_width > width) { - width = child_width; - } - - if (child_height > height) { - height = child_height; - } - } - - root_container.width = width; - root_container.height = height; -} - -// New containers - -swayc_t *new_output(struct sway_output *sway_output) { - struct wlr_box size; - wlr_output_effective_resolution(sway_output->wlr_output, - &size.width, &size.height); - const char *name = sway_output->wlr_output->name; - // Find current outputs to see if this already exists - { - int i, len = root_container.children->length; - for (i = 0; i < len; ++i) { - swayc_t *op = root_container.children->items[i]; - const char *op_name = op->name; - if (op_name && name && strcmp(op_name, name) == 0) { - sway_log(L_DEBUG, "restoring output %p: %s", - sway_output, op_name); - return op; - } - } - } - - struct output_config *oc = NULL, *all = NULL; - int i; - for (i = 0; i < config->output_configs->length; ++i) { - struct output_config *cur = config->output_configs->items[i]; - if (strcasecmp(name, cur->name) == 0) { - sway_log(L_DEBUG, "Matched output config for %s", name); - oc = cur; - } - if (strcasecmp("*", cur->name) == 0) { - sway_log(L_DEBUG, "Matched wildcard output config for %s", name); - all = cur; - } - - if (oc && all) { - break; - } - } - - if (!oc) { - oc = all; - } - - if (oc && !oc->enabled) { - return NULL; - } - - swayc_t *output = new_swayc(C_OUTPUT); - output->_handle.output = sway_output; - output->name = name ? strdup(name) : NULL; - output->width = size.width; - output->height = size.width; - output->unmanaged = create_list(); - output->bg_pid = 0; - - apply_output_config(oc, output); - add_child(&root_container, output); - load_swaybars(); - - // Create workspace - char *ws_name = NULL; - swayc_t *ws = NULL; - - if (name) { - for (i = 0; i < config->workspace_outputs->length; ++i) { - struct workspace_output *wso = config->workspace_outputs->items[i]; - if (strcasecmp(wso->output, name) == 0) { - sway_log(L_DEBUG, "Matched workspace to output: %s for %s", wso->workspace, wso->output); - // Check if any other workspaces are using this name - if ((ws = workspace_by_name(wso->workspace))) { - // if yes, move those to this output, because they should be here - move_workspace_to(ws, output); - } else if (!ws_name) { - // set a workspace name in case we need to create a default one - ws_name = strdup(wso->workspace); - } - } - } - } - - if (output->children->length == 0) { - if (!ws_name) { - ws_name = workspace_next_name(output->name); - } - // create and initialize default workspace - sway_log(L_DEBUG, "Creating default workspace %s", ws_name); - ws = new_workspace(output, ws_name); - ws->is_focused = true; - } else { - sort_workspaces(output); - set_focused_container(output->children->items[0]); - } - - free(ws_name); - update_root_geometry(); - return output; -} - -swayc_t *new_workspace(swayc_t *output, const char *name) { - if (!ASSERT_NONNULL(output)) { - return NULL; - } - sway_log(L_DEBUG, "Added workspace %s for output %u", name, (unsigned int)output->handle); - swayc_t *workspace = new_swayc(C_WORKSPACE); - - workspace->prev_layout = L_NONE; - workspace->layout = default_layout(output); - workspace->workspace_layout = default_layout(output); - - workspace->x = output->x; - workspace->y = output->y; - workspace->width = output->width; - workspace->height = output->height; - workspace->name = !name ? NULL : strdup(name); - workspace->visible = false; - workspace->floating = create_list(); - - add_child(output, workspace); - sort_workspaces(output); - - return workspace; -} - -swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) { - if (!ASSERT_NONNULL(child) - && !sway_assert(!child->is_floating, "cannot create container around floating window")) { - return NULL; - } - swayc_t *cont = new_swayc(C_CONTAINER); - - sway_log(L_DEBUG, "creating container %p around %p", cont, child); - - cont->prev_layout = L_NONE; - cont->layout = layout; - cont->width = child->width; - cont->height = child->height; - cont->x = child->x; - cont->y = child->y; - cont->visible = child->visible; - cont->cached_geometry = child->cached_geometry; - cont->gaps = child->gaps; - - /* Container inherits all of workspaces children, layout and whatnot */ - if (child->type == C_WORKSPACE) { - swayc_t *workspace = child; - // reorder focus - cont->focused = workspace->focused; - workspace->focused = cont; - // set all children focu to container - int i; - for (i = 0; i < workspace->children->length; ++i) { - ((swayc_t *)workspace->children->items[i])->parent = cont; - } - // Swap children - list_t *tmp_list = workspace->children; - workspace->children = cont->children; - cont->children = tmp_list; - // add container to workspace chidren - add_child(workspace, cont); - // give them proper layouts - cont->layout = workspace->workspace_layout; - cont->prev_layout = workspace->prev_layout; - /* TODO: might break shit in move_container!!! workspace->layout = layout; */ - set_focused_container_for(workspace, get_focused_view(workspace)); - } else { // Or is built around container - swayc_t *parent = replace_child(child, cont); - if (parent) { - add_child(cont, child); - } - } - return cont; -} - -swayc_t *new_view(swayc_t *sibling, struct sway_view *view) { - if (!ASSERT_NONNULL(sibling)) { - return NULL; - } - const char *title = view->iface.get_prop(view, VIEW_PROP_TITLE); - swayc_t *swayc = new_swayc(C_VIEW); - sway_log(L_DEBUG, "Adding new view %p:%s to container %p %d", - swayc, title, sibling, sibling ? sibling->type : 0); - // Setup values - swayc->_handle.view = view; - - swayc->name = title ? strdup(title) : NULL; - - const char *class = view->iface.get_prop(view, VIEW_PROP_CLASS); - swayc->class = class ? strdup(class) : NULL; - - const char *instance = view->iface.get_prop(view, VIEW_PROP_INSTANCE); - swayc->instance = instance ? strdup(instance) : NULL; - - const char *app_id = view->iface.get_prop(view, VIEW_PROP_APP_ID); - swayc->app_id = app_id ? strdup(app_id) : NULL; - - swayc->visible = true; - swayc->is_focused = true; - swayc->sticky = false; - swayc->width = 0; - swayc->height = 0; - swayc->desired_width = -1; - swayc->desired_height = -1; - // setup border - swayc->border_type = config->border; - swayc->border_thickness = config->border_thickness; - - swayc->is_floating = false; - - if (sibling->type == C_WORKSPACE) { - // Case of focused workspace, just create as child of it - add_child(sibling, swayc); - } else { - // Regular case, create as sibling of current container - add_sibling(sibling, swayc); - } - return swayc; -} - -swayc_t *new_floating_view(wlc_handle handle) { - if (swayc_active_workspace() == NULL) { - return NULL; - } - const char *title = wlc_view_get_title(handle); - swayc_t *view = new_swayc(C_VIEW); - sway_log(L_DEBUG, "Adding new view %" PRIuPTR ":%x:%s as a floating view", - handle, wlc_view_get_type(handle), title); - // Setup values - view->handle = handle; - view->name = title ? strdup(title) : NULL; - const char *class = wlc_view_get_class(handle); - view->class = class ? strdup(class) : NULL; - const char *instance = wlc_view_get_instance(handle); - view->instance = instance ? strdup(instance) : NULL; - const char *app_id = wlc_view_get_app_id(handle); - view->app_id = app_id ? strdup(app_id) : NULL; - view->visible = true; - view->sticky = false; - - // Set the geometry of the floating view - const struct wlc_geometry *geometry = wlc_view_get_geometry(handle); - - // give it requested geometry, but place in center if possible - // in top left otherwise - if (geometry->size.w != 0) { - view->x = (swayc_active_workspace()->width - geometry->size.w) / 2; - } else { - view->x = 0; - } - if (geometry->size.h != 0) { - view->y = (swayc_active_workspace()->height - geometry->size.h) / 2; - } else { - view->y = 0; - } - - view->width = geometry->size.w; - view->height = geometry->size.h; - - view->desired_width = view->width; - view->desired_height = view->height; - - // setup border - view->border_type = config->floating_border; - view->border_thickness = config->floating_border_thickness; - - view->is_floating = true; - - // Case of focused workspace, just create as child of it - list_add(swayc_active_workspace()->floating, view); - view->parent = swayc_active_workspace(); - if (swayc_active_workspace()->focused == NULL) { - set_focused_container_for(swayc_active_workspace(), view); - } - return view; -} - -void floating_view_sane_size(swayc_t *view) { - // floating_minimum is used as sane value. - // floating_maximum has priority in case of conflict - // TODO: implement total_outputs_dimensions() - if (config->floating_minimum_height != -1 && - view->desired_height < config->floating_minimum_height) { - view->desired_height = config->floating_minimum_height; - } - if (config->floating_minimum_width != -1 && - view->desired_width < config->floating_minimum_width) { - view->desired_width = config->floating_minimum_width; - } - - // if 0 do not resize, only enforce max value - if (config->floating_maximum_height == 0) { - // Missing total_outputs_dimensions() using swayc_active_workspace() - config->floating_maximum_height = swayc_active_workspace()->height; - - } else if (config->floating_maximum_height != -1 && - view->desired_height > config->floating_maximum_height) { - view->desired_height = config->floating_maximum_height; - } - - // if 0 do not resize, only enforce max value - if (config->floating_maximum_width == 0) { - // Missing total_outputs_dimensions() using swayc_active_workspace() - config->floating_maximum_width = swayc_active_workspace()->width; - - } else if (config->floating_maximum_width != -1 && - view->desired_width > config->floating_maximum_width) { - view->desired_width = config->floating_maximum_width; - } - - sway_log(L_DEBUG, "Sane values for view to %d x %d @ %.f, %.f", - view->desired_width, view->desired_height, view->x, view->y); - - return; -} - - -// Destroy container - -swayc_t *destroy_output(swayc_t *output) { - if (!ASSERT_NONNULL(output)) { - return NULL; - } - if (output->children->length > 0) { - // TODO save workspaces when there are no outputs. - // TODO also check if there will ever be no outputs except for exiting - // program - if (root_container.children->length > 1) { - int p = root_container.children->items[0] == output; - // Move workspace from this output to another output - while (output->children->length) { - swayc_t *child = output->children->items[0]; - remove_child(child); - add_child(root_container.children->items[p], child); - } - sort_workspaces(root_container.children->items[p]); - update_visibility(root_container.children->items[p]); - arrange_windows(root_container.children->items[p], -1, -1); - } - } - sway_log(L_DEBUG, "OUTPUT: Destroying output '%" PRIuPTR "'", output->handle); - free_swayc(output); - update_root_geometry(); - return &root_container; -} - -swayc_t *destroy_workspace(swayc_t *workspace) { - if (!ASSERT_NONNULL(workspace)) { - return NULL; - } - - // Do not destroy this if it's the last workspace on this output - swayc_t *output = swayc_parent_by_type(workspace, C_OUTPUT); - if (output && output->children->length == 1) { - return NULL; - } - - swayc_t *parent = workspace->parent; - // destroy the WS if there are no children - if (workspace->children->length == 0 && workspace->floating->length == 0) { - sway_log(L_DEBUG, "destroying workspace '%s'", workspace->name); - ipc_event_workspace(workspace, NULL, "empty"); - } else { - // Move children to a different workspace on this output - swayc_t *new_workspace = NULL; - int i; - for(i = 0; i < output->children->length; i++) { - if(output->children->items[i] != workspace) { - break; - } - } - new_workspace = output->children->items[i]; - - sway_log(L_DEBUG, "moving children to different workspace '%s' -> '%s'", - workspace->name, new_workspace->name); - - for(i = 0; i < workspace->children->length; i++) { - move_container_to(workspace->children->items[i], new_workspace); - } - - for(i = 0; i < workspace->floating->length; i++) { - move_container_to(workspace->floating->items[i], new_workspace); - } - } - - free_swayc(workspace); - return parent; -} - -swayc_t *destroy_container(swayc_t *container) { - if (!ASSERT_NONNULL(container)) { - return NULL; - } - while (container->children->length == 0 && container->type == C_CONTAINER) { - sway_log(L_DEBUG, "Container: Destroying container '%p'", container); - swayc_t *parent = container->parent; - free_swayc(container); - container = parent; - } - return container; -} - -swayc_t *destroy_view(swayc_t *view) { - if (!ASSERT_NONNULL(view)) { - return NULL; - } - sway_log(L_DEBUG, "Destroying view '%p'", view); - swayc_t *parent = view->parent; - free_swayc(view); - - // Destroy empty containers - if (parent && parent->type == C_CONTAINER) { - return destroy_container(parent); - } - return parent; -} - -// Container lookup - - -swayc_t *swayc_by_test(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data) { - if (!container->children) { - return NULL; - } - // Special case for checking floating stuff - int i; - if (container->type == C_WORKSPACE) { - for (i = 0; i < container->floating->length; ++i) { - swayc_t *child = container->floating->items[i]; - if (test(child, data)) { - return child; - } - } - } - for (i = 0; i < container->children->length; ++i) { - swayc_t *child = container->children->items[i]; - if (test(child, data)) { - return child; - } else { - swayc_t *res = swayc_by_test(child, test, data); - if (res) { - return res; - } - } - } - return NULL; -} - -static bool test_name(swayc_t *view, void *data) { - if (!view || !view->name) { - return false; - } - return strcmp(view->name, data) == 0; -} - -swayc_t *swayc_by_name(const char *name) { - return swayc_by_test(&root_container, test_name, (void *)name); -} - -swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type) { - if (!ASSERT_NONNULL(container)) { - return NULL; - } - if (!sway_assert(type < C_TYPES && type >= C_ROOT, "invalid type")) { - return NULL; - } - do { - container = container->parent; - } while (container && container->type != type); - return container; -} - -swayc_t *swayc_parent_by_layout(swayc_t *container, enum swayc_layouts layout) { - if (!ASSERT_NONNULL(container)) { - return NULL; - } - if (!sway_assert(layout < L_LAYOUTS && layout >= L_NONE, "invalid layout")) { - return NULL; - } - do { - container = container->parent; - } while (container && container->layout != layout); - return container; -} - -swayc_t *swayc_focus_by_type(swayc_t *container, enum swayc_types type) { - if (!ASSERT_NONNULL(container)) { - return NULL; - } - if (!sway_assert(type < C_TYPES && type >= C_ROOT, "invalid type")) { - return NULL; - } - do { - container = container->focused; - } while (container && container->type != type); - return container; -} - -swayc_t *swayc_focus_by_layout(swayc_t *container, enum swayc_layouts layout) { - if (!ASSERT_NONNULL(container)) { - return NULL; - } - if (!sway_assert(layout < L_LAYOUTS && layout >= L_NONE, "invalid layout")) { - return NULL; - } - do { - container = container->focused; - } while (container && container->layout != layout); - return container; -} - - -static swayc_t *_swayc_by_handle_helper(wlc_handle handle, swayc_t *parent) { - if (!parent || !parent->children) { - return NULL; - } - int i, len; - swayc_t **child; - if (parent->type == C_WORKSPACE) { - len = parent->floating->length; - child = (swayc_t **)parent->floating->items; - for (i = 0; i < len; ++i, ++child) { - if ((*child)->handle == handle) { - return *child; - } - } - } - - len = parent->children->length; - child = (swayc_t**)parent->children->items; - for (i = 0; i < len; ++i, ++child) { - if ((*child)->handle == handle) { - return *child; - } else { - swayc_t *res; - if ((res = _swayc_by_handle_helper(handle, *child))) { - return res; - } - } - } - return NULL; -} - -swayc_t *swayc_by_handle(wlc_handle handle) { - return _swayc_by_handle_helper(handle, &root_container); -} - -swayc_t *swayc_active_output(void) { - return root_container.focused; -} - -swayc_t *swayc_active_workspace(void) { - return root_container.focused ? root_container.focused->focused : NULL; -} - -swayc_t *swayc_active_workspace_for(swayc_t *cont) { - if (!cont) { - return NULL; - } - switch (cont->type) { - case C_ROOT: - cont = cont->focused; - /* Fallthrough */ - - case C_OUTPUT: - cont = cont ? cont->focused : NULL; - /* Fallthrough */ - - case C_WORKSPACE: - return cont; - - default: - return swayc_parent_by_type(cont, C_WORKSPACE); - } -} - -static bool pointer_test(swayc_t *view, void *_origin) { - const struct wlc_point *origin = _origin; - // Determine the output that the view is under - swayc_t *parent = swayc_parent_by_type(view, C_OUTPUT); - if (origin->x >= view->x && origin->y >= view->y - && origin->x < view->x + view->width && origin->y < view->y + view->height - && view->visible && parent == root_container.focused) { - return true; - } - return false; -} - -swayc_t *container_under_pointer(void) { - // root.output->workspace - if (!root_container.focused) { - return NULL; - } - swayc_t *lookup = root_container.focused; - // Case of empty workspace - if (lookup->children && !lookup->unmanaged) { - return NULL; - } - double x, y; - wlc_pointer_get_position_v2(&x, &y); - struct wlc_point origin = { .x = x, .y = y }; - - while (lookup && lookup->type != C_VIEW) { - int i; - int len; - for (int _i = 0; lookup->unmanaged && _i < lookup->unmanaged->length; ++_i) { - wlc_handle *handle = lookup->unmanaged->items[_i]; - const struct wlc_geometry *geo = wlc_view_get_geometry(*handle); - if (origin.x >= geo->origin.x && origin.y >= geo->origin.y - && origin.x < geo->origin.x + (int)geo->size.w - && origin.y < geo->origin.y + (int)geo->size.h) { - // Hack: we force focus upon unmanaged views here - wlc_view_focus(*handle); - return NULL; - } - } - // if tabbed/stacked go directly to focused container, otherwise search - // children - if (lookup->layout == L_TABBED || lookup->layout == L_STACKED) { - lookup = lookup->focused; - continue; - } - // if workspace, search floating - if (lookup->type == C_WORKSPACE) { - i = len = lookup->floating->length; - bool got_floating = false; - while (--i > -1) { - if (pointer_test(lookup->floating->items[i], &origin)) { - lookup = lookup->floating->items[i]; - got_floating = true; - break; - } - } - if (got_floating) { - continue; - } - } - // search children - len = lookup->children->length; - for (i = 0; i < len; ++i) { - if (pointer_test(lookup->children->items[i], &origin)) { - lookup = lookup->children->items[i]; - break; - } - } - // when border and titles are done, this could happen - if (i == len) { - break; - } - } - return lookup; -} - -swayc_t *container_find(swayc_t *container, bool (*f)(swayc_t *, const void *), const void *data) { - if (container->children == NULL || container->children->length == 0) { - return NULL; - } - - swayc_t *con; - if (container->type == C_WORKSPACE) { - for (int i = 0; i < container->floating->length; ++i) { - con = container->floating->items[i]; - if (f(con, data)) { - return con; - } - con = container_find(con, f, data); - if (con != NULL) { - return con; - } - } - } - - for (int i = 0; i < container->children->length; ++i) { - con = container->children->items[i]; - if (f(con, data)) { - return con; - } - - con = container_find(con, f, data); - if (con != NULL) { - return con; - } - } - - return NULL; -} - -// Container information - -bool swayc_is_fullscreen(swayc_t *view) { - return view && view->type == C_VIEW && (wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN); -} - -bool swayc_is_active(swayc_t *view) { - return view && view->type == C_VIEW && (wlc_view_get_state(view->handle) & WLC_BIT_ACTIVATED); -} - -bool swayc_is_parent_of(swayc_t *parent, swayc_t *child) { - while (child != &root_container) { - child = child->parent; - if (child == parent) { - return true; - } - } - return false; -} - -bool swayc_is_child_of(swayc_t *child, swayc_t *parent) { - return swayc_is_parent_of(parent, child); -} - -bool swayc_is_empty_workspace(swayc_t *container) { - return container->type == C_WORKSPACE && container->children->length == 0; -} - -int swayc_gap(swayc_t *container) { - if (container->type == C_VIEW || container->type == C_CONTAINER) { - return container->gaps >= 0 ? container->gaps : config->gaps_inner; - } else if (container->type == C_WORKSPACE) { - int base = container->gaps >= 0 ? container->gaps : config->gaps_outer; - if (config->edge_gaps && !(config->smart_gaps && container->children->length == 1)) { - // the inner gap is created via a margin around each window which - // is half the gap size, so the workspace also needs half a gap - // size to make the outermost gap the same size (excluding the - // actual "outer gap" size which is handled independently) - return base + config->gaps_inner / 2; - } else if (config->smart_gaps && container->children->length == 1) { - return 0; - } else { - return base; - } - } else { - return 0; - } -} - -// Mapping - -void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), void *data) { - if (container) { - int i; - if (container->children) { - for (i = 0; i < container->children->length; ++i) { - swayc_t *child = container->children->items[i]; - container_map(child, f, data); - } - } - if (container->floating) { - for (i = 0; i < container->floating->length; ++i) { - swayc_t *child = container->floating->items[i]; - container_map(child, f, data); - } - } - f(container, data); - } -} - -void update_visibility_output(swayc_t *container, wlc_handle output) { - // Inherit visibility - swayc_t *parent = container->parent; - container->visible = parent->visible; - // special cases where visibility depends on focus - if (parent->type == C_OUTPUT || parent->layout == L_TABBED || - parent->layout == L_STACKED) { - container->visible = parent->focused == container && parent->visible; - } - // Set visibility and output for view - if (container->type == C_VIEW) { - wlc_view_set_output(container->handle, output); - wlc_view_set_mask(container->handle, container->visible ? VISIBLE : 0); - } - // Update visibility for children - else { - if (container->children) { - int i, len = container->children->length; - for (i = 0; i < len; ++i) { - update_visibility_output(container->children->items[i], output); - } - } - if (container->floating) { - int i, len = container->floating->length; - for (i = 0; i < len; ++i) { - update_visibility_output(container->floating->items[i], output); - } - } - } -} - -void update_visibility(swayc_t *container) { - if (!container) return; - switch (container->type) { - case C_ROOT: - container->visible = true; - if (container->children) { - int i, len = container->children->length; - for (i = 0; i < len; ++i) { - update_visibility(container->children->items[i]); - } - } - return; - - case C_OUTPUT: - container->visible = true; - if (container->children) { - int i, len = container->children->length; - for (i = 0; i < len; ++i) { - update_visibility_output(container->children->items[i], container->handle); - } - } - return; - - default: - { - swayc_t *op = swayc_parent_by_type(container, C_OUTPUT); - update_visibility_output(container, op->handle); - } - } -} - -void set_gaps(swayc_t *view, void *_data) { - int *data = _data; - if (!ASSERT_NONNULL(view)) { - return; - } - if (view->type == C_WORKSPACE || view->type == C_VIEW) { - view->gaps = *data; - } -} - -void add_gaps(swayc_t *view, void *_data) { - int *data = _data; - if (!ASSERT_NONNULL(view)) { - return; - } - if (view->type == C_WORKSPACE || view->type == C_VIEW) { - if ((view->gaps += *data) < 0) { - view->gaps = 0; - } - } -} - -static void close_view(swayc_t *container, void *data) { - if (container->type == C_VIEW) { - wlc_view_close(container->handle); - } -} - -void close_views(swayc_t *container) { - container_map(container, close_view, NULL); -} - -swayc_t *swayc_tabbed_stacked_ancestor(swayc_t *view) { - swayc_t *parent = NULL; - if (!ASSERT_NONNULL(view)) { - return NULL; - } - while (view->type != C_WORKSPACE && view->parent && view->parent->type != C_WORKSPACE) { - view = view->parent; - if (view->layout == L_TABBED || view->layout == L_STACKED) { - parent = view; - } - } - - return parent; -} - -swayc_t *swayc_tabbed_stacked_parent(swayc_t *con) { - if (!ASSERT_NONNULL(con)) { - return NULL; - } - if (con->parent && (con->parent->layout == L_TABBED || con->parent->layout == L_STACKED)) { - return con->parent; - } - return NULL; -} - -swayc_t *swayc_change_layout(swayc_t *container, enum swayc_layouts layout) { - // if layout change modifies the auto layout's major axis, swap width and height - // to preserve current ratios. - if (is_auto_layout(layout) && is_auto_layout(container->layout)) { - enum swayc_layouts prev_major = - container->layout == L_AUTO_LEFT || container->layout == L_AUTO_RIGHT - ? L_HORIZ : L_VERT; - enum swayc_layouts new_major = - layout == L_AUTO_LEFT || layout == L_AUTO_RIGHT - ? L_HORIZ : L_VERT; - if (new_major != prev_major) { - for (int i = 0; i < container->children->length; ++i) { - swayc_t *child = container->children->items[i]; - double h = child->height; - child->height = child->width; - child->width = h; - } - } - } - if (container->type == C_WORKSPACE) { - container->workspace_layout = layout; - if (layout == L_HORIZ || layout == L_VERT || is_auto_layout(layout)) { - container->layout = layout; - } - } else { - container->layout = layout; - } - return container; -} diff --git a/sway/tree/criteria.c b/sway/tree/criteria.c deleted file mode 100644 index e8978ebe..00000000 --- a/sway/tree/criteria.c +++ /dev/null @@ -1,451 +0,0 @@ -#define _XOPEN_SOURCE 700 -#include -#include -#include -#include -#include "sway/criteria.h" -#include "sway/container.h" -#include "sway/config.h" -#include "stringop.h" -#include "list.h" -#include "log.h" - -enum criteria_type { // *must* keep in sync with criteria_strings[] - CRIT_CLASS, - CRIT_CON_ID, - CRIT_CON_MARK, - CRIT_FLOATING, - CRIT_ID, - CRIT_INSTANCE, - CRIT_TILING, - CRIT_TITLE, - CRIT_URGENT, - CRIT_WINDOW_ROLE, - CRIT_WINDOW_TYPE, - CRIT_WORKSPACE, - CRIT_LAST -}; - -static const char * const criteria_strings[CRIT_LAST] = { - [CRIT_CLASS] = "class", - [CRIT_CON_ID] = "con_id", - [CRIT_CON_MARK] = "con_mark", - [CRIT_FLOATING] = "floating", - [CRIT_ID] = "id", - [CRIT_INSTANCE] = "instance", - [CRIT_TILING] = "tiling", - [CRIT_TITLE] = "title", - [CRIT_URGENT] = "urgent", // either "latest" or "oldest" ... - [CRIT_WINDOW_ROLE] = "window_role", - [CRIT_WINDOW_TYPE] = "window_type", - [CRIT_WORKSPACE] = "workspace" -}; - -/** - * A single criteria token (ie. value/regex pair), - * e.g. 'class="some class regex"'. - */ -struct crit_token { - enum criteria_type type; - pcre *regex; - char *raw; -}; - -static void free_crit_token(struct crit_token *crit) { - pcre_free(crit->regex); - free(crit->raw); - free(crit); -} - -static void free_crit_tokens(list_t *crit_tokens) { - for (int i = 0; i < crit_tokens->length; i++) { - free_crit_token(crit_tokens->items[i]); - } - list_free(crit_tokens); -} - -// Extracts criteria string from its brackets. Returns new (duplicate) -// substring. -static char *criteria_from(const char *arg) { - char *criteria = NULL; - if (*arg == '[') { - criteria = strdup(arg + 1); - } else { - criteria = strdup(arg); - } - - int last = strlen(criteria) - 1; - if (criteria[last] == ']') { - criteria[last] = '\0'; - } - return criteria; -} - -// Return instances of c found in str. -static int countchr(char *str, char c) { - int found = 0; - for (int i = 0; str[i]; i++) { - if (str[i] == c) { - ++found; - } - } - return found; -} - -// criteria_str is e.g. '[class="some class regex" instance="instance name"]'. -// -// Will create array of pointers in buf, where first is duplicate of given -// string (must be freed) and the rest are pointers to names and values in the -// base string (every other, naturally). argc will be populated with the length -// of buf. -// -// Returns error string or NULL if successful. -static char *crit_tokens(int *argc, char ***buf, const char * const criteria_str) { - sway_log(L_DEBUG, "Parsing criteria: '%s'", criteria_str); - char *base = criteria_from(criteria_str); - char *head = base; - char *namep = head; // start of criteria name - char *valp = NULL; // start of value - - // We're going to place EOS markers where we need to and fill up an array - // of pointers to the start of each token (either name or value). - int pairs = countchr(base, '='); - int max_tokens = pairs * 2 + 1; // this gives us at least enough slots - - char **argv = *buf = calloc(max_tokens, sizeof(char*)); - argv[0] = base; // this needs to be freed by caller - bool quoted = true; - - *argc = 1; // uneven = name, even = value - while (*head && *argc < max_tokens) { - if (namep != head && *(head - 1) == '\\') { - // escaped character: don't try to parse this - } else if (*head == '=' && namep != head) { - if (*argc % 2 != 1) { - // we're not expecting a name - return strdup("Unable to parse criteria: " - "Found out of place equal sign"); - } else { - // name ends here - char *end = head; // don't want to rewind the head - while (*(end - 1) == ' ') { - --end; - } - *end = '\0'; - if (*(namep) == ' ') { - namep = strrchr(namep, ' ') + 1; - } - argv[*argc] = namep; - *argc += 1; - } - } else if (*head == '"') { - if (*argc % 2 != 0) { - // we're not expecting a value - return strdup("Unable to parse criteria: " - "Found quoted value where it was not expected"); - } else if (!valp) { // value starts here - valp = head + 1; - quoted = true; - } else { - // value ends here - argv[*argc] = valp; - *argc += 1; - *head = '\0'; - valp = NULL; - namep = head + 1; - } - } else if (*argc % 2 == 0 && *head != ' ') { - // parse unquoted values - if (!valp) { - quoted = false; - valp = head; // value starts here - } - } else if (valp && !quoted && *head == ' ') { - // value ends here - argv[*argc] = valp; - *argc += 1; - *head = '\0'; - valp = NULL; - namep = head + 1; - } - head++; - } - - // catch last unquoted value if needed - if (valp && !quoted && !*head) { - argv[*argc] = valp; - *argc += 1; - } - - return NULL; -} - -// Returns error string on failure or NULL otherwise. -static char *parse_criteria_name(enum criteria_type *type, char *name) { - *type = CRIT_LAST; - for (int i = 0; i < CRIT_LAST; i++) { - if (strcmp(criteria_strings[i], name) == 0) { - *type = (enum criteria_type) i; - break; - } - } - if (*type == CRIT_LAST) { - const char *fmt = "Criteria type '%s' is invalid or unsupported."; - int len = strlen(name) + strlen(fmt) - 1; - char *error = malloc(len); - snprintf(error, len, fmt, name); - return error; - } else if (*type == CRIT_URGENT || *type == CRIT_WINDOW_ROLE || - *type == CRIT_WINDOW_TYPE) { - // (we're just being helpful here) - const char *fmt = "\"%s\" criteria currently unsupported, " - "no window will match this"; - int len = strlen(fmt) + strlen(name) - 1; - char *error = malloc(len); - snprintf(error, len, fmt, name); - return error; - } - return NULL; -} - -// Returns error string on failure or NULL otherwise. -static char *generate_regex(pcre **regex, char *value) { - const char *reg_err; - int offset; - - *regex = pcre_compile(value, PCRE_UTF8 | PCRE_UCP, ®_err, &offset, NULL); - - if (!*regex) { - const char *fmt = "Regex compilation (for '%s') failed: %s"; - int len = strlen(fmt) + strlen(value) + strlen(reg_err) - 3; - char *error = malloc(len); - snprintf(error, len, fmt, value, reg_err); - return error; - } - return NULL; -} - -// Test whether the criterion corresponds to the currently focused window -static bool crit_is_focused(const char *value) { - return !strcmp(value, "focused") || !strcmp(value, "__focused__"); -} - -// Populate list with crit_tokens extracted from criteria string, returns error -// string or NULL if successful. -char *extract_crit_tokens(list_t *tokens, const char * const criteria) { - int argc; - char **argv = NULL, *error = NULL; - if ((error = crit_tokens(&argc, &argv, criteria))) { - goto ect_cleanup; - } - for (int i = 1; i + 1 < argc; i += 2) { - char* name = argv[i], *value = argv[i + 1]; - struct crit_token *token = calloc(1, sizeof(struct crit_token)); - token->raw = strdup(value); - - if ((error = parse_criteria_name(&token->type, name))) { - free_crit_token(token); - goto ect_cleanup; - } else if (token->type == CRIT_URGENT || crit_is_focused(value)) { - sway_log(L_DEBUG, "%s -> \"%s\"", name, value); - list_add(tokens, token); - } else if((error = generate_regex(&token->regex, value))) { - free_crit_token(token); - goto ect_cleanup; - } else { - sway_log(L_DEBUG, "%s -> /%s/", name, value); - list_add(tokens, token); - } - } -ect_cleanup: - free(argv[0]); // base string - free(argv); - return error; -} - -static int regex_cmp(const char *item, const pcre *regex) { - return pcre_exec(regex, NULL, item, strlen(item), 0, 0, NULL, 0); -} - -// test a single view if it matches list of criteria tokens (all of them). -static bool criteria_test(swayc_t *cont, list_t *tokens) { - if (cont->type != C_VIEW) { - return false; - } - int matches = 0; - for (int i = 0; i < tokens->length; i++) { - struct crit_token *crit = tokens->items[i]; - switch (crit->type) { - case CRIT_CLASS: - if (!cont->class) { - // ignore - } else if (crit_is_focused(crit->raw)) { - swayc_t *focused = get_focused_view(&root_container); - if (focused->class && strcmp(cont->class, focused->class) == 0) { - matches++; - } - } else if (crit->regex && regex_cmp(cont->class, crit->regex) == 0) { - matches++; - } - break; - case CRIT_CON_ID: { - char *endptr; - size_t crit_id = strtoul(crit->raw, &endptr, 10); - - if (*endptr == 0 && cont->id == crit_id) { - ++matches; - } - break; - } - case CRIT_CON_MARK: - if (crit->regex && cont->marks && (list_seq_find(cont->marks, (int (*)(const void *, const void *))regex_cmp, crit->regex) != -1)) { - // Make sure it isn't matching the NUL string - if ((strcmp(crit->raw, "") == 0) == (list_seq_find(cont->marks, (int (*)(const void *, const void *))strcmp, "") != -1)) { - ++matches; - } - } - break; - case CRIT_FLOATING: - if (cont->is_floating) { - matches++; - } - break; - case CRIT_ID: - if (!cont->app_id) { - // ignore - } else if (crit->regex && regex_cmp(cont->app_id, crit->regex) == 0) { - matches++; - } - break; - case CRIT_INSTANCE: - if (!cont->instance) { - // ignore - } else if (crit_is_focused(crit->raw)) { - swayc_t *focused = get_focused_view(&root_container); - if (focused->instance && strcmp(cont->instance, focused->instance) == 0) { - matches++; - } - } else if (crit->regex && regex_cmp(cont->instance, crit->regex) == 0) { - matches++; - } - break; - case CRIT_TILING: - if (!cont->is_floating) { - matches++; - } - break; - case CRIT_TITLE: - if (!cont->name) { - // ignore - } else if (crit_is_focused(crit->raw)) { - swayc_t *focused = get_focused_view(&root_container); - if (focused->name && strcmp(cont->name, focused->name) == 0) { - matches++; - } - } else if (crit->regex && regex_cmp(cont->name, crit->regex) == 0) { - matches++; - } - break; - case CRIT_URGENT: // "latest" or "oldest" - break; - case CRIT_WINDOW_ROLE: - break; - case CRIT_WINDOW_TYPE: - // TODO wlc indeed exposes this information - break; - case CRIT_WORKSPACE: ; - swayc_t *cont_ws = swayc_parent_by_type(cont, C_WORKSPACE); - if (!cont_ws || !cont_ws->name) { - // ignore - } else if (crit_is_focused(crit->raw)) { - swayc_t *focused_ws = swayc_active_workspace(); - if (focused_ws->name && strcmp(cont_ws->name, focused_ws->name) == 0) { - matches++; - } - } else if (crit->regex && regex_cmp(cont_ws->name, crit->regex) == 0) { - matches++; - } - break; - default: - sway_abort("Invalid criteria type (%i)", crit->type); - break; - } - } - return matches == tokens->length; -} - -int criteria_cmp(const void *a, const void *b) { - if (a == b) { - return 0; - } else if (!a) { - return -1; - } else if (!b) { - return 1; - } - const struct criteria *crit_a = a, *crit_b = b; - int cmp = lenient_strcmp(crit_a->cmdlist, crit_b->cmdlist); - if (cmp != 0) { - return cmp; - } - return lenient_strcmp(crit_a->crit_raw, crit_b->crit_raw); -} - -void free_criteria(struct criteria *crit) { - if (crit->tokens) { - free_crit_tokens(crit->tokens); - } - if (crit->cmdlist) { - free(crit->cmdlist); - } - if (crit->crit_raw) { - free(crit->crit_raw); - } - free(crit); -} - -bool criteria_any(swayc_t *cont, list_t *criteria) { - for (int i = 0; i < criteria->length; i++) { - struct criteria *bc = criteria->items[i]; - if (criteria_test(cont, bc->tokens)) { - return true; - } - } - return false; -} - -list_t *criteria_for(swayc_t *cont) { - list_t *criteria = config->criteria, *matches = create_list(); - for (int i = 0; i < criteria->length; i++) { - struct criteria *bc = criteria->items[i]; - if (criteria_test(cont, bc->tokens)) { - list_add(matches, bc); - } - } - return matches; -} - -struct list_tokens { - list_t *list; - list_t *tokens; -}; - -static void container_match_add(swayc_t *container, struct list_tokens *list_tokens) { - if (criteria_test(container, list_tokens->tokens)) { - list_add(list_tokens->list, container); - } -} - -list_t *container_for(list_t *tokens) { - struct list_tokens list_tokens = (struct list_tokens){create_list(), tokens}; - - container_map(&root_container, (void (*)(swayc_t *, void *))container_match_add, &list_tokens); - - for (int i = 0; i < scratchpad->length; ++i) { - swayc_t *c = scratchpad->items[i]; - if (criteria_test(c, tokens)) { - list_add(list_tokens.list, c); - } - } - - return list_tokens.list; -} diff --git a/sway/tree/focus.c b/sway/tree/focus.c deleted file mode 100644 index 66f7ee17..00000000 --- a/sway/tree/focus.c +++ /dev/null @@ -1,278 +0,0 @@ -#include "stdbool.h" -#include -#include "sway/focus.h" -#include "sway/workspace.h" -#include "sway/layout.h" -#include "sway/config.h" -#include "sway/input_state.h" -#include "sway/ipc-server.h" -#include "sway/border.h" -#include "log.h" - -bool locked_container_focus = false; -bool suspend_workspace_cleanup = false; - -// switches parent focus to c. will switch it accordingly -static void update_focus(swayc_t *c) { - // Handle if focus switches - swayc_t *parent = c->parent; - if (!parent) return; - if (parent->focused != c) { - // Get previous focus - swayc_t *prev = parent->focused; - // Set new focus - parent->focused = c; - - switch (c->type) { - // Shouldn't happen - case C_ROOT: return; - - // Case where output changes - case C_OUTPUT: - wlc_output_focus(c->handle); - break; - - // Case where workspace changes - case C_WORKSPACE: - if (prev) { - ipc_event_workspace(prev, c, "focus"); - - // if the old workspace has no children, destroy it - if(prev->children->length == 0 && prev->floating->length == 0 && !suspend_workspace_cleanup) { - destroy_workspace(prev); - } else { - // update visibility of old workspace - update_visibility(prev); - } - } - // Update visibility of newly focused workspace - update_visibility(c); - break; - - default: - case C_VIEW: - case C_CONTAINER: - break; - } - } -} - -bool move_focus(enum movement_direction direction) { - swayc_t *old_view = get_focused_container(&root_container); - swayc_t *new_view = get_swayc_in_direction(old_view, direction); - if (!new_view) { - return false; - } else if (new_view->type == C_ROOT) { - sway_log(L_DEBUG, "Not setting focus above the workspace level"); - return false; - } else if (new_view->type == C_OUTPUT) { - return set_focused_container(swayc_active_workspace_for(new_view)); - } else if (direction == MOVE_PARENT || direction == MOVE_CHILD) { - return set_focused_container(new_view); - } else if (config->mouse_warping) { - swayc_t *old_op = old_view->type == C_OUTPUT ? - old_view : swayc_parent_by_type(old_view, C_OUTPUT); - swayc_t *focused = get_focused_view(new_view); - if (set_focused_container(focused)) { - if (old_op != swayc_active_output() && focused && focused->type == C_VIEW) { - center_pointer_on(focused); - } - return true; - } - } else { - return set_focused_container(get_focused_view(new_view)); - } - return false; -} - -swayc_t *get_focused_container(swayc_t *parent) { - if (!parent) { - return swayc_active_workspace(); - } - while (!parent->is_focused && parent->focused) { - parent = parent->focused; - } - return parent; -} - -bool set_focused_container(swayc_t *c) { - if (locked_container_focus || !c || !c->parent) { - return false; - } - - // current ("old") workspace for sending workspace change event later - swayc_t *old_ws = swayc_active_workspace(); - // keep track of child count so we can determine if it gets destroyed - int old_ws_child_count = 0; - if (old_ws) { - old_ws_child_count = old_ws->children->length + old_ws->floating->length; - } - - // current ("old") focused container - swayc_t *old_focus = get_focused_container(&root_container); - // if old_focus is a workspace, then it's the same workspace as - // old_ws, and we'll need to null its pointer too, since it will - // be destroyed in the update_focus() call - bool old_focus_was_ws = (old_focus->type == C_WORKSPACE); - - // workspace of new focused container - swayc_t *workspace = swayc_active_workspace_for(c); - - if (swayc_is_fullscreen(get_focused_container(workspace))) { - // if switching to a workspace with a fullscreen view, - // focus on the fullscreen view - c = get_focused_container(workspace); - } - - swayc_log(L_DEBUG, c, "Setting focus to %p:%" PRIuPTR, c, c->handle); - - if (c->type == C_VIEW) { - // dispatch a window event - ipc_event_window(c, "focus"); - } - - // update the global pointer - current_focus = c; - - // update container focus from here to root, making necessary changes along - // the way - swayc_t *p = c; - if (p->type != C_OUTPUT && p->type != C_ROOT) { - p->is_focused = true; - } - while (p != &root_container) { - update_focus(p); - p = p->parent; - p->is_focused = false; - } - - if (old_focus_was_ws && old_ws_child_count == 0) { - // this workspace was destroyed in update_focus(), so null the pointers - old_focus = NULL; - old_ws = NULL; - } - - if (!(wlc_view_get_type(p->handle) & WLC_BIT_POPUP)) { - if (old_focus) { - if (old_focus->type == C_VIEW) { - wlc_view_set_state(old_focus->handle, WLC_BIT_ACTIVATED, false); - } - update_container_border(old_focus); - } - if (c->type == C_VIEW) { - wlc_view_set_state(c->handle, WLC_BIT_ACTIVATED, true); - } - /* TODO WLR - if (!desktop_shell.is_locked) { - // If the system is locked, we do everything _but_ actually setting - // focus. This includes making our internals think that this view is - // focused. - wlc_view_focus(c->handle); - } - */ - if (c->parent->layout != L_TABBED && c->parent->layout != L_STACKED) { - update_container_border(c); - } - - swayc_t *parent = swayc_tabbed_stacked_ancestor(c); - if (parent != NULL) { - arrange_backgrounds(); - arrange_windows(parent, -1, -1); - } - } - - if (old_ws != workspace) { - // old_ws might be NULL here but that's ok - ipc_event_workspace(old_ws, workspace, "focus"); - } - - return true; -} - -bool set_focused_container_for(swayc_t *a, swayc_t *c) { - if (locked_container_focus || !c) { - return false; - } - swayc_t *find = c; - while (find != a && (find = find->parent)) { - if (find == &root_container) { - return false; - } - } - - // Get workspace for c, get that workspaces current focused container. - swayc_t *workspace = swayc_active_workspace_for(c); - swayc_t *focused = get_focused_view(workspace); - // if the workspace we are changing focus to has a fullscreen view return - if (swayc_is_fullscreen(focused) && c != focused) { - return false; - } - - // Check if we are changing a parent container that will see change - bool effective = true; - while (find != &root_container) { - if (find->parent->focused != find) { - effective = false; - } - find = find->parent; - } - if (effective) { - // Go to set_focused_container - return set_focused_container(c); - } - - sway_log(L_DEBUG, "Setting focus for %p:%" PRIuPTR " to %p:%" PRIuPTR, - a, a->handle, c, c->handle); - - c->is_focused = true; - swayc_t *p = c; - while (p != a) { - update_focus(p); - p = p->parent; - p->is_focused = false; - } - return true; -} - -swayc_t *get_focused_view(swayc_t *parent) { - swayc_t *c = parent; - while (c && c->type != C_VIEW) { - if (c->type == C_WORKSPACE && c->focused == NULL) { - return c; - } - c = c->focused; - } - if (c == NULL) { - c = swayc_active_workspace_for(parent); - } - return c; -} - -swayc_t *get_focused_float(swayc_t *ws) { - if(!sway_assert(ws->type == C_WORKSPACE, "must be of workspace type")) { - ws = swayc_active_workspace(); - } - if (ws->floating->length) { - return ws->floating->items[ws->floating->length - 1]; - } - return NULL; -} - -swayc_t *get_focused_view_include_floating(swayc_t *parent) { - swayc_t *c = parent; - swayc_t *f = NULL; - - while (c && c->type != C_VIEW) { - if (c->type == C_WORKSPACE && c->focused == NULL) { - return ((f = get_focused_float(c))) ? f : c; - } - - c = c->focused; - } - - if (c == NULL) { - c = swayc_active_workspace_for(parent); - } - - return c; -} diff --git a/sway/tree/layout.c b/sway/tree/layout.c deleted file mode 100644 index 22f81688..00000000 --- a/sway/tree/layout.c +++ /dev/null @@ -1,1773 +0,0 @@ -#define _XOPEN_SOURCE 500 -#include -#include -#include -#include -#include "sway/config.h" -#include "sway/container.h" -#include "sway/workspace.h" -#include "sway/focus.h" -#include "sway/output.h" -#include "sway/ipc-server.h" -#include "sway/border.h" -#include "sway/layout.h" -#include "list.h" -#include "log.h" - -swayc_t root_container; -swayc_t *current_focus; -list_t *scratchpad; - -int min_sane_h = 60; -int min_sane_w = 100; - -void init_layout(void) { - root_container.id = 0; // normally assigned in new_swayc() - root_container.type = C_ROOT; - root_container.layout = L_NONE; - root_container.name = strdup("root"); - root_container.children = create_list(); - root_container.handle = -1; - root_container.visible = true; - current_focus = &root_container; - scratchpad = create_list(); -} - -int index_child(const swayc_t *child) { - swayc_t *parent = child->parent; - int i, len; - if (!child->is_floating) { - len = parent->children->length; - for (i = 0; i < len; ++i) { - if (parent->children->items[i] == child) { - break; - } - } - } else { - len = parent->floating->length; - for (i = 0; i < len; ++i) { - if (parent->floating->items[i] == child) { - break; - } - } - } - if (!sway_assert(i < len, "Stray container")) { - return -1; - } - return i; -} - -void add_child(swayc_t *parent, swayc_t *child) { - sway_log(L_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)", child, child->type, - child->width, child->height, parent, parent->type, parent->width, parent->height); - list_add(parent->children, child); - child->parent = parent; - // set focus for this container - if (!parent->focused) { - parent->focused = child; - } - if (parent->type == C_WORKSPACE && child->type == C_VIEW && (parent->workspace_layout == L_TABBED || parent->workspace_layout == L_STACKED)) { - child = new_container(child, parent->workspace_layout); - } -} - -static double *get_height(swayc_t *cont) { - return &cont->height; -} - -static double *get_width(swayc_t *cont) { - return &cont->width; -} - -void insert_child(swayc_t *parent, swayc_t *child, int index) { - if (index > parent->children->length) { - index = parent->children->length; - } - if (index < 0) { - index = 0; - } - list_insert(parent->children, index, child); - child->parent = parent; - if (!parent->focused) { - parent->focused = child; - } - if (parent->type == C_WORKSPACE && child->type == C_VIEW && (parent->workspace_layout == L_TABBED || parent->workspace_layout == L_STACKED)) { - child = new_container(child, parent->workspace_layout); - } - if (is_auto_layout(parent->layout)) { - /* go through each group, adjust the size of the first child of each group */ - double *(*get_maj_dim)(swayc_t *cont); - double *(*get_min_dim)(swayc_t *cont); - if (parent->layout == L_AUTO_LEFT || parent->layout == L_AUTO_RIGHT) { - get_maj_dim = get_width; - get_min_dim = get_height; - } else { - get_maj_dim = get_height; - get_min_dim = get_width; - } - for (int i = index; i < parent->children->length;) { - int start = auto_group_start_index(parent, i); - int end = auto_group_end_index(parent, i); - swayc_t *first = parent->children->items[start]; - if (start + 1 < parent->children->length) { - /* preserve the group's dimension along major axis */ - *get_maj_dim(first) = *get_maj_dim(parent->children->items[start + 1]); - } else { - /* new group, let the apply_layout handle it */ - first->height = first->width = 0; - break; - } - double remaining = *get_min_dim(parent); - for (int j = end - 1; j > start; --j) { - swayc_t *sibling = parent->children->items[j]; - if (sibling == child) { - /* the inserted child won't yet have its minor - dimension set */ - remaining -= *get_min_dim(parent) / (end - start); - } else { - remaining -= *get_min_dim(sibling); - } - } - *get_min_dim(first) = remaining; - i = end; - } - } -} - -void add_floating(swayc_t *ws, swayc_t *child) { - sway_log(L_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)", child, child->type, - child->width, child->height, ws, ws->type, ws->width, ws->height); - if (!sway_assert(ws->type == C_WORKSPACE, "Must be of workspace type")) { - return; - } - list_add(ws->floating, child); - child->parent = ws; - child->is_floating = true; - if (!ws->focused) { - ws->focused = child; - } - ipc_event_window(child, "floating"); -} - -swayc_t *add_sibling(swayc_t *fixed, swayc_t *active) { - swayc_t *parent = fixed->parent; - if (fixed->is_floating) { - if (active->is_floating) { - int i = index_child(fixed); - list_insert(parent->floating, i + 1, active); - } else { - list_add(parent->children, active); - } - } else { - if (active->is_floating) { - list_add(parent->floating, active); - } else { - int i = index_child(fixed); - if (is_auto_layout(parent->layout)) { - list_add(parent->children, active); - } else { - list_insert(parent->children, i + 1, active); - } - } - } - active->parent = parent; - // focus new child - parent->focused = active; - return active->parent; -} - -swayc_t *replace_child(swayc_t *child, swayc_t *new_child) { - swayc_t *parent = child->parent; - if (parent == NULL) { - return NULL; - } - int i = index_child(child); - if (child->is_floating) { - parent->floating->items[i] = new_child; - } else { - parent->children->items[i] = new_child; - } - // Set parent and focus for new_child - new_child->parent = child->parent; - if (child->parent->focused == child) { - child->parent->focused = new_child; - } - child->parent = NULL; - - // Set geometry for new child - new_child->x = child->x; - new_child->y = child->y; - new_child->width = child->width; - new_child->height = child->height; - - // reset geometry for child - child->width = 0; - child->height = 0; - - // deactivate child - if (child->type == C_VIEW) { - wlc_view_set_state(child->handle, WLC_BIT_ACTIVATED, false); - } - return parent; -} - -swayc_t *remove_child(swayc_t *child) { - int i; - swayc_t *parent = child->parent; - if (child->is_floating) { - // Special case for floating views - for (i = 0; i < parent->floating->length; ++i) { - if (parent->floating->items[i] == child) { - list_del(parent->floating, i); - break; - } - } - i = 0; - } else { - for (i = 0; i < parent->children->length; ++i) { - if (parent->children->items[i] == child) { - list_del(parent->children, i); - break; - } - } - if (is_auto_layout(parent->layout) && parent->children->length) { - /* go through each group, adjust the size of the last child of each group */ - double *(*get_maj_dim)(swayc_t *cont); - double *(*get_min_dim)(swayc_t *cont); - if (parent->layout == L_AUTO_LEFT || parent->layout == L_AUTO_RIGHT) { - get_maj_dim = get_width; - get_min_dim = get_height; - } else { - get_maj_dim = get_height; - get_min_dim = get_width; - } - for (int j = parent->children->length - 1; j >= i;) { - int start = auto_group_start_index(parent, j); - int end = auto_group_end_index(parent, j); - swayc_t *first = parent->children->items[start]; - if (i == start) { - /* removed element was first child in the current group, - use its size along the major axis */ - *get_maj_dim(first) = *get_maj_dim(child); - } else if (start > i) { - /* preserve the group's dimension along major axis */ - *get_maj_dim(first) = *get_maj_dim(parent->children->items[start - 1]); - } - if (end != parent->children->length) { - double remaining = *get_min_dim(parent); - for (int k = start; k < end - 1; ++k) { - swayc_t *sibling = parent->children->items[k]; - remaining -= *get_min_dim(sibling); - } - /* last element of the group gets remaining size, elements - that don't change groups keep their ratio */ - *get_min_dim((swayc_t *) parent->children->items[end - 1]) = remaining; - } /* else last group, let apply_layout handle it */ - j = start - 1; - } - } - } - // Set focused to new container - if (parent->focused == child) { - if (parent->children->length > 0) { - parent->focused = parent->children->items[i ? i-1:0]; - } else if (parent->floating && parent->floating->length) { - parent->focused = parent->floating->items[parent->floating->length - 1]; - } else { - parent->focused = NULL; - } - } - child->parent = NULL; - // deactivate view - if (child->type == C_VIEW) { - wlc_view_set_state(child->handle, WLC_BIT_ACTIVATED, false); - } - return parent; -} - -void swap_container(swayc_t *a, swayc_t *b) { - if (!sway_assert(a&&b, "parameters must be non null") || - !sway_assert(a->parent && b->parent, "containers must have parents")) { - return; - } - size_t a_index = index_child(a); - size_t b_index = index_child(b); - swayc_t *a_parent = a->parent; - swayc_t *b_parent = b->parent; - // Swap the pointers - if (a->is_floating) { - a_parent->floating->items[a_index] = b; - } else { - a_parent->children->items[a_index] = b; - } - if (b->is_floating) { - b_parent->floating->items[b_index] = a; - } else { - b_parent->children->items[b_index] = a; - } - a->parent = b_parent; - b->parent = a_parent; - if (a_parent->focused == a) { - a_parent->focused = b; - } - // don't want to double switch - if (b_parent->focused == b && a_parent != b_parent) { - b_parent->focused = a; - } -} - -void swap_geometry(swayc_t *a, swayc_t *b) { - double x = a->x; - double y = a->y; - double w = a->width; - double h = a->height; - a->x = b->x; - a->y = b->y; - a->width = b->width; - a->height = b->height; - b->x = x; - b->y = y; - b->width = w; - b->height = h; -} - -static void swap_children(swayc_t *container, int a, int b) { - if (a >= 0 && b >= 0 && a < container->children->length - && b < container->children->length - && a != b) { - swayc_t *pa = (swayc_t *)container->children->items[a]; - swayc_t *pb = (swayc_t *)container->children->items[b]; - container->children->items[a] = container->children->items[b]; - container->children->items[b] = pa; - if (is_auto_layout(container->layout)) { - size_t ga = auto_group_index(container, a); - size_t gb = auto_group_index(container, b); - if (ga != gb) { - swap_geometry(pa, pb); - } - } - } -} - -void move_container(swayc_t *container, enum movement_direction dir, int move_amt) { - enum swayc_layouts layout = L_NONE; - swayc_t *parent = container->parent; - if (container->is_floating) { - swayc_t *output = swayc_parent_by_type(container, C_OUTPUT); - switch(dir) { - case MOVE_LEFT: - container->x = MAX(0, container->x - move_amt); - break; - case MOVE_RIGHT: - container->x = MIN(output->width - container->width, container->x + move_amt); - break; - case MOVE_UP: - container->y = MAX(0, container->y - move_amt); - break; - case MOVE_DOWN: - container->y = MIN(output->height - container->height, container->y + move_amt); - break; - default: - break; - } - update_geometry(container); - return; - } - if (container->type != C_VIEW && container->type != C_CONTAINER) { - return; - } - if (dir == MOVE_UP || dir == MOVE_DOWN) { - layout = L_VERT; - } else if (dir == MOVE_LEFT || dir == MOVE_RIGHT) { - layout = L_HORIZ; - } else if (dir == MOVE_FIRST) { - // swap first child in auto layout with currently focused child - if (is_auto_layout(parent->layout)) { - int focused_idx = index_child(container); - swayc_t *first = parent->children->items[0]; - if (focused_idx > 0) { - list_swap(parent->children, 0, focused_idx); - swap_geometry(first, container); - } - arrange_windows(parent->parent, -1, -1); - ipc_event_window(container, "move"); - set_focused_container_for(parent->parent, container); - } - return; - } else if (! (dir == MOVE_NEXT || dir == MOVE_PREV)) { - return; - } - swayc_t *child = container; - bool ascended = false; - - // View is wrapped in intermediate container which is needed for displaying - // the titlebar. Moving only the view outside of its parent container would just - // wrap it again under worspace. There would effectively be no movement, - // just a change of wrapping container. - if (child->type == C_VIEW && - parent->type == C_CONTAINER && - parent->children->length == 1 && - parent->parent->type == C_WORKSPACE) { - child = parent; - parent = parent->parent; - } - - while (true) { - sway_log(L_DEBUG, "container:%p, parent:%p, child %p,", - container,parent,child); - if (parent->layout == layout - || (layout == L_NONE && (parent->type == C_CONTAINER || parent->type == C_WORKSPACE)) /* accept any layout for next/prev direction */ - || (parent->layout == L_TABBED && layout == L_HORIZ) - || (parent->layout == L_STACKED && layout == L_VERT) - || is_auto_layout(parent->layout)) { - int diff; - // If it has ascended (parent has moved up), no container is removed - // so insert it at index, or index+1. - // if it has not, the moved container is removed, so it needs to be - // inserted at index-1, or index+1 - if (ascended) { - diff = dir == MOVE_LEFT || dir == MOVE_UP || dir == MOVE_PREV ? 0 : 1; - } else { - diff = dir == MOVE_LEFT || dir == MOVE_UP || dir == MOVE_PREV ? -1 : 1; - } - int idx = index_child(child); - int desired = idx + diff; - if (dir == MOVE_NEXT || dir == MOVE_PREV) { - // Next/Prev always wrap. - if (desired < 0) { - desired += parent->children->length; - } else if (desired >= parent->children->length) { - desired = 0; - } - } - // when it has ascended, legal insertion position is 0:len - // when it has not, legal insertion position is 0:len-1 - if (desired >= 0 && desired - ascended < parent->children->length) { - if (!ascended) { - child = parent->children->items[desired]; - // Move container into sibling container - if (child->type == C_CONTAINER) { - parent = child; - // Insert it in first/last if matching layout, otherwise - // insert it next to focused container - if (parent->layout == layout - || (parent->layout == L_TABBED && layout == L_HORIZ) - || (parent->layout == L_STACKED && layout == L_VERT) - || is_auto_layout(parent->layout)) { - desired = (diff < 0) * parent->children->length; - } else { - desired = index_child(child->focused) + 1; - } - //reset geometry - container->width = container->height = 0; - } - } - if (container->parent == parent) { - swap_children(parent, idx, desired); - } else { - swayc_t *old_parent = remove_child(container); - insert_child(parent, container, desired); - destroy_container(old_parent); - sway_log(L_DEBUG,"Moving to %p %d", parent, desired); - } - break; - } - } - // Change parent layout if we need to - if (parent->children->length == 1 && parent->layout != layout && layout != L_NONE) { - /* swayc_change_layout(parent, layout); */ - parent->layout = layout; - continue; - } - if (parent->type == C_WORKSPACE) { - // If moving to an adjacent output we need a starting position (since this - // output might border to multiple outputs). - struct wlc_point abs_pos; - get_absolute_center_position(container, &abs_pos); - - swayc_t *output = swayc_adjacent_output(parent->parent, dir, &abs_pos, true); - - if (output) { - sway_log(L_DEBUG, "Moving between outputs"); - swayc_t *old_parent = remove_child(container); - destroy_container(old_parent); - - swayc_t *dest = output->focused; - switch (dir) { - case MOVE_LEFT: - case MOVE_UP: - // reset container geometry - container->width = container->height = 0; - add_child(dest, container); - break; - case MOVE_RIGHT: - case MOVE_DOWN: - // reset container geometry - container->width = container->height = 0; - insert_child(dest, container, 0); - break; - default: - break; - } - // arrange new workspace - arrange_windows(dest, -1, -1); - set_focused_container(container); - break; - } - - // We simply cannot move any further. - if (parent->layout == layout) { - break; - } - // Create container around workspace to insert child into - parent = new_container(parent, layout); - // Previous line set the resulting container's layout to - // workspace_layout. It should have been just layout. - parent->layout = parent->parent->layout; - } - ascended = true; - child = parent; - parent = child->parent; - } - arrange_windows(parent->parent, -1, -1); - ipc_event_window(container, "move"); - set_focused_container_for(parent->parent, container); -} - -void move_container_to(swayc_t* container, swayc_t* destination) { - if (container == destination || swayc_is_parent_of(container, destination)) { - return; - } - swayc_t *parent = remove_child(container); - // Send to new destination - if (container->is_floating) { - swayc_t *ws = swayc_active_workspace_for(destination); - add_floating(ws, container); - - // If the workspace only has one child after adding one, it - // means that the workspace was just initialized. - if (ws->children->length + ws->floating->length == 1) { - ipc_event_workspace(NULL, ws, "init"); - } - } else if (destination->type == C_WORKSPACE) { - // reset container geometry - container->width = container->height = 0; - add_child(destination, container); - - // If the workspace only has one child after adding one, it - // means that the workspace was just initialized. - if (destination->children->length + destination->floating->length == 1) { - ipc_event_workspace(NULL, destination, "init"); - } - } else { - // reset container geometry - container->width = container->height = 0; - add_sibling(destination, container); - } - // Destroy old container if we need to - parent = destroy_container(parent); - // Refocus - swayc_t *op1 = swayc_parent_by_type(destination, C_OUTPUT); - swayc_t *op2 = swayc_parent_by_type(parent, C_OUTPUT); - set_focused_container(get_focused_view(op1)); - arrange_windows(op1, -1, -1); - update_visibility(op1); - if (op1 != op2) { - set_focused_container(get_focused_view(op2)); - arrange_windows(op2, -1, -1); - update_visibility(op2); - } -} - -void move_workspace_to(swayc_t* workspace, swayc_t* destination) { - if (workspace == destination || swayc_is_parent_of(workspace, destination)) { - return; - } - swayc_t *src_op = remove_child(workspace); - // reset container geometry - workspace->width = workspace->height = 0; - add_child(destination, workspace); - sort_workspaces(destination); - // Refocus destination (change to new workspace) - set_focused_container(get_focused_view(workspace)); - arrange_windows(destination, -1, -1); - update_visibility(destination); - - // make sure source output has a workspace - if (src_op->children->length == 0) { - char *ws_name = workspace_next_name(src_op->name); - swayc_t *ws = new_workspace(src_op, ws_name); - ws->is_focused = true; - free(ws_name); - } - set_focused_container(get_focused_view(src_op)); - update_visibility(src_op); -} - -static void adjust_border_geometry(swayc_t *c, struct wlc_geometry *g, - const struct wlc_size *res, int left, int right, int top, int bottom) { - - g->size.w += left + right; - if (g->origin.x - left < 0) { - g->size.w += g->origin.x - left; - } else if (g->origin.x + g->size.w - right > res->w) { - g->size.w = res->w - g->origin.x + right; - } - - g->size.h += top + bottom; - if (g->origin.y - top < 0) { - g->size.h += g->origin.y - top; - } else if (g->origin.y + g->size.h - top > res->h) { - g->size.h = res->h - g->origin.y + top; - } - - g->origin.x = MIN((uint32_t)MAX(g->origin.x - left, 0), res->w); - g->origin.y = MIN((uint32_t)MAX(g->origin.y - top, 0), res->h); - -} - -static void update_border_geometry_floating(swayc_t *c, struct wlc_geometry *geometry) { - struct wlc_geometry g = *geometry; - c->actual_geometry = g; - - swayc_t *output = swayc_parent_by_type(c, C_OUTPUT); - struct wlc_size res; - output_get_scaled_size(output->handle, &res); - - switch (c->border_type) { - case B_NONE: - break; - case B_PIXEL: - adjust_border_geometry(c, &g, &res, c->border_thickness, - c->border_thickness, c->border_thickness, c->border_thickness); - break; - case B_NORMAL: - { - int title_bar_height = config->font_height + 4; // borders + padding - - adjust_border_geometry(c, &g, &res, c->border_thickness, - c->border_thickness, title_bar_height, c->border_thickness); - - struct wlc_geometry title_bar = { - .origin = { - .x = c->actual_geometry.origin.x - c->border_thickness, - .y = c->actual_geometry.origin.y - title_bar_height - }, - .size = { - .w = c->actual_geometry.size.w + (2 * c->border_thickness), - .h = title_bar_height - } - }; - c->title_bar_geometry = title_bar; - break; - } - } - - c->border_geometry = g; - *geometry = c->actual_geometry; - - update_container_border(c); -} - -void update_layout_geometry(swayc_t *parent, enum swayc_layouts prev_layout) { - switch (parent->layout) { - case L_TABBED: - case L_STACKED: - if (prev_layout != L_TABBED && prev_layout != L_STACKED) { - // cache current geometry for all non-float children - int i; - for (i = 0; i < parent->children->length; ++i) { - swayc_t *child = parent->children->items[i]; - child->cached_geometry.origin.x = child->x; - child->cached_geometry.origin.y = child->y; - child->cached_geometry.size.w = child->width; - child->cached_geometry.size.h = child->height; - } - } - break; - default: - if (prev_layout == L_TABBED || prev_layout == L_STACKED) { - // recover cached geometry for all non-float children - int i; - for (i = 0; i < parent->children->length; ++i) { - swayc_t *child = parent->children->items[i]; - // only recoverer cached geometry if non-zero - if (!wlc_geometry_equals(&child->cached_geometry, &wlc_geometry_zero)) { - child->x = child->cached_geometry.origin.x; - child->y = child->cached_geometry.origin.y; - child->width = child->cached_geometry.size.w; - child->height = child->cached_geometry.size.h; - } - } - } - break; - } -} - -static int update_gap_geometry(swayc_t *container, struct wlc_geometry *g) { - swayc_t *ws = swayc_parent_by_type(container, C_WORKSPACE); - swayc_t *op = ws->parent; - int gap = container->is_floating ? 0 : swayc_gap(container); - if (gap % 2 != 0) { - // because gaps are implemented as "half sized margins" it's currently - // not possible to align views properly with odd sized gaps. - gap -= 1; - } - - g->origin.x = container->x + gap/2 < op->width ? container->x + gap/2 : op->width-1; - g->origin.y = container->y + gap/2 < op->height ? container->y + gap/2 : op->height-1; - g->size.w = container->width > gap ? container->width - gap : 1; - g->size.h = container->height > gap ? container->height - gap : 1; - - if ((!config->edge_gaps && gap > 0) || (config->smart_gaps && ws->children->length == 1)) { - // Remove gap against the workspace edges. Because a pixel is not - // divisable, depending on gap size and the number of siblings our view - // might be at the workspace edge without being exactly so (thus test - // with gap, and align correctly). - if (container->x - gap <= ws->x) { - g->origin.x = ws->x; - g->size.w = container->width - gap/2; - } - if (container->y - gap <= ws->y) { - g->origin.y = ws->y; - g->size.h = container->height - gap/2; - } - if (container->x + container->width + gap >= ws->x + ws->width) { - g->size.w = ws->x + ws->width - g->origin.x; - } - if (container->y + container->height + gap >= ws->y + ws->height) { - g->size.h = ws->y + ws->height - g->origin.y; - } - } - - return gap; -} - -void update_geometry(swayc_t *container) { - if (container->type != C_VIEW && container->type != C_CONTAINER) { - return; - } - - swayc_t *workspace = swayc_parent_by_type(container, C_WORKSPACE); - swayc_t *op = workspace->parent; - swayc_t *parent = container->parent; - - struct wlc_geometry geometry = { - .origin = { - .x = container->x < op->width ? container->x : op->width-1, - .y = container->y < op->height ? container->y : op->height-1 - }, - .size = { - .w = container->width, - .h = container->height, - } - }; - - int gap = 0; - - // apply inner gaps to non-tabbed/stacked containers - swayc_t *p = swayc_tabbed_stacked_ancestor(container); - if (p == NULL) { - gap = update_gap_geometry(container, &geometry); - } - - swayc_t *output = swayc_parent_by_type(container, C_OUTPUT); - struct wlc_size size; - output_get_scaled_size(output->handle, &size); - - if (swayc_is_fullscreen(container)) { - geometry.origin.x = 0; - geometry.origin.y = 0; - geometry.size.w = size.w; - geometry.size.h = size.h; - if (op->focused == workspace) { - wlc_view_bring_to_front(container->handle); - } - - container->border_geometry = wlc_geometry_zero; - container->title_bar_geometry = wlc_geometry_zero; - border_clear(container->border); - } else if (container->is_floating) { // allocate border for floating window - update_border_geometry_floating(container, &geometry); - } else if (!container->is_floating) { // allocate border for titled window - container->border_geometry = geometry; - - int border_top = container->border_thickness; - int border_bottom = container->border_thickness; - int border_left = container->border_thickness; - int border_right = container->border_thickness; - - // handle hide_edge_borders - if (config->hide_edge_borders != E_NONE && (gap <= 0 || (config->smart_gaps && workspace->children->length == 1))) { - if (config->hide_edge_borders == E_VERTICAL || config->hide_edge_borders == E_BOTH) { - if (geometry.origin.x == workspace->x) { - border_left = 0; - } - - if (geometry.origin.x + geometry.size.w == workspace->x + workspace->width) { - border_right = 0; - } - } - - if (config->hide_edge_borders == E_HORIZONTAL || config->hide_edge_borders == E_BOTH) { - if (geometry.origin.y == workspace->y || should_hide_top_border(container, geometry.origin.y)) { - border_top = 0; - } - - if (geometry.origin.y + geometry.size.h == workspace->y + workspace->height) { - border_bottom = 0; - } - } - - if (config->hide_edge_borders == E_SMART && workspace->children->length == 1) { - border_top = 0; - border_bottom = 0; - border_left = 0; - border_right = 0; - } - } - - int title_bar_height = config->font_height + 4; //borders + padding - - if (parent->layout == L_TABBED && parent->children->length > 1) { - int i, x = 0, w, l, r; - l = parent->children->length; - w = geometry.size.w / l; - r = geometry.size.w % l; - for (i = 0; i < parent->children->length; ++i) { - swayc_t *view = parent->children->items[i]; - if (view == container) { - x = w * i; - if (i == l - 1) { - w += r; - } - break; - } - } - - struct wlc_geometry title_bar = { - .origin = { - .x = container->border_geometry.origin.x + x, - .y = container->border_geometry.origin.y - }, - .size = { - .w = w, - .h = title_bar_height - } - }; - geometry.origin.x += border_left; - geometry.origin.y += title_bar.size.h; - geometry.size.w -= (border_left + border_right); - geometry.size.h -= (border_bottom + title_bar.size.h); - container->title_bar_geometry = title_bar; - } else if (parent->layout == L_STACKED && parent->children->length > 1) { - int i, y = 0; - for (i = 0; i < parent->children->length; ++i) { - swayc_t *view = parent->children->items[i]; - if (view == container) { - y = title_bar_height * i; - } - } - - struct wlc_geometry title_bar = { - .origin = { - .x = container->border_geometry.origin.x, - .y = container->border_geometry.origin.y + y - }, - .size = { - .w = container->border_geometry.size.w, - .h = title_bar_height - } - }; - title_bar_height = title_bar_height * parent->children->length; - geometry.origin.x += border_left; - geometry.origin.y += title_bar_height; - geometry.size.w -= (border_left + border_right); - geometry.size.h -= (border_bottom + title_bar_height); - container->title_bar_geometry = title_bar; - } else { - switch (container->border_type) { - case B_NONE: - break; - case B_PIXEL: - geometry.origin.x += border_left; - geometry.origin.y += border_top; - geometry.size.w -= (border_left + border_right); - geometry.size.h -= (border_top + border_bottom); - break; - case B_NORMAL: - { - struct wlc_geometry title_bar = { - .origin = { - .x = container->border_geometry.origin.x, - .y = container->border_geometry.origin.y - }, - .size = { - .w = container->border_geometry.size.w, - .h = title_bar_height - } - }; - geometry.origin.x += border_left; - geometry.origin.y += title_bar.size.h; - geometry.size.w -= (border_left + border_right); - geometry.size.h -= (border_bottom + title_bar.size.h); - container->title_bar_geometry = title_bar; - break; - } - } - } - - container->actual_geometry = geometry; - - if (container->type == C_VIEW) { - update_container_border(container); - } - } - - if (container->type == C_VIEW) { - wlc_view_set_geometry(container->handle, 0, &geometry); - } -} - -/** - * Layout application prototypes - */ -static void apply_horiz_layout(swayc_t *container, const double x, - const double y, const double width, - const double height, const int start, - const int end); -static void apply_vert_layout(swayc_t *container, const double x, - const double y, const double width, - const double height, const int start, - const int end); -static void apply_tabbed_or_stacked_layout(swayc_t *container, double x, - double y, double width, - double height); - -static void apply_auto_layout(swayc_t *container, const double x, const double y, - const double width, const double height, - enum swayc_layouts group_layout, - bool master_first); - -static void arrange_windows_r(swayc_t *container, double width, double height) { - int i; - if (width == -1 || height == -1) { - swayc_log(L_DEBUG, container, "Arranging layout for %p", container); - width = container->width; - height = container->height; - } - // pixels are indivisible. if we don't round the pixels, then the view - // calculations will be off (e.g. 50.5 + 50.5 = 101, but in reality it's - // 50 + 50 = 100). doing it here cascades properly to all width/height/x/y. - width = floor(width); - height = floor(height); - - sway_log(L_DEBUG, "Arranging layout for %p %s %fx%f+%f,%f", container, - container->name, container->width, container->height, container->x, - container->y); - - double x = 0, y = 0; - switch (container->type) { - case C_ROOT: - for (i = 0; i < container->children->length; ++i) { - swayc_t *output = container->children->items[i]; - sway_log(L_DEBUG, "Arranging output '%s' at %f,%f", output->name, output->x, output->y); - arrange_windows_r(output, -1, -1); - } - return; - case C_OUTPUT: - { - struct wlc_size resolution; - output_get_scaled_size(container->handle, &resolution); - width = resolution.w; height = resolution.h; - // output must have correct size due to e.g. seamless mouse, - // but a workspace might be smaller depending on panels. - container->width = width; - container->height = height; - } - // arrange all workspaces: - for (i = 0; i < container->children->length; ++i) { - swayc_t *child = container->children->items[i]; - arrange_windows_r(child, -1, -1); - } - // Bring all unmanaged views to the front - for (i = 0; i < container->unmanaged->length; ++i) { - wlc_handle *handle = container->unmanaged->items[i]; - wlc_view_bring_to_front(*handle); - } - return; - case C_WORKSPACE: - { - swayc_t *output = swayc_parent_by_type(container, C_OUTPUT); - width = output->width, height = output->height; - /* TODO WLR - for (i = 0; i < desktop_shell.panels->length; ++i) { - struct panel_config *config = desktop_shell.panels->items[i]; - if (config->output == output->handle) { - struct wlc_size size = *wlc_surface_get_size(config->surface); - sway_log(L_DEBUG, "-> Found panel for this workspace: %ux%u, position: %u", size.w, size.h, config->panel_position); - switch (config->panel_position) { - case DESKTOP_SHELL_PANEL_POSITION_TOP: - y += size.h; height -= size.h; - break; - case DESKTOP_SHELL_PANEL_POSITION_BOTTOM: - height -= size.h; - break; - case DESKTOP_SHELL_PANEL_POSITION_LEFT: - x += size.w; width -= size.w; - break; - case DESKTOP_SHELL_PANEL_POSITION_RIGHT: - width -= size.w; - break; - } - } - } - */ - int gap = swayc_gap(container); - x = container->x = x + gap; - y = container->y = y + gap; - width = container->width = width - gap * 2; - height = container->height = height - gap * 2; - sway_log(L_DEBUG, "Arranging workspace '%s' at %f, %f", container->name, container->x, container->y); - } - // children are properly handled below - break; - case C_VIEW: - { - container->width = width; - container->height = height; - update_geometry(container); - sway_log(L_DEBUG, "Set view to %.f x %.f @ %.f, %.f", container->width, - container->height, container->x, container->y); - } - return; - default: - container->width = width; - container->height = height; - x = container->x; - y = container->y; - - // add gaps to top level tapped/stacked container - if (container->parent->type == C_WORKSPACE && - (container->layout == L_TABBED || container->layout == L_STACKED)) { - update_geometry(container); - width = container->border_geometry.size.w; - height = container->border_geometry.size.h; - x = container->border_geometry.origin.x; - y = container->border_geometry.origin.y; - } - - // update container size if it's a direct child in a tabbed/stacked layout - // if parent is a workspace, its actual_geometry won't be initialized - if (swayc_tabbed_stacked_parent(container) != NULL && - container->parent->type != C_WORKSPACE) { - // Use parent actual_geometry as a base for calculating - // container geometry - container->width = container->parent->actual_geometry.size.w; - container->height = container->parent->actual_geometry.size.h; - container->x = container->parent->actual_geometry.origin.x; - container->y = container->parent->actual_geometry.origin.y; - - update_geometry(container); - width = container->width = container->actual_geometry.size.w; - height = container->height = container->actual_geometry.size.h; - x = container->x = container->actual_geometry.origin.x; - y = container->y = container->actual_geometry.origin.y; - } - - break; - } - - switch (container->layout) { - case L_HORIZ: - default: - apply_horiz_layout(container, x, y, width, height, 0, - container->children->length); - break; - case L_VERT: - apply_vert_layout(container, x, y, width, height, 0, - container->children->length); - break; - case L_TABBED: - case L_STACKED: - apply_tabbed_or_stacked_layout(container, x, y, width, height); - break; - case L_AUTO_LEFT: - apply_auto_layout(container, x, y, width, height, L_VERT, true); - break; - case L_AUTO_RIGHT: - apply_auto_layout(container, x, y, width, height, L_VERT, false); - break; - case L_AUTO_TOP: - apply_auto_layout(container, x, y, width, height, L_HORIZ, true); - break; - case L_AUTO_BOTTOM: - apply_auto_layout(container, x, y, width, height, L_HORIZ, false); - break; - } - - // Arrage floating layouts for workspaces last - if (container->type == C_WORKSPACE) { - for (int i = 0; i < container->floating->length; ++i) { - swayc_t *view = container->floating->items[i]; - if (view->type == C_VIEW) { - update_geometry(view); - sway_log(L_DEBUG, "Set floating view to %.f x %.f @ %.f, %.f", - view->width, view->height, view->x, view->y); - if (swayc_is_fullscreen(view)) { - wlc_view_bring_to_front(view->handle); - } else if (!container->focused || - !swayc_is_fullscreen(container->focused)) { - wlc_view_bring_to_front(view->handle); - } - } - } - } -} - -void apply_horiz_layout(swayc_t *container, const double x, const double y, - const double width, const double height, - const int start, const int end) { - double scale = 0; - // Calculate total width - for (int i = start; i < end; ++i) { - double *old_width = &((swayc_t *)container->children->items[i])->width; - if (*old_width <= 0) { - if (end - start > 1) { - *old_width = width / (end - start - 1); - } else { - *old_width = width; - } - } - scale += *old_width; - } - scale = width / scale; - - // Resize windows - double child_x = x; - if (scale > 0.1) { - sway_log(L_DEBUG, "Arranging %p horizontally", container); - swayc_t *focused = NULL; - for (int i = start; i < end; ++i) { - swayc_t *child = container->children->items[i]; - sway_log(L_DEBUG, - "Calculating arrangement for %p:%d (will scale %f by %f)", child, - child->type, width, scale); - child->x = child_x; - child->y = y; - - if (child == container->focused) { - focused = child; - } - - if (i == end - 1) { - double remaining_width = x + width - child_x; - arrange_windows_r(child, remaining_width, height); - } else { - arrange_windows_r(child, child->width * scale, height); - } - child_x += child->width; - } - - // update focused view border last because it may - // depend on the title bar geometry of its siblings. - if (focused && container->children->length > 1) { - update_container_border(focused); - } - } -} - -void apply_vert_layout(swayc_t *container, const double x, const double y, - const double width, const double height, const int start, - const int end) { - int i; - double scale = 0; - // Calculate total height - for (i = start; i < end; ++i) { - double *old_height = &((swayc_t *)container->children->items[i])->height; - if (*old_height <= 0) { - if (end - start > 1) { - *old_height = height / (end - start - 1); - } else { - *old_height = height; - } - } - scale += *old_height; - } - scale = height / scale; - - // Resize - double child_y = y; - if (scale > 0.1) { - sway_log(L_DEBUG, "Arranging %p vertically", container); - swayc_t *focused = NULL; - for (i = start; i < end; ++i) { - swayc_t *child = container->children->items[i]; - sway_log(L_DEBUG, - "Calculating arrangement for %p:%d (will scale %f by %f)", child, - child->type, height, scale); - child->x = x; - child->y = child_y; - - if (child == container->focused) { - focused = child; - } - - if (i == end - 1) { - double remaining_height = y + height - child_y; - arrange_windows_r(child, width, remaining_height); - } else { - arrange_windows_r(child, width, child->height * scale); - } - child_y += child->height; - } - - // update focused view border last because it may - // depend on the title bar geometry of its siblings. - if (focused && container->children->length > 1) { - update_container_border(focused); - } - } -} - -void apply_tabbed_or_stacked_layout(swayc_t *container, double x, double y, - double width, double height) { - int i; - swayc_t *focused = NULL; - for (i = 0; i < container->children->length; ++i) { - swayc_t *child = container->children->items[i]; - child->x = x; - child->y = y; - if (child == container->focused) { - focused = child; - } else { - arrange_windows_r(child, width, height); - } - } - - if (focused) { - arrange_windows_r(focused, width, height); - } -} - -void apply_auto_layout(swayc_t *container, const double x, const double y, - const double width, const double height, - enum swayc_layouts group_layout, - bool master_first) { - // Auto layout "container" in width x height @ x, y - // using "group_layout" for each of the groups in the container. - // There is one "master" group, plus container->nb_slave_groups. - // Each group is layed out side by side following the "major" axis. - // The direction of the layout used for groups is the "minor" axis. - // Example: - // - // ---- major axis --> - // +---------+-----------+ - // | | | | - // | master | slave 1 | | - // | +-----------+ | minor axis (direction of group_layout) - // | | | | - // | | slave 2 | V - // +---------+-----------+ - // - // container with three children (one master and two slaves) and - // a single slave group (containing slave 1 and 2). The master - // group and slave group are layed out using L_VERT. - - size_t nb_groups = auto_group_count(container); - - // the target dimension of the container along the "major" axis, each - // group in the container will be layed out using "group_layout" along - // the "minor" axis. - double dim_maj; - double pos_maj; - - // x and y coords for the next group to be laid out. - const double *group_x, *group_y; - - // pos of the next group to layout along the major axis - double pos; - - // size of the next group along the major axis. - double group_dim; - - // height and width of next group to be laid out. - const double *group_h, *group_w; - - switch (group_layout) { - default: - sway_log(L_DEBUG, "Unknown layout type (%d) used in %s()", - group_layout, __func__); - /* fall through */ - case L_VERT: - dim_maj = width; - pos_maj = x; - - group_x = &pos; - group_y = &y; - group_w = &group_dim; - group_h = &height; - break; - case L_HORIZ: - dim_maj = height; - pos_maj = y; - - group_x = &x; - group_y = &pos; - group_w = &width; - group_h = &group_dim; - break; - } - - /* Determine the dimension of each of the groups in the layout. - * Dimension will be width for a VERT layout and height for a HORIZ - * layout. */ - double old_group_dim[nb_groups]; - double old_dim = 0; - for (size_t group = 0; group < nb_groups; ++group) { - int idx; - if (auto_group_bounds(container, group, &idx, NULL)) { - swayc_t *child = container->children->items[idx]; - double *dim = group_layout == L_HORIZ ? &child->height : &child->width; - if (*dim <= 0) { - // New child with uninitialized dimension - *dim = dim_maj; - if (nb_groups > 1) { - // child gets a dimension proportional to existing groups, - // it will be later scaled based on to the available size - // in the major axis. - *dim /= (nb_groups - 1); - } - } - old_dim += *dim; - old_group_dim[group] = *dim; - } - } - double scale = dim_maj / old_dim; - - /* Apply layout to each group */ - pos = pos_maj; - - for (size_t group = 0; group < nb_groups; ++group) { - int start, end; // index of first (inclusive) and last (exclusive) child in the group - if (auto_group_bounds(container, group, &start, &end)) { - // adjusted size of the group - group_dim = old_group_dim[group] * scale; - if (group == nb_groups - 1) { - group_dim = pos_maj + dim_maj - pos; // remaining width - } - sway_log(L_DEBUG, "Arranging container %p column %zu, children [%d,%d[ (%fx%f+%f,%f)", - container, group, start, end, *group_w, *group_h, *group_x, *group_y); - switch (group_layout) { - default: - case L_VERT: - apply_vert_layout(container, *group_x, *group_y, *group_w, *group_h, start, end); - break; - case L_HORIZ: - apply_horiz_layout(container, *group_x, *group_y, *group_w, *group_h, start, end); - break; - } - - /* update position for next group */ - pos += group_dim; - } - } -} - -void arrange_windows(swayc_t *container, double width, double height) { - update_visibility(container); - arrange_windows_r(container, width, height); - layout_log(&root_container, 0); -} - -void arrange_backgrounds(void) { - /* TODO WLR - struct background_config *bg; - for (int i = 0; i < desktop_shell.backgrounds->length; ++i) { - bg = desktop_shell.backgrounds->items[i]; - wlc_view_send_to_back(bg->handle); - } - */ -} - -/** - * Get swayc in the direction of newly entered output. - */ -static swayc_t *get_swayc_in_output_direction(swayc_t *output, enum movement_direction dir) { - if (!output) { - return NULL; - } - - swayc_t *ws = swayc_focus_by_type(output, C_WORKSPACE); - if (ws && ws->children->length > 0) { - switch (dir) { - case MOVE_LEFT: - // get most right child of new output - return ws->children->items[ws->children->length-1]; - case MOVE_RIGHT: - // get most left child of new output - return ws->children->items[0]; - case MOVE_UP: - case MOVE_DOWN: - { - swayc_t *focused_view = swayc_focus_by_type(ws, C_VIEW); - if (focused_view && focused_view->parent) { - swayc_t *parent = focused_view->parent; - if (parent->layout == L_VERT) { - if (dir == MOVE_UP) { - // get child furthest down on new output - return parent->children->items[parent->children->length-1]; - } else if (dir == MOVE_DOWN) { - // get child furthest up on new output - return parent->children->items[0]; - } - } - return focused_view; - } - break; - } - default: - break; - } - } - - return output; -} - -swayc_t *get_swayc_in_direction_under(swayc_t *container, enum movement_direction dir, swayc_t *limit) { - if (dir == MOVE_CHILD) { - return container->focused; - } - - swayc_t *parent = container->parent; - if (dir == MOVE_PARENT) { - if (parent->type == C_OUTPUT) { - return NULL; - } else { - return parent; - } - } - - if (dir == MOVE_PREV || dir == MOVE_NEXT) { - int focused_idx = index_child(container); - if (focused_idx == -1) { - return NULL; - } else { - int desired = (focused_idx + (dir == MOVE_NEXT ? 1 : -1)) % - parent->children->length; - if (desired < 0) { - desired += parent->children->length; - } - return parent->children->items[desired]; - } - } - - // If moving to an adjacent output we need a starting position (since this - // output might border to multiple outputs). - struct wlc_point abs_pos; - get_absolute_center_position(container, &abs_pos); - - if (container->type == C_VIEW && swayc_is_fullscreen(container)) { - sway_log(L_DEBUG, "Moving from fullscreen view, skipping to output"); - container = swayc_parent_by_type(container, C_OUTPUT); - get_absolute_center_position(container, &abs_pos); - swayc_t *output = swayc_adjacent_output(container, dir, &abs_pos, true); - return get_swayc_in_output_direction(output, dir); - } - - if (container->type == C_WORKSPACE && container->fullscreen) { - sway_log(L_DEBUG, "Moving to fullscreen view"); - return container->fullscreen; - } - - swayc_t *wrap_candidate = NULL; - while (true) { - // Test if we can even make a difference here - bool can_move = false; - int desired; - int idx = index_child(container); - if (parent->type == C_ROOT) { - swayc_t *output = swayc_adjacent_output(container, dir, &abs_pos, true); - if (!output || output == container) { - return wrap_candidate; - } - sway_log(L_DEBUG, "Moving between outputs"); - return get_swayc_in_output_direction(output, dir); - } else { - if (is_auto_layout(parent->layout)) { - bool is_major = parent->layout == L_AUTO_LEFT || parent->layout == L_AUTO_RIGHT - ? dir == MOVE_LEFT || dir == MOVE_RIGHT - : dir == MOVE_DOWN || dir == MOVE_UP; - size_t gidx = auto_group_index(parent, idx); - if (is_major) { - size_t desired_grp = gidx + (dir == MOVE_RIGHT || dir == MOVE_DOWN ? 1 : -1); - can_move = auto_group_bounds(parent, desired_grp, &desired, NULL); - } else { - desired = idx + (dir == MOVE_RIGHT || dir == MOVE_DOWN ? 1 : -1); - int start, end; - can_move = auto_group_bounds(parent, gidx, &start, &end) - && desired >= start && desired < end; - } - } else { - if (dir == MOVE_LEFT || dir == MOVE_RIGHT) { - if (parent->layout == L_HORIZ || parent->layout == L_TABBED) { - can_move = true; - desired = idx + (dir == MOVE_LEFT ? -1 : 1); - } - } else { - if (parent->layout == L_VERT || parent->layout == L_STACKED) { - can_move = true; - desired = idx + (dir == MOVE_UP ? -1 : 1); - } - } - } - } - - if (can_move) { - if (container->is_floating) { - if (desired < 0) { - wrap_candidate = parent->floating->items[parent->floating->length-1]; - } else if (desired >= parent->floating->length){ - wrap_candidate = parent->floating->items[0]; - } else { - wrap_candidate = parent->floating->items[desired]; - } - if (wrap_candidate) { - wlc_view_bring_to_front(wrap_candidate->handle); - } - return wrap_candidate; - } else if (desired < 0 || desired >= parent->children->length) { - can_move = false; - int len = parent->children->length; - if (!wrap_candidate && len > 1) { - if (desired < 0) { - wrap_candidate = parent->children->items[len-1]; - } else { - wrap_candidate = parent->children->items[0]; - } - if (config->force_focus_wrapping) { - return wrap_candidate; - } - } - } else { - sway_log(L_DEBUG, "%s cont %d-%p dir %i sibling %d: %p", __func__, - idx, container, dir, desired, parent->children->items[desired]); - return parent->children->items[desired]; - } - } - if (!can_move) { - container = parent; - parent = parent->parent; - if (!parent || container == limit) { - // wrapping is the last chance - return wrap_candidate; - } - } - } -} - -swayc_t *get_swayc_in_direction(swayc_t *container, enum movement_direction dir) { - return get_swayc_in_direction_under(container, dir, NULL); -} - -void recursive_resize(swayc_t *container, double amount, enum wlc_resize_edge edge) { - int i; - bool layout_match = true; - sway_log(L_DEBUG, "Resizing %p with amount: %f", container, amount); - if (edge == WLC_RESIZE_EDGE_LEFT || edge == WLC_RESIZE_EDGE_RIGHT) { - container->width += amount; - layout_match = container->layout == L_HORIZ; - } else if (edge == WLC_RESIZE_EDGE_TOP || edge == WLC_RESIZE_EDGE_BOTTOM) { - container->height += amount; - layout_match = container->layout == L_VERT; - } - if (container->type == C_VIEW) { - update_geometry(container); - return; - } - if (layout_match) { - for (i = 0; i < container->children->length; i++) { - recursive_resize(container->children->items[i], amount/container->children->length, edge); - } - } else { - for (i = 0; i < container->children->length; i++) { - recursive_resize(container->children->items[i], amount, edge); - } - } -} - -enum swayc_layouts default_layout(swayc_t *output) { - if (config->default_layout != L_NONE) { - return config->default_layout; - } else if (config->default_orientation != L_NONE) { - return config->default_orientation; - } else if (output->width >= output->height) { - return L_HORIZ; - } else { - return L_VERT; - } -} - -bool is_auto_layout(enum swayc_layouts layout) { - return (layout >= L_AUTO_FIRST) && (layout <= L_AUTO_LAST); -} - -/** - * Return the number of master elements in a container - */ -static inline size_t auto_master_count(const swayc_t *container) { - sway_assert(container->children->length >= 0, "Container %p has (negative) children %d", - container, container->children->length); - return MIN(container->nb_master, (size_t)container->children->length); -} - -/** - * Return the number of children in the slave groups. This corresponds to the children - * that are not members of the master group. - */ -static inline size_t auto_slave_count(const swayc_t *container) { - return container->children->length - auto_master_count(container); -} - -/** - * Return the number of slave groups in the container. - */ -size_t auto_slave_group_count(const swayc_t *container) { - return MIN(container->nb_slave_groups, auto_slave_count(container)); -} - -/** - * Return the combined number of master and slave groups in the container. - */ -size_t auto_group_count(const swayc_t *container) { - return auto_slave_group_count(container) - + (container->children->length && container->nb_master ? 1 : 0); -} - -/** - * given the index of a container's child, return the index of the first child of the group - * which index is a member of. - */ -int auto_group_start_index(const swayc_t *container, int index) { - if (index < 0 || ! is_auto_layout(container->layout) - || (size_t)index < container->nb_master) { - return 0; - } else { - size_t nb_slaves = auto_slave_count(container); - size_t nb_slave_grp = auto_slave_group_count(container); - size_t grp_sz = nb_slaves / nb_slave_grp; - size_t remainder = nb_slaves % nb_slave_grp; - int idx2 = (nb_slave_grp - remainder) * grp_sz + container->nb_master; - int start_idx; - if (index < idx2) { - start_idx = ((index - container->nb_master) / grp_sz) * grp_sz + container->nb_master; - } else { - start_idx = idx2 + ((index - idx2) / (grp_sz + 1)) * (grp_sz + 1); - } - return MIN(start_idx, container->children->length); - } -} - -/** - * given the index of a container's child, return the index of the first child of the group - * that follows the one which index is a member of. - * This makes the function usable to walk through the groups in a container. - */ -int auto_group_end_index(const swayc_t *container, int index) { - if (index < 0 || ! is_auto_layout(container->layout)) { - return container->children->length; - } else { - int nxt_idx; - if ((size_t)index < container->nb_master) { - nxt_idx = auto_master_count(container); - } else { - size_t nb_slaves = auto_slave_count(container); - size_t nb_slave_grp = auto_slave_group_count(container); - size_t grp_sz = nb_slaves / nb_slave_grp; - size_t remainder = nb_slaves % nb_slave_grp; - int idx2 = (nb_slave_grp - remainder) * grp_sz + container->nb_master; - if (index < idx2) { - nxt_idx = ((index - container->nb_master) / grp_sz + 1) * grp_sz + container->nb_master; - } else { - nxt_idx = idx2 + ((index - idx2) / (grp_sz + 1) + 1) * (grp_sz + 1); - } - } - return MIN(nxt_idx, container->children->length); - } -} - -/** - * return the index of the Group containing th child of . - * The index is the order of the group along the container's major axis (starting at 0). - */ -size_t auto_group_index(const swayc_t *container, int index) { - if (index < 0) { - return 0; - } - bool master_first = (container->layout == L_AUTO_LEFT || container->layout == L_AUTO_TOP); - size_t nb_slaves = auto_slave_count(container); - if ((size_t)index < container->nb_master) { - if (master_first || nb_slaves <= 0) { - return 0; - } else { - return auto_slave_group_count(container); - } - } else { - size_t nb_slave_grp = auto_slave_group_count(container); - size_t grp_sz = nb_slaves / nb_slave_grp; - size_t remainder = nb_slaves % nb_slave_grp; - int idx2 = (nb_slave_grp - remainder) * grp_sz + container->nb_master; - size_t grp_idx; - if (index < idx2) { - grp_idx = (index - container->nb_master) / grp_sz; - } else { - grp_idx = (nb_slave_grp - remainder) + (index - idx2) / (grp_sz + 1) ; - } - return grp_idx + (master_first && container-> nb_master ? 1 : 0); - } -} - -/** - * Return the first index (inclusive) and last index (exclusive) of the elements of a group in - * an auto layout. - * If the bounds of the given group can be calculated, they are returned in the start/end - * parameters (int pointers) and the return value will be true. - * The indexes are passed by reference and can be NULL. - */ -bool auto_group_bounds(const swayc_t *container, size_t group_index, int *start, int *end) { - size_t nb_grp = auto_group_count(container); - if (group_index >= nb_grp) { - return false; - } - bool master_first = (container->layout == L_AUTO_LEFT || container->layout == L_AUTO_TOP); - size_t nb_master = auto_master_count(container); - size_t nb_slave_grp = auto_slave_group_count(container); - int g_start, g_end; - if (nb_master && (master_first ? group_index == 0 : group_index == nb_grp - 1)) { - g_start = 0; - g_end = nb_master; - } else { - size_t nb_slaves = auto_slave_count(container); - size_t grp_sz = nb_slaves / nb_slave_grp; - size_t remainder = nb_slaves % nb_slave_grp; - size_t g0 = master_first && container->nb_master ? 1 : 0; - size_t g1 = g0 + nb_slave_grp - remainder; - if (group_index < g1) { - g_start = container->nb_master + (group_index - g0) * grp_sz; - g_end = g_start + grp_sz; - } else { - size_t g2 = group_index - g1; - g_start = container->nb_master - + (nb_slave_grp - remainder) * grp_sz - + g2 * (grp_sz + 1); - g_end = g_start + grp_sz + 1; - } - } - if (start) { - *start = g_start; - } - if (end) { - *end = g_end; - } - return true; -} diff --git a/sway/tree/output.c b/sway/tree/output.c deleted file mode 100644 index edfcac98..00000000 --- a/sway/tree/output.c +++ /dev/null @@ -1,278 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include "sway/output.h" -#include "log.h" -#include "list.h" - -void output_get_scaled_size(wlc_handle handle, struct wlc_size *size) { - *size = *wlc_output_get_resolution(handle); - uint32_t scale = wlc_output_get_scale(handle); - size->w /= scale; - size->h /= scale; -} - -swayc_t *output_by_name(const char* name, const struct wlc_point *abs_pos) { - swayc_t *output = NULL; - // If there is no output directly next to the current one, use - // swayc_opposite_output to wrap. - if (strcasecmp(name, "left") == 0) { - output = swayc_adjacent_output(NULL, MOVE_LEFT, abs_pos, true); - if (!output) { - output = swayc_opposite_output(MOVE_RIGHT, abs_pos); - } - } else if (strcasecmp(name, "right") == 0) { - output = swayc_adjacent_output(NULL, MOVE_RIGHT, abs_pos, true); - if (!output) { - output = swayc_opposite_output(MOVE_LEFT, abs_pos); - } - } else if (strcasecmp(name, "up") == 0) { - output = swayc_adjacent_output(NULL, MOVE_UP, abs_pos, true); - if (!output) { - output = swayc_opposite_output(MOVE_DOWN, abs_pos); - } - } else if (strcasecmp(name, "down") == 0) { - output = swayc_adjacent_output(NULL, MOVE_DOWN, abs_pos, true); - if (!output) { - output = swayc_opposite_output(MOVE_UP, abs_pos); - } - } else { - for(int i = 0; i < root_container.children->length; ++i) { - swayc_t *c = root_container.children->items[i]; - if (c->type == C_OUTPUT && strcasecmp(c->name, name) == 0) { - return c; - } - } - } - return output; -} - -swayc_t *swayc_opposite_output(enum movement_direction dir, - const struct wlc_point *abs_pos) { - - // Search through all the outputs and pick the output whose edge covers the - // given position, and is at leftmost/rightmost/upmost/downmost side of the - // screen (decided by the direction given). - swayc_t *opposite = NULL; - char *dir_text = NULL; - switch(dir) { - case MOVE_LEFT: - case MOVE_RIGHT: ; - for (int i = 0; i < root_container.children->length; ++i) { - swayc_t *c = root_container.children->items[i]; - if (abs_pos->y >= c->y && abs_pos->y <= c->y + c->height) { - if (!opposite) { - opposite = c; - } else if ((dir == MOVE_LEFT && c->x < opposite->x) - || (dir == MOVE_RIGHT && c->x > opposite->x)) { - opposite = c; - } - } - } - dir_text = dir == MOVE_LEFT ? "leftmost" : "rightmost"; - break; - case MOVE_UP: - case MOVE_DOWN: ; - for (int i = 0; i < root_container.children->length; ++i) { - swayc_t *c = root_container.children->items[i]; - if (abs_pos->x >= c->x && abs_pos->x <= c->x + c->width) { - if (!opposite) { - opposite = c; - } else if ((dir == MOVE_UP && c->y < opposite->y) - || (dir == MOVE_DOWN && c->y > opposite->y)) { - opposite = c; - } - } - } - dir_text = dir == MOVE_UP ? "upmost" : "downmost"; - break; - default: - sway_abort("Function called with invalid argument."); - break; - } - if (opposite) { - sway_log(L_DEBUG, "%s (%.0fx%.0f+%.0f+%.0f) is %s from y-position %i", - opposite->name, opposite->width, opposite->height, opposite->x, opposite->y, - dir_text, abs_pos->y); - } - return opposite; -} - -// Position is where on the edge (as absolute position) the adjacent output should be searched for. -swayc_t *swayc_adjacent_output(swayc_t *output, enum movement_direction dir, - const struct wlc_point *abs_pos, bool pick_closest) { - - if (!output) { - output = swayc_active_output(); - } - // In order to find adjacent outputs we need to test that the outputs are - // aligned on one axis (decided by the direction given) and that the given - // position is within the edge of the adjacent output. If no such output - // exists we pick the adjacent output within the edge that is closest to - // the given position, if any. - swayc_t *adjacent = NULL; - char *dir_text = NULL; - switch(dir) { - case MOVE_LEFT: - case MOVE_RIGHT: ; - double delta_y = 0; - for(int i = 0; i < root_container.children->length; ++i) { - swayc_t *c = root_container.children->items[i]; - if (c == output || c->type != C_OUTPUT) { - continue; - } - bool x_aligned = dir == MOVE_LEFT ? - c->x + c->width == output->x : - c->x == output->x + output->width; - if (!x_aligned) { - continue; - } - if (abs_pos->y >= c->y && abs_pos->y <= c->y + c->height) { - delta_y = 0; - adjacent = c; - break; - } else if (pick_closest) { - // track closest adjacent output - double top_y = c->y, bottom_y = c->y + c->height; - if (top_y >= output->y && top_y <= output->y + output->height) { - double delta = top_y - abs_pos->y; - if (delta < 0) delta = -delta; - if (delta < delta_y || !adjacent) { - delta_y = delta; - adjacent = c; - } - } - // we check both points and pick the closest - if (bottom_y >= output->y && bottom_y <= output->y + output->height) { - double delta = bottom_y - abs_pos->y; - if (delta < 0) delta = -delta; - if (delta < delta_y || !adjacent) { - delta_y = delta; - adjacent = c; - } - } - } - } - dir_text = dir == MOVE_LEFT ? "left of" : "right of"; - if (adjacent && delta_y == 0) { - sway_log(L_DEBUG, "%s (%.0fx%.0f+%.0f+%.0f) is %s current output %s (y-position %i)", - adjacent->name, adjacent->width, adjacent->height, adjacent->x, adjacent->y, - dir_text, output->name, abs_pos->y); - } else if (adjacent) { - // so we end up picking the closest adjacent output because - // there is no directly adjacent to the given position - sway_log(L_DEBUG, "%s (%.0fx%.0f+%.0f+%.0f) is %s current output %s (y-position %i, delta: %.0f)", - adjacent->name, adjacent->width, adjacent->height, adjacent->x, adjacent->y, - dir_text, output->name, abs_pos->y, delta_y); - } - break; - case MOVE_UP: - case MOVE_DOWN: ; - double delta_x = 0; - for(int i = 0; i < root_container.children->length; ++i) { - swayc_t *c = root_container.children->items[i]; - if (c == output || c->type != C_OUTPUT) { - continue; - } - bool y_aligned = dir == MOVE_UP ? - c->y + c->height == output->y : - c->y == output->y + output->height; - if (!y_aligned) { - continue; - } - if (abs_pos->x >= c->x && abs_pos->x <= c->x + c->width) { - delta_x = 0; - adjacent = c; - break; - } else if (pick_closest) { - // track closest adjacent output - double left_x = c->x, right_x = c->x + c->width; - if (left_x >= output->x && left_x <= output->x + output->width) { - double delta = left_x - abs_pos->x; - if (delta < 0) delta = -delta; - if (delta < delta_x || !adjacent) { - delta_x = delta; - adjacent = c; - } - } - // we check both points and pick the closest - if (right_x >= output->x && right_x <= output->x + output->width) { - double delta = right_x - abs_pos->x; - if (delta < 0) delta = -delta; - if (delta < delta_x || !adjacent) { - delta_x = delta; - adjacent = c; - } - } - } - } - dir_text = dir == MOVE_UP ? "above" : "below"; - if (adjacent && delta_x == 0) { - sway_log(L_DEBUG, "%s (%.0fx%.0f+%.0f+%.0f) is %s current output %s (x-position %i)", - adjacent->name, adjacent->width, adjacent->height, adjacent->x, adjacent->y, - dir_text, output->name, abs_pos->x); - } else if (adjacent) { - // so we end up picking the closest adjacent output because - // there is no directly adjacent to the given position - sway_log(L_DEBUG, "%s (%.0fx%.0f+%.0f+%.0f) is %s current output %s (x-position %i, delta: %.0f)", - adjacent->name, adjacent->width, adjacent->height, adjacent->x, adjacent->y, - dir_text, output->name, abs_pos->x, delta_x); - } - break; - default: - sway_abort("Function called with invalid argument."); - break; - } - return adjacent; -} - -void get_absolute_position(swayc_t *container, struct wlc_point *point) { - if (!container || !point) - sway_abort("Need container and wlc_point (was %p, %p).", container, point); - - if (container->type == C_OUTPUT) { - // Coordinates are already absolute. - point->x = container->x; - point->y = container->y; - } else { - swayc_t *output = swayc_parent_by_type(container, C_OUTPUT); - if (container->type == C_WORKSPACE) { - // Workspace coordinates are actually wrong/arbitrary, but should - // be same as output. - point->x = output->x; - point->y = output->y; - } else { - point->x = output->x + container->x; - point->y = output->y + container->y; - } - } -} - -void get_absolute_center_position(swayc_t *container, struct wlc_point *point) { - get_absolute_position(container, point); - point->x += container->width/2; - point->y += container->height/2; -} - -static int sort_workspace_cmp_qsort(const void *_a, const void *_b) { - swayc_t *a = *(void **)_a; - swayc_t *b = *(void **)_b; - int retval = 0; - - if (isdigit(a->name[0]) && isdigit(b->name[0])) { - int a_num = strtol(a->name, NULL, 10); - int b_num = strtol(b->name, NULL, 10); - retval = (a_num < b_num) ? -1 : (a_num > b_num); - } else if (isdigit(a->name[0])) { - retval = -1; - } else if (isdigit(b->name[0])) { - retval = 1; - } - - return retval; -} - -void sort_workspaces(swayc_t *output) { - list_stable_sort(output->children, sort_workspace_cmp_qsort); -} diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c deleted file mode 100644 index 14cde146..00000000 --- a/sway/tree/workspace.c +++ /dev/null @@ -1,373 +0,0 @@ -#define _XOPEN_SOURCE 500 -#include -#include -#include -#include -#include -#include -#include -#include -#include "sway/ipc-server.h" -#include "sway/workspace.h" -#include "sway/layout.h" -#include "sway/container.h" -#include "sway/handlers.h" -#include "sway/config.h" -#include "sway/focus.h" -#include "stringop.h" -#include "util.h" -#include "list.h" -#include "log.h" -#include "ipc.h" - -char *prev_workspace_name = NULL; -struct workspace_by_number_data { - int len; - const char *cset; - const char *name; -}; - -static bool workspace_valid_on_output(const char *output_name, const char *ws_name) { - int i; - for (i = 0; i < config->workspace_outputs->length; ++i) { - struct workspace_output *wso = config->workspace_outputs->items[i]; - if (strcasecmp(wso->workspace, ws_name) == 0) { - if (strcasecmp(wso->output, output_name) != 0) { - return false; - } - } - } - - return true; -} - -char *workspace_next_name(const char *output_name) { - sway_log(L_DEBUG, "Workspace: Generating new workspace name for output %s", output_name); - int i; - int l = 1; - // Scan all workspace bindings to find the next available workspace name, - // if none are found/available then default to a number - struct sway_mode *mode = config->current_mode; - - int order = INT_MAX; - char *target = NULL; - for (i = 0; i < mode->bindings->length; ++i) { - struct sway_binding *binding = mode->bindings->items[i]; - char *cmdlist = strdup(binding->command); - char *dup = cmdlist; - char *name = NULL; - - // workspace n - char *cmd = argsep(&cmdlist, " "); - if (cmdlist) { - name = argsep(&cmdlist, ",;"); - } - - if (strcmp("workspace", cmd) == 0 && name) { - sway_log(L_DEBUG, "Got valid workspace command for target: '%s'", name); - char *_target = strdup(name); - strip_quotes(_target); - while (isspace(*_target)) - _target++; - - // Make sure that the command references an actual workspace - // not a command about workspaces - if (strcmp(_target, "next") == 0 || - strcmp(_target, "prev") == 0 || - strcmp(_target, "next_on_output") == 0 || - strcmp(_target, "prev_on_output") == 0 || - strcmp(_target, "number") == 0 || - strcmp(_target, "back_and_forth") == 0 || - strcmp(_target, "current") == 0) - { - free(_target); - free(dup); - continue; - } - - // Make sure that the workspace doesn't already exist - if (workspace_by_name(_target)) { - free(_target); - free(dup); - continue; - } - - // make sure that the workspace can appear on the given - // output - if (!workspace_valid_on_output(output_name, _target)) { - free(_target); - free(dup); - continue; - } - - if (binding->order < order) { - order = binding->order; - free(target); - target = _target; - sway_log(L_DEBUG, "Workspace: Found free name %s", _target); - } - } - free(dup); - } - if (target != NULL) { - return target; - } - // As a fall back, get the current number of active workspaces - // and return that + 1 for the next workspace's name - int ws_num = root_container.children->length; - if (ws_num >= 10) { - l = 2; - } else if (ws_num >= 100) { - l = 3; - } - char *name = malloc(l + 1); - if (!name) { - sway_log(L_ERROR, "Could not allocate workspace name"); - return NULL; - } - sprintf(name, "%d", ws_num++); - return name; -} - -swayc_t *workspace_create(const char* name) { - swayc_t *parent; - // Search for workspace<->output pair - int i, e = config->workspace_outputs->length; - for (i = 0; i < e; ++i) { - struct workspace_output *wso = config->workspace_outputs->items[i]; - if (strcasecmp(wso->workspace, name) == 0) - { - // Find output to use if it exists - e = root_container.children->length; - for (i = 0; i < e; ++i) { - parent = root_container.children->items[i]; - if (strcmp(parent->name, wso->output) == 0) { - return new_workspace(parent, name); - } - } - break; - } - } - // Otherwise create a new one - parent = get_focused_container(&root_container); - parent = swayc_parent_by_type(parent, C_OUTPUT); - return new_workspace(parent, name); -} - -static bool _workspace_by_name(swayc_t *view, void *data) { - return (view->type == C_WORKSPACE) && - (strcasecmp(view->name, (char *) data) == 0); -} - -swayc_t *workspace_by_name(const char* name) { - if (strcmp(name, "prev") == 0) { - return workspace_prev(); - } - else if (strcmp(name, "prev_on_output") == 0) { - return workspace_output_prev(); - } - else if (strcmp(name, "next") == 0) { - return workspace_next(); - } - else if (strcmp(name, "next_on_output") == 0) { - return workspace_output_next(); - } - else if (strcmp(name, "current") == 0) { - return swayc_active_workspace(); - } - else { - return swayc_by_test(&root_container, _workspace_by_name, (void *) name); - } -} - -static bool _workspace_by_number(swayc_t *view, void *data) { - if (view->type != C_WORKSPACE) { - return false; - } - struct workspace_by_number_data *wbnd = data; - int a = strspn(view->name, wbnd->cset); - return a == wbnd->len && strncmp(view->name, wbnd->name, a) == 0; -} -swayc_t *workspace_by_number(const char* name) { - struct workspace_by_number_data wbnd = {0, "1234567890", name}; - wbnd.len = strspn(name, wbnd.cset); - if (wbnd.len <= 0) { - return NULL; - } - return swayc_by_test(&root_container, _workspace_by_number, (void *) &wbnd); -} - -/** - * Get the previous or next workspace on the specified output. - * Wraps around at the end and beginning. - * If next is false, the previous workspace is returned, otherwise the next one is returned. - */ -swayc_t *workspace_output_prev_next_impl(swayc_t *output, bool next) { - if (!sway_assert(output->type == C_OUTPUT, "Argument must be an output, is %d", output->type)) { - return NULL; - } - - int i; - for (i = 0; i < output->children->length; i++) { - if (output->children->items[i] == output->focused) { - return output->children->items[wrap(i + (next ? 1 : -1), output->children->length)]; - } - } - - // Doesn't happen, at worst the for loop returns the previously active workspace - return NULL; -} - -/** - * Get the previous or next workspace. If the first/last workspace on an output is active, - * proceed to the previous/next output's previous/next workspace. - * If next is false, the previous workspace is returned, otherwise the next one is returned. - */ -swayc_t *workspace_prev_next_impl(swayc_t *workspace, bool next) { - if (!sway_assert(workspace->type == C_WORKSPACE, "Argument must be a workspace, is %d", workspace->type)) { - return NULL; - } - - swayc_t *current_output = workspace->parent; - int offset = next ? 1 : -1; - int start = next ? 0 : 1; - int end = next ? (current_output->children->length) - 1 : current_output->children->length; - int i; - for (i = start; i < end; i++) { - if (current_output->children->items[i] == workspace) { - return current_output->children->items[i + offset]; - } - } - - // Given workspace is the first/last on the output, jump to the previous/next output - int num_outputs = root_container.children->length; - for (i = 0; i < num_outputs; i++) { - if (root_container.children->items[i] == current_output) { - swayc_t *next_output = root_container.children->items[wrap(i + offset, num_outputs)]; - return workspace_output_prev_next_impl(next_output, next); - } - } - - // Doesn't happen, at worst the for loop returns the previously active workspace on the active output - return NULL; -} - -swayc_t *workspace_output_next() { - return workspace_output_prev_next_impl(swayc_active_output(), true); -} - -swayc_t *workspace_next() { - return workspace_prev_next_impl(swayc_active_workspace(), true); -} - -swayc_t *workspace_output_prev() { - return workspace_output_prev_next_impl(swayc_active_output(), false); -} - -swayc_t *workspace_prev() { - return workspace_prev_next_impl(swayc_active_workspace(), false); -} - -bool workspace_switch(swayc_t *workspace) { - if (!workspace) { - return false; - } - swayc_t *active_ws = swayc_active_workspace(); - if (config->auto_back_and_forth && active_ws == workspace && prev_workspace_name) { - swayc_t *new_ws = workspace_by_name(prev_workspace_name); - workspace = new_ws ? new_ws : workspace_create(prev_workspace_name); - } - - if (!prev_workspace_name - || (strcmp(prev_workspace_name, active_ws->name) - && active_ws != workspace)) { - free(prev_workspace_name); - prev_workspace_name = malloc(strlen(active_ws->name) + 1); - if (!prev_workspace_name) { - sway_log(L_ERROR, "Unable to allocate previous workspace name"); - return false; - } - strcpy(prev_workspace_name, active_ws->name); - } - - // move sticky containers - if (swayc_parent_by_type(active_ws, C_OUTPUT) == swayc_parent_by_type(workspace, C_OUTPUT)) { - // don't change list while traversing it, use intermediate list instead - list_t *stickies = create_list(); - for (int i = 0; i < active_ws->floating->length; i++) { - swayc_t *cont = active_ws->floating->items[i]; - if (cont->sticky) { - list_add(stickies, cont); - } - } - for (int i = 0; i < stickies->length; i++) { - swayc_t *cont = stickies->items[i]; - sway_log(L_DEBUG, "Moving sticky container %p to %p:%s", - cont, workspace, workspace->name); - swayc_t *parent = remove_child(cont); - add_floating(workspace, cont); - // Destroy old container if we need to - destroy_container(parent); - } - list_free(stickies); - } - sway_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name); - if (!set_focused_container(get_focused_view(workspace))) { - return false; - } - swayc_t *output = swayc_parent_by_type(workspace, C_OUTPUT); - arrange_backgrounds(); - arrange_windows(output, -1, -1); - return true; -} - -swayc_t *workspace_for_pid(pid_t pid) { - int i; - swayc_t *ws = NULL; - struct pid_workspace *pw = NULL; - - sway_log(L_DEBUG, "looking for workspace for pid %d", pid); - - // leaving this here as it's useful for debugging - // sway_log(L_DEBUG, "all pid_workspaces"); - // for (int k = 0; k < config->pid_workspaces->length; k++) { - // pw = config->pid_workspaces->items[k]; - // sway_log(L_DEBUG, "pid %d workspace %s time_added %li", *pw->pid, pw->workspace, *pw->time_added); - // } - - do { - for (i = 0; i < config->pid_workspaces->length; i++) { - pw = config->pid_workspaces->items[i]; - pid_t *pw_pid = pw->pid; - - if (pid == *pw_pid) { - sway_log(L_DEBUG, "found pid_workspace for pid %d, workspace %s", pid, pw->workspace); - break; // out of for loop - } - - pw = NULL; - } - - if (pw) { - break; // out of do-while loop - } - - pid = get_parent_pid(pid); - // no sense in looking for matches for pid 0. - // also, if pid == getpid(), that is the compositor's - // pid, which definitely isn't helpful - } while (pid > 0 && pid != getpid()); - - if (pw) { - ws = workspace_by_name(pw->workspace); - - if (!ws) { - sway_log(L_DEBUG, "Creating workspace %s for pid %d because it disappeared", pw->workspace, pid); - ws = workspace_create(pw->workspace); - } - - list_del(config->pid_workspaces, i); - } - - return ws; -} -- cgit v1.2.3 From b2d871cfe215a82266d01847f4787bbcf8c721c9 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sat, 31 Mar 2018 21:21:26 -0400 Subject: Partially implement move command Works: - move [container|window] to workspace - Note, this should be able to move C_CONTAINER but this is untested - move [workspace] to output [left|right|up|down|] Not implemented yet: - move [left|right|up|down] - move scratchpad - move position --- include/sway/output.h | 2 + include/sway/tree/container.h | 5 ++ include/sway/tree/layout.h | 12 +-- sway/commands.c | 1 + sway/commands/focus.c | 7 +- sway/commands/move.c | 181 ++++++++++++++++++++++++++++++++++++++++++ sway/desktop/output.c | 9 ++- sway/input/keyboard.c | 4 +- sway/meson.build | 1 + sway/tree/container.c | 18 +++++ sway/tree/layout.c | 58 ++++++++------ sway/tree/output.c | 11 +++ 12 files changed, 268 insertions(+), 41 deletions(-) create mode 100644 sway/commands/move.c (limited to 'sway/commands/move.c') diff --git a/include/sway/output.h b/include/sway/output.h index b4980cd8..b343ecff 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -36,4 +36,6 @@ void output_damage_whole(struct sway_output *output); void output_damage_whole_view(struct sway_output *output, struct sway_view *view); +struct sway_container *output_by_name(const char *name); + #endif diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 6aa66da0..aff2e58e 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -84,9 +84,14 @@ struct sway_container { struct { struct wl_signal destroy; + // Raised after the tree updates, but before arrange_windows + // Passed the previous parent + struct wl_signal reparent; } events; }; +const char *container_type_to_str(enum sway_container_type type); + // TODO only one container create function and pass the type? struct sway_container *container_output_create( struct sway_output *sway_output); diff --git a/include/sway/tree/layout.h b/include/sway/tree/layout.h index 0a904c4b..e1034657 100644 --- a/include/sway/tree/layout.h +++ b/include/sway/tree/layout.h @@ -11,9 +11,6 @@ enum movement_direction { MOVE_DOWN, MOVE_PARENT, MOVE_CHILD, - MOVE_NEXT, - MOVE_PREV, - MOVE_FIRST }; struct sway_container; @@ -32,7 +29,8 @@ struct sway_root { void layout_init(void); -void container_add_child(struct sway_container *parent, struct sway_container *child); +void container_add_child(struct sway_container *parent, + struct sway_container *child); struct sway_container *container_add_sibling(struct sway_container *parent, struct sway_container *child); @@ -44,7 +42,11 @@ struct sway_container *container_reap_empty(struct sway_container *container); void container_move_to(struct sway_container* container, struct sway_container* destination); -enum sway_container_layout container_get_default_layout(struct sway_container *output); +void container_move(struct sway_container *container, + enum movement_direction dir, int move_amt); + +enum sway_container_layout container_get_default_layout( + struct sway_container *output); void container_sort_workspaces(struct sway_container *output); diff --git a/sway/commands.c b/sway/commands.c index 90544220..b6af3d1a 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -162,6 +162,7 @@ static struct cmd_handler command_handlers[] = { { "focus", cmd_focus }, { "kill", cmd_kill }, { "layout", cmd_layout }, + { "move", cmd_move }, { "reload", cmd_reload }, }; diff --git a/sway/commands/focus.c b/sway/commands/focus.c index 64f079f4..0a521b9e 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c @@ -20,10 +20,6 @@ static bool parse_movement_direction(const char *name, *out = MOVE_PARENT; } else if (strcasecmp(name, "child") == 0) { *out = MOVE_CHILD; - } else if (strcasecmp(name, "next") == 0) { - *out = MOVE_NEXT; - } else if (strcasecmp(name, "prev") == 0) { - *out = MOVE_PREV; } else { return false; } @@ -51,7 +47,8 @@ struct cmd_results *cmd_focus(int argc, char **argv) { "Expected 'focus ' or 'focus output '"); } - struct sway_container *next_focus = container_get_in_direction(con, seat, direction); + struct sway_container *next_focus = container_get_in_direction( + con, seat, direction); if (next_focus) { sway_seat_set_focus(seat, next_focus); } diff --git a/sway/commands/move.c b/sway/commands/move.c new file mode 100644 index 00000000..222ef314 --- /dev/null +++ b/sway/commands/move.c @@ -0,0 +1,181 @@ +#include +#include +#include +#include +#include +#include "sway/commands.h" +#include "sway/input/seat.h" +#include "sway/output.h" +#include "sway/tree/container.h" +#include "sway/tree/layout.h" +#include "sway/tree/workspace.h" +#include "stringop.h" +#include "list.h" + +static const char* expected_syntax = + "Expected 'move <[px] px>' or " + "'move to workspace ' or " + "'move to output ' or " + "'move position mouse'"; + +static struct sway_container *output_in_direction(const char *direction, + struct wlr_output *reference, int ref_ox, int ref_oy) { + int ref_lx = ref_ox + reference->lx, + ref_ly = ref_oy + reference->ly; + struct { + char *name; + enum wlr_direction direction; + } names[] = { + { "up", WLR_DIRECTION_UP }, + { "down", WLR_DIRECTION_DOWN }, + { "left", WLR_DIRECTION_LEFT }, + { "right", WLR_DIRECTION_RIGHT }, + }; + for (size_t i = 0; i < sizeof(names) / sizeof(names[0]); ++i) { + if (strcasecmp(names[i].name, direction) == 0) { + struct wlr_output *adjacent = wlr_output_layout_adjacent_output( + root_container.sway_root->output_layout, + names[i].direction, reference, ref_lx, ref_ly); + if (adjacent) { + struct sway_output *sway_output = adjacent->data; + return sway_output->swayc; + } + break; + } + } + return output_by_name(direction); +} + +static struct cmd_results *cmd_move_container(struct sway_container *current, + int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "move container/window", + EXPECTED_AT_LEAST, 4))) { + return error; + } else if (strcasecmp(argv[1], "to") == 0 + && strcasecmp(argv[2], "workspace") == 0) { + // move container to workspace x + if (current->type == C_WORKSPACE) { + // TODO: Wrap children in a container and move that + return cmd_results_new(CMD_FAILURE, "move", "Unimplemented"); + } else if (current->type != C_CONTAINER && current->type != C_VIEW) { + return cmd_results_new(CMD_FAILURE, "move", + "Can only move containers and views."); + } + struct sway_container *ws; + const char *num_name = NULL; + char *ws_name = NULL; + if (argc == 5 && strcasecmp(argv[3], "number") == 0) { + // move "container to workspace number x" + num_name = argv[4]; + ws = workspace_by_number(num_name); + } else { + ws_name = join_args(argv + 3, argc - 3); + ws = workspace_by_name(ws_name); + } + if (!ws) { + ws = workspace_create(ws_name ? ws_name : num_name); + } + free(ws_name); + struct sway_container *old_parent = current->parent; + struct sway_container *focus = sway_seat_get_focus_inactive( + config->handler_context.seat, ws); + container_move_to(current, focus); + sway_seat_set_focus(config->handler_context.seat, old_parent); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } else if (strcasecmp(argv[1], "to") == 0 + && strcasecmp(argv[2], "output") == 0) { + if (current->type == C_WORKSPACE) { + // TODO: Wrap children in a container and move that + return cmd_results_new(CMD_FAILURE, "move", "Unimplemented"); + } else if (current->type != C_CONTAINER + && current->type != C_VIEW) { + return cmd_results_new(CMD_FAILURE, "move", + "Can only move containers and views."); + } + struct sway_container *source = container_parent(current, C_OUTPUT); + struct sway_container *destination = output_in_direction(argv[3], + source->sway_output->wlr_output, current->x, current->y); + if (!destination) { + return cmd_results_new(CMD_FAILURE, "move workspace", + "Can't find output with name/direction '%s'", argv[3]); + } + struct sway_container *focus = sway_seat_get_focus_inactive( + config->handler_context.seat, destination); + if (!focus) { + // We've never been to this output before + focus = destination->children->items[0]; + } + container_move_to(current, focus); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } + return cmd_results_new(CMD_INVALID, "move", expected_syntax); +} + +static struct cmd_results *cmd_move_workspace(struct sway_container *current, + int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "move workspace", EXPECTED_EQUAL_TO, 4))) { + return error; + } else if (strcasecmp(argv[1], "to") != 0 + || strcasecmp(argv[2], "output") != 0) { + return cmd_results_new(CMD_INVALID, "move", expected_syntax); + } + struct sway_container *source = container_parent(current, C_OUTPUT); + int center_x = current->width / 2 + current->x, + center_y = current->height / 2 + current->y; + struct sway_container *destination = output_in_direction(argv[3], + source->sway_output->wlr_output, center_x, center_y); + if (!destination) { + return cmd_results_new(CMD_FAILURE, "move workspace", + "Can't find output with name/direction '%s'", argv[3]); + } + if (current->type != C_WORKSPACE) { + current = container_parent(current, C_WORKSPACE); + } + container_move_to(current, destination); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +struct cmd_results *cmd_move(int argc, char **argv) { + struct cmd_results *error = NULL; + int move_amt = 10; + if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) { + return error; + } + struct sway_container *current = config->handler_context.current_container; + + if (argc == 2 || (argc == 3 && strcasecmp(argv[2], "px") == 0)) { + char *inv; + move_amt = (int)strtol(argv[1], &inv, 10); + if (*inv != '\0' && strcasecmp(inv, "px") != 0) { + move_amt = 10; + } + } + + if (strcasecmp(argv[0], "left") == 0) { + container_move(current, MOVE_LEFT, move_amt); + } else if (strcasecmp(argv[0], "right") == 0) { + container_move(current, MOVE_RIGHT, move_amt); + } else if (strcasecmp(argv[0], "up") == 0) { + container_move(current, MOVE_UP, move_amt); + } else if (strcasecmp(argv[0], "down") == 0) { + container_move(current, MOVE_DOWN, move_amt); + } else if (strcasecmp(argv[0], "container") == 0 + || strcasecmp(argv[0], "window") == 0) { + return cmd_move_container(current, argc, argv); + } else if (strcasecmp(argv[0], "workspace") == 0) { + return cmd_move_workspace(current, argc, argv); + } else if (strcasecmp(argv[0], "scratchpad") == 0 + || (strcasecmp(argv[0], "to") == 0 + && strcasecmp(argv[1], "scratchpad") == 0)) { + // TODO: scratchpad + return cmd_results_new(CMD_FAILURE, "move", "Unimplemented"); + } else if (strcasecmp(argv[0], "position") == 0) { + // TODO: floating + return cmd_results_new(CMD_FAILURE, "move", "Unimplemented"); + } else { + return cmd_results_new(CMD_INVALID, "move", expected_syntax); + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 0d706c52..c4265818 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -229,9 +229,12 @@ static void render_output(struct sway_output *output, struct timespec *when, struct sway_seat *seat = input_manager_current_seat(input_manager); struct sway_container *focus = sway_seat_get_focus_inactive(seat, output->swayc); - struct sway_container *workspace = (focus->type == C_WORKSPACE ? - focus : - container_parent(focus, C_WORKSPACE)); + if (!focus) { + // We've never been to this output before + focus = output->swayc->children->items[0]; + } + struct sway_container *workspace = focus->type == C_WORKSPACE ? + focus : container_parent(focus, C_WORKSPACE); struct render_data rdata = { .output = output, diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 99685052..8d22b684 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -97,8 +97,8 @@ static void keyboard_execute_command(struct sway_keyboard *keyboard, config->handler_context.seat = keyboard->seat_device->sway_seat; struct cmd_results *results = execute_command(binding->command, NULL); if (results->status != CMD_SUCCESS) { - wlr_log(L_DEBUG, "could not run command for binding: %s", - binding->command); + wlr_log(L_DEBUG, "could not run command for binding: %s (%s)", + binding->command, results->error); } free_cmd_results(results); } diff --git a/sway/meson.build b/sway/meson.build index 0cc620ea..38945b4c 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -19,6 +19,7 @@ sway_sources = files( 'commands/input.c', 'commands/layout.c', 'commands/mode.c', + 'commands/move.c', 'commands/seat.c', 'commands/seat/attach.c', 'commands/seat/fallback.c', diff --git a/sway/tree/container.c b/sway/tree/container.c index 746dbf1f..21fe3fb0 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -33,6 +33,23 @@ static list_t *get_bfs_queue() { return bfs_queue; } +const char *container_type_to_str(enum sway_container_type type) { + switch (type) { + case C_ROOT: + return "C_ROOT"; + case C_OUTPUT: + return "C_OUTPUT"; + case C_WORKSPACE: + return "C_WORKSPACE"; + case C_CONTAINER: + return "C_CONTAINER"; + case C_VIEW: + return "C_VIEW"; + default: + return "C_UNKNOWN"; + } +} + static void notify_new_container(struct sway_container *container) { wl_signal_emit(&root_container.sway_root->events.new_container, container); ipc_event_window(container, "new"); @@ -54,6 +71,7 @@ static struct sway_container *container_create(enum sway_container_type type) { } wl_signal_init(&c->events.destroy); + wl_signal_init(&c->events.reparent); return c; } diff --git a/sway/tree/layout.c b/sway/tree/layout.c index ce0682dc..a8941a40 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -106,8 +106,10 @@ struct sway_container *container_reap_empty(struct sway_container *container) { if (!sway_assert(container, "reaping null container")) { return NULL; } - wlr_log(L_DEBUG, "reaping %p %s", container, container->name); - while (container != &root_container && container->children->length == 0) { + wlr_log(L_DEBUG, "Reaping %p %s '%s'", container, + container_type_to_str(container->type), container->name); + while (container->type != C_ROOT && container->type != C_OUTPUT + && container->children->length == 0) { if (container->type == C_WORKSPACE) { if (!workspace_is_visible(container)) { struct sway_container *parent = container->parent; @@ -138,22 +140,46 @@ struct sway_container *container_remove_child(struct sway_container *child) { return container_reap_empty(parent); } -void container_move_to(struct sway_container* container, - struct sway_container* destination) { +void container_move_to(struct sway_container *container, + struct sway_container *destination) { if (container == destination || container_has_anscestor(container, destination)) { return; } struct sway_container *old_parent = container_remove_child(container); container->width = container->height = 0; - struct sway_container *new_parent = - container_add_sibling(destination, container); + struct sway_container *new_parent; + if (destination->type == C_VIEW) { + new_parent = container_add_sibling(destination, container); + } else { + new_parent = destination; + container_add_child(destination, container); + } + wl_signal_emit(&container->events.reparent, old_parent); + if (container->type == C_WORKSPACE) { + struct sway_seat *seat = sway_input_manager_get_default_seat( + input_manager); + if (old_parent->children->length == 0) { + char *ws_name = workspace_next_name(old_parent->name); + struct sway_container *ws = + container_workspace_create(old_parent, ws_name); + free(ws_name); + sway_seat_set_focus(seat, ws); + } + container_sort_workspaces(new_parent); + sway_seat_set_focus(seat, new_parent); + } if (old_parent) { arrange_windows(old_parent, -1, -1); } arrange_windows(new_parent, -1, -1); } +void container_move(struct sway_container *container, + enum movement_direction dir, int move_amt) { + // TODO +} + enum sway_container_layout container_get_default_layout( struct sway_container *output) { if (config->default_layout != L_NONE) { @@ -521,26 +547,6 @@ static struct sway_container *get_swayc_in_direction_under( } } - if (dir == MOVE_PREV || dir == MOVE_NEXT) { - int focused_idx = index_child(container); - if (focused_idx == -1) { - return NULL; - } else { - int desired = (focused_idx + (dir == MOVE_NEXT ? 1 : -1)) % - parent->children->length; - if (desired < 0) { - desired += parent->children->length; - } - return parent->children->items[desired]; - } - } - - // If moving to an adjacent output we need a starting position (since this - // output might border to multiple outputs). - //struct wlc_point abs_pos; - //get_layout_center_position(container, &abs_pos); - - // TODO WLR fullscreen /* if (container->type == C_VIEW && swayc_is_fullscreen(container)) { diff --git a/sway/tree/output.c b/sway/tree/output.c index 7248fd00..2331dc2b 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -1,3 +1,4 @@ +#include #include "sway/tree/container.h" #include "sway/tree/layout.h" #include "sway/output.h" @@ -37,3 +38,13 @@ struct sway_container *container_output_destroy(struct sway_container *output) { container_destroy(output); return &root_container; } + +struct sway_container *output_by_name(const char *name) { + for (int i = 0; i < root_container.children->length; ++i) { + struct sway_container *output = root_container.children->items[i]; + if (strcasecmp(output->name, name) == 0){ + return output; + } + } + return NULL; +} -- cgit v1.2.3 From e3689dd5a93b4f4ae62637a2b81797335aafdcaf Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Mon, 2 Apr 2018 11:57:06 -0400 Subject: Fixes regarding @emersion's feedback --- sway/commands/move.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sway/commands/move.c') diff --git a/sway/commands/move.c b/sway/commands/move.c index 222ef314..ab959b77 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -106,7 +106,9 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, // We've never been to this output before focus = destination->children->items[0]; } + struct sway_container *old_parent = current->parent; container_move_to(current, focus); + sway_seat_set_focus(config->handler_context.seat, old_parent); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } return cmd_results_new(CMD_INVALID, "move", expected_syntax); @@ -149,7 +151,8 @@ struct cmd_results *cmd_move(int argc, char **argv) { char *inv; move_amt = (int)strtol(argv[1], &inv, 10); if (*inv != '\0' && strcasecmp(inv, "px") != 0) { - move_amt = 10; + return cmd_results_new(CMD_FAILURE, "move", + "Invalid distance specified"); } } -- cgit v1.2.3 From 5f4761c4f40f5d6ec550ccabaebe0f990b6e8bbc Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 3 Apr 2018 13:08:45 -0400 Subject: unify workspace create functions --- include/sway/tree/workspace.h | 2 -- sway/commands/move.c | 2 +- sway/commands/workspace.c | 6 +++--- sway/tree/container.c | 47 +++++++++++++++++++++++++++++++++++-------- sway/tree/workspace.c | 33 +++--------------------------- 5 files changed, 46 insertions(+), 44 deletions(-) (limited to 'sway/commands/move.c') diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h index 4e4c3450..8d49fefb 100644 --- a/include/sway/tree/workspace.h +++ b/include/sway/tree/workspace.h @@ -7,8 +7,6 @@ extern char *prev_workspace_name; char *workspace_next_name(const char *output_name); -struct sway_container *workspace_create(const char *name); - bool workspace_switch(struct sway_container *workspace); struct sway_container *workspace_by_number(const char* name); diff --git a/sway/commands/move.c b/sway/commands/move.c index 644c622b..7ac5f009 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -74,7 +74,7 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, ws = workspace_by_name(ws_name); } if (!ws) { - ws = workspace_create(ws_name ? ws_name : num_name); + ws = container_workspace_create(NULL, ws_name ? ws_name : num_name); } free(ws_name); struct sway_container *old_parent = current->parent; diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c index aa4096f7..a3702803 100644 --- a/sway/commands/workspace.c +++ b/sway/commands/workspace.c @@ -61,7 +61,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { if (strcasecmp(argv[0], "number") == 0) { if (!(ws = workspace_by_number(argv[1]))) { char *name = join_args(argv + 1, argc - 1); - ws = workspace_create(name); + ws = container_workspace_create(NULL, name); free(name); } } else if (strcasecmp(argv[0], "next") == 0) { @@ -80,12 +80,12 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { ws = old_workspace; } else if (prev_workspace_name && !(ws = workspace_by_name(prev_workspace_name))) { - ws = workspace_create(prev_workspace_name); + ws = container_workspace_create(NULL, prev_workspace_name); } } else { char *name = join_args(argv, argc); if (!(ws = workspace_by_name(name))) { - ws = workspace_create(name); + ws = container_workspace_create(NULL, name); } free(name); } diff --git a/sway/tree/container.c b/sway/tree/container.c index 1c41bf5d..7ccd43ea 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -110,7 +110,8 @@ struct sway_container *container_finish(struct sway_container *cont) { return parent; } -static struct sway_container *container_output_destroy(struct sway_container *output) { +static struct sway_container *container_output_destroy( + struct sway_container *output) { if (!sway_assert(output, "cannot destroy null output")) { return NULL; } @@ -245,7 +246,8 @@ struct sway_container *container_destroy(struct sway_container *con) { break; case C_CONTAINER: if (con->children != NULL && con->children->length) { - assert(false && "dont destroy container containers with children"); + assert(false && + "dont destroy container containers with children"); } container_finish(con); // TODO return parent to arrange maybe? @@ -271,7 +273,8 @@ static void container_close_func(struct sway_container *container, void *data) { } struct sway_container *container_close(struct sway_container *con) { - if (!sway_assert(con != NULL, "container_close called with a NULL container")) { + if (!sway_assert(con != NULL, + "container_close called with a NULL container")) { return NULL; } @@ -359,12 +362,39 @@ struct sway_container *container_output_create( return output; } -struct sway_container *container_workspace_create( - struct sway_container *output, const char *name) { - if (!sway_assert(output, - "container_workspace_create called with null output")) { - return NULL; +static struct sway_container *workspace_get_initial_output(const char *name) { + struct sway_container *parent; + // Search for workspace<->output pair + int i, e = config->workspace_outputs->length; + for (i = 0; i < e; ++i) { + struct workspace_output *wso = config->workspace_outputs->items[i]; + if (strcasecmp(wso->workspace, name) == 0) { + // Find output to use if it exists + e = root_container.children->length; + for (i = 0; i < e; ++i) { + parent = root_container.children->items[i]; + if (strcmp(parent->name, wso->output) == 0) { + return parent; + } + } + break; + } } + // Otherwise put it on the focused output + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_container *focus = + seat_get_focus_inactive(seat, &root_container); + parent = focus; + parent = container_parent(parent, C_OUTPUT); + return parent; +} + +struct sway_container *container_workspace_create(struct sway_container *output, + const char *name) { + if (output == NULL) { + output = workspace_get_initial_output(name); + } + wlr_log(L_DEBUG, "Added workspace %s for output %s", name, output->name); struct sway_container *workspace = container_create(C_WORKSPACE); @@ -380,6 +410,7 @@ struct sway_container *container_workspace_create( container_add_child(output, workspace); container_sort_workspaces(output); notify_new_container(workspace); + return workspace; } diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 7d180009..d5a16410 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -179,35 +179,6 @@ struct sway_container *workspace_by_name(const char *name) { } } -struct sway_container *workspace_create(const char *name) { - struct sway_container *parent; - // Search for workspace<->output pair - int i, e = config->workspace_outputs->length; - for (i = 0; i < e; ++i) { - struct workspace_output *wso = config->workspace_outputs->items[i]; - if (strcasecmp(wso->workspace, name) == 0) { - // Find output to use if it exists - e = root_container.children->length; - for (i = 0; i < e; ++i) { - parent = root_container.children->items[i]; - if (strcmp(parent->name, wso->output) == 0) { - return container_workspace_create(parent, name); - } - } - break; - } - } - // Otherwise create a new one - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = - seat_get_focus_inactive(seat, &root_container); - parent = focus; - parent = container_parent(parent, C_OUTPUT); - struct sway_container *new_ws = container_workspace_create(parent, name); - ipc_event_workspace(NULL, new_ws, "init"); - return new_ws; -} - /** * Get the previous or next workspace on the specified output. Wraps around at * the end and beginning. If next is false, the previous workspace is returned, @@ -319,7 +290,9 @@ bool workspace_switch(struct sway_container *workspace) { && active_ws == workspace && prev_workspace_name) { struct sway_container *new_ws = workspace_by_name(prev_workspace_name); - workspace = new_ws ? new_ws : workspace_create(prev_workspace_name); + workspace = new_ws ? + new_ws : + container_workspace_create(NULL, prev_workspace_name); } if (!prev_workspace_name || (strcmp(prev_workspace_name, active_ws->name) -- cgit v1.2.3 From a001890fb8a9fc8c7f0b8eac03ca5912be2de479 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 3 Apr 2018 19:52:17 -0400 Subject: move workspace create to workspace.c --- include/sway/tree/container.h | 8 +++--- sway/commands/move.c | 2 +- sway/commands/workspace.c | 6 ++--- sway/desktop/output.c | 2 +- sway/tree/container.c | 62 ++++--------------------------------------- sway/tree/layout.c | 2 +- sway/tree/workspace.c | 54 ++++++++++++++++++++++++++++++++++++- 7 files changed, 69 insertions(+), 67 deletions(-) (limited to 'sway/commands/move.c') diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index f36b4bd1..277165ea 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -95,7 +95,7 @@ struct sway_container *container_create(enum sway_container_type type); const char *container_type_to_str(enum sway_container_type type); -struct sway_container *container_output_create( +struct sway_container *output_create( struct sway_output *sway_output); /** @@ -108,13 +108,13 @@ struct sway_container *container_container_create(); * Create a new output. Outputs are children of the root container and have no * order in the tree structure. */ -struct sway_container *container_output_create(struct sway_output *sway_output); +struct sway_container *output_create(struct sway_output *sway_output); /** * Create a new workspace container. Workspaces are children of an output * container and are ordered alphabetically by name. */ -struct sway_container *container_workspace_create(struct sway_container *output, const char *name); +struct sway_container *workspace_create(struct sway_container *output, const char *name); /* * Create a new view container. A view can be a child of a workspace container @@ -178,4 +178,6 @@ bool container_has_anscestor(struct sway_container *container, bool container_has_child(struct sway_container *con, struct sway_container *child); +void container_create_notify(struct sway_container *container); + #endif diff --git a/sway/commands/move.c b/sway/commands/move.c index 7ac5f009..c954ab94 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -74,7 +74,7 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, ws = workspace_by_name(ws_name); } if (!ws) { - ws = container_workspace_create(NULL, ws_name ? ws_name : num_name); + ws = workspace_create(NULL, ws_name ? ws_name : num_name); } free(ws_name); struct sway_container *old_parent = current->parent; diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c index a3702803..958b3222 100644 --- a/sway/commands/workspace.c +++ b/sway/commands/workspace.c @@ -61,7 +61,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { if (strcasecmp(argv[0], "number") == 0) { if (!(ws = workspace_by_number(argv[1]))) { char *name = join_args(argv + 1, argc - 1); - ws = container_workspace_create(NULL, name); + ws = workspace_create(NULL, name); free(name); } } else if (strcasecmp(argv[0], "next") == 0) { @@ -80,12 +80,12 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { ws = old_workspace; } else if (prev_workspace_name && !(ws = workspace_by_name(prev_workspace_name))) { - ws = container_workspace_create(NULL, prev_workspace_name); + ws = workspace_create(NULL, prev_workspace_name); } } else { char *name = join_args(argv, argc); if (!(ws = workspace_by_name(name))) { - ws = container_workspace_create(NULL, name); + ws = workspace_create(NULL, name); } free(name); } diff --git a/sway/desktop/output.c b/sway/desktop/output.c index de5076d8..96f23291 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -396,7 +396,7 @@ void handle_new_output(struct wl_listener *listener, void *data) { output->damage = wlr_output_damage_create(wlr_output); - output->swayc = container_output_create(output); + output->swayc = output_create(output); if (!output->swayc) { free(output); return; diff --git a/sway/tree/container.c b/sway/tree/container.c index fdbb2922..8ed30b44 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -51,7 +51,7 @@ const char *container_type_to_str(enum sway_container_type type) { } } -static void notify_new_container(struct sway_container *container) { +void container_create_notify(struct sway_container *container) { wl_signal_emit(&root_container.sway_root->events.new_container, container); ipc_event_window(container, "new"); } @@ -312,7 +312,7 @@ struct sway_container *container_close(struct sway_container *con) { return parent; } -struct sway_container *container_output_create( +struct sway_container *output_create( struct sway_output *sway_output) { struct wlr_box size; wlr_output_effective_resolution(sway_output->wlr_output, &size.width, @@ -363,7 +363,7 @@ struct sway_container *container_output_create( // Create workspace char *ws_name = workspace_next_name(output->name); wlr_log(L_DEBUG, "Creating default workspace %s", ws_name); - struct sway_container *ws = container_workspace_create(output, ws_name); + struct sway_container *ws = workspace_create(output, ws_name); // Set each seat's focus if not already set struct sway_seat *seat = NULL; wl_list_for_each(seat, &input_manager->seats, link) { @@ -373,62 +373,10 @@ struct sway_container *container_output_create( } free(ws_name); - notify_new_container(output); + container_create_notify(output); return output; } -static struct sway_container *get_workspace_initial_output(const char *name) { - struct sway_container *parent; - // Search for workspace<->output pair - int e = config->workspace_outputs->length; - for (int i = 0; i < config->workspace_outputs->length; ++i) { - struct workspace_output *wso = config->workspace_outputs->items[i]; - if (strcasecmp(wso->workspace, name) == 0) { - // Find output to use if it exists - e = root_container.children->length; - for (i = 0; i < e; ++i) { - parent = root_container.children->items[i]; - if (strcmp(parent->name, wso->output) == 0) { - return parent; - } - } - break; - } - } - // Otherwise put it on the focused output - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = - seat_get_focus_inactive(seat, &root_container); - parent = focus; - parent = container_parent(parent, C_OUTPUT); - return parent; -} - -struct sway_container *container_workspace_create(struct sway_container *output, - const char *name) { - if (output == NULL) { - output = get_workspace_initial_output(name); - } - - wlr_log(L_DEBUG, "Added workspace %s for output %s", name, output->name); - struct sway_container *workspace = container_create(C_WORKSPACE); - - workspace->x = output->x; - workspace->y = output->y; - workspace->width = output->width; - workspace->height = output->height; - workspace->name = !name ? NULL : strdup(name); - workspace->prev_layout = L_NONE; - workspace->layout = container_get_default_layout(output); - workspace->workspace_layout = workspace->layout; - - container_add_child(output, workspace); - container_sort_workspaces(output); - notify_new_container(workspace); - - return workspace; -} - struct sway_container *container_view_create(struct sway_container *sibling, struct sway_view *sway_view) { if (!sway_assert(sibling, @@ -452,7 +400,7 @@ struct sway_container *container_view_create(struct sway_container *sibling, // Regular case, create as sibling of current container container_add_sibling(sibling, swayc); } - notify_new_container(swayc); + container_create_notify(swayc); return swayc; } diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 3cbbf3b4..a46359bd 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -149,7 +149,7 @@ void container_move_to(struct sway_container *container, if (old_parent->children->length == 0) { char *ws_name = workspace_next_name(old_parent->name); struct sway_container *ws = - container_workspace_create(old_parent, ws_name); + workspace_create(old_parent, ws_name); free(ws_name); seat_set_focus(seat, ws); } diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index d5a16410..6ba3d973 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -14,6 +14,58 @@ #include "log.h" #include "util.h" +static struct sway_container *get_workspace_initial_output(const char *name) { + struct sway_container *parent; + // Search for workspace<->output pair + int e = config->workspace_outputs->length; + for (int i = 0; i < config->workspace_outputs->length; ++i) { + struct workspace_output *wso = config->workspace_outputs->items[i]; + if (strcasecmp(wso->workspace, name) == 0) { + // Find output to use if it exists + e = root_container.children->length; + for (i = 0; i < e; ++i) { + parent = root_container.children->items[i]; + if (strcmp(parent->name, wso->output) == 0) { + return parent; + } + } + break; + } + } + // Otherwise put it on the focused output + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_container *focus = + seat_get_focus_inactive(seat, &root_container); + parent = focus; + parent = container_parent(parent, C_OUTPUT); + return parent; +} + +struct sway_container *workspace_create(struct sway_container *output, + const char *name) { + if (output == NULL) { + output = get_workspace_initial_output(name); + } + + wlr_log(L_DEBUG, "Added workspace %s for output %s", name, output->name); + struct sway_container *workspace = container_create(C_WORKSPACE); + + workspace->x = output->x; + workspace->y = output->y; + workspace->width = output->width; + workspace->height = output->height; + workspace->name = !name ? NULL : strdup(name); + workspace->prev_layout = L_NONE; + workspace->layout = container_get_default_layout(output); + workspace->workspace_layout = workspace->layout; + + container_add_child(output, workspace); + container_sort_workspaces(output); + container_create_notify(workspace); + + return workspace; +} + char *prev_workspace_name = NULL; struct workspace_by_number_data { int len; @@ -292,7 +344,7 @@ bool workspace_switch(struct sway_container *workspace) { struct sway_container *new_ws = workspace_by_name(prev_workspace_name); workspace = new_ws ? new_ws : - container_workspace_create(NULL, prev_workspace_name); + workspace_create(NULL, prev_workspace_name); } if (!prev_workspace_name || (strcmp(prev_workspace_name, active_ws->name) -- cgit v1.2.3 From 57954a2b24f1e211c3b8811fb898ef4e076cb098 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Mon, 2 Apr 2018 13:49:37 -0400 Subject: Implement move [left|right|up|down] The exact semantics of this command are complicated. I'll describe each test scenario as s-expressions. Everything assumes L_HORIZ if not specified, but if you rotate everything 90 degrees the same test cases hold. ``` (container (view a) (view b focus) (view c)) -> move left (container (view b focus) (view a) (view c)) (container (view a) (view b focus) (view c)) -> move right (container (view a) (view c) (view b focus)) (container L_VERT (view a)) (container L_HORIZ (view b) (view c focus)) -> move up (container L_VERT (view a) (view c focus)) (container L_HORIZ (view b)) (workspace (view a) (view b focus) (view c)) -> move up (workspace [split direction flipped] (view b focus) (container (view a) (view c))) (workspace (view a) (view b focus) (view c)) -> move down (workspace [split direction flipped] (container (view a) (view c)) (view b focus))) Note: outputs use wlr_output_layout instead of assuming that i+/-1 is the next output in the move direction. (root (output X11-1 (workspace 1)) (output X11-2 (workspace 1 (view a focus) (view b))))) -> move left (root (output X11-1 (workspace 1 (view a focus))) (output X11-2 (workspace 1 (view b))))) (root (output X11-1 (workspace 1 (container (view a) (view b))) (output X11-2 (workspace 1 (view c focus))))) -> move left (root (output X11-1 (workspace 1 (container (view a) (view b)) (view c focus))) (output X11-2 (workspace 1))) ``` --- include/sway/tree/container.h | 7 + sway/commands/move.c | 4 + sway/tree/container.c | 46 ++++--- sway/tree/layout.c | 294 ++++++++++++++++++++++++++++++++++++++---- 4 files changed, 306 insertions(+), 45 deletions(-) (limited to 'sway/commands/move.c') diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 4c60530f..2a8b8aba 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -182,4 +182,11 @@ void container_create_notify(struct sway_container *container); void container_damage_whole(struct sway_container *container); +bool container_reap_empty(struct sway_container *con); + +struct sway_container *container_reap_empty_recursive( + struct sway_container *con); + +struct sway_container *container_flatten(struct sway_container *container); + #endif diff --git a/sway/commands/move.c b/sway/commands/move.c index c954ab94..15a5ebc4 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -82,6 +82,8 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, config->handler_context.seat, ws); container_move_to(current, focus); seat_set_focus(config->handler_context.seat, old_parent); + container_reap_empty(old_parent); + container_reap_empty(focus->parent); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } else if (strcasecmp(argv[1], "to") == 0 && strcasecmp(argv[2], "output") == 0) { @@ -109,6 +111,8 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, struct sway_container *old_parent = current->parent; container_move_to(current, focus); seat_set_focus(config->handler_context.seat, old_parent); + container_reap_empty(old_parent); + container_reap_empty(focus->parent); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } return cmd_results_new(CMD_INVALID, "move", expected_syntax); diff --git a/sway/tree/container.c b/sway/tree/container.c index ab8363bc..ea1c93bb 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -208,7 +208,7 @@ static void container_root_finish(struct sway_container *con) { wlr_log(L_ERROR, "TODO: destroy the root container"); } -static bool container_reap_empty(struct sway_container *con) { +bool container_reap_empty(struct sway_container *con) { switch (con->type) { case C_ROOT: case C_OUTPUT: @@ -225,14 +225,6 @@ static bool container_reap_empty(struct sway_container *con) { if (con->children->length == 0) { _container_destroy(con); return true; - } else if (con->children->length == 1) { - struct sway_container *child = con->children->items[0]; - if (child->type == C_CONTAINER) { - container_remove_child(child); - container_replace_child(con, child); - _container_destroy(con); - return true; - } } case C_VIEW: break; @@ -245,6 +237,29 @@ static bool container_reap_empty(struct sway_container *con) { return false; } +struct sway_container *container_reap_empty_recursive( + struct sway_container *con) { + while (con) { + struct sway_container *next = con->parent; + if (!container_reap_empty(con)) { + break; + } + con = next; + } + return con; +} + +struct sway_container *container_flatten(struct sway_container *container) { + while (container->type == C_CONTAINER && container->children->length == 1) { + struct sway_container *child = container->children->items[0]; + struct sway_container *parent = container->parent; + container_replace_child(container, child); + container_destroy(container); + container = parent; + } + return container; +} + struct sway_container *container_destroy(struct sway_container *con) { if (con == NULL) { return NULL; @@ -283,18 +298,7 @@ struct sway_container *container_destroy(struct sway_container *con) { break; } - struct sway_container *tmp = parent; - while (parent) { - tmp = parent->parent; - - if (!container_reap_empty(parent)) { - break; - } - - parent = tmp; - } - - return tmp; + return container_reap_empty_recursive(parent); } static void container_close_func(struct sway_container *container, void *data) { diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 343f349a..a060cb85 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -100,13 +100,31 @@ static int index_child(const struct sway_container *child) { return i; } +void container_insert_child(struct sway_container *parent, + struct sway_container *child, int i) { + struct sway_container *old_parent = NULL; + list_insert(parent->children, i, child); + child->parent = parent; + if (old_parent && old_parent != parent) { + wl_signal_emit(&child->events.reparent, old_parent); + } +} + struct sway_container *container_add_sibling(struct sway_container *fixed, struct sway_container *active) { // TODO handle floating + struct sway_container *old_parent = NULL; + if (active->parent) { + old_parent = active->parent; + container_remove_child(active); + } struct sway_container *parent = fixed->parent; int i = index_child(fixed); list_insert(parent->children, i + 1, active); active->parent = parent; + if (old_parent && old_parent != parent) { + wl_signal_emit(&active->events.reparent, old_parent); + } return active->parent; } @@ -166,9 +184,253 @@ void container_move_to(struct sway_container *container, arrange_windows(new_parent, -1, -1); } +static bool sway_dir_to_wlr(enum movement_direction dir, + enum wlr_direction *out) { + switch (dir) { + case MOVE_UP: + *out = WLR_DIRECTION_UP; + break; + case MOVE_DOWN: + *out = WLR_DIRECTION_DOWN; + break; + case MOVE_LEFT: + *out = WLR_DIRECTION_LEFT; + break; + case MOVE_RIGHT: + *out = WLR_DIRECTION_RIGHT; + break; + default: + return false; + } + + return true; +} + +static bool is_parallel(enum sway_container_layout layout, + enum movement_direction dir) { + switch (layout) { + case L_TABBED: + case L_STACKED: + case L_HORIZ: + return dir == MOVE_LEFT || dir == MOVE_RIGHT; + case L_VERT: + return dir == MOVE_UP || dir == MOVE_DOWN; + default: + return false; + } +} + +static enum movement_direction invert_movement(enum movement_direction dir) { + switch (dir) { + case MOVE_LEFT: + return MOVE_RIGHT; + case MOVE_RIGHT: + return MOVE_LEFT; + case MOVE_UP: + return MOVE_DOWN; + case MOVE_DOWN: + return MOVE_LEFT; + default: + sway_assert(0, "This function expects left|right|up|down"); + return MOVE_LEFT; + } +} + +/* Gets the index of the most extreme member based on the movement offset */ +static int container_limit(struct sway_container *container, int offs) { + if (container->children->length == 0) { + return 0; + } + return offs < 0 ? 0 : container->children->length - 1; +} + +static int move_offs(enum movement_direction move_dir) { + return move_dir == MOVE_LEFT || move_dir == MOVE_UP ? -1 : 1; +} + +static void workspace_rejigger(struct sway_container *ws, + struct sway_container *child, enum movement_direction move_dir) { + struct sway_container *original_parent = child->parent; + struct sway_container *new_parent = + container_split(ws, ws->layout); + + container_remove_child(child); + for (int i = 0; i < ws->children->length; ++i) { + struct sway_container *_child = ws->children->items[i]; + container_move_to(new_parent, _child); + } + + int index = move_offs(move_dir); + container_insert_child(ws, child, index < 0 ? 0 : 1); + container_set_layout(ws, + move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT); + + container_flatten(ws); + container_reap_empty_recursive(original_parent); + arrange_windows(ws, -1, -1); +} + void container_move(struct sway_container *container, - enum movement_direction dir, int move_amt) { - // TODO + enum movement_direction move_dir, int move_amt) { + if (!sway_assert( + container->type != C_CONTAINER || container->type != C_VIEW, + "Can only move containers and views")) { + return; + } + int offs = move_offs(move_dir); + + struct sway_container *sibling = NULL; + struct sway_container *current = container; + struct sway_container *parent = current->parent; + + if (parent != container_flatten(parent)) { + // Special case: we were the last one in this container, so flatten it + // and leave + return; + } + + while (!sibling) { + if (current->type == C_ROOT) { + return; + } + + parent = current->parent; + wlr_log(L_DEBUG, "Visiting %p %s '%s'", current, + container_type_to_str(current->type), current->name); + + int index = index_child(current); + int limit = container_limit(parent, offs); + + switch (current->type) { + case C_OUTPUT: { + enum wlr_direction wlr_dir; + sway_dir_to_wlr(move_dir, &wlr_dir); + double ref_x = current->x + current->width / 2; + double ref_y = current->y + current->height / 2; + ref_x += current->sway_output->wlr_output->lx; + ref_y += current->sway_output->wlr_output->ly; + struct wlr_output *next = wlr_output_layout_adjacent_output( + root_container.sway_root->output_layout, wlr_dir, + current->sway_output->wlr_output, + current->x, current->y); + if (!next) { + wlr_log(L_DEBUG, "Hit edge of output, nowhere else to go"); + return; + } + struct sway_output *next_output = next->data; + current = next_output->swayc; + wlr_log(L_DEBUG, "Selected next output (%s)", current->name); + // Select workspace and get outta here + current = seat_get_focus_inactive( + config->handler_context.seat, current); + if (current->type != C_WORKSPACE) { + current = container_parent(current, C_WORKSPACE); + } + sibling = current; + break; + } + case C_WORKSPACE: + if (!is_parallel(current->layout, move_dir)) { + // Special case + wlr_log(L_DEBUG, "Rejiggering the workspace"); + workspace_rejigger(current, container, move_dir); + return; + } else { + wlr_log(L_DEBUG, "Selecting output"); + current = current->parent; + } + break; + case C_CONTAINER: + case C_VIEW: + if (is_parallel(parent->layout, move_dir)) { + if (index == limit) { + if (current->parent == container->parent) { + wlr_log(L_DEBUG, "Hit limit, selecting parent"); + current = current->parent; + } else { + wlr_log(L_DEBUG, "Hit limit, " + "promoting descendant to sibling"); + // Special case + struct sway_container *old_parent = container->parent; + container_remove_child(container); + container_insert_child(current->parent, container, + index + (offs < 0 ? 0 : 1)); + container->width = container->height = 0; + arrange_windows(current->parent, -1, -1); + arrange_windows(old_parent, -1, -1); + return; + } + } else { + wlr_log(L_DEBUG, "Selecting sibling"); + sibling = parent->children->items[index + offs]; + } + } else { + wlr_log(L_DEBUG, "Moving up to find a parallel container"); + current = current->parent; + } + break; + default: + sway_assert(0, "Not expecting to see container of type %s here", + container_type_to_str(current->type)); + return; + } + } + + // Part two: move stuff around + int index = index_child(container); + struct sway_container *old_parent = container->parent; + + switch (sibling->type) { + case C_VIEW: + if (sibling->parent == container->parent) { + wlr_log(L_DEBUG, "Swapping siblings"); + sibling->parent->children->items[index + offs] = container; + sibling->parent->children->items[index] = sibling; + arrange_windows(sibling->parent, -1, -1); + } else { + wlr_log(L_DEBUG, "Promoting to sibling of cousin"); + container_remove_child(container); + container_insert_child(sibling->parent, container, + index_child(sibling) + (offs > 0 ? 0 : 1)); + container->width = container->height = 0; + arrange_windows(sibling->parent, -1, -1); + arrange_windows(old_parent, -1, -1); + } + break; + case C_WORKSPACE: // Note: only in the case of moving between outputs + case C_CONTAINER: + if (is_parallel(sibling->layout, move_dir)) { + int limit = container_limit(sibling, move_dir); + wlr_log(L_DEBUG, "Reparenting container (paralell)"); + limit = limit != 0 ? limit + 1 : limit; // Convert to index + wlr_log(L_DEBUG, "Reparenting container (paralell) %d", limit); + container_remove_child(container); + container_insert_child(sibling, container, limit); + container->width = container->height = 0; + arrange_windows(sibling, -1, -1); + arrange_windows(old_parent, -1, -1); + } else { + wlr_log(L_DEBUG, "Reparenting container (perpendicular)"); + container_remove_child(container); + struct sway_container *focus_inactive = seat_get_focus_inactive( + config->handler_context.seat, sibling); + if (focus_inactive) { + container_add_sibling(focus_inactive, container); + } else if (sibling->children->length) { + container_add_sibling(sibling->children->items[0], container); + } else { + container_add_child(sibling, container); + } + container->width = container->height = 0; + arrange_windows(sibling, -1, -1); + arrange_windows(old_parent, -1, -1); + } + break; + default: + sway_assert(0, "Not expecting to see container of type %s here", + container_type_to_str(sibling->type)); + return; + } } enum sway_container_layout container_get_default_layout( @@ -320,6 +582,7 @@ void arrange_windows(struct sway_container *container, container->children->length); break; } + container_damage_whole(container); } static void apply_horiz_layout(struct sway_container *container, @@ -512,28 +775,6 @@ static void get_layout_center_position(struct sway_container *container, } } -static bool sway_dir_to_wlr(enum movement_direction dir, - enum wlr_direction *out) { - switch (dir) { - case MOVE_UP: - *out = WLR_DIRECTION_UP; - break; - case MOVE_DOWN: - *out = WLR_DIRECTION_DOWN; - break; - case MOVE_LEFT: - *out = WLR_DIRECTION_LEFT; - break; - case MOVE_RIGHT: - *out = WLR_DIRECTION_RIGHT; - break; - default: - return false; - } - - return true; -} - static struct sway_container *sway_output_from_wlr(struct wlr_output *output) { if (output == NULL) { return NULL; @@ -673,6 +914,9 @@ struct sway_container *container_replace_child(struct sway_container *child, int i = index_child(child); // TODO floating + if (new_child->parent) { + container_remove_child(new_child); + } parent->children->items[i] = new_child; new_child->parent = parent; child->parent = NULL; @@ -718,7 +962,9 @@ struct sway_container *container_split(struct sway_container *child, } container_add_child(workspace, cont); + enum sway_container_layout old_layout = workspace->layout; container_set_layout(workspace, layout); + cont->layout = old_layout; if (set_focus) { seat_set_focus(seat, cont); -- cgit v1.2.3 From 63b2543749e57e4340f539a2742fd13e89d96d94 Mon Sep 17 00:00:00 2001 From: db Date: Sun, 8 Apr 2018 22:49:06 +0200 Subject: Add workspace_auto_back_and_forth for move cmd --- sway/commands/move.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'sway/commands/move.c') diff --git a/sway/commands/move.c b/sway/commands/move.c index 15a5ebc4..a5273ba4 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -1,3 +1,4 @@ +#define _XOPEN_SOURCE 500 #include #include #include @@ -63,18 +64,29 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, "Can only move containers and views."); } struct sway_container *ws; - const char *num_name = NULL; char *ws_name = NULL; if (argc == 5 && strcasecmp(argv[3], "number") == 0) { // move "container to workspace number x" - num_name = argv[4]; - ws = workspace_by_number(num_name); + ws_name = strdup(argv[4]); + ws = workspace_by_number(ws_name); } else { ws_name = join_args(argv + 3, argc - 3); ws = workspace_by_name(ws_name); } + + if (config->auto_back_and_forth && prev_workspace_name) { + // auto back and forth move + struct sway_container *curr_ws = container_parent(current, C_WORKSPACE); + if (curr_ws->name && strcmp(curr_ws->name, ws_name) == 0) { + // if target workspace is the current one + free(ws_name); + ws_name = strdup(prev_workspace_name); + ws = workspace_by_name(ws_name); + } + } + if (!ws) { - ws = workspace_create(NULL, ws_name ? ws_name : num_name); + ws = workspace_create(NULL, ws_name); } free(ws_name); struct sway_container *old_parent = current->parent; -- cgit v1.2.3