From eafa655ff1b1e63e595ec1dba14449e31f930af2 Mon Sep 17 00:00:00 2001 From: William McKinnon Date: Fri, 29 Nov 2024 17:22:07 -0500 Subject: [PATCH 001/105] removed bloat (lol) --- CONTRIBUTING.md | 245 -- LICENSE | 19 - client/meson.build | 14 - client/pool-buffer.c | 132 -- common/background-image.c | 220 -- common/cairo.c | 44 - common/gesture.c | 333 --- common/ipc-client.c | 149 -- common/list.c | 160 -- common/log.c | 126 -- common/loop.c | 184 -- common/meson.build | 23 - common/pango.c | 138 -- common/stringop.c | 363 --- common/util.c | 144 -- completions/bash/sway | 46 - completions/bash/swaybar | 44 - completions/bash/swaymsg | 65 - completions/fish/sway.fish | 11 - completions/fish/swaymsg.fish | 25 - completions/fish/swaynag.fish | 30 - completions/meson.build | 57 - completions/zsh/_sway | 22 - completions/zsh/_swaybar | 13 - completions/zsh/_swaymsg | 40 - config.in | 240 -- include/background-image.h | 20 - include/cairo_util.h | 14 - include/gesture.h | 104 - include/ipc-client.h | 49 - include/ipc.h | 41 - include/list.h | 35 - include/log.h | 58 - include/loop.h | 54 - include/meson.build | 1 - include/pango.h | 25 - include/pool-buffer.h | 24 - include/stringop.h | 43 - include/sway/commands.h | 346 --- include/sway/config.h | 779 ------- include/sway/criteria.h | 83 - include/sway/decoration.h | 17 - include/sway/desktop.h | 13 - include/sway/desktop/idle_inhibit_v1.h | 47 - include/sway/desktop/launcher.h | 40 - include/sway/desktop/transaction.h | 54 - include/sway/input/cursor.h | 150 -- include/sway/input/input-manager.h | 77 - include/sway/input/keyboard.h | 95 - include/sway/input/libinput.h | 14 - include/sway/input/seat.h | 387 ---- include/sway/input/switch.h | 24 - include/sway/input/tablet.h | 69 - include/sway/input/text_input.h | 93 - include/sway/ipc-json.h | 20 - include/sway/ipc-server.h | 26 - include/sway/layer_criteria.h | 20 - include/sway/layers.h | 72 - include/sway/output.h | 236 -- include/sway/server.h | 192 -- include/sway/surface.h | 24 - include/sway/swaynag.h | 30 - include/sway/tree/arrange.h | 19 - include/sway/tree/container.h | 394 ---- include/sway/tree/node.h | 78 - include/sway/tree/root.h | 89 - include/sway/tree/view.h | 392 ---- include/sway/tree/workspace.h | 156 -- include/sway/xdg_decoration.h | 19 - include/sway/xwayland.h | 31 - include/swaybar/bar.h | 118 - include/swaybar/config.h | 95 - include/swaybar/i3bar.h | 35 - include/swaybar/input.h | 83 - include/swaybar/ipc.h | 12 - include/swaybar/render.h | 8 - include/swaybar/status_line.h | 46 - include/swaybar/tray/host.h | 17 - include/swaybar/tray/icon.h | 43 - include/swaybar/tray/item.h | 58 - include/swaybar/tray/tray.h | 42 - include/swaybar/tray/watcher.h | 18 - include/swaynag/config.h | 13 - include/swaynag/render.h | 7 - include/swaynag/swaynag.h | 111 - include/swaynag/types.h | 50 - include/util.h | 64 - meson.build | 288 --- meson_options.txt | 11 - protocols/idle.xml | 49 - protocols/meson.build | 44 - protocols/wlr-input-inhibitor-unstable-v1.xml | 67 - protocols/wlr-layer-shell-unstable-v1.xml | 390 ---- ...lr-output-power-management-unstable-v1.xml | 128 -- sway-portals.conf | 6 - sway.desktop | 5 - sway/commands.c | 552 ----- sway/commands/assign.c | 63 - sway/commands/bar.c | 136 -- sway/commands/bar/bind.c | 129 -- sway/commands/bar/binding_mode_indicator.c | 23 - sway/commands/bar/colors.c | 152 -- sway/commands/bar/font.c | 31 - sway/commands/bar/gaps.c | 57 - sway/commands/bar/height.c | 20 - sway/commands/bar/hidden_state.c | 74 - sway/commands/bar/icon_theme.c | 24 - sway/commands/bar/id.c | 35 - sway/commands/bar/mode.c | 78 - sway/commands/bar/modifier.c | 38 - sway/commands/bar/output.c | 49 - sway/commands/bar/pango_markup.c | 22 - sway/commands/bar/position.c | 23 - sway/commands/bar/separator_symbol.c | 16 - sway/commands/bar/status_command.c | 23 - sway/commands/bar/status_edge_padding.c | 21 - sway/commands/bar/status_padding.c | 21 - sway/commands/bar/strip_workspace_name.c | 28 - sway/commands/bar/strip_workspace_numbers.c | 28 - sway/commands/bar/swaybar_command.c | 16 - sway/commands/bar/tray_bind.c | 95 - sway/commands/bar/tray_output.c | 50 - sway/commands/bar/tray_padding.c | 39 - sway/commands/bar/workspace_buttons.c | 22 - sway/commands/bar/workspace_min_width.c | 33 - sway/commands/bar/wrap_scroll.c | 22 - sway/commands/bind.c | 762 ------- sway/commands/blur.c | 32 - sway/commands/blur_brightness.c | 29 - sway/commands/blur_contrast.c | 29 - sway/commands/blur_noise.c | 29 - sway/commands/blur_passes.c | 29 - sway/commands/blur_radius.c | 29 - sway/commands/blur_saturation.c | 30 - sway/commands/blur_xray.c | 26 - sway/commands/border.c | 101 - sway/commands/client.c | 98 - sway/commands/corner_radius.c | 42 - sway/commands/create_output.c | 49 - sway/commands/default_border.c | 27 - sway/commands/default_dim_inactive.c | 30 - sway/commands/default_floating_border.c | 29 - sway/commands/default_orientation.c | 21 - sway/commands/dim_inactive.c | 27 - sway/commands/dim_inactive_colors.c | 40 - sway/commands/exec.c | 19 - sway/commands/exec_always.c | 130 -- sway/commands/exit.c | 14 - sway/commands/floating.c | 59 - sway/commands/floating_minmax_size.c | 52 - sway/commands/floating_modifier.c | 34 - sway/commands/focus.c | 474 ---- sway/commands/focus_follows_mouse.c | 21 - sway/commands/focus_on_window_activation.c | 25 - sway/commands/focus_wrapping.c | 23 - sway/commands/font.c | 50 - sway/commands/for_window.c | 37 - sway/commands/force_display_urgency_hint.c | 27 - sway/commands/force_focus_wrapping.c | 27 - sway/commands/fullscreen.c | 58 - sway/commands/gaps.c | 231 -- sway/commands/gesture.c | 166 -- sway/commands/hide_edge_borders.c | 48 - sway/commands/include.c | 14 - sway/commands/inhibit_idle.c | 51 - sway/commands/input.c | 106 - sway/commands/input/accel_profile.c | 27 - sway/commands/input/calibration_matrix.c | 35 - sway/commands/input/click_method.c | 30 - sway/commands/input/drag.c | 25 - sway/commands/input/drag_lock.c | 25 - sway/commands/input/dwt.c | 25 - sway/commands/input/dwtp.c | 25 - sway/commands/input/events.c | 163 -- sway/commands/input/left_handed.c | 21 - sway/commands/input/map_from_region.c | 87 - sway/commands/input/map_to_output.c | 23 - sway/commands/input/map_to_region.c | 53 - sway/commands/input/middle_emulation.c | 25 - sway/commands/input/natural_scroll.c | 21 - sway/commands/input/pointer_accel.c | 29 - sway/commands/input/repeat_delay.c | 24 - sway/commands/input/repeat_rate.c | 24 - sway/commands/input/rotation_angle.c | 29 - sway/commands/input/scroll_button.c | 37 - sway/commands/input/scroll_button_lock.c | 26 - sway/commands/input/scroll_factor.c | 31 - sway/commands/input/scroll_method.c | 31 - sway/commands/input/tap.c | 26 - sway/commands/input/tap_button_map.c | 27 - sway/commands/input/tool_mode.c | 73 - sway/commands/input/xkb_capslock.c | 21 - sway/commands/input/xkb_file.c | 49 - sway/commands/input/xkb_layout.c | 21 - sway/commands/input/xkb_model.c | 21 - sway/commands/input/xkb_numlock.c | 19 - sway/commands/input/xkb_options.c | 21 - sway/commands/input/xkb_rules.c | 21 - sway/commands/input/xkb_switch_layout.c | 115 - sway/commands/input/xkb_variant.c | 21 - sway/commands/kill.c | 31 - sway/commands/layer_effects.c | 33 - sway/commands/layout.c | 186 -- sway/commands/mark.c | 68 - sway/commands/max_render_time.c | 32 - sway/commands/mode.c | 90 - sway/commands/mouse_warping.c | 21 - sway/commands/move.c | 1065 --------- sway/commands/new_float.c | 13 - sway/commands/new_window.c | 13 - sway/commands/no_focus.c | 34 - sway/commands/nop.c | 5 - sway/commands/opacity.c | 42 - sway/commands/output.c | 127 -- sway/commands/output/adaptive_sync.c | 22 - sway/commands/output/background.c | 157 -- sway/commands/output/disable.c | 13 - sway/commands/output/dpms.c | 8 - sway/commands/output/enable.c | 15 - sway/commands/output/max_render_time.c | 28 - sway/commands/output/mode.c | 118 - sway/commands/output/position.c | 41 - sway/commands/output/power.c | 43 - sway/commands/output/render_bit_depth.c | 29 - sway/commands/output/scale.c | 22 - sway/commands/output/scale_filter.c | 34 - sway/commands/output/subpixel.c | 36 - sway/commands/output/toggle.c | 37 - sway/commands/output/transform.c | 89 - sway/commands/output/unplug.c | 54 - sway/commands/popup_during_fullscreen.c | 24 - sway/commands/primary_selection.c | 23 - sway/commands/reload.c | 76 - sway/commands/rename.c | 102 - sway/commands/resize.c | 598 ----- sway/commands/saturation.c | 43 - sway/commands/scratchpad.c | 132 -- sway/commands/scratchpad_minimize.c | 18 - sway/commands/seat.c | 81 - sway/commands/seat/attach.c | 28 - sway/commands/seat/cursor.c | 131 -- sway/commands/seat/fallback.c | 18 - sway/commands/seat/hide_cursor.c | 50 - sway/commands/seat/idle.c | 79 - sway/commands/seat/keyboard_grouping.c | 26 - sway/commands/seat/pointer_constraint.c | 58 - sway/commands/seat/shortcuts_inhibitor.c | 96 - sway/commands/seat/xcursor_theme.c | 33 - sway/commands/set.c | 60 - sway/commands/shadow_blur_radius.c | 25 - sway/commands/shadow_color.c | 28 - sway/commands/shadow_inactive_color.c | 25 - sway/commands/shadow_offset.c | 27 - sway/commands/shadows.c | 29 - sway/commands/shadows_on_csd.c | 19 - sway/commands/shortcuts_inhibitor.c | 49 - sway/commands/show_marks.c | 35 - sway/commands/smart_borders.c | 23 - sway/commands/smart_corner_radius.c | 17 - sway/commands/smart_gaps.c | 28 - sway/commands/split.c | 115 - sway/commands/sticky.c | 49 - sway/commands/swap.c | 108 - sway/commands/swaybg_command.c | 25 - sway/commands/swaynag_command.c | 25 - sway/commands/tiling_drag.c | 13 - sway/commands/tiling_drag_threshold.c | 21 - sway/commands/title_align.c | 30 - sway/commands/title_format.c | 27 - sway/commands/titlebar_border_thickness.c | 34 - sway/commands/titlebar_padding.c | 61 - sway/commands/titlebar_separator.c | 19 - sway/commands/unmark.c | 53 - sway/commands/urgent.c | 32 - sway/commands/workspace.c | 241 -- sway/commands/workspace_layout.c | 21 - sway/commands/ws_auto_back_and_forth.c | 14 - sway/commands/xwayland.c | 34 - sway/config.c | 1122 ---------- sway/config/bar.c | 274 --- sway/config/input.c | 398 ---- sway/config/output.c | 909 -------- sway/config/seat.c | 227 -- sway/criteria.c | 792 ------- sway/decoration.c | 65 - sway/desktop/desktop.c | 40 - sway/desktop/idle_inhibit_v1.c | 159 -- sway/desktop/launcher.c | 268 --- sway/desktop/layer_shell.c | 773 ------- sway/desktop/output.c | 1295 ----------- sway/desktop/render.c | 1848 ---------------- sway/desktop/surface.c | 72 - sway/desktop/transaction.c | 552 ----- sway/desktop/xdg_shell.c | 580 ----- sway/desktop/xwayland.c | 937 -------- sway/input/cursor.c | 1522 ------------- sway/input/input-manager.c | 732 ------ sway/input/keyboard.c | 1099 --------- sway/input/libinput.c | 406 ---- sway/input/seat.c | 1777 --------------- sway/input/seatop_default.c | 1160 ---------- sway/input/seatop_down.c | 259 --- sway/input/seatop_move_floating.c | 84 - sway/input/seatop_move_tiling.c | 494 ----- sway/input/seatop_resize_floating.c | 196 -- sway/input/seatop_resize_tiling.c | 166 -- sway/input/switch.c | 125 -- sway/input/tablet.c | 376 ---- sway/input/text_input.c | 684 ------ sway/ipc-json.c | 1481 ------------- sway/ipc-server.c | 972 -------- sway/layer_criteria.c | 91 - sway/lock.c | 219 -- sway/main.c | 431 ---- sway/meson.build | 277 --- sway/realtime.c | 40 - sway/server.c | 401 ---- sway/sway-bar.5.scd | 231 -- sway/sway-input.5.scd | 318 --- sway/sway-ipc.7.scd | 1913 ---------------- sway/sway-output.5.scd | 185 -- sway/sway.1.scd | 113 - sway/sway.5.scd | 1147 ---------- sway/swaynag.c | 165 -- sway/tree/arrange.c | 373 ---- sway/tree/container.c | 1970 ----------------- sway/tree/node.c | 161 -- sway/tree/output.c | 428 ---- sway/tree/root.c | 330 --- sway/tree/view.c | 1493 ------------- sway/tree/workspace.c | 1022 --------- sway/xdg_activation_v1.c | 64 - sway/xdg_decoration.c | 87 - swaybar/bar.c | 555 ----- swaybar/config.c | 136 -- swaybar/i3bar.c | 317 --- swaybar/input.c | 539 ----- swaybar/ipc.c | 606 ----- swaybar/main.c | 104 - swaybar/meson.build | 41 - swaybar/render.c | 863 -------- swaybar/status_line.c | 206 -- swaybar/swaybar-protocol.7.scd | 263 --- swaybar/tray/host.c | 208 -- swaybar/tray/icon.c | 526 ----- swaybar/tray/item.c | 542 ----- swaybar/tray/tray.c | 133 -- swaybar/tray/watcher.c | 216 -- swaymsg/main.c | 645 ------ swaymsg/meson.build | 8 - swaymsg/swaymsg.1.scd | 128 -- swaynag/config.c | 453 ---- swaynag/main.c | 120 - swaynag/meson.build | 21 - swaynag/render.c | 301 --- swaynag/swaynag.1.scd | 135 -- swaynag/swaynag.5.scd | 109 - swaynag/swaynag.c | 568 ----- swaynag/types.c | 186 -- 359 files changed, 62186 deletions(-) delete mode 100644 CONTRIBUTING.md delete mode 100644 LICENSE delete mode 100644 client/meson.build delete mode 100644 client/pool-buffer.c delete mode 100644 common/background-image.c delete mode 100644 common/cairo.c delete mode 100644 common/gesture.c delete mode 100644 common/ipc-client.c delete mode 100644 common/list.c delete mode 100644 common/log.c delete mode 100644 common/loop.c delete mode 100644 common/meson.build delete mode 100644 common/pango.c delete mode 100644 common/stringop.c delete mode 100644 common/util.c delete mode 100644 completions/bash/sway delete mode 100644 completions/bash/swaybar delete mode 100644 completions/bash/swaymsg delete mode 100644 completions/fish/sway.fish delete mode 100644 completions/fish/swaymsg.fish delete mode 100644 completions/fish/swaynag.fish delete mode 100644 completions/meson.build delete mode 100644 completions/zsh/_sway delete mode 100644 completions/zsh/_swaybar delete mode 100644 completions/zsh/_swaymsg delete mode 100644 config.in delete mode 100644 include/background-image.h delete mode 100644 include/cairo_util.h delete mode 100644 include/gesture.h delete mode 100644 include/ipc-client.h delete mode 100644 include/ipc.h delete mode 100644 include/list.h delete mode 100644 include/log.h delete mode 100644 include/loop.h delete mode 100644 include/meson.build delete mode 100644 include/pango.h delete mode 100644 include/pool-buffer.h delete mode 100644 include/stringop.h delete mode 100644 include/sway/commands.h delete mode 100644 include/sway/config.h delete mode 100644 include/sway/criteria.h delete mode 100644 include/sway/decoration.h delete mode 100644 include/sway/desktop.h delete mode 100644 include/sway/desktop/idle_inhibit_v1.h delete mode 100644 include/sway/desktop/launcher.h delete mode 100644 include/sway/desktop/transaction.h delete mode 100644 include/sway/input/cursor.h delete mode 100644 include/sway/input/input-manager.h delete mode 100644 include/sway/input/keyboard.h delete mode 100644 include/sway/input/libinput.h delete mode 100644 include/sway/input/seat.h delete mode 100644 include/sway/input/switch.h delete mode 100644 include/sway/input/tablet.h delete mode 100644 include/sway/input/text_input.h delete mode 100644 include/sway/ipc-json.h delete mode 100644 include/sway/ipc-server.h delete mode 100644 include/sway/layer_criteria.h delete mode 100644 include/sway/layers.h delete mode 100644 include/sway/output.h delete mode 100644 include/sway/server.h delete mode 100644 include/sway/surface.h delete mode 100644 include/sway/swaynag.h delete mode 100644 include/sway/tree/arrange.h delete mode 100644 include/sway/tree/container.h delete mode 100644 include/sway/tree/node.h delete mode 100644 include/sway/tree/root.h delete mode 100644 include/sway/tree/view.h delete mode 100644 include/sway/tree/workspace.h delete mode 100644 include/sway/xdg_decoration.h delete mode 100644 include/sway/xwayland.h delete mode 100644 include/swaybar/bar.h delete mode 100644 include/swaybar/config.h delete mode 100644 include/swaybar/i3bar.h delete mode 100644 include/swaybar/input.h delete mode 100644 include/swaybar/ipc.h delete mode 100644 include/swaybar/render.h delete mode 100644 include/swaybar/status_line.h delete mode 100644 include/swaybar/tray/host.h delete mode 100644 include/swaybar/tray/icon.h delete mode 100644 include/swaybar/tray/item.h delete mode 100644 include/swaybar/tray/tray.h delete mode 100644 include/swaybar/tray/watcher.h delete mode 100644 include/swaynag/config.h delete mode 100644 include/swaynag/render.h delete mode 100644 include/swaynag/swaynag.h delete mode 100644 include/swaynag/types.h delete mode 100644 include/util.h delete mode 100644 meson.build delete mode 100644 meson_options.txt delete mode 100644 protocols/idle.xml delete mode 100644 protocols/meson.build delete mode 100644 protocols/wlr-input-inhibitor-unstable-v1.xml delete mode 100644 protocols/wlr-layer-shell-unstable-v1.xml delete mode 100644 protocols/wlr-output-power-management-unstable-v1.xml delete mode 100644 sway-portals.conf delete mode 100644 sway.desktop 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/bind.c delete mode 100644 sway/commands/bar/binding_mode_indicator.c delete mode 100644 sway/commands/bar/colors.c delete mode 100644 sway/commands/bar/font.c delete mode 100644 sway/commands/bar/gaps.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/separator_symbol.c delete mode 100644 sway/commands/bar/status_command.c delete mode 100644 sway/commands/bar/status_edge_padding.c delete mode 100644 sway/commands/bar/status_padding.c delete mode 100644 sway/commands/bar/strip_workspace_name.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_bind.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/workspace_min_width.c delete mode 100644 sway/commands/bar/wrap_scroll.c delete mode 100644 sway/commands/bind.c delete mode 100644 sway/commands/blur.c delete mode 100644 sway/commands/blur_brightness.c delete mode 100644 sway/commands/blur_contrast.c delete mode 100644 sway/commands/blur_noise.c delete mode 100644 sway/commands/blur_passes.c delete mode 100644 sway/commands/blur_radius.c delete mode 100644 sway/commands/blur_saturation.c delete mode 100644 sway/commands/blur_xray.c delete mode 100644 sway/commands/border.c delete mode 100644 sway/commands/client.c delete mode 100644 sway/commands/corner_radius.c delete mode 100644 sway/commands/create_output.c delete mode 100644 sway/commands/default_border.c delete mode 100644 sway/commands/default_dim_inactive.c delete mode 100644 sway/commands/default_floating_border.c delete mode 100644 sway/commands/default_orientation.c delete mode 100644 sway/commands/dim_inactive.c delete mode 100644 sway/commands/dim_inactive_colors.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_minmax_size.c delete mode 100644 sway/commands/floating_modifier.c delete mode 100644 sway/commands/focus.c delete mode 100644 sway/commands/focus_follows_mouse.c delete mode 100644 sway/commands/focus_on_window_activation.c delete mode 100644 sway/commands/focus_wrapping.c delete mode 100644 sway/commands/font.c delete mode 100644 sway/commands/for_window.c delete mode 100644 sway/commands/force_display_urgency_hint.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/gesture.c delete mode 100644 sway/commands/hide_edge_borders.c delete mode 100644 sway/commands/include.c delete mode 100644 sway/commands/inhibit_idle.c delete mode 100644 sway/commands/input.c delete mode 100644 sway/commands/input/accel_profile.c delete mode 100644 sway/commands/input/calibration_matrix.c delete mode 100644 sway/commands/input/click_method.c delete mode 100644 sway/commands/input/drag.c delete mode 100644 sway/commands/input/drag_lock.c delete mode 100644 sway/commands/input/dwt.c delete mode 100644 sway/commands/input/dwtp.c delete mode 100644 sway/commands/input/events.c delete mode 100644 sway/commands/input/left_handed.c delete mode 100644 sway/commands/input/map_from_region.c delete mode 100644 sway/commands/input/map_to_output.c delete mode 100644 sway/commands/input/map_to_region.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/repeat_delay.c delete mode 100644 sway/commands/input/repeat_rate.c delete mode 100644 sway/commands/input/rotation_angle.c delete mode 100644 sway/commands/input/scroll_button.c delete mode 100644 sway/commands/input/scroll_button_lock.c delete mode 100644 sway/commands/input/scroll_factor.c delete mode 100644 sway/commands/input/scroll_method.c delete mode 100644 sway/commands/input/tap.c delete mode 100644 sway/commands/input/tap_button_map.c delete mode 100644 sway/commands/input/tool_mode.c delete mode 100644 sway/commands/input/xkb_capslock.c delete mode 100644 sway/commands/input/xkb_file.c delete mode 100644 sway/commands/input/xkb_layout.c delete mode 100644 sway/commands/input/xkb_model.c delete mode 100644 sway/commands/input/xkb_numlock.c delete mode 100644 sway/commands/input/xkb_options.c delete mode 100644 sway/commands/input/xkb_rules.c delete mode 100644 sway/commands/input/xkb_switch_layout.c delete mode 100644 sway/commands/input/xkb_variant.c delete mode 100644 sway/commands/kill.c delete mode 100644 sway/commands/layer_effects.c delete mode 100644 sway/commands/layout.c delete mode 100644 sway/commands/mark.c delete mode 100644 sway/commands/max_render_time.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/nop.c delete mode 100644 sway/commands/opacity.c delete mode 100644 sway/commands/output.c delete mode 100644 sway/commands/output/adaptive_sync.c delete mode 100644 sway/commands/output/background.c delete mode 100644 sway/commands/output/disable.c delete mode 100644 sway/commands/output/dpms.c delete mode 100644 sway/commands/output/enable.c delete mode 100644 sway/commands/output/max_render_time.c delete mode 100644 sway/commands/output/mode.c delete mode 100644 sway/commands/output/position.c delete mode 100644 sway/commands/output/power.c delete mode 100644 sway/commands/output/render_bit_depth.c delete mode 100644 sway/commands/output/scale.c delete mode 100644 sway/commands/output/scale_filter.c delete mode 100644 sway/commands/output/subpixel.c delete mode 100644 sway/commands/output/toggle.c delete mode 100644 sway/commands/output/transform.c delete mode 100644 sway/commands/output/unplug.c delete mode 100644 sway/commands/popup_during_fullscreen.c delete mode 100644 sway/commands/primary_selection.c delete mode 100644 sway/commands/reload.c delete mode 100644 sway/commands/rename.c delete mode 100644 sway/commands/resize.c delete mode 100644 sway/commands/saturation.c delete mode 100644 sway/commands/scratchpad.c delete mode 100644 sway/commands/scratchpad_minimize.c delete mode 100644 sway/commands/seat.c delete mode 100644 sway/commands/seat/attach.c delete mode 100644 sway/commands/seat/cursor.c delete mode 100644 sway/commands/seat/fallback.c delete mode 100644 sway/commands/seat/hide_cursor.c delete mode 100644 sway/commands/seat/idle.c delete mode 100644 sway/commands/seat/keyboard_grouping.c delete mode 100644 sway/commands/seat/pointer_constraint.c delete mode 100644 sway/commands/seat/shortcuts_inhibitor.c delete mode 100644 sway/commands/seat/xcursor_theme.c delete mode 100644 sway/commands/set.c delete mode 100644 sway/commands/shadow_blur_radius.c delete mode 100644 sway/commands/shadow_color.c delete mode 100644 sway/commands/shadow_inactive_color.c delete mode 100644 sway/commands/shadow_offset.c delete mode 100644 sway/commands/shadows.c delete mode 100644 sway/commands/shadows_on_csd.c delete mode 100644 sway/commands/shortcuts_inhibitor.c delete mode 100644 sway/commands/show_marks.c delete mode 100644 sway/commands/smart_borders.c delete mode 100644 sway/commands/smart_corner_radius.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/swap.c delete mode 100644 sway/commands/swaybg_command.c delete mode 100644 sway/commands/swaynag_command.c delete mode 100644 sway/commands/tiling_drag.c delete mode 100644 sway/commands/tiling_drag_threshold.c delete mode 100644 sway/commands/title_align.c delete mode 100644 sway/commands/title_format.c delete mode 100644 sway/commands/titlebar_border_thickness.c delete mode 100644 sway/commands/titlebar_padding.c delete mode 100644 sway/commands/titlebar_separator.c delete mode 100644 sway/commands/unmark.c delete mode 100644 sway/commands/urgent.c delete mode 100644 sway/commands/workspace.c delete mode 100644 sway/commands/workspace_layout.c delete mode 100644 sway/commands/ws_auto_back_and_forth.c delete mode 100644 sway/commands/xwayland.c delete mode 100644 sway/config.c delete mode 100644 sway/config/bar.c delete mode 100644 sway/config/input.c delete mode 100644 sway/config/output.c delete mode 100644 sway/config/seat.c delete mode 100644 sway/criteria.c delete mode 100644 sway/decoration.c delete mode 100644 sway/desktop/desktop.c delete mode 100644 sway/desktop/idle_inhibit_v1.c delete mode 100644 sway/desktop/launcher.c delete mode 100644 sway/desktop/layer_shell.c delete mode 100644 sway/desktop/output.c delete mode 100644 sway/desktop/render.c delete mode 100644 sway/desktop/surface.c delete mode 100644 sway/desktop/transaction.c delete mode 100644 sway/desktop/xdg_shell.c delete mode 100644 sway/desktop/xwayland.c delete mode 100644 sway/input/cursor.c delete mode 100644 sway/input/input-manager.c delete mode 100644 sway/input/keyboard.c delete mode 100644 sway/input/libinput.c delete mode 100644 sway/input/seat.c delete mode 100644 sway/input/seatop_default.c delete mode 100644 sway/input/seatop_down.c delete mode 100644 sway/input/seatop_move_floating.c delete mode 100644 sway/input/seatop_move_tiling.c delete mode 100644 sway/input/seatop_resize_floating.c delete mode 100644 sway/input/seatop_resize_tiling.c delete mode 100644 sway/input/switch.c delete mode 100644 sway/input/tablet.c delete mode 100644 sway/input/text_input.c delete mode 100644 sway/ipc-json.c delete mode 100644 sway/ipc-server.c delete mode 100644 sway/layer_criteria.c delete mode 100644 sway/lock.c delete mode 100644 sway/main.c delete mode 100644 sway/meson.build delete mode 100644 sway/realtime.c delete mode 100644 sway/server.c delete mode 100644 sway/sway-bar.5.scd delete mode 100644 sway/sway-input.5.scd delete mode 100644 sway/sway-ipc.7.scd delete mode 100644 sway/sway-output.5.scd delete mode 100644 sway/sway.1.scd delete mode 100644 sway/sway.5.scd delete mode 100644 sway/swaynag.c delete mode 100644 sway/tree/arrange.c delete mode 100644 sway/tree/container.c delete mode 100644 sway/tree/node.c delete mode 100644 sway/tree/output.c delete mode 100644 sway/tree/root.c delete mode 100644 sway/tree/view.c delete mode 100644 sway/tree/workspace.c delete mode 100644 sway/xdg_activation_v1.c delete mode 100644 sway/xdg_decoration.c delete mode 100644 swaybar/bar.c delete mode 100644 swaybar/config.c delete mode 100644 swaybar/i3bar.c delete mode 100644 swaybar/input.c delete mode 100644 swaybar/ipc.c delete mode 100644 swaybar/main.c delete mode 100644 swaybar/meson.build delete mode 100644 swaybar/render.c delete mode 100644 swaybar/status_line.c delete mode 100644 swaybar/swaybar-protocol.7.scd delete mode 100644 swaybar/tray/host.c delete mode 100644 swaybar/tray/icon.c delete mode 100644 swaybar/tray/item.c delete mode 100644 swaybar/tray/tray.c delete mode 100644 swaybar/tray/watcher.c delete mode 100644 swaymsg/main.c delete mode 100644 swaymsg/meson.build delete mode 100644 swaymsg/swaymsg.1.scd delete mode 100644 swaynag/config.c delete mode 100644 swaynag/main.c delete mode 100644 swaynag/meson.build delete mode 100644 swaynag/render.c delete mode 100644 swaynag/swaynag.1.scd delete mode 100644 swaynag/swaynag.5.scd delete mode 100644 swaynag/swaynag.c delete mode 100644 swaynag/types.c diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 4f043f7a7..000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,245 +0,0 @@ -# Contributing to sway - -Contributing just involves sending a pull request. You will probably be more -successful with your contribution if you visit #sway-devel on Libera Chat -upfront and discuss your plans. - -Note: rules are made to be broken. Adjust or ignore any/all of these as you see -fit, but be prepared to justify it to your peers. - -## Scope of future changes to sway - -**Important**: Sway has completed its core value proposition: it is a fully -featured Wayland-compatible replacement for i3. It is not our intention to -expand on the scope of what i3 aims to accomplish. Our priorities now are -increasing the stability, reliability, and performance of sway within its -current scope. For this reason, most new window management feature requests are -not accepted, even if accompanied by a patch. - -## Pull Requests - -If you already have your own pull request habits, feel free to use them. If you -don't, however, allow me to make a suggestion: feature branches pulled from -upstream. Try this: - -1. Fork sway -2. `git clone https://github.com/username/sway && cd sway` -3. `git remote add upstream https://github.com/swaywm/sway` - -You only need to do this once. You're never going to use your fork's master -branch. Instead, when you start working on a feature, do this: - -1. `git fetch upstream` -2. `git checkout -b add-so-and-so-feature upstream/master` -3. Add and commit your changes -4. `git push -u origin add-so-and-so-feature` -5. Make a pull request from your feature branch - -When you submit your pull request, your commit log should do most of the talking -when it comes to describing your changes and their motivation. In addition to -this, your pull request's comments will ideally include a test plan that the -reviewers can use to (1) demonstrate the problem on master, if applicable and -(2) verify that the problem no longer exists with your changes applied (or that -your new features work correctly). Document all of the edge cases you're aware -of so we can adequately test them - then verify the test plan yourself before -submitting. - -## Commit Messages - -Please strive to write good commit messages. Here's some guidelines to follow: - -The first line should be limited to 50 characters and should be a sentence that -completes the thought [When applied, this commit will...] *"Implement -cmd_move"* or *"Fix #742"* or *"Improve performance of arrange_windows on ARM"* -or similar. - -The subsequent lines should be separated from the subject line by a single -blank line, and include optional details. In this you can give justification -for the change, [reference Github -issues](https://help.github.com/articles/closing-issues-via-commit-messages/), -or explain some of the subtler details of your patch. This is important because -when someone finds a line of code they don't understand later, they can use the -`git blame` command to find out what the author was thinking when they wrote -it. It's also easier to review your pull requests if they're separated into -logical commits that have good commit messages and justify themselves in the -extended commit description. - -As a good rule of thumb, anything you might put into the pull request -description on Github is probably fair game for going into the extended commit -message as well. - -See [here](https://chris.beams.io/posts/git-commit/) for more details. - -## Code Review - -When your changes are submitted for review, one or more core committers will -look over them. Smaller changes might be merged with little fanfare, but larger -changes will typically see review from several people. Be prepared to receive -some feedback - you may be asked to make changes to your work. Our code review -process is: - -1. **Triage** the pull request. Do the commit messages make sense? Is a test - plan necessary and/or present? Add anyone as reviewers that you think should - be there (using the relevant GitHub feature, if you have the permissions, or - with an @mention if necessary). -2. **Review** the code. Look for code style violations, naming convention - violations, buffer overflows, memory leaks, logic errors, non-portable code - (including GNU-isms), etc. For significant changes to the public API, loop in - a couple more people for discussion. -3. **Execute** the test plan, if present. -4. **Merge** the pull request when all reviewers approve. -5. **File** follow-up tickets if appropriate. - -## Style Reference - -Sway is written in C with a style similar to the [kernel -style](https://www.kernel.org/doc/Documentation/process/coding-style.rst), but -with a few notable differences. - -Try to keep your code conforming to C11 and POSIX as much as possible, and do -not use GNU extensions. - -### Brackets - -Brackets always go on the same line, including in functions. -Always include brackets for if/while/for, even if it's a single statement. -```c -void function(void) { - if (condition1) { - do_thing1(); - } - - if (condition2) { - do_thing2(); - } else { - do_thing3(); - } -} -``` - -### Indentation - -Indentations are a single tab. - -For long lines that need to be broken, the continuation line should be indented -with an additional tab. - -If the line being broken is opening a new block (functions, if, while, etc.), -the continuation line should be indented with two tabs, so they can't be -misread as being part of the block. - -```c -really_long_function(argument1, argument2, ..., - argument3, argument4); - -if (condition1 && condition2 && ... - condition3 && condition4) { - do_thing(); -} -``` - -Try to break the line in the place which you think is the most appropriate to -balance the lines. - -### Line Length - -Try to keep your lines under 80 columns, assuming a tab width equal to 4 spaces, -but you can go up to 100 if it improves readability. Don't break lines -indiscriminately, try to find nice breaking points so your code is easy to read. - -### Names - -Global function and type names should be prefixed with `sway_submodule_` (e.g. -`struct sway_output`, `sway_output_destroy`). For static functions and -types local to a file, the names chosen aren't as important. Static functions -shouldn't have a `sway_` prefix. - -For include guards, use the header's filename relative to include. Uppercase -all of the characters, and replace any invalid characters with an underscore. - -### Construction/Destruction Functions - -For functions that are responsible for constructing and destructing an object, -they should be written as a pair of one of two forms: - -* `init`/`finish`: These initialize/deinitialize a type, but are **NOT** - responsible for allocating it. They should accept a pointer to some - pre-allocated memory (e.g. a member of a struct). -* `create`/`destroy`: These also initialize/deinitialize, but will return a - pointer to a `malloc`ed chunk of memory, and will `free` it in `destroy`. - -A destruction function should always be able to accept a NULL pointer or a -zeroed value and exit cleanly; this simplifies error handling a lot. - -### Error Codes - -For functions not returning a value, they should return a (stdbool.h) bool to -indicated if they succeeded or not. - -### Macros - -Keep the use of macros to a minimum, especially if a function can do the job. If -you do need to use them, try to keep them close to where they're being used and -`#undef` them after. - -### Example - -```c -struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) { - struct wlr_backend *backend; - if (getenv("WAYLAND_DISPLAY") || getenv("_WAYLAND_DISPLAY")) { - backend = attempt_wl_backend(display); - if (backend) { - return backend; - } - } - - const char *x11_display = getenv("DISPLAY"); - if (x11_display) { - return wlr_x11_backend_create(display, x11_display); - } - - // Attempt DRM+libinput - - struct wlr_session *session = wlr_session_create(display); - if (!session) { - wlr_log(WLR_ERROR, "Failed to start a DRM session"); - return NULL; - } - - int gpu = wlr_session_find_gpu(session); - if (gpu == -1) { - wlr_log(WLR_ERROR, "Failed to open DRM device"); - goto error_session; - } - - backend = wlr_multi_backend_create(session); - if (!backend) { - goto error_gpu; - } - - struct wlr_backend *libinput = wlr_libinput_backend_create(display, session); - if (!libinput) { - goto error_multi; - } - - struct wlr_backend *drm = wlr_drm_backend_create(display, session, gpu); - if (!drm) { - goto error_libinput; - } - - wlr_multi_backend_add(backend, libinput); - wlr_multi_backend_add(backend, drm); - return backend; - -error_libinput: - wlr_backend_destroy(libinput); -error_multi: - wlr_backend_destroy(backend); -error_gpu: - wlr_session_close_file(session, gpu); -error_session: - wlr_session_destroy(session); - return NULL; -} -``` diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 3e0cacc25..000000000 --- a/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2016-2017 Drew DeVault - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/client/meson.build b/client/meson.build deleted file mode 100644 index 4484a38c7..000000000 --- a/client/meson.build +++ /dev/null @@ -1,14 +0,0 @@ -lib_sway_client = static_library( - 'sway-client', - files( - 'pool-buffer.c', - ), - dependencies: [ - cairo, - pango, - pangocairo, - wayland_client - ], - link_with: [lib_sway_common], - include_directories: sway_inc -) diff --git a/client/pool-buffer.c b/client/pool-buffer.c deleted file mode 100644 index 3546b8971..000000000 --- a/client/pool-buffer.c +++ /dev/null @@ -1,132 +0,0 @@ -#define _POSIX_C_SOURCE 200809 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "config.h" -#include "pool-buffer.h" -#include "util.h" - -static int anonymous_shm_open(void) { - int retries = 100; - - do { - // try a probably-unique name - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - pid_t pid = getpid(); - char name[50]; - snprintf(name, sizeof(name), "/sway-%x-%x", - (unsigned int)pid, (unsigned int)ts.tv_nsec); - - // shm_open guarantees that O_CLOEXEC is set - int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); - if (fd >= 0) { - shm_unlink(name); - return fd; - } - - --retries; - } while (retries > 0 && errno == EEXIST); - - return -1; -} - -static void buffer_release(void *data, struct wl_buffer *wl_buffer) { - struct pool_buffer *buffer = data; - buffer->busy = false; -} - -static const struct wl_buffer_listener buffer_listener = { - .release = buffer_release -}; - -static struct pool_buffer *create_buffer(struct wl_shm *shm, - struct pool_buffer *buf, int32_t width, int32_t height, - uint32_t format) { - uint32_t stride = width * 4; - size_t size = stride * height; - - int fd = anonymous_shm_open(); - if (fd == -1) { - return NULL; - } - if (ftruncate(fd, size) < 0) { - close(fd); - return NULL; - } - void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size); - buf->buffer = wl_shm_pool_create_buffer(pool, 0, - width, height, stride, format); - wl_shm_pool_destroy(pool); - close(fd); - - buf->size = size; - buf->width = width; - buf->height = height; - buf->data = data; - buf->surface = cairo_image_surface_create_for_data(data, - CAIRO_FORMAT_ARGB32, width, height, stride); - buf->cairo = cairo_create(buf->surface); - buf->pango = pango_cairo_create_context(buf->cairo); - - wl_buffer_add_listener(buf->buffer, &buffer_listener, buf); - return buf; -} - -void destroy_buffer(struct pool_buffer *buffer) { - if (buffer->buffer) { - wl_buffer_destroy(buffer->buffer); - } - if (buffer->cairo) { - cairo_destroy(buffer->cairo); - } - if (buffer->surface) { - cairo_surface_destroy(buffer->surface); - } - if (buffer->pango) { - g_object_unref(buffer->pango); - } - if (buffer->data) { - munmap(buffer->data, buffer->size); - } - memset(buffer, 0, sizeof(struct pool_buffer)); -} - -struct pool_buffer *get_next_buffer(struct wl_shm *shm, - struct pool_buffer pool[static 2], uint32_t width, uint32_t height) { - struct pool_buffer *buffer = NULL; - - for (size_t i = 0; i < 2; ++i) { - if (pool[i].busy) { - continue; - } - buffer = &pool[i]; - } - - if (!buffer) { - return NULL; - } - - if (buffer->width != width || buffer->height != height) { - destroy_buffer(buffer); - } - - if (!buffer->buffer) { - if (!create_buffer(shm, buffer, width, height, - WL_SHM_FORMAT_ARGB8888)) { - return NULL; - } - } - buffer->busy = true; - return buffer; -} diff --git a/common/background-image.c b/common/background-image.c deleted file mode 100644 index 994a08052..000000000 --- a/common/background-image.c +++ /dev/null @@ -1,220 +0,0 @@ -#include -#include "background-image.h" -#include "cairo_util.h" -#include "log.h" -#if HAVE_GDK_PIXBUF -#include -#endif - -enum background_mode parse_background_mode(const char *mode) { - if (strcmp(mode, "stretch") == 0) { - return BACKGROUND_MODE_STRETCH; - } else if (strcmp(mode, "fill") == 0) { - return BACKGROUND_MODE_FILL; - } else if (strcmp(mode, "fit") == 0) { - return BACKGROUND_MODE_FIT; - } else if (strcmp(mode, "center") == 0) { - return BACKGROUND_MODE_CENTER; - } else if (strcmp(mode, "tile") == 0) { - return BACKGROUND_MODE_TILE; - } else if (strcmp(mode, "solid_color") == 0) { - return BACKGROUND_MODE_SOLID_COLOR; - } - sway_log(SWAY_ERROR, "Unsupported background mode: %s", mode); - return BACKGROUND_MODE_INVALID; -} - -#if HAVE_GDK_PIXBUF -static cairo_surface_t* gdk_cairo_image_surface_create_from_pixbuf( - const GdkPixbuf *gdkbuf) { - int chan = gdk_pixbuf_get_n_channels(gdkbuf); - if (chan < 3) { - return NULL; - } - - const guint8* gdkpix = gdk_pixbuf_read_pixels(gdkbuf); - if (!gdkpix) { - return NULL; - } - gint w = gdk_pixbuf_get_width(gdkbuf); - gint h = gdk_pixbuf_get_height(gdkbuf); - int stride = gdk_pixbuf_get_rowstride(gdkbuf); - - cairo_format_t fmt = (chan == 3) ? CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_ARGB32; - cairo_surface_t * cs = cairo_image_surface_create (fmt, w, h); - cairo_surface_flush (cs); - if ( !cs || cairo_surface_status(cs) != CAIRO_STATUS_SUCCESS) { - return NULL; - } - - int cstride = cairo_image_surface_get_stride(cs); - unsigned char * cpix = cairo_image_surface_get_data(cs); - - if (chan == 3) { - int i; - for (i = h; i; --i) { - const guint8 *gp = gdkpix; - unsigned char *cp = cpix; - const guint8* end = gp + 3*w; - while (gp < end) { -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - cp[0] = gp[2]; - cp[1] = gp[1]; - cp[2] = gp[0]; -#else - cp[1] = gp[0]; - cp[2] = gp[1]; - cp[3] = gp[2]; -#endif - gp += 3; - cp += 4; - } - gdkpix += stride; - cpix += cstride; - } - } else { - /* premul-color = alpha/255 * color/255 * 255 = (alpha*color)/255 - * (z/255) = z/256 * 256/255 = z/256 (1 + 1/255) - * = z/256 + (z/256)/255 = (z + z/255)/256 - * # recurse once - * = (z + (z + z/255)/256)/256 - * = (z + z/256 + z/256/255) / 256 - * # only use 16bit uint operations, loose some precision, - * # result is floored. - * -> (z + z>>8)>>8 - * # add 0x80/255 = 0.5 to convert floor to round - * => (z+0x80 + (z+0x80)>>8 ) >> 8 - * ------ - * tested as equal to lround(z/255.0) for uint z in [0..0xfe02] - */ -#define PREMUL_ALPHA(x,a,b,z) \ - G_STMT_START { z = a * b + 0x80; x = (z + (z >> 8)) >> 8; } \ - G_STMT_END - int i; - for (i = h; i; --i) { - const guint8 *gp = gdkpix; - unsigned char *cp = cpix; - const guint8* end = gp + 4*w; - guint z1, z2, z3; - while (gp < end) { -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - PREMUL_ALPHA(cp[0], gp[2], gp[3], z1); - PREMUL_ALPHA(cp[1], gp[1], gp[3], z2); - PREMUL_ALPHA(cp[2], gp[0], gp[3], z3); - cp[3] = gp[3]; -#else - PREMUL_ALPHA(cp[1], gp[0], gp[3], z1); - PREMUL_ALPHA(cp[2], gp[1], gp[3], z2); - PREMUL_ALPHA(cp[3], gp[2], gp[3], z3); - cp[0] = gp[3]; -#endif - gp += 4; - cp += 4; - } - gdkpix += stride; - cpix += cstride; - } -#undef PREMUL_ALPHA - } - cairo_surface_mark_dirty(cs); - return cs; -} -#endif // HAVE_GDK_PIXBUF - -cairo_surface_t *load_background_image(const char *path) { - cairo_surface_t *image; -#if HAVE_GDK_PIXBUF - GError *err = NULL; - GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(path, &err); - if (!pixbuf) { - sway_log(SWAY_ERROR, "Failed to load background image (%s).", - err->message); - return NULL; - } - image = gdk_cairo_image_surface_create_from_pixbuf(pixbuf); - g_object_unref(pixbuf); -#else - image = cairo_image_surface_create_from_png(path); -#endif // HAVE_GDK_PIXBUF - if (!image) { - sway_log(SWAY_ERROR, "Failed to read background image."); - return NULL; - } - if (cairo_surface_status(image) != CAIRO_STATUS_SUCCESS) { - sway_log(SWAY_ERROR, "Failed to read background image: %s." -#if !HAVE_GDK_PIXBUF - "\nSway was compiled without gdk_pixbuf support, so only" - "\nPNG images can be loaded. This is the likely cause." -#endif // !HAVE_GDK_PIXBUF - , cairo_status_to_string(cairo_surface_status(image))); - return NULL; - } - return image; -} - -void render_background_image(cairo_t *cairo, cairo_surface_t *image, - enum background_mode mode, int buffer_width, int buffer_height) { - double width = cairo_image_surface_get_width(image); - double height = cairo_image_surface_get_height(image); - - cairo_save(cairo); - switch (mode) { - case BACKGROUND_MODE_STRETCH: - cairo_scale(cairo, - (double)buffer_width / width, - (double)buffer_height / height); - cairo_set_source_surface(cairo, image, 0, 0); - break; - case BACKGROUND_MODE_FILL: { - double window_ratio = (double)buffer_width / buffer_height; - double bg_ratio = width / height; - - if (window_ratio > bg_ratio) { - double scale = (double)buffer_width / width; - cairo_scale(cairo, scale, scale); - cairo_set_source_surface(cairo, image, - 0, (double)buffer_height / 2 / scale - height / 2); - } else { - double scale = (double)buffer_height / height; - cairo_scale(cairo, scale, scale); - cairo_set_source_surface(cairo, image, - (double)buffer_width / 2 / scale - width / 2, 0); - } - break; - } - case BACKGROUND_MODE_FIT: { - double window_ratio = (double)buffer_width / buffer_height; - double bg_ratio = width / height; - - if (window_ratio > bg_ratio) { - double scale = (double)buffer_height / height; - cairo_scale(cairo, scale, scale); - cairo_set_source_surface(cairo, image, - (double)buffer_width / 2 / scale - width / 2, 0); - } else { - double scale = (double)buffer_width / width; - cairo_scale(cairo, scale, scale); - cairo_set_source_surface(cairo, image, - 0, (double)buffer_height / 2 / scale - height / 2); - } - break; - } - case BACKGROUND_MODE_CENTER: - cairo_set_source_surface(cairo, image, - (double)buffer_width / 2 - width / 2, - (double)buffer_height / 2 - height / 2); - break; - case BACKGROUND_MODE_TILE: { - cairo_pattern_t *pattern = cairo_pattern_create_for_surface(image); - cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); - cairo_set_source(cairo, pattern); - break; - } - case BACKGROUND_MODE_SOLID_COLOR: - case BACKGROUND_MODE_INVALID: - assert(0); - break; - } - cairo_paint(cairo); - cairo_restore(cairo); -} diff --git a/common/cairo.c b/common/cairo.c deleted file mode 100644 index 7c59d48c4..000000000 --- a/common/cairo.c +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include -#include "cairo_util.h" - -void cairo_set_source_u32(cairo_t *cairo, uint32_t color) { - cairo_set_source_rgba(cairo, - (color >> (3*8) & 0xFF) / 255.0, - (color >> (2*8) & 0xFF) / 255.0, - (color >> (1*8) & 0xFF) / 255.0, - (color >> (0*8) & 0xFF) / 255.0); -} - -cairo_subpixel_order_t to_cairo_subpixel_order(enum wl_output_subpixel subpixel) { - switch (subpixel) { - case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB: - return CAIRO_SUBPIXEL_ORDER_RGB; - case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR: - return CAIRO_SUBPIXEL_ORDER_BGR; - case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB: - return CAIRO_SUBPIXEL_ORDER_VRGB; - case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR: - return CAIRO_SUBPIXEL_ORDER_VBGR; - default: - return CAIRO_SUBPIXEL_ORDER_DEFAULT; - } - return CAIRO_SUBPIXEL_ORDER_DEFAULT; -} - -cairo_surface_t *cairo_image_surface_scale(cairo_surface_t *image, - int width, int height) { - int image_width = cairo_image_surface_get_width(image); - int image_height = cairo_image_surface_get_height(image); - - cairo_surface_t *new = - cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); - cairo_t *cairo = cairo_create(new); - cairo_scale(cairo, (double)width / image_width, - (double)height / image_height); - cairo_set_source_surface(cairo, image, 0, 0); - - cairo_paint(cairo); - cairo_destroy(cairo); - return new; -} diff --git a/common/gesture.c b/common/gesture.c deleted file mode 100644 index 58170443d..000000000 --- a/common/gesture.c +++ /dev/null @@ -1,333 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include "gesture.h" - -#include -#include -#include -#include -#include -#include "list.h" -#include "log.h" -#include "stringop.h" - -const uint8_t GESTURE_FINGERS_ANY = 0; - -char *gesture_parse(const char *input, struct gesture *output) { - // Clear output in case of failure - output->type = GESTURE_TYPE_NONE; - output->fingers = GESTURE_FINGERS_ANY; - output->directions = GESTURE_DIRECTION_NONE; - - // Split input type, fingers and directions - list_t *split = split_string(input, ":"); - if (split->length < 1 || split->length > 3) { - return format_str( - "expected [:][:direction], got %s", - input); - } - - // Parse gesture type - if (strcmp(split->items[0], "hold") == 0) { - output->type = GESTURE_TYPE_HOLD; - } else if (strcmp(split->items[0], "pinch") == 0) { - output->type = GESTURE_TYPE_PINCH; - } else if (strcmp(split->items[0], "swipe") == 0) { - output->type = GESTURE_TYPE_SWIPE; - } else { - return format_str("expected hold|pinch|swipe, got %s", - (const char *)split->items[0]); - } - - // Parse optional arguments - if (split->length > 1) { - char *next = split->items[1]; - - // Try to parse as finger count (1-9) - if (strlen(next) == 1 && '1' <= next[0] && next[0] <= '9') { - output->fingers = atoi(next); - - // Move to next if available - next = split->length == 3 ? split->items[2] : NULL; - } else if (split->length == 3) { - // Fail here if argument can only be finger count - return format_str("expected 1-9, got %s", next); - } - - // If there is an argument left, try to parse as direction - if (next) { - list_t *directions = split_string(next, "+"); - - for (int i = 0; i < directions->length; ++i) { - const char *item = directions->items[i]; - if (strcmp(item, "any") == 0) { - continue; - } else if (strcmp(item, "up") == 0) { - output->directions |= GESTURE_DIRECTION_UP; - } else if (strcmp(item, "down") == 0) { - output->directions |= GESTURE_DIRECTION_DOWN; - } else if (strcmp(item, "left") == 0) { - output->directions |= GESTURE_DIRECTION_LEFT; - } else if (strcmp(item, "right") == 0) { - output->directions |= GESTURE_DIRECTION_RIGHT; - } else if (strcmp(item, "inward") == 0) { - output->directions |= GESTURE_DIRECTION_INWARD; - } else if (strcmp(item, "outward") == 0) { - output->directions |= GESTURE_DIRECTION_OUTWARD; - } else if (strcmp(item, "clockwise") == 0) { - output->directions |= GESTURE_DIRECTION_CLOCKWISE; - } else if (strcmp(item, "counterclockwise") == 0) { - output->directions |= GESTURE_DIRECTION_COUNTERCLOCKWISE; - } else { - return format_str("expected direction, got %s", item); - } - } - list_free_items_and_destroy(directions); - } - } // if optional args - - list_free_items_and_destroy(split); - - return NULL; -} - -const char *gesture_type_string(enum gesture_type type) { - switch (type) { - case GESTURE_TYPE_NONE: - return "none"; - case GESTURE_TYPE_HOLD: - return "hold"; - case GESTURE_TYPE_PINCH: - return "pinch"; - case GESTURE_TYPE_SWIPE: - return "swipe"; - } - - return NULL; -} - -const char *gesture_direction_string(enum gesture_direction direction) { - switch (direction) { - case GESTURE_DIRECTION_NONE: - return "none"; - case GESTURE_DIRECTION_UP: - return "up"; - case GESTURE_DIRECTION_DOWN: - return "down"; - case GESTURE_DIRECTION_LEFT: - return "left"; - case GESTURE_DIRECTION_RIGHT: - return "right"; - case GESTURE_DIRECTION_INWARD: - return "inward"; - case GESTURE_DIRECTION_OUTWARD: - return "outward"; - case GESTURE_DIRECTION_CLOCKWISE: - return "clockwise"; - case GESTURE_DIRECTION_COUNTERCLOCKWISE: - return "counterclockwise"; - } - - return NULL; -} - -// Helper to turn combination of directions flags into string representation. -static char *gesture_directions_to_string(uint32_t directions) { - char *result = NULL; - - for (uint8_t bit = 0; bit < 32; bit++) { - uint32_t masked = directions & (1 << bit); - if (masked) { - const char *name = gesture_direction_string(masked); - - if (!name) { - name = "unknown"; - } - - if (!result) { - result = strdup(name); - } else { - char *new = format_str("%s+%s", result, name); - free(result); - result = new; - } - } - } - - if(!result) { - return strdup("any"); - } - - return result; -} - -char *gesture_to_string(struct gesture *gesture) { - char *directions = gesture_directions_to_string(gesture->directions); - char *result = format_str("%s:%u:%s", - gesture_type_string(gesture->type), - gesture->fingers, directions); - free(directions); - return result; -} - -bool gesture_check(struct gesture *target, enum gesture_type type, uint8_t fingers) { - // Check that gesture type matches - if (target->type != type) { - return false; - } - - // Check that finger count matches - if (target->fingers != GESTURE_FINGERS_ANY && target->fingers != fingers) { - return false; - } - - return true; -} - -bool gesture_match(struct gesture *target, struct gesture *to_match, bool exact) { - // Check type and fingers - if (!gesture_check(target, to_match->type, to_match->fingers)) { - return false; - } - - // Enforce exact matches ... - if (exact && target->directions != to_match->directions) { - return false; - } - - // ... or ensure all target directions are matched - return (target->directions & to_match->directions) == target->directions; -} - -bool gesture_equal(struct gesture *a, struct gesture *b) { - return a->type == b->type - && a->fingers == b->fingers - && a->directions == b->directions; -} - -// Return count of set bits in directions bit field. -static uint8_t gesture_directions_count(uint32_t directions) { - uint8_t count = 0; - for (; directions; directions >>= 1) { - count += directions & 1; - } - return count; -} - -// Compare direction bit count of two direction. -static int8_t gesture_directions_compare(uint32_t a, uint32_t b) { - return gesture_directions_count(a) - gesture_directions_count(b); -} - -// Compare two direction based on their direction bit count -int8_t gesture_compare(struct gesture *a, struct gesture *b) { - return gesture_directions_compare(a->directions, b->directions); -} - -void gesture_tracker_begin(struct gesture_tracker *tracker, - enum gesture_type type, uint8_t fingers) { - tracker->type = type; - tracker->fingers = fingers; - - tracker->dx = 0.0; - tracker->dy = 0.0; - tracker->scale = 1.0; - tracker->rotation = 0.0; - - sway_log(SWAY_DEBUG, "begin tracking %s:%u:? gesture", - gesture_type_string(type), fingers); -} - -bool gesture_tracker_check(struct gesture_tracker *tracker, enum gesture_type type) { - return tracker->type == type; -} - -void gesture_tracker_update(struct gesture_tracker *tracker, - double dx, double dy, double scale, double rotation) { - if (tracker->type == GESTURE_TYPE_HOLD) { - sway_assert(false, "hold does not update."); - return; - } - - tracker->dx += dx; - tracker->dy += dy; - - if (tracker->type == GESTURE_TYPE_PINCH) { - tracker->scale = scale; - tracker->rotation += rotation; - } - - sway_log(SWAY_DEBUG, "update tracking %s:%u:? gesture: %f %f %f %f", - gesture_type_string(tracker->type), - tracker->fingers, - tracker->dx, tracker->dy, - tracker->scale, tracker->rotation); -} - -void gesture_tracker_cancel(struct gesture_tracker *tracker) { - sway_log(SWAY_DEBUG, "cancel tracking %s:%u:? gesture", - gesture_type_string(tracker->type), tracker->fingers); - - tracker->type = GESTURE_TYPE_NONE; -} - -struct gesture *gesture_tracker_end(struct gesture_tracker *tracker) { - struct gesture *result = calloc(1, sizeof(struct gesture)); - - // Ignore gesture under some threshold - // TODO: Make configurable - const double min_rotation = 5; - const double min_scale_delta = 0.1; - - // Determine direction - switch(tracker->type) { - // Gestures with scale and rotation - case GESTURE_TYPE_PINCH: - if (tracker->rotation > min_rotation) { - result->directions |= GESTURE_DIRECTION_CLOCKWISE; - } - if (tracker->rotation < -min_rotation) { - result->directions |= GESTURE_DIRECTION_COUNTERCLOCKWISE; - } - - if (tracker->scale > (1.0 + min_scale_delta)) { - result->directions |= GESTURE_DIRECTION_OUTWARD; - } - if (tracker->scale < (1.0 - min_scale_delta)) { - result->directions |= GESTURE_DIRECTION_INWARD; - } - __attribute__ ((fallthrough)); - // Gestures with dx and dy - case GESTURE_TYPE_SWIPE: - if (fabs(tracker->dx) > fabs(tracker->dy)) { - if (tracker->dx > 0) { - result->directions |= GESTURE_DIRECTION_RIGHT; - } else { - result->directions |= GESTURE_DIRECTION_LEFT; - } - } else { - if (tracker->dy > 0) { - result->directions |= GESTURE_DIRECTION_DOWN; - } else { - result->directions |= GESTURE_DIRECTION_UP; - } - } - // Gesture without any direction - case GESTURE_TYPE_HOLD: - break; - // Not tracking any gesture - case GESTURE_TYPE_NONE: - sway_assert(false, "Not tracking any gesture."); - return result; - } - - result->type = tracker->type; - result->fingers = tracker->fingers; - - char *description = gesture_to_string(result); - sway_log(SWAY_DEBUG, "end tracking gesture: %s", description); - free(description); - - tracker->type = GESTURE_TYPE_NONE; - - return result; -} diff --git a/common/ipc-client.c b/common/ipc-client.c deleted file mode 100644 index d30212d25..000000000 --- a/common/ipc-client.c +++ /dev/null @@ -1,149 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include -#include "ipc-client.h" -#include "log.h" - -static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'}; - -#define IPC_HEADER_SIZE (sizeof(ipc_magic) + 8) - -char *get_socketpath(void) { - const char *swaysock = getenv("SWAYSOCK"); - if (swaysock) { - return strdup(swaysock); - } - char *line = NULL; - size_t line_size = 0; - FILE *fp = popen("sway --get-socketpath 2>/dev/null", "r"); - if (fp) { - ssize_t nret = getline(&line, &line_size, fp); - pclose(fp); - if (nret > 0) { - // remove trailing newline, if there is one - if (line[nret - 1] == '\n') { - line[nret - 1] = '\0'; - } - return line; - } - } - const char *i3sock = getenv("I3SOCK"); - if (i3sock) { - free(line); - return strdup(i3sock); - } - fp = popen("i3 --get-socketpath 2>/dev/null", "r"); - if (fp) { - ssize_t nret = getline(&line, &line_size, fp); - pclose(fp); - if (nret > 0) { - // remove trailing newline, if there is one - if (line[nret - 1] == '\n') { - line[nret - 1] = '\0'; - } - return line; - } - } - free(line); - return NULL; -} - -int ipc_open_socket(const char *socket_path) { - struct sockaddr_un addr; - int socketfd; - if ((socketfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { - sway_abort("Unable to open Unix socket"); - } - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1); - addr.sun_path[sizeof(addr.sun_path) - 1] = 0; - int l = sizeof(struct sockaddr_un); - if (connect(socketfd, (struct sockaddr *)&addr, l) == -1) { - sway_abort("Unable to connect to %s", socket_path); - } - return socketfd; -} - -bool ipc_set_recv_timeout(int socketfd, struct timeval tv) { - if (setsockopt(socketfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) { - sway_log_errno(SWAY_ERROR, "Failed to set ipc recv timeout"); - return false; - } - return true; -} - -struct ipc_response *ipc_recv_response(int socketfd) { - char data[IPC_HEADER_SIZE]; - - size_t total = 0; - while (total < IPC_HEADER_SIZE) { - ssize_t received = recv(socketfd, data + total, IPC_HEADER_SIZE - total, 0); - if (received <= 0) { - sway_abort("Unable to receive IPC response"); - } - total += received; - } - - struct ipc_response *response = malloc(sizeof(struct ipc_response)); - if (!response) { - goto error_1; - } - - memcpy(&response->size, data + sizeof(ipc_magic), sizeof(uint32_t)); - memcpy(&response->type, data + sizeof(ipc_magic) + sizeof(uint32_t), sizeof(uint32_t)); - - char *payload = malloc(response->size + 1); - if (!payload) { - goto error_2; - } - - total = 0; - while (total < response->size) { - ssize_t received = recv(socketfd, payload + total, response->size - total, 0); - if (received < 0) { - sway_abort("Unable to receive IPC response"); - } - total += received; - } - payload[response->size] = '\0'; - response->payload = payload; - - return response; -error_2: - free(response); -error_1: - sway_log(SWAY_ERROR, "Unable to allocate memory for IPC response"); - return NULL; -} - -void free_ipc_response(struct ipc_response *response) { - free(response->payload); - free(response); -} - -char *ipc_single_command(int socketfd, uint32_t type, const char *payload, uint32_t *len) { - char data[IPC_HEADER_SIZE]; - memcpy(data, ipc_magic, sizeof(ipc_magic)); - memcpy(data + sizeof(ipc_magic), len, sizeof(*len)); - memcpy(data + sizeof(ipc_magic) + sizeof(*len), &type, sizeof(type)); - - if (write(socketfd, data, IPC_HEADER_SIZE) == -1) { - sway_abort("Unable to send IPC header"); - } - - if (write(socketfd, payload, *len) == -1) { - sway_abort("Unable to send IPC payload"); - } - - struct ipc_response *resp = ipc_recv_response(socketfd); - char *response = resp->payload; - *len = resp->size; - free(resp); - - return response; -} diff --git a/common/list.c b/common/list.c deleted file mode 100644 index c3e2fe204..000000000 --- a/common/list.c +++ /dev/null @@ -1,160 +0,0 @@ -#include "list.h" -#include -#include -#include -#include "log.h" - -list_t *create_list(void) { - list_t *list = malloc(sizeof(list_t)); - if (!list) { - return NULL; - } - list->capacity = 10; - list->length = 0; - list->items = malloc(sizeof(void*) * list->capacity); - return list; -} - -static void list_resize(list_t *list) { - if (list->length == list->capacity) { - list->capacity *= 2; - list->items = realloc(list->items, sizeof(void*) * list->capacity); - } -} - -void list_free(list_t *list) { - if (list == NULL) { - return; - } - free(list->items); - free(list); -} - -void list_add(list_t *list, void *item) { - list_resize(list); - list->items[list->length++] = item; -} - -void list_insert(list_t *list, int index, void *item) { - list_resize(list); - memmove(&list->items[index + 1], &list->items[index], sizeof(void*) * (list->length - index)); - list->length++; - list->items[index] = item; -} - -void list_del(list_t *list, int index) { - list->length--; - memmove(&list->items[index], &list->items[index + 1], sizeof(void*) * (list->length - index)); -} - -void list_cat(list_t *list, list_t *source) { - for (int i = 0; i < source->length; ++i) { - list_add(list, source->items[i]); - } -} - -void list_qsort(list_t *list, int compare(const void *left, const void *right)) { - qsort(list->items, list->length, sizeof(void *), compare); -} - -int list_seq_find(list_t *list, int compare(const void *item, const void *data), const void *data) { - for (int i = 0; i < list->length; i++) { - void *item = list->items[i]; - if (compare(item, data) == 0) { - return i; - } - } - return -1; -} - -int list_find(list_t *list, const void *item) { - for (int i = 0; i < list->length; i++) { - if (list->items[i] == item) { - return i; - } - } - return -1; -} - -void list_swap(list_t *list, int src, int dest) { - void *tmp = list->items[src]; - list->items[src] = list->items[dest]; - list->items[dest] = tmp; -} - -void list_move_to_end(list_t *list, void *item) { - int i; - for (i = 0; i < list->length; ++i) { - if (list->items[i] == item) { - break; - } - } - if (!sway_assert(i < list->length, "Item not found in list")) { - return; - } - list_del(list, i); - list_add(list, item); -} - -static void list_rotate(list_t *list, int from, int to) { - void *tmp = list->items[to]; - - while (to > from) { - list->items[to] = list->items[to - 1]; - to--; - } - - list->items[from] = tmp; -} - -static void list_inplace_merge(list_t *list, int left, int last, int mid, int compare(const void *a, const void *b)) { - int right = mid + 1; - - if (compare(&list->items[mid], &list->items[right]) <= 0) { - return; - } - - while (left <= mid && right <= last) { - if (compare(&list->items[left], &list->items[right]) <= 0) { - left++; - } else { - list_rotate(list, left, right); - left++; - mid++; - right++; - } - } -} - -static void list_inplace_sort(list_t *list, int first, int last, int compare(const void *a, const void *b)) { - if (first >= last) { - return; - } else if ((last - first) == 1) { - if (compare(&list->items[first], &list->items[last]) > 0) { - list_swap(list, first, last); - } - } else { - int mid = (int)((last + first) / 2); - list_inplace_sort(list, first, mid, compare); - list_inplace_sort(list, mid + 1, last, compare); - list_inplace_merge(list, first, last, mid, compare); - } -} - -void list_stable_sort(list_t *list, int compare(const void *a, const void *b)) { - if (list->length > 1) { - list_inplace_sort(list, 0, list->length - 1, compare); - } -} - -void list_free_items_and_destroy(list_t *list) { - if (!list) { - return; - } - - for (int i = 0; i < list->length; ++i) { - free(list->items[i]); - } - list_free(list); -} - diff --git a/common/log.c b/common/log.c deleted file mode 100644 index 483420e7f..000000000 --- a/common/log.c +++ /dev/null @@ -1,126 +0,0 @@ -#define _POSIX_C_SOURCE 200112L -#include -#include -#include -#include -#include -#include -#include "log.h" - -static terminate_callback_t log_terminate = exit; - -void _sway_abort(const char *format, ...) { - va_list args; - va_start(args, format); - _sway_vlog(SWAY_ERROR, format, args); - va_end(args); - log_terminate(EXIT_FAILURE); -} - -bool _sway_assert(bool condition, const char *format, ...) { - if (condition) { - return true; - } - - va_list args; - va_start(args, format); - _sway_vlog(SWAY_ERROR, format, args); - va_end(args); - -#ifndef NDEBUG - raise(SIGABRT); -#endif - - return false; -} - -static bool colored = true; -static sway_log_importance_t log_importance = SWAY_ERROR; -static struct timespec start_time = {-1, -1}; - -static const char *verbosity_colors[] = { - [SWAY_SILENT] = "", - [SWAY_ERROR ] = "\x1B[1;31m", - [SWAY_INFO ] = "\x1B[1;34m", - [SWAY_DEBUG ] = "\x1B[1;90m", -}; - -static const char *verbosity_headers[] = { - [SWAY_SILENT] = "", - [SWAY_ERROR] = "[ERROR]", - [SWAY_INFO] = "[INFO]", - [SWAY_DEBUG] = "[DEBUG]", -}; - -static void timespec_sub(struct timespec *r, const struct timespec *a, - const struct timespec *b) { - const long NSEC_PER_SEC = 1000000000; - r->tv_sec = a->tv_sec - b->tv_sec; - r->tv_nsec = a->tv_nsec - b->tv_nsec; - if (r->tv_nsec < 0) { - r->tv_sec--; - r->tv_nsec += NSEC_PER_SEC; - } -} - -static void init_start_time(void) { - if (start_time.tv_sec >= 0) { - return; - } - clock_gettime(CLOCK_MONOTONIC, &start_time); -} - -static void sway_log_stderr(sway_log_importance_t verbosity, const char *fmt, - va_list args) { - init_start_time(); - - if (verbosity > log_importance) { - return; - } - - struct timespec ts = {0}; - clock_gettime(CLOCK_MONOTONIC, &ts); - timespec_sub(&ts, &ts, &start_time); - - fprintf(stderr, "%02d:%02d:%02d.%03ld ", (int)(ts.tv_sec / 60 / 60), - (int)(ts.tv_sec / 60 % 60), (int)(ts.tv_sec % 60), - ts.tv_nsec / 1000000); - - unsigned c = (verbosity < SWAY_LOG_IMPORTANCE_LAST) ? verbosity : - SWAY_LOG_IMPORTANCE_LAST - 1; - - if (colored && isatty(STDERR_FILENO)) { - fprintf(stderr, "%s", verbosity_colors[c]); - } else { - fprintf(stderr, "%s ", verbosity_headers[c]); - } - - vfprintf(stderr, fmt, args); - - if (colored && isatty(STDERR_FILENO)) { - fprintf(stderr, "\x1B[0m"); - } - fprintf(stderr, "\n"); -} - -void sway_log_init(sway_log_importance_t verbosity, terminate_callback_t callback) { - init_start_time(); - - if (verbosity < SWAY_LOG_IMPORTANCE_LAST) { - log_importance = verbosity; - } - if (callback) { - log_terminate = callback; - } -} - -void _sway_vlog(sway_log_importance_t verbosity, const char *fmt, va_list args) { - sway_log_stderr(verbosity, fmt, args); -} - -void _sway_log(sway_log_importance_t verbosity, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - sway_log_stderr(verbosity, fmt, args); - va_end(args); -} diff --git a/common/loop.c b/common/loop.c deleted file mode 100644 index 80fe18eae..000000000 --- a/common/loop.c +++ /dev/null @@ -1,184 +0,0 @@ -#define _POSIX_C_SOURCE 200112L -#include -#include -#include -#include -#include -#include -#include -#include -#include "list.h" -#include "log.h" -#include "loop.h" - -struct loop_fd_event { - void (*callback)(int fd, short mask, void *data); - void *data; -}; - -struct loop_timer { - void (*callback)(void *data); - void *data; - struct timespec expiry; -}; - -struct loop { - struct pollfd *fds; - int fd_length; - int fd_capacity; - - list_t *fd_events; // struct loop_fd_event - list_t *timers; // struct loop_timer -}; - -struct loop *loop_create(void) { - struct loop *loop = calloc(1, sizeof(struct loop)); - if (!loop) { - sway_log(SWAY_ERROR, "Unable to allocate memory for loop"); - return NULL; - } - loop->fd_capacity = 10; - loop->fds = malloc(sizeof(struct pollfd) * loop->fd_capacity); - loop->fd_events = create_list(); - loop->timers = create_list(); - return loop; -} - -void loop_destroy(struct loop *loop) { - list_free_items_and_destroy(loop->fd_events); - list_free_items_and_destroy(loop->timers); - free(loop->fds); - free(loop); -} - -void loop_poll(struct loop *loop) { - // Calculate next timer in ms - int ms = INT_MAX; - if (loop->timers->length) { - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - for (int i = 0; i < loop->timers->length; ++i) { - struct loop_timer *timer = loop->timers->items[i]; - int timer_ms = (timer->expiry.tv_sec - now.tv_sec) * 1000; - timer_ms += (timer->expiry.tv_nsec - now.tv_nsec) / 1000000; - if (timer_ms < ms) { - ms = timer_ms; - } - } - } - if (ms < 0) { - ms = 0; - } - - poll(loop->fds, loop->fd_length, ms); - - // Dispatch fds - for (int i = 0; i < loop->fd_length; ++i) { - struct pollfd pfd = loop->fds[i]; - struct loop_fd_event *event = loop->fd_events->items[i]; - - // Always send these events - unsigned events = pfd.events | POLLHUP | POLLERR; - - if (pfd.revents & events) { - event->callback(pfd.fd, pfd.revents, event->data); - } - } - - // Dispatch timers - if (loop->timers->length) { - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - for (int i = 0; i < loop->timers->length; ++i) { - struct loop_timer *timer = loop->timers->items[i]; - bool expired = timer->expiry.tv_sec < now.tv_sec || - (timer->expiry.tv_sec == now.tv_sec && - timer->expiry.tv_nsec < now.tv_nsec); - if (expired) { - timer->callback(timer->data); - loop_remove_timer(loop, timer); - --i; - } - } - } -} - -void loop_add_fd(struct loop *loop, int fd, short mask, - void (*callback)(int fd, short mask, void *data), void *data) { - struct loop_fd_event *event = calloc(1, sizeof(struct loop_fd_event)); - if (!event) { - sway_log(SWAY_ERROR, "Unable to allocate memory for event"); - return; - } - event->callback = callback; - event->data = data; - list_add(loop->fd_events, event); - - struct pollfd pfd = {fd, mask, 0}; - - if (loop->fd_length == loop->fd_capacity) { - int capacity = loop->fd_capacity + 10; - struct pollfd *tmp = realloc(loop->fds, - sizeof(struct pollfd) * capacity); - if (!tmp) { - sway_log(SWAY_ERROR, "Unable to allocate memory for pollfd"); - return; - } - loop->fds = tmp; - loop->fd_capacity = capacity; - } - - loop->fds[loop->fd_length++] = pfd; -} - -struct loop_timer *loop_add_timer(struct loop *loop, int ms, - void (*callback)(void *data), void *data) { - struct loop_timer *timer = calloc(1, sizeof(struct loop_timer)); - if (!timer) { - sway_log(SWAY_ERROR, "Unable to allocate memory for timer"); - return NULL; - } - timer->callback = callback; - timer->data = data; - - clock_gettime(CLOCK_MONOTONIC, &timer->expiry); - timer->expiry.tv_sec += ms / 1000; - - long int nsec = (ms % 1000) * 1000000; - if (timer->expiry.tv_nsec + nsec >= 1000000000) { - timer->expiry.tv_sec++; - nsec -= 1000000000; - } - timer->expiry.tv_nsec += nsec; - - list_add(loop->timers, timer); - - return timer; -} - -bool loop_remove_fd(struct loop *loop, int fd) { - for (int i = 0; i < loop->fd_length; ++i) { - if (loop->fds[i].fd == fd) { - free(loop->fd_events->items[i]); - list_del(loop->fd_events, i); - - loop->fd_length--; - memmove(&loop->fds[i], &loop->fds[i + 1], - sizeof(struct pollfd) * (loop->fd_length - i)); - - return true; - } - } - return false; -} - -bool loop_remove_timer(struct loop *loop, struct loop_timer *timer) { - for (int i = 0; i < loop->timers->length; ++i) { - if (loop->timers->items[i] == timer) { - list_del(loop->timers, i); - free(timer); - return true; - } - } - return false; -} diff --git a/common/meson.build b/common/meson.build deleted file mode 100644 index 3756075a9..000000000 --- a/common/meson.build +++ /dev/null @@ -1,23 +0,0 @@ -lib_sway_common = static_library( - 'sway-common', - files( - 'background-image.c', - 'cairo.c', - 'gesture.c', - 'ipc-client.c', - 'log.c', - 'loop.c', - 'list.c', - 'pango.c', - 'stringop.c', - 'util.c' - ), - dependencies: [ - cairo, - gdk_pixbuf, - pango, - pangocairo, - wayland_client.partial_dependency(compile_args: true) - ], - include_directories: sway_inc -) diff --git a/common/pango.c b/common/pango.c deleted file mode 100644 index 288569b30..000000000 --- a/common/pango.c +++ /dev/null @@ -1,138 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include "cairo_util.h" -#include "log.h" -#include "stringop.h" - -size_t escape_markup_text(const char *src, char *dest) { - size_t length = 0; - if (dest) { - dest[0] = '\0'; - } - - while (src[0]) { - switch (src[0]) { - case '&': - length += 5; - lenient_strcat(dest, "&"); - break; - case '<': - length += 4; - lenient_strcat(dest, "<"); - break; - case '>': - length += 4; - lenient_strcat(dest, ">"); - break; - case '\'': - length += 6; - lenient_strcat(dest, "'"); - break; - case '"': - length += 6; - lenient_strcat(dest, """); - break; - default: - if (dest) { - dest[length] = *src; - dest[length + 1] = '\0'; - } - length += 1; - } - src++; - } - return length; -} - -PangoLayout *get_pango_layout(cairo_t *cairo, const PangoFontDescription *desc, - const char *text, double scale, bool markup) { - PangoLayout *layout = pango_cairo_create_layout(cairo); - PangoAttrList *attrs; - if (markup) { - char *buf; - GError *error = NULL; - if (pango_parse_markup(text, -1, 0, &attrs, &buf, NULL, &error)) { - pango_layout_set_text(layout, buf, -1); - free(buf); - } else { - sway_log(SWAY_ERROR, "pango_parse_markup '%s' -> error %s", text, - error->message); - g_error_free(error); - markup = false; // fallback to plain text - } - } - if (!markup) { - attrs = pango_attr_list_new(); - pango_layout_set_text(layout, text, -1); - } - - pango_attr_list_insert(attrs, pango_attr_scale_new(scale)); - pango_layout_set_font_description(layout, desc); - pango_layout_set_single_paragraph_mode(layout, 1); - pango_layout_set_attributes(layout, attrs); - pango_attr_list_unref(attrs); - return layout; -} - -void get_text_size(cairo_t *cairo, const PangoFontDescription *desc, int *width, int *height, - int *baseline, double scale, bool markup, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - char *buf = vformat_str(fmt, args); - va_end(args); - if (buf == NULL) { - return; - } - - PangoLayout *layout = get_pango_layout(cairo, desc, buf, scale, markup); - pango_cairo_update_layout(cairo, layout); - pango_layout_get_pixel_size(layout, width, height); - if (baseline) { - *baseline = pango_layout_get_baseline(layout) / PANGO_SCALE; - } - g_object_unref(layout); - - free(buf); -} - -void get_text_metrics(const PangoFontDescription *description, int *height, int *baseline) { - cairo_t *cairo = cairo_create(NULL); - PangoContext *pango = pango_cairo_create_context(cairo); - // When passing NULL as a language, pango uses the current locale. - PangoFontMetrics *metrics = pango_context_get_metrics(pango, description, NULL); - - *baseline = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE; - *height = *baseline + pango_font_metrics_get_descent(metrics) / PANGO_SCALE; - - pango_font_metrics_unref(metrics); - g_object_unref(pango); - cairo_destroy(cairo); -} - -void render_text(cairo_t *cairo, const PangoFontDescription *desc, - double scale, bool markup, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - char *buf = vformat_str(fmt, args); - va_end(args); - if (buf == NULL) { - return; - } - - PangoLayout *layout = get_pango_layout(cairo, desc, buf, scale, markup); - cairo_font_options_t *fo = cairo_font_options_create(); - cairo_get_font_options(cairo, fo); - pango_cairo_context_set_font_options(pango_layout_get_context(layout), fo); - cairo_font_options_destroy(fo); - pango_cairo_update_layout(cairo, layout); - pango_cairo_show_layout(cairo, layout); - g_object_unref(layout); - - free(buf); -} diff --git a/common/stringop.c b/common/stringop.c deleted file mode 100644 index c503143ae..000000000 --- a/common/stringop.c +++ /dev/null @@ -1,363 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include -#include -#include "list.h" -#include "log.h" -#include "stringop.h" - -static const char whitespace[] = " \f\n\r\t\v"; - -void strip_whitespace(char *str) { - size_t len = strlen(str); - size_t start = strspn(str, whitespace); - memmove(str, &str[start], len + 1 - start); - - if (*str) { - for (len -= start + 1; isspace(str[len]); --len) {} - str[len + 1] = '\0'; - } -} - -void strip_quotes(char *str) { - bool in_str = false; - bool in_chr = false; - bool escaped = false; - char *end = strchr(str,0); - while (*str) { - if (*str == '\'' && !in_str && !escaped) { - in_chr = !in_chr; - goto shift_over; - } else if (*str == '\"' && !in_chr && !escaped) { - in_str = !in_str; - goto shift_over; - } else if (*str == '\\') { - escaped = !escaped; - ++str; - continue; - } - escaped = false; - ++str; - continue; - shift_over: - memmove(str, str+1, end-- - str); - } - *end = '\0'; -} - -char *lenient_strcat(char *dest, const char *src) { - if (dest && src) { - return strcat(dest, src); - } - return dest; -} - -char *lenient_strncat(char *dest, const char *src, size_t len) { - if (dest && src) { - return strncat(dest, src, len); - } - return dest; -} - -// strcmp that also handles null pointers. -int lenient_strcmp(const char *a, const char *b) { - if (a == b) { - return 0; - } else if (!a) { - return -1; - } else if (!b) { - return 1; - } else { - return strcmp(a, b); - } -} - -list_t *split_string(const char *str, const char *delims) { - list_t *res = create_list(); - char *copy = strdup(str); - - char *token = strtok(copy, delims); - while (token) { - list_add(res, strdup(token)); - token = strtok(NULL, delims); - } - free(copy); - return res; -} - -char **split_args(const char *start, int *argc) { - *argc = 0; - int alloc = 2; - char **argv = malloc(sizeof(char *) * alloc); - bool in_token = false; - bool in_string = false; - bool in_char = false; - bool in_brackets = false; // brackets are used for criteria - bool escaped = false; - const char *end = start; - if (start) { - while (*start) { - if (!in_token) { - start = (end += strspn(end, whitespace)); - in_token = true; - } - if (*end == '"' && !in_char && !escaped) { - in_string = !in_string; - } else if (*end == '\'' && !in_string && !escaped) { - in_char = !in_char; - } else if (*end == '[' && !in_string && !in_char && !in_brackets && !escaped) { - in_brackets = true; - } else if (*end == ']' && !in_string && !in_char && in_brackets && !escaped) { - in_brackets = false; - } else if (*end == '\\') { - escaped = !escaped; - } else if (*end == '\0' || (!in_string && !in_char && !in_brackets - && !escaped && strchr(whitespace, *end))) { - goto add_token; - } - if (*end != '\\') { - escaped = false; - } - ++end; - continue; - add_token: - if (end - start > 0) { - char *token = malloc(end - start + 1); - strncpy(token, start, end - start + 1); - token[end - start] = '\0'; - argv[*argc] = token; - if (++*argc + 1 == alloc) { - argv = realloc(argv, (alloc *= 2) * sizeof(char *)); - } - } - in_token = false; - escaped = false; - } - } - argv[*argc] = NULL; - return argv; -} - -void free_argv(int argc, char **argv) { - while (argc-- > 0) { - free(argv[argc]); - } - free(argv); -} - -int unescape_string(char *string) { - /* TODO: More C string escapes */ - int len = strlen(string); - int i; - for (i = 0; string[i]; ++i) { - if (string[i] == '\\') { - switch (string[++i]) { - case '0': - string[i - 1] = '\0'; - return i - 1; - case 'a': - string[i - 1] = '\a'; - string[i] = '\0'; - break; - case 'b': - string[i - 1] = '\b'; - string[i] = '\0'; - break; - case 'f': - string[i - 1] = '\f'; - string[i] = '\0'; - break; - case 'n': - string[i - 1] = '\n'; - string[i] = '\0'; - break; - case 'r': - string[i - 1] = '\r'; - string[i] = '\0'; - break; - case 't': - string[i - 1] = '\t'; - string[i] = '\0'; - break; - case 'v': - string[i - 1] = '\v'; - string[i] = '\0'; - break; - case '\\': - string[i] = '\0'; - break; - case '\'': - string[i - 1] = '\''; - string[i] = '\0'; - break; - case '\"': - string[i - 1] = '\"'; - string[i] = '\0'; - break; - case '?': - string[i - 1] = '?'; - string[i] = '\0'; - break; - case 'x': - { - unsigned char c = 0; - if (string[i+1] >= '0' && string[i+1] <= '9') { - c = string[i+1] - '0'; - if (string[i+2] >= '0' && string[i+2] <= '9') { - c *= 0x10; - c += string[i+2] - '0'; - string[i+2] = '\0'; - } - string[i+1] = '\0'; - } - string[i] = '\0'; - string[i - 1] = c; - } - } - } - } - // Shift characters over nullspaces - int shift = 0; - for (i = 0; i < len; ++i) { - if (string[i] == 0) { - shift++; - continue; - } - string[i-shift] = string[i]; - } - string[len - shift] = 0; - return len - shift; -} - -char *join_args(char **argv, int argc) { - if (!sway_assert(argc > 0, "argc should be positive")) { - return NULL; - } - int len = 0, i; - for (i = 0; i < argc; ++i) { - len += strlen(argv[i]) + 1; - } - char *res = malloc(len); - len = 0; - for (i = 0; i < argc; ++i) { - strcpy(res + len, argv[i]); - len += strlen(argv[i]); - res[len++] = ' '; - } - res[len - 1] = '\0'; - return res; -} - -static inline char *argsep_next_interesting(const char *src, const char *delim) { - char *special = strpbrk(src, "\"'\\"); - char *next_delim = strpbrk(src, delim); - if (!special) { - return next_delim; - } - if (!next_delim) { - return special; - } - return (next_delim < special) ? next_delim : special; -} - -char *argsep(char **stringp, const char *delim, char *matched) { - char *start = *stringp; - char *end = start; - bool in_string = false; - bool in_char = false; - bool escaped = false; - char *interesting = NULL; - - while ((interesting = argsep_next_interesting(end, delim))) { - if (escaped && interesting != end) { - escaped = false; - } - if (*interesting == '"' && !in_char && !escaped) { - in_string = !in_string; - end = interesting + 1; - } else if (*interesting == '\'' && !in_string && !escaped) { - in_char = !in_char; - end = interesting + 1; - } else if (*interesting == '\\') { - escaped = !escaped; - end = interesting + 1; - } else if (!in_string && !in_char && !escaped) { - // We must have matched a separator - end = interesting; - if (matched) { - *matched = *end; - } - if (end - start) { - *(end++) = 0; - *stringp = end; - break; - } else { - end = ++start; - } - } else { - end++; - } - } - if (!interesting) { - *stringp = NULL; - if (matched) { - *matched = '\0'; - } - } - return start; -} - -bool expand_path(char **path) { - wordexp_t p = {0}; - while (strstr(*path, " ")) { - *path = realloc(*path, strlen(*path) + 2); - char *ptr = strstr(*path, " ") + 1; - memmove(ptr + 1, ptr, strlen(ptr) + 1); - *ptr = '\\'; - } - if (wordexp(*path, &p, 0) != 0 || p.we_wordv[0] == NULL) { - wordfree(&p); - return false; - } - free(*path); - *path = join_args(p.we_wordv, p.we_wordc); - wordfree(&p); - return true; -} - -char *vformat_str(const char *fmt, va_list args) { - char *str = NULL; - va_list args_copy; - va_copy(args_copy, args); - - int len = vsnprintf(NULL, 0, fmt, args); - if (len < 0) { - sway_log_errno(SWAY_ERROR, "vsnprintf(\"%s\") failed", fmt); - goto out; - } - - str = malloc(len + 1); - if (str == NULL) { - sway_log_errno(SWAY_ERROR, "malloc() failed"); - goto out; - } - - vsnprintf(str, len + 1, fmt, args_copy); - -out: - va_end(args_copy); - return str; -} - -char *format_str(const char *fmt, ...) { - va_list args; - va_start(args, fmt); - char *str = vformat_str(fmt, args); - va_end(args); - return str; -} diff --git a/common/util.c b/common/util.c deleted file mode 100644 index 5d4c0673d..000000000 --- a/common/util.c +++ /dev/null @@ -1,144 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include -#include -#include "log.h" -#include "util.h" - -int wrap(int i, int max) { - return ((i % max) + max) % max; -} - -bool parse_color(const char *color, uint32_t *result) { - if (color[0] == '#') { - ++color; - } - int len = strlen(color); - if ((len != 6 && len != 8) || !isxdigit(color[0]) || !isxdigit(color[1])) { - return false; - } - char *ptr; - uint32_t parsed = strtoul(color, &ptr, 16); - if (*ptr != '\0') { - return false; - } - *result = len == 6 ? ((parsed << 8) | 0xFF) : parsed; - return true; -} - -void color_to_rgba(float dest[static 4], uint32_t color) { - dest[0] = ((color >> 24) & 0xff) / 255.0; - dest[1] = ((color >> 16) & 0xff) / 255.0; - dest[2] = ((color >> 8) & 0xff) / 255.0; - dest[3] = (color & 0xff) / 255.0; -} - -bool parse_boolean(const char *boolean, bool current) { - if (strcasecmp(boolean, "1") == 0 - || strcasecmp(boolean, "yes") == 0 - || strcasecmp(boolean, "on") == 0 - || strcasecmp(boolean, "true") == 0 - || strcasecmp(boolean, "enable") == 0 - || strcasecmp(boolean, "enabled") == 0 - || strcasecmp(boolean, "active") == 0) { - return true; - } else if (strcasecmp(boolean, "toggle") == 0) { - return !current; - } - // All other values are false to match i3 - return false; -} - -float parse_float(const char *value) { - errno = 0; - char *end; - float flt = strtof(value, &end); - if (*end || errno) { - sway_log(SWAY_DEBUG, "Invalid float value '%s', defaulting to NAN", value); - return NAN; - } - return flt; -} - -enum movement_unit parse_movement_unit(const char *unit) { - if (strcasecmp(unit, "px") == 0) { - return MOVEMENT_UNIT_PX; - } - if (strcasecmp(unit, "ppt") == 0) { - return MOVEMENT_UNIT_PPT; - } - if (strcasecmp(unit, "default") == 0) { - return MOVEMENT_UNIT_DEFAULT; - } - return MOVEMENT_UNIT_INVALID; -} - -int parse_movement_amount(int argc, char **argv, - struct movement_amount *amount) { - if (!sway_assert(argc > 0, "Expected args in parse_movement_amount")) { - amount->amount = 0; - amount->unit = MOVEMENT_UNIT_INVALID; - return 0; - } - - char *err; - amount->amount = (int)strtol(argv[0], &err, 10); - if (*err) { - // e.g. 10px - amount->unit = parse_movement_unit(err); - return 1; - } - if (argc == 1) { - amount->unit = MOVEMENT_UNIT_DEFAULT; - return 1; - } - // Try the second argument - amount->unit = parse_movement_unit(argv[1]); - if (amount->unit == MOVEMENT_UNIT_INVALID) { - amount->unit = MOVEMENT_UNIT_DEFAULT; - return 1; - } - return 2; -} - -const char *sway_wl_output_subpixel_to_string(enum wl_output_subpixel subpixel) { - switch (subpixel) { - case WL_OUTPUT_SUBPIXEL_UNKNOWN: - return "unknown"; - case WL_OUTPUT_SUBPIXEL_NONE: - return "none"; - case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB: - return "rgb"; - case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR: - return "bgr"; - case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB: - return "vrgb"; - case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR: - return "vbgr"; - } - sway_assert(false, "Unknown value for wl_output_subpixel."); - return NULL; -} - -bool sway_set_cloexec(int fd, bool cloexec) { - int flags = fcntl(fd, F_GETFD); - if (flags == -1) { - sway_log_errno(SWAY_ERROR, "fcntl failed"); - return false; - } - if (cloexec) { - flags = flags | FD_CLOEXEC; - } else { - flags = flags & ~FD_CLOEXEC; - } - if (fcntl(fd, F_SETFD, flags) == -1) { - sway_log_errno(SWAY_ERROR, "fcntl failed"); - return false; - } - return true; -} diff --git a/completions/bash/sway b/completions/bash/sway deleted file mode 100644 index 01b20073f..000000000 --- a/completions/bash/sway +++ /dev/null @@ -1,46 +0,0 @@ -# sway(1) completion - -_sway() -{ - local cur prev short long - _get_comp_words_by_ref cur prev - - short=( - -h - -c - -C - -d - -v - -V - ) - - long=( - --help - --config - --validate - --debug - --version - --verbose - --get-socketpath - ) - - case $prev in - -c|--config) - _filedir - return - ;; - esac - - if [[ $cur == --* ]]; then - COMPREPLY=($(compgen -W "${long[*]}" -- "$cur")) - elif [[ $cur == -* ]]; then - COMPREPLY=($(compgen -W "${short[*]}" -- "$cur")) - COMPREPLY+=($(compgen -W "${long[*]}" -- "$cur")) - else - COMPREPLY=($(compgen -W "${short[*]}" -- "$cur")) - COMPREPLY+=($(compgen -W "${long[*]}" -- "$cur")) - COMPREPLY+=($(compgen -c -- "$cur")) - fi - -} && -complete -F _sway sway diff --git a/completions/bash/swaybar b/completions/bash/swaybar deleted file mode 100644 index 3709d4f97..000000000 --- a/completions/bash/swaybar +++ /dev/null @@ -1,44 +0,0 @@ -# swaybar(1) completion - -_swaybar() -{ - local cur prev short long - _get_comp_words_by_ref cur prev - - short=( - -h - -v - -s - -b - -d - ) - - long=( - --help - --version - --socket - --bar_id - --debug - ) - - case $prev in - -s|--socket) - _filedir - return - ;; - -b|--bar_id) - bars=($(swaymsg -t get_bar_config | jq -r '.[]')) - COMPREPLY=($(compgen -W "${bars[*]}" -- "$cur")) - return - ;; - esac - - if [[ $cur == --* ]]; then - COMPREPLY=($(compgen -W "${long[*]}" -- "$cur")) - else - COMPREPLY=($(compgen -W "${short[*]}" -- "$cur")) - COMPREPLY+=($(compgen -W "${long[*]}" -- "$cur")) - fi - -} && -complete -F _swaybar swaybar diff --git a/completions/bash/swaymsg b/completions/bash/swaymsg deleted file mode 100644 index 304577516..000000000 --- a/completions/bash/swaymsg +++ /dev/null @@ -1,65 +0,0 @@ -# swaymsg(1) completion - -_swaymsg() -{ - local cur prev types short long - _get_comp_words_by_ref cur prev - - types=( - 'get_workspaces' - 'get_seats' - 'get_inputs' - 'get_outputs' - 'get_tree' - 'get_marks' - 'get_bar_config' - 'get_version' - 'get_binding_modes' - 'get_binding_state' - 'get_config' - 'send_tick' - 'subscribe' - ) - - short=( - -h - -m - -p - -q - -r - -s - -t - -v - ) - - long=( - --help - --monitor - --pretty - --quiet - --raw - --socket - --type - --version - ) - - case $prev in - -s|--socket) - _filedir - return - ;; - -t|--type) - COMPREPLY=($(compgen -W "${types[*]}" -- "$cur")) - return - ;; - esac - - if [[ $cur == --* ]]; then - COMPREPLY=($(compgen -W "${long[*]}" -- "$cur")) - else - COMPREPLY=($(compgen -W "${short[*]}" -- "$cur")) - COMPREPLY+=($(compgen -W "${long[*]}" -- "$cur")) - fi - -} && -complete -F _swaymsg swaymsg diff --git a/completions/fish/sway.fish b/completions/fish/sway.fish deleted file mode 100644 index 444fd273d..000000000 --- a/completions/fish/sway.fish +++ /dev/null @@ -1,11 +0,0 @@ -# sway(1) completion - -complete -f -c sway -complete -c sway -s h -l help --description "Show help message and quit." -complete -c sway -s c -l config --description "Specifies a config file." -r -complete -c sway -s C -l validate --description "Check the validity of the config file, then exit." -complete -c sway -s d -l debug --description "Enables full logging, including debug information." -complete -c sway -s v -l version --description "Show the version number and quit." -complete -c sway -s V -l verbose --description "Enables more verbose logging." -complete -c sway -l get-socketpath --description "Gets the IPC socket path and prints it, then exits." - diff --git a/completions/fish/swaymsg.fish b/completions/fish/swaymsg.fish deleted file mode 100644 index 5ee7dcc0b..000000000 --- a/completions/fish/swaymsg.fish +++ /dev/null @@ -1,25 +0,0 @@ -# swaymsg(1) completion - -complete -f -c swaymsg -complete -c swaymsg -s h -l help --description "Show help message and quit." -complete -c swaymsg -s m -l monitor --description "Monitor subscribed events until killed." -complete -c swaymsg -s p -l pretty --description "Use pretty output even when not using a tty." -complete -c swaymsg -s q -l quiet --description "Sends the IPC message but does not print the response from sway." -complete -c swaymsg -s r -l raw --description "Use raw output even if using tty." -complete -c swaymsg -s s -l socket -r --description "Use the specified socket path. Otherwise, swaymsg will ask where the socket is (which is the value of $SWAYSOCK, then of $I3SOCK)." -complete -c swaymsg -s v -l version --description "Print the version (of swaymsg) and quit." - -complete -c swaymsg -s t -l type -fr --description "Specify the type of IPC message." -complete -c swaymsg -s t -l type -fra 'get_workspaces' --description "Gets a JSON-encoded list of workspaces and their status." -complete -c swaymsg -s t -l type -fra 'get_inputs' --description "Gets a JSON-encoded list of current inputs." -complete -c swaymsg -s t -l type -fra 'get_outputs' --description "Gets a JSON-encoded list of current outputs." -complete -c swaymsg -s t -l type -fra 'get_tree' --description "Gets a JSON-encoded layout tree of all open windows, containers, outputs, workspaces, and so on." -complete -c swaymsg -s t -l type -fra 'get_marks' --description "Get a JSON-encoded list of marks." -complete -c swaymsg -s t -l type -fra 'get_bar_config' --description "Get a JSON-encoded configuration for swaybar." -complete -c swaymsg -s t -l type -fra 'get_version' --description "Get JSON-encoded version information for the running instance of sway." -complete -c swaymsg -s t -l type -fra 'get_binding_modes' --description "Gets a JSON-encoded list of currently configured binding modes." -complete -c swaymsg -s t -l type -fra 'get_binding_state' --description "Get JSON-encoded info about the current binding state." -complete -c swaymsg -s t -l type -fra 'get_config' --description "Gets a JSON-encoded copy of the current configuration." -complete -c swaymsg -s t -l type -fra 'get_seats' --description "Gets a JSON-encoded list of all seats, its properties and all assigned devices." -complete -c swaymsg -s t -l type -fra 'send_tick' --description "Sends a tick event to all subscribed clients." -complete -c swaymsg -s t -l type -fra 'subscribe' --description "Subscribe to a list of event types." diff --git a/completions/fish/swaynag.fish b/completions/fish/swaynag.fish deleted file mode 100644 index 7015d5e34..000000000 --- a/completions/fish/swaynag.fish +++ /dev/null @@ -1,30 +0,0 @@ -# swaynag -complete -f -c swaynag -complete -c swaynag -s C -l config -r --description 'The config file to use. Default: $HOME/.swaynag/config, $XDG_CONFIG_HOME/swaynag/config, and SYSCONFDIR/swaynag/config.' -complete -c swaynag -s d -l debug --description 'Enable debugging.' -complete -c swaynag -s e -l edge -fr --description 'Set the edge to use: top or bottom' -complete -c swaynag -s f -l font -r --description 'Set the font to use.' -complete -c swaynag -s h -l help --description 'Show help message and quit.' -complete -c swaynag -s b -l button -fr --description 'Create a button with a text and an action which is executed when pressed. Multiple buttons can be defined by providing the flag multiple times.' -complete -c swaynag -s l -l detailed-message --description 'Read a detailed message from stdin. A button to toggle details will be added. Details are shown in a scrollable multi-line text area.' -complete -c swaynag -s L -l detailed-button -fr --description 'Set the text for the button that toggles details. This has no effect if there is not a detailed message. The default is "Toggle details".' -complete -c swaynag -s m -l message -fr --description 'Set the message text.' -complete -c swaynag -s o -l output -fr --description 'Set the output to use.' -complete -c swaynag -s s -l dismiss-button -fr --description 'Sets the text for the dismiss nagbar button. The default is "X".' -complete -c swaynag -s t -l type -fr --description 'Set the message type. Two types are created by default "error" and "warning". Custom types can be defined in the config file.' -complete -c swaynag -s v -l version --description 'Show the version number and quit.' - -# Appearance -complete -c swaynag -l background -fr --description 'Set the color of the background.' -complete -c swaynag -l border -fr --description 'Set the color of the border.' -complete -c swaynag -l border-bottom -fr --description 'Set the color of the bottom border.' -complete -c swaynag -l button-background -fr --description 'Set the color for the background for buttons.' -complete -c swaynag -l text -fr --description 'Set the text color.' -complete -c swaynag -l border-bottom-size -fr --description 'Set the thickness of the bottom border.' -complete -c swaynag -l message-padding -fr --description 'Set the padding for the message.' -complete -c swaynag -l details-border-size -fr --description 'Set the thickness for the details border.' -complete -c swaynag -l button-border-size -fr --description 'Set the thickness for the button border.' -complete -c swaynag -l button-gap -fr --description 'Set the size of the gap between buttons.' -complete -c swaynag -l button-dismiss-gap -fr --description 'Set the size of the gap between the dismiss button and another button.' -complete -c swaynag -l button-margin-right -fr --description 'Set the margin from the right of the dismiss button to edge.' -complete -c swaynag -l button-padding -fr --description 'Set the padding for the button text.' diff --git a/completions/meson.build b/completions/meson.build deleted file mode 100644 index 6bca93913..000000000 --- a/completions/meson.build +++ /dev/null @@ -1,57 +0,0 @@ -if get_option('zsh-completions') - zsh_files = files( - 'zsh/_sway', - 'zsh/_swaymsg', - ) - zsh_install_dir = join_paths(datadir, 'zsh', 'site-functions') - - install_data(zsh_files, install_dir: zsh_install_dir) -endif - -if get_option('bash-completions') - bash_comp = dependency('bash-completion', required: false) - - bash_files = files( - 'bash/sway', - 'bash/swaymsg', - ) - - if get_option('swaybar') - bash_files += files('bash/swaybar') - endif - - if bash_comp.found() - bash_install_dir = bash_comp.get_variable( - pkgconfig: 'completionsdir', - pkgconfig_define: ['datadir', datadir] - ) - else - bash_install_dir = join_paths(datadir, 'bash-completion', 'completions') - endif - - install_data(bash_files, install_dir: bash_install_dir) -endif - -if get_option('fish-completions') - fish_comp = dependency('fish', required: false) - - fish_files = files( - 'fish/sway.fish', - 'fish/swaymsg.fish', - ) - - if get_option('swaynag') - fish_files += files('fish/swaynag.fish') - endif - - if fish_comp.found() - fish_install_dir = fish_comp.get_variable( - pkgconfig: 'completionsdir', - pkgconfig_define: ['datadir', datadir] - ) - else - fish_install_dir = join_paths(datadir, 'fish', 'vendor_completions.d') - endif - - install_data(fish_files, install_dir: fish_install_dir) -endif diff --git a/completions/zsh/_sway b/completions/zsh/_sway deleted file mode 100644 index a7f55cc58..000000000 --- a/completions/zsh/_sway +++ /dev/null @@ -1,22 +0,0 @@ -#compdef sway -#------------ -# Description -# ----------- -# -# Completion script for the sway window manager (http://swaywm.org) -# -# --------------------------------------------- -# Author -# ------- -# -# * Seth Barberee -# -# ------------------------------- -_arguments -s \ - '(-v --version)'{-v,--version}'[Show the version number and quit]' \ - '(-h --help)'{-h,--help}'[Show help message and quit]' \ - '(-c --config)'{-c,--config}'[Specify a config file]:files:_files' \ - '(-C --validate)'{-C,--validate}'[Check validity of the config file, then exit]' \ - '(-d --debug)'{-d,--debug}'[Enables full logging, including debug information]' \ - '(-V --verbose)'{-V,--verbose}'[Enables more verbose logging]' \ - '(--get-socketpath)'--get-socketpath'[Gets the IPC socket path and prints it, then exits]' diff --git a/completions/zsh/_swaybar b/completions/zsh/_swaybar deleted file mode 100644 index af2cee956..000000000 --- a/completions/zsh/_swaybar +++ /dev/null @@ -1,13 +0,0 @@ -#compdef swaybar -# -# Completion script for swaybar -# - -local bars=($(swaymsg -t get_bar_config | jq -r '.[]')) - -_arguments -s \ - '(-h --help)'{-h,--help}'[Show help message and quit]' \ - '(-v --version)'{-v,--version}'[Show version and quit]' \ - '(-s --socket)'{-s,--socket}'[Connect to sway via socket]:filename:_files' \ - '(-b --bar_id)'{-b,--bar-id}'[Bar ID for which to get the configuration]:filename:($bars)'\ - '(-d --debug)'{-d,--debug}'[Enable debugging]' diff --git a/completions/zsh/_swaymsg b/completions/zsh/_swaymsg deleted file mode 100644 index 106f3d9dc..000000000 --- a/completions/zsh/_swaymsg +++ /dev/null @@ -1,40 +0,0 @@ -#compdef swaymsg -#----------------- -# Description -# ----------- -# -# Completion script for swaymsg in sway wm (http://swaywm.org) -# -# ------------------------------------------------------ -# Author -# -------- -# -# * Seth Barberee -# -# ------------------------------------------- - -types=( -'get_workspaces' -'get_seats' -'get_inputs' -'get_outputs' -'get_tree' -'get_marks' -'get_bar_config' -'get_version' -'get_binding_modes' -'get_binding_state' -'get_config' -'send_tick' -'subscribe' -) - -_arguments -s \ - '(-h --help)'{-h,--help}'[Show help message and quit]' \ - '(-m --monitor)'{-m,--monitor}'[Monitor until killed (-t SUBSCRIBE only)]' \ - '(-p --pretty)'{-p,--pretty}'[Use pretty output even when not using a tty]' \ - '(-q --quiet)'{-q,--quiet}'[Be quiet]' \ - '(-r --raw)'{-r,--raw}'[Use raw output even if using a tty]' \ - '(-s --socket)'{-s,--socket}'[Use the specified socket path]:files:_files' \ - '(-t --type)'{-t,--type}'[Specify the message type]:type:{_describe "type" types}' \ - '(-v --version)'{-v,--version}'[Show the version number and quit]' diff --git a/config.in b/config.in deleted file mode 100644 index d478178ec..000000000 --- a/config.in +++ /dev/null @@ -1,240 +0,0 @@ -# Default config for sway -# -# Copy this to ~/.config/sway/config and edit it to your liking. -# -# Read `man 5 sway` for a complete reference. - -### Variables -# -# Logo key. Use Mod1 for Alt. -set $mod Mod4 -# Home row direction keys, like vim -set $left h -set $down j -set $up k -set $right l -# Your preferred terminal emulator -set $term foot -# Your preferred application launcher -# Note: pass the final command to swaymsg so that the resulting window can be opened -# on the original workspace that the command was run on. -set $menu dmenu_path | wmenu | xargs swaymsg exec -- - -### Appearance -# window corner radius in px -corner_radius 10 - -# Window background blur -blur off -blur_xray off -blur_passes 2 -blur_radius 5 - -shadows off -shadows_on_csd off -shadow_blur_radius 20 -shadow_color #0000007F - -# inactive window fade amount. 0.0 = no dimming, 1.0 = fully dimmed -default_dim_inactive 0.0 -dim_inactive_colors.unfocused #000000FF -dim_inactive_colors.urgent #900000FF - -# Move minimized windows into Scratchpad (enable|disable) -scratchpad_minimize disable - -### Output configuration -# -# Default wallpaper (more resolutions are available in @datadir@/backgrounds/sway/) -output * bg @datadir@/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png fill -# -# Example configuration: -# -# output HDMI-A-1 resolution 1920x1080 position 1920,0 -# -# You can get the names of your outputs by running: swaymsg -t get_outputs - -### Idle configuration -# -# Example configuration: -# -# exec swayidle -w \ -# timeout 300 'swaylock -f -c 000000' \ -# timeout 600 'swaymsg "output * power off"' resume 'swaymsg "output * power on"' \ -# before-sleep 'swaylock -f -c 000000' -# -# This will lock your screen after 300 seconds of inactivity, then turn off -# your displays after another 300 seconds, and turn your screens back on when -# resumed. It will also lock your screen before your computer goes to sleep. - -### Input configuration -# -# Example configuration: -# -# input "2:14:SynPS/2_Synaptics_TouchPad" { -# dwt enabled -# tap enabled -# natural_scroll enabled -# middle_emulation enabled -# } -# -# You can get the names of your inputs by running: swaymsg -t get_inputs -# Read `man 5 sway-input` for more information about this section. - -### Key bindings -# -# Basics: -# - # Start a terminal - bindsym $mod+Return exec $term - - # Kill focused window - bindsym $mod+Shift+q kill - - # Start your launcher - bindsym $mod+d exec $menu - - # Drag floating windows by holding down $mod and left mouse button. - # Resize them with right mouse button + $mod. - # Despite the name, also works for non-floating windows. - # Change normal to inverse to use left mouse button for resizing and right - # mouse button for dragging. - floating_modifier $mod normal - - # Reload the configuration file - bindsym $mod+Shift+c reload - - # Exit sway (logs you out of your Wayland session) - bindsym $mod+Shift+e exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -B 'Yes, exit sway' 'swaymsg exit' -# -# Moving around: -# - # Move your focus around - bindsym $mod+$left focus left - bindsym $mod+$down focus down - bindsym $mod+$up focus up - bindsym $mod+$right focus right - # Or use $mod+[up|down|left|right] - bindsym $mod+Left focus left - bindsym $mod+Down focus down - bindsym $mod+Up focus up - bindsym $mod+Right focus right - - # Move the focused window with the same, but add Shift - bindsym $mod+Shift+$left move left - bindsym $mod+Shift+$down move down - bindsym $mod+Shift+$up move up - bindsym $mod+Shift+$right move right - # Ditto, with arrow keys - bindsym $mod+Shift+Left move left - bindsym $mod+Shift+Down move down - bindsym $mod+Shift+Up move up - bindsym $mod+Shift+Right move right -# -# Workspaces: -# - # Switch to workspace - bindsym $mod+1 workspace number 1 - bindsym $mod+2 workspace number 2 - bindsym $mod+3 workspace number 3 - bindsym $mod+4 workspace number 4 - bindsym $mod+5 workspace number 5 - bindsym $mod+6 workspace number 6 - bindsym $mod+7 workspace number 7 - bindsym $mod+8 workspace number 8 - bindsym $mod+9 workspace number 9 - bindsym $mod+0 workspace number 10 - # Move focused container to workspace - bindsym $mod+Shift+1 move container to workspace number 1 - bindsym $mod+Shift+2 move container to workspace number 2 - bindsym $mod+Shift+3 move container to workspace number 3 - bindsym $mod+Shift+4 move container to workspace number 4 - bindsym $mod+Shift+5 move container to workspace number 5 - bindsym $mod+Shift+6 move container to workspace number 6 - bindsym $mod+Shift+7 move container to workspace number 7 - bindsym $mod+Shift+8 move container to workspace number 8 - bindsym $mod+Shift+9 move container to workspace number 9 - bindsym $mod+Shift+0 move container to workspace number 10 - # Note: workspaces can have any name you want, not just numbers. - # We just use 1-10 as the default. -# -# Layout stuff: -# - # You can "split" the current object of your focus with - # $mod+b or $mod+v, for horizontal and vertical splits - # respectively. - bindsym $mod+b splith - bindsym $mod+v splitv - - # Switch the current container between different layout styles - bindsym $mod+s layout stacking - bindsym $mod+w layout tabbed - bindsym $mod+e layout toggle split - - # Make the current focus fullscreen - bindsym $mod+f fullscreen - - # Toggle the current focus between tiling and floating mode - bindsym $mod+Shift+space floating toggle - - # Swap focus between the tiling area and the floating area - bindsym $mod+space focus mode_toggle - - # Move focus to the parent container - bindsym $mod+a focus parent -# -# Scratchpad: -# - # Sway has a "scratchpad", which is a bag of holding for windows. - # You can send windows there and get them back later. - - # Move the currently focused window to the scratchpad - bindsym $mod+Shift+minus move scratchpad - - # Show the next scratchpad window or hide the focused scratchpad window. - # If there are multiple scratchpad windows, this command cycles through them. - bindsym $mod+minus scratchpad show -# -# Resizing containers: -# -mode "resize" { - # left will shrink the containers width - # right will grow the containers width - # up will shrink the containers height - # down will grow the containers height - bindsym $left resize shrink width 10px - bindsym $down resize grow height 10px - bindsym $up resize shrink height 10px - bindsym $right resize grow width 10px - - # Ditto, with arrow keys - bindsym Left resize shrink width 10px - bindsym Down resize grow height 10px - bindsym Up resize shrink height 10px - bindsym Right resize grow width 10px - - # Return to default mode - bindsym Return mode "default" - bindsym Escape mode "default" -} -bindsym $mod+r mode "resize" - -# -# Status Bar: -# -# Read `man 5 sway-bar` for more information about this section. -bar { - position top - - # When the status_command prints a new line to stdout, swaybar updates. - # The default just shows the current date and time. - status_command while date +'%Y-%m-%d %X'; do sleep 1; done - - colors { - statusline #ffffff - background #323232 - inactive_workspace #32323200 #32323200 #5c5c5c - } -} - -include @sysconfdir@/sway/config.d/* diff --git a/include/background-image.h b/include/background-image.h deleted file mode 100644 index a97ef3752..000000000 --- a/include/background-image.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _SWAY_BACKGROUND_IMAGE_H -#define _SWAY_BACKGROUND_IMAGE_H -#include "cairo_util.h" - -enum background_mode { - BACKGROUND_MODE_STRETCH, - BACKGROUND_MODE_FILL, - BACKGROUND_MODE_FIT, - BACKGROUND_MODE_CENTER, - BACKGROUND_MODE_TILE, - BACKGROUND_MODE_SOLID_COLOR, - BACKGROUND_MODE_INVALID, -}; - -enum background_mode parse_background_mode(const char *mode); -cairo_surface_t *load_background_image(const char *path); -void render_background_image(cairo_t *cairo, cairo_surface_t *image, - enum background_mode mode, int buffer_width, int buffer_height); - -#endif diff --git a/include/cairo_util.h b/include/cairo_util.h deleted file mode 100644 index dc049c6dc..000000000 --- a/include/cairo_util.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _SWAY_CAIRO_UTIL_H -#define _SWAY_CAIRO_UTIL_H -#include "config.h" -#include -#include -#include - -void cairo_set_source_u32(cairo_t *cairo, uint32_t color); -cairo_subpixel_order_t to_cairo_subpixel_order(enum wl_output_subpixel subpixel); - -cairo_surface_t *cairo_image_surface_scale(cairo_surface_t *image, - int width, int height); - -#endif diff --git a/include/gesture.h b/include/gesture.h deleted file mode 100644 index 9c6b0f91c..000000000 --- a/include/gesture.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef _SWAY_GESTURE_H -#define _SWAY_GESTURE_H - -#include -#include - -/** - * A gesture type used in binding. - */ -enum gesture_type { - GESTURE_TYPE_NONE = 0, - GESTURE_TYPE_HOLD, - GESTURE_TYPE_PINCH, - GESTURE_TYPE_SWIPE, -}; - -// Turns single type enum value to constant string representation. -const char *gesture_type_string(enum gesture_type direction); - -// Value to use to accept any finger count -extern const uint8_t GESTURE_FINGERS_ANY; - -/** - * A gesture direction used in binding. - */ -enum gesture_direction { - GESTURE_DIRECTION_NONE = 0, - // Directions based on delta x and y - GESTURE_DIRECTION_UP = 1 << 0, - GESTURE_DIRECTION_DOWN = 1 << 1, - GESTURE_DIRECTION_LEFT = 1 << 2, - GESTURE_DIRECTION_RIGHT = 1 << 3, - // Directions based on scale - GESTURE_DIRECTION_INWARD = 1 << 4, - GESTURE_DIRECTION_OUTWARD = 1 << 5, - // Directions based on rotation - GESTURE_DIRECTION_CLOCKWISE = 1 << 6, - GESTURE_DIRECTION_COUNTERCLOCKWISE = 1 << 7, -}; - -// Turns single direction enum value to constant string representation. -const char *gesture_direction_string(enum gesture_direction direction); - -/** - * Struct representing a pointer gesture - */ -struct gesture { - enum gesture_type type; - uint8_t fingers; - uint32_t directions; -}; - -/** - * Parses gesture from [:][:] string. - * - * Return NULL on success, otherwise error message string - */ -char *gesture_parse(const char *input, struct gesture *output); - -// Turns gesture into string representation -char *gesture_to_string(struct gesture *gesture); - -// Check if gesture is of certain type and finger count. -bool gesture_check(struct gesture *target, - enum gesture_type type, uint8_t fingers); - -// Check if a gesture target/binding is match by other gesture/input -bool gesture_match(struct gesture *target, - struct gesture *to_match, bool exact); - -// Returns true if gesture are exactly the same -bool gesture_equal(struct gesture *a, struct gesture *b); - -// Compare distance between two matched target gestures. -int8_t gesture_compare(struct gesture *a, struct gesture *b); - -// Small helper struct to track gestures over time -struct gesture_tracker { - enum gesture_type type; - uint8_t fingers; - double dx, dy; - double scale; - double rotation; -}; - -// Begin gesture tracking -void gesture_tracker_begin(struct gesture_tracker *tracker, - enum gesture_type type, uint8_t fingers); - -// Check if the provides type is currently being tracked -bool gesture_tracker_check(struct gesture_tracker *tracker, - enum gesture_type type); - -// Update gesture track with new data point -void gesture_tracker_update(struct gesture_tracker *tracker, double dx, - double dy, double scale, double rotation); - -// Reset tracker -void gesture_tracker_cancel(struct gesture_tracker *tracker); - -// Reset tracker and return gesture tracked -struct gesture *gesture_tracker_end(struct gesture_tracker *tracker); - -#endif diff --git a/include/ipc-client.h b/include/ipc-client.h deleted file mode 100644 index 9c5712d73..000000000 --- a/include/ipc-client.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef _SWAY_IPC_CLIENT_H -#define _SWAY_IPC_CLIENT_H - -// arbitrary number, it's probably sufficient, higher number = more memory usage -#define JSON_MAX_DEPTH 512 - -#include -#include -#include - -#include "ipc.h" - -/** - * IPC response including type of IPC response, size of payload and the json - * encoded payload string. - */ -struct ipc_response { - uint32_t size; - uint32_t type; - char *payload; -}; - -/** - * Gets the path to the IPC socket from sway. - */ -char *get_socketpath(void); -/** - * Opens the sway socket. - */ -int ipc_open_socket(const char *socket_path); -/** - * Issues a single IPC command and returns the buffer. len will be updated with - * the length of the buffer returned from sway. - */ -char *ipc_single_command(int socketfd, uint32_t type, const char *payload, uint32_t *len); -/** - * Receives a single IPC response and returns an ipc_response. - */ -struct ipc_response *ipc_recv_response(int socketfd); -/** - * Free ipc_response struct - */ -void free_ipc_response(struct ipc_response *response); -/** - * Sets the receive timeout for the IPC socket - */ -bool ipc_set_recv_timeout(int socketfd, struct timeval tv); - -#endif diff --git a/include/ipc.h b/include/ipc.h deleted file mode 100644 index ff0117502..000000000 --- a/include/ipc.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _SWAY_IPC_H -#define _SWAY_IPC_H - -#define event_mask(ev) (1 << (ev & 0x7F)) - -enum ipc_command_type { - // i3 command types - see i3's I3_REPLY_TYPE constants - IPC_COMMAND = 0, - IPC_GET_WORKSPACES = 1, - IPC_SUBSCRIBE = 2, - IPC_GET_OUTPUTS = 3, - IPC_GET_TREE = 4, - IPC_GET_MARKS = 5, - IPC_GET_BAR_CONFIG = 6, - IPC_GET_VERSION = 7, - IPC_GET_BINDING_MODES = 8, - IPC_GET_CONFIG = 9, - IPC_SEND_TICK = 10, - IPC_SYNC = 11, - IPC_GET_BINDING_STATE = 12, - - // sway-specific command types - IPC_GET_INPUTS = 100, - IPC_GET_SEATS = 101, - - // Events sent from sway to clients. Events have the highest bits set. - IPC_EVENT_WORKSPACE = ((1<<31) | 0), - IPC_EVENT_OUTPUT = ((1<<31) | 1), - IPC_EVENT_MODE = ((1<<31) | 2), - IPC_EVENT_WINDOW = ((1<<31) | 3), - IPC_EVENT_BARCONFIG_UPDATE = ((1<<31) | 4), - IPC_EVENT_BINDING = ((1<<31) | 5), - IPC_EVENT_SHUTDOWN = ((1<<31) | 6), - IPC_EVENT_TICK = ((1<<31) | 7), - - // sway-specific event types - IPC_EVENT_BAR_STATE_UPDATE = ((1<<31) | 20), - IPC_EVENT_INPUT = ((1<<31) | 21), -}; - -#endif diff --git a/include/list.h b/include/list.h deleted file mode 100644 index 895f6cc01..000000000 --- a/include/list.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _SWAY_LIST_H -#define _SWAY_LIST_H - -typedef struct { - int capacity; - int length; - void **items; -} list_t; - -list_t *create_list(void); -void list_free(list_t *list); -void list_add(list_t *list, void *item); -void list_insert(list_t *list, int index, void *item); -void list_del(list_t *list, int index); -void list_cat(list_t *list, list_t *source); -// See qsort. Remember to use *_qsort functions as compare functions, -// because they dereference the left and right arguments first! -void list_qsort(list_t *list, int compare(const void *left, const void *right)); -// Return index for first item in list that returns 0 for given compare -// function or -1 if none matches. -int list_seq_find(list_t *list, int compare(const void *item, const void *cmp_to), const void *cmp_to); -int list_find(list_t *list, const void *item); -// stable sort since qsort is not guaranteed to be stable -void list_stable_sort(list_t *list, int compare(const void *a, const void *b)); -// swap two elements in a list -void list_swap(list_t *list, int src, int dest); -// move item to end of list -void list_move_to_end(list_t *list, void *item); - -/* Calls `free` for each item in the list, then frees the list. - * Do not use this to free lists of primitives or items that require more - * complicated deallocation code. - */ -void list_free_items_and_destroy(list_t *list); -#endif diff --git a/include/log.h b/include/log.h deleted file mode 100644 index 41399a9fa..000000000 --- a/include/log.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef _SWAY_LOG_H -#define _SWAY_LOG_H - -#include -#include -#include -#include - -typedef enum { - SWAY_SILENT = 0, - SWAY_ERROR = 1, - SWAY_INFO = 2, - SWAY_DEBUG = 3, - SWAY_LOG_IMPORTANCE_LAST, -} sway_log_importance_t; - -#ifdef __GNUC__ -#define ATTRIB_PRINTF(start, end) __attribute__((format(printf, start, end))) -#else -#define ATTRIB_PRINTF(start, end) -#endif - -void error_handler(int sig); - -typedef void (*terminate_callback_t)(int exit_code); - -// Will log all messages less than or equal to `verbosity` -// The `terminate` callback is called by `sway_abort` -void sway_log_init(sway_log_importance_t verbosity, terminate_callback_t terminate); - -void _sway_log(sway_log_importance_t verbosity, const char *format, ...) ATTRIB_PRINTF(2, 3); -void _sway_vlog(sway_log_importance_t verbosity, const char *format, va_list args) ATTRIB_PRINTF(2, 0); -void _sway_abort(const char *filename, ...) ATTRIB_PRINTF(1, 2); -bool _sway_assert(bool condition, const char* format, ...) ATTRIB_PRINTF(2, 3); - -#ifdef SWAY_REL_SRC_DIR -// strip prefix from __FILE__, leaving the path relative to the project root -#define _SWAY_FILENAME ((const char *)__FILE__ + sizeof(SWAY_REL_SRC_DIR) - 1) -#else -#define _SWAY_FILENAME __FILE__ -#endif - -#define sway_log(verb, fmt, ...) \ - _sway_log(verb, "[%s:%d] " fmt, _SWAY_FILENAME, __LINE__, ##__VA_ARGS__) - -#define sway_vlog(verb, fmt, args) \ - _sway_vlog(verb, "[%s:%d] " fmt, _SWAY_FILENAME, __LINE__, args) - -#define sway_log_errno(verb, fmt, ...) \ - sway_log(verb, fmt ": %s", ##__VA_ARGS__, strerror(errno)) - -#define sway_abort(FMT, ...) \ - _sway_abort("[%s:%d] " FMT, _SWAY_FILENAME, __LINE__, ##__VA_ARGS__) - -#define sway_assert(COND, FMT, ...) \ - _sway_assert(COND, "[%s:%d] %s:" FMT, _SWAY_FILENAME, __LINE__, __PRETTY_FUNCTION__, ##__VA_ARGS__) - -#endif diff --git a/include/loop.h b/include/loop.h deleted file mode 100644 index 2f608edaf..000000000 --- a/include/loop.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef _SWAY_LOOP_H -#define _SWAY_LOOP_H -#include - -/** - * This is an event loop system designed for sway clients, not sway itself. - * - * The loop consists of file descriptors and timers. Typically the Wayland - * display's file descriptor will be one of the fds in the loop. - */ - -struct loop; -struct loop_timer; - -/** - * Create an event loop. - */ -struct loop *loop_create(void); - -/** - * Destroy the event loop (eg. on program termination). - */ -void loop_destroy(struct loop *loop); - -/** - * Poll the event loop. This will block until one of the fds has data. - */ -void loop_poll(struct loop *loop); - -/** - * Add a file descriptor to the loop. - */ -void loop_add_fd(struct loop *loop, int fd, short mask, - void (*func)(int fd, short mask, void *data), void *data); - -/** - * Add a timer to the loop. - * - * When the timer expires, the timer will be removed from the loop and freed. - */ -struct loop_timer *loop_add_timer(struct loop *loop, int ms, - void (*callback)(void *data), void *data); - -/** - * Remove a file descriptor from the loop. - */ -bool loop_remove_fd(struct loop *loop, int fd); - -/** - * Remove a timer from the loop. - */ -bool loop_remove_timer(struct loop *loop, struct loop_timer *timer); - -#endif diff --git a/include/meson.build b/include/meson.build deleted file mode 100644 index 65ed027ad..000000000 --- a/include/meson.build +++ /dev/null @@ -1 +0,0 @@ -configure_file(output: 'config.h', configuration: conf_data) diff --git a/include/pango.h b/include/pango.h deleted file mode 100644 index 228e39cfa..000000000 --- a/include/pango.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef _SWAY_PANGO_H -#define _SWAY_PANGO_H -#include -#include -#include -#include -#include -#include "stringop.h" - -/** - * Utility function which escape characters a & < > ' ". - * - * The function returns the length of the escaped string, optionally writing the - * escaped string to dest if provided. - */ -size_t escape_markup_text(const char *src, char *dest); -PangoLayout *get_pango_layout(cairo_t *cairo, const PangoFontDescription *desc, - const char *text, double scale, bool markup); -void get_text_size(cairo_t *cairo, const PangoFontDescription *desc, int *width, int *height, - int *baseline, double scale, bool markup, const char *fmt, ...) _SWAY_ATTRIB_PRINTF(8, 9); -void get_text_metrics(const PangoFontDescription *desc, int *height, int *baseline); -void render_text(cairo_t *cairo, PangoFontDescription *desc, - double scale, bool markup, const char *fmt, ...) _SWAY_ATTRIB_PRINTF(5, 6); - -#endif diff --git a/include/pool-buffer.h b/include/pool-buffer.h deleted file mode 100644 index b7a95afe9..000000000 --- a/include/pool-buffer.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _SWAY_BUFFERS_H -#define _SWAY_BUFFERS_H -#include -#include -#include -#include -#include - -struct pool_buffer { - struct wl_buffer *buffer; - cairo_surface_t *surface; - cairo_t *cairo; - PangoContext *pango; - uint32_t width, height; - void *data; - size_t size; - bool busy; -}; - -struct pool_buffer *get_next_buffer(struct wl_shm *shm, - struct pool_buffer pool[static 2], uint32_t width, uint32_t height); -void destroy_buffer(struct pool_buffer *buffer); - -#endif diff --git a/include/stringop.h b/include/stringop.h deleted file mode 100644 index 19a50f237..000000000 --- a/include/stringop.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef _SWAY_STRINGOP_H -#define _SWAY_STRINGOP_H - -#include -#include -#include "list.h" - -#ifdef __GNUC__ -#define _SWAY_ATTRIB_PRINTF(start, end) __attribute__((format(printf, start, end))) -#else -#define _SWAY_ATTRIB_PRINTF(start, end) -#endif - -void strip_whitespace(char *str); -void strip_quotes(char *str); - -// strcat that does nothing if dest or src is NULL -char *lenient_strcat(char *dest, const char *src); -char *lenient_strncat(char *dest, const char *src, size_t len); - -// strcmp that also handles null pointers. -int lenient_strcmp(const char *a, const char *b); - -// Simply split a string with delims, free with `list_free_items_and_destroy` -list_t *split_string(const char *str, const char *delims); - -// Splits an argument string, keeping quotes intact -char **split_args(const char *str, int *argc); -void free_argv(int argc, char **argv); - -int unescape_string(char *string); -char *join_args(char **argv, int argc); - -// Split string into 2 by delim, handle quotes -char *argsep(char **stringp, const char *delim, char *matched_delim); - -// Expand a path using shell replacements such as $HOME and ~ -bool expand_path(char **path); - -char *vformat_str(const char *fmt, va_list args) _SWAY_ATTRIB_PRINTF(1, 0); -char *format_str(const char *fmt, ...) _SWAY_ATTRIB_PRINTF(1, 2); - -#endif diff --git a/include/sway/commands.h b/include/sway/commands.h deleted file mode 100644 index 8f21b989e..000000000 --- a/include/sway/commands.h +++ /dev/null @@ -1,346 +0,0 @@ -#ifndef _SWAY_COMMANDS_H -#define _SWAY_COMMANDS_H - -#include -#include "config.h" -#include "stringop.h" - -struct sway_container; - -typedef struct cmd_results *sway_cmd(int argc, char **argv); - -struct cmd_handler { - const char *command; - sway_cmd *handle; -}; - -/** - * 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 */ - CMD_BLOCK, - CMD_BLOCK_COMMANDS, - CMD_BLOCK_END -}; - -/** - * Stores the result of executing a command. - */ -struct cmd_results { - enum cmd_status status; - /** - * Human friendly error message, or NULL on success - */ - char *error; -}; - -enum expected_args { - EXPECTED_AT_LEAST, - EXPECTED_AT_MOST, - EXPECTED_EQUAL_TO -}; - -struct cmd_results *checkarg(int argc, const char *name, - enum expected_args type, int val); - -const struct cmd_handler *find_handler(const char *line, - const struct cmd_handler *cmd_handlers, size_t handlers_size); - -/** - * Parse and executes a command. - * - * If the command string contains criteria then the command will be executed on - * all matching containers. Otherwise, it'll run on the `con` container. If - * `con` is NULL then it'll run on the currently focused container. - */ -list_t *execute_command(char *command, struct sway_seat *seat, - struct sway_container *con); -/** - * Parse and handles a command during config file loading. - * - * Do not use this under normal conditions. - */ -struct cmd_results *config_command(char *command, char **new_block); -/** - * Parse and handle a sub command - */ -struct cmd_results *config_subcommand(char **argv, int argc, - const struct cmd_handler *handlers, size_t handlers_size); -/* - * 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 *error, ...) _SWAY_ATTRIB_PRINTF(2, 3); -/** - * Frees a cmd_results object. - */ -void free_cmd_results(struct cmd_results *results); -/** - * Serializes a list of cmd_results to a JSON string. - * - * Free the JSON string later on. - */ -char *cmd_results_to_json(list_t *res_list); - -/** - * TODO: Move this function and its dependent functions to container.c. - */ -void container_resize_tiled(struct sway_container *parent, uint32_t axis, - int amount); - -struct sway_container *container_find_resize_parent(struct sway_container *con, - uint32_t edge); - -/** - * Effect handlers value parsers - */ -bool cmd_corner_radius_parse_value(char *arg, int* result); - -/** - * Handlers shared by exec and exec_always. - */ -sway_cmd cmd_exec_validate; -sway_cmd cmd_exec_process; - -sway_cmd cmd_assign; -sway_cmd cmd_bar; -sway_cmd cmd_bindcode; -sway_cmd cmd_bindgesture; -sway_cmd cmd_bindswitch; -sway_cmd cmd_bindsym; -sway_cmd cmd_blur; -sway_cmd cmd_blur_brightness; -sway_cmd cmd_blur_contrast; -sway_cmd cmd_blur_noise; -sway_cmd cmd_blur_passes; -sway_cmd cmd_blur_radius; -sway_cmd cmd_blur_saturation; -sway_cmd cmd_blur_xray; -sway_cmd cmd_border; -sway_cmd cmd_client_noop; -sway_cmd cmd_client_focused; -sway_cmd cmd_client_focused_inactive; -sway_cmd cmd_client_focused_tab_title; -sway_cmd cmd_client_unfocused; -sway_cmd cmd_client_urgent; -sway_cmd cmd_client_placeholder; -sway_cmd cmd_client_background; -sway_cmd cmd_commands; -sway_cmd cmd_corner_radius; -sway_cmd cmd_create_output; -sway_cmd cmd_default_border; -sway_cmd cmd_default_dim_inactive; -sway_cmd cmd_default_floating_border; -sway_cmd cmd_default_orientation; -sway_cmd cmd_dim_inactive; -sway_cmd cmd_dim_inactive_colors_unfocused; -sway_cmd cmd_dim_inactive_colors_urgent; -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_modifier; -sway_cmd cmd_floating_scroll; -sway_cmd cmd_focus; -sway_cmd cmd_focus_follows_mouse; -sway_cmd cmd_focus_on_window_activation; -sway_cmd cmd_focus_wrapping; -sway_cmd cmd_font; -sway_cmd cmd_for_window; -sway_cmd cmd_force_display_urgency_hint; -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_inhibit_idle; -sway_cmd cmd_input; -sway_cmd cmd_seat; -sway_cmd cmd_ipc; -sway_cmd cmd_kill; -sway_cmd cmd_layer_effects; -sway_cmd cmd_layout; -sway_cmd cmd_log_colors; -sway_cmd cmd_mark; -sway_cmd cmd_max_render_time; -sway_cmd cmd_mode; -sway_cmd cmd_mouse_warping; -sway_cmd cmd_move; -sway_cmd cmd_nop; -sway_cmd cmd_opacity; -sway_cmd cmd_saturation; -sway_cmd cmd_new_float; -sway_cmd cmd_new_window; -sway_cmd cmd_no_focus; -sway_cmd cmd_output; -sway_cmd cmd_permit; -sway_cmd cmd_popup_during_fullscreen; -sway_cmd cmd_primary_selection; -sway_cmd cmd_reject; -sway_cmd cmd_reload; -sway_cmd cmd_rename; -sway_cmd cmd_resize; -sway_cmd cmd_scratchpad; -sway_cmd cmd_scratchpad_minimize; -sway_cmd cmd_seamless_mouse; -sway_cmd cmd_set; -sway_cmd cmd_shortcuts_inhibitor; -sway_cmd cmd_shadow_blur_radius; -sway_cmd cmd_shadow_color; -sway_cmd cmd_shadow_offset; -sway_cmd cmd_shadow_inactive_color; -sway_cmd cmd_shadows; -sway_cmd cmd_shadows_on_csd; -sway_cmd cmd_show_marks; -sway_cmd cmd_smart_borders; -sway_cmd cmd_smart_corner_radius; -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_swaybg_command; -sway_cmd cmd_swaynag_command; -sway_cmd cmd_swap; -sway_cmd cmd_tiling_drag; -sway_cmd cmd_tiling_drag_threshold; -sway_cmd cmd_title_align; -sway_cmd cmd_title_format; -sway_cmd cmd_titlebar_border_thickness; -sway_cmd cmd_titlebar_padding; -sway_cmd cmd_titlebar_separator; -sway_cmd cmd_unbindcode; -sway_cmd cmd_unbindswitch; -sway_cmd cmd_unbindgesture; -sway_cmd cmd_unbindsym; -sway_cmd cmd_unmark; -sway_cmd cmd_urgent; -sway_cmd cmd_workspace; -sway_cmd cmd_workspace_layout; -sway_cmd cmd_ws_auto_back_and_forth; -sway_cmd cmd_xwayland; - -sway_cmd bar_cmd_bindcode; -sway_cmd bar_cmd_binding_mode_indicator; -sway_cmd bar_cmd_bindsym; -sway_cmd bar_cmd_colors; -sway_cmd bar_cmd_font; -sway_cmd bar_cmd_gaps; -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_separator_symbol; -sway_cmd bar_cmd_status_command; -sway_cmd bar_cmd_status_edge_padding; -sway_cmd bar_cmd_status_padding; -sway_cmd bar_cmd_pango_markup; -sway_cmd bar_cmd_strip_workspace_numbers; -sway_cmd bar_cmd_strip_workspace_name; -sway_cmd bar_cmd_swaybar_command; -sway_cmd bar_cmd_tray_bindcode; -sway_cmd bar_cmd_tray_bindsym; -sway_cmd bar_cmd_tray_output; -sway_cmd bar_cmd_tray_padding; -sway_cmd bar_cmd_unbindcode; -sway_cmd bar_cmd_unbindsym; -sway_cmd bar_cmd_wrap_scroll; -sway_cmd bar_cmd_workspace_buttons; -sway_cmd bar_cmd_workspace_min_width; - -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_seat; -sway_cmd input_cmd_accel_profile; -sway_cmd input_cmd_calibration_matrix; -sway_cmd input_cmd_click_method; -sway_cmd input_cmd_drag; -sway_cmd input_cmd_drag_lock; -sway_cmd input_cmd_dwt; -sway_cmd input_cmd_dwtp; -sway_cmd input_cmd_events; -sway_cmd input_cmd_left_handed; -sway_cmd input_cmd_map_from_region; -sway_cmd input_cmd_map_to_output; -sway_cmd input_cmd_map_to_region; -sway_cmd input_cmd_middle_emulation; -sway_cmd input_cmd_natural_scroll; -sway_cmd input_cmd_pointer_accel; -sway_cmd input_cmd_rotation_angle; -sway_cmd input_cmd_scroll_factor; -sway_cmd input_cmd_repeat_delay; -sway_cmd input_cmd_repeat_rate; -sway_cmd input_cmd_scroll_button; -sway_cmd input_cmd_scroll_button_lock; -sway_cmd input_cmd_scroll_method; -sway_cmd input_cmd_tap; -sway_cmd input_cmd_tap_button_map; -sway_cmd input_cmd_tool_mode; -sway_cmd input_cmd_xkb_capslock; -sway_cmd input_cmd_xkb_file; -sway_cmd input_cmd_xkb_layout; -sway_cmd input_cmd_xkb_model; -sway_cmd input_cmd_xkb_numlock; -sway_cmd input_cmd_xkb_options; -sway_cmd input_cmd_xkb_rules; -sway_cmd input_cmd_xkb_switch_layout; -sway_cmd input_cmd_xkb_variant; - -sway_cmd output_cmd_adaptive_sync; -sway_cmd output_cmd_background; -sway_cmd output_cmd_disable; -sway_cmd output_cmd_dpms; -sway_cmd output_cmd_enable; -sway_cmd output_cmd_max_render_time; -sway_cmd output_cmd_mode; -sway_cmd output_cmd_modeline; -sway_cmd output_cmd_position; -sway_cmd output_cmd_power; -sway_cmd output_cmd_render_bit_depth; -sway_cmd output_cmd_scale; -sway_cmd output_cmd_scale_filter; -sway_cmd output_cmd_subpixel; -sway_cmd output_cmd_toggle; -sway_cmd output_cmd_transform; -sway_cmd output_cmd_unplug; - -sway_cmd seat_cmd_attach; -sway_cmd seat_cmd_cursor; -sway_cmd seat_cmd_fallback; -sway_cmd seat_cmd_hide_cursor; -sway_cmd seat_cmd_idle_inhibit; -sway_cmd seat_cmd_idle_wake; -sway_cmd seat_cmd_keyboard_grouping; -sway_cmd seat_cmd_pointer_constraint; -sway_cmd seat_cmd_shortcuts_inhibitor; -sway_cmd seat_cmd_xcursor_theme; - -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 84e4ab8e7..000000000 --- a/include/sway/config.h +++ /dev/null @@ -1,779 +0,0 @@ -#ifndef _SWAY_CONFIG_H -#define _SWAY_CONFIG_H -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../include/config.h" -#include "gesture.h" -#include "list.h" -#include "stringop.h" -#include "swaynag.h" -#include "tree/container.h" -#include "scenefx/types/fx/blur_data.h" -#include "sway/input/tablet.h" -#include "sway/tree/root.h" -#include "wlr-layer-shell-unstable-v1-protocol.h" -#include - -// TODO: Refactor this shit - -/** - * Describes a variable created via the `set` command. - */ -struct sway_variable { - char *name; - char *value; -}; - -enum binding_input_type { - BINDING_KEYCODE, - BINDING_KEYSYM, - BINDING_MOUSECODE, - BINDING_MOUSESYM, - BINDING_SWITCH, // dummy, only used to call seat_execute_command - BINDING_GESTURE // dummy, only used to call seat_execute_command -}; - -enum binding_flags { - BINDING_RELEASE = 1 << 0, - BINDING_LOCKED = 1 << 1, // keyboard only - BINDING_BORDER = 1 << 2, // mouse only; trigger on container border - BINDING_CONTENTS = 1 << 3, // mouse only; trigger on container contents - BINDING_TITLEBAR = 1 << 4, // mouse only; trigger on container titlebar - BINDING_CODE = 1 << 5, // keyboard only; convert keysyms into keycodes - BINDING_RELOAD = 1 << 6, // switch only; (re)trigger binding on reload - BINDING_INHIBITED = 1 << 7, // keyboard only: ignore shortcut inhibitor - BINDING_NOREPEAT = 1 << 8, // keyboard only; do not trigger when repeating a held key - BINDING_EXACT = 1 << 9, // gesture only; only trigger on exact match -}; - -/** - * A key (or mouse) binding and an associated command. - */ -struct sway_binding { - enum binding_input_type type; - int order; - char *input; - uint32_t flags; - list_t *keys; // sorted in ascending order - list_t *syms; // sorted in ascending order; NULL if BINDING_CODE is not set - uint32_t modifiers; - xkb_layout_index_t group; - char *command; -}; - -enum sway_switch_trigger { - SWAY_SWITCH_TRIGGER_OFF, - SWAY_SWITCH_TRIGGER_ON, - SWAY_SWITCH_TRIGGER_TOGGLE, -}; - -/** - * A laptop switch binding and an associated command. - */ -struct sway_switch_binding { - enum wlr_switch_type type; - enum sway_switch_trigger trigger; - uint32_t flags; - char *command; -}; - -/** - * A gesture binding and an associated command. - */ -struct sway_gesture_binding { - char *input; - uint32_t flags; - struct gesture gesture; - char *command; -}; - -/** - * Focus on window activation. - */ -enum sway_fowa { - FOWA_SMART, - FOWA_URGENT, - FOWA_FOCUS, - FOWA_NONE, -}; - -/** - * A "mode" of keybindings created via the `mode` command. - */ -struct sway_mode { - char *name; - list_t *keysym_bindings; - list_t *keycode_bindings; - list_t *mouse_bindings; - list_t *switch_bindings; - list_t *gesture_bindings; - bool pango; -}; - -struct input_config_mapped_from_region { - double x1, y1; - double x2, y2; - bool mm; -}; - -struct calibration_matrix { - bool configured; - float matrix[6]; -}; - -enum input_config_mapped_to { - MAPPED_TO_DEFAULT, - MAPPED_TO_OUTPUT, - MAPPED_TO_REGION, -}; - -struct input_config_tool { - enum wlr_tablet_tool_type type; - enum sway_tablet_tool_mode mode; -}; - -/** - * options for input devices - */ -struct input_config { - char *identifier; - const char *input_type; - - int accel_profile; - struct calibration_matrix calibration_matrix; - int click_method; - int drag; - int drag_lock; - int dwt; - int dwtp; - int left_handed; - int middle_emulation; - int natural_scroll; - float pointer_accel; - float rotation_angle; - float scroll_factor; - int repeat_delay; - int repeat_rate; - int scroll_button; - int scroll_button_lock; - int scroll_method; - int send_events; - int tap; - int tap_button_map; - - char *xkb_layout; - char *xkb_model; - char *xkb_options; - char *xkb_rules; - char *xkb_variant; - char *xkb_file; - - bool xkb_file_is_set; - - int xkb_numlock; - int xkb_capslock; - - struct input_config_mapped_from_region *mapped_from_region; - - enum input_config_mapped_to mapped_to; - char *mapped_to_output; - struct wlr_box *mapped_to_region; - - list_t *tools; - - bool capturable; - struct wlr_box region; -}; - -/** - * Options for misc device configurations that happen in the seat block - */ -struct seat_attachment_config { - char *identifier; - // TODO other things are configured here for some reason -}; - -enum seat_config_hide_cursor_when_typing { - HIDE_WHEN_TYPING_DEFAULT, // the default is currently disabled - HIDE_WHEN_TYPING_ENABLE, - HIDE_WHEN_TYPING_DISABLE, -}; - -enum seat_config_allow_constrain { - CONSTRAIN_DEFAULT, // the default is currently enabled - CONSTRAIN_ENABLE, - CONSTRAIN_DISABLE, -}; - -enum seat_config_shortcuts_inhibit { - SHORTCUTS_INHIBIT_DEFAULT, // the default is currently enabled - SHORTCUTS_INHIBIT_ENABLE, - SHORTCUTS_INHIBIT_DISABLE, -}; - -enum seat_keyboard_grouping { - KEYBOARD_GROUP_DEFAULT, // the default is currently smart - KEYBOARD_GROUP_NONE, - KEYBOARD_GROUP_SMART, // keymap and repeat info -}; - -enum sway_input_idle_source { - IDLE_SOURCE_KEYBOARD = 1 << 0, - IDLE_SOURCE_POINTER = 1 << 1, - IDLE_SOURCE_TOUCH = 1 << 2, - IDLE_SOURCE_TABLET_PAD = 1 << 3, - IDLE_SOURCE_TABLET_TOOL = 1 << 4, - IDLE_SOURCE_SWITCH = 1 << 5, -}; - -/** - * Options for multiseat and other misc device configurations - */ -struct seat_config { - char *name; - int fallback; // -1 means not set - list_t *attachments; // list of seat_attachment configs - int hide_cursor_timeout; - enum seat_config_hide_cursor_when_typing hide_cursor_when_typing; - enum seat_config_allow_constrain allow_constrain; - enum seat_config_shortcuts_inhibit shortcuts_inhibit; - enum seat_keyboard_grouping keyboard_grouping; - uint32_t idle_inhibit_sources, idle_wake_sources; - struct { - char *name; - int size; - } xcursor_theme; -}; - -enum scale_filter_mode { - SCALE_FILTER_DEFAULT, // the default is currently smart - SCALE_FILTER_LINEAR, - SCALE_FILTER_NEAREST, - SCALE_FILTER_SMART, -}; - -enum render_bit_depth { - RENDER_BIT_DEPTH_DEFAULT, // the default is currently 8 - RENDER_BIT_DEPTH_8, - RENDER_BIT_DEPTH_10, -}; - -/** - * Size and position configuration for a particular output. - * - * This is set via the `output` command. - */ -struct output_config { - char *name; - int enabled; - int power; - int width, height; - float refresh_rate; - int custom_mode; - drmModeModeInfo drm_mode; - int x, y; - float scale; - enum scale_filter_mode scale_filter; - int32_t transform; - enum wl_output_subpixel subpixel; - int max_render_time; // In milliseconds - int adaptive_sync; - enum render_bit_depth render_bit_depth; - - char *background; - char *background_option; - char *background_fallback; -}; - -/** - * Stores size of gaps for each side - */ -struct side_gaps { - int top; - int right; - int bottom; - int left; -}; - -enum smart_gaps_mode { - SMART_GAPS_OFF, - SMART_GAPS_ON, - SMART_GAPS_INVERSE_OUTER, -}; - -/** - * Stores configuration for a workspace, regardless of whether the workspace - * exists. - */ -struct workspace_config { - char *workspace; - list_t *outputs; - int gaps_inner; - struct side_gaps gaps_outer; -}; - -enum pango_markup_config { - PANGO_MARKUP_DISABLED = false, - PANGO_MARKUP_ENABLED = true, - PANGO_MARKUP_DEFAULT // The default is font dependent ("pango:" prefix) -}; - -struct bar_config { - char *swaybar_command; - struct wl_client *client; - struct wl_listener client_destroy; - - /** - * 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; - bool visible_by_modifier; // only relevant in "hide" mode - /** - * 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; - char *position; - list_t *bindings; - char *status_command; - enum pango_markup_config pango_markup; - char *font; - int height; // -1 not defined - bool workspace_buttons; - bool wrap_scroll; - char *separator_symbol; - bool strip_workspace_numbers; - bool strip_workspace_name; - bool binding_mode_indicator; - bool verbose; - struct side_gaps gaps; - int status_padding; - int status_edge_padding; - uint32_t workspace_min_width; - 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; - -#if HAVE_TRAY - char *icon_theme; - struct wl_list tray_bindings; // struct tray_binding::link - list_t *tray_outputs; // char * - int tray_padding; -#endif -}; - -struct bar_binding { - uint32_t button; - bool release; - char *command; -}; - -#if HAVE_TRAY -struct tray_binding { - uint32_t button; - const char *command; - struct wl_list link; // struct tray_binding::link -}; -#endif - -struct border_colors { - float border[4]; - float background[4]; - float text[4]; - float indicator[4]; - float child_border[4]; -}; - -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 */ -}; - -enum edge_border_smart_types { - ESMART_OFF, - ESMART_ON, /**< hide edges if precisely one window is present in workspace */ - ESMART_NO_GAPS, /**< hide edges if one window and gaps to edge is zero */ -}; - -enum sway_popup_during_fullscreen { - POPUP_SMART, - POPUP_IGNORE, - POPUP_LEAVE, -}; - -enum focus_follows_mouse_mode { - FOLLOWS_NO, - FOLLOWS_YES, - FOLLOWS_ALWAYS, -}; - -enum focus_wrapping_mode { - WRAP_NO, - WRAP_YES, - WRAP_FORCE, - WRAP_WORKSPACE, -}; - -enum mouse_warping_mode { - WARP_NO, - WARP_OUTPUT, - WARP_CONTAINER, -}; - -enum alignment { - ALIGN_LEFT, - ALIGN_CENTER, - ALIGN_RIGHT, -}; - -enum xwayland_mode { - XWAYLAND_MODE_DISABLED, - XWAYLAND_MODE_LAZY, - XWAYLAND_MODE_IMMEDIATE, -}; - -/** - * The configuration struct. The result of loading a config file. - */ -struct sway_config { - int corner_radius; - bool smart_corner_radius; - - float default_dim_inactive; - struct { - float unfocused[4]; - float urgent[4]; - } dim_inactive_colors; - - bool shadow_enabled; - bool shadows_on_csd_enabled; - int shadow_blur_sigma; - float shadow_color[4]; - float shadow_inactive_color[4]; - float shadow_offset_x, shadow_offset_y; - - bool blur_enabled; - bool blur_xray; - struct blur_data blur_params; - - bool titlebar_separator; - bool scratchpad_minimize; - - list_t *layer_criteria; - - char *swaynag_command; - struct swaynag_instance swaynag_config_errors; - list_t *symbols; - list_t *modes; - list_t *bars; - list_t *cmd_queue; - list_t *workspace_configs; - list_t *output_configs; - list_t *input_configs; - list_t *input_type_configs; - list_t *seat_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; - bool floating_mod_inverse; - 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 sway_container_layout default_orientation; - enum sway_container_layout default_layout; - char *font; // Used for IPC. - PangoFontDescription *font_description; // Used internally for rendering and validating. - int font_height; - int font_baseline; - bool pango_markup; - int titlebar_border_thickness; - int titlebar_h_padding; - int titlebar_v_padding; - size_t urgent_timeout; - enum sway_fowa focus_on_window_activation; - enum sway_popup_during_fullscreen popup_during_fullscreen; - enum xwayland_mode xwayland; - - // swaybg - char *swaybg_command; - struct wl_client *swaybg_client; - struct wl_listener swaybg_client_destroy; - - // Flags - enum focus_follows_mouse_mode focus_follows_mouse; - enum mouse_warping_mode mouse_warping; - enum focus_wrapping_mode focus_wrapping; - bool active; - bool failed; - bool reloading; - bool reading; - bool validating; - bool auto_back_and_forth; - bool show_marks; - enum alignment title_align; - bool primary_selection; - - bool tiling_drag; - int tiling_drag_threshold; - - enum smart_gaps_mode smart_gaps; - int gaps_inner; - struct side_gaps gaps_outer; - - list_t *config_chain; - bool user_config_path; - const char *current_config_path; - const char *current_config; - int current_config_line_number; - char *current_config_line; - - enum sway_container_border border; - enum sway_container_border floating_border; - int border_thickness; - int floating_border_thickness; - enum edge_border_types hide_edge_borders; - enum edge_border_smart_types hide_edge_borders_smart; - bool hide_lone_tab; - - // border colors - struct { - struct border_colors focused; - struct border_colors focused_inactive; - struct border_colors focused_tab_title; - struct border_colors unfocused; - struct border_colors urgent; - struct border_colors placeholder; - float background[4]; - } border_colors; - - bool has_focused_tab_title; - - // floating view - int32_t floating_maximum_width; - int32_t floating_maximum_height; - int32_t floating_minimum_width; - int32_t floating_minimum_height; - - // The keysym to keycode translation - struct xkb_state *keysym_translation_state; - - // Context for command handlers - struct { - struct input_config *input_config; - struct output_config *output_config; - struct seat_config *seat_config; - struct sway_seat *seat; - struct sway_node *node; - struct sway_container *container; - struct sway_workspace *workspace; - bool node_overridden; // True if the node is selected by means other than focus - struct { - int argc; - char **argv; - } leftovers; - } handler_context; -}; - -/** - * 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, bool validating); - -/** - * Loads an included config. Can only be used after load_main_config. - */ -void load_include_configs(const char *path, struct sway_config *config, - struct swaynag_instance *swaynag); - -/** - * Reads the config from the given FILE. - */ -bool read_config(FILE *file, struct sway_config *config, - struct swaynag_instance *swaynag); - -/** - * Run the commands that were deferred when reading the config file. - */ -void run_deferred_commands(void); - -/** - * Run the binding commands that were deferred when initializing the inputs - */ -void run_deferred_bindings(void); - -/** - * Adds a warning entry to the swaynag instance used for errors. - */ -void config_add_swaynag_warning(char *fmt, ...) _SWAY_ATTRIB_PRINTF(1, 2); - -/** - * Free config struct - */ -void free_config(struct sway_config *config); - -void free_sway_variable(struct sway_variable *var); - -/** - * Does variable replacement for a string based on the config's currently loaded variables. - */ -char *do_var_replacement(char *str); - -int input_identifier_cmp(const void *item, const void *data); - -struct input_config *new_input_config(const char* identifier); - -void merge_input_config(struct input_config *dst, struct input_config *src); - -struct input_config *store_input_config(struct input_config *ic, char **error); - -void input_config_fill_rule_names(struct input_config *ic, - struct xkb_rule_names *rules); - -void free_input_config(struct input_config *ic); - -int seat_name_cmp(const void *item, const void *data); - -struct seat_config *new_seat_config(const char* name); - -void merge_seat_config(struct seat_config *dst, struct seat_config *src); - -struct seat_config *copy_seat_config(struct seat_config *seat); - -void free_seat_config(struct seat_config *ic); - -struct seat_attachment_config *seat_attachment_config_new(void); - -struct seat_attachment_config *seat_config_get_attachment( - struct seat_config *seat_config, char *identifier); - -struct seat_config *store_seat_config(struct seat_config *seat); - -int output_name_cmp(const void *item, const void *data); - -void output_get_identifier(char *identifier, size_t len, - struct sway_output *output); - -const char *sway_output_scale_filter_to_string(enum scale_filter_mode scale_filter); - -struct output_config *new_output_config(const char *name); - -void merge_output_config(struct output_config *dst, struct output_config *src); - -bool apply_output_config(struct output_config *oc, struct sway_output *output); - -bool test_output_config(struct output_config *oc, struct sway_output *output); - -struct output_config *store_output_config(struct output_config *oc); - -struct output_config *find_output_config(struct sway_output *output); - -void apply_output_config_to_outputs(struct output_config *oc); - -void reset_outputs(void); - -void free_output_config(struct output_config *oc); - -bool spawn_swaybg(void); - -int workspace_output_cmp_workspace(const void *a, const void *b); - -void free_sway_binding(struct sway_binding *sb); - -void free_switch_binding(struct sway_switch_binding *binding); - -void free_gesture_binding(struct sway_gesture_binding *binding); - -void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding); - -void load_swaybar(struct bar_config *bar); - -void load_swaybars(void); - -struct bar_config *default_bar_config(void); - -void free_bar_config(struct bar_config *bar); - -void free_bar_binding(struct bar_binding *binding); - -void free_workspace_config(struct workspace_config *wsc); - -/** - * Updates the value of config->font_height based on the metrics for title's - * font as reported by pango. - * - * If the height has changed, all containers will be rearranged to take on the - * new size. - */ -void config_update_font_height(void); - -/** - * Convert bindsym into bindcode using the first configured layout. - * Return false in case the conversion is unsuccessful. - */ -bool translate_binding(struct sway_binding *binding); - -void translate_keysyms(struct input_config *input_config); - -void binding_add_translated(struct sway_binding *binding, list_t *bindings); - -int config_get_blur_size(); - -bool config_should_parameters_blur(); - -bool config_should_parameters_blur_effects(); - -bool config_should_parameters_shadow(); - -/* Global config singleton. */ -extern struct sway_config *config; - -#endif diff --git a/include/sway/criteria.h b/include/sway/criteria.h deleted file mode 100644 index 8da345ea6..000000000 --- a/include/sway/criteria.h +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef _SWAY_CRITERIA_H -#define _SWAY_CRITERIA_H - -#define PCRE2_CODE_UNIT_WIDTH 8 -#include -#include "config.h" -#include "list.h" -#include "tree/view.h" - -enum criteria_type { - CT_COMMAND = 1 << 0, - CT_ASSIGN_OUTPUT = 1 << 1, - CT_ASSIGN_WORKSPACE = 1 << 2, - CT_ASSIGN_WORKSPACE_NUMBER = 1 << 3, - CT_NO_FOCUS = 1 << 4, -}; - -enum pattern_type { - PATTERN_PCRE2, - PATTERN_FOCUSED, -}; - -struct pattern { - enum pattern_type match_type; - pcre2_code *regex; -}; - -struct criteria { - enum criteria_type type; - char *raw; // entire criteria string (for logging) - char *cmdlist; - char *target; // workspace or output name for `assign` criteria - - struct pattern *title; - struct pattern *shell; - struct pattern *app_id; - struct pattern *con_mark; - uint32_t con_id; // internal ID -#if HAVE_XWAYLAND - struct pattern *class; - uint32_t id; // X11 window ID - struct pattern *instance; - struct pattern *window_role; - enum atom_name window_type; -#endif - bool all; - bool floating; - bool tiling; - char urgent; // 'l' for latest or 'o' for oldest - struct pattern *workspace; - pid_t pid; -}; - -bool criteria_is_empty(struct criteria *criteria); -bool criteria_is_equal(struct criteria *left, struct criteria *right); - -bool criteria_already_exists(struct criteria *criteria); - -void criteria_destroy(struct criteria *criteria); - -/** - * Generate a criteria struct from a raw criteria string such as - * [class="foo" instance="bar"] (brackets inclusive). - * - * The error argument is expected to be an address of a null pointer. If an - * error is encountered, the function will return NULL and the pointer will be - * changed to point to the error string. This string should be freed afterwards. - */ -struct criteria *criteria_parse(char *raw, char **error); - -/** - * Compile a list of criterias matching the given view. - * - * Criteria types can be bitwise ORed. - */ -list_t *criteria_for_view(struct sway_view *view, enum criteria_type types); - -/** - * Compile a list of containers matching the given criteria. - */ -list_t *criteria_get_containers(struct criteria *criteria); - -#endif diff --git a/include/sway/decoration.h b/include/sway/decoration.h deleted file mode 100644 index 7916746e6..000000000 --- a/include/sway/decoration.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef _SWAY_DECORATION_H -#define _SWAY_DECORATION_H - -#include - -struct sway_server_decoration { - struct wlr_server_decoration *wlr_server_decoration; - struct wl_list link; - - struct wl_listener destroy; - struct wl_listener mode; -}; - -struct sway_server_decoration *decoration_from_surface( - struct wlr_surface *surface); - -#endif diff --git a/include/sway/desktop.h b/include/sway/desktop.h deleted file mode 100644 index 7f2f5b3eb..000000000 --- a/include/sway/desktop.h +++ /dev/null @@ -1,13 +0,0 @@ -#include - -struct sway_container; -struct sway_view; - -void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly, - bool whole); - -void desktop_damage_whole_container(struct sway_container *con); - -void desktop_damage_box(struct wlr_box *box); - -void desktop_damage_view(struct sway_view *view); diff --git a/include/sway/desktop/idle_inhibit_v1.h b/include/sway/desktop/idle_inhibit_v1.h deleted file mode 100644 index 84cc666d0..000000000 --- a/include/sway/desktop/idle_inhibit_v1.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef _SWAY_DESKTOP_IDLE_INHIBIT_V1_H -#define _SWAY_DESKTOP_IDLE_INHIBIT_V1_H -#include - -enum sway_idle_inhibit_mode { - INHIBIT_IDLE_APPLICATION, // Application set inhibitor (when visible) - INHIBIT_IDLE_FOCUS, // User set inhibitor when focused - INHIBIT_IDLE_FULLSCREEN, // User set inhibitor when fullscreen + visible - INHIBIT_IDLE_OPEN, // User set inhibitor while open - INHIBIT_IDLE_VISIBLE // User set inhibitor when visible -}; - -struct sway_idle_inhibit_manager_v1 { - struct wlr_idle_inhibit_manager_v1 *wlr_manager; - struct wl_listener new_idle_inhibitor_v1; - struct wl_list inhibitors; -}; - -struct sway_idle_inhibitor_v1 { - struct wlr_idle_inhibitor_v1 *wlr_inhibitor; - struct sway_view *view; - enum sway_idle_inhibit_mode mode; - - struct wl_list link; - struct wl_listener destroy; -}; - -bool sway_idle_inhibit_v1_is_active( - struct sway_idle_inhibitor_v1 *inhibitor); - -void sway_idle_inhibit_v1_check_active(void); - -void sway_idle_inhibit_v1_user_inhibitor_register(struct sway_view *view, - enum sway_idle_inhibit_mode mode); - -struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_user_inhibitor_for_view( - struct sway_view *view); - -struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_application_inhibitor_for_view( - struct sway_view *view); - -void sway_idle_inhibit_v1_user_inhibitor_destroy( - struct sway_idle_inhibitor_v1 *inhibitor); - -bool sway_idle_inhibit_manager_v1_init(void); - -#endif diff --git a/include/sway/desktop/launcher.h b/include/sway/desktop/launcher.h deleted file mode 100644 index 412068a90..000000000 --- a/include/sway/desktop/launcher.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef _SWAY_LAUNCHER_H -#define _SWAY_LAUNCHER_H - -#include -#include -#include "sway/input/seat.h" - -struct launcher_ctx { - pid_t pid; - char *fallback_name; - struct wlr_xdg_activation_token_v1 *token; - struct wl_listener token_destroy; - struct sway_seat *seat; - struct wl_listener seat_destroy; - - bool activated; - bool had_focused_surface; - - struct sway_node *node; - struct wl_listener node_destroy; - - struct wl_list link; // sway_server::pending_launcher_ctxs -}; - -struct launcher_ctx *launcher_ctx_find_pid(pid_t pid); - -struct sway_workspace *launcher_ctx_get_workspace(struct launcher_ctx *ctx); - -void launcher_ctx_consume(struct launcher_ctx *ctx); - -void launcher_ctx_destroy(struct launcher_ctx *ctx); - -struct launcher_ctx *launcher_ctx_create_internal(void); - -struct launcher_ctx *launcher_ctx_create( - struct wlr_xdg_activation_token_v1 *token, struct sway_node *node); - -const char *launcher_ctx_get_token_name(struct launcher_ctx *ctx); - -#endif diff --git a/include/sway/desktop/transaction.h b/include/sway/desktop/transaction.h deleted file mode 100644 index 7dd58ba8c..000000000 --- a/include/sway/desktop/transaction.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef _SWAY_TRANSACTION_H -#define _SWAY_TRANSACTION_H -#include - -/** - * Transactions enable us to perform atomic layout updates. - * - * A transaction contains a list of containers and their new state. - * A state might contain a new size, or new border settings, or new parent/child - * relationships. - * - * Committing a transaction makes sway notify of all the affected clients with - * their new sizes. We then wait for all the views to respond with their new - * surface sizes. When all are ready, or when a timeout has passed, we apply the - * updates all at the same time. - * - * When we want to make adjustments to the layout, we change the pending state - * in containers, mark them as dirty and call transaction_commit_dirty(). This - * create and commits a transaction from the dirty containers. - */ - -struct sway_transaction_instruction; -struct sway_view; - -/** - * Find all dirty containers, create and commit a transaction containing them, - * and unmark them as dirty. - */ -void transaction_commit_dirty(void); - -/* - * Same as transaction_commit_dirty, but signalling that this is a - * client-initiated change has already taken effect. - */ -void transaction_commit_dirty_client(void); - -/** - * Notify the transaction system that a view is ready for the new layout. - * - * When all views in the transaction are ready, the layout will be applied. - */ -void transaction_notify_view_ready_by_serial(struct sway_view *view, - uint32_t serial); - -/** - * Notify the transaction system that a view is ready for the new layout, but - * identifying the instruction by geometry rather than by serial. - * - * This is used by xwayland views, as they don't have serials. - */ -void transaction_notify_view_ready_by_geometry(struct sway_view *view, - double x, double y, int width, int height); - -#endif diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h deleted file mode 100644 index 1e21c66fe..000000000 --- a/include/sway/input/cursor.h +++ /dev/null @@ -1,150 +0,0 @@ -#ifndef _SWAY_INPUT_CURSOR_H -#define _SWAY_INPUT_CURSOR_H -#include -#include -#include -#include -#include -#include "sway/input/seat.h" -#include "config.h" - -#define SWAY_CURSOR_PRESSED_BUTTONS_CAP 32 - -#define SWAY_SCROLL_UP KEY_MAX + 1 -#define SWAY_SCROLL_DOWN KEY_MAX + 2 -#define SWAY_SCROLL_LEFT KEY_MAX + 3 -#define SWAY_SCROLL_RIGHT KEY_MAX + 4 - -struct sway_cursor { - struct sway_seat *seat; - struct wlr_cursor *cursor; - struct { - double x, y; - struct sway_node *node; - } previous; - struct wlr_xcursor_manager *xcursor_manager; - struct wl_list tablets; - struct wl_list tablet_pads; - - const char *image; - struct wl_client *image_client; - struct wlr_surface *image_surface; - int hotspot_x, hotspot_y; - - struct wlr_pointer_constraint_v1 *active_constraint; - pixman_region32_t confine; // invalid if active_constraint == NULL - bool active_confine_requires_warp; - - struct wl_listener hold_begin; - struct wl_listener hold_end; - struct wl_listener pinch_begin; - struct wl_listener pinch_update; - struct wl_listener pinch_end; - struct wl_listener swipe_begin; - struct wl_listener swipe_update; - struct wl_listener swipe_end; - - struct wl_listener motion; - struct wl_listener motion_absolute; - struct wl_listener button; - struct wl_listener axis; - struct wl_listener frame; - - struct wl_listener touch_down; - struct wl_listener touch_up; - struct wl_listener touch_cancel; - struct wl_listener touch_motion; - struct wl_listener touch_frame; - bool simulating_pointer_from_touch; - bool pointer_touch_up; - int32_t pointer_touch_id; - - struct wl_listener tool_axis; - struct wl_listener tool_tip; - struct wl_listener tool_proximity; - struct wl_listener tool_button; - bool simulating_pointer_from_tool_tip; - bool simulating_pointer_from_tool_button; - uint32_t tool_buttons; - - struct wl_listener request_set_cursor; - struct wl_listener image_surface_destroy; - - struct wl_listener constraint_commit; - - struct wl_event_source *hide_source; - bool hidden; - // This field is just a cache of the field in seat_config in order to avoid - // costly seat_config lookups on every keypress. HIDE_WHEN_TYPING_DEFAULT - // indicates that there is no cached value. - enum seat_config_hide_cursor_when_typing hide_when_typing; - - size_t pressed_button_count; -}; - -struct sway_node; - -struct sway_node *node_at_coords( - struct sway_seat *seat, double lx, double ly, - struct wlr_surface **surface, double *sx, double *sy); - -void sway_cursor_destroy(struct sway_cursor *cursor); -struct sway_cursor *sway_cursor_create(struct sway_seat *seat); - -/** - * "Rebase" a cursor on top of whatever view is underneath it. - * - * This chooses a cursor icon and sends a motion event to the surface. - */ -void cursor_rebase(struct sway_cursor *cursor); -void cursor_rebase_all(void); -void cursor_update_image(struct sway_cursor *cursor, struct sway_node *node); - -void cursor_handle_activity_from_idle_source(struct sway_cursor *cursor, - enum sway_input_idle_source idle_source); -void cursor_handle_activity_from_device(struct sway_cursor *cursor, - struct wlr_input_device *device); -void cursor_unhide(struct sway_cursor *cursor); -int cursor_get_timeout(struct sway_cursor *cursor); -void cursor_notify_key_press(struct sway_cursor *cursor); - -void pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, - struct wlr_input_device *device, double dx, double dy, - double dx_unaccel, double dy_unaccel); - -void dispatch_cursor_button(struct sway_cursor *cursor, - struct wlr_input_device *device, uint32_t time_msec, uint32_t button, - enum wlr_button_state state); - -void dispatch_cursor_axis(struct sway_cursor *cursor, - struct wlr_pointer_axis_event *event); - -void cursor_set_image(struct sway_cursor *cursor, const char *image, - struct wl_client *client); - -void cursor_set_image_surface(struct sway_cursor *cursor, - struct wlr_surface *surface, int32_t hotspot_x, int32_t hotspot_y, - struct wl_client *client); - -void cursor_warp_to_container(struct sway_cursor *cursor, - struct sway_container *container, bool force); - -void cursor_warp_to_workspace(struct sway_cursor *cursor, - struct sway_workspace *workspace); - - -void sway_cursor_constrain(struct sway_cursor *cursor, - struct wlr_pointer_constraint_v1 *constraint); - -uint32_t get_mouse_bindsym(const char *name, char **error); - -uint32_t get_mouse_bindcode(const char *name, char **error); - -// Considers both bindsym and bindcode -uint32_t get_mouse_button(const char *name, char **error); - -const char *get_mouse_button_name(uint32_t button); - -void handle_request_set_cursor_shape(struct wl_listener *listener, void *data); - -#endif diff --git a/include/sway/input/input-manager.h b/include/sway/input/input-manager.h deleted file mode 100644 index 4bd517093..000000000 --- a/include/sway/input/input-manager.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef _SWAY_INPUT_INPUT_MANAGER_H -#define _SWAY_INPUT_INPUT_MANAGER_H -#include -#include -#include -#include -#include -#include "sway/server.h" -#include "sway/config.h" -#include "list.h" - -struct sway_input_device { - char *identifier; - struct wlr_input_device *wlr_device; - struct wl_list link; - struct wl_listener device_destroy; - bool is_virtual; -}; - -struct sway_input_manager { - struct wl_list devices; - struct wl_list seats; - - struct wlr_input_inhibit_manager *inhibit; - struct wlr_keyboard_shortcuts_inhibit_manager_v1 *keyboard_shortcuts_inhibit; - struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard; - struct wlr_virtual_pointer_manager_v1 *virtual_pointer; - struct wlr_pointer_gestures_v1 *pointer_gestures; - - struct wl_listener new_input; - struct wl_listener inhibit_activate; - struct wl_listener inhibit_deactivate; - struct wl_listener keyboard_shortcuts_inhibit_new_inhibitor; - struct wl_listener virtual_keyboard_new; - struct wl_listener virtual_pointer_new; -}; - -struct sway_input_manager *input_manager_create(struct sway_server *server); - -bool input_manager_has_focus(struct sway_node *node); - -void input_manager_set_focus(struct sway_node *node); - -void input_manager_configure_xcursor(void); - -void input_manager_apply_input_config(struct input_config *input_config); - -void input_manager_configure_all_input_mappings(void); - -void input_manager_reset_input(struct sway_input_device *input_device); - -void input_manager_reset_all_inputs(void); - -void input_manager_apply_seat_config(struct seat_config *seat_config); - -struct sway_seat *input_manager_get_default_seat(void); - -struct sway_seat *input_manager_get_seat(const char *seat_name, bool create); - -/** - * If none of the seat configs have a fallback setting (either true or false), - * create the default seat (if needed) and set it as the fallback - */ -void input_manager_verify_fallback_seat(void); - -/** - * Gets the last seat the user interacted with - */ -struct sway_seat *input_manager_current_seat(void); - -struct input_config *input_device_get_config(struct sway_input_device *device); - -char *input_device_get_identifier(struct wlr_input_device *device); - -const char *input_device_get_type(struct sway_input_device *device); - -#endif diff --git a/include/sway/input/keyboard.h b/include/sway/input/keyboard.h deleted file mode 100644 index 571d9e6fa..000000000 --- a/include/sway/input/keyboard.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef _SWAY_INPUT_KEYBOARD_H -#define _SWAY_INPUT_KEYBOARD_H - -#include "sway/input/seat.h" - -#define SWAY_KEYBOARD_PRESSED_KEYS_CAP 32 - -/** - * Get modifier mask from modifier name. - * - * Returns the modifier mask or 0 if the name isn't found. - */ -uint32_t get_modifier_mask_by_name(const char *name); - -/** - * Get modifier name from modifier mask. - * - * Returns the modifier name or NULL if it isn't found. - */ -const char *get_modifier_name_by_mask(uint32_t modifier); - -/** - * Get an array of modifier names from modifier_masks - * - * Populates the names array and return the number of names added. - */ -int get_modifier_names(const char **names, uint32_t modifier_masks); - -struct sway_shortcut_state { - /** - * A list of pressed key ids (either keysyms or keycodes), - * including duplicates when different keycodes produce the same key id. - * - * Each key id is associated with the keycode (in `pressed_keycodes`) - * whose press generated it, so that the key id can be removed on - * keycode release without recalculating the transient link between - * keycode and key id at the time of the key press. - */ - uint32_t pressed_keys[SWAY_KEYBOARD_PRESSED_KEYS_CAP]; - /** - * The list of keycodes associated to currently pressed key ids, - * including duplicates when a keycode generates multiple key ids. - */ - uint32_t pressed_keycodes[SWAY_KEYBOARD_PRESSED_KEYS_CAP]; - uint32_t last_keycode; - uint32_t last_raw_modifiers; - size_t npressed; - uint32_t current_key; -}; - -struct sway_keyboard { - struct sway_seat_device *seat_device; - struct wlr_keyboard *wlr; - - struct xkb_keymap *keymap; - xkb_layout_index_t effective_layout; - - int32_t repeat_rate; - int32_t repeat_delay; - - struct wl_listener keyboard_key; - struct wl_listener keyboard_modifiers; - - struct sway_shortcut_state state_keysyms_translated; - struct sway_shortcut_state state_keysyms_raw; - struct sway_shortcut_state state_keycodes; - struct sway_shortcut_state state_pressed_sent; - struct sway_binding *held_binding; - - struct wl_event_source *key_repeat_source; - struct sway_binding *repeat_binding; -}; - -struct sway_keyboard_group { - struct wlr_keyboard_group *wlr_group; - struct sway_seat_device *seat_device; - struct wl_listener keyboard_key; - struct wl_listener keyboard_modifiers; - struct wl_listener enter; - struct wl_listener leave; - struct wl_list link; // sway_seat::keyboard_groups -}; - -struct xkb_keymap *sway_keyboard_compile_keymap(struct input_config *ic, - char **error); - -struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, - struct sway_seat_device *device); - -void sway_keyboard_configure(struct sway_keyboard *keyboard); - -void sway_keyboard_destroy(struct sway_keyboard *keyboard); - -void sway_keyboard_disarm_key_repeat(struct sway_keyboard *keyboard); -#endif diff --git a/include/sway/input/libinput.h b/include/sway/input/libinput.h deleted file mode 100644 index 1f84a8e31..000000000 --- a/include/sway/input/libinput.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _SWAY_INPUT_LIBINPUT_H -#define _SWAY_INPUT_LIBINPUT_H -#include "sway/input/input-manager.h" - -bool sway_input_configure_libinput_device(struct sway_input_device *device); - -void sway_input_configure_libinput_device_send_events( - struct sway_input_device *device); - -void sway_input_reset_libinput_device(struct sway_input_device *device); - -bool sway_libinput_device_is_builtin(struct sway_input_device *device); - -#endif diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h deleted file mode 100644 index 6063ead3a..000000000 --- a/include/sway/input/seat.h +++ /dev/null @@ -1,387 +0,0 @@ -#ifndef _SWAY_INPUT_SEAT_H -#define _SWAY_INPUT_SEAT_H - -#include -#include -#include -#include -#include -#include "sway/config.h" -#include "sway/input/input-manager.h" -#include "sway/input/tablet.h" -#include "sway/input/text_input.h" - -struct sway_seat; -struct fx_render_context; - -struct sway_seatop_impl { - void (*button)(struct sway_seat *seat, uint32_t time_msec, - struct wlr_input_device *device, uint32_t button, - enum wlr_button_state state); - void (*pointer_motion)(struct sway_seat *seat, uint32_t time_msec); - void (*pointer_axis)(struct sway_seat *seat, - struct wlr_pointer_axis_event *event); - void (*hold_begin)(struct sway_seat *seat, - struct wlr_pointer_hold_begin_event *event); - void (*hold_end)(struct sway_seat *seat, - struct wlr_pointer_hold_end_event *event); - void (*pinch_begin)(struct sway_seat *seat, - struct wlr_pointer_pinch_begin_event *event); - void (*pinch_update)(struct sway_seat *seat, - struct wlr_pointer_pinch_update_event *event); - void (*pinch_end)(struct sway_seat *seat, - struct wlr_pointer_pinch_end_event *event); - void (*swipe_begin)(struct sway_seat *seat, - struct wlr_pointer_swipe_begin_event *event); - void (*swipe_update)(struct sway_seat *seat, - struct wlr_pointer_swipe_update_event *event); - void (*swipe_end)(struct sway_seat *seat, - struct wlr_pointer_swipe_end_event *event); - void (*rebase)(struct sway_seat *seat, uint32_t time_msec); - void (*touch_motion)(struct sway_seat *seat, - struct wlr_touch_motion_event *event, double lx, double ly); - void (*touch_up)(struct sway_seat *seat, - struct wlr_touch_up_event *event); - void (*touch_down)(struct sway_seat *seat, - struct wlr_touch_down_event *event, double lx, double ly); - void (*touch_cancel)(struct sway_seat *seat, - struct wlr_touch_cancel_event *event); - void (*tablet_tool_motion)(struct sway_seat *seat, - struct sway_tablet_tool *tool, uint32_t time_msec); - void (*tablet_tool_tip)(struct sway_seat *seat, struct sway_tablet_tool *tool, - uint32_t time_msec, enum wlr_tablet_tool_tip_state state); - void (*end)(struct sway_seat *seat); - void (*unref)(struct sway_seat *seat, struct sway_container *con); - void (*render)(struct sway_seat *seat, struct fx_render_context *ctx); - bool allow_set_cursor; -}; - -struct sway_seat_device { - struct sway_seat *sway_seat; - struct sway_input_device *input_device; - struct sway_keyboard *keyboard; - struct sway_switch *switch_device; - struct sway_tablet *tablet; - struct sway_tablet_pad *tablet_pad; - struct wl_list link; // sway_seat::devices -}; - -struct sway_seat_node { - struct sway_seat *seat; - struct sway_node *node; - - struct wl_list link; // sway_seat::focus_stack - - struct wl_listener destroy; -}; - -struct sway_drag_icon { - struct sway_seat *seat; - struct wlr_drag_icon *wlr_drag_icon; - struct wl_list link; // sway_root::drag_icons - - double x, y; // in layout-local coordinates - int dx, dy; // offset in surface-local coordinates - - struct wl_listener surface_commit; - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener destroy; -}; - -struct sway_drag { - struct sway_seat *seat; - struct wlr_drag *wlr_drag; - struct wl_listener destroy; -}; - -struct sway_seat { - struct wlr_seat *wlr_seat; - struct sway_cursor *cursor; - - bool has_focus; - struct wl_list focus_stack; // list of containers in focus order - struct sway_workspace *workspace; - char *prev_workspace_name; // for workspace back_and_forth - - struct wlr_layer_surface_v1 *focused_layer; - // If the exclusive layer is set, views cannot receive keyboard focus - bool has_exclusive_layer; - - // If exclusive_client is set, no other clients will receive input events - struct wl_client *exclusive_client; - - // Last touch point - int32_t touch_id; - double touch_x, touch_y; - - // Seat operations (drag and resize) - const struct sway_seatop_impl *seatop_impl; - void *seatop_data; - - uint32_t last_button_serial; - - uint32_t idle_inhibit_sources, idle_wake_sources; - - list_t *deferred_bindings; // struct sway_binding - - struct sway_input_method_relay im_relay; - - struct wl_listener focus_destroy; - struct wl_listener new_node; - struct wl_listener request_start_drag; - struct wl_listener start_drag; - struct wl_listener request_set_selection; - struct wl_listener request_set_primary_selection; - - struct wl_list devices; // sway_seat_device::link - struct wl_list keyboard_groups; // sway_keyboard_group::link - struct wl_list keyboard_shortcuts_inhibitors; - // sway_keyboard_shortcuts_inhibitor::link - - struct wl_list link; // input_manager::seats -}; - -struct sway_pointer_constraint { - struct sway_cursor *cursor; - struct wlr_pointer_constraint_v1 *constraint; - - struct wl_listener set_region; - struct wl_listener destroy; -}; - -struct sway_keyboard_shortcuts_inhibitor { - struct wlr_keyboard_shortcuts_inhibitor_v1 *inhibitor; - - struct wl_listener destroy; - - struct wl_list link; // sway_seat::keyboard_shortcuts_inhibitors -}; - -struct sway_seat *seat_create(const char *seat_name); - -void seat_destroy(struct sway_seat *seat); - -void seat_add_device(struct sway_seat *seat, - struct sway_input_device *device); - -void seat_configure_device(struct sway_seat *seat, - struct sway_input_device *device); - -void seat_configure_device_mapping(struct sway_seat *seat, - struct sway_input_device *input_device); - -void seat_reset_device(struct sway_seat *seat, - struct sway_input_device *input_device); - -void seat_remove_device(struct sway_seat *seat, - struct sway_input_device *device); - -void seat_configure_xcursor(struct sway_seat *seat); - -void seat_set_focus(struct sway_seat *seat, struct sway_node *node); - -void seat_set_focus_container(struct sway_seat *seat, - struct sway_container *con); - -void seat_set_focus_workspace(struct sway_seat *seat, - struct sway_workspace *ws); - -/** - * Manipulate the focus stack without triggering any other behaviour. - * - * This can be used to set focus_inactive by calling the function a second time - * with the real focus. - */ -void seat_set_raw_focus(struct sway_seat *seat, struct sway_node *node); - -void seat_set_focus_surface(struct sway_seat *seat, - struct wlr_surface *surface, bool unfocus); - -void seat_set_focus_layer(struct sway_seat *seat, - struct wlr_layer_surface_v1 *layer); - -void seat_set_exclusive_client(struct sway_seat *seat, - struct wl_client *client); - -struct sway_node *seat_get_focus(struct sway_seat *seat); - -struct sway_workspace *seat_get_focused_workspace(struct sway_seat *seat); - -// If a scratchpad container is fullscreen global, this can be used to try to -// determine the last focused workspace. Otherwise, this should yield the same -// results as seat_get_focused_workspace. -struct sway_workspace *seat_get_last_known_workspace(struct sway_seat *seat); - -struct sway_container *seat_get_focused_container(struct sway_seat *seat); - -/** - * Return the last container to be focused for the seat (or the most recently - * opened if no container has received focused) that is a child of the given - * container. The focus-inactive container of the root window is the focused - * container for the seat (if the seat does have focus). This function can be - * used to determine what container gets focused next if the focused container - * is destroyed, or focus moves to a container with children and we need to - * descend into the next leaf in focus order. - */ -struct sway_node *seat_get_focus_inactive(struct sway_seat *seat, - struct sway_node *node); - -struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat, - struct sway_workspace *workspace); - -/** - * Descend into the focus stack to find the focus-inactive view. Useful for - * container placement when they change position in the tree. - */ -struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat, - struct sway_node *ancestor); - -/** - * Return the immediate child of container which was most recently focused. - */ -struct sway_node *seat_get_active_tiling_child(struct sway_seat *seat, - struct sway_node *parent); - -/** - * Iterate over the focus-inactive children of the container calling the - * function on each. - */ -void seat_for_each_node(struct sway_seat *seat, - void (*f)(struct sway_node *node, void *data), void *data); - -void seat_apply_config(struct sway_seat *seat, struct seat_config *seat_config); - -struct seat_config *seat_get_config(struct sway_seat *seat); - -struct seat_config *seat_get_config_by_name(const char *name); - -void seat_idle_notify_activity(struct sway_seat *seat, - enum sway_input_idle_source source); - -bool seat_is_input_allowed(struct sway_seat *seat, struct wlr_surface *surface); - -void drag_icon_update_position(struct sway_drag_icon *icon); - -enum wlr_edges find_resize_edge(struct sway_container *cont, - struct wlr_surface *surface, struct sway_cursor *cursor); - -void seatop_begin_default(struct sway_seat *seat); - -void seatop_begin_down(struct sway_seat *seat, struct sway_container *con, - double sx, double sy); - -void seatop_begin_down_on_surface(struct sway_seat *seat, - struct wlr_surface *surface, double sx, double sy); - -void seatop_begin_touch_down(struct sway_seat *seat, struct wlr_surface *surface, - struct wlr_touch_down_event *event, double sx, double sy, double lx, double ly); - -void seatop_begin_move_floating(struct sway_seat *seat, - struct sway_container *con); - -void seatop_begin_move_tiling_threshold(struct sway_seat *seat, - struct sway_container *con); - -void seatop_begin_move_tiling(struct sway_seat *seat, - struct sway_container *con); - -void seatop_begin_resize_floating(struct sway_seat *seat, - struct sway_container *con, enum wlr_edges edge); - -void seatop_begin_resize_tiling(struct sway_seat *seat, - struct sway_container *con, enum wlr_edges edge); - -struct sway_container *seat_get_focus_inactive_floating(struct sway_seat *seat, - struct sway_workspace *workspace); - -void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec, - uint32_t button, enum wlr_button_state state); - -void seat_consider_warp_to_focus(struct sway_seat *seat); - -void seatop_button(struct sway_seat *seat, uint32_t time_msec, - struct wlr_input_device *device, uint32_t button, - enum wlr_button_state state); - -void seatop_pointer_motion(struct sway_seat *seat, uint32_t time_msec); - -void seatop_pointer_axis(struct sway_seat *seat, - struct wlr_pointer_axis_event *event); - -void seatop_tablet_tool_tip(struct sway_seat *seat, - struct sway_tablet_tool *tool, uint32_t time_msec, - enum wlr_tablet_tool_tip_state state); - -void seatop_tablet_tool_motion(struct sway_seat *seat, - struct sway_tablet_tool *tool, uint32_t time_msec); - -void seatop_hold_begin(struct sway_seat *seat, - struct wlr_pointer_hold_begin_event *event); -void seatop_hold_end(struct sway_seat *seat, - struct wlr_pointer_hold_end_event *event); - -void seatop_pinch_begin(struct sway_seat *seat, - struct wlr_pointer_pinch_begin_event *event); -void seatop_pinch_update(struct sway_seat *seat, - struct wlr_pointer_pinch_update_event *event); -void seatop_pinch_end(struct sway_seat *seat, - struct wlr_pointer_pinch_end_event *event); - -void seatop_swipe_begin(struct sway_seat *seat, - struct wlr_pointer_swipe_begin_event *event); -void seatop_swipe_update(struct sway_seat *seat, - struct wlr_pointer_swipe_update_event *event); -void seatop_swipe_end(struct sway_seat *seat, - struct wlr_pointer_swipe_end_event *event); - -void seatop_touch_motion(struct sway_seat *seat, - struct wlr_touch_motion_event *event, double lx, double ly); - -void seatop_touch_up(struct sway_seat *seat, - struct wlr_touch_up_event *event); - -void seatop_touch_down(struct sway_seat *seat, - struct wlr_touch_down_event *event, double lx, double ly); - -void seatop_touch_cancel(struct sway_seat *seat, - struct wlr_touch_cancel_event *event); - -void seatop_rebase(struct sway_seat *seat, uint32_t time_msec); - -/** - * End a seatop (ie. free any seatop specific resources). - */ -void seatop_end(struct sway_seat *seat); - -/** - * Instructs the seatop implementation to drop any references to the given - * container (eg. because the container is destroying). - * The seatop may choose to abort itself in response to this. - */ -void seatop_unref(struct sway_seat *seat, struct sway_container *con); - -/** - * Instructs a seatop to render anything that it needs to render - * (eg. dropzone for move-tiling) - */ -void seatop_render(struct sway_seat *seat, struct fx_render_context *ctx); - -bool seatop_allows_set_cursor(struct sway_seat *seat); - -/** - * Returns the keyboard shortcuts inhibitor that applies to the given surface - * or NULL if none exists. - */ -struct sway_keyboard_shortcuts_inhibitor * -keyboard_shortcuts_inhibitor_get_for_surface(const struct sway_seat *seat, - const struct wlr_surface *surface); - -/** - * Returns the keyboard shortcuts inhibitor that applies to the currently - * focused surface of a seat or NULL if none exists. - */ -struct sway_keyboard_shortcuts_inhibitor * -keyboard_shortcuts_inhibitor_get_for_focused_surface(const struct sway_seat *seat); - -#endif diff --git a/include/sway/input/switch.h b/include/sway/input/switch.h deleted file mode 100644 index de6787b7f..000000000 --- a/include/sway/input/switch.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _SWAY_INPUT_SWITCH_H -#define _SWAY_INPUT_SWITCH_H - -#include "sway/input/seat.h" - -struct sway_switch { - struct sway_seat_device *seat_device; - struct wlr_switch *wlr; - enum wlr_switch_state state; - enum wlr_switch_type type; - - struct wl_listener switch_toggle; -}; - -struct sway_switch *sway_switch_create(struct sway_seat *seat, - struct sway_seat_device *device); - -void sway_switch_configure(struct sway_switch *sway_switch); - -void sway_switch_destroy(struct sway_switch *sway_switch); - -void sway_switch_retrigger_bindings_for_all(void); - -#endif diff --git a/include/sway/input/tablet.h b/include/sway/input/tablet.h deleted file mode 100644 index 2fa5db6d8..000000000 --- a/include/sway/input/tablet.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef _SWAY_INPUT_TABLET_H -#define _SWAY_INPUT_TABLET_H -#include - -struct sway_seat; -struct wlr_tablet_tool; - -struct sway_tablet { - struct wl_list link; - struct sway_seat_device *seat_device; - struct wlr_tablet_v2_tablet *tablet_v2; -}; - -enum sway_tablet_tool_mode { - SWAY_TABLET_TOOL_MODE_ABSOLUTE, - SWAY_TABLET_TOOL_MODE_RELATIVE, -}; - -struct sway_tablet_tool { - struct sway_seat *seat; - struct sway_tablet *tablet; - struct wlr_tablet_v2_tablet_tool *tablet_v2_tool; - - enum sway_tablet_tool_mode mode; - double tilt_x, tilt_y; - - struct wl_listener set_cursor; - struct wl_listener tool_destroy; -}; - -struct sway_tablet_pad { - struct wl_list link; - struct sway_seat_device *seat_device; - struct sway_tablet *tablet; - struct wlr_tablet_pad *wlr; - struct wlr_tablet_v2_tablet_pad *tablet_v2_pad; - - struct wl_listener attach; - struct wl_listener button; - struct wl_listener ring; - struct wl_listener strip; - - struct wlr_surface *current_surface; - struct wl_listener surface_destroy; - - struct wl_listener tablet_destroy; -}; - -struct sway_tablet *sway_tablet_create(struct sway_seat *seat, - struct sway_seat_device *device); - -void sway_configure_tablet(struct sway_tablet *tablet); - -void sway_tablet_destroy(struct sway_tablet *tablet); - -void sway_tablet_tool_configure(struct sway_tablet *tablet, - struct wlr_tablet_tool *wlr_tool); - -struct sway_tablet_pad *sway_tablet_pad_create(struct sway_seat *seat, - struct sway_seat_device *device); - -void sway_configure_tablet_pad(struct sway_tablet_pad *tablet_pad); - -void sway_tablet_pad_destroy(struct sway_tablet_pad *tablet_pad); - -void sway_tablet_pad_set_focus(struct sway_tablet_pad *tablet_pad, - struct wlr_surface *surface); - -#endif diff --git a/include/sway/input/text_input.h b/include/sway/input/text_input.h deleted file mode 100644 index f583af7a9..000000000 --- a/include/sway/input/text_input.h +++ /dev/null @@ -1,93 +0,0 @@ -#ifndef _SWAY_INPUT_TEXT_INPUT_H -#define _SWAY_INPUT_TEXT_INPUT_H - -#include -#include -#include -#include - -/** - * The relay structure manages the relationship between text-input and - * input_method interfaces on a given seat. Multiple text-input interfaces may - * be bound to a relay, but at most one will be focused (receiving events) at - * a time. At most one input-method interface may be bound to the seat. The - * relay manages life cycle of both sides. When both sides are present and - * focused, the relay passes messages between them. - * - * Text input focus is a subset of keyboard focus - if the text-input is - * in the focused state, wl_keyboard sent an enter as well. However, having - * wl_keyboard focused doesn't mean that text-input will be focused. - */ -struct sway_input_method_relay { - struct sway_seat *seat; - - struct wl_list text_inputs; // sway_text_input::link - struct wl_list input_popups; // sway_input_popup::link - struct wlr_input_method_v2 *input_method; // doesn't have to be present - - struct wl_listener text_input_new; - - struct wl_listener input_method_new; - struct wl_listener input_method_commit; - struct wl_listener input_method_new_popup_surface; - struct wl_listener input_method_grab_keyboard; - struct wl_listener input_method_destroy; - - struct wl_listener input_method_keyboard_grab_destroy; -}; - -struct sway_input_popup { - struct sway_input_method_relay *relay; - struct wlr_input_popup_surface_v2 *popup_surface; - - int x, y; - bool visible; - - struct wl_list link; - - struct wl_listener popup_map; - struct wl_listener popup_unmap; - struct wl_listener popup_destroy; - struct wl_listener popup_surface_commit; - - struct wl_listener focused_surface_unmap; -}; - -struct sway_text_input { - struct sway_input_method_relay *relay; - - struct wlr_text_input_v3 *input; - // The surface getting seat's focus. Stored for when text-input cannot - // be sent an enter event immediately after getting focus, e.g. when - // there's no input method available. Cleared once text-input is entered. - struct wlr_surface *pending_focused_surface; - - struct wl_list link; - - struct wl_listener pending_focused_surface_destroy; - - struct wl_listener text_input_enable; - struct wl_listener text_input_commit; - struct wl_listener text_input_disable; - struct wl_listener text_input_destroy; -}; - -void sway_input_method_relay_init(struct sway_seat *seat, - struct sway_input_method_relay *relay); - -void sway_input_method_relay_finish(struct sway_input_method_relay *relay); - -// Updates currently focused surface. Surface must belong to the same seat. -void sway_input_method_relay_set_focus(struct sway_input_method_relay *relay, - struct wlr_surface *surface); - -struct sway_text_input *sway_text_input_create( - struct sway_input_method_relay *relay, - struct wlr_text_input_v3 *text_input); - -bool sway_input_popup_get_position( - struct sway_input_popup *popup, int *lx, int *ly); - -void sway_input_popup_damage(struct sway_input_popup *popup); - -#endif diff --git a/include/sway/ipc-json.h b/include/sway/ipc-json.h deleted file mode 100644 index bc9f49856..000000000 --- a/include/sway/ipc-json.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _SWAY_IPC_JSON_H -#define _SWAY_IPC_JSON_H -#include -#include "sway/output.h" -#include "sway/tree/container.h" -#include "sway/input/input-manager.h" - -json_object *ipc_json_get_version(void); - -json_object *ipc_json_get_binding_mode(void); - -json_object *ipc_json_describe_disabled_output(struct sway_output *o); -json_object *ipc_json_describe_non_desktop_output(struct sway_output_non_desktop *o); -json_object *ipc_json_describe_node(struct sway_node *node); -json_object *ipc_json_describe_node_recursive(struct sway_node *node); -json_object *ipc_json_describe_input(struct sway_input_device *device); -json_object *ipc_json_describe_seat(struct sway_seat *seat); -json_object *ipc_json_describe_bar_config(struct bar_config *bar); - -#endif diff --git a/include/sway/ipc-server.h b/include/sway/ipc-server.h deleted file mode 100644 index d4c009427..000000000 --- a/include/sway/ipc-server.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef _SWAY_IPC_SERVER_H -#define _SWAY_IPC_SERVER_H -#include -#include "sway/config.h" -#include "sway/input/input-manager.h" -#include "sway/tree/container.h" -#include "ipc.h" - -struct sway_server; - -void ipc_init(struct sway_server *server); - -struct sockaddr_un *ipc_user_sockaddr(void); - -void ipc_event_workspace(struct sway_workspace *old, - struct sway_workspace *new, const char *change); -void ipc_event_window(struct sway_container *window, const char *change); -void ipc_event_barconfig_update(struct bar_config *bar); -void ipc_event_bar_state_update(struct bar_config *bar); -void ipc_event_mode(const char *mode, bool pango); -void ipc_event_shutdown(const char *reason); -void ipc_event_binding(struct sway_binding *binding); -void ipc_event_input(const char *change, struct sway_input_device *device); -void ipc_event_output(void); - -#endif diff --git a/include/sway/layer_criteria.h b/include/sway/layer_criteria.h deleted file mode 100644 index f0906460f..000000000 --- a/include/sway/layer_criteria.h +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include "sway/layers.h" -#include "sway/config.h" - -struct layer_criteria { - char *namespace; - char *cmdlist; -}; - -void layer_criteria_destroy(struct layer_criteria *criteria); - -bool layer_criteria_is_equal(struct layer_criteria *a, struct layer_criteria *b); - -bool layer_criteria_already_exists(struct layer_criteria *criteria); - -// Gathers all of the matching criterias for a specified `sway_layer_surface` -list_t *layer_criterias_for_sway_layer_surface(struct sway_layer_surface *sway_layer); - -// Parses the `layer_criteria` and applies the effects to the `sway_layer_surface` -void layer_criteria_parse(struct sway_layer_surface *sway_layer, struct layer_criteria *criteria); diff --git a/include/sway/layers.h b/include/sway/layers.h deleted file mode 100644 index bb7cbb22c..000000000 --- a/include/sway/layers.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef _SWAY_LAYERS_H -#define _SWAY_LAYERS_H -#include -#include -#include - -enum layer_parent { - LAYER_PARENT_LAYER, - LAYER_PARENT_POPUP, -}; - -struct sway_layer_surface { - struct wlr_layer_surface_v1 *layer_surface; - struct wl_list link; - - struct wl_listener destroy; - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener surface_commit; - struct wl_listener output_destroy; - struct wl_listener new_popup; - struct wl_listener new_subsurface; - - struct wlr_box geo; - bool mapped; - struct wlr_box extent; - enum zwlr_layer_shell_v1_layer layer; - - struct wl_list subsurfaces; - - bool has_shadow; - bool has_blur; - bool blur_ignore_transparent; - int corner_radius; -}; - -struct sway_layer_popup { - struct wlr_xdg_popup *wlr_popup; - enum layer_parent parent_type; - union { - struct sway_layer_surface *parent_layer; - struct sway_layer_popup *parent_popup; - }; - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener destroy; - struct wl_listener commit; - struct wl_listener new_popup; -}; - -struct sway_layer_subsurface { - struct wlr_subsurface *wlr_subsurface; - struct sway_layer_surface *layer_surface; - struct wl_list link; - - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener destroy; - struct wl_listener commit; -}; - -struct sway_output; - -struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface( - struct wlr_surface *surface); - -void arrange_layers(struct sway_output *output); - -struct sway_layer_surface *layer_from_wlr_layer_surface_v1( - struct wlr_layer_surface_v1 *layer_surface); - -#endif diff --git a/include/sway/output.h b/include/sway/output.h deleted file mode 100644 index 0e9e27c9b..000000000 --- a/include/sway/output.h +++ /dev/null @@ -1,236 +0,0 @@ -#ifndef _SWAY_OUTPUT_H -#define _SWAY_OUTPUT_H -#include -#include -#include -#include -#include -#include "config.h" -#include "scenefx/render/pass.h" -#include "sway/tree/node.h" -#include "sway/tree/view.h" - -struct decoration_data get_undecorated_decoration_data(); - -struct sway_server; -struct sway_container; - -struct decoration_data { - float alpha; - float saturation; - int corner_radius; - float dim; - float *dim_color; - bool has_titlebar; - bool discard_transparent; - bool blur; - bool shadow; -}; - -struct render_data { - struct fx_render_context *ctx; - pixman_region32_t *damage; - struct wlr_box *clip_box; - struct decoration_data deco_data; - struct sway_view *view; -}; - -struct sway_output_state { - list_t *workspaces; - struct sway_workspace *active_workspace; -}; - -struct sway_output { - struct sway_node node; - struct wlr_output *wlr_output; - struct sway_server *server; - struct wl_list link; - - struct wl_list layers[4]; // sway_layer_surface::link - struct wlr_box usable_area; - - struct timespec last_frame; - struct wlr_damage_ring damage_ring; - - int lx, ly; // layout coords - int width, height; // transformed buffer size - enum wl_output_subpixel detected_subpixel; - enum scale_filter_mode scale_filter; - - bool enabling, enabled; - list_t *workspaces; - - struct sway_output_state current; - - struct wl_listener layout_destroy; - struct wl_listener destroy; - struct wl_listener commit; - struct wl_listener present; - struct wl_listener damage; - struct wl_listener frame; - struct wl_listener needs_frame; - struct wl_listener request_state; - - struct { - struct wl_signal disable; - } events; - - struct timespec last_presentation; - uint32_t refresh_nsec; - int max_render_time; // In milliseconds - struct wl_event_source *repaint_timer; - bool gamma_lut_changed; -}; - -struct sway_output_non_desktop { - struct wlr_output *wlr_output; - - struct wl_listener destroy; -}; - -struct fx_render_context { - struct sway_output *output; - struct wlr_renderer *renderer; - pixman_region32_t *output_damage; - - struct fx_gles_render_pass *pass; -}; - -struct sway_output *output_create(struct wlr_output *wlr_output); - -void output_destroy(struct sway_output *output); - -void output_begin_destroy(struct sway_output *output); - -struct sway_output *output_from_wlr_output(struct wlr_output *output); - -struct sway_output *output_get_in_direction(struct sway_output *reference, - enum wlr_direction direction); - -void output_add_workspace(struct sway_output *output, - struct sway_workspace *workspace); - -typedef void (*sway_surface_iterator_func_t)(struct sway_output *output, - struct sway_view *view, struct wlr_surface *surface, struct wlr_box *box, - void *user_data); - -void output_damage_whole(struct sway_output *output); - -void output_damage_surface(struct sway_output *output, double ox, double oy, - struct wlr_surface *surface, bool whole); - -void output_damage_from_view(struct sway_output *output, - struct sway_view *view); - -void output_damage_box(struct sway_output *output, struct wlr_box *box); - -void output_damage_whole_container(struct sway_output *output, - struct sway_container *con); - -bool output_match_name_or_id(struct sway_output *output, - const char *name_or_id); - -// this ONLY includes the enabled outputs -struct sway_output *output_by_name_or_id(const char *name_or_id); - -// this includes all the outputs, including disabled ones -struct sway_output *all_output_by_name_or_id(const char *name_or_id); - -void output_sort_workspaces(struct sway_output *output); - -void output_enable(struct sway_output *output); - -void output_disable(struct sway_output *output); - -bool output_has_opaque_overlay_layer_surface(struct sway_output *output); - -struct sway_workspace *output_get_active_workspace(struct sway_output *output); - -void output_render(struct fx_render_context *ctx); - -void output_surface_for_each_surface(struct sway_output *output, - struct wlr_surface *surface, double ox, double oy, - sway_surface_iterator_func_t iterator, void *user_data); - -void output_view_for_each_surface(struct sway_output *output, - struct sway_view *view, sway_surface_iterator_func_t iterator, - void *user_data); - -void output_view_for_each_popup_surface(struct sway_output *output, - struct sway_view *view, sway_surface_iterator_func_t iterator, - void *user_data); - -void output_layer_for_each_surface(struct sway_output *output, - struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator, - void *user_data); - -void output_layer_for_each_toplevel_surface(struct sway_output *output, - struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator, - void *user_data); - -void output_layer_for_each_popup_surface(struct sway_output *output, - struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator, - void *user_data); - -#if HAVE_XWAYLAND -void output_unmanaged_for_each_surface(struct sway_output *output, - struct wl_list *unmanaged, sway_surface_iterator_func_t iterator, - void *user_data); -#endif - -void output_input_popups_for_each_surface(struct sway_output *output, - struct wl_list *input_popups, sway_surface_iterator_func_t iterator, - void *user_data); - -void output_drag_icons_for_each_surface(struct sway_output *output, - struct wl_list *drag_icons, sway_surface_iterator_func_t iterator, - void *user_data); - -void output_for_each_workspace(struct sway_output *output, - void (*f)(struct sway_workspace *ws, void *data), void *data); - -void output_for_each_container(struct sway_output *output, - void (*f)(struct sway_container *con, void *data), void *data); - -struct sway_workspace *output_find_workspace(struct sway_output *output, - bool (*test)(struct sway_workspace *ws, void *data), void *data); - -struct sway_container *output_find_container(struct sway_output *output, - bool (*test)(struct sway_container *con, void *data), void *data); - -void output_get_box(struct sway_output *output, struct wlr_box *box); - -enum sway_container_layout output_get_default_layout( - struct sway_output *output); - -void render_rect(struct fx_render_context *ctx, const struct wlr_box *_box, - float color[static 4]); - -void render_rounded_rect(struct fx_render_context *ctx, const struct wlr_box *_box, - float color[static 4], int corner_radius, enum corner_location corner_location); - -void render_blur(struct fx_render_context *ctx, struct wlr_texture *texture, - const struct wlr_fbox *src_box, const struct wlr_box *dst_box, - bool optimized_blur, pixman_region32_t *opaque_region, - struct decoration_data deco_data); - -void premultiply_alpha(float color[4], float opacity); - -void scale_box(struct wlr_box *box, float scale); - -enum wlr_direction opposite_direction(enum wlr_direction d); - -void handle_output_layout_change(struct wl_listener *listener, void *data); - -void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data); - -void handle_output_manager_apply(struct wl_listener *listener, void *data); - -void handle_output_manager_test(struct wl_listener *listener, void *data); - -void handle_output_power_manager_set_mode(struct wl_listener *listener, - void *data); - -struct sway_output_non_desktop *output_non_desktop_create(struct wlr_output *wlr_output); - -#endif diff --git a/include/sway/server.h b/include/sway/server.h deleted file mode 100644 index ef70ae4e2..000000000 --- a/include/sway/server.h +++ /dev/null @@ -1,192 +0,0 @@ -#ifndef _SWAY_SERVER_H -#define _SWAY_SERVER_H -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "config.h" -#include "list.h" -#include "sway/desktop/idle_inhibit_v1.h" -#if HAVE_XWAYLAND -#include "sway/xwayland.h" -#endif - -struct sway_transaction; - -struct sway_server { - struct wl_display *wl_display; - struct wl_event_loop *wl_event_loop; - const char *socket; - - struct wlr_backend *backend; - struct wlr_session *session; - // secondary headless backend used for creating virtual outputs on-the-fly - struct wlr_backend *headless_backend; - struct wlr_renderer *renderer; - struct wlr_allocator *allocator; - - struct wlr_compositor *compositor; - struct wl_listener compositor_new_surface; - - struct wlr_linux_dmabuf_v1 *linux_dmabuf_v1; - - struct wlr_data_device_manager *data_device_manager; - - struct sway_input_manager *input; - - struct wl_listener new_output; - struct wl_listener output_layout_change; - - struct wlr_idle_notifier_v1 *idle_notifier_v1; - struct sway_idle_inhibit_manager_v1 idle_inhibit_manager_v1; - - struct wlr_layer_shell_v1 *layer_shell; - struct wl_listener layer_shell_surface; - - struct wlr_xdg_shell *xdg_shell; - struct wl_listener xdg_shell_surface; - - struct wlr_tablet_manager_v2 *tablet_v2; - -#if HAVE_XWAYLAND - struct sway_xwayland xwayland; - struct wl_listener xwayland_surface; - struct wl_listener xwayland_ready; -#endif - - struct wlr_relative_pointer_manager_v1 *relative_pointer_manager; - - struct wlr_server_decoration_manager *server_decoration_manager; - struct wl_listener server_decoration; - struct wl_list decorations; // sway_server_decoration::link - - struct wlr_xdg_decoration_manager_v1 *xdg_decoration_manager; - struct wl_listener xdg_decoration; - struct wl_list xdg_decorations; // sway_xdg_decoration::link - - struct wlr_drm_lease_v1_manager *drm_lease_manager; - struct wl_listener drm_lease_request; - - struct wlr_presentation *presentation; - - struct wlr_pointer_constraints_v1 *pointer_constraints; - struct wl_listener pointer_constraint; - - struct wlr_output_manager_v1 *output_manager_v1; - struct wl_listener output_manager_apply; - struct wl_listener output_manager_test; - - struct wlr_gamma_control_manager_v1 *gamma_control_manager_v1; - struct wl_listener gamma_control_set_gamma; - - struct { - bool locked; - struct wlr_session_lock_manager_v1 *manager; - - struct wlr_session_lock_v1 *lock; - struct wlr_surface *focused; - struct wl_listener lock_new_surface; - struct wl_listener lock_unlock; - struct wl_listener lock_destroy; - - struct wl_listener new_lock; - struct wl_listener manager_destroy; - } session_lock; - - struct wlr_output_power_manager_v1 *output_power_manager_v1; - struct wl_listener output_power_manager_set_mode; - struct wlr_input_method_manager_v2 *input_method; - struct wlr_text_input_manager_v3 *text_input; - struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager; - struct wlr_content_type_manager_v1 *content_type_manager_v1; - struct wlr_data_control_manager_v1 *data_control_manager_v1; - struct wlr_screencopy_manager_v1 *screencopy_manager_v1; - struct wlr_export_dmabuf_manager_v1 *export_dmabuf_manager_v1; - struct wlr_security_context_manager_v1 *security_context_manager_v1; - - struct wlr_xdg_activation_v1 *xdg_activation_v1; - struct wl_listener xdg_activation_v1_request_activate; - struct wl_listener xdg_activation_v1_new_token; - - struct wl_listener request_set_cursor_shape; - - struct wl_list pending_launcher_ctxs; // launcher_ctx::link - - // The timeout for transactions, after which a transaction is applied - // regardless of readiness. - size_t txn_timeout_ms; - - // Stores a transaction after it has been committed, but is waiting for - // views to ack the new dimensions before being applied. A queued - // transaction is frozen and must not have new instructions added to it. - struct sway_transaction *queued_transaction; - - // Stores a pending transaction that will be committed once the existing - // queued transaction is applied and freed. The pending transaction can be - // updated with new instructions as needed. - struct sway_transaction *pending_transaction; - - // Stores the nodes that have been marked as "dirty" and will be put into - // the pending transaction. - list_t *dirty_nodes; -}; - -extern struct sway_server server; - -struct sway_debug { - bool noatomic; // Ignore atomic layout updates - bool txn_timings; // Log verbose messages about transactions - bool txn_wait; // Always wait for the timeout before applying - bool noscanout; // Disable direct scan-out - - enum { - DAMAGE_DEFAULT, // Default behaviour - DAMAGE_HIGHLIGHT, // Highlight regions of the screen being damaged - DAMAGE_RERENDER, // Render the full output when any damage occurs - } damage; -}; - -extern struct sway_debug debug; - -bool server_init(struct sway_server *server); -void server_fini(struct sway_server *server); -bool server_start(struct sway_server *server); -void server_run(struct sway_server *server); - -void restore_nofile_limit(void); - -void handle_compositor_new_surface(struct wl_listener *listener, void *data); -void handle_new_output(struct wl_listener *listener, void *data); - -void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data); -void handle_layer_shell_surface(struct wl_listener *listener, void *data); -void sway_session_lock_init(void); -void handle_xdg_shell_surface(struct wl_listener *listener, void *data); -#if HAVE_XWAYLAND -void handle_xwayland_surface(struct wl_listener *listener, void *data); -#endif -void handle_server_decoration(struct wl_listener *listener, void *data); -void handle_xdg_decoration(struct wl_listener *listener, void *data); -void handle_pointer_constraint(struct wl_listener *listener, void *data); -void xdg_activation_v1_handle_request_activate(struct wl_listener *listener, - void *data); -void xdg_activation_v1_handle_new_token(struct wl_listener *listener, - void *data); - -void set_rr_scheduling(void); - -#endif diff --git a/include/sway/surface.h b/include/sway/surface.h deleted file mode 100644 index a7a8ec3ff..000000000 --- a/include/sway/surface.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _SWAY_SURFACE_H -#define _SWAY_SURFACE_H -#include - -struct sway_surface { - struct wlr_surface *wlr_surface; - - struct wl_listener destroy; - - /** - * This timer can be used for issuing delayed frame done callbacks (for - * example, to improve presentation latency). Its handler is set to a - * function that issues a frame done callback to this surface. - */ - struct wl_event_source *frame_done_timer; -}; - -void surface_update_outputs(struct wlr_surface *surface); -void surface_enter_output(struct wlr_surface *surface, - struct sway_output *output); -void surface_leave_output(struct wlr_surface *surface, - struct sway_output *output); - -#endif diff --git a/include/sway/swaynag.h b/include/sway/swaynag.h deleted file mode 100644 index 03bd52c33..000000000 --- a/include/sway/swaynag.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef _SWAY_SWAYNAG_H -#define _SWAY_SWAYNAG_H -#include -#include "stringop.h" - -struct swaynag_instance { - struct wl_client *client; - struct wl_listener client_destroy; - - const char *args; - int fd[2]; - bool detailed; -}; - -// Spawn swaynag. If swaynag->detailed, then swaynag->fd[1] will left open -// so it can be written to. Call swaynag_show when done writing. This will -// be automatically called by swaynag_log if the instance is not spawned and -// swaynag->detailed is true. -bool swaynag_spawn(const char *swaynag_command, - struct swaynag_instance *swaynag); - -// Write a log message to swaynag->fd[1]. This will fail when swaynag->detailed -// is false. -void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag, - const char *fmt, ...) _SWAY_ATTRIB_PRINTF(3, 4); - -// If swaynag->detailed, close swaynag->fd[1] so swaynag displays -void swaynag_show(struct swaynag_instance *swaynag); - -#endif diff --git a/include/sway/tree/arrange.h b/include/sway/tree/arrange.h deleted file mode 100644 index 06a2279c1..000000000 --- a/include/sway/tree/arrange.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _SWAY_ARRANGE_H -#define _SWAY_ARRANGE_H - -struct sway_output; -struct sway_workspace; -struct sway_container; -struct sway_node; - -void arrange_container(struct sway_container *container); - -void arrange_workspace(struct sway_workspace *workspace); - -void arrange_output(struct sway_output *output); - -void arrange_root(void); - -void arrange_node(struct sway_node *node); - -#endif diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h deleted file mode 100644 index 42fb71bf0..000000000 --- a/include/sway/tree/container.h +++ /dev/null @@ -1,394 +0,0 @@ -#ifndef _SWAY_CONTAINER_H -#define _SWAY_CONTAINER_H -#include -#include -#include -#include "list.h" -#include "sway/tree/node.h" - -struct sway_view; -struct sway_seat; - -enum sway_container_layout { - L_NONE, - L_HORIZ, - L_VERT, - L_STACKED, - L_TABBED, -}; - -enum sway_container_border { - B_NONE, - B_PIXEL, - B_NORMAL, - B_CSD, -}; - -enum sway_fullscreen_mode { - FULLSCREEN_NONE, - FULLSCREEN_WORKSPACE, - FULLSCREEN_GLOBAL, -}; - -struct sway_root; -struct sway_output; -struct sway_workspace; -struct sway_view; - -enum wlr_direction; - -struct sway_container_state { - // Container properties - enum sway_container_layout layout; - double x, y; - double width, height; - - enum sway_fullscreen_mode fullscreen_mode; - - struct sway_workspace *workspace; // NULL when hidden in the scratchpad - struct sway_container *parent; // NULL if container in root of workspace - list_t *children; // struct sway_container - - struct sway_container *focused_inactive_child; - bool focused; - - enum sway_container_border border; - int border_thickness; - bool border_top; - bool border_bottom; - bool border_left; - bool border_right; - - // These are in layout coordinates. - double content_x, content_y; - double content_width, content_height; -}; - -struct sway_container { - struct sway_node node; - struct sway_view *view; - - struct sway_container_state current; - struct sway_container_state pending; - - char *title; // The view's title (unformatted) - char *formatted_title; // The title displayed in the title bar - - enum sway_container_layout prev_split_layout; - - // Whether stickiness has been enabled on this container. Use - // `container_is_sticky_[or_child]` rather than accessing this field - // directly; it'll also check that the container is floating. - bool is_sticky; - - // For C_ROOT, this has no meaning - // For other types, this is the position in layout coordinates - // Includes borders - double saved_x, saved_y; - double saved_width, saved_height; - - // Used when the view changes to CSD unexpectedly. This will be a non-B_CSD - // border which we use to restore when the view returns to SSD. - enum sway_container_border saved_border; - - // The share of the space of parent container this container occupies - double width_fraction; - double height_fraction; - - // The share of space of the parent container that all children occupy - // Used for doing the resize calculations - double child_total_width; - double child_total_height; - - // In most cases this is the same as the content x and y, but if the view - // refuses to resize to the content dimensions then it can be smaller. - // These are in layout coordinates. - double surface_x, surface_y; - - // Outputs currently being intersected - list_t *outputs; // struct sway_output - - // Indicates that the container is a scratchpad container. - // Both hidden and visible scratchpad containers have scratchpad=true. - // Hidden scratchpad containers have a NULL parent. - bool scratchpad; - - bool shadow_enabled; - - bool blur_enabled; - - float saturation; - - // Stores last output size and position for adjusting coordinates of - // scratchpad windows. - // Unused for non-scratchpad windows. - struct wlr_box transform; - - float alpha; - - int corner_radius; - - float dim; - - struct wlr_texture *title_focused; - struct wlr_texture *title_focused_inactive; - struct wlr_texture *title_focused_tab_title; - struct wlr_texture *title_unfocused; - struct wlr_texture *title_urgent; - - list_t *marks; // char * - struct wlr_texture *marks_focused; - struct wlr_texture *marks_focused_inactive; - struct wlr_texture *marks_focused_tab_title; - struct wlr_texture *marks_unfocused; - struct wlr_texture *marks_urgent; - - struct { - struct wl_signal destroy; - } events; -}; - -struct sway_container *container_create(struct sway_view *view); - -void container_destroy(struct sway_container *con); - -void container_begin_destroy(struct sway_container *con); - -/** - * Search a container's descendants a container based on test criteria. Returns - * the first container that passes the test. - */ -struct sway_container *container_find_child(struct sway_container *container, - bool (*test)(struct sway_container *view, void *data), void *data); - -/** - * Find a container at the given coordinates. Returns the surface and - * surface-local coordinates of the given layout coordinates if the container - * is a view and the view contains a surface at those coordinates. - */ -struct sway_container *container_at(struct sway_workspace *workspace, - double lx, double ly, struct wlr_surface **surface, - double *sx, double *sy); - -struct sway_container *tiling_container_at( - struct sway_node *parent, double lx, double ly, - struct wlr_surface **surface, double *sx, double *sy); - -void container_for_each_child(struct sway_container *container, - void (*f)(struct sway_container *container, void *data), void *data); - -/** - * Returns the fullscreen container obstructing this container if it exists. - */ -struct sway_container *container_obstructing_fullscreen_container(struct sway_container *container); - -/** - * Returns true if the given container is an ancestor of this container. - */ -bool container_has_ancestor(struct sway_container *container, - struct sway_container *ancestor); - -void container_update_textures_recursive(struct sway_container *con); - -void container_damage_whole(struct sway_container *container); - -void container_reap_empty(struct sway_container *con); - -struct sway_container *container_flatten(struct sway_container *container); - -void container_update_title_textures(struct sway_container *container); - -size_t container_build_representation(enum sway_container_layout layout, - list_t *children, char *buffer); - -void container_update_representation(struct sway_container *container); - -/** - * Return the height of a regular title bar. - */ -size_t container_titlebar_height(void); - -void floating_calculate_constraints(int *min_width, int *max_width, - int *min_height, int *max_height); - -void floating_fix_coordinates(struct sway_container *con, - struct wlr_box *old, struct wlr_box *new); - -void container_floating_resize_and_center(struct sway_container *con); - -void container_floating_set_default_size(struct sway_container *con); - -void container_set_resizing(struct sway_container *con, bool resizing); - -void container_set_floating(struct sway_container *container, bool enable); - -void container_set_geometry_from_content(struct sway_container *con); - -/** - * Determine if the given container is itself floating. - * This will return false for any descendants of a floating container. - * - * Uses pending container state. - */ -bool container_is_floating(struct sway_container *container); - -/** - * Same as above, but for current container state. - */ -bool container_is_current_floating(struct sway_container *container); - -/** - * Get a container's box in layout coordinates. - */ -void container_get_box(struct sway_container *container, struct wlr_box *box); - -/** - * Move a floating container by the specified amount. - */ -void container_floating_translate(struct sway_container *con, - double x_amount, double y_amount); - -/** - * Choose an output for the floating container's new position. - */ -struct sway_output *container_floating_find_output(struct sway_container *con); - -/** - * Move a floating container to a new layout-local position. - */ -void container_floating_move_to(struct sway_container *con, - double lx, double ly); - -/** - * Move a floating container to the center of the workspace. - */ -void container_floating_move_to_center(struct sway_container *con); - -bool container_has_urgent_child(struct sway_container *container); - -/** - * If the container is involved in a drag or resize operation via a mouse, this - * ends the operation. - */ -void container_end_mouse_operation(struct sway_container *container); - -void container_set_fullscreen(struct sway_container *con, - enum sway_fullscreen_mode mode); - -/** - * Convenience function. - */ -void container_fullscreen_disable(struct sway_container *con); - -/** - * Walk up the container tree branch starting at the given container, and return - * its earliest ancestor. - */ -struct sway_container *container_toplevel_ancestor( - struct sway_container *container); - -/** - * Return true if the container is floating, or a child of a floating split - * container. - */ -bool container_is_floating_or_child(struct sway_container *container); - -/** - * Return true if the container is fullscreen, or a child of a fullscreen split - * container. - */ -bool container_is_fullscreen_or_child(struct sway_container *container); - -/** - * Return the output which will be used for scale purposes. - * This is the most recently entered output. - * If the container is not on any output, return NULL. - */ -struct sway_output *container_get_effective_output(struct sway_container *con); - -void container_discover_outputs(struct sway_container *con); - -enum sway_container_layout container_parent_layout(struct sway_container *con); - -enum sway_container_layout container_current_parent_layout( - struct sway_container *con); - -list_t *container_get_siblings(struct sway_container *container); - -int container_sibling_index(struct sway_container *child); - -list_t *container_get_current_siblings(struct sway_container *container); - -void container_handle_fullscreen_reparent(struct sway_container *con); - -void container_add_child(struct sway_container *parent, - struct sway_container *child); - -void container_insert_child(struct sway_container *parent, - struct sway_container *child, int i); - -/** - * Side should be 0 to add before, or 1 to add after. - */ -void container_add_sibling(struct sway_container *parent, - struct sway_container *child, bool after); - -void container_detach(struct sway_container *child); - -void container_replace(struct sway_container *container, - struct sway_container *replacement); - -void container_swap(struct sway_container *con1, struct sway_container *con2); - -struct sway_container *container_split(struct sway_container *child, - enum sway_container_layout layout); - -bool container_is_transient_for(struct sway_container *child, - struct sway_container *ancestor); - -/** - * Find any container that has the given mark and return it. - */ -struct sway_container *container_find_mark(char *mark); - -/** - * Find any container that has the given mark and remove the mark from the - * container. Returns true if it matched a container. - */ -bool container_find_and_unmark(char *mark); - -/** - * Remove all marks from the container. - */ -void container_clear_marks(struct sway_container *container); - -bool container_has_mark(struct sway_container *container, char *mark); - -void container_add_mark(struct sway_container *container, char *mark); - -void container_update_marks_textures(struct sway_container *container); - -void container_raise_floating(struct sway_container *con); - -bool container_is_scratchpad_hidden(struct sway_container *con); - -bool container_is_scratchpad_hidden_or_child(struct sway_container *con); - -bool container_is_sticky(struct sway_container *con); - -bool container_is_sticky_or_child(struct sway_container *con); - -/** - * This will destroy pairs of redundant H/V splits - * e.g. H[V[H[app app]] app] -> H[app app app] - * The middle "V[H[" are eliminated by a call to container_squash - * on the V[ con. It's grandchildren are added to its parent. - * - * This function is roughly equivalent to i3's tree_flatten here: - * https://github.com/i3/i3/blob/1f0c628cde40cf87371481041b7197344e0417c6/src/tree.c#L651 - * - * Returns the number of new containers added to the parent - */ -int container_squash(struct sway_container *con); - -#endif diff --git a/include/sway/tree/node.h b/include/sway/tree/node.h deleted file mode 100644 index 03a389a48..000000000 --- a/include/sway/tree/node.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef _SWAY_NODE_H -#define _SWAY_NODE_H -#include -#include -#include "list.h" - -#define MIN_SANE_W 100 -#define MIN_SANE_H 60 - -struct sway_root; -struct sway_output; -struct sway_workspace; -struct sway_container; -struct sway_transaction_instruction; -struct wlr_box; - -enum sway_node_type { - N_ROOT, - N_OUTPUT, - N_WORKSPACE, - N_CONTAINER, -}; - -struct sway_node { - enum sway_node_type type; - union { - struct sway_root *sway_root; - struct sway_output *sway_output; - struct sway_workspace *sway_workspace; - struct sway_container *sway_container; - }; - - /** - * A unique ID to identify this node. - * Primarily used in the get_tree JSON output. - */ - size_t id; - - struct sway_transaction_instruction *instruction; - size_t ntxnrefs; - bool destroying; - - // If true, indicates that the container has pending state that differs from - // the current. - bool dirty; - - struct { - struct wl_signal destroy; - } events; -}; - -void node_init(struct sway_node *node, enum sway_node_type type, void *thing); - -const char *node_type_to_str(enum sway_node_type type); - -/** - * Mark a node as dirty if it isn't already. Dirty nodes will be included in the - * next transaction then unmarked as dirty. - */ -void node_set_dirty(struct sway_node *node); - -bool node_is_view(struct sway_node *node); - -char *node_get_name(struct sway_node *node); - -void node_get_box(struct sway_node *node, struct wlr_box *box); - -struct sway_output *node_get_output(struct sway_node *node); - -enum sway_container_layout node_get_layout(struct sway_node *node); - -struct sway_node *node_get_parent(struct sway_node *node); - -list_t *node_get_children(struct sway_node *node); - -bool node_has_ancestor(struct sway_node *node, struct sway_node *ancestor); - -#endif diff --git a/include/sway/tree/root.h b/include/sway/tree/root.h deleted file mode 100644 index a2c088e76..000000000 --- a/include/sway/tree/root.h +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef _SWAY_ROOT_H -#define _SWAY_ROOT_H -#include -#include -#include -#include -#include "sway/tree/container.h" -#include "sway/tree/node.h" -#include "config.h" -#include "list.h" - -extern struct sway_root *root; - -struct sway_root { - struct sway_node node; - struct wlr_output_layout *output_layout; - - struct wl_listener output_layout_change; -#if HAVE_XWAYLAND - struct wl_list xwayland_unmanaged; // sway_xwayland_unmanaged::link -#endif - struct wl_list drag_icons; // sway_drag_icon::link - - // Includes disabled outputs - struct wl_list all_outputs; // sway_output::link - - double x, y; - double width, height; - - list_t *outputs; // struct sway_output - list_t *non_desktop_outputs; // struct sway_output_non_desktop - list_t *scratchpad; // struct sway_container - - // For when there's no connected outputs - struct sway_output *fallback_output; - - struct sway_container *fullscreen_global; - - struct { - struct wl_signal new_node; - } events; -}; - -struct sway_root *root_create(void); - -void root_destroy(struct sway_root *root); - -/** - * Move a container to the scratchpad. - * If a workspace is passed, the container is assumed to have been in - * the scratchpad before and is shown on the workspace. - * The ws parameter can safely be NULL. - */ -void root_scratchpad_add_container(struct sway_container *con, - struct sway_workspace *ws); - -/** - * Remove a container from the scratchpad. - */ -void root_scratchpad_remove_container(struct sway_container *con); - -/** - * Show a single scratchpad container. - */ -void root_scratchpad_show(struct sway_container *con); - -/** - * Hide a single scratchpad container. - */ -void root_scratchpad_hide(struct sway_container *con); - -void root_for_each_workspace(void (*f)(struct sway_workspace *ws, void *data), - void *data); - -void root_for_each_container(void (*f)(struct sway_container *con, void *data), - void *data); - -struct sway_output *root_find_output( - bool (*test)(struct sway_output *output, void *data), void *data); - -struct sway_workspace *root_find_workspace( - bool (*test)(struct sway_workspace *ws, void *data), void *data); - -struct sway_container *root_find_container( - bool (*test)(struct sway_container *con, void *data), void *data); - -void root_get_box(struct sway_root *root, struct wlr_box *box); - -#endif diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h deleted file mode 100644 index 76cfdf3a4..000000000 --- a/include/sway/tree/view.h +++ /dev/null @@ -1,392 +0,0 @@ -#ifndef _SWAY_VIEW_H -#define _SWAY_VIEW_H -#include -#include -#include "sway/config.h" -#if HAVE_XWAYLAND -#include -#endif -#include "sway/input/input-manager.h" -#include "sway/input/seat.h" - -struct sway_container; -struct sway_xdg_decoration; - -enum sway_view_type { - SWAY_VIEW_XDG_SHELL, -#if HAVE_XWAYLAND - SWAY_VIEW_XWAYLAND, -#endif -}; - -enum sway_view_prop { - VIEW_PROP_TITLE, - VIEW_PROP_APP_ID, - VIEW_PROP_CLASS, - VIEW_PROP_INSTANCE, - VIEW_PROP_WINDOW_TYPE, - VIEW_PROP_WINDOW_ROLE, -#if HAVE_XWAYLAND - VIEW_PROP_X11_WINDOW_ID, - VIEW_PROP_X11_PARENT_ID, -#endif -}; - -struct sway_view_impl { - void (*get_constraints)(struct sway_view *view, double *min_width, - double *max_width, double *min_height, double *max_height); - const char *(*get_string_prop)(struct sway_view *view, - enum sway_view_prop prop); - uint32_t (*get_int_prop)(struct sway_view *view, enum sway_view_prop prop); - uint32_t (*configure)(struct sway_view *view, double lx, double ly, - int width, int height); - void (*set_activated)(struct sway_view *view, bool activated); - void (*set_tiled)(struct sway_view *view, bool tiled); - void (*set_fullscreen)(struct sway_view *view, bool fullscreen); - void (*set_resizing)(struct sway_view *view, bool resizing); - bool (*wants_floating)(struct sway_view *view); - void (*for_each_surface)(struct sway_view *view, - wlr_surface_iterator_func_t iterator, void *user_data); - void (*for_each_popup_surface)(struct sway_view *view, - wlr_surface_iterator_func_t iterator, void *user_data); - bool (*is_transient_for)(struct sway_view *child, - struct sway_view *ancestor); - void (*close)(struct sway_view *view); - void (*close_popups)(struct sway_view *view); - void (*destroy)(struct sway_view *view); -}; - -struct sway_saved_buffer { - struct wlr_client_buffer *buffer; - int x, y; - int width, height; - enum wl_output_transform transform; - struct wlr_fbox source_box; - struct wl_list link; // sway_view::saved_buffers -}; - -struct sway_view { - enum sway_view_type type; - const struct sway_view_impl *impl; - - struct sway_container *container; // NULL if unmapped and transactions finished - struct wlr_surface *surface; // NULL for unmapped views - struct sway_xdg_decoration *xdg_decoration; - - pid_t pid; - struct launcher_ctx *ctx; - - // The size the view would want to be if it weren't tiled. - // Used when changing a view from tiled to floating. - int natural_width, natural_height; - - char *title_format; - - bool using_csd; - - struct timespec urgent; - bool allow_request_urgent; - struct wl_event_source *urgent_timer; - - struct wl_list saved_buffers; // sway_saved_buffer::link - - // The geometry for whatever the client is committing, regardless of - // transaction state. Updated on every commit. - struct wlr_box geometry; - - // The "old" geometry during a transaction. Used to damage the old location - // when a transaction is applied. - struct wlr_box saved_geometry; - - struct wlr_foreign_toplevel_handle_v1 *foreign_toplevel; - struct wl_listener foreign_activate_request; - struct wl_listener foreign_fullscreen_request; - struct wl_listener foreign_close_request; - struct wl_listener foreign_destroy; - struct wl_listener foreign_minimize; - - bool destroying; - - list_t *executed_criteria; // struct criteria * - - union { - struct wlr_xdg_toplevel *wlr_xdg_toplevel; -#if HAVE_XWAYLAND - struct wlr_xwayland_surface *wlr_xwayland_surface; -#endif - }; - - struct { - struct wl_signal unmap; - } events; - - struct wl_listener surface_new_subsurface; - - int max_render_time; // In milliseconds - - enum seat_config_shortcuts_inhibit shortcuts_inhibit; -}; - -struct sway_xdg_shell_view { - struct sway_view view; - - struct wl_listener commit; - struct wl_listener request_move; - struct wl_listener request_resize; - struct wl_listener request_maximize; - struct wl_listener request_minimize; - struct wl_listener request_fullscreen; - struct wl_listener set_title; - struct wl_listener set_app_id; - struct wl_listener new_popup; - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener destroy; -}; -#if HAVE_XWAYLAND -struct sway_xwayland_view { - struct sway_view view; - - struct wl_listener commit; - struct wl_listener request_move; - struct wl_listener request_resize; - struct wl_listener request_maximize; - struct wl_listener request_minimize; - struct wl_listener request_configure; - struct wl_listener request_fullscreen; - struct wl_listener request_activate; - struct wl_listener set_title; - struct wl_listener set_class; - struct wl_listener set_role; - struct wl_listener set_startup_id; - struct wl_listener set_window_type; - struct wl_listener set_hints; - struct wl_listener set_decorations; - struct wl_listener associate; - struct wl_listener dissociate; - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener destroy; - struct wl_listener override_redirect; -}; - -struct sway_xwayland_unmanaged { - struct wlr_xwayland_surface *wlr_xwayland_surface; - struct wl_list link; - - int lx, ly; - - struct wl_listener request_activate; - struct wl_listener request_configure; - struct wl_listener request_fullscreen; - struct wl_listener commit; - struct wl_listener set_geometry; - struct wl_listener associate; - struct wl_listener dissociate; - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener destroy; - struct wl_listener override_redirect; -}; -#endif -struct sway_view_child; - -struct sway_view_child_impl { - void (*get_view_coords)(struct sway_view_child *child, int *sx, int *sy); - void (*destroy)(struct sway_view_child *child); -}; - -/** - * A view child is a surface in the view tree, such as a subsurface or a popup. - */ -struct sway_view_child { - const struct sway_view_child_impl *impl; - struct wl_list link; - - struct sway_view *view; - struct sway_view_child *parent; - struct wl_list children; // sway_view_child::link - struct wlr_surface *surface; - bool mapped; - - struct wl_listener surface_commit; - struct wl_listener surface_new_subsurface; - struct wl_listener surface_map; - struct wl_listener surface_unmap; - struct wl_listener surface_destroy; - struct wl_listener view_unmap; -}; - -struct sway_subsurface { - struct sway_view_child child; - - struct wl_listener destroy; -}; - -struct sway_xdg_popup { - struct sway_view_child child; - - struct wlr_xdg_popup *wlr_xdg_popup; - - struct wl_listener new_popup; - struct wl_listener destroy; -}; - -const char *view_get_title(struct sway_view *view); - -const char *view_get_app_id(struct sway_view *view); - -const char *view_get_class(struct sway_view *view); - -const char *view_get_instance(struct sway_view *view); - -uint32_t view_get_x11_window_id(struct sway_view *view); - -uint32_t view_get_x11_parent_id(struct sway_view *view); - -const char *view_get_window_role(struct sway_view *view); - -uint32_t view_get_window_type(struct sway_view *view); - -const char *view_get_shell(struct sway_view *view); - -void view_get_constraints(struct sway_view *view, double *min_width, - double *max_width, double *min_height, double *max_height); - -uint32_t view_configure(struct sway_view *view, double lx, double ly, int width, - int height); - -bool view_inhibit_idle(struct sway_view *view); - -/** - * Whether or not this view's most distant ancestor (possibly itself) is the - * only visible node in its tree. If the view is tiling, there may be floating - * views. If the view is floating, there may be tiling views or views in a - * different floating container. - */ -bool view_ancestor_is_only_visible(struct sway_view *view); - -/** - * Configure the view's position and size based on the container's position and - * size, taking borders into consideration. - */ -void view_autoconfigure(struct sway_view *view); - -void view_set_activated(struct sway_view *view, bool activated); - -/** - * Called when the view requests to be focused. - */ -void view_request_activate(struct sway_view *view, struct sway_seat *seat); - -/* - * Called when the view requests urgent state - */ -void view_request_urgent(struct sway_view *view); - -/** - * If possible, instructs the client to change their decoration mode. - */ -void view_set_csd_from_server(struct sway_view *view, bool enabled); - -/** - * Updates the view's border setting when the client unexpectedly changes their - * decoration mode. - */ -void view_update_csd_from_client(struct sway_view *view, bool enabled); - -void view_set_tiled(struct sway_view *view, bool tiled); - -void view_close(struct sway_view *view); - -void view_close_popups(struct sway_view *view); - -void view_damage_from(struct sway_view *view); - -/** - * Iterate all surfaces of a view (toplevels + popups). - */ -void view_for_each_surface(struct sway_view *view, - wlr_surface_iterator_func_t iterator, void *user_data); - -/** - * Iterate all popup surfaces of a view. - */ -void view_for_each_popup_surface(struct sway_view *view, - wlr_surface_iterator_func_t iterator, void *user_data); - -// view implementation - -void view_init(struct sway_view *view, enum sway_view_type type, - const struct sway_view_impl *impl); - -void view_destroy(struct sway_view *view); - -void view_begin_destroy(struct sway_view *view); - -/** - * Map a view, ie. make it visible in the tree. - * - * `fullscreen` should be set to true (and optionally `fullscreen_output` - * should be populated) if the view should be made fullscreen immediately. - * - * `decoration` should be set to true if the client prefers CSD. The client's - * preference may be ignored. - */ -void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, - bool fullscreen, struct wlr_output *fullscreen_output, bool decoration); - -void view_unmap(struct sway_view *view); - -void view_update_size(struct sway_view *view); -void view_center_surface(struct sway_view *view); - -void view_child_init(struct sway_view_child *child, - const struct sway_view_child_impl *impl, struct sway_view *view, - struct wlr_surface *surface); - -void view_child_destroy(struct sway_view_child *child); - - -struct sway_view *view_from_wlr_xdg_surface( - struct wlr_xdg_surface *xdg_surface); -#if HAVE_XWAYLAND -struct sway_view *view_from_wlr_xwayland_surface( - struct wlr_xwayland_surface *xsurface); -#endif -struct sway_view *view_from_wlr_surface(struct wlr_surface *surface); - -/** - * Re-read the view's title property and update any relevant title bars. - * The force argument makes it recreate the title bars even if the title hasn't - * changed. - */ -void view_update_title(struct sway_view *view, bool force); - -/** - * Run any criteria that match the view and haven't been run on this view - * before. - */ -void view_execute_criteria(struct sway_view *view); - -/** - * Returns true if there's a possibility the view may be rendered on screen. - * Intended for damage tracking. - */ -bool view_is_visible(struct sway_view *view); - -void view_set_urgent(struct sway_view *view, bool enable); - -bool view_is_urgent(struct sway_view *view); - -void view_remove_saved_buffer(struct sway_view *view); - -void view_save_buffer(struct sway_view *view); - -bool view_is_transient_for(struct sway_view *child, struct sway_view *ancestor); - -void view_assign_ctx(struct sway_view *view, struct launcher_ctx *ctx); - -bool gaps_to_edge(struct sway_view *view); - -#endif diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h deleted file mode 100644 index 1e7d9b823..000000000 --- a/include/sway/tree/workspace.h +++ /dev/null @@ -1,156 +0,0 @@ -#ifndef _SWAY_WORKSPACE_H -#define _SWAY_WORKSPACE_H - -#include -#include "sway/config.h" -#include "sway/tree/container.h" -#include "sway/tree/node.h" - -struct sway_view; - -struct sway_workspace_state { - struct sway_container *fullscreen; - double x, y; - int width, height; - enum sway_container_layout layout; - struct sway_output *output; - list_t *floating; - list_t *tiling; - - struct sway_container *focused_inactive_child; - bool focused; -}; - -struct sway_workspace { - struct sway_node node; - struct sway_container *fullscreen; - - char *name; - char *representation; - - double x, y; - int width, height; - enum sway_container_layout layout; - enum sway_container_layout prev_split_layout; - - struct side_gaps current_gaps; - int gaps_inner; - struct side_gaps gaps_outer; - - struct sway_output *output; // NULL if no outputs are connected - list_t *floating; // struct sway_container - list_t *tiling; // struct sway_container - list_t *output_priority; - bool urgent; - - struct sway_workspace_state current; -}; - -struct workspace_config *workspace_find_config(const char *ws_name); - -struct sway_output *workspace_get_initial_output(const char *name); - -struct sway_workspace *workspace_create(struct sway_output *output, - const char *name); - -void workspace_destroy(struct sway_workspace *workspace); - -void workspace_begin_destroy(struct sway_workspace *workspace); - -void workspace_consider_destroy(struct sway_workspace *ws); - -char *workspace_next_name(const char *output_name); - -struct sway_workspace *workspace_auto_back_and_forth( - struct sway_workspace *workspace); - -bool workspace_switch(struct sway_workspace *workspace); - -struct sway_workspace *workspace_by_number(const char* name); - -struct sway_workspace *workspace_by_name(const char*); - -struct sway_workspace *workspace_output_next(struct sway_workspace *current); - -struct sway_workspace *workspace_next(struct sway_workspace *current); - -struct sway_workspace *workspace_output_prev(struct sway_workspace *current); - -struct sway_workspace *workspace_prev(struct sway_workspace *current); - -bool workspace_is_visible(struct sway_workspace *ws); - -bool workspace_is_empty(struct sway_workspace *ws); - -void workspace_output_raise_priority(struct sway_workspace *workspace, - struct sway_output *old_output, struct sway_output *new_output); - -void workspace_output_add_priority(struct sway_workspace *workspace, - struct sway_output *output); - -struct sway_output *workspace_output_get_highest_available( - struct sway_workspace *ws, struct sway_output *exclude); - -void workspace_detect_urgent(struct sway_workspace *workspace); - -bool workspace_get_blur_info(struct sway_workspace *ws, - pixman_region32_t *blur_region); - -void workspace_for_each_container(struct sway_workspace *ws, - void (*f)(struct sway_container *con, void *data), void *data); - -struct sway_container *workspace_find_container(struct sway_workspace *ws, - bool (*test)(struct sway_container *con, void *data), void *data); - -/** - * Wrap the workspace's tiling children in a new container. - * The new container will be the only direct tiling child of the workspace. - * The new container is returned. - */ -struct sway_container *workspace_wrap_children(struct sway_workspace *ws); - -void workspace_unwrap_children(struct sway_workspace *ws, - struct sway_container *wrap); - -void workspace_detach(struct sway_workspace *workspace); - -struct sway_container *workspace_add_tiling(struct sway_workspace *workspace, - struct sway_container *con); - -void workspace_add_floating(struct sway_workspace *workspace, - struct sway_container *con); - -/** - * Adds a tiling container to the workspace without considering - * the workspace_layout, so the con will not be split. - */ -void workspace_insert_tiling_direct(struct sway_workspace *workspace, - struct sway_container *con, int index); - -struct sway_container *workspace_insert_tiling(struct sway_workspace *workspace, - struct sway_container *con, int index); - -void workspace_remove_gaps(struct sway_workspace *ws); - -void workspace_add_gaps(struct sway_workspace *ws); - -struct sway_container *workspace_split(struct sway_workspace *workspace, - enum sway_container_layout layout); - -void workspace_update_representation(struct sway_workspace *ws); - -void workspace_get_box(struct sway_workspace *workspace, struct wlr_box *box); - -size_t workspace_num_tiling_views(struct sway_workspace *ws); - -size_t workspace_num_sticky_containers(struct sway_workspace *ws); - -/** - * workspace_squash is container_flatten in the reverse - * direction. Instead of eliminating redundant splits that are - * parents of the target container, it eliminates pairs of - * redundant H/V splits that are children of the workspace. - */ -void workspace_squash(struct sway_workspace *workspace); - -#endif diff --git a/include/sway/xdg_decoration.h b/include/sway/xdg_decoration.h deleted file mode 100644 index 8bef4c6d4..000000000 --- a/include/sway/xdg_decoration.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _SWAY_XDG_DECORATION_H -#define _SWAY_XDG_DECORATION_H - -#include - -struct sway_xdg_decoration { - struct wlr_xdg_toplevel_decoration_v1 *wlr_xdg_decoration; - struct wl_list link; - - struct sway_view *view; - - struct wl_listener destroy; - struct wl_listener request_mode; -}; - -struct sway_xdg_decoration *xdg_decoration_from_surface( - struct wlr_surface *surface); - -#endif diff --git a/include/sway/xwayland.h b/include/sway/xwayland.h deleted file mode 100644 index 93055c46c..000000000 --- a/include/sway/xwayland.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef SWAY_XWAYLAND_H -#define SWAY_XWAYLAND_H - -#include -#include - -enum atom_name { - NET_WM_WINDOW_TYPE_NORMAL, - NET_WM_WINDOW_TYPE_DIALOG, - NET_WM_WINDOW_TYPE_UTILITY, - NET_WM_WINDOW_TYPE_TOOLBAR, - NET_WM_WINDOW_TYPE_SPLASH, - NET_WM_WINDOW_TYPE_MENU, - NET_WM_WINDOW_TYPE_DROPDOWN_MENU, - NET_WM_WINDOW_TYPE_POPUP_MENU, - NET_WM_WINDOW_TYPE_TOOLTIP, - NET_WM_WINDOW_TYPE_NOTIFICATION, - NET_WM_STATE_MODAL, - ATOM_LAST, -}; - -struct sway_xwayland { - struct wlr_xwayland *wlr_xwayland; - struct wlr_xcursor_manager *xcursor_manager; - - xcb_atom_t atoms[ATOM_LAST]; -}; - -void handle_xwayland_ready(struct wl_listener *listener, void *data); - -#endif diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h deleted file mode 100644 index 197d21901..000000000 --- a/include/swaybar/bar.h +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef _SWAYBAR_BAR_H -#define _SWAYBAR_BAR_H -#include -#include "config.h" -#include "input.h" -#include "pool-buffer.h" -#include "cursor-shape-v1-client-protocol.h" -#include "wlr-layer-shell-unstable-v1-client-protocol.h" -#include "xdg-output-unstable-v1-client-protocol.h" - -struct swaybar_config; -struct swaybar_output; -#if HAVE_TRAY -struct swaybar_tray; -#endif -struct swaybar_workspace; -struct loop; - -struct swaybar { - char *id; - char *mode; - bool mode_pango_markup; - - // only relevant when bar is in "hide" mode - bool visible_by_modifier; - bool visible_by_urgency; - bool visible_by_mode; - bool visible; - - struct wl_display *display; - struct wl_compositor *compositor; - struct zwlr_layer_shell_v1 *layer_shell; - struct zxdg_output_manager_v1 *xdg_output_manager; - struct wp_cursor_shape_manager_v1 *cursor_shape_manager; - struct wl_shm *shm; - - struct swaybar_config *config; - struct status_line *status; - - struct loop *eventloop; - - int ipc_event_socketfd; - int ipc_socketfd; - - struct wl_list outputs; // swaybar_output::link - struct wl_list unused_outputs; // swaybar_output::link - struct wl_list seats; // swaybar_seat::link - -#if HAVE_TRAY - struct swaybar_tray *tray; -#endif - - bool running; -}; - -struct swaybar_output { - struct wl_list link; // swaybar::outputs - struct swaybar *bar; - struct wl_output *output; - struct zxdg_output_v1 *xdg_output; - struct wl_surface *surface; - struct zwlr_layer_surface_v1 *layer_surface; - uint32_t wl_name; - - struct wl_list workspaces; // swaybar_workspace::link - struct wl_list hotspots; // swaybar_hotspot::link - - char *name; - char *identifier; - bool focused; - - uint32_t width, height; - int32_t scale; - enum wl_output_subpixel subpixel; - struct pool_buffer buffers[2]; - struct pool_buffer *current_buffer; - bool dirty; - bool frame_scheduled; - - uint32_t output_height, output_width, output_x, output_y; -}; - -struct swaybar_workspace { - struct wl_list link; // swaybar_output::workspaces - int num; - char *name; - char *label; - bool focused; - bool visible; - bool urgent; -}; - -bool bar_setup(struct swaybar *bar, const char *socket_path); -void bar_run(struct swaybar *bar); -void bar_teardown(struct swaybar *bar); - -void set_bar_dirty(struct swaybar *bar); - -/* - * Determines whether the bar should be visible and changes it to be so. - * If the current visibility of the bar is the different to what it should be, - * then it adds or destroys the layer surface as required, - * as well as sending the cont or stop signal to the status command. - * If the current visibility of the bar is already what it should be, - * then this function is a no-op, unless moving_layer is true, which occurs - * when the bar changes from "hide" to "dock" mode or vice versa, and the bar - * needs to be destroyed and re-added in order to change its layer. - * - * Returns true if the bar is now visible, otherwise false. - */ -bool determine_bar_visibility(struct swaybar *bar, bool moving_layer); -void free_workspaces(struct wl_list *list); - -void status_in(int fd, short mask, void *data); - -void destroy_layer_surface(struct swaybar_output *output); - -#endif diff --git a/include/swaybar/config.h b/include/swaybar/config.h deleted file mode 100644 index 361acd991..000000000 --- a/include/swaybar/config.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef _SWAYBAR_CONFIG_H -#define _SWAYBAR_CONFIG_H -#include -#include -#include -#include "../include/config.h" -#include "list.h" -#include "util.h" -#include - -struct box_colors { - uint32_t border; - uint32_t background; - uint32_t text; -}; - -struct config_output { - struct wl_list link; // swaybar_config::outputs - char *name; -}; - -struct swaybar_binding { - uint32_t button; - char *command; - bool release; -}; - -struct swaybar_config { - char *status_command; - bool pango_markup; - uint32_t position; // zwlr_layer_surface_v1_anchor - PangoFontDescription *font_description; - char *sep_symbol; - char *mode; - char *hidden_state; - char *modifier; - bool strip_workspace_numbers; - bool strip_workspace_name; - bool binding_mode_indicator; - bool wrap_scroll; - bool workspace_buttons; - uint32_t workspace_min_width; - list_t *bindings; - struct wl_list outputs; // config_output::link - int height; - int status_padding; - int status_edge_padding; - struct { - int top; - int right; - int bottom; - int left; - } gaps; - - struct { - uint32_t background; - uint32_t statusline; - uint32_t separator; - - uint32_t focused_background; - uint32_t focused_statusline; - uint32_t focused_separator; - - struct box_colors focused_workspace; - struct box_colors active_workspace; - struct box_colors inactive_workspace; - struct box_colors urgent_workspace; - struct box_colors binding_mode; - } colors; - -#if HAVE_TRAY - char *icon_theme; - struct wl_list tray_bindings; // struct tray_binding::link - bool tray_hidden; - list_t *tray_outputs; // char * - int tray_padding; -#endif -}; - -#if HAVE_TRAY -struct tray_binding { - uint32_t button; - char *command; - struct wl_list link; // struct tray_binding::link -}; - -void free_tray_binding(struct tray_binding *binding); -#endif - -struct swaybar_config *init_config(void); -void free_config(struct swaybar_config *config); -uint32_t parse_position(const char *position); -void free_binding(struct swaybar_binding *binding); - -#endif diff --git a/include/swaybar/i3bar.h b/include/swaybar/i3bar.h deleted file mode 100644 index dced2a6cd..000000000 --- a/include/swaybar/i3bar.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _SWAYBAR_I3BAR_H -#define _SWAYBAR_I3BAR_H - -#include "input.h" -#include "status_line.h" - -struct i3bar_block { - struct wl_list link; // status_link::blocks - int ref_count; - char *full_text, *short_text, *align, *min_width_str; - bool urgent; - uint32_t color; - bool color_set; - int min_width; - char *name, *instance; - bool separator; - int separator_block_width; - bool markup; - // Airblader features - uint32_t background; - uint32_t border; - bool border_set; - int border_top; - int border_bottom; - int border_left; - int border_right; -}; - -void i3bar_block_unref(struct i3bar_block *block); -bool i3bar_handle_readable(struct status_line *status); -enum hotspot_event_handling i3bar_block_send_click(struct status_line *status, - struct i3bar_block *block, double x, double y, double rx, double ry, - double w, double h, int scale, uint32_t button, bool released); - -#endif diff --git a/include/swaybar/input.h b/include/swaybar/input.h deleted file mode 100644 index 8ea88a69a..000000000 --- a/include/swaybar/input.h +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef _SWAYBAR_INPUT_H -#define _SWAYBAR_INPUT_H - -#include -#include -#include "list.h" - -#define SWAY_SCROLL_UP KEY_MAX + 1 -#define SWAY_SCROLL_DOWN KEY_MAX + 2 -#define SWAY_SCROLL_LEFT KEY_MAX + 3 -#define SWAY_SCROLL_RIGHT KEY_MAX + 4 - -#define SWAY_CONTINUOUS_SCROLL_TIMEOUT 1000 -#define SWAY_CONTINUOUS_SCROLL_THRESHOLD 10000 - -struct swaybar; -struct swaybar_output; - -struct swaybar_pointer { - struct wl_pointer *pointer; - struct wl_cursor_theme *cursor_theme; - struct wl_cursor_image *cursor_image; - struct wl_surface *cursor_surface; - struct swaybar_output *current; - double x, y; - uint32_t serial; -}; - -struct touch_slot { - int32_t id; - uint32_t time; - struct swaybar_output *output; - double start_x, start_y; - double x, y; -}; - -struct swaybar_touch { - struct wl_touch *touch; - struct touch_slot slots[16]; -}; - -enum hotspot_event_handling { - HOTSPOT_IGNORE, - HOTSPOT_PROCESS, -}; - -struct swaybar_hotspot { - struct wl_list link; // swaybar_output::hotspots - int x, y, width, height; - enum hotspot_event_handling (*callback)(struct swaybar_output *output, - struct swaybar_hotspot *hotspot, double x, double y, uint32_t button, - bool released, void *data); - void (*destroy)(void *data); - void *data; -}; - -struct swaybar_scroll_axis { - wl_fixed_t value; - uint32_t discrete_steps; - uint32_t update_time; -}; - -struct swaybar_seat { - struct swaybar *bar; - uint32_t wl_name; - struct wl_seat *wl_seat; - struct swaybar_pointer pointer; - struct swaybar_touch touch; - struct wl_list link; // swaybar_seat:link - struct swaybar_scroll_axis axis[2]; -}; - -extern const struct wl_seat_listener seat_listener; - -void update_cursor(struct swaybar_seat *seat); - -uint32_t event_to_x11_button(uint32_t event); - -void free_hotspots(struct wl_list *list); - -void swaybar_seat_free(struct swaybar_seat *seat); - -#endif diff --git a/include/swaybar/ipc.h b/include/swaybar/ipc.h deleted file mode 100644 index d8cd0c761..000000000 --- a/include/swaybar/ipc.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _SWAYBAR_IPC_H -#define _SWAYBAR_IPC_H -#include -#include "swaybar/bar.h" - -bool ipc_initialize(struct swaybar *bar); -bool handle_ipc_readable(struct swaybar *bar); -bool ipc_get_workspaces(struct swaybar *bar); -void ipc_send_workspace_command(struct swaybar *bar, const char *ws); -void ipc_execute_binding(struct swaybar *bar, struct swaybar_binding *bind); - -#endif diff --git a/include/swaybar/render.h b/include/swaybar/render.h deleted file mode 100644 index ebdc69e44..000000000 --- a/include/swaybar/render.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _SWAYBAR_RENDER_H -#define _SWAYBAR_RENDER_H - -struct swaybar_output; - -void render_frame(struct swaybar_output *output); - -#endif diff --git a/include/swaybar/status_line.h b/include/swaybar/status_line.h deleted file mode 100644 index 65c3a7969..000000000 --- a/include/swaybar/status_line.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef _SWAYBAR_STATUS_LINE_H -#define _SWAYBAR_STATUS_LINE_H -#include -#include -#include -#include -#include "bar.h" - -enum status_protocol { - PROTOCOL_UNDEF, - PROTOCOL_ERROR, - PROTOCOL_TEXT, - PROTOCOL_I3BAR, -}; - -struct status_line { - struct swaybar *bar; - - pid_t pid; - int read_fd, write_fd; - FILE *read, *write; - - enum status_protocol protocol; - const char *text; - struct wl_list blocks; // i3bar_block::link - - int stop_signal; - int cont_signal; - - bool click_events; - bool float_event_coords; - bool clicked; - char *buffer; - size_t buffer_size; - size_t buffer_index; - bool started; - bool expecting_comma; - json_tokener *tokener; -}; - -struct status_line *status_line_init(char *cmd); -void status_error(struct status_line *status, const char *text); -bool status_handle_readable(struct status_line *status); -void status_line_free(struct status_line *status); - -#endif diff --git a/include/swaybar/tray/host.h b/include/swaybar/tray/host.h deleted file mode 100644 index 2d4cf82b1..000000000 --- a/include/swaybar/tray/host.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef _SWAYBAR_TRAY_HOST_H -#define _SWAYBAR_TRAY_HOST_H - -#include - -struct swaybar_tray; - -struct swaybar_host { - struct swaybar_tray *tray; - char *service; - char *watcher_interface; -}; - -bool init_host(struct swaybar_host *host, char *protocol, struct swaybar_tray *tray); -void finish_host(struct swaybar_host *host); - -#endif diff --git a/include/swaybar/tray/icon.h b/include/swaybar/tray/icon.h deleted file mode 100644 index 3673674b9..000000000 --- a/include/swaybar/tray/icon.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef _SWAYBAR_TRAY_ICON_H -#define _SWAYBAR_TRAY_ICON_H - -#include "list.h" - -struct icon_theme_subdir { - char *name; - int size; - - enum { - THRESHOLD, - SCALABLE, - FIXED - } type; - - int max_size; - int min_size; - int threshold; -}; - -struct icon_theme { - char *name; - char *comment; - list_t *inherits; // char * - list_t *directories; // char * - - char *dir; - list_t *subdirs; // struct icon_theme_subdir * -}; - -void init_themes(list_t **themes, list_t **basedirs); -void finish_themes(list_t *themes, list_t *basedirs); - -/* - * Finds an icon of a specified size given a list of themes and base directories. - * If the icon is found, the pointers min_size & max_size are set to minimum & - * maximum size that the icon can be scaled to, respectively. - * Returns: path of icon (which should be freed), or NULL if the icon is not found. - */ -char *find_icon(list_t *themes, list_t *basedirs, char *name, int size, - char *theme, int *min_size, int *max_size); - -#endif diff --git a/include/swaybar/tray/item.h b/include/swaybar/tray/item.h deleted file mode 100644 index 73937a0cc..000000000 --- a/include/swaybar/tray/item.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef _SWAYBAR_TRAY_ITEM_H -#define _SWAYBAR_TRAY_ITEM_H - -#include -#include -#include -#include -#include "swaybar/tray/tray.h" -#include "list.h" - -struct swaybar_output; - -struct swaybar_pixmap { - int size; - unsigned char pixels[]; -}; - -struct swaybar_sni_slot { - struct wl_list link; // swaybar_sni::slots - struct swaybar_sni *sni; - const char *prop; - const char *type; - void *dest; - sd_bus_slot *slot; -}; - -struct swaybar_sni { - // icon properties - struct swaybar_tray *tray; - cairo_surface_t *icon; - int min_size; - int max_size; - int target_size; - - // dbus properties - char *watcher_id; - char *service; - char *path; - char *interface; - - char *status; - char *icon_name; - list_t *icon_pixmap; // struct swaybar_pixmap * - char *attention_icon_name; - list_t *attention_icon_pixmap; // struct swaybar_pixmap * - bool item_is_menu; - char *menu; - char *icon_theme_path; // non-standard KDE property - - struct wl_list slots; // swaybar_sni_slot::link -}; - -struct swaybar_sni *create_sni(char *id, struct swaybar_tray *tray); -void destroy_sni(struct swaybar_sni *sni); -uint32_t render_sni(cairo_t *cairo, struct swaybar_output *output, double *x, - struct swaybar_sni *sni); - -#endif diff --git a/include/swaybar/tray/tray.h b/include/swaybar/tray/tray.h deleted file mode 100644 index d2e80a6d4..000000000 --- a/include/swaybar/tray/tray.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef _SWAYBAR_TRAY_TRAY_H -#define _SWAYBAR_TRAY_TRAY_H - -#include "config.h" -#if HAVE_LIBSYSTEMD -#include -#elif HAVE_LIBELOGIND -#include -#elif HAVE_BASU -#include -#endif -#include -#include -#include "swaybar/tray/host.h" -#include "list.h" - -struct swaybar; -struct swaybar_output; -struct swaybar_watcher; - -struct swaybar_tray { - struct swaybar *bar; - - int fd; - sd_bus *bus; - - struct swaybar_host host_xdg; - struct swaybar_host host_kde; - list_t *items; // struct swaybar_sni * - struct swaybar_watcher *watcher_xdg; - struct swaybar_watcher *watcher_kde; - - list_t *basedirs; // char * - list_t *themes; // struct swaybar_theme * -}; - -struct swaybar_tray *create_tray(struct swaybar *bar); -void destroy_tray(struct swaybar_tray *tray); -void tray_in(int fd, short mask, void *data); -uint32_t render_tray(cairo_t *cairo, struct swaybar_output *output, double *x); - -#endif diff --git a/include/swaybar/tray/watcher.h b/include/swaybar/tray/watcher.h deleted file mode 100644 index 8f276da8e..000000000 --- a/include/swaybar/tray/watcher.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _SWAYBAR_TRAY_WATCHER_H -#define _SWAYBAR_TRAY_WATCHER_H - -#include "swaybar/tray/tray.h" -#include "list.h" - -struct swaybar_watcher { - char *interface; - sd_bus *bus; - list_t *hosts; - list_t *items; - int version; -}; - -struct swaybar_watcher *create_watcher(char *protocol, sd_bus *bus); -void destroy_watcher(struct swaybar_watcher *watcher); - -#endif diff --git a/include/swaynag/config.h b/include/swaynag/config.h deleted file mode 100644 index 0d8889de0..000000000 --- a/include/swaynag/config.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _SWAYNAG_CONFIG_H -#define _SWAYNAG_CONFIG_H -#include "swaynag/swaynag.h" -#include "list.h" - -int swaynag_parse_options(int argc, char **argv, struct swaynag *swaynag, - list_t *types, struct swaynag_type *type, char **config, bool *debug); - -char *swaynag_get_config_path(void); - -int swaynag_load_config(char *path, struct swaynag *swaynag, list_t *types); - -#endif diff --git a/include/swaynag/render.h b/include/swaynag/render.h deleted file mode 100644 index d09e59297..000000000 --- a/include/swaynag/render.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _SWAYNAG_RENDER_H -#define _SWAYNAG_RENDER_H -#include "swaynag/swaynag.h" - -void render_frame(struct swaynag *swaynag); - -#endif diff --git a/include/swaynag/swaynag.h b/include/swaynag/swaynag.h deleted file mode 100644 index fb9e9c218..000000000 --- a/include/swaynag/swaynag.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef _SWAYNAG_SWAYNAG_H -#define _SWAYNAG_SWAYNAG_H -#include -#include -#include "list.h" -#include "pool-buffer.h" -#include "cursor-shape-v1-client-protocol.h" - -#include "swaynag/types.h" - -#define SWAYNAG_MAX_HEIGHT 500 - -struct swaynag; - -enum swaynag_action_type { - SWAYNAG_ACTION_DISMISS, - SWAYNAG_ACTION_EXPAND, - SWAYNAG_ACTION_COMMAND, -}; - -struct swaynag_pointer { - struct wl_pointer *pointer; - uint32_t serial; - struct wl_cursor_theme *cursor_theme; - struct wl_cursor_image *cursor_image; - struct wl_surface *cursor_surface; - int x; - int y; -}; - -struct swaynag_seat { - struct wl_seat *wl_seat; - uint32_t wl_name; - struct swaynag *swaynag; - struct swaynag_pointer pointer; - struct wl_list link; -}; - -struct swaynag_output { - char *name; - struct wl_output *wl_output; - uint32_t wl_name; - uint32_t scale; - struct swaynag *swaynag; - struct wl_list link; -}; - -struct swaynag_button { - char *text; - enum swaynag_action_type type; - char *action; - int x; - int y; - int width; - int height; - bool terminal; - bool dismiss; -}; - -struct swaynag_details { - bool visible; - char *message; - char *details_text; - - int x; - int y; - int width; - int height; - - int offset; - int visible_lines; - int total_lines; - struct swaynag_button *button_details; - struct swaynag_button button_up; - struct swaynag_button button_down; -}; - -struct swaynag { - bool run_display; - - struct wl_display *display; - struct wl_compositor *compositor; - struct wl_seat *seat; - struct wl_shm *shm; - struct wl_list outputs; // swaynag_output::link - struct wl_list seats; // swaynag_seat::link - struct swaynag_output *output; - struct zwlr_layer_shell_v1 *layer_shell; - struct zwlr_layer_surface_v1 *layer_surface; - struct wp_cursor_shape_manager_v1 *cursor_shape_manager; - struct wl_surface *surface; - - uint32_t width; - uint32_t height; - int32_t scale; - struct pool_buffer buffers[2]; - struct pool_buffer *current_buffer; - - struct swaynag_type *type; - char *message; - list_t *buttons; - struct swaynag_details details; -}; - -void swaynag_setup(struct swaynag *swaynag); - -void swaynag_run(struct swaynag *swaynag); - -void swaynag_destroy(struct swaynag *swaynag); - -#endif diff --git a/include/swaynag/types.h b/include/swaynag/types.h deleted file mode 100644 index 9c3c50db4..000000000 --- a/include/swaynag/types.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef _SWAYNAG_TYPES_H -#define _SWAYNAG_TYPES_H - -#include -#include -#include "list.h" - -struct swaynag_type { - char *name; - - PangoFontDescription *font_description; - char *output; - uint32_t anchors; - int32_t layer; // enum zwlr_layer_shell_v1_layer or -1 if unset - - // Colors - uint32_t button_text; - uint32_t button_background; - uint32_t details_background; - uint32_t background; - uint32_t text; - uint32_t border; - uint32_t border_bottom; - - // Sizing - ssize_t bar_border_thickness; - ssize_t message_padding; - ssize_t details_border_thickness; - ssize_t button_border_thickness; - ssize_t button_gap; - ssize_t button_gap_close; - ssize_t button_margin_right; - ssize_t button_padding; -}; - -struct swaynag_type *swaynag_type_new(const char *name); - -void swaynag_types_add_default(list_t *types); - -struct swaynag_type *swaynag_type_get(list_t *types, char *name); - -struct swaynag_type *swaynag_type_clone(struct swaynag_type *type); - -void swaynag_type_merge(struct swaynag_type *dest, struct swaynag_type *src); - -void swaynag_type_free(struct swaynag_type *type); - -void swaynag_types_free(list_t *types); - -#endif diff --git a/include/util.h b/include/util.h deleted file mode 100644 index f887d4895..000000000 --- a/include/util.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef _SWAY_UTIL_H -#define _SWAY_UTIL_H - -#include -#include -#include - -enum movement_unit { - MOVEMENT_UNIT_PX, - MOVEMENT_UNIT_PPT, - MOVEMENT_UNIT_DEFAULT, - MOVEMENT_UNIT_INVALID, -}; - -struct movement_amount { - int amount; - enum movement_unit unit; -}; - -/* - * Parse units such as "px" or "ppt" - */ -enum movement_unit parse_movement_unit(const char *unit); - -/* - * Parse arguments such as "10", "10px" or "10 px". - * Returns the number of arguments consumed. - */ -int parse_movement_amount(int argc, char **argv, - struct movement_amount *amount); - -/** - * Wrap i into the range [0, max] - */ -int wrap(int i, int max); - -/** - * Given a string that represents an RGB(A) color, result will be set to a - * uint32_t version of the color, as long as it is valid. If it is invalid, - * then false will be returned and result will be untouched. - */ -bool parse_color(const char *color, uint32_t *result); - -void color_to_rgba(float dest[static 4], uint32_t color); - -/** - * Given a string that represents a boolean, return the boolean value. This - * function also takes in the current boolean value to support toggling. If - * toggling is not desired, pass in true for current so that toggling values - * get parsed as not true. - */ -bool parse_boolean(const char *boolean, bool current); - -/** - * Given a string that represents a floating point value, return a float. - * Returns NAN on error. - */ -float parse_float(const char *value); - -const char *sway_wl_output_subpixel_to_string(enum wl_output_subpixel subpixel); - -bool sway_set_cloexec(int fd, bool cloexec); - -#endif diff --git a/meson.build b/meson.build deleted file mode 100644 index d5086804f..000000000 --- a/meson.build +++ /dev/null @@ -1,288 +0,0 @@ -project( - 'sway', - 'c', - version: '0.4', - license: 'MIT', - meson_version: '>=0.60.0', - default_options: [ - 'c_std=c11', - 'warning_level=2', - 'werror=true', - ], -) - -add_project_arguments( - [ - '-DWLR_USE_UNSTABLE', - - '-Wno-unused-parameter', - '-Wno-unused-result', - '-Wno-missing-braces', - '-Wno-format-zero-length', - '-Wundef', - '-Wvla', - ], - language: 'c', -) - -cc = meson.get_compiler('c') - -is_freebsd = host_machine.system().startswith('freebsd') -datadir = get_option('datadir') -sysconfdir = get_option('sysconfdir') -prefix = get_option('prefix') - -if is_freebsd - add_project_arguments('-D_C11_SOURCE', language: 'c') -endif - -# Execute the scenefx subproject, if any -subproject( - 'scenefx', - required: false, -) -scenefx = dependency('scenefx') - -# Execute the wlroots subproject, if any -wlroots_version = ['>=0.17.0', '<0.18.0'] -subproject( - 'wlroots', - default_options: ['examples=false'], - required: false, - version: wlroots_version, -) -wlroots = dependency('wlroots', version: wlroots_version) -wlroots_features = { - 'xwayland': false, - 'libinput_backend': false, - 'session': false, -} -foreach name, _ : wlroots_features - var_name = 'have_' + name.underscorify() - have = wlroots.get_variable(pkgconfig: var_name, internal: var_name) == 'true' - wlroots_features += { name: have } -endforeach - -if get_option('xwayland').enabled() and not wlroots_features['xwayland'] - error('Cannot enable Xwayland in sway: wlroots has been built without Xwayland support') -endif - -null_dep = dependency('', required: false) - -jsonc = dependency('json-c', version: '>=0.13') -pcre2 = dependency('libpcre2-8') -wayland_server = dependency('wayland-server', version: '>=1.21.0') -wayland_client = dependency('wayland-client') -wayland_cursor = dependency('wayland-cursor') -wayland_egl = dependency('wayland-egl') -egl = dependency('egl') -wayland_protos = dependency('wayland-protocols', version: '>=1.24') -xkbcommon = dependency('xkbcommon', version: '>=1.5.0') -cairo = dependency('cairo') -pango = dependency('pango') -pangocairo = dependency('pangocairo') -gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: get_option('gdk-pixbuf')) -pixman = dependency('pixman-1') -libevdev = dependency('libevdev') -libinput = wlroots_features['libinput_backend'] ? dependency('libinput', version: '>=1.21.0') : null_dep -xcb = dependency('xcb', required: get_option('xwayland')) -drm_full = dependency('libdrm') # only needed for drm_fourcc.h -drm = drm_full.partial_dependency(compile_args: true, includes: true) -libudev = wlroots_features['libinput_backend'] ? dependency('libudev') : null_dep -math = cc.find_library('m') -rt = cc.find_library('rt') -xcb_icccm = dependency('xcb-icccm', required: get_option('xwayland')) -threads = dependency('threads') # for pthread_setschedparam - -have_xwayland = xcb.found() and xcb_icccm.found() and wlroots_features['xwayland'] - -if get_option('sd-bus-provider') == 'auto' - if not get_option('tray').disabled() - assert(get_option('auto_features').auto(), 'sd-bus-provider must not be set to auto since auto_features != auto') - endif - sdbus = dependency(['libsystemd', 'libelogind'], - required: false, - version: '>=239', - ) - if not sdbus.found() - sdbus = dependency('basu', required: false) - endif -else - sdbus = dependency(get_option('sd-bus-provider'), required: get_option('tray')) -endif - -tray_deps_found = sdbus.found() -if get_option('tray').enabled() and not tray_deps_found - error('Building with -Dtray=enabled, but sd-bus has not been not found') -endif -have_tray = (not get_option('tray').disabled()) and tray_deps_found - -conf_data = configuration_data() - -conf_data.set10('HAVE_XWAYLAND', have_xwayland) -conf_data.set10('HAVE_GDK_PIXBUF', gdk_pixbuf.found()) -conf_data.set10('HAVE_LIBSYSTEMD', sdbus.found() and sdbus.name() == 'libsystemd') -conf_data.set10('HAVE_LIBELOGIND', sdbus.found() and sdbus.name() == 'libelogind') -conf_data.set10('HAVE_BASU', sdbus.found() and sdbus.name() == 'basu') -conf_data.set10('HAVE_TRAY', have_tray) -conf_data.set10('HAVE_LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM', cc.has_header_symbol( - 'libinput.h', - 'LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM', - dependencies: libinput, -)) - -scdoc = dependency('scdoc', version: '>=1.9.2', native: true, required: get_option('man-pages')) -if scdoc.found() - scdoc_prog = find_program(scdoc.get_variable(pkgconfig: 'scdoc'), native: true) - mandir = get_option('mandir') - man_files = [ - 'sway/sway.1.scd', - 'sway/sway.5.scd', - 'sway/sway-bar.5.scd', - 'sway/sway-input.5.scd', - 'sway/sway-ipc.7.scd', - 'sway/sway-output.5.scd', - 'swaybar/swaybar-protocol.7.scd', - 'swaymsg/swaymsg.1.scd', - ] - - if get_option('swaynag') - man_files += [ - 'swaynag/swaynag.1.scd', - 'swaynag/swaynag.5.scd', - ] - endif - - foreach filename : man_files - topic = filename.split('.')[-3].split('/')[-1] - section = filename.split('.')[-2] - output = '@0@.@1@'.format(topic, section) - - custom_target( - output, - input: filename, - output: output, - command: scdoc_prog, - install: true, - feed: true, - capture: true, - install_dir: '@0@/man@1@'.format(mandir, section) - ) - endforeach -endif - -add_project_arguments('-DSYSCONFDIR="/@0@"'.format(join_paths(prefix, sysconfdir)), language : 'c') - -version = '"@0@"'.format(meson.project_version()) -git = find_program('git', native: true, required: false) -if git.found() - git_commit = run_command([git, 'rev-parse', '--short', 'HEAD'], check: false) - git_branch = run_command([git, 'rev-parse', '--abbrev-ref', 'HEAD'], check: false) - if git_commit.returncode() == 0 and git_branch.returncode() == 0 - version = '"@0@-@1@ (" __DATE__ ", branch \'@2@\')"'.format( - meson.project_version(), - git_commit.stdout().strip(), - git_branch.stdout().strip(), - ) - endif -endif -add_project_arguments('-DSWAY_VERSION=@0@'.format(version), language: 'c') -add_project_arguments('-DSWAY_ORIGINAL_VERSION="1.9.0"', language: 'c') - -# Compute the relative path used by compiler invocations. -source_root = meson.current_source_dir().split('/') -build_root = meson.global_build_root().split('/') -relative_dir_parts = [] -i = 0 -in_prefix = true -foreach p : build_root - if i >= source_root.length() or not in_prefix or p != source_root[i] - in_prefix = false - relative_dir_parts += '..' - endif - i += 1 -endforeach -i = 0 -in_prefix = true -foreach p : source_root - if i >= build_root.length() or not in_prefix or build_root[i] != p - in_prefix = false - relative_dir_parts += p - endif - i += 1 -endforeach -relative_dir = join_paths(relative_dir_parts) + '/' - -# Strip relative path prefixes from the code if possible, otherwise hide them. -if cc.has_argument('-fmacro-prefix-map=/prefix/to/hide=') - add_project_arguments( - '-fmacro-prefix-map=@0@='.format(relative_dir), - language: 'c', - ) -else - add_project_arguments( - '-DSWAY_REL_SRC_DIR="@0@"'.format(relative_dir), - language: 'c', - ) -endif - - -sway_inc = include_directories('include') - -subdir('include') -subdir('protocols') -subdir('common') -subdir('sway') -subdir('swaymsg') - -if get_option('swaybar') or get_option('swaynag') - subdir('client') -endif -if get_option('swaybar') - subdir('swaybar') -endif -if get_option('swaynag') - subdir('swaynag') -endif - -config = configuration_data() -config.set('datadir', join_paths(prefix, datadir)) -config.set('prefix', prefix) -config.set('sysconfdir', join_paths(prefix, sysconfdir)) - -configure_file( - configuration: config, - input: 'config.in', - output: '@BASENAME@', - install_dir: join_paths(sysconfdir, 'sway') -) - -install_data( - 'sway.desktop', - install_dir: join_paths(datadir, 'wayland-sessions') -) - -if get_option('default-wallpaper') - wallpaper_files = files( - 'assets/Sway_Wallpaper_Blue_768x1024.png', - 'assets/Sway_Wallpaper_Blue_768x1024_Portrait.png', - 'assets/Sway_Wallpaper_Blue_1136x640.png', - 'assets/Sway_Wallpaper_Blue_1136x640_Portrait.png', - 'assets/Sway_Wallpaper_Blue_1366x768.png', - 'assets/Sway_Wallpaper_Blue_1920x1080.png', - 'assets/Sway_Wallpaper_Blue_2048x1536.png', - 'assets/Sway_Wallpaper_Blue_2048x1536_Portrait.png', - ) - wallpaper_install_dir = join_paths(datadir, 'backgrounds', 'sway') - - install_data(wallpaper_files, install_dir: wallpaper_install_dir) -endif - -subdir('completions') - -summary({ - 'xwayland': have_xwayland, - 'gdk-pixbuf': gdk_pixbuf.found(), - 'tray': have_tray, - 'man-pages': scdoc.found(), -}, bool_yn: true) diff --git a/meson_options.txt b/meson_options.txt deleted file mode 100644 index 8d0d6509c..000000000 --- a/meson_options.txt +++ /dev/null @@ -1,11 +0,0 @@ -option('default-wallpaper', type: 'boolean', value: true, description: 'Install the default wallpaper.') -option('zsh-completions', type: 'boolean', value: true, description: 'Install zsh shell completions.') -option('bash-completions', type: 'boolean', value: true, description: 'Install bash shell completions.') -option('fish-completions', type: 'boolean', value: true, description: 'Install fish shell completions.') -option('swaybar', type: 'boolean', value: true, description: 'Enable support for swaybar') -option('swaynag', type: 'boolean', value: true, description: 'Enable support for swaynag') -option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications') -option('tray', type: 'feature', value: 'auto', description: 'Enable support for swaybar tray') -option('gdk-pixbuf', type: 'feature', value: 'auto', description: 'Enable support for more image formats in swaybar tray') -option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages') -option('sd-bus-provider', type: 'combo', choices: ['auto', 'libsystemd', 'libelogind', 'basu'], value: 'auto', description: 'Provider of the sd-bus library') diff --git a/protocols/idle.xml b/protocols/idle.xml deleted file mode 100644 index 92d9989c7..000000000 --- a/protocols/idle.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - . - ]]> - - - This interface allows to monitor user idle time on a given seat. The interface - allows to register timers which trigger after no user activity was registered - on the seat for a given interval. It notifies when user activity resumes. - - This is useful for applications wanting to perform actions when the user is not - interacting with the system, e.g. chat applications setting the user as away, power - management features to dim screen, etc.. - - - - - - - - - - - - - - - - - - - - - - diff --git a/protocols/meson.build b/protocols/meson.build deleted file mode 100644 index 2992ac585..000000000 --- a/protocols/meson.build +++ /dev/null @@ -1,44 +0,0 @@ -wl_protocol_dir = wayland_protos.get_variable('pkgdatadir') - -wayland_scanner_dep = dependency('wayland-scanner', native: true) -wayland_scanner = find_program( - wayland_scanner_dep.get_variable('wayland_scanner'), - native: true, -) - -protocols = [ - wl_protocol_dir / 'stable/xdg-shell/xdg-shell.xml', - wl_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml', - wl_protocol_dir / 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml', - wl_protocol_dir / 'unstable/tablet/tablet-unstable-v2.xml', - wl_protocol_dir / 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml', - wl_protocol_dir / 'staging/content-type/content-type-v1.xml', - wl_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml', - 'wlr-layer-shell-unstable-v1.xml', - 'idle.xml', - 'wlr-input-inhibitor-unstable-v1.xml', - 'wlr-output-power-management-unstable-v1.xml', -] - -wl_protos_src = [] - -foreach xml : protocols - wl_protos_src += custom_target( - xml.underscorify() + '_c', - input: xml, - output: '@BASENAME@-protocol.c', - command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'], - ) - wl_protos_src += custom_target( - xml.underscorify() + '_server_h', - input: xml, - output: '@BASENAME@-protocol.h', - command: [wayland_scanner, 'server-header', '@INPUT@', '@OUTPUT@'], - ) - wl_protos_src += custom_target( - xml.underscorify() + '_client_h', - input: xml, - output: '@BASENAME@-client-protocol.h', - command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@'], - ) -endforeach diff --git a/protocols/wlr-input-inhibitor-unstable-v1.xml b/protocols/wlr-input-inhibitor-unstable-v1.xml deleted file mode 100644 index b62d1bb44..000000000 --- a/protocols/wlr-input-inhibitor-unstable-v1.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - Copyright © 2018 Drew DeVault - - Permission to use, copy, modify, distribute, and sell this - software and its documentation for any purpose is hereby granted - without fee, provided that the above copyright notice appear in - all copies and that both that copyright notice and this permission - notice appear in supporting documentation, and that the name of - the copyright holders not be used in advertising or publicity - pertaining to distribution of the software without specific, - written prior permission. The copyright holders make no - representations about the suitability of this software for any - purpose. It is provided "as is" without express or implied - warranty. - - THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS - SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY - SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, - ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF - THIS SOFTWARE. - - - - - Clients can use this interface to prevent input events from being sent to - any surfaces but its own, which is useful for example in lock screen - software. It is assumed that access to this interface will be locked down - to whitelisted clients by the compositor. - - - - - Activates the input inhibitor. As long as the inhibitor is active, the - compositor will not send input events to other clients. - - - - - - - - - - - - While this resource exists, input to clients other than the owner of the - inhibitor resource will not receive input events. The client that owns - this resource will receive all input events normally. The compositor will - also disable all of its own input processing (such as keyboard shortcuts) - while the inhibitor is active. - - The compositor may continue to send input events to selected clients, - such as an on-screen keyboard (via the input-method protocol). - - - - - Destroy the inhibitor and allow other clients to receive input. - - - - diff --git a/protocols/wlr-layer-shell-unstable-v1.xml b/protocols/wlr-layer-shell-unstable-v1.xml deleted file mode 100644 index d62fd51e9..000000000 --- a/protocols/wlr-layer-shell-unstable-v1.xml +++ /dev/null @@ -1,390 +0,0 @@ - - - - Copyright © 2017 Drew DeVault - - Permission to use, copy, modify, distribute, and sell this - software and its documentation for any purpose is hereby granted - without fee, provided that the above copyright notice appear in - all copies and that both that copyright notice and this permission - notice appear in supporting documentation, and that the name of - the copyright holders not be used in advertising or publicity - pertaining to distribution of the software without specific, - written prior permission. The copyright holders make no - representations about the suitability of this software for any - purpose. It is provided "as is" without express or implied - warranty. - - THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS - SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY - SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, - ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF - THIS SOFTWARE. - - - - - Clients can use this interface to assign the surface_layer role to - wl_surfaces. Such surfaces are assigned to a "layer" of the output and - rendered with a defined z-depth respective to each other. They may also be - anchored to the edges and corners of a screen and specify input handling - semantics. This interface should be suitable for the implementation of - many desktop shell components, and a broad number of other applications - that interact with the desktop. - - - - - Create a layer surface for an existing surface. This assigns the role of - layer_surface, or raises a protocol error if another role is already - assigned. - - Creating a layer surface from a wl_surface which has a buffer attached - or committed is a client error, and any attempts by a client to attach - or manipulate a buffer prior to the first layer_surface.configure call - must also be treated as errors. - - After creating a layer_surface object and setting it up, the client - must perform an initial commit without any buffer attached. - The compositor will reply with a layer_surface.configure event. - The client must acknowledge it and is then allowed to attach a buffer - to map the surface. - - You may pass NULL for output to allow the compositor to decide which - output to use. Generally this will be the one that the user most - recently interacted with. - - Clients can specify a namespace that defines the purpose of the layer - surface. - - - - - - - - - - - - - - - - - These values indicate which layers a surface can be rendered in. They - are ordered by z depth, bottom-most first. Traditional shell surfaces - will typically be rendered between the bottom and top layers. - Fullscreen shell surfaces are typically rendered at the top layer. - Multiple surfaces can share a single layer, and ordering within a - single layer is undefined. - - - - - - - - - - - - - This request indicates that the client will not use the layer_shell - object any more. Objects that have been created through this instance - are not affected. - - - - - - - An interface that may be implemented by a wl_surface, for surfaces that - are designed to be rendered as a layer of a stacked desktop-like - environment. - - Layer surface state (layer, size, anchor, exclusive zone, - margin, interactivity) is double-buffered, and will be applied at the - time wl_surface.commit of the corresponding wl_surface is called. - - Attaching a null buffer to a layer surface unmaps it. - - Unmapping a layer_surface means that the surface cannot be shown by the - compositor until it is explicitly mapped again. The layer_surface - returns to the state it had right after layer_shell.get_layer_surface. - The client can re-map the surface by performing a commit without any - buffer attached, waiting for a configure event and handling it as usual. - - - - - Sets the size of the surface in surface-local coordinates. The - compositor will display the surface centered with respect to its - anchors. - - If you pass 0 for either value, the compositor will assign it and - inform you of the assignment in the configure event. You must set your - anchor to opposite edges in the dimensions you omit; not doing so is a - protocol error. Both values are 0 by default. - - Size is double-buffered, see wl_surface.commit. - - - - - - - - Requests that the compositor anchor the surface to the specified edges - and corners. If two orthogonal edges are specified (e.g. 'top' and - 'left'), then the anchor point will be the intersection of the edges - (e.g. the top left corner of the output); otherwise the anchor point - will be centered on that edge, or in the center if none is specified. - - Anchor is double-buffered, see wl_surface.commit. - - - - - - - Requests that the compositor avoids occluding an area with other - surfaces. The compositor's use of this information is - implementation-dependent - do not assume that this region will not - actually be occluded. - - A positive value is only meaningful if the surface is anchored to one - edge or an edge and both perpendicular edges. If the surface is not - anchored, anchored to only two perpendicular edges (a corner), anchored - to only two parallel edges or anchored to all edges, a positive value - will be treated the same as zero. - - A positive zone is the distance from the edge in surface-local - coordinates to consider exclusive. - - Surfaces that do not wish to have an exclusive zone may instead specify - how they should interact with surfaces that do. If set to zero, the - surface indicates that it would like to be moved to avoid occluding - surfaces with a positive exclusive zone. If set to -1, the surface - indicates that it would not like to be moved to accommodate for other - surfaces, and the compositor should extend it all the way to the edges - it is anchored to. - - For example, a panel might set its exclusive zone to 10, so that - maximized shell surfaces are not shown on top of it. A notification - might set its exclusive zone to 0, so that it is moved to avoid - occluding the panel, but shell surfaces are shown underneath it. A - wallpaper or lock screen might set their exclusive zone to -1, so that - they stretch below or over the panel. - - The default value is 0. - - Exclusive zone is double-buffered, see wl_surface.commit. - - - - - - - Requests that the surface be placed some distance away from the anchor - point on the output, in surface-local coordinates. Setting this value - for edges you are not anchored to has no effect. - - The exclusive zone includes the margin. - - Margin is double-buffered, see wl_surface.commit. - - - - - - - - - - Types of keyboard interaction possible for layer shell surfaces. The - rationale for this is twofold: (1) some applications are not interested - in keyboard events and not allowing them to be focused can improve the - desktop experience; (2) some applications will want to take exclusive - keyboard focus. - - - - - This value indicates that this surface is not interested in keyboard - events and the compositor should never assign it the keyboard focus. - - This is the default value, set for newly created layer shell surfaces. - - This is useful for e.g. desktop widgets that display information or - only have interaction with non-keyboard input devices. - - - - - Request exclusive keyboard focus if this surface is above the shell surface layer. - - For the top and overlay layers, the seat will always give - exclusive keyboard focus to the top-most layer which has keyboard - interactivity set to exclusive. If this layer contains multiple - surfaces with keyboard interactivity set to exclusive, the compositor - determines the one receiving keyboard events in an implementation- - defined manner. In this case, no guarantee is made when this surface - will receive keyboard focus (if ever). - - For the bottom and background layers, the compositor is allowed to use - normal focus semantics. - - This setting is mainly intended for applications that need to ensure - they receive all keyboard events, such as a lock screen or a password - prompt. - - - - - This requests the compositor to allow this surface to be focused and - unfocused by the user in an implementation-defined manner. The user - should be able to unfocus this surface even regardless of the layer - it is on. - - Typically, the compositor will want to use its normal mechanism to - manage keyboard focus between layer shell surfaces with this setting - and regular toplevels on the desktop layer (e.g. click to focus). - Nevertheless, it is possible for a compositor to require a special - interaction to focus or unfocus layer shell surfaces (e.g. requiring - a click even if focus follows the mouse normally, or providing a - keybinding to switch focus between layers). - - This setting is mainly intended for desktop shell components (e.g. - panels) that allow keyboard interaction. Using this option can allow - implementing a desktop shell that can be fully usable without the - mouse. - - - - - - - Set how keyboard events are delivered to this surface. By default, - layer shell surfaces do not receive keyboard events; this request can - be used to change this. - - This setting is inherited by child surfaces set by the get_popup - request. - - Layer surfaces receive pointer, touch, and tablet events normally. If - you do not want to receive them, set the input region on your surface - to an empty region. - - Keyboard interactivity is double-buffered, see wl_surface.commit. - - - - - - - This assigns an xdg_popup's parent to this layer_surface. This popup - should have been created via xdg_surface::get_popup with the parent set - to NULL, and this request must be invoked before committing the popup's - initial state. - - See the documentation of xdg_popup for more details about what an - xdg_popup is and how it is used. - - - - - - - When a configure event is received, if a client commits the - surface in response to the configure event, then the client - must make an ack_configure request sometime before the commit - request, passing along the serial of the configure event. - - If the client receives multiple configure events before it - can respond to one, it only has to ack the last configure event. - - A client is not required to commit immediately after sending - an ack_configure request - it may even ack_configure several times - before its next surface commit. - - A client may send multiple ack_configure requests before committing, but - only the last request sent before a commit indicates which configure - event the client really is responding to. - - - - - - - This request destroys the layer surface. - - - - - - The configure event asks the client to resize its surface. - - Clients should arrange their surface for the new states, and then send - an ack_configure request with the serial sent in this configure event at - some point before committing the new surface. - - The client is free to dismiss all but the last configure event it - received. - - The width and height arguments specify the size of the window in - surface-local coordinates. - - The size is a hint, in the sense that the client is free to ignore it if - it doesn't resize, pick a smaller size (to satisfy aspect ratio or - resize in steps of NxM pixels). If the client picks a smaller size and - is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the - surface will be centered on this axis. - - If the width or height arguments are zero, it means the client should - decide its own window dimension. - - - - - - - - - The closed event is sent by the compositor when the surface will no - longer be shown. The output may have been destroyed or the user may - have asked for it to be removed. Further changes to the surface will be - ignored. The client should destroy the resource after receiving this - event, and create a new surface if they so choose. - - - - - - - - - - - - - - - - - - - - - - Change the layer that the surface is rendered on. - - Layer is double-buffered, see wl_surface.commit. - - - - - diff --git a/protocols/wlr-output-power-management-unstable-v1.xml b/protocols/wlr-output-power-management-unstable-v1.xml deleted file mode 100644 index a97783991..000000000 --- a/protocols/wlr-output-power-management-unstable-v1.xml +++ /dev/null @@ -1,128 +0,0 @@ - - - - Copyright © 2019 Purism SPC - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice (including the next - paragraph) shall be included in all copies or substantial portions of the - Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - - - This protocol allows clients to control power management modes - of outputs that are currently part of the compositor space. The - intent is to allow special clients like desktop shells to power - down outputs when the system is idle. - - To modify outputs not currently part of the compositor space see - wlr-output-management. - - Warning! The protocol described in this file is experimental and - backward incompatible changes may be made. Backward compatible changes - may be added together with the corresponding interface version bump. - Backward incompatible changes are done by bumping the version number in - the protocol and interface names and resetting the interface version. - Once the protocol is to be declared stable, the 'z' prefix and the - version number in the protocol and interface names are removed and the - interface version number is reset. - - - - - This interface is a manager that allows creating per-output power - management mode controls. - - - - - Create a output power management mode control that can be used to - adjust the power management mode for a given output. - - - - - - - - All objects created by the manager will still remain valid, until their - appropriate destroy request has been called. - - - - - - - This object offers requests to set the power management mode of - an output. - - - - - - - - - - - - - - Set an output's power save mode to the given mode. The mode change - is effective immediately. If the output does not support the given - mode a failed event is sent. - - - - - - - Report the power management mode change of an output. - - The mode event is sent after an output changed its power - management mode. The reason can be a client using set_mode or the - compositor deciding to change an output's mode. - This event is also sent immediately when the object is created - so the client is informed about the current power management mode. - - - - - - - This event indicates that the output power management mode control - is no longer valid. This can happen for a number of reasons, - including: - - The output doesn't support power management - - Another client already has exclusive power management mode control - for this output - - The output disappeared - - Upon receiving this event, the client should destroy this object. - - - - - - Destroys the output power management mode control object. - - - - diff --git a/sway-portals.conf b/sway-portals.conf deleted file mode 100644 index aa046f63c..000000000 --- a/sway-portals.conf +++ /dev/null @@ -1,6 +0,0 @@ -[preferred] -# Use xdg-desktop-portal-gtk for every portal interface... -default=gtk -# ... except for the ScreenCast and Screenshot -org.freedesktop.impl.portal.ScreenCast=wlr -org.freedesktop.impl.portal.Screenshot=wlr diff --git a/sway.desktop b/sway.desktop deleted file mode 100644 index 9f33bcffa..000000000 --- a/sway.desktop +++ /dev/null @@ -1,5 +0,0 @@ -[Desktop Entry] -Name=SwayFX -Comment=An i3-compatible Wayland compositor -Exec=sway -Type=Application diff --git a/sway/commands.c b/sway/commands.c deleted file mode 100644 index 2e048203a..000000000 --- a/sway/commands.c +++ /dev/null @@ -1,552 +0,0 @@ -#define _POSIX_C_SOURCE 200809 -#include -#include -#include -#include -#include -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/criteria.h" -#include "sway/input/input-manager.h" -#include "sway/input/seat.h" -#include "sway/tree/view.h" -#include "stringop.h" -#include "log.h" - -// Returns error object, or NULL if check succeeds. -struct cmd_results *checkarg(int argc, const char *name, enum expected_args type, int val) { - const char *error_name = NULL; - switch (type) { - case EXPECTED_AT_LEAST: - if (argc < val) { - error_name = "at least "; - } - break; - case EXPECTED_AT_MOST: - if (argc > val) { - error_name = "at most "; - } - break; - case EXPECTED_EQUAL_TO: - if (argc != val) { - error_name = ""; - } - } - return error_name ? - cmd_results_new(CMD_INVALID, "Invalid %s command " - "(expected %s%d argument%s, got %d)", - name, error_name, val, val != 1 ? "s" : "", argc) - : NULL; -} - -/* Keep alphabetized */ -static const struct cmd_handler handlers[] = { - { "assign", cmd_assign }, - { "bar", cmd_bar }, - { "bindcode", cmd_bindcode }, - { "bindgesture", cmd_bindgesture }, - { "bindswitch", cmd_bindswitch }, - { "bindsym", cmd_bindsym }, - { "blur", cmd_blur }, - { "blur_brightness", cmd_blur_brightness }, - { "blur_contrast", cmd_blur_contrast }, - { "blur_noise", cmd_blur_noise }, - { "blur_passes", cmd_blur_passes }, - { "blur_radius", cmd_blur_radius }, - { "blur_saturation", cmd_blur_saturation }, - { "blur_xray", cmd_blur_xray }, - { "client.background", cmd_client_noop }, - { "client.focused", cmd_client_focused }, - { "client.focused_inactive", cmd_client_focused_inactive }, - { "client.focused_tab_title", cmd_client_focused_tab_title }, - { "client.placeholder", cmd_client_noop }, - { "client.unfocused", cmd_client_unfocused }, - { "client.urgent", cmd_client_urgent }, - { "corner_radius", cmd_corner_radius }, - { "default_border", cmd_default_border }, - { "default_dim_inactive", cmd_default_dim_inactive }, - { "default_floating_border", cmd_default_floating_border }, - { "dim_inactive", cmd_dim_inactive }, - { "dim_inactive_colors.unfocused", cmd_dim_inactive_colors_unfocused }, - { "dim_inactive_colors.urgent", cmd_dim_inactive_colors_urgent }, - { "exec", cmd_exec }, - { "exec_always", cmd_exec_always }, - { "floating_maximum_size", cmd_floating_maximum_size }, - { "floating_minimum_size", cmd_floating_minimum_size }, - { "floating_modifier", cmd_floating_modifier }, - { "focus", cmd_focus }, - { "focus_follows_mouse", cmd_focus_follows_mouse }, - { "focus_on_window_activation", cmd_focus_on_window_activation }, - { "focus_wrapping", cmd_focus_wrapping }, - { "font", cmd_font }, - { "for_window", cmd_for_window }, - { "force_display_urgency_hint", cmd_force_display_urgency_hint }, - { "force_focus_wrapping", cmd_force_focus_wrapping }, - { "fullscreen", cmd_fullscreen }, - { "gaps", cmd_gaps }, - { "hide_edge_borders", cmd_hide_edge_borders }, - { "input", cmd_input }, - { "layer_effects", cmd_layer_effects }, - { "mode", cmd_mode }, - { "mouse_warping", cmd_mouse_warping }, - { "new_float", cmd_new_float }, - { "new_window", cmd_new_window }, - { "no_focus", cmd_no_focus }, - { "output", cmd_output }, - { "popup_during_fullscreen", cmd_popup_during_fullscreen }, - { "seat", cmd_seat }, - { "set", cmd_set }, - { "shadow_blur_radius", cmd_shadow_blur_radius }, - { "shadow_color", cmd_shadow_color }, - { "shadow_inactive_color", cmd_shadow_inactive_color }, - { "shadow_offset", cmd_shadow_offset }, - { "shadows", cmd_shadows }, - { "shadows_on_csd", cmd_shadows_on_csd }, - { "show_marks", cmd_show_marks }, - { "smart_borders", cmd_smart_borders }, - { "smart_corner_radius", cmd_smart_corner_radius }, - { "smart_gaps", cmd_smart_gaps }, - { "tiling_drag", cmd_tiling_drag }, - { "tiling_drag_threshold", cmd_tiling_drag_threshold }, - { "title_align", cmd_title_align }, - { "titlebar_border_thickness", cmd_titlebar_border_thickness }, - { "titlebar_padding", cmd_titlebar_padding }, - { "titlebar_separator", cmd_titlebar_separator }, - { "unbindcode", cmd_unbindcode }, - { "unbindgesture", cmd_unbindgesture }, - { "unbindswitch", cmd_unbindswitch }, - { "unbindsym", cmd_unbindsym }, - { "workspace", cmd_workspace }, - { "workspace_auto_back_and_forth", cmd_ws_auto_back_and_forth }, -}; - -/* Config-time only commands. Keep alphabetized */ -static const struct cmd_handler config_handlers[] = { - { "default_orientation", cmd_default_orientation }, - { "include", cmd_include }, - { "scratchpad_minimize", cmd_scratchpad_minimize }, - { "primary_selection", cmd_primary_selection }, - { "swaybg_command", cmd_swaybg_command }, - { "swaynag_command", cmd_swaynag_command }, - { "workspace_layout", cmd_workspace_layout }, - { "xwayland", cmd_xwayland }, -}; - -/* Runtime-only commands. Keep alphabetized */ -static const struct cmd_handler command_handlers[] = { - { "border", cmd_border }, - { "create_output", cmd_create_output }, - { "exit", cmd_exit }, - { "floating", cmd_floating }, - { "fullscreen", cmd_fullscreen }, - { "inhibit_idle", cmd_inhibit_idle }, - { "kill", cmd_kill }, - { "layout", cmd_layout }, - { "mark", cmd_mark }, - { "max_render_time", cmd_max_render_time }, - { "move", cmd_move }, - { "nop", cmd_nop }, - { "opacity", cmd_opacity }, - { "reload", cmd_reload }, - { "rename", cmd_rename }, - { "resize", cmd_resize }, - { "saturation", cmd_saturation }, - { "scratchpad", cmd_scratchpad }, - { "shortcuts_inhibitor", cmd_shortcuts_inhibitor }, - { "split", cmd_split }, - { "splith", cmd_splith }, - { "splitt", cmd_splitt }, - { "splitv", cmd_splitv }, - { "sticky", cmd_sticky }, - { "swap", cmd_swap }, - { "title_format", cmd_title_format }, - { "unmark", cmd_unmark }, - { "urgent", cmd_urgent }, -}; - -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); -} - -const struct cmd_handler *find_handler(const char *line, - const struct cmd_handler *handlers, size_t handlers_size) { - if (!handlers || !handlers_size) { - return NULL; - } - const struct cmd_handler query = { .command = line }; - return bsearch(&query, handlers, - handlers_size / sizeof(struct cmd_handler), - sizeof(struct cmd_handler), handler_compare); -} - -static const struct cmd_handler *find_handler_ex(char *line, - const struct cmd_handler *config_handlers, size_t config_handlers_size, - const struct cmd_handler *command_handlers, size_t command_handlers_size, - const struct cmd_handler *handlers, size_t handlers_size) { - const struct cmd_handler *handler = NULL; - if (config->reading) { - handler = find_handler(line, config_handlers, config_handlers_size); - } else if (config->active) { - handler = find_handler(line, command_handlers, command_handlers_size); - } - return handler ? handler : find_handler(line, handlers, handlers_size); -} - -static const struct cmd_handler *find_core_handler(char *line) { - return find_handler_ex(line, config_handlers, sizeof(config_handlers), - command_handlers, sizeof(command_handlers), - handlers, sizeof(handlers)); -} - -static void set_config_node(struct sway_node *node, bool node_overridden) { - config->handler_context.node = node; - config->handler_context.container = NULL; - config->handler_context.workspace = NULL; - config->handler_context.node_overridden = node_overridden; - - if (node == NULL) { - return; - } - - switch (node->type) { - case N_CONTAINER: - config->handler_context.container = node->sway_container; - config->handler_context.workspace = node->sway_container->pending.workspace; - break; - case N_WORKSPACE: - config->handler_context.workspace = node->sway_workspace; - break; - case N_ROOT: - case N_OUTPUT: - break; - } -} - -list_t *execute_command(char *_exec, struct sway_seat *seat, - struct sway_container *con) { - char *cmd; - char matched_delim = ';'; - list_t *containers = NULL; - bool using_criteria = false; - - if (seat == NULL) { - // passing a NULL seat means we just pick the default seat - seat = input_manager_get_default_seat(); - if (!sway_assert(seat, "could not find a seat to run the command on")) { - return NULL; - } - } - - char *exec = strdup(_exec); - char *head = exec; - list_t *res_list = create_list(); - - if (!res_list || !exec) { - return NULL; - } - - config->handler_context.seat = seat; - - do { - for (; isspace(*head); ++head) {} - // Extract criteria (valid for this command list only). - if (matched_delim == ';') { - using_criteria = false; - if (*head == '[') { - char *error = NULL; - struct criteria *criteria = criteria_parse(head, &error); - if (!criteria) { - list_add(res_list, - cmd_results_new(CMD_INVALID, "%s", error)); - free(error); - goto cleanup; - } - list_free(containers); - containers = criteria_get_containers(criteria); - head += strlen(criteria->raw); - criteria_destroy(criteria); - using_criteria = true; - // Skip leading whitespace - for (; isspace(*head); ++head) {} - } - } - // Split command list - cmd = argsep(&head, ";,", &matched_delim); - for (; isspace(*cmd); ++cmd) {} - - if (strcmp(cmd, "") == 0) { - sway_log(SWAY_INFO, "Ignoring empty command."); - continue; - } - sway_log(SWAY_INFO, "Handling command '%s'", cmd); - //TODO better handling of argv - int argc; - char **argv = split_args(cmd, &argc); - if (strcmp(argv[0], "exec") != 0 && - strcmp(argv[0], "exec_always") != 0 && - strcmp(argv[0], "mode") != 0) { - for (int i = 1; i < argc; ++i) { - if (*argv[i] == '\"' || *argv[i] == '\'') { - strip_quotes(argv[i]); - } - } - } - const struct cmd_handler *handler = find_core_handler(argv[0]); - if (!handler) { - list_add(res_list, cmd_results_new(CMD_INVALID, - "Unknown/invalid command '%s'", argv[0])); - free_argv(argc, argv); - goto cleanup; - } - - // Var replacement, for all but first argument of set - for (int i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) { - argv[i] = do_var_replacement(argv[i]); - } - - - if (!using_criteria) { - if (con) { - set_config_node(&con->node, true); - } else { - set_config_node(seat_get_focus_inactive(seat, &root->node), - false); - } - struct cmd_results *res = handler->handle(argc-1, argv+1); - list_add(res_list, res); - if (res->status == CMD_INVALID) { - free_argv(argc, argv); - goto cleanup; - } - } else if (containers->length == 0) { - list_add(res_list, - cmd_results_new(CMD_FAILURE, "No matching node.")); - } else { - struct cmd_results *fail_res = NULL; - for (int i = 0; i < containers->length; ++i) { - struct sway_container *container = containers->items[i]; - set_config_node(&container->node, true); - struct cmd_results *res = handler->handle(argc-1, argv+1); - if (res->status == CMD_SUCCESS) { - free_cmd_results(res); - } else { - // last failure will take precedence - if (fail_res) { - free_cmd_results(fail_res); - } - fail_res = res; - if (res->status == CMD_INVALID) { - list_add(res_list, fail_res); - free_argv(argc, argv); - goto cleanup; - } - } - } - list_add(res_list, - fail_res ? fail_res : cmd_results_new(CMD_SUCCESS, NULL)); - } - free_argv(argc, argv); - } while(head); -cleanup: - free(exec); - list_free(containers); - return res_list; -} - -// this is like execute_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) execute_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, char **new_block) { - struct cmd_results *results = NULL; - int argc; - char **argv = split_args(exec, &argc); - - // Check for empty lines - if (!argc) { - results = cmd_results_new(CMD_SUCCESS, NULL); - goto cleanup; - } - - // Check for the start of a block - if (argc > 1 && strcmp(argv[argc - 1], "{") == 0) { - *new_block = join_args(argv, argc - 1); - results = cmd_results_new(CMD_BLOCK, NULL); - goto cleanup; - } - - // Check for the end of a block - if (strcmp(argv[argc - 1], "}") == 0) { - results = cmd_results_new(CMD_BLOCK_END, NULL); - goto cleanup; - } - - // Make sure the command is not stored in a variable - if (*argv[0] == '$') { - argv[0] = do_var_replacement(argv[0]); - char *temp = join_args(argv, argc); - free_argv(argc, argv); - argv = split_args(temp, &argc); - free(temp); - if (!argc) { - results = cmd_results_new(CMD_SUCCESS, NULL); - goto cleanup; - } - } - - // Determine the command handler - sway_log(SWAY_INFO, "Config command: %s", exec); - const struct cmd_handler *handler = find_core_handler(argv[0]); - if (!handler || !handler->handle) { - if (handler) { - results = cmd_results_new(CMD_INVALID, - "Command '%s' is shimmed, but unimplemented", argv[0]); - } else { - results = cmd_results_new(CMD_INVALID, - "Unknown/invalid command '%s'", argv[0]); - } - goto cleanup; - } - - // Do variable replacement - if (handler->handle == cmd_set && argc > 1 && *argv[1] == '$') { - // Escape the variable name so it does not get replaced by one shorter - char *temp = calloc(1, strlen(argv[1]) + 2); - temp[0] = '$'; - strcpy(&temp[1], argv[1]); - free(argv[1]); - argv[1] = temp; - } - char *command = do_var_replacement(join_args(argv, argc)); - sway_log(SWAY_INFO, "After replacement: %s", command); - free_argv(argc, argv); - argv = split_args(command, &argc); - free(command); - - // Strip quotes and unescape the string - for (int i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) { - if (handler->handle != cmd_exec && handler->handle != cmd_exec_always - && handler->handle != cmd_mode - && handler->handle != cmd_bindsym - && handler->handle != cmd_bindcode - && handler->handle != cmd_bindswitch - && handler->handle != cmd_bindgesture - && handler->handle != cmd_set - && handler->handle != cmd_for_window - && (*argv[i] == '\"' || *argv[i] == '\'')) { - strip_quotes(argv[i]); - } - unescape_string(argv[i]); - } - - // Run command - results = handler->handle(argc - 1, argv + 1); - -cleanup: - free_argv(argc, argv); - return results; -} - -struct cmd_results *config_subcommand(char **argv, int argc, - const struct cmd_handler *handlers, size_t handlers_size) { - char *command = join_args(argv, argc); - sway_log(SWAY_DEBUG, "Subcommand: %s", command); - free(command); - - const struct cmd_handler *handler = find_handler(argv[0], handlers, - handlers_size); - if (!handler) { - return cmd_results_new(CMD_INVALID, - "Unknown/invalid command '%s'", argv[0]); - } - if (handler->handle) { - return handler->handle(argc - 1, argv + 1); - } - return cmd_results_new(CMD_INVALID, - "The command '%s' is shimmed, but unimplemented", argv[0]); -} - -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); - 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); - goto cleanup; - } - - const struct cmd_handler *handler = find_handler(cmd, NULL, 0); - if (!handler && strcmp(cmd, "*") != 0) { - results = cmd_results_new(CMD_INVALID, - "Unknown/invalid command '%s'", cmd); - goto cleanup; - } - - results = cmd_results_new(CMD_SUCCESS, NULL); - -cleanup: - free_argv(argc, argv); - return results; -} - -struct cmd_results *cmd_results_new(enum cmd_status status, - const char *format, ...) { - struct cmd_results *results = malloc(sizeof(struct cmd_results)); - if (!results) { - sway_log(SWAY_ERROR, "Unable to allocate command results"); - return NULL; - } - results->status = status; - if (format) { - va_list args; - va_start(args, format); - results->error = vformat_str(format, args); - va_end(args); - } else { - results->error = NULL; - } - return results; -} - -void free_cmd_results(struct cmd_results *results) { - if (results->error) { - free(results->error); - } - free(results); -} - -char *cmd_results_to_json(list_t *res_list) { - json_object *result_array = json_object_new_array(); - for (int i = 0; i < res_list->length; ++i) { - struct cmd_results *results = res_list->items[i]; - json_object *root = json_object_new_object(); - json_object_object_add(root, "success", - json_object_new_boolean(results->status == CMD_SUCCESS)); - if (results->error) { - json_object_object_add(root, "parse_error", - json_object_new_boolean(results->status == CMD_INVALID)); - 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); - char *res = strdup(json); - json_object_put(result_array); - return res; -} diff --git a/sway/commands/assign.c b/sway/commands/assign.c deleted file mode 100644 index f7d911f77..000000000 --- a/sway/commands/assign.c +++ /dev/null @@ -1,63 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include "sway/commands.h" -#include "sway/criteria.h" -#include "list.h" -#include "log.h" -#include "stringop.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; - } - - // Create criteria - char *err_str = NULL; - struct criteria *criteria = criteria_parse(argv[0], &err_str); - if (!criteria) { - error = cmd_results_new(CMD_INVALID, "%s", err_str); - free(err_str); - return error; - } - - --argc; ++argv; - - if (strncmp(*argv, "→", strlen("→")) == 0) { - if (argc < 2) { - free(criteria); - return cmd_results_new(CMD_INVALID, "Missing workspace"); - } - --argc; - ++argv; - } - - if (strcmp(*argv, "output") == 0) { - criteria->type = CT_ASSIGN_OUTPUT; - --argc; ++argv; - } else { - if (strcmp(*argv, "workspace") == 0) { - --argc; ++argv; - } - if (strcmp(*argv, "number") == 0) { - --argc; ++argv; - if (argv[0][0] < '0' || argv[0][0] > '9') { - free(criteria); - return cmd_results_new(CMD_INVALID, - "Invalid workspace number '%s'", argv[0]); - } - criteria->type = CT_ASSIGN_WORKSPACE_NUMBER; - } else { - criteria->type = CT_ASSIGN_WORKSPACE; - } - } - - criteria->target = join_args(argv, argc); - - list_add(config->criteria, criteria); - sway_log(SWAY_DEBUG, "assign: '%s' -> '%s' added", criteria->raw, - criteria->target); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/bar.c b/sway/commands/bar.c deleted file mode 100644 index 22756acbf..000000000 --- a/sway/commands/bar.c +++ /dev/null @@ -1,136 +0,0 @@ -#define _POSIX_C_SOURCE 200809 -#include -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/ipc-server.h" -#include "log.h" - -// Must be in alphabetical order for bsearch -static const struct cmd_handler bar_handlers[] = { - { "bindcode", bar_cmd_bindcode }, - { "binding_mode_indicator", bar_cmd_binding_mode_indicator }, - { "bindsym", bar_cmd_bindsym }, - { "colors", bar_cmd_colors }, - { "font", bar_cmd_font }, - { "gaps", bar_cmd_gaps }, - { "height", bar_cmd_height }, - { "hidden_state", bar_cmd_hidden_state }, - { "icon_theme", bar_cmd_icon_theme }, - { "mode", bar_cmd_mode }, - { "modifier", bar_cmd_modifier }, - { "output", bar_cmd_output }, - { "pango_markup", bar_cmd_pango_markup }, - { "position", bar_cmd_position }, - { "separator_symbol", bar_cmd_separator_symbol }, - { "status_command", bar_cmd_status_command }, - { "status_edge_padding", bar_cmd_status_edge_padding }, - { "status_padding", bar_cmd_status_padding }, - { "strip_workspace_name", bar_cmd_strip_workspace_name }, - { "strip_workspace_numbers", bar_cmd_strip_workspace_numbers }, - { "tray_bindcode", bar_cmd_tray_bindcode }, - { "tray_bindsym", bar_cmd_tray_bindsym }, - { "tray_output", bar_cmd_tray_output }, - { "tray_padding", bar_cmd_tray_padding }, - { "unbindcode", bar_cmd_unbindcode }, - { "unbindsym", bar_cmd_unbindsym }, - { "workspace_buttons", bar_cmd_workspace_buttons }, - { "workspace_min_width", bar_cmd_workspace_min_width }, - { "wrap_scroll", bar_cmd_wrap_scroll }, -}; - -// Must be in alphabetical order for bsearch -static const struct cmd_handler bar_config_handlers[] = { - { "id", bar_cmd_id }, - { "swaybar_command", bar_cmd_swaybar_command }, -}; - -// Determines whether the subcommand is valid in any bar handler struct -static bool is_subcommand(char *name) { - return find_handler(name, bar_handlers, sizeof(bar_handlers)) || - find_handler(name, bar_config_handlers, sizeof(bar_config_handlers)); -} - -struct cmd_results *cmd_bar(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "bar", EXPECTED_AT_LEAST, 2))) { - return error; - } - - char *id = NULL; - if (strcmp(argv[0], "id") != 0 && is_subcommand(argv[1])) { - for (int i = 0; i < config->bars->length; ++i) { - struct bar_config *item = config->bars->items[i]; - if (strcmp(item->id, argv[0]) == 0) { - sway_log(SWAY_DEBUG, "Selecting bar: %s", argv[0]); - config->current_bar = item; - break; - } - } - if (!config->current_bar) { - id = strdup(argv[0]); - } - ++argv; --argc; - } else if (config->reading && !config->current_bar) { - id = format_str("bar-%d", config->bars->length); - if (!id) { - return cmd_results_new(CMD_FAILURE, "Unable to allocate bar id"); - } - } else if (!config->reading && strcmp(argv[0], "mode") != 0 && - strcmp(argv[0], "hidden_state") != 0) { - if (is_subcommand(argv[0])) { - return cmd_results_new(CMD_INVALID, "No bar defined."); - } else { - return cmd_results_new(CMD_INVALID, - "Unknown/invalid command '%s'", argv[1]); - } - } - - if (id) { - sway_log(SWAY_DEBUG, "Creating bar: %s", id); - config->current_bar = default_bar_config(); - if (!config->current_bar) { - free(id); - return cmd_results_new(CMD_FAILURE, "Unable to allocate bar config"); - } - config->current_bar->id = id; - } - - struct cmd_results *res = NULL; - if (find_handler(argv[0], bar_config_handlers, - sizeof(bar_config_handlers))) { - if (config->reading) { - res = config_subcommand(argv, argc, bar_config_handlers, - sizeof(bar_config_handlers)); - } else { - res = cmd_results_new(CMD_INVALID, - "Can only be used in the config file"); - } - } else { - res = config_subcommand(argv, argc, bar_handlers, sizeof(bar_handlers)); - } - - if (res && res->status != CMD_SUCCESS) { - if (id) { - free_bar_config(config->current_bar); - config->current_bar = NULL; - id = NULL; - } - return res; - } - - if (id) { - list_add(config->bars, config->current_bar); - } - - if (!config->reading && config->current_bar) { - ipc_event_barconfig_update(config->current_bar); - if (id) { - load_swaybar(config->current_bar); - } - config->current_bar = NULL; - } - - return res; -} diff --git a/sway/commands/bar/bind.c b/sway/commands/bar/bind.c deleted file mode 100644 index 8a837e3f1..000000000 --- a/sway/commands/bar/bind.c +++ /dev/null @@ -1,129 +0,0 @@ -#include -#include -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/input/cursor.h" -#include "list.h" -#include "log.h" -#include "stringop.h" - -static struct cmd_results *binding_add(struct bar_binding *binding, - list_t *mode_bindings) { - const char *name = get_mouse_button_name(binding->button); - bool overwritten = false; - for (int i = 0; i < mode_bindings->length; i++) { - struct bar_binding *other = mode_bindings->items[i]; - if (other->button == binding->button && - other->release == binding->release) { - overwritten = true; - mode_bindings->items[i] = binding; - free_bar_binding(other); - sway_log(SWAY_DEBUG, "[bar %s] Updated binding for %u (%s)%s", - config->current_bar->id, binding->button, name, - binding->release ? " - release" : ""); - break; - } - } - if (!overwritten) { - list_add(mode_bindings, binding); - sway_log(SWAY_DEBUG, "[bar %s] Added binding for %u (%s)%s", - config->current_bar->id, binding->button, name, - binding->release ? " - release" : ""); - } - return cmd_results_new(CMD_SUCCESS, NULL); -} - -static struct cmd_results *binding_remove(struct bar_binding *binding, - list_t *mode_bindings) { - const char *name = get_mouse_button_name(binding->button); - for (int i = 0; i < mode_bindings->length; i++) { - struct bar_binding *other = mode_bindings->items[i]; - if (other->button == binding->button && - other->release == binding->release) { - sway_log(SWAY_DEBUG, "[bar %s] Unbound binding for %u (%s)%s", - config->current_bar->id, binding->button, name, - binding->release ? " - release" : ""); - free_bar_binding(other); - free_bar_binding(binding); - list_del(mode_bindings, i); - return cmd_results_new(CMD_SUCCESS, NULL); - } - } - - struct cmd_results *error = cmd_results_new(CMD_FAILURE, "Could not " - "find binding for [bar %s]" " Button %u (%s)%s", - config->current_bar->id, binding->button, name, - binding->release ? " - release" : ""); - free_bar_binding(binding); - return error; -} - -static struct cmd_results *bar_cmd_bind(int argc, char **argv, bool code, - bool unbind) { - int minargs = 2; - const char *command; - if (unbind) { - minargs--; - command = code ? "bar unbindcode" : "bar unbindsym"; - } else { - command = code ? "bar bindcode" : "bar bindsym"; - } - - struct cmd_results *error = NULL; - if ((error = checkarg(argc, command, EXPECTED_AT_LEAST, minargs))) { - return error; - } - - struct bar_binding *binding = calloc(1, sizeof(struct bar_binding)); - if (!binding) { - return cmd_results_new(CMD_FAILURE, "Unable to allocate bar binding"); - } - - binding->release = false; - if (strcmp("--release", argv[0]) == 0) { - binding->release = true; - argv++; - argc--; - } - - char *message = NULL; - if (code) { - binding->button = get_mouse_bindcode(argv[0], &message); - } else { - binding->button = get_mouse_bindsym(argv[0], &message); - } - if (message) { - free_bar_binding(binding); - error = cmd_results_new(CMD_INVALID, "%s", message); - free(message); - return error; - } else if (!binding->button) { - free_bar_binding(binding); - return cmd_results_new(CMD_INVALID, "Unknown button %s", argv[0]); - } - list_t *bindings = config->current_bar->bindings; - if (unbind) { - return binding_remove(binding, bindings); - } - - binding->command = join_args(argv + 1, argc - 1); - return binding_add(binding, bindings); -} - -struct cmd_results *bar_cmd_bindcode(int argc, char **argv) { - return bar_cmd_bind(argc, argv, true, false); -} - -struct cmd_results *bar_cmd_bindsym(int argc, char **argv) { - return bar_cmd_bind(argc, argv, false, false); -} - -struct cmd_results *bar_cmd_unbindcode(int argc, char **argv) { - return bar_cmd_bind(argc, argv, true, true); -} - -struct cmd_results *bar_cmd_unbindsym(int argc, char **argv) { - return bar_cmd_bind(argc, argv, false, true); -} diff --git a/sway/commands/bar/binding_mode_indicator.c b/sway/commands/bar/binding_mode_indicator.c deleted file mode 100644 index b58d8a838..000000000 --- a/sway/commands/bar/binding_mode_indicator.c +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "log.h" -#include "util.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; - } - config->current_bar->binding_mode_indicator = - parse_boolean(argv[0], config->current_bar->binding_mode_indicator); - if (config->current_bar->binding_mode_indicator) { - sway_log(SWAY_DEBUG, "Enabling binding mode indicator on bar: %s", - config->current_bar->id); - } else { - sway_log(SWAY_DEBUG, "Disabling binding mode indicator on bar: %s", - config->current_bar->id); - } - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/bar/colors.c b/sway/commands/bar/colors.c deleted file mode 100644 index 275fa3c64..000000000 --- a/sway/commands/bar/colors.c +++ /dev/null @@ -1,152 +0,0 @@ -#include -#include "sway/commands.h" -#include "log.h" -#include "util.h" - -// Must be in alphabetical order for bsearch -static const 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 char *hex_to_rgba_hex(const char *hex) { - uint32_t color; - if (!parse_color(hex, &color)) { - return NULL; - } - char *rgba = malloc(10); - if (!rgba) { - return NULL; - } - snprintf(rgba, 10, "#%08x", color); - return rgba; -} - -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; - } - - char *rgba = hex_to_rgba_hex(argv[0]); - if (!rgba) { - return cmd_results_new(CMD_INVALID, "Invalid color: %s", argv[0]); - } - - free(*color); - *color = rgba; - return cmd_results_new(CMD_SUCCESS, NULL); -} - -static struct cmd_results *parse_three_colors(char ***colors, - const char *cmd_name, int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 3))) { - return error; - } - - char *rgba[3] = {0}; - for (int i = 0; i < 3; i++) { - rgba[i] = hex_to_rgba_hex(argv[i]); - if (!rgba[i]) { - return cmd_results_new(CMD_INVALID, "Invalid color: %s", argv[i]); - } - } - - for (int i = 0; i < 3; i++) { - free(*colors[i]); - *colors[i] = rgba[i]; - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} - -struct cmd_results *bar_cmd_colors(int argc, char **argv) { - return config_subcommand(argv, argc, bar_colors_handlers, - sizeof(bar_colors_handlers)); -} - -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_statusline), - "focused_statusline", 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/font.c b/sway/commands/bar/font.c deleted file mode 100644 index 891c87af8..000000000 --- a/sway/commands/bar/font.c +++ /dev/null @@ -1,31 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#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; - } - char *font = join_args(argv, argc); - free(config->current_bar->font); - - if (strncmp(font, "pango:", 6) == 0) { - if (config->current_bar->pango_markup == PANGO_MARKUP_DEFAULT) { - config->current_bar->pango_markup = true; - } - config->current_bar->font = strdup(font + 6); - } else { - if (config->current_bar->pango_markup == PANGO_MARKUP_DEFAULT) { - config->current_bar->pango_markup = false; - } - config->current_bar->font = strdup(font); - } - - free(font); - sway_log(SWAY_DEBUG, "Settings font '%s' for bar: %s", - config->current_bar->font, config->current_bar->id); - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/bar/gaps.c b/sway/commands/bar/gaps.c deleted file mode 100644 index 9fa3e756a..000000000 --- a/sway/commands/bar/gaps.c +++ /dev/null @@ -1,57 +0,0 @@ -#include -#include -#include -#include "sway/commands.h" -#include "sway/ipc-server.h" -#include "log.h" - -struct cmd_results *bar_cmd_gaps(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 1))) { - return error; - } - if ((error = checkarg(argc, "gaps", EXPECTED_AT_MOST, 4))) { - return error; - } - - int top = 0, right = 0, bottom = 0, left = 0; - - for (int i = 0; i < argc; i++) { - char *end; - int amount = strtol(argv[i], &end, 10); - if (strlen(end) && strcasecmp(end, "px") != 0) { - return cmd_results_new(CMD_INVALID, - "Expected 'bar [] gaps | " - " | '"); - } - - if (i == 0) { - top = amount; - } - if (i == 0 || i == 1) { - right = amount; - } - if (i == 0 || i == 2) { - bottom = amount; - } - if (i == 0 || i == 1 || i == 3) { - left = amount; - } - } - - config->current_bar->gaps.top = top; - config->current_bar->gaps.right = right; - config->current_bar->gaps.bottom = bottom; - config->current_bar->gaps.left = left; - - sway_log(SWAY_DEBUG, "Setting bar gaps to %d %d %d %d on bar: %s", - config->current_bar->gaps.top, config->current_bar->gaps.right, - config->current_bar->gaps.bottom, config->current_bar->gaps.left, - config->current_bar->id); - - if (!config->reading) { - ipc_event_barconfig_update(config->current_bar); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/bar/height.c b/sway/commands/bar/height.c deleted file mode 100644 index 945eb7071..000000000 --- a/sway/commands/bar/height.c +++ /dev/null @@ -1,20 +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, - "Invalid height value: %s", argv[0]); - } - config->current_bar->height = height; - sway_log(SWAY_DEBUG, "Setting bar height to %d on bar: %s", - height, config->current_bar->id); - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/bar/hidden_state.c b/sway/commands/bar/hidden_state.c deleted file mode 100644 index 8b661e3a1..000000000 --- a/sway/commands/bar/hidden_state.c +++ /dev/null @@ -1,74 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#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, "Invalid value %s", hidden_state); - } - if (strcmp(old_state, bar->hidden_state) != 0) { - if (!config->current_bar) { - ipc_event_barconfig_update(bar); - } - sway_log(SWAY_DEBUG, "Setting hidden_state: '%s' for bar: %s", - bar->hidden_state, bar->id); - } - // free old mode - free(old_state); - return 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_AT_MOST, 2))) { - return error; - } - if (config->reading && argc > 1) { - return cmd_results_new(CMD_INVALID, - "Unexpected value %s in config mode", argv[1]); - } - - if (config->current_bar && argc == 2 && - strcmp(config->current_bar->id, argv[1]) != 0) { - return cmd_results_new(CMD_INVALID, "Conflicting bar ids: %s and %s", - config->current_bar->id, argv[1]); - } - - const char *state = argv[0]; - if (config->current_bar) { - error = bar_set_hidden_state(config->current_bar, state); - } else { - const char *id = argc == 2 ? argv[1] : NULL; - for (int i = 0; i < config->bars->length; ++i) { - struct bar_config *bar = config->bars->items[i]; - if (id) { - if (strcmp(id, bar->id) == 0) { - error = bar_set_hidden_state(bar, state); - break; - } - } else if ((error = bar_set_hidden_state(bar, state))) { - break; - } - } - } - return error ? error : cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/bar/icon_theme.c b/sway/commands/bar/icon_theme.c deleted file mode 100644 index 6ac07843d..000000000 --- a/sway/commands/bar/icon_theme.c +++ /dev/null @@ -1,24 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include "config.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "log.h" - -struct cmd_results *bar_cmd_icon_theme(int argc, char **argv) { -#if HAVE_TRAY - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "icon_theme", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - sway_log(SWAY_DEBUG, "[Bar %s] Setting icon theme to %s", - config->current_bar->id, argv[0]); - free(config->current_bar->icon_theme); - config->current_bar->icon_theme = strdup(argv[0]); - return cmd_results_new(CMD_SUCCESS, NULL); -#else - return cmd_results_new(CMD_INVALID, - "Sway has been compiled without tray support"); -#endif -} diff --git a/sway/commands/bar/id.c b/sway/commands/bar/id.c deleted file mode 100644 index a9a617430..000000000 --- a/sway/commands/bar/id.c +++ /dev/null @@ -1,35 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#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; - if (strcmp(name, oldname) == 0) { - return cmd_results_new(CMD_SUCCESS, NULL); // NOP - } else if (strcmp(name, "id") == 0) { - return cmd_results_new(CMD_INVALID, "id cannot be 'id'"); - } - // check if id is used by a previously defined bar - for (int 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 '%s' already defined for another bar. Id unchanged (%s).", - name, oldname); - } - } - - sway_log(SWAY_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); -} diff --git a/sway/commands/bar/mode.c b/sway/commands/bar/mode.c deleted file mode 100644 index 7c2f423bb..000000000 --- a/sway/commands/bar/mode.c +++ /dev/null @@ -1,78 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#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{ - 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 if (strcasecmp("overlay", mode) == 0) { - bar->mode = strdup("overlay"); - } else { - return cmd_results_new(CMD_INVALID, "Invalid value %s", mode); - } - - if (strcmp(old_mode, bar->mode) != 0) { - if (!config->current_bar) { - ipc_event_barconfig_update(bar); - } - sway_log(SWAY_DEBUG, "Setting mode: '%s' for bar: %s", bar->mode, bar->id); - } - - // free old mode - free(old_mode); - return 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_AT_MOST, 2))) { - return error; - } - if (config->reading && argc > 1) { - return cmd_results_new(CMD_INVALID, - "Unexpected value %s in config mode", argv[1]); - } - - if (config->current_bar && argc == 2 && - strcmp(config->current_bar->id, argv[1]) != 0) { - return cmd_results_new(CMD_INVALID, "Conflicting bar ids: %s and %s", - config->current_bar->id, argv[1]); - } - - const char *mode = argv[0]; - if (config->current_bar) { - error = bar_set_mode(config->current_bar, mode); - } else { - const char *id = argc == 2 ? argv[1] : NULL; - for (int i = 0; i < config->bars->length; ++i) { - struct bar_config *bar = config->bars->items[i]; - if (id) { - if (strcmp(id, bar->id) == 0) { - error = bar_set_mode(bar, mode); - break; - } - } else if ((error = bar_set_mode(bar, mode))) { - break; - } - } - } - return error ? error : cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/bar/modifier.c b/sway/commands/bar/modifier.c deleted file mode 100644 index 983d21795..000000000 --- a/sway/commands/bar/modifier.c +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/input/keyboard.h" -#include "log.h" -#include "stringop.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; - } - - uint32_t mod = 0; - if (strcmp(argv[0], "none") != 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; - } else if (strcmp(split->items[i], "none") == 0) { - error = cmd_results_new(CMD_INVALID, - "none cannot be used along with other modifiers"); - list_free_items_and_destroy(split); - return error; - } else { - error = cmd_results_new(CMD_INVALID, - "Unknown modifier '%s'", (char *)split->items[i]); - list_free_items_and_destroy(split); - return error; - } - } - list_free_items_and_destroy(split); - } - config->current_bar->modifier = mod; - sway_log(SWAY_DEBUG, - "Show/Hide the bar when pressing '%s' in hide mode.", argv[0]); - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/bar/output.c b/sway/commands/bar/output.c deleted file mode 100644 index cac1d0568..000000000 --- a/sway/commands/bar/output.c +++ /dev/null @@ -1,49 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#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; - } - - const char *output = argv[0]; - list_t *outputs = config->current_bar->outputs; - if (!outputs) { - outputs = create_list(); - config->current_bar->outputs = outputs; - } - - bool add_output = true; - if (strcmp("*", output) == 0) { - // remove all previous defined outputs and replace with '*' - while (outputs->length) { - free(outputs->items[0]); - list_del(outputs, 0); - } - } else { - // only add output if not already defined, if the list has '*', remove - // it, in favor of a manual list - for (int i = 0; i < outputs->length; ++i) { - const char *find = outputs->items[i]; - if (strcmp("*", find) == 0) { - free(outputs->items[i]); - list_del(outputs, i); - } else if (strcmp(output, find) == 0) { - add_output = false; - break; - } - } - } - - if (add_output) { - list_add(outputs, strdup(output)); - sway_log(SWAY_DEBUG, "Adding bar: '%s' to output '%s'", - config->current_bar->id, output); - } - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/bar/pango_markup.c b/sway/commands/bar/pango_markup.c deleted file mode 100644 index ee51390da..000000000 --- a/sway/commands/bar/pango_markup.c +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "log.h" -#include "util.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; - } - config->current_bar->pango_markup = - parse_boolean(argv[0], config->current_bar->pango_markup); - if (config->current_bar->pango_markup) { - sway_log(SWAY_DEBUG, "Enabling pango markup for bar: %s", - config->current_bar->id); - } else { - sway_log(SWAY_DEBUG, "Disabling pango markup for bar: %s", - config->current_bar->id); - } - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/bar/position.c b/sway/commands/bar/position.c deleted file mode 100644 index b207de0bf..000000000 --- a/sway/commands/bar/position.c +++ /dev/null @@ -1,23 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#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; - } - char *valid[] = { "top", "bottom" }; - for (size_t i = 0; i < sizeof(valid) / sizeof(valid[0]); ++i) { - if (strcasecmp(valid[i], argv[0]) == 0) { - sway_log(SWAY_DEBUG, "Setting bar position '%s' for bar: %s", - argv[0], config->current_bar->id); - free(config->current_bar->position); - config->current_bar->position = strdup(argv[0]); - return cmd_results_new(CMD_SUCCESS, NULL); - } - } - return cmd_results_new(CMD_INVALID, "Invalid value %s", argv[0]); -} diff --git a/sway/commands/bar/separator_symbol.c b/sway/commands/bar/separator_symbol.c deleted file mode 100644 index 6737d4d24..000000000 --- a/sway/commands/bar/separator_symbol.c +++ /dev/null @@ -1,16 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#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; - } - free(config->current_bar->separator_symbol); - config->current_bar->separator_symbol = strdup(argv[0]); - sway_log(SWAY_DEBUG, "Settings separator_symbol '%s' for bar: %s", - config->current_bar->separator_symbol, config->current_bar->id); - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/bar/status_command.c b/sway/commands/bar/status_command.c deleted file mode 100644 index bb92e8e07..000000000 --- a/sway/commands/bar/status_command.c +++ /dev/null @@ -1,23 +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; - } - free(config->current_bar->status_command); - config->current_bar->status_command = NULL; - - char *new_command = join_args(argv, argc); - if (strcmp(new_command, "-") != 0) { - config->current_bar->status_command = new_command; - sway_log(SWAY_DEBUG, "Feeding bar with status command: %s", - config->current_bar->status_command); - } else { - free(new_command); - } - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/bar/status_edge_padding.c b/sway/commands/bar/status_edge_padding.c deleted file mode 100644 index 75ef86f09..000000000 --- a/sway/commands/bar/status_edge_padding.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "log.h" - -struct cmd_results *bar_cmd_status_edge_padding(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "status_edge_padding", EXPECTED_EQUAL_TO, 1))) { - return error; - } - char *end; - int padding = strtol(argv[0], &end, 10); - if (strlen(end) || padding < 0) { - return cmd_results_new(CMD_INVALID, - "Padding must be a positive integer"); - } - config->current_bar->status_edge_padding = padding; - sway_log(SWAY_DEBUG, "Status edge padding on bar %s: %d", - config->current_bar->id, config->current_bar->status_edge_padding); - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/bar/status_padding.c b/sway/commands/bar/status_padding.c deleted file mode 100644 index 0c65e516e..000000000 --- a/sway/commands/bar/status_padding.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "log.h" - -struct cmd_results *bar_cmd_status_padding(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "status_padding", EXPECTED_EQUAL_TO, 1))) { - return error; - } - char *end; - int padding = strtol(argv[0], &end, 10); - if (strlen(end) || padding < 0) { - return cmd_results_new(CMD_INVALID, - "Padding must be a positive integer"); - } - config->current_bar->status_padding = padding; - sway_log(SWAY_DEBUG, "Status padding on bar %s: %d", - config->current_bar->id, config->current_bar->status_padding); - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/bar/strip_workspace_name.c b/sway/commands/bar/strip_workspace_name.c deleted file mode 100644 index 764321a89..000000000 --- a/sway/commands/bar/strip_workspace_name.c +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "log.h" -#include "util.h" - -struct cmd_results *bar_cmd_strip_workspace_name(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, - "strip_workspace_name", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - config->current_bar->strip_workspace_name = - parse_boolean(argv[0], config->current_bar->strip_workspace_name); - - if (config->current_bar->strip_workspace_name) { - config->current_bar->strip_workspace_numbers = false; - - sway_log(SWAY_DEBUG, "Stripping workspace name on bar: %s", - config->current_bar->id); - } else { - sway_log(SWAY_DEBUG, "Enabling workspace name on bar: %s", - config->current_bar->id); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/bar/strip_workspace_numbers.c b/sway/commands/bar/strip_workspace_numbers.c deleted file mode 100644 index 2d7fe1a7f..000000000 --- a/sway/commands/bar/strip_workspace_numbers.c +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "log.h" -#include "util.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; - } - - config->current_bar->strip_workspace_numbers = - parse_boolean(argv[0], config->current_bar->strip_workspace_numbers); - - if (config->current_bar->strip_workspace_numbers) { - config->current_bar->strip_workspace_name = false; - - sway_log(SWAY_DEBUG, "Stripping workspace numbers on bar: %s", - config->current_bar->id); - } else { - sway_log(SWAY_DEBUG, "Enabling workspace numbers on bar: %s", - config->current_bar->id); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/bar/swaybar_command.c b/sway/commands/bar/swaybar_command.c deleted file mode 100644 index 0892a898a..000000000 --- a/sway/commands/bar/swaybar_command.c +++ /dev/null @@ -1,16 +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; - } - free(config->current_bar->swaybar_command); - config->current_bar->swaybar_command = join_args(argv, argc); - sway_log(SWAY_DEBUG, "Using custom swaybar command: %s", - config->current_bar->swaybar_command); - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/bar/tray_bind.c b/sway/commands/bar/tray_bind.c deleted file mode 100644 index 3dc9bc4cc..000000000 --- a/sway/commands/bar/tray_bind.c +++ /dev/null @@ -1,95 +0,0 @@ -#include -#include "config.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/input/cursor.h" -#include "log.h" - -static struct cmd_results *tray_bind(int argc, char **argv, bool code) { -#if HAVE_TRAY - const char *command = code ? "bar tray_bindcode" : "bar tray_bindsym"; - struct cmd_results *error = NULL; - if ((error = checkarg(argc, command, EXPECTED_EQUAL_TO, 2))) { - return error; - } - - struct tray_binding *binding = calloc(1, sizeof(struct tray_binding)); - if (!binding) { - return cmd_results_new(CMD_FAILURE, "Unable to allocate tray binding"); - } - - char *message = NULL; - if (code) { - binding->button = get_mouse_bindcode(argv[0], &message); - } else { - binding->button = get_mouse_bindsym(argv[0], &message); - } - if (message) { - free(binding); - error = cmd_results_new(CMD_INVALID, "%s", message); - free(message); - return error; - } else if (!binding->button) { - free(binding); - return cmd_results_new(CMD_INVALID, "Unknown button %s", argv[0]); - } - const char *name = get_mouse_button_name(binding->button); - - static const char *commands[] = { - "ContextMenu", - "Activate", - "SecondaryActivate", - "ScrollDown", - "ScrollLeft", - "ScrollRight", - "ScrollUp", - "nop" - }; - - for (size_t i = 0; i < sizeof(commands) / sizeof(commands[0]); ++i) { - if (strcasecmp(argv[1], commands[i]) == 0) { - binding->command = commands[i]; - } - } - if (!binding->command) { - free(binding); - return cmd_results_new(CMD_INVALID, "[Bar %s] Invalid tray command %s", - config->current_bar->id, argv[1]); - } - - bool overwritten = false; - struct tray_binding *other = NULL; - wl_list_for_each(other, &config->current_bar->tray_bindings, link) { - if (other->button == binding->button) { - overwritten = true; - other->command = binding->command; - free(binding); - binding = other; - sway_log(SWAY_DEBUG, - "[bar %s] Updated tray binding for %u (%s) to %s", - config->current_bar->id, binding->button, name, - binding->command); - break; - } - } - if (!overwritten) { - wl_list_insert(&config->current_bar->tray_bindings, &binding->link); - sway_log(SWAY_DEBUG, "[bar %s] Added tray binding for %u (%s) to %s", - config->current_bar->id, binding->button, name, - binding->command); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -#else - return cmd_results_new(CMD_INVALID, - "Sway has been compiled without tray support"); -#endif -} - -struct cmd_results *bar_cmd_tray_bindcode(int argc, char **argv) { - return tray_bind(argc, argv, true); -} - -struct cmd_results *bar_cmd_tray_bindsym(int argc, char **argv) { - return tray_bind(argc, argv, false); -} diff --git a/sway/commands/bar/tray_output.c b/sway/commands/bar/tray_output.c deleted file mode 100644 index eb3b486e2..000000000 --- a/sway/commands/bar/tray_output.c +++ /dev/null @@ -1,50 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include "config.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "list.h" -#include "log.h" - -struct cmd_results *bar_cmd_tray_output(int argc, char **argv) { -#if HAVE_TRAY - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "tray_output", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - list_t *outputs = config->current_bar->tray_outputs; - if (!outputs) { - config->current_bar->tray_outputs = outputs = create_list(); - } - - if (strcmp(argv[0], "none") == 0) { - sway_log(SWAY_DEBUG, "Hiding tray on bar: %s", config->current_bar->id); - for (int i = 0; i < outputs->length; ++i) { - free(outputs->items[i]); - } - outputs->length = 0; - } else if (strcmp(argv[0], "*") == 0) { - sway_log(SWAY_DEBUG, "Showing tray on all outputs for bar: %s", - config->current_bar->id); - while (outputs->length) { - free(outputs->items[0]); - list_del(outputs, 0); - } - return cmd_results_new(CMD_SUCCESS, NULL); - } else { - sway_log(SWAY_DEBUG, "Showing tray on output '%s' for bar: %s", argv[0], - config->current_bar->id); - if (outputs->length == 1 && strcmp(outputs->items[0], "none") == 0) { - free(outputs->items[0]); - list_del(outputs, 0); - } - } - list_add(outputs, strdup(argv[0])); - - return cmd_results_new(CMD_SUCCESS, NULL); -#else - return cmd_results_new(CMD_INVALID, - "Sway has been compiled without tray support"); -#endif -} diff --git a/sway/commands/bar/tray_padding.c b/sway/commands/bar/tray_padding.c deleted file mode 100644 index f90b6003f..000000000 --- a/sway/commands/bar/tray_padding.c +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include -#include "config.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "log.h" - -struct cmd_results *bar_cmd_tray_padding(int argc, char **argv) { -#if HAVE_TRAY - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "tray_padding", EXPECTED_AT_LEAST, 1))) { - return error; - } - if ((error = checkarg(argc, "tray_padding", EXPECTED_AT_MOST, 2))) { - return error; - } - - struct bar_config *bar = config->current_bar; - - char *end; - int padding = strtol(argv[0], &end, 10); - if (padding < 0 || (*end != '\0' && strcasecmp(end, "px") != 0)) { - return cmd_results_new(CMD_INVALID, - "[Bar %s] Invalid tray padding value: %s", bar->id, argv[0]); - } - - if (argc == 2 && strcasecmp(argv[1], "px") != 0) { - return cmd_results_new(CMD_INVALID, - "Expected 'tray_padding [px]'"); - } - - sway_log(SWAY_DEBUG, "[Bar %s] Setting tray padding to %d", bar->id, padding); - config->current_bar->tray_padding = padding; - return cmd_results_new(CMD_SUCCESS, NULL); -#else - return cmd_results_new(CMD_INVALID, - "Sway has been compiled without tray support"); -#endif -} diff --git a/sway/commands/bar/workspace_buttons.c b/sway/commands/bar/workspace_buttons.c deleted file mode 100644 index 6bfb16165..000000000 --- a/sway/commands/bar/workspace_buttons.c +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "log.h" -#include "util.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; - } - config->current_bar->workspace_buttons = - parse_boolean(argv[0], config->current_bar->workspace_buttons); - if (config->current_bar->workspace_buttons) { - sway_log(SWAY_DEBUG, "Enabling workspace buttons on bar: %s", - config->current_bar->id); - } else { - sway_log(SWAY_DEBUG, "Disabling workspace buttons on bar: %s", - config->current_bar->id); - } - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/bar/workspace_min_width.c b/sway/commands/bar/workspace_min_width.c deleted file mode 100644 index 8d65592ca..000000000 --- a/sway/commands/bar/workspace_min_width.c +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include -#include "config.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "log.h" - -struct cmd_results *bar_cmd_workspace_min_width(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "workspace_min_width", EXPECTED_AT_LEAST, 1))) { - return error; - } - - struct bar_config *bar = config->current_bar; - - char *end; - int min_width = strtol(argv[0], &end, 10); - if (min_width < 0 || (*end != '\0' && strcasecmp(end, "px") != 0)) { - return cmd_results_new(CMD_INVALID, - "[Bar %s] Invalid minimum workspace button width value: %s", - bar->id, argv[0]); - } - - if (argc == 2 && strcasecmp(argv[1], "px") != 0) { - return cmd_results_new(CMD_INVALID, - "Expected 'workspace_min_width [px]'"); - } - - sway_log(SWAY_DEBUG, "[Bar %s] Setting minimum workspace button width to %d", - bar->id, min_width); - config->current_bar->workspace_min_width = min_width; - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/bar/wrap_scroll.c b/sway/commands/bar/wrap_scroll.c deleted file mode 100644 index f57e393df..000000000 --- a/sway/commands/bar/wrap_scroll.c +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "log.h" -#include "util.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; - } - config->current_bar->wrap_scroll = - parse_boolean(argv[0], config->current_bar->wrap_scroll); - if (config->current_bar->wrap_scroll) { - sway_log(SWAY_DEBUG, "Enabling wrap scroll on bar: %s", - config->current_bar->id); - } else { - sway_log(SWAY_DEBUG, "Disabling wrap scroll on bar: %s", - config->current_bar->id); - } - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/bind.c b/sway/commands/bind.c deleted file mode 100644 index 979e178fd..000000000 --- a/sway/commands/bind.c +++ /dev/null @@ -1,762 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/desktop/transaction.h" -#include "sway/input/cursor.h" -#include "sway/input/keyboard.h" -#include "sway/ipc-server.h" -#include "list.h" -#include "log.h" -#include "stringop.h" -#include "util.h" - -int binding_order = 0; - -void free_sway_binding(struct sway_binding *binding) { - if (!binding) { - return; - } - - list_free_items_and_destroy(binding->keys); - list_free_items_and_destroy(binding->syms); - free(binding->input); - free(binding->command); - free(binding); -} - -void free_switch_binding(struct sway_switch_binding *binding) { - if (!binding) { - return; - } - free(binding->command); - free(binding); -} - -/** - * Returns true if the bindings have the same switch type and state combinations. - */ -static bool binding_switch_compare(struct sway_switch_binding *binding_a, - struct sway_switch_binding *binding_b) { - if (binding_a->type != binding_b->type) { - return false; - } - if (binding_a->trigger != binding_b->trigger) { - return false; - } - if ((binding_a->flags & BINDING_LOCKED) != - (binding_b->flags & BINDING_LOCKED)) { - return false; - } - return true; -} - -/** - * Returns true if the bindings have the same key and modifier combinations. - * Note that keyboard layout is not considered, so the bindings might actually - * not be equivalent on some layouts. - */ -static bool binding_key_compare(struct sway_binding *binding_a, - struct sway_binding *binding_b) { - if (strcmp(binding_a->input, binding_b->input) != 0) { - return false; - } - - if (binding_a->type != binding_b->type) { - return false; - } - - uint32_t conflict_generating_flags = BINDING_RELEASE | BINDING_BORDER - | BINDING_CONTENTS | BINDING_TITLEBAR | BINDING_LOCKED - | BINDING_INHIBITED; - if ((binding_a->flags & conflict_generating_flags) != - (binding_b->flags & conflict_generating_flags)) { - return false; - } - - if (binding_a->group != binding_b->group) { - return false; - } - - if (binding_a->modifiers ^ binding_b->modifiers) { - return false; - } - - if (binding_a->keys->length != binding_b->keys->length) { - return false; - } - - // Keys are sorted - int keys_len = binding_a->keys->length; - for (int i = 0; i < keys_len; ++i) { - uint32_t key_a = *(uint32_t *)binding_a->keys->items[i]; - uint32_t key_b = *(uint32_t *)binding_b->keys->items[i]; - if (key_a != key_b) { - return false; - } - } - - return true; -} - -static int key_qsort_cmp(const void *keyp_a, const void *keyp_b) { - uint32_t key_a = **(uint32_t **)keyp_a; - uint32_t key_b = **(uint32_t **)keyp_b; - return (key_a < key_b) ? -1 : ((key_a > key_b) ? 1 : 0); -} - -/** - * From a keycode, bindcode, or bindsym name and the most likely binding type, - * identify the appropriate numeric value corresponding to the key. Return NULL - * and set *key_val if successful, otherwise return a specific error. Change - * the value of *type if the initial type guess was incorrect and if this - * was the first identified key. - */ -static struct cmd_results *identify_key(const char* name, bool first_key, - uint32_t* key_val, enum binding_input_type* type) { - if (*type == BINDING_MOUSECODE) { - // check for mouse bindcodes - char *message = NULL; - uint32_t button = get_mouse_bindcode(name, &message); - if (!button) { - if (message) { - struct cmd_results *error = - cmd_results_new(CMD_INVALID, "%s", message); - free(message); - return error; - } else { - return cmd_results_new(CMD_INVALID, - "Unknown button code %s", name); - } - } - *key_val = button; - } else if (*type == BINDING_MOUSESYM) { - // check for mouse bindsyms (x11 buttons or event names) - char *message = NULL; - uint32_t button = get_mouse_bindsym(name, &message); - if (!button) { - if (message) { - struct cmd_results *error = - cmd_results_new(CMD_INVALID, "%s", message); - free(message); - return error; - } else { - return cmd_results_new(CMD_INVALID, "Unknown button %s", name); - } - } - *key_val = button; - } else if (*type == BINDING_KEYCODE) { - // check for keycode. If it is the first key, allow mouse bindcodes - if (first_key) { - char *message = NULL; - uint32_t button = get_mouse_bindcode(name, &message); - free(message); - if (button) { - *type = BINDING_MOUSECODE; - *key_val = button; - return NULL; - } - } - - xkb_keycode_t keycode = strtol(name, NULL, 10); - if (!xkb_keycode_is_legal_ext(keycode)) { - if (first_key) { - return cmd_results_new(CMD_INVALID, - "Invalid keycode or button code '%s'", name); - } else { - return cmd_results_new(CMD_INVALID, - "Invalid keycode '%s'", name); - } - } - *key_val = keycode; - } else { - // check for keysym. If it is the first key, allow mouse bindsyms - if (first_key) { - char *message = NULL; - uint32_t button = get_mouse_bindsym(name, &message); - if (message) { - struct cmd_results *error = - cmd_results_new(CMD_INVALID, "%s", message); - free(message); - return error; - } else if (button) { - *type = BINDING_MOUSESYM; - *key_val = button; - return NULL; - } - } - - xkb_keysym_t keysym = xkb_keysym_from_name(name, - XKB_KEYSYM_CASE_INSENSITIVE); - if (!keysym) { - if (first_key) { - return cmd_results_new(CMD_INVALID, - "Unknown key or button '%s'", name); - } else { - return cmd_results_new(CMD_INVALID, "Unknown key '%s'", name); - } - } - *key_val = keysym; - } - return NULL; -} - -static struct cmd_results *switch_binding_add( - struct sway_switch_binding *binding, const char *bindtype, - const char *switchcombo, bool warn) { - list_t *mode_bindings = config->current_mode->switch_bindings; - // overwrite the binding if it already exists - bool overwritten = false; - for (int i = 0; i < mode_bindings->length; ++i) { - struct sway_switch_binding *config_binding = mode_bindings->items[i]; - if (binding_switch_compare(binding, config_binding)) { - sway_log(SWAY_INFO, "Overwriting binding '%s' to `%s` from `%s`", - switchcombo, binding->command, config_binding->command); - if (warn) { - config_add_swaynag_warning("Overwriting binding" - "'%s' to `%s` from `%s`", - switchcombo, binding->command, - config_binding->command); - } - free_switch_binding(config_binding); - mode_bindings->items[i] = binding; - overwritten = true; - } - } - - if (!overwritten) { - list_add(mode_bindings, binding); - sway_log(SWAY_DEBUG, "%s - Bound %s to command `%s`", - bindtype, switchcombo, binding->command); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} - -static struct cmd_results *switch_binding_remove( - struct sway_switch_binding *binding, const char *bindtype, - const char *switchcombo) { - list_t *mode_bindings = config->current_mode->switch_bindings; - for (int i = 0; i < mode_bindings->length; ++i) { - struct sway_switch_binding *config_binding = mode_bindings->items[i]; - if (binding_switch_compare(binding, config_binding)) { - free_switch_binding(config_binding); - free_switch_binding(binding); - list_del(mode_bindings, i); - sway_log(SWAY_DEBUG, "%s - Unbound %s switch", - bindtype, switchcombo); - return cmd_results_new(CMD_SUCCESS, NULL); - } - } - - free_switch_binding(binding); - return cmd_results_new(CMD_FAILURE, "Could not find switch binding `%s`", - switchcombo); -} - -/** - * Insert or update the binding. - * Return the binding which has been replaced or NULL. - */ -static struct sway_binding *binding_upsert(struct sway_binding *binding, - list_t *mode_bindings) { - for (int i = 0; i < mode_bindings->length; ++i) { - struct sway_binding *config_binding = mode_bindings->items[i]; - if (binding_key_compare(binding, config_binding)) { - mode_bindings->items[i] = binding; - return config_binding; - } - } - - list_add(mode_bindings, binding); - return NULL; -} - -static struct cmd_results *binding_add(struct sway_binding *binding, - list_t *mode_bindings, const char *bindtype, - const char *keycombo, bool warn) { - struct sway_binding *config_binding = binding_upsert(binding, mode_bindings); - - if (config_binding) { - sway_log(SWAY_INFO, "Overwriting binding '%s' for device '%s' " - "to `%s` from `%s`", keycombo, binding->input, - binding->command, config_binding->command); - if (warn) { - config_add_swaynag_warning("Overwriting binding" - "'%s' for device '%s' to `%s` from `%s`", - keycombo, binding->input, binding->command, - config_binding->command); - } - free_sway_binding(config_binding); - } else { - sway_log(SWAY_DEBUG, "%s - Bound %s to command `%s` for device '%s'", - bindtype, keycombo, binding->command, binding->input); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} - -static struct cmd_results *binding_remove(struct sway_binding *binding, - list_t *mode_bindings, const char *bindtype, - const char *keycombo) { - for (int i = 0; i < mode_bindings->length; ++i) { - struct sway_binding *config_binding = mode_bindings->items[i]; - if (binding_key_compare(binding, config_binding)) { - sway_log(SWAY_DEBUG, "%s - Unbound `%s` from device '%s'", - bindtype, keycombo, binding->input); - free_sway_binding(config_binding); - free_sway_binding(binding); - list_del(mode_bindings, i); - return cmd_results_new(CMD_SUCCESS, NULL); - } - } - free_sway_binding(binding); - return cmd_results_new(CMD_FAILURE, "Could not find binding `%s` " - "for the given flags", keycombo); -} - -static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, - bool bindcode, bool unbind) { - const char *bindtype; - int minargs = 2; - if (unbind) { - bindtype = bindcode ? "unbindcode" : "unbindsym"; - minargs--; - } else { - bindtype = bindcode ? "bindcode": "bindsym"; - } - - struct cmd_results *error = NULL; - if ((error = checkarg(argc, bindtype, EXPECTED_AT_LEAST, minargs))) { - return error; - } - - struct sway_binding *binding = calloc(1, sizeof(struct sway_binding)); - if (!binding) { - return cmd_results_new(CMD_FAILURE, "Unable to allocate binding"); - } - binding->input = strdup("*"); - binding->keys = create_list(); - binding->group = XKB_LAYOUT_INVALID; - binding->modifiers = 0; - binding->flags = 0; - binding->type = bindcode ? BINDING_KEYCODE : BINDING_KEYSYM; - - bool exclude_titlebar = false; - bool warn = true; - - while (argc > 0) { - if (strcmp("--release", argv[0]) == 0) { - binding->flags |= BINDING_RELEASE; - } else if (strcmp("--locked", argv[0]) == 0) { - binding->flags |= BINDING_LOCKED; - } else if (strcmp("--inhibited", argv[0]) == 0) { - binding->flags |= BINDING_INHIBITED; - } else if (strcmp("--whole-window", argv[0]) == 0) { - binding->flags |= BINDING_BORDER | BINDING_CONTENTS | BINDING_TITLEBAR; - } else if (strcmp("--border", argv[0]) == 0) { - binding->flags |= BINDING_BORDER; - } else if (strcmp("--to-code", argv[0]) == 0) { - if (!bindcode) { - binding->flags |= BINDING_CODE; - } - } else if (strcmp("--exclude-titlebar", argv[0]) == 0) { - exclude_titlebar = true; - } else if (strncmp("--input-device=", argv[0], - strlen("--input-device=")) == 0) { - free(binding->input); - binding->input = strdup(argv[0] + strlen("--input-device=")); - strip_quotes(binding->input); - } else if (strcmp("--no-warn", argv[0]) == 0) { - warn = false; - } else if (strcmp("--no-repeat", argv[0]) == 0) { - binding->flags |= BINDING_NOREPEAT; - } else { - break; - } - argv++; - argc--; - } - if (binding->flags & (BINDING_BORDER | BINDING_CONTENTS | BINDING_TITLEBAR) - || exclude_titlebar) { - binding->type = binding->type == BINDING_KEYCODE ? - BINDING_MOUSECODE : BINDING_MOUSESYM; - } - - if (argc < minargs) { - free_sway_binding(binding); - return cmd_results_new(CMD_FAILURE, - "Invalid %s command " - "(expected at least %d non-option arguments, got %d)", - bindtype, minargs, argc); - } - - list_t *split = split_string(argv[0], "+"); - for (int i = 0; i < split->length; ++i) { - // Check for group - if (strncmp(split->items[i], "Group", strlen("Group")) == 0) { - if (binding->group != XKB_LAYOUT_INVALID) { - free_sway_binding(binding); - list_free_items_and_destroy(split); - return cmd_results_new(CMD_FAILURE, - "Only one group can be specified"); - } - char *end; - int group = strtol(split->items[i] + strlen("Group"), &end, 10); - if (group < 1 || group > 4 || end[0] != '\0') { - free_sway_binding(binding); - list_free_items_and_destroy(split); - return cmd_results_new(CMD_FAILURE, "Invalid group"); - } - binding->group = group - 1; - continue; - } else if (strcmp(split->items[i], "Mode_switch") == 0) { - // For full i3 compatibility, Mode_switch is an alias for Group2 - if (binding->group != XKB_LAYOUT_INVALID) { - free_sway_binding(binding); - list_free_items_and_destroy(split); - return cmd_results_new(CMD_FAILURE, - "Only one group can be specified"); - } - binding->group = 1; - } - - // Check for a modifier key - uint32_t mod; - if ((mod = get_modifier_mask_by_name(split->items[i])) > 0) { - binding->modifiers |= mod; - continue; - } - - // Identify the key and possibly change binding->type - uint32_t key_val = 0; - error = identify_key(split->items[i], binding->keys->length == 0, - &key_val, &binding->type); - if (error) { - free_sway_binding(binding); - list_free(split); - return error; - } - - uint32_t *key = calloc(1, sizeof(uint32_t)); - if (!key) { - free_sway_binding(binding); - list_free_items_and_destroy(split); - return cmd_results_new(CMD_FAILURE, - "Unable to allocate binding key"); - } - *key = key_val; - list_add(binding->keys, key); - } - list_free_items_and_destroy(split); - - // refine region of interest for mouse binding once we are certain - // that this is one - if (exclude_titlebar) { - binding->flags &= ~BINDING_TITLEBAR; - } else if (binding->type == BINDING_MOUSECODE - || binding->type == BINDING_MOUSESYM) { - binding->flags |= BINDING_TITLEBAR; - } - - // sort ascending - list_qsort(binding->keys, key_qsort_cmp); - - // translate keysyms into keycodes - if (!translate_binding(binding)) { - sway_log(SWAY_INFO, - "Unable to translate bindsym into bindcode: %s", argv[0]); - } - - list_t *mode_bindings; - if (binding->type == BINDING_KEYCODE) { - mode_bindings = config->current_mode->keycode_bindings; - } else if (binding->type == BINDING_KEYSYM) { - mode_bindings = config->current_mode->keysym_bindings; - } else { - mode_bindings = config->current_mode->mouse_bindings; - } - - if (unbind) { - return binding_remove(binding, mode_bindings, bindtype, argv[0]); - } - - binding->command = join_args(argv + 1, argc - 1); - binding->order = binding_order++; - return binding_add(binding, mode_bindings, bindtype, argv[0], warn); -} - -struct cmd_results *cmd_bind_or_unbind_switch(int argc, char **argv, - bool unbind) { - int minargs = 2; - char *bindtype = "bindswitch"; - if (unbind) { - minargs--; - bindtype = "unbindswitch"; - } - - struct cmd_results *error = NULL; - if ((error = checkarg(argc, bindtype, EXPECTED_AT_LEAST, minargs))) { - return error; - } - struct sway_switch_binding *binding = calloc(1, sizeof(struct sway_switch_binding)); - if (!binding) { - return cmd_results_new(CMD_FAILURE, "Unable to allocate binding"); - } - - bool warn = true; - - // Handle flags - while (argc > 0) { - if (strcmp("--locked", argv[0]) == 0) { - binding->flags |= BINDING_LOCKED; - } else if (strcmp("--no-warn", argv[0]) == 0) { - warn = false; - } else if (strcmp("--reload", argv[0]) == 0) { - binding->flags |= BINDING_RELOAD; - } else { - break; - } - argv++; - argc--; - } - - if (argc < minargs) { - free(binding); - return cmd_results_new(CMD_FAILURE, - "Invalid %s command (expected at least %d " - "non-option arguments, got %d)", bindtype, minargs, argc); - } - - list_t *split = split_string(argv[0], ":"); - if (split->length != 2) { - free_switch_binding(binding); - return cmd_results_new(CMD_FAILURE, - "Invalid %s command (expected binding with the form " - ":)", bindtype); - } - if (strcmp(split->items[0], "tablet") == 0) { - binding->type = WLR_SWITCH_TYPE_TABLET_MODE; - } else if (strcmp(split->items[0], "lid") == 0) { - binding->type = WLR_SWITCH_TYPE_LID; - } else { - free_switch_binding(binding); - return cmd_results_new(CMD_FAILURE, - "Invalid %s command (expected switch binding: " - "unknown switch %s)", bindtype, - (const char *)split->items[0]); - } - if (strcmp(split->items[1], "on") == 0) { - binding->trigger = SWAY_SWITCH_TRIGGER_ON; - } else if (strcmp(split->items[1], "off") == 0) { - binding->trigger = SWAY_SWITCH_TRIGGER_OFF; - } else if (strcmp(split->items[1], "toggle") == 0) { - binding->trigger = SWAY_SWITCH_TRIGGER_TOGGLE; - } else { - free_switch_binding(binding); - return cmd_results_new(CMD_FAILURE, - "Invalid %s command " - "(expected switch state: unknown state %s)", - bindtype, (const char *)split->items[1]); - } - list_free_items_and_destroy(split); - - if (unbind) { - return switch_binding_remove(binding, bindtype, argv[0]); - } - binding->command = join_args(argv + 1, argc - 1); - return switch_binding_add(binding, bindtype, argv[0], warn); -} - -struct cmd_results *cmd_bindsym(int argc, char **argv) { - return cmd_bindsym_or_bindcode(argc, argv, false, false); -} - -struct cmd_results *cmd_bindcode(int argc, char **argv) { - return cmd_bindsym_or_bindcode(argc, argv, true, false); -} - -struct cmd_results *cmd_unbindsym(int argc, char **argv) { - return cmd_bindsym_or_bindcode(argc, argv, false, true); -} - -struct cmd_results *cmd_unbindcode(int argc, char **argv) { - return cmd_bindsym_or_bindcode(argc, argv, true, true); -} - -struct cmd_results *cmd_bindswitch(int argc, char **argv) { - return cmd_bind_or_unbind_switch(argc, argv, false); -} - -struct cmd_results *cmd_unbindswitch(int argc, char **argv) { - return cmd_bind_or_unbind_switch(argc, argv, true); -} - -/** - * Execute the command associated to a binding - */ -void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) { - if (!config->active) { - sway_log(SWAY_DEBUG, "deferring command for binding: %s", - binding->command); - struct sway_binding *deferred = calloc(1, sizeof(struct sway_binding)); - if (!deferred) { - sway_log(SWAY_ERROR, "Failed to allocate deferred binding"); - return; - } - memcpy(deferred, binding, sizeof(struct sway_binding)); - deferred->command = binding->command ? strdup(binding->command) : NULL; - list_add(seat->deferred_bindings, deferred); - return; - } - - sway_log(SWAY_DEBUG, "running command for binding: %s", binding->command); - struct sway_container *con = NULL; - if (binding->type == BINDING_MOUSESYM - || binding->type == BINDING_MOUSECODE) { - struct wlr_surface *surface = NULL; - double sx, sy; - struct sway_node *node = node_at_coords(seat, - seat->cursor->cursor->x, seat->cursor->cursor->y, - &surface, &sx, &sy); - if (node && node->type == N_CONTAINER) { - con = node->sway_container; - } - } - - list_t *res_list = execute_command(binding->command, seat, con); - bool success = true; - for (int i = 0; i < res_list->length; ++i) { - struct cmd_results *results = res_list->items[i]; - if (results->status != CMD_SUCCESS) { - sway_log(SWAY_DEBUG, "could not run command for binding: %s (%s)", - binding->command, results->error); - success = false; - } - free_cmd_results(results); - } - list_free(res_list); - if (success) { - ipc_event_binding(binding); - } - - transaction_commit_dirty(); -} - -/** - * The last found keycode associated with the keysym - * and the total count of matches. - */ -struct keycode_matches { - xkb_keysym_t keysym; - xkb_keycode_t keycode; - int count; -}; - -/** - * Iterate through keycodes in the keymap to find ones matching - * the specified keysym. - */ -static void find_keycode(struct xkb_keymap *keymap, - xkb_keycode_t keycode, void *data) { - xkb_keysym_t keysym = xkb_state_key_get_one_sym( - config->keysym_translation_state, keycode); - - if (keysym == XKB_KEY_NoSymbol) { - return; - } - - struct keycode_matches *matches = data; - if (matches->keysym == keysym) { - matches->keycode = keycode; - matches->count++; - } -} - -/** - * Return the keycode for the specified keysym. - */ -static struct keycode_matches get_keycode_for_keysym(xkb_keysym_t keysym) { - struct keycode_matches matches = { - .keysym = keysym, - .keycode = XKB_KEYCODE_INVALID, - .count = 0, - }; - - xkb_keymap_key_for_each( - xkb_state_get_keymap(config->keysym_translation_state), - find_keycode, &matches); - return matches; -} - -bool translate_binding(struct sway_binding *binding) { - if ((binding->flags & BINDING_CODE) == 0) { - return true; - } - - switch (binding->type) { - // a bindsym to translate - case BINDING_KEYSYM: - binding->syms = binding->keys; - binding->keys = create_list(); - break; - // a bindsym to re-translate - case BINDING_KEYCODE: - list_free_items_and_destroy(binding->keys); - binding->keys = create_list(); - break; - default: - return true; - } - - for (int i = 0; i < binding->syms->length; ++i) { - xkb_keysym_t *keysym = binding->syms->items[i]; - struct keycode_matches matches = get_keycode_for_keysym(*keysym); - - if (matches.count != 1) { - sway_log(SWAY_INFO, "Unable to convert keysym %" PRIu32 " into" - " a single keycode (found %d matches)", - *keysym, matches.count); - goto error; - } - - xkb_keycode_t *keycode = malloc(sizeof(xkb_keycode_t)); - if (!keycode) { - sway_log(SWAY_ERROR, "Unable to allocate memory for a keycode"); - goto error; - } - - *keycode = matches.keycode; - list_add(binding->keys, keycode); - } - - list_qsort(binding->keys, key_qsort_cmp); - binding->type = BINDING_KEYCODE; - return true; - -error: - list_free_items_and_destroy(binding->keys); - binding->type = BINDING_KEYSYM; - binding->keys = binding->syms; - binding->syms = NULL; - return false; -} - -void binding_add_translated(struct sway_binding *binding, - list_t *mode_bindings) { - struct sway_binding *config_binding = - binding_upsert(binding, mode_bindings); - - if (config_binding) { - sway_log(SWAY_INFO, "Overwriting binding for device '%s' " - "to `%s` from `%s`", binding->input, - binding->command, config_binding->command); - free_sway_binding(config_binding); - } -} diff --git a/sway/commands/blur.c b/sway/commands/blur.c deleted file mode 100644 index 52e3fdb93..000000000 --- a/sway/commands/blur.c +++ /dev/null @@ -1,32 +0,0 @@ -#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/output.h" -#include "util.h" - -struct cmd_results *cmd_blur(int argc, char **argv) { - struct cmd_results *error = checkarg(argc, "blur", EXPECTED_AT_LEAST, 1); - - if (error) { - return error; - } - - struct sway_container *con = config->handler_context.container; - - bool result = parse_boolean(argv[0], true); - if (con == NULL) { - config->blur_enabled = result; - } else { - con->blur_enabled = result; - } - - struct sway_output *output; - wl_list_for_each(output, &root->all_outputs, link) { - struct fx_effect_framebuffers *effect_fbos = - fx_effect_framebuffers_try_get(output->wlr_output); - effect_fbos->blur_buffer_dirty = true; - output_damage_whole(output); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/blur_brightness.c b/sway/commands/blur_brightness.c deleted file mode 100644 index 6ff60975a..000000000 --- a/sway/commands/blur_brightness.c +++ /dev/null @@ -1,29 +0,0 @@ -#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/output.h" - -struct cmd_results *cmd_blur_brightness(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "blur_brightness", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - char *inv; - float value = strtof(argv[0], &inv); - if (*inv != '\0' || value < 0 || value > 2) { - return cmd_results_new(CMD_FAILURE, "Invalid brightness specified"); - } - - config->blur_params.brightness = value; - - struct sway_output *output; - wl_list_for_each(output, &root->all_outputs, link) { - struct fx_effect_framebuffers *effect_fbos = - fx_effect_framebuffers_try_get(output->wlr_output); - effect_fbos->blur_buffer_dirty = true; - output_damage_whole(output); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/blur_contrast.c b/sway/commands/blur_contrast.c deleted file mode 100644 index ba046e63a..000000000 --- a/sway/commands/blur_contrast.c +++ /dev/null @@ -1,29 +0,0 @@ -#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/output.h" - -struct cmd_results *cmd_blur_contrast(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "blur_contrast", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - char *inv; - float value = strtof(argv[0], &inv); - if (*inv != '\0' || value < 0 || value > 2) { - return cmd_results_new(CMD_FAILURE, "Invalid brightness specified"); - } - - config->blur_params.contrast = value; - - struct sway_output *output; - wl_list_for_each(output, &root->all_outputs, link) { - struct fx_effect_framebuffers *effect_fbos = - fx_effect_framebuffers_try_get(output->wlr_output); - effect_fbos->blur_buffer_dirty = true; - output_damage_whole(output); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/blur_noise.c b/sway/commands/blur_noise.c deleted file mode 100644 index 358b20f5e..000000000 --- a/sway/commands/blur_noise.c +++ /dev/null @@ -1,29 +0,0 @@ -#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/output.h" - -struct cmd_results *cmd_blur_noise(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "blur_noise", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - char *inv; - float value = strtof(argv[0], &inv); - if (*inv != '\0' || value < 0 || value > 1) { - return cmd_results_new(CMD_FAILURE, "Invalid noise specified"); - } - - config->blur_params.noise = value; - - struct sway_output *output; - wl_list_for_each(output, &root->all_outputs, link) { - struct fx_effect_framebuffers *effect_fbos = - fx_effect_framebuffers_try_get(output->wlr_output); - effect_fbos->blur_buffer_dirty = true; - output_damage_whole(output); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/blur_passes.c b/sway/commands/blur_passes.c deleted file mode 100644 index c79f99d1c..000000000 --- a/sway/commands/blur_passes.c +++ /dev/null @@ -1,29 +0,0 @@ -#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/output.h" - -struct cmd_results *cmd_blur_passes(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "blur_passes", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - char *inv; - int value = strtol(argv[0], &inv, 10); - if (*inv != '\0' || value < 0 || value > 10) { - return cmd_results_new(CMD_FAILURE, "Invalid size specified"); - } - - config->blur_params.num_passes = value; - - struct sway_output *output; - wl_list_for_each(output, &root->all_outputs, link) { - struct fx_effect_framebuffers *effect_fbos = - fx_effect_framebuffers_try_get(output->wlr_output); - effect_fbos->blur_buffer_dirty = true; - output_damage_whole(output); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/blur_radius.c b/sway/commands/blur_radius.c deleted file mode 100644 index 85e90e77a..000000000 --- a/sway/commands/blur_radius.c +++ /dev/null @@ -1,29 +0,0 @@ -#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/output.h" - -struct cmd_results *cmd_blur_radius(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "blur_radius", EXPECTED_AT_LEAST, 1))) { - return error; - } - - char *inv; - int value = strtol(argv[0], &inv, 10); - if (*inv != '\0' || value < 0 || value > 10) { - return cmd_results_new(CMD_FAILURE, "Invalid size specified"); - } - - config->blur_params.radius = value; - - struct sway_output *output; - wl_list_for_each(output, &root->all_outputs, link) { - struct fx_effect_framebuffers *effect_fbos = - fx_effect_framebuffers_try_get(output->wlr_output); - effect_fbos->blur_buffer_dirty = true; - output_damage_whole(output); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/blur_saturation.c b/sway/commands/blur_saturation.c deleted file mode 100644 index ae6352d21..000000000 --- a/sway/commands/blur_saturation.c +++ /dev/null @@ -1,30 +0,0 @@ -#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/output.h" - -struct cmd_results *cmd_blur_saturation(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "blur_saturation", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - char *inv; - float value = strtof(argv[0], &inv); - if (*inv != '\0' || value < 0 || value > 2) { - return cmd_results_new(CMD_FAILURE, "Invalid saturation specified"); - } - - config->blur_params.saturation = value; - - struct sway_output *output; - wl_list_for_each(output, &root->all_outputs, link) { - struct fx_effect_framebuffers *effect_fbos = - fx_effect_framebuffers_try_get(output->wlr_output); - effect_fbos->blur_buffer_dirty = true; - output_damage_whole(output); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} - diff --git a/sway/commands/blur_xray.c b/sway/commands/blur_xray.c deleted file mode 100644 index 6986b3616..000000000 --- a/sway/commands/blur_xray.c +++ /dev/null @@ -1,26 +0,0 @@ -#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/output.h" -#include "util.h" - -struct cmd_results *cmd_blur_xray(int argc, char **argv) { - struct cmd_results *error = checkarg(argc, "blur_xray", EXPECTED_AT_LEAST, 1); - - if (error) { - return error; - } - - bool result = parse_boolean(argv[0], config->blur_xray); - config->blur_xray = result; - - struct sway_output *output; - wl_list_for_each(output, &root->all_outputs, link) { - struct fx_effect_framebuffers *effect_fbos = - fx_effect_framebuffers_try_get(output->wlr_output); - effect_fbos->blur_buffer_dirty = true; - output_damage_whole(output); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/border.c b/sway/commands/border.c deleted file mode 100644 index 7818fc962..000000000 --- a/sway/commands/border.c +++ /dev/null @@ -1,101 +0,0 @@ -#include "log.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/input/cursor.h" -#include "sway/input/input-manager.h" -#include "sway/tree/arrange.h" -#include "sway/tree/container.h" -#include "sway/tree/view.h" - -// A couple of things here: -// - view->border should never be B_CSD when the view is tiled, even when CSD is -// in use (we set using_csd instead and render a sway border). -// - view->saved_border should be the last applied border when switching to CSD. -// - view->using_csd should always reflect whether CSD is applied or not. -static void set_border(struct sway_container *con, - enum sway_container_border new_border) { - if (con->view) { - if (con->view->using_csd && new_border != B_CSD) { - view_set_csd_from_server(con->view, false); - } else if (!con->view->using_csd && new_border == B_CSD) { - view_set_csd_from_server(con->view, true); - con->saved_border = con->pending.border; - } - } - if (new_border != B_CSD || container_is_floating(con)) { - con->pending.border = new_border; - } - if (con->view) { - con->view->using_csd = new_border == B_CSD; - } -} - -static void border_toggle(struct sway_container *con) { - if (con->view && con->view->using_csd) { - set_border(con, B_NONE); - return; - } - switch (con->pending.border) { - case B_NONE: - set_border(con, B_PIXEL); - break; - case B_PIXEL: - set_border(con, B_NORMAL); - break; - case B_NORMAL: - if (con->view && con->view->xdg_decoration) { - set_border(con, B_CSD); - } else { - set_border(con, B_NONE); - } - break; - case B_CSD: - // view->using_csd should be true so it would have returned above - sway_assert(false, "Unreachable"); - break; - } -} - -struct cmd_results *cmd_border(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "border", EXPECTED_AT_LEAST, 1))) { - return error; - } - - struct sway_container *container = config->handler_context.container; - if (!container || !container->view) { - return cmd_results_new(CMD_INVALID, "Only views can have borders"); - } - struct sway_view *view = container->view; - - if (strcmp(argv[0], "none") == 0) { - set_border(container, B_NONE); - } else if (strcmp(argv[0], "normal") == 0) { - set_border(container, B_NORMAL); - } else if (strcmp(argv[0], "pixel") == 0) { - set_border(container, B_PIXEL); - } else if (strcmp(argv[0], "csd") == 0) { - if (!view->xdg_decoration) { - return cmd_results_new(CMD_INVALID, - "This window doesn't support client side decorations"); - } - set_border(container, B_CSD); - } else if (strcmp(argv[0], "toggle") == 0) { - border_toggle(container); - } else { - return cmd_results_new(CMD_INVALID, - "Expected 'border ' " - "or 'border pixel '"); - } - if (argc == 2) { - container->pending.border_thickness = atoi(argv[1]); - } - - if (container_is_floating(container)) { - container_set_geometry_from_content(container); - } - - arrange_container(container); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/client.c b/sway/commands/client.c deleted file mode 100644 index 772631456..000000000 --- a/sway/commands/client.c +++ /dev/null @@ -1,98 +0,0 @@ -#include "log.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/output.h" -#include "sway/tree/container.h" -#include "util.h" - -static void rebuild_textures_iterator(struct sway_container *con, void *data) { - container_update_marks_textures(con); - container_update_title_textures(con); -} - -static struct cmd_results *handle_command(int argc, char **argv, char *cmd_name, - struct border_colors *class, const char *default_indicator) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, cmd_name, EXPECTED_AT_LEAST, 3)) || - (error = checkarg(argc, cmd_name, EXPECTED_AT_MOST, 5))) { - return error; - } - - if (argc > 3 && strcmp(cmd_name, "client.focused_tab_title") == 0) { - sway_log(SWAY_ERROR, - "Warning: indicator and child_border colors have no effect for %s", - cmd_name); - } - - struct border_colors colors = {0}; - const char *ind_hex = argc > 3 ? argv[3] : default_indicator; - const char *child_hex = argc > 4 ? argv[4] : argv[1]; // def to background - - struct { - const char *name; - const char *hex; - float *rgba[4]; - } properties[] = { - { "border", argv[0], colors.border }, - { "background", argv[1], colors.background }, - { "text", argv[2], colors.text }, - { "indicator", ind_hex, colors.indicator }, - { "child_border", child_hex, colors.child_border } - }; - for (size_t i = 0; i < sizeof(properties) / sizeof(properties[0]); i++) { - uint32_t color; - if (!parse_color(properties[i].hex, &color)) { - return cmd_results_new(CMD_INVALID, "Invalid %s color %s", - properties[i].name, properties[i].hex); - } - color_to_rgba(*properties[i].rgba, color); - } - - memcpy(class, &colors, sizeof(struct border_colors)); - - if (config->active) { - root_for_each_container(rebuild_textures_iterator, NULL); - - for (int i = 0; i < root->outputs->length; ++i) { - struct sway_output *output = root->outputs->items[i]; - output_damage_whole(output); - } - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} - -struct cmd_results *cmd_client_focused(int argc, char **argv) { - return handle_command(argc, argv, "client.focused", - &config->border_colors.focused, "#2e9ef4ff"); -} - -struct cmd_results *cmd_client_focused_inactive(int argc, char **argv) { - return handle_command(argc, argv, "client.focused_inactive", - &config->border_colors.focused_inactive, "#484e50ff"); -} - -struct cmd_results *cmd_client_unfocused(int argc, char **argv) { - return handle_command(argc, argv, "client.unfocused", - &config->border_colors.unfocused, "#292d2eff"); -} - -struct cmd_results *cmd_client_urgent(int argc, char **argv) { - return handle_command(argc, argv, "client.urgent", - &config->border_colors.urgent, "#900000ff"); -} - -struct cmd_results *cmd_client_noop(int argc, char **argv) { - sway_log(SWAY_INFO, "Warning: %s is ignored by sway", argv[-1]); - return cmd_results_new(CMD_SUCCESS, NULL); -} - -struct cmd_results *cmd_client_focused_tab_title(int argc, char **argv) { - struct cmd_results *result = handle_command(argc, argv, - "client.focused_tab_title", - &config->border_colors.focused_tab_title, "#2e9ef4ff"); - if (result && result->status == CMD_SUCCESS) { - config->has_focused_tab_title = true; - } - return result; -} diff --git a/sway/commands/corner_radius.c b/sway/commands/corner_radius.c deleted file mode 100644 index fe8b458f2..000000000 --- a/sway/commands/corner_radius.c +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/tree/container.h" -#include "log.h" - -bool cmd_corner_radius_parse_value(char *arg, int* result) { - char *inv; - int value = strtol(arg, &inv, 10); - if (*inv != '\0' || value < 0 || value > 99) { - return false; - } - *result = value; - return true; -} - -struct cmd_results *cmd_corner_radius(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "corner_radius", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - int value = 0; - if (!cmd_corner_radius_parse_value(argv[0], &value)) { - return cmd_results_new(CMD_FAILURE, "Invalid size specified"); - } - - config->corner_radius = value; - - /* - titlebar padding depends on corner_radius to - ensure that titlebars are rendered nicely - */ - if (value > config->titlebar_h_padding) { - config->titlebar_h_padding = value; - } - if (value > (int)container_titlebar_height()) { - config->titlebar_v_padding = (value - config->font_height) / 2; - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/create_output.c b/sway/commands/create_output.c deleted file mode 100644 index 79283fd11..000000000 --- a/sway/commands/create_output.c +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include -#include -#include -#if WLR_HAS_X11_BACKEND -#include -#endif -#include "sway/commands.h" -#include "sway/server.h" -#include "log.h" - -static void create_output(struct wlr_backend *backend, void *data) { - bool *done = data; - if (*done) { - return; - } - - if (wlr_backend_is_wl(backend)) { - wlr_wl_output_create(backend); - *done = true; - } else if (wlr_backend_is_headless(backend)) { - wlr_headless_add_output(backend, 1920, 1080); - *done = true; - } -#if WLR_HAS_X11_BACKEND - else if (wlr_backend_is_x11(backend)) { - wlr_x11_output_create(backend); - *done = true; - } -#endif -} - -/** - * This command is intended for developer use only. - */ -struct cmd_results *cmd_create_output(int argc, char **argv) { - sway_assert(wlr_backend_is_multi(server.backend), - "Expected a multi backend"); - - bool done = false; - wlr_multi_for_each_backend(server.backend, create_output, &done); - - if (!done) { - return cmd_results_new(CMD_INVALID, - "Can only create outputs for Wayland, X11 or headless backends"); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/default_border.c b/sway/commands/default_border.c deleted file mode 100644 index 5c0fee3f3..000000000 --- a/sway/commands/default_border.c +++ /dev/null @@ -1,27 +0,0 @@ -#include "log.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/tree/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 (strcmp(argv[0], "none") == 0) { - config->border = B_NONE; - } else if (strcmp(argv[0], "normal") == 0) { - config->border = B_NORMAL; - } else if (strcmp(argv[0], "pixel") == 0) { - config->border = B_PIXEL; - } else { - return cmd_results_new(CMD_INVALID, - "Expected 'default_border ' or 'default_border '"); - } - if (argc == 2) { - config->border_thickness = atoi(argv[1]); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/default_dim_inactive.c b/sway/commands/default_dim_inactive.c deleted file mode 100644 index 04d8acdfc..000000000 --- a/sway/commands/default_dim_inactive.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "log.h" -#include "sway/output.h" - - -struct cmd_results *cmd_default_dim_inactive(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "default_dim_inactive", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - char *err; - float val = strtof(argv[0], &err); - if (*err || val < 0.0f || val > 1.0f) { - return cmd_results_new(CMD_INVALID, "default_dim_inactive float invalid"); - } - - config->default_dim_inactive = val; - - if (config->active) { - for (int i = 0; i < root->outputs->length; ++i) { - struct sway_output *output = root->outputs->items[i]; - output_damage_whole(output); - } - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/default_floating_border.c b/sway/commands/default_floating_border.c deleted file mode 100644 index 7e4edc366..000000000 --- a/sway/commands/default_floating_border.c +++ /dev/null @@ -1,29 +0,0 @@ -#include "log.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/tree/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 (strcmp(argv[0], "none") == 0) { - config->floating_border = B_NONE; - } else if (strcmp(argv[0], "normal") == 0) { - config->floating_border = B_NORMAL; - } else if (strcmp(argv[0], "pixel") == 0) { - config->floating_border = B_PIXEL; - } else { - return cmd_results_new(CMD_INVALID, - "Expected 'default_floating_border ' " - "or 'default_floating_border '"); - } - if (argc == 2) { - config->floating_border_thickness = atoi(argv[1]); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/default_orientation.c b/sway/commands/default_orientation.c deleted file mode 100644 index fd42c1679..000000000 --- a/sway/commands/default_orientation.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include -#include "sway/commands.h" - -struct cmd_results *cmd_default_orientation(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "default_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, - "Expected 'orientation '"); - } - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/dim_inactive.c b/sway/commands/dim_inactive.c deleted file mode 100644 index e287ba4d3..000000000 --- a/sway/commands/dim_inactive.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "log.h" -#include "sway/output.h" -#include "sway/tree/container.h" - -struct cmd_results *cmd_dim_inactive(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "dim_inactive", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - char *err; - float val = strtof(argv[0], &err); - if (*err || val < 0.0f || val > 1.0f) { - return cmd_results_new(CMD_INVALID, "dim_inactive float invalid"); - } - - struct sway_container *container = config->handler_context.container; - if (!container) { - return cmd_results_new(CMD_INVALID, "cmd_dim cannot be used without a for_window rule"); - } - - container->dim = val; - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/dim_inactive_colors.c b/sway/commands/dim_inactive_colors.c deleted file mode 100644 index db8cc2999..000000000 --- a/sway/commands/dim_inactive_colors.c +++ /dev/null @@ -1,40 +0,0 @@ -#include "log.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/output.h" -#include "sway/tree/container.h" -#include "util.h" - -static struct cmd_results *handle_command(int argc, char **argv, char *cmd_name, - float config_option[4]) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, cmd_name, EXPECTED_AT_LEAST, 1))) { - return error; - } - - uint32_t color; - if (!parse_color(argv[0], &color)) { - return cmd_results_new(CMD_INVALID, "Invalid %s color %s", - cmd_name, argv[0]); - } - color_to_rgba(config_option, color); - - if (config->active) { - for (int i = 0; i < root->outputs->length; ++i) { - struct sway_output *output = root->outputs->items[i]; - output_damage_whole(output); - } - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} - -struct cmd_results *cmd_dim_inactive_colors_unfocused(int argc, char **argv) { - return handle_command(argc, argv, "dim_inactive_colors.unfocused", - config->dim_inactive_colors.unfocused); -} - -struct cmd_results *cmd_dim_inactive_colors_urgent(int argc, char **argv) { - return handle_command(argc, argv, "dim_inactive_colors.urgent", - config->dim_inactive_colors.urgent); -} diff --git a/sway/commands/exec.c b/sway/commands/exec.c deleted file mode 100644 index 2c6f3d2d5..000000000 --- a/sway/commands/exec.c +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "log.h" -#include "stringop.h" - -struct cmd_results *cmd_exec(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = cmd_exec_validate(argc, argv))) { - return error; - } - if (config->reloading) { - char *args = join_args(argv, argc); - sway_log(SWAY_DEBUG, "Ignoring 'exec %s' due to reload", args); - free(args); - return cmd_results_new(CMD_SUCCESS, NULL); - } - return cmd_exec_process(argc, argv); -} diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c deleted file mode 100644 index 8fca19093..000000000 --- a/sway/commands/exec_always.c +++ /dev/null @@ -1,130 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/server.h" -#include "sway/desktop/launcher.h" -#include "sway/tree/container.h" -#include "sway/tree/root.h" -#include "sway/tree/workspace.h" -#include "log.h" -#include "stringop.h" - -struct cmd_results *cmd_exec_validate(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, argv[-1], EXPECTED_AT_LEAST, 1))) { - return error; - } - if (!config->active || config->validating) { - return cmd_results_new(CMD_DEFER, NULL); - } - return error; -} - -static void export_xdga_token(struct launcher_ctx *ctx) { - const char *token = launcher_ctx_get_token_name(ctx); - setenv("XDG_ACTIVATION_TOKEN", token, 1); -} - -static void export_startup_id(struct launcher_ctx *ctx) { - const char *token = launcher_ctx_get_token_name(ctx); - setenv("DESKTOP_STARTUP_ID", token, 1); -} - -struct cmd_results *cmd_exec_process(int argc, char **argv) { - struct cmd_results *error = NULL; - char *cmd = NULL; - bool no_startup_id = false; - if (strcmp(argv[0], "--no-startup-id") == 0) { - no_startup_id = true; - --argc; ++argv; - if ((error = checkarg(argc, argv[-1], EXPECTED_AT_LEAST, 1))) { - return error; - } - } - - if (argc == 1 && (argv[0][0] == '\'' || argv[0][0] == '"')) { - cmd = strdup(argv[0]); - strip_quotes(cmd); - } else { - cmd = join_args(argv, argc); - } - - sway_log(SWAY_DEBUG, "Executing %s", cmd); - - int fd[2]; - if (pipe(fd) != 0) { - sway_log(SWAY_ERROR, "Unable to create pipe for fork"); - } - - pid_t pid, child; - struct launcher_ctx *ctx = launcher_ctx_create_internal(); - // Fork process - if ((pid = fork()) == 0) { - // Fork child process again - restore_nofile_limit(); - setsid(); - sigset_t set; - sigemptyset(&set); - sigprocmask(SIG_SETMASK, &set, NULL); - signal(SIGPIPE, SIG_DFL); - close(fd[0]); - if ((child = fork()) == 0) { - close(fd[1]); - if (ctx) { - export_xdga_token(ctx); - } - if (ctx && !no_startup_id) { - export_startup_id(ctx); - } - execlp("sh", "sh", "-c", cmd, (void *)NULL); - sway_log_errno(SWAY_ERROR, "execlp failed"); - _exit(1); - } - 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(cmd); - close(fd[0]); - close(fd[1]); - return cmd_results_new(CMD_FAILURE, "fork() failed"); - } - free(cmd); - 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 - waitpid(pid, NULL, 0); - if (child > 0) { - sway_log(SWAY_DEBUG, "Child process created with pid %d", child); - if (ctx != NULL) { - sway_log(SWAY_DEBUG, "Recording workspace for process %d", child); - ctx->pid = child; - } - } else { - launcher_ctx_destroy(ctx); - return cmd_results_new(CMD_FAILURE, "Second fork() failed"); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} - -struct cmd_results *cmd_exec_always(int argc, char **argv) { - struct cmd_results *error; - if ((error = cmd_exec_validate(argc, argv))) { - return error; - } - return cmd_exec_process(argc, argv); -} diff --git a/sway/commands/exit.c b/sway/commands/exit.c deleted file mode 100644 index 10cde640c..000000000 --- a/sway/commands/exit.c +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" - -void sway_terminate(int exit_code); - -struct cmd_results *cmd_exit(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "exit", EXPECTED_EQUAL_TO, 0))) { - return error; - } - sway_terminate(0); - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/floating.c b/sway/commands/floating.c deleted file mode 100644 index 74f6522c7..000000000 --- a/sway/commands/floating.c +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "sway/input/seat.h" -#include "sway/ipc-server.h" -#include "sway/output.h" -#include "sway/tree/arrange.h" -#include "sway/tree/container.h" -#include "sway/tree/view.h" -#include "sway/tree/workspace.h" -#include "list.h" -#include "util.h" - -struct cmd_results *cmd_floating(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1))) { - return error; - } - if (!root->outputs->length) { - return cmd_results_new(CMD_INVALID, - "Can't run this command while there's no outputs connected."); - } - struct sway_container *container = config->handler_context.container; - struct sway_workspace *workspace = config->handler_context.workspace; - if (!container && workspace->tiling->length == 0) { - return cmd_results_new(CMD_INVALID, "Can't float an empty workspace"); - } - if (!container) { - // Wrap the workspace's children in a container so we can float it - container = workspace_wrap_children(workspace); - workspace->layout = L_HORIZ; - seat_set_focus_container(config->handler_context.seat, container); - } - - if (container_is_scratchpad_hidden(container)) { - return cmd_results_new(CMD_INVALID, - "Can't change floating on hidden scratchpad container"); - } - - // If the container is in a floating split container, - // operate on the split container instead of the child. - if (container_is_floating_or_child(container)) { - while (container->pending.parent) { - container = container->pending.parent; - } - } - - bool wants_floating = - parse_boolean(argv[0], container_is_floating(container)); - - container_set_floating(container, wants_floating); - - // Floating containers in the scratchpad should be ignored - if (container->pending.workspace) { - arrange_workspace(container->pending.workspace); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/floating_minmax_size.c b/sway/commands/floating_minmax_size.c deleted file mode 100644 index e8c24ace2..000000000 --- a/sway/commands/floating_minmax_size.c +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "sway/commands.h" -#include "log.h" - -static const char min_usage[] = - "Expected 'floating_minimum_size x '"; - -static const char max_usage[] = - "Expected 'floating_maximum_size x '"; - -static struct cmd_results *handle_command(int argc, char **argv, char *cmd_name, - const char *usage, int *config_width, int *config_height) { - struct cmd_results *error; - if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 3))) { - return error; - } - - char *err; - int width = (int)strtol(argv[0], &err, 10); - if (*err) { - return cmd_results_new(CMD_INVALID, "%s", usage); - } - - if (strcmp(argv[1], "x") != 0) { - return cmd_results_new(CMD_INVALID, "%s", usage); - } - - int height = (int)strtol(argv[2], &err, 10); - if (*err) { - return cmd_results_new(CMD_INVALID, "%s", usage); - } - - *config_width = width; - *config_height = height; - - return cmd_results_new(CMD_SUCCESS, NULL); -} - -struct cmd_results *cmd_floating_minimum_size(int argc, char **argv) { - return handle_command(argc, argv, "floating_minimum_size", min_usage, - &config->floating_minimum_width, &config->floating_minimum_height); -} - -struct cmd_results *cmd_floating_maximum_size(int argc, char **argv) { - return handle_command(argc, argv, "floating_maximum_size", max_usage, - &config->floating_maximum_width, &config->floating_maximum_height); -} diff --git a/sway/commands/floating_modifier.c b/sway/commands/floating_modifier.c deleted file mode 100644 index c02bce978..000000000 --- a/sway/commands/floating_modifier.c +++ /dev/null @@ -1,34 +0,0 @@ -#include "strings.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/input/keyboard.h" - -struct cmd_results *cmd_floating_modifier(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "floating_modifier", EXPECTED_AT_LEAST, 1))) { - return error; - } - - if (strcasecmp(argv[0], "none") == 0) { - config->floating_mod = 0; - return cmd_results_new(CMD_SUCCESS, NULL); - } - - uint32_t mod = get_modifier_mask_by_name(argv[0]); - if (!mod) { - return cmd_results_new(CMD_INVALID, "Invalid modifier"); - } - - if (argc == 1 || strcasecmp(argv[1], "normal") == 0) { - config->floating_mod_inverse = false; - } else if (strcasecmp(argv[1], "inverse") == 0) { - config->floating_mod_inverse = true; - } else { - return cmd_results_new(CMD_INVALID, - "Usage: floating_modifier [inverse|normal]"); - } - - config->floating_mod = mod; - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/focus.c b/sway/commands/focus.c deleted file mode 100644 index facd82de7..000000000 --- a/sway/commands/focus.c +++ /dev/null @@ -1,474 +0,0 @@ -#include -#include -#include -#include "log.h" -#include "sway/commands.h" -#include "sway/input/input-manager.h" -#include "sway/input/cursor.h" -#include "sway/input/seat.h" -#include "sway/output.h" -#include "sway/tree/arrange.h" -#include "sway/tree/root.h" -#include "sway/tree/view.h" -#include "sway/tree/workspace.h" -#include "stringop.h" -#include "util.h" - -static bool get_direction_from_next_prev(struct sway_container *container, - struct sway_seat *seat, const char *name, enum wlr_direction *out) { - enum sway_container_layout parent_layout = L_NONE; - if (container) { - parent_layout = container_parent_layout(container); - } - - if (strcasecmp(name, "prev") == 0) { - switch (parent_layout) { - case L_HORIZ: - case L_TABBED: - *out = WLR_DIRECTION_LEFT; - break; - case L_VERT: - case L_STACKED: - *out = WLR_DIRECTION_UP; - break; - case L_NONE: - return true; - default: - return false; - } - } else if (strcasecmp(name, "next") == 0) { - switch (parent_layout) { - case L_HORIZ: - case L_TABBED: - *out = WLR_DIRECTION_RIGHT; - break; - case L_VERT: - case L_STACKED: - *out = WLR_DIRECTION_DOWN; - break; - case L_NONE: - return true; - default: - return false; - } - } else { - return false; - } - - return true; -} - -static bool parse_direction(const char *name, - enum wlr_direction *out) { - if (strcasecmp(name, "left") == 0) { - *out = WLR_DIRECTION_LEFT; - } else if (strcasecmp(name, "right") == 0) { - *out = WLR_DIRECTION_RIGHT; - } else if (strcasecmp(name, "up") == 0) { - *out = WLR_DIRECTION_UP; - } else if (strcasecmp(name, "down") == 0) { - *out = WLR_DIRECTION_DOWN; - } else { - return false; - } - - return true; -} - -/** - * Get node in the direction of newly entered output. - */ -static struct sway_node *get_node_in_output_direction( - struct sway_output *output, enum wlr_direction dir) { - struct sway_seat *seat = config->handler_context.seat; - struct sway_workspace *ws = output_get_active_workspace(output); - if (!sway_assert(ws, "Expected output to have a workspace")) { - return NULL; - } - if (ws->fullscreen) { - return seat_get_focus_inactive(seat, &ws->fullscreen->node); - } - struct sway_container *container = NULL; - - if (ws->tiling->length > 0) { - switch (dir) { - case WLR_DIRECTION_LEFT: - if (ws->layout == L_HORIZ || ws->layout == L_TABBED) { - // get most right child of new output - container = ws->tiling->items[ws->tiling->length-1]; - } else { - container = seat_get_focus_inactive_tiling(seat, ws); - } - break; - case WLR_DIRECTION_RIGHT: - if (ws->layout == L_HORIZ || ws->layout == L_TABBED) { - // get most left child of new output - container = ws->tiling->items[0]; - } else { - container = seat_get_focus_inactive_tiling(seat, ws); - } - break; - case WLR_DIRECTION_UP: - if (ws->layout == L_VERT || ws->layout == L_STACKED) { - // get most bottom child of new output - container = ws->tiling->items[ws->tiling->length-1]; - } else { - container = seat_get_focus_inactive_tiling(seat, ws); - } - break; - case WLR_DIRECTION_DOWN: - if (ws->layout == L_VERT || ws->layout == L_STACKED) { - // get most top child of new output - container = ws->tiling->items[0]; - } else { - container = seat_get_focus_inactive_tiling(seat, ws); - } - break; - } - } - - if (container) { - container = seat_get_focus_inactive_view(seat, &container->node); - return &container->node; - } - - return &ws->node; -} - -static struct sway_node *node_get_in_direction_tiling( - struct sway_container *container, struct sway_seat *seat, - enum wlr_direction dir, bool descend) { - struct sway_container *wrap_candidate = NULL; - struct sway_container *current = container; - while (current) { - if (current->pending.fullscreen_mode == FULLSCREEN_WORKSPACE) { - // Fullscreen container with a direction - go straight to outputs - struct sway_output *output = current->pending.workspace->output; - struct sway_output *new_output = - output_get_in_direction(output, dir); - if (!new_output) { - return NULL; - } - return get_node_in_output_direction(new_output, dir); - } - if (current->pending.fullscreen_mode == FULLSCREEN_GLOBAL) { - return NULL; - } - - bool can_move = false; - int desired; - int idx = container_sibling_index(current); - enum sway_container_layout parent_layout = - container_parent_layout(current); - list_t *siblings = container_get_siblings(current); - - if (dir == WLR_DIRECTION_LEFT || dir == WLR_DIRECTION_RIGHT) { - if (parent_layout == L_HORIZ || parent_layout == L_TABBED) { - can_move = true; - desired = idx + (dir == WLR_DIRECTION_LEFT ? -1 : 1); - } - } else { - if (parent_layout == L_VERT || parent_layout == L_STACKED) { - can_move = true; - desired = idx + (dir == WLR_DIRECTION_UP ? -1 : 1); - } - } - - if (can_move) { - if (desired < 0 || desired >= siblings->length) { - int len = siblings->length; - if (config->focus_wrapping != WRAP_NO && !wrap_candidate - && len > 1) { - if (desired < 0) { - wrap_candidate = siblings->items[len-1]; - } else { - wrap_candidate = siblings->items[0]; - } - if (config->focus_wrapping == WRAP_FORCE) { - struct sway_container *c = seat_get_focus_inactive_view( - seat, &wrap_candidate->node); - return &c->node; - } - } - } else { - struct sway_container *desired_con = siblings->items[desired]; - if (!descend) { - return &desired_con->node; - } else { - struct sway_container *c = seat_get_focus_inactive_view( - seat, &desired_con->node); - return &c->node; - } - } - } - - current = current->pending.parent; - } - - // Check a different output - struct sway_output *output = container->pending.workspace->output; - struct sway_output *new_output = output_get_in_direction(output, dir); - if ((config->focus_wrapping != WRAP_WORKSPACE || - container->node.type == N_WORKSPACE) && new_output) { - return get_node_in_output_direction(new_output, dir); - } - - // If there is a wrap candidate, return its focus inactive view - if (wrap_candidate) { - struct sway_container *wrap_inactive = seat_get_focus_inactive_view( - seat, &wrap_candidate->node); - return &wrap_inactive->node; - } - - return NULL; -} - -static struct sway_node *node_get_in_direction_floating( - struct sway_container *con, struct sway_seat *seat, - enum wlr_direction dir) { - double ref_lx = con->pending.x + con->pending.width / 2; - double ref_ly = con->pending.y + con->pending.height / 2; - double closest_distance = DBL_MAX; - struct sway_container *closest_con = NULL; - - if (!con->pending.workspace) { - return NULL; - } - - for (int i = 0; i < con->pending.workspace->floating->length; i++) { - struct sway_container *floater = con->pending.workspace->floating->items[i]; - if (floater == con) { - continue; - } - float distance = dir == WLR_DIRECTION_LEFT || dir == WLR_DIRECTION_RIGHT - ? (floater->pending.x + floater->pending.width / 2) - ref_lx - : (floater->pending.y + floater->pending.height / 2) - ref_ly; - if (dir == WLR_DIRECTION_LEFT || dir == WLR_DIRECTION_UP) { - distance = -distance; - } - if (distance < 0) { - continue; - } - if (distance < closest_distance) { - closest_distance = distance; - closest_con = floater; - } - } - - return closest_con ? &closest_con->node : NULL; -} - -static struct cmd_results *focus_mode(struct sway_workspace *ws, - struct sway_seat *seat, bool floating) { - struct sway_container *new_focus = NULL; - if (floating) { - new_focus = seat_get_focus_inactive_floating(seat, ws); - } else { - new_focus = seat_get_focus_inactive_tiling(seat, ws); - } - if (new_focus) { - struct sway_container *new_focus_view = - seat_get_focus_inactive_view(seat, &new_focus->node); - if (new_focus_view) { - new_focus = new_focus_view; - } - seat_set_focus_container(seat, new_focus); - - // If we're on the floating layer and the floating container area - // overlaps the position on the tiling layer that would be warped to, - // `seat_consider_warp_to_focus` would decide not to warp, but we need - // to anyway. - if (config->mouse_warping == WARP_CONTAINER) { - cursor_warp_to_container(seat->cursor, new_focus, true); - } else { - seat_consider_warp_to_focus(seat); - } - } else { - return cmd_results_new(CMD_FAILURE, - "Failed to find a %s container in workspace.", - floating ? "floating" : "tiling"); - } - return cmd_results_new(CMD_SUCCESS, NULL); -} - -static struct cmd_results *focus_output(struct sway_seat *seat, - int argc, char **argv) { - if (!argc) { - return cmd_results_new(CMD_INVALID, - "Expected 'focus output '."); - } - char *identifier = join_args(argv, argc); - struct sway_output *output = output_by_name_or_id(identifier); - - if (!output) { - enum wlr_direction direction; - if (!parse_direction(identifier, &direction)) { - free(identifier); - return cmd_results_new(CMD_INVALID, - "There is no output with that name."); - } - struct sway_workspace *ws = seat_get_focused_workspace(seat); - if (!ws) { - free(identifier); - return cmd_results_new(CMD_FAILURE, - "No focused workspace to base directions off of."); - } - output = output_get_in_direction(ws->output, direction); - - if (!output) { - int center_lx = ws->output->lx + ws->output->width / 2; - int center_ly = ws->output->ly + ws->output->height / 2; - struct wlr_output *target = wlr_output_layout_farthest_output( - root->output_layout, opposite_direction(direction), - ws->output->wlr_output, center_lx, center_ly); - if (target) { - output = output_from_wlr_output(target); - } - } - } - - free(identifier); - if (output) { - seat_set_focus(seat, seat_get_focus_inactive(seat, &output->node)); - seat_consider_warp_to_focus(seat); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} - -static struct cmd_results *focus_parent(void) { - struct sway_seat *seat = config->handler_context.seat; - struct sway_container *con = config->handler_context.container; - if (!con || con->pending.fullscreen_mode) { - return cmd_results_new(CMD_SUCCESS, NULL); - } - struct sway_node *parent = node_get_parent(&con->node); - if (parent) { - seat_set_focus(seat, parent); - seat_consider_warp_to_focus(seat); - } - return cmd_results_new(CMD_SUCCESS, NULL); -} - -static struct cmd_results *focus_child(void) { - struct sway_seat *seat = config->handler_context.seat; - struct sway_node *node = config->handler_context.node; - struct sway_node *focus = seat_get_active_tiling_child(seat, node); - if (focus) { - seat_set_focus(seat, focus); - seat_consider_warp_to_focus(seat); - } - return cmd_results_new(CMD_SUCCESS, NULL); -} - -struct cmd_results *cmd_focus(int argc, char **argv) { - if (config->reading || !config->active) { - return cmd_results_new(CMD_DEFER, NULL); - } - if (!root->outputs->length) { - return cmd_results_new(CMD_INVALID, - "Can't run this command while there's no outputs connected."); - } - struct sway_node *node = config->handler_context.node; - struct sway_container *container = config->handler_context.container; - struct sway_workspace *workspace = config->handler_context.workspace; - struct sway_seat *seat = config->handler_context.seat; - if (node->type < N_WORKSPACE) { - return cmd_results_new(CMD_FAILURE, - "Command 'focus' cannot be used above the workspace level."); - } - - if (argc == 0) { - if (!container) { - return cmd_results_new(CMD_FAILURE, "No container to focus was specified."); - } - - if (container_is_scratchpad_hidden_or_child(container)) { - root_scratchpad_show(container); - } - // if we are switching to a container under a fullscreen window, we first - // need to exit fullscreen so that the newly focused container becomes visible - struct sway_container *obstructing = container_obstructing_fullscreen_container(container); - if (obstructing) { - container_fullscreen_disable(obstructing); - arrange_root(); - } - seat_set_focus_container(seat, container); - seat_consider_warp_to_focus(seat); - container_raise_floating(container); - return cmd_results_new(CMD_SUCCESS, NULL); - } - - if (strcmp(argv[0], "floating") == 0) { - return focus_mode(workspace, seat, true); - } else if (strcmp(argv[0], "tiling") == 0) { - return focus_mode(workspace, seat, false); - } else if (strcmp(argv[0], "mode_toggle") == 0) { - bool floating = container && container_is_floating_or_child(container); - return focus_mode(workspace, seat, !floating); - } - - if (strcmp(argv[0], "output") == 0) { - argc--; argv++; - return focus_output(seat, argc, argv); - } - - if (strcasecmp(argv[0], "parent") == 0) { - return focus_parent(); - } - if (strcasecmp(argv[0], "child") == 0) { - return focus_child(); - } - - enum wlr_direction direction = 0; - bool descend = true; - if (!parse_direction(argv[0], &direction)) { - if (!get_direction_from_next_prev(container, seat, argv[0], &direction)) { - return cmd_results_new(CMD_INVALID, - "Expected 'focus ' " - "or 'focus output '"); - } else if (argc == 2 && strcasecmp(argv[1], "sibling") == 0) { - descend = false; - } - } - - if (!direction) { - return cmd_results_new(CMD_SUCCESS, NULL); - } - - if (node->type == N_WORKSPACE) { - // Jump to the next output - struct sway_output *new_output = - output_get_in_direction(workspace->output, direction); - if (!new_output) { - return cmd_results_new(CMD_SUCCESS, NULL); - } - - struct sway_node *node = - get_node_in_output_direction(new_output, direction); - seat_set_focus(seat, node); - seat_consider_warp_to_focus(seat); - return cmd_results_new(CMD_SUCCESS, NULL); - } - - if (!sway_assert(container, "Expected container to be non null")) { - return cmd_results_new(CMD_FAILURE, ""); - } - struct sway_node *next_focus = NULL; - if (container_is_floating(container) && - container->pending.fullscreen_mode == FULLSCREEN_NONE) { - next_focus = node_get_in_direction_floating(container, seat, direction); - } else { - next_focus = node_get_in_direction_tiling(container, seat, direction, descend); - } - if (next_focus) { - seat_set_focus(seat, next_focus); - seat_consider_warp_to_focus(seat); - - if (next_focus->type == N_CONTAINER) { - container_raise_floating(next_focus->sway_container); - } - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/focus_follows_mouse.c b/sway/commands/focus_follows_mouse.c deleted file mode 100644 index 7afb5f623..000000000 --- a/sway/commands/focus_follows_mouse.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "util.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; - } else if(strcmp(argv[0], "no") == 0) { - config->focus_follows_mouse = FOLLOWS_NO; - } else if(strcmp(argv[0], "yes") == 0) { - config->focus_follows_mouse = FOLLOWS_YES; - } else if(strcmp(argv[0], "always") == 0) { - config->focus_follows_mouse = FOLLOWS_ALWAYS; - } else { - return cmd_results_new(CMD_FAILURE, - "Expected 'focus_follows_mouse no|yes|always'"); - } - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/focus_on_window_activation.c b/sway/commands/focus_on_window_activation.c deleted file mode 100644 index 2163fc590..000000000 --- a/sway/commands/focus_on_window_activation.c +++ /dev/null @@ -1,25 +0,0 @@ -#include "sway/commands.h" - -struct cmd_results *cmd_focus_on_window_activation(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "focus_on_window_activation", - EXPECTED_EQUAL_TO, 1))) { - return error; - } - - if (strcmp(argv[0], "smart") == 0) { - config->focus_on_window_activation = FOWA_SMART; - } else if (strcmp(argv[0], "urgent") == 0) { - config->focus_on_window_activation = FOWA_URGENT; - } else if (strcmp(argv[0], "focus") == 0) { - config->focus_on_window_activation = FOWA_FOCUS; - } else if (strcmp(argv[0], "none") == 0) { - config->focus_on_window_activation = FOWA_NONE; - } else { - return cmd_results_new(CMD_INVALID, - "Expected " - "'focus_on_window_activation smart|urgent|focus|none'"); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/focus_wrapping.c b/sway/commands/focus_wrapping.c deleted file mode 100644 index d3901cb8f..000000000 --- a/sway/commands/focus_wrapping.c +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "util.h" - -struct cmd_results *cmd_focus_wrapping(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "focus_wrapping", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - if (strcasecmp(argv[0], "force") == 0) { - config->focus_wrapping = WRAP_FORCE; - } else if (strcasecmp(argv[0], "workspace") == 0) { - config->focus_wrapping = WRAP_WORKSPACE; - } else if (parse_boolean(argv[0], config->focus_wrapping == WRAP_YES)) { - config->focus_wrapping = WRAP_YES; - } else { - config->focus_wrapping = WRAP_NO; - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/font.c b/sway/commands/font.c deleted file mode 100644 index 74bb6b9f4..000000000 --- a/sway/commands/font.c +++ /dev/null @@ -1,50 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "log.h" -#include "stringop.h" -#include - -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 (strncmp(font, "pango:", 6) == 0) { - config->pango_markup = true; - config->font = strdup(font + 6); - free(font); - } else { - config->pango_markup = false; - config->font = font; - } - - // Parse the font early so we can reject it if it's not valid for pango. - // Also avoids re-parsing each time we render text. - PangoFontDescription *font_description = pango_font_description_from_string(config->font); - - const char *family = pango_font_description_get_family(font_description); - if (family == NULL) { - pango_font_description_free(font_description); - return cmd_results_new(CMD_FAILURE, "Invalid font family."); - } - - const gint size = pango_font_description_get_size(font_description); - if (size == 0) { - pango_font_description_free(font_description); - return cmd_results_new(CMD_FAILURE, "Invalid font size."); - } - - if (config->font_description != NULL) { - pango_font_description_free(config->font_description); - } - - config->font_description = font_description; - config_update_font_height(); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/for_window.c b/sway/commands/for_window.c deleted file mode 100644 index 905e67767..000000000 --- a/sway/commands/for_window.c +++ /dev/null @@ -1,37 +0,0 @@ -#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; - } - - char *err_str = NULL; - struct criteria *criteria = criteria_parse(argv[0], &err_str); - if (!criteria) { - error = cmd_results_new(CMD_INVALID, "%s", err_str); - free(err_str); - return error; - } - - criteria->type = CT_COMMAND; - criteria->cmdlist = join_args(argv + 1, argc - 1); - - // Check if it already exists - if (criteria_already_exists(criteria)) { - sway_log(SWAY_DEBUG, "for_window already exists: '%s' -> '%s'", - criteria->raw, criteria->cmdlist); - criteria_destroy(criteria); - return cmd_results_new(CMD_SUCCESS, NULL); - } - - list_add(config->criteria, criteria); - sway_log(SWAY_DEBUG, "for_window: '%s' -> '%s' added", criteria->raw, criteria->cmdlist); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/force_display_urgency_hint.c b/sway/commands/force_display_urgency_hint.c deleted file mode 100644 index 3d432cba9..000000000 --- a/sway/commands/force_display_urgency_hint.c +++ /dev/null @@ -1,27 +0,0 @@ -#include "sway/commands.h" -#include "sway/config.h" -#include - -struct cmd_results *cmd_force_display_urgency_hint(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "force_display_urgency_hint", - EXPECTED_AT_LEAST, 1))) { - return error; - } - - errno = 0; - char *end; - int timeout = (int)strtol(argv[0], &end, 10); - if (errno || end == argv[0] || (*end && strcmp(end, "ms") != 0)) { - return cmd_results_new(CMD_INVALID, "timeout integer invalid"); - } - - if (argc > 1 && strcmp(argv[1], "ms") != 0) { - return cmd_results_new(CMD_INVALID, - "Expected 'force_display_urgency_hint [ms]'"); - } - - config->urgent_timeout = timeout > 0 ? timeout : 0; - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/force_focus_wrapping.c b/sway/commands/force_focus_wrapping.c deleted file mode 100644 index fafc1c3ef..000000000 --- a/sway/commands/force_focus_wrapping.c +++ /dev/null @@ -1,27 +0,0 @@ -#include "sway/commands.h" -#include "sway/config.h" -#include "log.h" -#include "util.h" - -struct cmd_results *cmd_force_focus_wrapping(int argc, char **argv) { - sway_log(SWAY_INFO, "Warning: force_focus_wrapping is deprecated. " - "Use focus_wrapping instead."); - if (config->reading) { - config_add_swaynag_warning("force_focus_wrapping is deprecated. " - "Use focus_wrapping instead."); - } - - struct cmd_results *error = - checkarg(argc, "force_focus_wrapping", EXPECTED_EQUAL_TO, 1); - if (error) { - return error; - } - - if (parse_boolean(argv[0], config->focus_wrapping == WRAP_FORCE)) { - config->focus_wrapping = WRAP_FORCE; - } else { - config->focus_wrapping = WRAP_YES; - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c deleted file mode 100644 index 21c1e9a09..000000000 --- a/sway/commands/fullscreen.c +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include "log.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/tree/arrange.h" -#include "sway/tree/container.h" -#include "sway/tree/view.h" -#include "sway/tree/workspace.h" -#include "util.h" - -// fullscreen [enable|disable|toggle] [global] -struct cmd_results *cmd_fullscreen(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "fullscreen", EXPECTED_AT_MOST, 2))) { - return error; - } - if (!root->outputs->length) { - return cmd_results_new(CMD_FAILURE, - "Can't run this command while there's no outputs connected."); - } - struct sway_container *container = config->handler_context.container; - - if (!container) { - // If the focus is not a container, do nothing successfully - return cmd_results_new(CMD_SUCCESS, NULL); - } else if (!container->pending.workspace) { - // If in the scratchpad, operate on the highest container - while (container->pending.parent) { - container = container->pending.parent; - } - } - - bool is_fullscreen = container->pending.fullscreen_mode != FULLSCREEN_NONE; - bool global = false; - bool enable = !is_fullscreen; - - if (argc >= 1) { - if (strcasecmp(argv[0], "global") == 0) { - global = true; - } else { - enable = parse_boolean(argv[0], is_fullscreen); - } - } - - if (argc >= 2) { - global = strcasecmp(argv[1], "global") == 0; - } - - enum sway_fullscreen_mode mode = FULLSCREEN_NONE; - if (enable) { - mode = global ? FULLSCREEN_GLOBAL : FULLSCREEN_WORKSPACE; - } - - container_set_fullscreen(container, mode); - arrange_root(); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/gaps.c b/sway/commands/gaps.c deleted file mode 100644 index 1deeb56e1..000000000 --- a/sway/commands/gaps.c +++ /dev/null @@ -1,231 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/tree/arrange.h" -#include "sway/tree/workspace.h" -#include "log.h" -#include "stringop.h" -#include - -enum gaps_op { - GAPS_OP_SET, - GAPS_OP_ADD, - GAPS_OP_SUBTRACT, - GAPS_OP_TOGGLE -}; - -struct gaps_data { - bool inner; - struct { - bool top; - bool right; - bool bottom; - bool left; - } outer; - enum gaps_op operation; - int amount; -}; - -// Prevent negative outer gaps from moving windows out of the workspace. -static void prevent_invalid_outer_gaps(void) { - if (config->gaps_outer.top < -config->gaps_inner) { - config->gaps_outer.top = -config->gaps_inner; - } - if (config->gaps_outer.right < -config->gaps_inner) { - config->gaps_outer.right = -config->gaps_inner; - } - if (config->gaps_outer.bottom < -config->gaps_inner) { - config->gaps_outer.bottom = -config->gaps_inner; - } - if (config->gaps_outer.left < -config->gaps_inner) { - config->gaps_outer.left = -config->gaps_inner; - } -} - -// gaps inner|outer|horizontal|vertical|top|right|bottom|left -static const char expected_defaults[] = - "'gaps inner|outer|horizontal|vertical|top|right|bottom|left '"; -static struct cmd_results *gaps_set_defaults(int argc, char **argv) { - struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 2); - if (error) { - return error; - } - - char *end; - int amount = strtol(argv[1], &end, 10); - if (strlen(end) && strcasecmp(end, "px") != 0) { - return cmd_results_new(CMD_INVALID, "Expected %s", expected_defaults); - } - - bool valid = false; - if (!strcasecmp(argv[0], "inner")) { - valid = true; - config->gaps_inner = (amount >= 0) ? amount : 0; - } else { - if (!strcasecmp(argv[0], "outer") || !strcasecmp(argv[0], "vertical") - || !strcasecmp(argv[0], "top")) { - valid = true; - config->gaps_outer.top = amount; - } - if (!strcasecmp(argv[0], "outer") || !strcasecmp(argv[0], "horizontal") - || !strcasecmp(argv[0], "right")) { - valid = true; - config->gaps_outer.right = amount; - } - if (!strcasecmp(argv[0], "outer") || !strcasecmp(argv[0], "vertical") - || !strcasecmp(argv[0], "bottom")) { - valid = true; - config->gaps_outer.bottom = amount; - } - if (!strcasecmp(argv[0], "outer") || !strcasecmp(argv[0], "horizontal") - || !strcasecmp(argv[0], "left")) { - valid = true; - config->gaps_outer.left = amount; - } - } - if (!valid) { - return cmd_results_new(CMD_INVALID, "Expected %s", expected_defaults); - } - - prevent_invalid_outer_gaps(); - return cmd_results_new(CMD_SUCCESS, NULL); -} - -static void apply_gaps_op(int *prop, enum gaps_op op, int amount) { - switch (op) { - case GAPS_OP_SET: - *prop = amount; - break; - case GAPS_OP_ADD: - *prop += amount; - break; - case GAPS_OP_SUBTRACT: - *prop -= amount; - break; - case GAPS_OP_TOGGLE: - *prop = *prop ? 0 : amount; - break; - } -} - -static void configure_gaps(struct sway_workspace *ws, void *_data) { - // Apply operation to gaps - struct gaps_data *data = _data; - if (data->inner) { - apply_gaps_op(&ws->gaps_inner, data->operation, data->amount); - } - if (data->outer.top) { - apply_gaps_op(&(ws->gaps_outer.top), data->operation, data->amount); - } - if (data->outer.right) { - apply_gaps_op(&(ws->gaps_outer.right), data->operation, data->amount); - } - if (data->outer.bottom) { - apply_gaps_op(&(ws->gaps_outer.bottom), data->operation, data->amount); - } - if (data->outer.left) { - apply_gaps_op(&(ws->gaps_outer.left), data->operation, data->amount); - } - - // Prevent invalid gaps configurations. - if (ws->gaps_inner < 0) { - ws->gaps_inner = 0; - } - prevent_invalid_outer_gaps(); - arrange_workspace(ws); -} - -// gaps inner|outer|horizontal|vertical|top|right|bottom|left current|all -// set|plus|minus|toggle -static const char expected_runtime[] = "'gaps inner|outer|horizontal|vertical|" - "top|right|bottom|left current|all set|plus|minus|toggle '"; -static struct cmd_results *gaps_set_runtime(int argc, char **argv) { - struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 4); - if (error) { - return error; - } - if (!root->outputs->length) { - return cmd_results_new(CMD_INVALID, - "Can't run this command while there's no outputs connected."); - } - - struct gaps_data data = {0}; - - if (strcasecmp(argv[0], "inner") == 0) { - data.inner = true; - } else { - data.outer.top = !strcasecmp(argv[0], "outer") || - !strcasecmp(argv[0], "vertical") || !strcasecmp(argv[0], "top"); - data.outer.right = !strcasecmp(argv[0], "outer") || - !strcasecmp(argv[0], "horizontal") || !strcasecmp(argv[0], "right"); - data.outer.bottom = !strcasecmp(argv[0], "outer") || - !strcasecmp(argv[0], "vertical") || !strcasecmp(argv[0], "bottom"); - data.outer.left = !strcasecmp(argv[0], "outer") || - !strcasecmp(argv[0], "horizontal") || !strcasecmp(argv[0], "left"); - } - if (!data.inner && !data.outer.top && !data.outer.right && - !data.outer.bottom && !data.outer.left) { - return cmd_results_new(CMD_INVALID, "Expected %s", expected_runtime); - } - - bool all; - if (strcasecmp(argv[1], "current") == 0) { - all = false; - } else if (strcasecmp(argv[1], "all") == 0) { - all = true; - } else { - return cmd_results_new(CMD_INVALID, "Expected %s", expected_runtime); - } - - if (strcasecmp(argv[2], "set") == 0) { - data.operation = GAPS_OP_SET; - } else if (strcasecmp(argv[2], "plus") == 0) { - data.operation = GAPS_OP_ADD; - } else if (strcasecmp(argv[2], "minus") == 0) { - data.operation = GAPS_OP_SUBTRACT; - } else if (strcasecmp(argv[2], "toggle") == 0) { - data.operation = GAPS_OP_TOGGLE; - } else { - return cmd_results_new(CMD_INVALID, "Expected %s", expected_runtime); - } - - char *end; - data.amount = strtol(argv[3], &end, 10); - if (strlen(end) && strcasecmp(end, "px") != 0) { - return cmd_results_new(CMD_INVALID, "Expected %s", expected_runtime); - } - - if (all) { - root_for_each_workspace(configure_gaps, &data); - } else { - configure_gaps(config->handler_context.workspace, &data); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} - -// gaps inner|outer|| - sets defaults for workspaces -// gaps inner|outer|| current|all set|plus|minus|toggle - runtime only -// = horizontal|vertical -// = top|right|bottom|left -struct cmd_results *cmd_gaps(int argc, char **argv) { - struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 2); - if (error) { - return error; - } - - bool config_loading = !config->active || config->reloading; - - if (argc == 2) { - return gaps_set_defaults(argc, argv); - } - if (argc == 4 && !config_loading) { - return gaps_set_runtime(argc, argv); - } - if (config_loading) { - return cmd_results_new(CMD_INVALID, "Expected %s", expected_defaults); - } - return cmd_results_new(CMD_INVALID, "Expected %s or %s", - expected_runtime, expected_defaults); -} diff --git a/sway/commands/gesture.c b/sway/commands/gesture.c deleted file mode 100644 index d4442cc35..000000000 --- a/sway/commands/gesture.c +++ /dev/null @@ -1,166 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include "sway/config.h" - -#include "gesture.h" -#include "log.h" -#include "stringop.h" -#include "sway/commands.h" - -void free_gesture_binding(struct sway_gesture_binding *binding) { - if (!binding) { - return; - } - free(binding->input); - free(binding->command); - free(binding); -} - -/** - * Returns true if the bindings have the same gesture type, direction, etc - */ -static bool binding_gesture_equal(struct sway_gesture_binding *binding_a, - struct sway_gesture_binding *binding_b) { - if (strcmp(binding_a->input, binding_b->input) != 0) { - return false; - } - - if (!gesture_equal(&binding_a->gesture, &binding_b->gesture)) { - return false; - } - - if ((binding_a->flags & BINDING_EXACT) != - (binding_b->flags & BINDING_EXACT)) { - return false; - } - return true; -} - -/** - * Add gesture binding to config - */ -static struct cmd_results *gesture_binding_add( - struct sway_gesture_binding *binding, - const char *gesturecombo, bool warn) { - list_t *mode_bindings = config->current_mode->gesture_bindings; - // overwrite the binding if it already exists - bool overwritten = false; - for (int i = 0; i < mode_bindings->length; ++i) { - struct sway_gesture_binding *config_binding = mode_bindings->items[i]; - if (binding_gesture_equal(binding, config_binding)) { - sway_log(SWAY_INFO, "Overwriting binding '%s' to `%s` from `%s`", - gesturecombo, binding->command, config_binding->command); - if (warn) { - config_add_swaynag_warning("Overwriting binding" - "'%s' to `%s` from `%s`", - gesturecombo, binding->command, - config_binding->command); - } - free_gesture_binding(config_binding); - mode_bindings->items[i] = binding; - overwritten = true; - } - } - - if (!overwritten) { - list_add(mode_bindings, binding); - sway_log(SWAY_DEBUG, "bindgesture - Bound %s to command `%s`", - gesturecombo, binding->command); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} - -/** - * Remove gesture binding from config - */ -static struct cmd_results *gesture_binding_remove( - struct sway_gesture_binding *binding, const char *gesturecombo) { - list_t *mode_bindings = config->current_mode->gesture_bindings; - for (int i = 0; i < mode_bindings->length; ++i) { - struct sway_gesture_binding *config_binding = mode_bindings->items[i]; - if (binding_gesture_equal(binding, config_binding)) { - free_gesture_binding(config_binding); - free_gesture_binding(binding); - list_del(mode_bindings, i); - sway_log(SWAY_DEBUG, "unbindgesture - Unbound %s gesture", - gesturecombo); - return cmd_results_new(CMD_SUCCESS, NULL); - } - } - - free_gesture_binding(binding); - return cmd_results_new(CMD_FAILURE, "Could not find gesture binding `%s`", - gesturecombo); -} - -/** - * Parse and execute bindgesture or unbindgesture command. - */ -static struct cmd_results *cmd_bind_or_unbind_gesture(int argc, char **argv, bool unbind) { - int minargs = 2; - char *bindtype = "bindgesture"; - if (unbind) { - minargs--; - bindtype = "unbindgesture"; - } - - struct cmd_results *error = NULL; - if ((error = checkarg(argc, bindtype, EXPECTED_AT_LEAST, minargs))) { - return error; - } - struct sway_gesture_binding *binding = calloc(1, sizeof(struct sway_gesture_binding)); - if (!binding) { - return cmd_results_new(CMD_FAILURE, "Unable to allocate binding"); - } - binding->input = strdup("*"); - - bool warn = true; - - // Handle flags - while (argc > 0) { - if (strcmp("--exact", argv[0]) == 0) { - binding->flags |= BINDING_EXACT; - } else if (strcmp("--no-warn", argv[0]) == 0) { - warn = false; - } else if (strncmp("--input-device=", argv[0], - strlen("--input-device=")) == 0) { - free(binding->input); - binding->input = strdup(argv[0] + strlen("--input-device=")); - } else { - break; - } - argv++; - argc--; - } - - if (argc < minargs) { - free(binding); - return cmd_results_new(CMD_FAILURE, - "Invalid %s command (expected at least %d " - "non-option arguments, got %d)", bindtype, minargs, argc); - } - - char* errmsg = NULL; - if ((errmsg = gesture_parse(argv[0], &binding->gesture))) { - free(binding); - struct cmd_results *final = cmd_results_new(CMD_FAILURE, - "Invalid %s command (%s)", - bindtype, errmsg); - free(errmsg); - return final; - } - - if (unbind) { - return gesture_binding_remove(binding, argv[0]); - } - binding->command = join_args(argv + 1, argc - 1); - return gesture_binding_add(binding, argv[0], warn); -} - -struct cmd_results *cmd_bindgesture(int argc, char **argv) { - return cmd_bind_or_unbind_gesture(argc, argv, false); -} - -struct cmd_results *cmd_unbindgesture(int argc, char **argv) { - return cmd_bind_or_unbind_gesture(argc, argv, true); -} diff --git a/sway/commands/hide_edge_borders.c b/sway/commands/hide_edge_borders.c deleted file mode 100644 index 43bd6dc86..000000000 --- a/sway/commands/hide_edge_borders.c +++ /dev/null @@ -1,48 +0,0 @@ -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/tree/arrange.h" -#include "sway/tree/view.h" - -struct cmd_results *cmd_hide_edge_borders(int argc, char **argv) { - const char *expected_syntax = "Expected 'hide_edge_borders [--i3] " - "none|vertical|horizontal|both|smart|smart_no_gaps"; - - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "hide_edge_borders", EXPECTED_AT_LEAST, 1))) { - return error; - } - - bool hide_lone_tab = false; - if (strcmp(*argv, "--i3") == 0) { - hide_lone_tab = true; - ++argv; - --argc; - } - - if (!argc) { - return cmd_results_new(CMD_INVALID, "%s", expected_syntax); - } - - if (strcmp(argv[0], "none") == 0) { - config->hide_edge_borders = E_NONE; - } else if (strcmp(argv[0], "vertical") == 0) { - config->hide_edge_borders = E_VERTICAL; - } else if (strcmp(argv[0], "horizontal") == 0) { - config->hide_edge_borders = E_HORIZONTAL; - } else if (strcmp(argv[0], "both") == 0) { - config->hide_edge_borders = E_BOTH; - } else if (strcmp(argv[0], "smart") == 0) { - config->hide_edge_borders = E_NONE; - config->hide_edge_borders_smart = ESMART_ON; - } else if (strcmp(argv[0], "smart_no_gaps") == 0) { - config->hide_edge_borders = E_NONE; - config->hide_edge_borders_smart = ESMART_NO_GAPS; - } else { - return cmd_results_new(CMD_INVALID, "%s", expected_syntax); - } - config->hide_lone_tab = hide_lone_tab; - - arrange_root(); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/include.c b/sway/commands/include.c deleted file mode 100644 index d4c14c35f..000000000 --- a/sway/commands/include.c +++ /dev/null @@ -1,14 +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; - } - - // We don't care if the included config(s) fails to load. - load_include_configs(argv[0], config, &config->swaynag_config_errors); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/inhibit_idle.c b/sway/commands/inhibit_idle.c deleted file mode 100644 index 6125736ac..000000000 --- a/sway/commands/inhibit_idle.c +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/desktop/idle_inhibit_v1.h" -#include "sway/tree/container.h" -#include "sway/tree/view.h" - -struct cmd_results *cmd_inhibit_idle(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "inhibit_idle", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - struct sway_container *con = config->handler_context.container; - if (!con || !con->view) { - return cmd_results_new(CMD_INVALID, - "Only views can have idle inhibitors"); - } - - bool clear = false; - enum sway_idle_inhibit_mode mode; - if (strcmp(argv[0], "focus") == 0) { - mode = INHIBIT_IDLE_FOCUS; - } else if (strcmp(argv[0], "fullscreen") == 0) { - mode = INHIBIT_IDLE_FULLSCREEN; - } else if (strcmp(argv[0], "open") == 0) { - mode = INHIBIT_IDLE_OPEN; - } else if (strcmp(argv[0], "none") == 0) { - clear = true; - } else if (strcmp(argv[0], "visible") == 0) { - mode = INHIBIT_IDLE_VISIBLE; - } else { - return cmd_results_new(CMD_INVALID, - "Expected `inhibit_idle focus|fullscreen|open|none|visible`"); - } - - struct sway_idle_inhibitor_v1 *inhibitor = - sway_idle_inhibit_v1_user_inhibitor_for_view(con->view); - if (inhibitor) { - if (clear) { - sway_idle_inhibit_v1_user_inhibitor_destroy(inhibitor); - } else { - inhibitor->mode = mode; - sway_idle_inhibit_v1_check_active(); - } - } else if (!clear) { - sway_idle_inhibit_v1_user_inhibitor_register(con->view, mode); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input.c b/sway/commands/input.c deleted file mode 100644 index 306c40f74..000000000 --- a/sway/commands/input.c +++ /dev/null @@ -1,106 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "sway/input/input-manager.h" -#include "sway/input/keyboard.h" -#include "log.h" -#include "stringop.h" - -// must be in order for the bsearch -static const struct cmd_handler input_handlers[] = { - { "accel_profile", input_cmd_accel_profile }, - { "calibration_matrix", input_cmd_calibration_matrix }, - { "click_method", input_cmd_click_method }, - { "drag", input_cmd_drag }, - { "drag_lock", input_cmd_drag_lock }, - { "dwt", input_cmd_dwt }, - { "dwtp", input_cmd_dwtp }, - { "events", input_cmd_events }, - { "left_handed", input_cmd_left_handed }, - { "map_from_region", input_cmd_map_from_region }, - { "map_to_output", input_cmd_map_to_output }, - { "map_to_region", input_cmd_map_to_region }, - { "middle_emulation", input_cmd_middle_emulation }, - { "natural_scroll", input_cmd_natural_scroll }, - { "pointer_accel", input_cmd_pointer_accel }, - { "repeat_delay", input_cmd_repeat_delay }, - { "repeat_rate", input_cmd_repeat_rate }, - { "rotation_angle", input_cmd_rotation_angle }, - { "scroll_button", input_cmd_scroll_button }, - { "scroll_button_lock", input_cmd_scroll_button_lock }, - { "scroll_factor", input_cmd_scroll_factor }, - { "scroll_method", input_cmd_scroll_method }, - { "tap", input_cmd_tap }, - { "tap_button_map", input_cmd_tap_button_map }, - { "tool_mode", input_cmd_tool_mode }, - { "xkb_file", input_cmd_xkb_file }, - { "xkb_layout", input_cmd_xkb_layout }, - { "xkb_model", input_cmd_xkb_model }, - { "xkb_options", input_cmd_xkb_options }, - { "xkb_rules", input_cmd_xkb_rules }, - { "xkb_switch_layout", input_cmd_xkb_switch_layout }, - { "xkb_variant", input_cmd_xkb_variant }, -}; - -// must be in order for the bsearch -static const struct cmd_handler input_config_handlers[] = { - { "xkb_capslock", input_cmd_xkb_capslock }, - { "xkb_numlock", input_cmd_xkb_numlock }, -}; - -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; - } - - sway_log(SWAY_DEBUG, "entering input block: %s", argv[0]); - - config->handler_context.input_config = new_input_config(argv[0]); - if (!config->handler_context.input_config) { - return cmd_results_new(CMD_FAILURE, "Couldn't allocate config"); - } - - struct cmd_results *res; - - if (find_handler(argv[1], input_config_handlers, - sizeof(input_config_handlers))) { - if (config->reading) { - res = config_subcommand(argv + 1, argc - 1, - input_config_handlers, sizeof(input_config_handlers)); - } else { - res = cmd_results_new(CMD_FAILURE, - "Can only be used in config file."); - } - } else { - res = config_subcommand(argv + 1, argc - 1, - input_handlers, sizeof(input_handlers)); - } - - if ((!res || res->status == CMD_SUCCESS) && - strcmp(argv[1], "xkb_switch_layout") != 0) { - char *error = NULL; - struct input_config *ic = - store_input_config(config->handler_context.input_config, &error); - if (!ic) { - free_input_config(config->handler_context.input_config); - if (res) { - free_cmd_results(res); - } - res = cmd_results_new(CMD_FAILURE, "Failed to compile keymap: %s", - error ? error : "(details unavailable)"); - free(error); - return res; - } - - if (!config->reloading) { - input_manager_apply_input_config(ic); - } - } else { - free_input_config(config->handler_context.input_config); - } - - config->handler_context.input_config = NULL; - - return res; -} diff --git a/sway/commands/input/accel_profile.c b/sway/commands/input/accel_profile.c deleted file mode 100644 index 08f324cca..000000000 --- a/sway/commands/input/accel_profile.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include -#include "sway/config.h" -#include "sway/commands.h" -#include "sway/input/input-manager.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; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - if (strcasecmp(argv[0], "adaptive") == 0) { - ic->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE; - } else if (strcasecmp(argv[0], "flat") == 0) { - ic->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT; - } else { - return cmd_results_new(CMD_INVALID, - "Expected 'accel_profile '"); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/calibration_matrix.c b/sway/commands/input/calibration_matrix.c deleted file mode 100644 index 38749fbb9..000000000 --- a/sway/commands/input/calibration_matrix.c +++ /dev/null @@ -1,35 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include "sway/config.h" -#include "sway/commands.h" -#include "sway/input/input-manager.h" -#include "log.h" -#include "stringop.h" -#include "util.h" - -struct cmd_results *input_cmd_calibration_matrix(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "calibration_matrix", EXPECTED_EQUAL_TO, 6))) { - return error; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - float parsed[6]; - for (int i = 0; i < argc; ++i) { - char *item = argv[i]; - float x = parse_float(item); - if (isnan(x)) { - return cmd_results_new(CMD_FAILURE, "calibration_matrix: unable to parse float: %s", item); - } - parsed[i] = x; - } - - ic->calibration_matrix.configured = true; - memcpy(ic->calibration_matrix.matrix, parsed, sizeof(ic->calibration_matrix.matrix)); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/click_method.c b/sway/commands/input/click_method.c deleted file mode 100644 index 919c7cb7d..000000000 --- a/sway/commands/input/click_method.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/input/input-manager.h" -#include "log.h" - -struct cmd_results *input_cmd_click_method(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "click_method", EXPECTED_AT_LEAST, 1))) { - return error; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - if (strcasecmp(argv[0], "none") == 0) { - ic->click_method = LIBINPUT_CONFIG_CLICK_METHOD_NONE; - } else if (strcasecmp(argv[0], "button_areas") == 0) { - ic->click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS; - } else if (strcasecmp(argv[0], "clickfinger") == 0) { - ic->click_method = LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER; - } else { - return cmd_results_new(CMD_INVALID, - "Expected 'click_method '"); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/drag.c b/sway/commands/input/drag.c deleted file mode 100644 index 062357d4f..000000000 --- a/sway/commands/input/drag.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include -#include "sway/config.h" -#include "sway/commands.h" -#include "sway/input/input-manager.h" -#include "util.h" - -struct cmd_results *input_cmd_drag(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "drag", EXPECTED_AT_LEAST, 1))) { - return error; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - if (parse_boolean(argv[0], true)) { - ic->drag = LIBINPUT_CONFIG_DRAG_ENABLED; - } else { - ic->drag = LIBINPUT_CONFIG_DRAG_DISABLED; - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/drag_lock.c b/sway/commands/input/drag_lock.c deleted file mode 100644 index 24c548e2d..000000000 --- a/sway/commands/input/drag_lock.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include -#include "sway/config.h" -#include "sway/commands.h" -#include "sway/input/input-manager.h" -#include "util.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; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - if (parse_boolean(argv[0], true)) { - ic->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED; - } else { - ic->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_DISABLED; - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/dwt.c b/sway/commands/input/dwt.c deleted file mode 100644 index a7a4e4943..000000000 --- a/sway/commands/input/dwt.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include -#include "sway/config.h" -#include "sway/commands.h" -#include "sway/input/input-manager.h" -#include "util.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; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - if (parse_boolean(argv[0], true)) { - ic->dwt = LIBINPUT_CONFIG_DWT_ENABLED; - } else { - ic->dwt = LIBINPUT_CONFIG_DWT_DISABLED; - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/dwtp.c b/sway/commands/input/dwtp.c deleted file mode 100644 index 232e2b261..000000000 --- a/sway/commands/input/dwtp.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include -#include "sway/config.h" -#include "sway/commands.h" -#include "sway/input/input-manager.h" -#include "util.h" - -struct cmd_results *input_cmd_dwtp(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "dwtp", EXPECTED_AT_LEAST, 1))) { - return error; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - if (parse_boolean(argv[0], true)) { - ic->dwtp = LIBINPUT_CONFIG_DWTP_ENABLED; - } else { - ic->dwtp = LIBINPUT_CONFIG_DWTP_DISABLED; - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/events.c b/sway/commands/input/events.c deleted file mode 100644 index 08d99bf0b..000000000 --- a/sway/commands/input/events.c +++ /dev/null @@ -1,163 +0,0 @@ -#include -#include -#include -#include -#include "sway/config.h" -#include "sway/commands.h" -#include "sway/input/input-manager.h" -#include "log.h" - -#if WLR_HAS_LIBINPUT_BACKEND -#include -#endif - -static void toggle_supported_send_events_for_device(struct input_config *ic, - struct sway_input_device *input_device) { -#if WLR_HAS_LIBINPUT_BACKEND - struct wlr_input_device *wlr_device = input_device->wlr_device; - if (!wlr_input_device_is_libinput(wlr_device)) { - return; - } - struct libinput_device *libinput_dev = - wlr_libinput_get_device_handle(wlr_device); - - enum libinput_config_send_events_mode mode = - libinput_device_config_send_events_get_mode(libinput_dev); - uint32_t possible = - libinput_device_config_send_events_get_modes(libinput_dev); - - switch (mode) { - case LIBINPUT_CONFIG_SEND_EVENTS_ENABLED: - mode = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE; - if (possible & mode) { - break; - } - // fall through - case LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE: - mode = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED; - if (possible & mode) { - break; - } - // fall through - case LIBINPUT_CONFIG_SEND_EVENTS_DISABLED: - default: - mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; - break; - } - - ic->send_events = mode; -#endif -} - -static int mode_for_name(const char *name) { - if (!strcmp(name, "enabled")) { - return LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; - } else if (!strcmp(name, "disabled_on_external_mouse")) { - return LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE; - } else if (!strcmp(name, "disabled")) { - return LIBINPUT_CONFIG_SEND_EVENTS_DISABLED; - } - return -1; -} - -static void toggle_select_send_events_for_device(struct input_config *ic, - struct sway_input_device *input_device, int argc, char **argv) { -#if WLR_HAS_LIBINPUT_BACKEND - if (!wlr_input_device_is_libinput(input_device->wlr_device)) { - return; - } - // Get the currently set event mode since ic is a new config that will be - // merged on the existing later. It should be set to INT_MIN before this. - ic->send_events = libinput_device_config_send_events_get_mode( - wlr_libinput_get_device_handle(input_device->wlr_device)); - - int index; - for (index = 0; index < argc; ++index) { - if (mode_for_name(argv[index]) == ic->send_events) { - ++index; - break; - } - } - ic->send_events = mode_for_name(argv[index % argc]); -#endif -} - -static void toggle_send_events(int argc, char **argv) { - struct input_config *ic = config->handler_context.input_config; - bool wildcard = strcmp(ic->identifier, "*") == 0; - const char *type = strncmp(ic->identifier, "type:", strlen("type:")) == 0 - ? ic->identifier + strlen("type:") : NULL; - struct sway_input_device *device = NULL; - wl_list_for_each(device, &server.input->devices, link) { - if (wildcard || type) { - ic = new_input_config(device->identifier); - if (!ic) { - continue; - } - if (type && strcmp(input_device_get_type(device), type) != 0) { - continue; - } - } else if (strcmp(ic->identifier, device->identifier) != 0) { - continue; - } - - if (argc) { - toggle_select_send_events_for_device(ic, device, argc, argv); - } else { - toggle_supported_send_events_for_device(ic, device); - } - - if (wildcard || type) { - store_input_config(ic, NULL); - } else { - return; - } - } -} - -struct cmd_results *input_cmd_events(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "events", EXPECTED_AT_LEAST, 1))) { - return error; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - if (strcasecmp(argv[0], "enabled") == 0) { - ic->send_events = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; - } else if (strcasecmp(argv[0], "disabled") == 0) { - ic->send_events = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED; - } else if (strcasecmp(argv[0], "disabled_on_external_mouse") == 0) { - ic->send_events = - LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE; - } else if (config->reading) { - return cmd_results_new(CMD_INVALID, - "Expected 'events '"); - } else if (strcasecmp(argv[0], "toggle") == 0) { - for (int i = 1; i < argc; ++i) { - if (mode_for_name(argv[i]) == -1) { - return cmd_results_new(CMD_INVALID, - "Invalid toggle mode %s", argv[i]); - } - } - - toggle_send_events(argc - 1, argv + 1); - - if (strcmp(ic->identifier, "*") == 0 || - strncmp(ic->identifier, "type:", strlen("type:")) == 0) { - // Update the device input configs and then reset the type/wildcard - // config send events mode so that is does not override the device - // ones. The device ones will be applied when attempting to apply - // the type/wildcard config - ic->send_events = INT_MIN; - } - } else { - return cmd_results_new(CMD_INVALID, - "Expected 'events '"); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/left_handed.c b/sway/commands/input/left_handed.c deleted file mode 100644 index 93d8d56d8..000000000 --- a/sway/commands/input/left_handed.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include -#include "sway/config.h" -#include "sway/commands.h" -#include "sway/input/input-manager.h" -#include "util.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; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - ic->left_handed = parse_boolean(argv[0], true); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/map_from_region.c b/sway/commands/input/map_from_region.c deleted file mode 100644 index 4400e111c..000000000 --- a/sway/commands/input/map_from_region.c +++ /dev/null @@ -1,87 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include "log.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/input/input-manager.h" - -static bool parse_coords(const char *str, double *x, double *y, bool *mm) { - *mm = false; - - char *end; - - // Check for "0x" prefix to avoid strtod treating the string as hex - if (str[0] == '0' && str[1] == 'x') { - if (strlen(str) < 3) { - return false; - } - *x = 0; - end = (char *)str + 2; - } else { - *x = strtod(str, &end); - if (end[0] != 'x') { - return false; - } - ++end; - } - - *y = strtod(end, &end); - if (end[0] == 'm') { - // Expect mm - if (end[1] != 'm') { - return false; - } - *mm = true; - end = &end[2]; - } - if (end[0] != '\0') { - return false; - } - - return true; -} - -struct cmd_results *input_cmd_map_from_region(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "map_from_region", EXPECTED_EQUAL_TO, 2))) { - return error; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined"); - } - - ic->mapped_from_region = - calloc(1, sizeof(struct input_config_mapped_from_region)); - - bool mm1, mm2; - if (!parse_coords(argv[0], &ic->mapped_from_region->x1, - &ic->mapped_from_region->y1, &mm1)) { - free(ic->mapped_from_region); - ic->mapped_from_region = NULL; - return cmd_results_new(CMD_FAILURE, "Invalid top-left coordinates"); - } - if (!parse_coords(argv[1], &ic->mapped_from_region->x2, - &ic->mapped_from_region->y2, &mm2)) { - free(ic->mapped_from_region); - ic->mapped_from_region = NULL; - return cmd_results_new(CMD_FAILURE, "Invalid bottom-right coordinates"); - } - if (ic->mapped_from_region->x1 > ic->mapped_from_region->x2 || - ic->mapped_from_region->y1 > ic->mapped_from_region->y2) { - free(ic->mapped_from_region); - ic->mapped_from_region = NULL; - return cmd_results_new(CMD_FAILURE, "Invalid rectangle"); - } - if (mm1 != mm2) { - free(ic->mapped_from_region); - ic->mapped_from_region = NULL; - return cmd_results_new(CMD_FAILURE, - "Both coordinates must be in the same unit"); - } - ic->mapped_from_region->mm = mm1; - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/map_to_output.c b/sway/commands/input/map_to_output.c deleted file mode 100644 index f60fb7d57..000000000 --- a/sway/commands/input/map_to_output.c +++ /dev/null @@ -1,23 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include "sway/config.h" -#include "sway/commands.h" -#include "sway/input/input-manager.h" -#include "log.h" - -struct cmd_results *input_cmd_map_to_output(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "map_to_output", EXPECTED_EQUAL_TO, 1))) { - return error; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - ic->mapped_to = MAPPED_TO_OUTPUT; - ic->mapped_to_output = strdup(argv[0]); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/map_to_region.c b/sway/commands/input/map_to_region.c deleted file mode 100644 index ad535db23..000000000 --- a/sway/commands/input/map_to_region.c +++ /dev/null @@ -1,53 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include "sway/commands.h" -#include "sway/config.h" - -struct cmd_results *input_cmd_map_to_region(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "map_to_region", EXPECTED_EQUAL_TO, 4))) { - return error; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined"); - } - - ic->mapped_to = MAPPED_TO_REGION; - ic->mapped_to_region = calloc(1, sizeof(struct wlr_box)); - - const char *errstr; - char *end; - - ic->mapped_to_region->x = strtol(argv[0], &end, 10); - if (end[0] != '\0') { - errstr = "Invalid X coordinate"; - goto error; - } - - ic->mapped_to_region->y = strtol(argv[1], &end, 10); - if (end[0] != '\0') { - errstr = "Invalid Y coordinate"; - goto error; - } - - ic->mapped_to_region->width = strtol(argv[2], &end, 10); - if (end[0] != '\0' || ic->mapped_to_region->width < 1) { - errstr = "Invalid width"; - goto error; - } - - ic->mapped_to_region->height = strtol(argv[3], &end, 10); - if (end[0] != '\0' || ic->mapped_to_region->height < 1) { - errstr = "Invalid height"; - goto error; - } - - return cmd_results_new(CMD_SUCCESS, NULL); - -error: - free(ic->mapped_to_region); - ic->mapped_to_region = NULL; - return cmd_results_new(CMD_FAILURE, "%s", errstr); -} diff --git a/sway/commands/input/middle_emulation.c b/sway/commands/input/middle_emulation.c deleted file mode 100644 index 9f32692e0..000000000 --- a/sway/commands/input/middle_emulation.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include -#include "sway/config.h" -#include "sway/commands.h" -#include "sway/input/input-manager.h" -#include "util.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; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - if (parse_boolean(argv[0], true)) { - ic->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED; - } else { - ic->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED; - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/natural_scroll.c b/sway/commands/input/natural_scroll.c deleted file mode 100644 index dec32a5ba..000000000 --- a/sway/commands/input/natural_scroll.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include -#include "sway/config.h" -#include "sway/commands.h" -#include "sway/input/input-manager.h" -#include "util.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; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - ic->natural_scroll = parse_boolean(argv[0], true); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/pointer_accel.c b/sway/commands/input/pointer_accel.c deleted file mode 100644 index e214b32f8..000000000 --- a/sway/commands/input/pointer_accel.c +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include -#include -#include "sway/config.h" -#include "sway/commands.h" -#include "sway/input/input-manager.h" -#include "util.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; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - float pointer_accel = parse_float(argv[0]); - if (isnan(pointer_accel)) { - return cmd_results_new(CMD_INVALID, - "Invalid pointer accel; expected float."); - } if (pointer_accel < -1 || pointer_accel > 1) { - return cmd_results_new(CMD_INVALID, "Input out of range [-1, 1]"); - } - ic->pointer_accel = pointer_accel; - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/repeat_delay.c b/sway/commands/input/repeat_delay.c deleted file mode 100644 index 5b787fe63..000000000 --- a/sway/commands/input/repeat_delay.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include -#include "sway/config.h" -#include "sway/commands.h" -#include "sway/input/input-manager.h" - -struct cmd_results *input_cmd_repeat_delay(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "repeat_delay", EXPECTED_EQUAL_TO, 1))) { - return error; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - int repeat_delay = atoi(argv[0]); - if (repeat_delay < 0) { - return cmd_results_new(CMD_INVALID, "Repeat delay cannot be negative"); - } - ic->repeat_delay = repeat_delay; - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/repeat_rate.c b/sway/commands/input/repeat_rate.c deleted file mode 100644 index 79c5efe22..000000000 --- a/sway/commands/input/repeat_rate.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include -#include "sway/config.h" -#include "sway/commands.h" -#include "sway/input/input-manager.h" - -struct cmd_results *input_cmd_repeat_rate(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "repeat_rate", EXPECTED_EQUAL_TO, 1))) { - return error; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - int repeat_rate = atoi(argv[0]); - if (repeat_rate < 0) { - return cmd_results_new(CMD_INVALID, "Repeat rate cannot be negative"); - } - ic->repeat_rate = repeat_rate; - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/rotation_angle.c b/sway/commands/input/rotation_angle.c deleted file mode 100644 index 5e278fff7..000000000 --- a/sway/commands/input/rotation_angle.c +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include -#include -#include "sway/config.h" -#include "sway/commands.h" -#include "sway/input/input-manager.h" -#include "util.h" - -struct cmd_results *input_cmd_rotation_angle(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "rotation_angle", EXPECTED_AT_LEAST, 1))) { - return error; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - float rotation_angle = parse_float(argv[0]); - if (isnan(rotation_angle)) { - return cmd_results_new(CMD_INVALID, - "Invalid rotation_angle; expected float."); - } if (rotation_angle < 0 || rotation_angle > 360) { - return cmd_results_new(CMD_INVALID, "Input out of range [0, 360)"); - } - ic->rotation_angle = rotation_angle; - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/scroll_button.c b/sway/commands/input/scroll_button.c deleted file mode 100644 index 81f69a6df..000000000 --- a/sway/commands/input/scroll_button.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include "sway/config.h" -#include "sway/commands.h" -#include "sway/input/cursor.h" - -struct cmd_results *input_cmd_scroll_button(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "scroll_button", EXPECTED_AT_LEAST, 1))) { - return error; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - if (strcmp(*argv, "disable") == 0) { - ic->scroll_button = 0; - return cmd_results_new(CMD_SUCCESS, NULL); - } - - char *message = NULL; - uint32_t button = get_mouse_button(*argv, &message); - if (message) { - error = cmd_results_new(CMD_INVALID, "%s", message); - free(message); - return error; - } else if (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_DOWN - || button == SWAY_SCROLL_LEFT || button == SWAY_SCROLL_RIGHT) { - return cmd_results_new(CMD_INVALID, - "X11 axis buttons are not supported for scroll_button"); - } else if (!button) { - return cmd_results_new(CMD_INVALID, "Unknown button %s", *argv); - } - ic->scroll_button = button; - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/scroll_button_lock.c b/sway/commands/input/scroll_button_lock.c deleted file mode 100644 index f96b65145..000000000 --- a/sway/commands/input/scroll_button_lock.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include -#include -#include "sway/config.h" -#include "sway/commands.h" -#include "sway/input/input-manager.h" -#include "util.h" - -struct cmd_results *input_cmd_scroll_button_lock(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "scroll_button_lock", EXPECTED_AT_LEAST, 1))) { - return error; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - if (parse_boolean(argv[0], true)) { - ic->scroll_button_lock = LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_ENABLED; - } else { - ic->scroll_button_lock = LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED; - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/scroll_factor.c b/sway/commands/input/scroll_factor.c deleted file mode 100644 index 4b72b6fa8..000000000 --- a/sway/commands/input/scroll_factor.c +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include -#include -#include -#include "sway/config.h" -#include "sway/commands.h" -#include "sway/input/input-manager.h" -#include "util.h" - -struct cmd_results *input_cmd_scroll_factor(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "scroll_factor", EXPECTED_AT_LEAST, 1))) { - return error; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - float scroll_factor = parse_float(argv[0]); - if (isnan(scroll_factor)) { - return cmd_results_new(CMD_INVALID, - "Invalid scroll factor; expected float."); - } else if (scroll_factor < 0) { - return cmd_results_new(CMD_INVALID, - "Scroll factor cannot be negative."); - } - ic->scroll_factor = scroll_factor; - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/scroll_method.c b/sway/commands/input/scroll_method.c deleted file mode 100644 index cd8b5f7a7..000000000 --- a/sway/commands/input/scroll_method.c +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include -#include "sway/config.h" -#include "sway/commands.h" -#include "sway/input/input-manager.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; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - if (strcasecmp(argv[0], "none") == 0) { - ic->scroll_method = LIBINPUT_CONFIG_SCROLL_NO_SCROLL; - } else if (strcasecmp(argv[0], "two_finger") == 0) { - ic->scroll_method = LIBINPUT_CONFIG_SCROLL_2FG; - } else if (strcasecmp(argv[0], "edge") == 0) { - ic->scroll_method = LIBINPUT_CONFIG_SCROLL_EDGE; - } else if (strcasecmp(argv[0], "on_button_down") == 0) { - ic->scroll_method = LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN; - } else { - return cmd_results_new(CMD_INVALID, - "Expected 'scroll_method '"); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/tap.c b/sway/commands/input/tap.c deleted file mode 100644 index 443fd49d7..000000000 --- a/sway/commands/input/tap.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include -#include "sway/config.h" -#include "sway/commands.h" -#include "sway/input/input-manager.h" -#include "log.h" -#include "util.h" - -struct cmd_results *input_cmd_tap(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "tap", EXPECTED_AT_LEAST, 1))) { - return error; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - if (parse_boolean(argv[0], true)) { - ic->tap = LIBINPUT_CONFIG_TAP_ENABLED; - } else { - ic->tap = LIBINPUT_CONFIG_TAP_DISABLED; - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/tap_button_map.c b/sway/commands/input/tap_button_map.c deleted file mode 100644 index 77ac6de7b..000000000 --- a/sway/commands/input/tap_button_map.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include -#include "sway/config.h" -#include "sway/commands.h" -#include "sway/input/input-manager.h" - -struct cmd_results *input_cmd_tap_button_map(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "tap_button_map", EXPECTED_AT_LEAST, 1))) { - return error; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - if (strcasecmp(argv[0], "lrm") == 0) { - ic->tap_button_map = LIBINPUT_CONFIG_TAP_MAP_LRM; - } else if (strcasecmp(argv[0], "lmr") == 0) { - ic->tap_button_map = LIBINPUT_CONFIG_TAP_MAP_LMR; - } else { - return cmd_results_new(CMD_INVALID, - "Expected 'tap_button_map '"); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/tool_mode.c b/sway/commands/input/tool_mode.c deleted file mode 100644 index 04316857f..000000000 --- a/sway/commands/input/tool_mode.c +++ /dev/null @@ -1,73 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" - -static void set_tool_mode(struct input_config *ic, - enum wlr_tablet_tool_type type, enum sway_tablet_tool_mode mode) { - for (int i = 0; i < ic->tools->length; i++) { - struct input_config_tool *tool = ic->tools->items[i]; - if (tool->type == type) { - tool->mode = mode; - return; - } - } - - struct input_config_tool *tool = calloc(1, sizeof(*tool)); - if (tool) { - tool->type = type; - tool->mode = mode; - list_add(ic->tools, tool); - } -} - -struct cmd_results *input_cmd_tool_mode(int argc, char **argv) { - struct cmd_results *error; - if ((error = checkarg(argc, "tool_mode", EXPECTED_AT_LEAST, 2))) { - return error; - } - - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - enum sway_tablet_tool_mode tool_mode; - if (!strcasecmp(argv[1], "absolute")) { - tool_mode = SWAY_TABLET_TOOL_MODE_ABSOLUTE; - } else if (!strcasecmp(argv[1], "relative")) { - tool_mode = SWAY_TABLET_TOOL_MODE_RELATIVE; - } else { - goto invalid_command; - } - - if (!strcasecmp(argv[0], "*")) { - set_tool_mode(ic, WLR_TABLET_TOOL_TYPE_PEN, tool_mode); - set_tool_mode(ic, WLR_TABLET_TOOL_TYPE_ERASER, tool_mode); - set_tool_mode(ic, WLR_TABLET_TOOL_TYPE_BRUSH, tool_mode); - set_tool_mode(ic, WLR_TABLET_TOOL_TYPE_PENCIL, tool_mode); - set_tool_mode(ic, WLR_TABLET_TOOL_TYPE_AIRBRUSH, tool_mode); - } else { - enum wlr_tablet_tool_type tool_type; - if (!strcasecmp(argv[0], "pen")) { - tool_type = WLR_TABLET_TOOL_TYPE_PEN; - } else if (!strcasecmp(argv[0], "eraser")) { - tool_type = WLR_TABLET_TOOL_TYPE_ERASER; - } else if (!strcasecmp(argv[0], "brush")) { - tool_type = WLR_TABLET_TOOL_TYPE_BRUSH; - } else if (!strcasecmp(argv[0], "pencil")) { - tool_type = WLR_TABLET_TOOL_TYPE_PENCIL; - } else if (!strcasecmp(argv[0], "airbrush")) { - tool_type = WLR_TABLET_TOOL_TYPE_AIRBRUSH; - } else { - goto invalid_command; - } - - set_tool_mode(ic, tool_type, tool_mode); - } - - return cmd_results_new(CMD_SUCCESS, NULL); - -invalid_command: - return cmd_results_new(CMD_INVALID, - "Expected 'tool_mode '"); -} diff --git a/sway/commands/input/xkb_capslock.c b/sway/commands/input/xkb_capslock.c deleted file mode 100644 index 7ce98ebbe..000000000 --- a/sway/commands/input/xkb_capslock.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include -#include "sway/config.h" -#include "sway/commands.h" -#include "sway/input/input-manager.h" -#include "util.h" - -struct cmd_results *input_cmd_xkb_capslock(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "xkb_capslock", EXPECTED_AT_LEAST, 1))) { - return error; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - ic->xkb_capslock = parse_boolean(argv[0], false); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/xkb_file.c b/sway/commands/input/xkb_file.c deleted file mode 100644 index 493f94fbd..000000000 --- a/sway/commands/input/xkb_file.c +++ /dev/null @@ -1,49 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include "sway/config.h" -#include "sway/commands.h" -#include "log.h" -#include "stringop.h" - -struct cmd_results *input_cmd_xkb_file(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "xkb_file", EXPECTED_EQUAL_TO, 1))) { - return error; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - if (strcmp(argv[0], "-") == 0) { - free(ic->xkb_file); - ic->xkb_file = NULL; - } else { - ic->xkb_file = strdup(argv[0]); - if (!expand_path(&ic->xkb_file)) { - error = cmd_results_new(CMD_INVALID, "Invalid syntax (%s)", - ic->xkb_file); - free(ic->xkb_file); - ic->xkb_file = NULL; - return error; - } - if (!ic->xkb_file) { - sway_log(SWAY_ERROR, "Failed to allocate expanded path"); - return cmd_results_new(CMD_FAILURE, "Unable to allocate resource"); - } - - bool can_access = access(ic->xkb_file, F_OK) != -1; - if (!can_access) { - sway_log_errno(SWAY_ERROR, "Unable to access xkb file '%s'", - ic->xkb_file); - config_add_swaynag_warning("Unable to access xkb file '%s'", - ic->xkb_file); - } - } - ic->xkb_file_is_set = true; - - sway_log(SWAY_DEBUG, "set-xkb_file for config: %s file: %s", - ic->identifier, ic->xkb_file); - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/xkb_layout.c b/sway/commands/input/xkb_layout.c deleted file mode 100644 index 226265175..000000000 --- a/sway/commands/input/xkb_layout.c +++ /dev/null @@ -1,21 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include "sway/config.h" -#include "sway/commands.h" -#include "log.h" - -struct cmd_results *input_cmd_xkb_layout(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "xkb_layout", EXPECTED_EQUAL_TO, 1))) { - return error; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - ic->xkb_layout = strdup(argv[0]); - - sway_log(SWAY_DEBUG, "set-xkb_layout for config: %s layout: %s", - ic->identifier, ic->xkb_layout); - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/xkb_model.c b/sway/commands/input/xkb_model.c deleted file mode 100644 index f4a33de3e..000000000 --- a/sway/commands/input/xkb_model.c +++ /dev/null @@ -1,21 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include "sway/config.h" -#include "sway/commands.h" -#include "log.h" - -struct cmd_results *input_cmd_xkb_model(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "xkb_model", EXPECTED_EQUAL_TO, 1))) { - return error; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - ic->xkb_model = strdup(argv[0]); - - sway_log(SWAY_DEBUG, "set-xkb_model for config: %s model: %s", - ic->identifier, ic->xkb_model); - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/xkb_numlock.c b/sway/commands/input/xkb_numlock.c deleted file mode 100644 index 87d3e60c1..000000000 --- a/sway/commands/input/xkb_numlock.c +++ /dev/null @@ -1,19 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include "sway/config.h" -#include "sway/commands.h" -#include "util.h" - -struct cmd_results *input_cmd_xkb_numlock(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "xkb_numlock", EXPECTED_AT_LEAST, 1))) { - return error; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - ic->xkb_numlock = parse_boolean(argv[0], false); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/xkb_options.c b/sway/commands/input/xkb_options.c deleted file mode 100644 index d609293f7..000000000 --- a/sway/commands/input/xkb_options.c +++ /dev/null @@ -1,21 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include "sway/config.h" -#include "sway/commands.h" -#include "log.h" - -struct cmd_results *input_cmd_xkb_options(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "xkb_options", EXPECTED_EQUAL_TO, 1))) { - return error; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - ic->xkb_options = strdup(argv[0]); - - sway_log(SWAY_DEBUG, "set-xkb_options for config: %s options: %s", - ic->identifier, ic->xkb_options); - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/xkb_rules.c b/sway/commands/input/xkb_rules.c deleted file mode 100644 index 3b59622c4..000000000 --- a/sway/commands/input/xkb_rules.c +++ /dev/null @@ -1,21 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include "sway/config.h" -#include "sway/commands.h" -#include "log.h" - -struct cmd_results *input_cmd_xkb_rules(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "xkb_rules", EXPECTED_EQUAL_TO, 1))) { - return error; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - ic->xkb_rules = strdup(argv[0]); - - sway_log(SWAY_DEBUG, "set-xkb_rules for config: %s rules: %s", - ic->identifier, ic->xkb_rules); - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/xkb_switch_layout.c b/sway/commands/input/xkb_switch_layout.c deleted file mode 100644 index 3cce4ec8d..000000000 --- a/sway/commands/input/xkb_switch_layout.c +++ /dev/null @@ -1,115 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include "sway/config.h" -#include "sway/commands.h" -#include "sway/input/input-manager.h" -#include "log.h" - -struct xkb_switch_layout_action { - struct wlr_keyboard *keyboard; - xkb_layout_index_t layout; -}; - -static void switch_layout(struct wlr_keyboard *kbd, xkb_layout_index_t idx) { - xkb_layout_index_t num_layouts = xkb_keymap_num_layouts(kbd->keymap); - if (idx >= num_layouts) { - return; - } - wlr_keyboard_notify_modifiers(kbd, kbd->modifiers.depressed, - kbd->modifiers.latched, kbd->modifiers.locked, idx); -} - -static xkb_layout_index_t get_current_layout_index(struct wlr_keyboard *kbd) { - xkb_layout_index_t num_layouts = xkb_keymap_num_layouts(kbd->keymap); - assert(num_layouts > 0); - - xkb_layout_index_t layout_idx; - for (layout_idx = 0; layout_idx < num_layouts; layout_idx++) { - if (xkb_state_layout_index_is_active(kbd->xkb_state, - layout_idx, XKB_STATE_LAYOUT_EFFECTIVE)) { - break; - } - } - return layout_idx; -} - -static xkb_layout_index_t get_layout_relative(struct wlr_keyboard *kbd, int dir) { - xkb_layout_index_t num_layouts = xkb_keymap_num_layouts(kbd->keymap); - xkb_layout_index_t idx = get_current_layout_index(kbd); - return (idx + num_layouts + dir) % num_layouts; -} - -struct cmd_results *input_cmd_xkb_switch_layout(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "xkb_switch_layout", EXPECTED_EQUAL_TO, 1))) { - return error; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - if (config->reading || !config->active) { - return cmd_results_new(CMD_DEFER, NULL); - } - - const char *layout_str = argv[0]; - int relative, layout; - - if (strcmp(layout_str, "next") == 0) { - relative = 1; - } else if (strcmp(layout_str, "prev") == 0) { - relative = -1; - } else { - char *end; - layout = strtol(layout_str, &end, 10); - if (layout_str[0] == '\0' || end[0] != '\0') { - return cmd_results_new(CMD_FAILURE, "Invalid argument."); - } else if (layout < 0) { - return cmd_results_new(CMD_FAILURE, "Invalid layout index."); - } - relative = 0; - } - - struct xkb_switch_layout_action *actions = calloc( - wl_list_length(&server.input->devices), - sizeof(struct xkb_switch_layout_action)); - size_t actions_len = 0; - - if (!actions) { - return cmd_results_new(CMD_FAILURE, "Unable to allocate actions"); - } - - /* Calculate new indexes first because switching a layout in one - keyboard may result in a change on other keyboards as well because - of keyboard groups. */ - struct sway_input_device *dev; - wl_list_for_each(dev, &server.input->devices, link) { - if (strcmp(ic->identifier, "*") != 0 && - strcmp(ic->identifier, "type:keyboard") != 0 && - strcmp(ic->identifier, dev->identifier) != 0) { - continue; - } - if (dev->wlr_device->type != WLR_INPUT_DEVICE_KEYBOARD) { - continue; - } - - struct xkb_switch_layout_action *action = - &actions[actions_len++]; - - action->keyboard = wlr_keyboard_from_input_device(dev->wlr_device); - if (relative) { - action->layout = get_layout_relative(action->keyboard, relative); - } else { - action->layout = layout; - } - } - - for (size_t i = 0; i < actions_len; i++) { - switch_layout(actions[i].keyboard, actions[i].layout); - } - free(actions); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/input/xkb_variant.c b/sway/commands/input/xkb_variant.c deleted file mode 100644 index d0e21d778..000000000 --- a/sway/commands/input/xkb_variant.c +++ /dev/null @@ -1,21 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include "sway/config.h" -#include "sway/commands.h" -#include "log.h" - -struct cmd_results *input_cmd_xkb_variant(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "xkb_variant", EXPECTED_EQUAL_TO, 1))) { - return error; - } - struct input_config *ic = config->handler_context.input_config; - if (!ic) { - return cmd_results_new(CMD_FAILURE, "No input device defined."); - } - - ic->xkb_variant = strdup(argv[0]); - - sway_log(SWAY_DEBUG, "set-xkb_variant for config: %s variant: %s", - ic->identifier, ic->xkb_variant); - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/kill.c b/sway/commands/kill.c deleted file mode 100644 index f1e95e4bb..000000000 --- a/sway/commands/kill.c +++ /dev/null @@ -1,31 +0,0 @@ -#include "log.h" -#include "sway/input/input-manager.h" -#include "sway/input/seat.h" -#include "sway/tree/container.h" -#include "sway/tree/view.h" -#include "sway/tree/workspace.h" -#include "sway/commands.h" - -static void close_container_iterator(struct sway_container *con, void *data) { - if (con->view) { - view_close(con->view); - } -} - -struct cmd_results *cmd_kill(int argc, char **argv) { - if (!root->outputs->length) { - return cmd_results_new(CMD_INVALID, - "Can't run this command while there's no outputs connected."); - } - struct sway_container *con = config->handler_context.container; - struct sway_workspace *ws = config->handler_context.workspace; - - if (con) { - close_container_iterator(con, NULL); - container_for_each_child(con, close_container_iterator, NULL); - } else { - workspace_for_each_container(ws, close_container_iterator, NULL); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/layer_effects.c b/sway/commands/layer_effects.c deleted file mode 100644 index 3d5cc8c0b..000000000 --- a/sway/commands/layer_effects.c +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include "log.h" -#include "stringop.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/layer_criteria.h" -#include "sway/output.h" -#include "util.h" - -struct cmd_results *cmd_layer_effects(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "layer_effects", EXPECTED_AT_LEAST, 2))) { - return error; - } - - struct layer_criteria *criteria = malloc(sizeof(struct layer_criteria)); - criteria->namespace = malloc(strlen(argv[0]) + 1); - strcpy(criteria->namespace, argv[0]); - criteria->cmdlist = join_args(argv + 1, argc - 1); - - // Check if the rule already exists - if (layer_criteria_already_exists(criteria)) { - sway_log(SWAY_DEBUG, "layer_effect already exists: '%s' '%s'", - criteria->namespace, criteria->cmdlist); - layer_criteria_destroy(criteria); - return cmd_results_new(CMD_SUCCESS, NULL); - } - - list_add(config->layer_criteria, criteria); - sway_log(SWAY_DEBUG, "layer_effect: '%s' '%s' added", criteria->namespace, criteria->cmdlist); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/layout.c b/sway/commands/layout.c deleted file mode 100644 index 12ce48398..000000000 --- a/sway/commands/layout.c +++ /dev/null @@ -1,186 +0,0 @@ -#include -#include -#include -#include "sway/commands.h" -#include "sway/output.h" -#include "sway/tree/arrange.h" -#include "sway/tree/container.h" -#include "sway/tree/workspace.h" -#include "log.h" - -static enum sway_container_layout parse_layout_string(char *s) { - if (strcasecmp(s, "splith") == 0) { - return L_HORIZ; - } else if (strcasecmp(s, "splitv") == 0) { - return L_VERT; - } else if (strcasecmp(s, "tabbed") == 0) { - return L_TABBED; - } else if (strcasecmp(s, "stacking") == 0) { - return L_STACKED; - } - return L_NONE; -} - -static const char expected_syntax[] = - "Expected 'layout default|tabbed|stacking|splitv|splith' or " - "'layout toggle [split|all]' or " - "'layout toggle [split|tabbed|stacking|splitv|splith] [split|tabbed|stacking|splitv|splith]...'"; - -static enum sway_container_layout toggle_split_layout( - enum sway_container_layout layout, - enum sway_container_layout prev_split_layout, - struct sway_output *output) { - if (layout == L_HORIZ) { - return L_VERT; - } else if (layout == L_VERT) { - return L_HORIZ; - } else if (prev_split_layout != L_NONE) { - return prev_split_layout; - } else if (config->default_orientation != L_NONE) { - return config->default_orientation; - } else if (output->height > output->width) { - return L_VERT; - } - return L_HORIZ; -} - -static enum sway_container_layout get_layout_toggle(int argc, char **argv, - enum sway_container_layout layout, - enum sway_container_layout prev_split_layout, - struct sway_output *output) { - // "layout toggle" - if (argc == 1) { - return toggle_split_layout(layout, prev_split_layout, output); - } - - if (argc == 2) { - // "layout toggle split" (same as "layout toggle") - if (strcasecmp(argv[1], "split") == 0) { - return toggle_split_layout(layout, prev_split_layout, output); - } - // "layout toggle all" - if (strcasecmp(argv[1], "all") == 0) { - return layout == L_HORIZ ? L_VERT : - layout == L_VERT ? L_STACKED : - layout == L_STACKED ? L_TABBED : L_HORIZ; - } - return L_NONE; - } - - enum sway_container_layout parsed; - int curr = 1; - for (; curr < argc; curr++) { - parsed = parse_layout_string(argv[curr]); - if (parsed == layout || (strcmp(argv[curr], "split") == 0 && - (layout == L_VERT || layout == L_HORIZ))) { - break; - } - } - for (int i = curr + 1; i != curr; ++i) { - // cycle round to find next valid layout - if (i >= argc) { - i = 1; - } - parsed = parse_layout_string(argv[i]); - if (parsed != L_NONE) { - return parsed; - } - if (strcmp(argv[i], "split") == 0) { - return toggle_split_layout(layout, prev_split_layout, output); - } - // invalid layout strings are silently ignored - } - return L_NONE; -} - -static enum sway_container_layout get_layout(int argc, char **argv, - enum sway_container_layout layout, - enum sway_container_layout prev_split_layout, - struct sway_output *output) { - // Check if assigned directly - enum sway_container_layout parsed = parse_layout_string(argv[0]); - if (parsed != L_NONE) { - return parsed; - } - - if (strcasecmp(argv[0], "default") == 0) { - return prev_split_layout; - } - - if (strcasecmp(argv[0], "toggle") == 0) { - return get_layout_toggle(argc, argv, layout, prev_split_layout, output); - } - - return L_NONE; -} - -struct cmd_results *cmd_layout(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "layout", EXPECTED_AT_LEAST, 1))) { - return error; - } - if (!root->outputs->length) { - return cmd_results_new(CMD_INVALID, - "Can't run this command while there's no outputs connected."); - } - struct sway_container *container = config->handler_context.container; - struct sway_workspace *workspace = config->handler_context.workspace; - - if (container && container_is_floating(container)) { - return cmd_results_new(CMD_FAILURE, - "Unable to change layout of floating windows"); - } - - // Operate on parent container, like i3. - if (container) { - container = container->pending.parent; - } - - // We could be working with a container OR a workspace. These are different - // structures, so we set up pointers to they layouts so we can refer them in - // an abstract way. - enum sway_container_layout new_layout = L_NONE; - enum sway_container_layout old_layout = L_NONE; - if (container) { - old_layout = container->pending.layout; - new_layout = get_layout(argc, argv, - container->pending.layout, container->prev_split_layout, - container->pending.workspace->output); - } else { - old_layout = workspace->layout; - new_layout = get_layout(argc, argv, - workspace->layout, workspace->prev_split_layout, - workspace->output); - } - if (new_layout == L_NONE) { - return cmd_results_new(CMD_INVALID, "%s", expected_syntax); - } - if (new_layout != old_layout) { - if (container) { - if (old_layout != L_TABBED && old_layout != L_STACKED) { - container->prev_split_layout = old_layout; - } - container->pending.layout = new_layout; - container_update_representation(container); - } else if (config->handler_context.container) { - // i3 avoids changing workspace layouts with a new container - // https://github.com/i3/i3/blob/3cd1c45eba6de073bc4300eebb4e1cc1a0c4479a/src/con.c#L1817 - container = workspace_wrap_children(workspace); - container->pending.layout = new_layout; - container_update_representation(container); - } else { - if (old_layout != L_TABBED && old_layout != L_STACKED) { - workspace->prev_split_layout = old_layout; - } - workspace->layout = new_layout; - workspace_update_representation(workspace); - } - if (root->fullscreen_global) { - arrange_root(); - } else { - arrange_workspace(workspace); - } - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/mark.c b/sway/commands/mark.c deleted file mode 100644 index aa5f185c8..000000000 --- a/sway/commands/mark.c +++ /dev/null @@ -1,68 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/tree/view.h" -#include "list.h" -#include "log.h" -#include "stringop.h" - -// mark foo Same as mark --replace foo -// mark --add foo Add this mark to view's list -// mark --replace foo Replace view's marks with this single one -// mark --add --toggle foo Toggle current mark and persist other marks -// mark --replace --toggle foo Toggle current mark and remove other marks - -struct cmd_results *cmd_mark(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "mark", EXPECTED_AT_LEAST, 1))) { - return error; - } - struct sway_container *container = config->handler_context.container; - if (!container) { - return cmd_results_new(CMD_INVALID, "Only containers can have marks"); - } - - bool add = false, toggle = false; - while (argc > 0 && strncmp(*argv, "--", 2) == 0) { - if (strcmp(*argv, "--add") == 0) { - add = true; - } else if (strcmp(*argv, "--replace") == 0) { - add = false; - } else if (strcmp(*argv, "--toggle") == 0) { - toggle = true; - } else { - return cmd_results_new(CMD_INVALID, - "Unrecognized argument '%s'", *argv); - } - ++argv; - --argc; - } - - if (!argc) { - return cmd_results_new(CMD_INVALID, - "Expected '[--add|--replace] [--toggle] '"); - } - - char *mark = join_args(argv, argc); - bool had_mark = container_has_mark(container, mark); - - if (!add) { - // Replacing - container_clear_marks(container); - } - - container_find_and_unmark(mark); - - if (!toggle || !had_mark) { - container_add_mark(container, mark); - } - - free(mark); - container_update_marks_textures(container); - if (container->view) { - view_execute_criteria(container->view); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/max_render_time.c b/sway/commands/max_render_time.c deleted file mode 100644 index ec3282f18..000000000 --- a/sway/commands/max_render_time.c +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/tree/view.h" - -struct cmd_results *cmd_max_render_time(int argc, char **argv) { - if (!argc) { - return cmd_results_new(CMD_INVALID, "Missing max render time argument."); - } - - int max_render_time; - if (!strcmp(*argv, "off")) { - max_render_time = 0; - } else { - char *end; - max_render_time = strtol(*argv, &end, 10); - if (*end || max_render_time <= 0) { - return cmd_results_new(CMD_INVALID, "Invalid max render time."); - } - } - - struct sway_container *container = config->handler_context.container; - if (!container || !container->view) { - return cmd_results_new(CMD_INVALID, - "Only views can have a max_render_time"); - } - - struct sway_view *view = container->view; - view->max_render_time = max_render_time; - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/mode.c b/sway/commands/mode.c deleted file mode 100644 index 7263efcba..000000000 --- a/sway/commands/mode.c +++ /dev/null @@ -1,90 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/ipc-server.h" -#include "list.h" -#include "log.h" -#include "stringop.h" - -// Must be in order for the bsearch -static const struct cmd_handler mode_handlers[] = { - { "bindcode", cmd_bindcode }, - { "bindgesture", cmd_bindgesture }, - { "bindswitch", cmd_bindswitch }, - { "bindsym", cmd_bindsym }, - { "set", cmd_set }, - { "unbindcode", cmd_unbindcode }, - { "unbindgesture", cmd_unbindgesture }, - { "unbindswitch", cmd_unbindswitch }, - { "unbindsym", cmd_unbindsym }, -}; - -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; - } - - bool pango = strcmp(*argv, "--pango_markup") == 0; - if (pango) { - argc--; argv++; - if (argc == 0) { - return cmd_results_new(CMD_FAILURE, "Mode name is missing"); - } - } - - if (config->reading && argc == 1) { - return cmd_results_new(CMD_DEFER, NULL); - } - - char *mode_name = *argv; - strip_quotes(mode_name); - struct sway_mode *mode = NULL; - // Find mode - for (int i = 0; i < config->modes->length; ++i) { - struct sway_mode *test = config->modes->items[i]; - if (strcmp(test->name, mode_name) == 0) { - mode = test; - break; - } - } - // Create mode if it doesn't exist - if (!mode && argc > 1) { - mode = calloc(1, sizeof(struct sway_mode)); - if (!mode) { - return cmd_results_new(CMD_FAILURE, "Unable to allocate mode"); - } - mode->name = strdup(mode_name); - mode->keysym_bindings = create_list(); - mode->keycode_bindings = create_list(); - mode->mouse_bindings = create_list(); - mode->switch_bindings = create_list(); - mode->gesture_bindings = create_list(); - mode->pango = pango; - list_add(config->modes, mode); - } - if (!mode) { - error = cmd_results_new(CMD_INVALID, "Unknown mode `%s'", mode_name); - return error; - } - // Set current mode - struct sway_mode *stored_mode = config->current_mode; - config->current_mode = mode; - if (argc == 1) { - // trigger IPC mode event - sway_log(SWAY_DEBUG, "Switching to mode `%s' (pango=%d)", - mode->name, mode->pango); - ipc_event_mode(config->current_mode->name, - config->current_mode->pango); - return cmd_results_new(CMD_SUCCESS, NULL); - } - - // Create binding - struct cmd_results *result = config_subcommand(argv + 1, argc - 1, - mode_handlers, sizeof(mode_handlers)); - config->current_mode = stored_mode; - - return result; -} diff --git a/sway/commands/mouse_warping.c b/sway/commands/mouse_warping.c deleted file mode 100644 index 8b643f625..000000000 --- a/sway/commands/mouse_warping.c +++ /dev/null @@ -1,21 +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], "container") == 0) { - config->mouse_warping = WARP_CONTAINER; - } else if (strcasecmp(argv[0], "output") == 0) { - config->mouse_warping = WARP_OUTPUT; - } else if (strcasecmp(argv[0], "none") == 0) { - config->mouse_warping = WARP_NO; - } else { - return cmd_results_new(CMD_FAILURE, - "Expected 'mouse_warping output|container|none'"); - } - return cmd_results_new(CMD_SUCCESS, NULL); -} - diff --git a/sway/commands/move.c b/sway/commands/move.c deleted file mode 100644 index 69ed06c0b..000000000 --- a/sway/commands/move.c +++ /dev/null @@ -1,1065 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include -#include -#include "sway/commands.h" -#include "sway/input/cursor.h" -#include "sway/input/seat.h" -#include "sway/ipc-server.h" -#include "sway/output.h" -#include "sway/tree/arrange.h" -#include "sway/tree/container.h" -#include "sway/tree/root.h" -#include "sway/tree/workspace.h" -#include "stringop.h" -#include "list.h" -#include "log.h" -#include "util.h" - -static const char expected_syntax[] = - "Expected 'move <[px] px>' or " - "'move [--no-auto-back-and-forth] [to] workspace ' or " - "'move [to] output ' or " - "'move [to] mark '"; - -static struct sway_output *output_in_direction(const char *direction_string, - struct sway_output *reference, int ref_lx, int ref_ly) { - if (strcasecmp(direction_string, "current") == 0) { - struct sway_workspace *active_ws = - seat_get_focused_workspace(config->handler_context.seat); - if (!active_ws) { - return NULL; - } - return active_ws->output; - } - - struct { - char *name; - enum wlr_direction direction; - } names[] = { - { "up", WLR_DIRECTION_UP }, - { "down", WLR_DIRECTION_DOWN }, - { "left", WLR_DIRECTION_LEFT }, - { "right", WLR_DIRECTION_RIGHT }, - }; - - enum wlr_direction direction = 0; - - for (size_t i = 0; i < sizeof(names) / sizeof(names[0]); ++i) { - if (strcasecmp(names[i].name, direction_string) == 0) { - direction = names[i].direction; - break; - } - } - - if (reference && direction) { - struct wlr_output *target = wlr_output_layout_adjacent_output( - root->output_layout, direction, reference->wlr_output, - ref_lx, ref_ly); - - if (!target) { - target = wlr_output_layout_farthest_output( - root->output_layout, opposite_direction(direction), - reference->wlr_output, ref_lx, ref_ly); - } - - if (target) { - return target->data; - } - } - - return output_by_name_or_id(direction_string); -} - -static bool is_parallel(enum sway_container_layout layout, - enum wlr_direction dir) { - switch (layout) { - case L_TABBED: - case L_HORIZ: - return dir == WLR_DIRECTION_LEFT || dir == WLR_DIRECTION_RIGHT; - case L_STACKED: - case L_VERT: - return dir == WLR_DIRECTION_UP || dir == WLR_DIRECTION_DOWN; - default: - return false; - } -} - -/** - * Ensures all seats focus the fullscreen container if needed. - */ -static void workspace_focus_fullscreen(struct sway_workspace *workspace) { - if (!workspace->fullscreen) { - return; - } - struct sway_seat *seat; - struct sway_workspace *focus_ws; - wl_list_for_each(seat, &server.input->seats, link) { - focus_ws = seat_get_focused_workspace(seat); - if (focus_ws == workspace) { - struct sway_node *new_focus = - seat_get_focus_inactive(seat, &workspace->fullscreen->node); - seat_set_raw_focus(seat, new_focus); - } - } -} - -static void container_move_to_container_from_direction( - struct sway_container *container, struct sway_container *destination, - enum wlr_direction move_dir) { - if (destination->view) { - if (destination->pending.parent == container->pending.parent && - destination->pending.workspace == container->pending.workspace) { - sway_log(SWAY_DEBUG, "Swapping siblings"); - list_t *siblings = container_get_siblings(container); - int container_index = list_find(siblings, container); - int destination_index = list_find(siblings, destination); - list_swap(siblings, container_index, destination_index); - container_update_representation(container); - } else { - sway_log(SWAY_DEBUG, "Promoting to sibling of cousin"); - int offset = - move_dir == WLR_DIRECTION_LEFT || move_dir == WLR_DIRECTION_UP; - int index = container_sibling_index(destination) + offset; - if (destination->pending.parent) { - container_insert_child(destination->pending.parent, container, index); - } else { - workspace_insert_tiling(destination->pending.workspace, - container, index); - } - container->pending.width = container->pending.height = 0; - container->width_fraction = container->height_fraction = 0; - workspace_squash(destination->pending.workspace); - } - return; - } - - if (is_parallel(destination->pending.layout, move_dir)) { - sway_log(SWAY_DEBUG, "Reparenting container (parallel)"); - int index = - move_dir == WLR_DIRECTION_RIGHT || move_dir == WLR_DIRECTION_DOWN ? - 0 : destination->pending.children->length; - container_insert_child(destination, container, index); - container->pending.width = container->pending.height = 0; - container->width_fraction = container->height_fraction = 0; - workspace_squash(destination->pending.workspace); - return; - } - - sway_log(SWAY_DEBUG, "Reparenting container (perpendicular)"); - struct sway_node *focus_inactive = seat_get_active_tiling_child( - config->handler_context.seat, &destination->node); - if (!focus_inactive || focus_inactive == &destination->node) { - // The container has no children - container_add_child(destination, container); - return; - } - - // Try again but with the child - container_move_to_container_from_direction(container, - focus_inactive->sway_container, move_dir); -} - -static void container_move_to_workspace_from_direction( - struct sway_container *container, struct sway_workspace *workspace, - enum wlr_direction move_dir) { - container->pending.width = container->pending.height = 0; - container->width_fraction = container->height_fraction = 0; - - if (is_parallel(workspace->layout, move_dir)) { - sway_log(SWAY_DEBUG, "Reparenting container (parallel)"); - int index = - move_dir == WLR_DIRECTION_RIGHT || move_dir == WLR_DIRECTION_DOWN ? - 0 : workspace->tiling->length; - workspace_insert_tiling(workspace, container, index); - return; - } - - sway_log(SWAY_DEBUG, "Reparenting container (perpendicular)"); - struct sway_container *focus_inactive = seat_get_focus_inactive_tiling( - config->handler_context.seat, workspace); - if (!focus_inactive) { - // The workspace has no tiling children - workspace_add_tiling(workspace, container); - return; - } - while (focus_inactive->pending.parent) { - focus_inactive = focus_inactive->pending.parent; - } - container_move_to_container_from_direction(container, focus_inactive, - move_dir); -} - -static void container_move_to_workspace(struct sway_container *container, - struct sway_workspace *workspace) { - if (container->pending.workspace == workspace) { - return; - } - struct sway_workspace *old_workspace = container->pending.workspace; - if (container_is_floating(container)) { - struct sway_output *old_output = container->pending.workspace->output; - container_detach(container); - workspace_add_floating(workspace, container); - container_handle_fullscreen_reparent(container); - // If changing output, adjust the coordinates of the window. - if (old_output != workspace->output && !container->pending.fullscreen_mode) { - struct wlr_box workspace_box, old_workspace_box; - workspace_get_box(workspace, &workspace_box); - workspace_get_box(old_workspace, &old_workspace_box); - floating_fix_coordinates(container, &old_workspace_box, &workspace_box); - if (container->scratchpad && workspace->output) { - struct wlr_box output_box; - output_get_box(workspace->output, &output_box); - container->transform = workspace_box; - } - } - } else { - container_detach(container); - if (workspace_is_empty(workspace) && container->pending.children) { - workspace_unwrap_children(workspace, container); - } else { - container->pending.width = container->pending.height = 0; - container->width_fraction = container->height_fraction = 0; - workspace_add_tiling(workspace, container); - } - container_update_representation(container); - } - if (container->view) { - ipc_event_window(container, "move"); - } - workspace_detect_urgent(old_workspace); - workspace_detect_urgent(workspace); - workspace_focus_fullscreen(workspace); -} - -static void container_move_to_container(struct sway_container *container, - struct sway_container *destination) { - if (container == destination - || container_has_ancestor(container, destination) - || container_has_ancestor(destination, container)) { - return; - } - if (container_is_floating(container)) { - container_move_to_workspace(container, destination->pending.workspace); - return; - } - struct sway_workspace *old_workspace = container->pending.workspace; - - container_detach(container); - container->pending.width = container->pending.height = 0; - container->width_fraction = container->height_fraction = 0; - - if (destination->view) { - container_add_sibling(destination, container, 1); - } else { - container_add_child(destination, container); - } - - if (container->view) { - ipc_event_window(container, "move"); - } - - if (destination->pending.workspace) { - workspace_focus_fullscreen(destination->pending.workspace); - workspace_detect_urgent(destination->pending.workspace); - } - - if (old_workspace && old_workspace != destination->pending.workspace) { - workspace_detect_urgent(old_workspace); - } -} - -static bool container_move_to_next_output(struct sway_container *container, - struct sway_output *output, enum wlr_direction move_dir) { - struct sway_output *next_output = - output_get_in_direction(output, move_dir); - if (next_output) { - struct sway_workspace *ws = output_get_active_workspace(next_output); - if (!sway_assert(ws, "Expected output to have a workspace")) { - return false; - } - switch (container->pending.fullscreen_mode) { - case FULLSCREEN_NONE: - container_move_to_workspace_from_direction(container, ws, move_dir); - return true; - case FULLSCREEN_WORKSPACE: - container_move_to_workspace(container, ws); - return true; - case FULLSCREEN_GLOBAL: - return false; - } - } - return false; -} - -// Returns true if moved -static bool container_move_in_direction(struct sway_container *container, - enum wlr_direction move_dir) { - // If moving a fullscreen view, only consider outputs - switch (container->pending.fullscreen_mode) { - case FULLSCREEN_NONE: - break; - case FULLSCREEN_WORKSPACE: - return container_move_to_next_output(container, - container->pending.workspace->output, move_dir); - case FULLSCREEN_GLOBAL: - return false; - } - - int offs = - move_dir == WLR_DIRECTION_LEFT || move_dir == WLR_DIRECTION_UP ? -1 : 1; - int index = -1; - int desired = -1; - list_t *siblings = NULL; - struct sway_container *target = NULL; - - // Look for a suitable ancestor of the container to move within - struct sway_container *ancestor = NULL; - struct sway_container *current = container; - bool wrapped = false; - while (!ancestor) { - // Don't allow containers to move out of their - // fullscreen or floating parent - if (current->pending.fullscreen_mode || container_is_floating(current)) { - return false; - } - - enum sway_container_layout parent_layout = container_parent_layout(current); - if (!is_parallel(parent_layout, move_dir)) { - if (!current->pending.parent) { - // No parallel parent, so we reorient the workspace - current = workspace_wrap_children(current->pending.workspace); - current->pending.workspace->layout = - move_dir == WLR_DIRECTION_LEFT || - move_dir == WLR_DIRECTION_RIGHT ? - L_HORIZ : L_VERT; - container->pending.height = container->pending.width = 0; - container->height_fraction = container->width_fraction = 0; - workspace_update_representation(current->pending.workspace); - wrapped = true; - } else { - // Keep looking for a parallel parent - current = current->pending.parent; - } - continue; - } - - // Only scratchpad hidden containers don't have siblings - // so siblings != NULL here - siblings = container_get_siblings(current); - index = list_find(siblings, current); - desired = index + offs; - target = desired == -1 || desired == siblings->length ? - NULL : siblings->items[desired]; - - // If the move is simple we can complete it here early - if (current == container) { - if (target) { - // Container will swap with or descend into its neighbor - container_move_to_container_from_direction(container, - target, move_dir); - return true; - } else if (!container->pending.parent) { - // Container is at workspace level so we move it to the - // next workspace if possible - return container_move_to_next_output(container, - current->pending.workspace->output, move_dir); - } else { - // Container has escaped its immediate parallel parent - current = current->pending.parent; - continue; - } - } - - // We found a suitable ancestor, the loop will end - ancestor = current; - } - - if (target) { - // Container will move in with its cousin - container_move_to_container_from_direction(container, - target, move_dir); - return true; - } else if (!wrapped && !container->pending.parent->pending.parent && - container->pending.parent->pending.children->length == 1) { - // Treat singleton children as if they are at workspace level like i3 - // https://github.com/i3/i3/blob/1d9160f2d247dbaa83fb62f02fd7041dec767fc2/src/move.c#L367 - return container_move_to_next_output(container, - ancestor->pending.workspace->output, move_dir); - } else { - // Container will be promoted - struct sway_container *old_parent = container->pending.parent; - if (ancestor->pending.parent) { - // Container will move in with its parent - container_insert_child(ancestor->pending.parent, container, - index + (offs < 0 ? 0 : 1)); - } else { - // Container will move to workspace level, - // may be re-split by workspace_layout - workspace_insert_tiling(ancestor->pending.workspace, container, - index + (offs < 0 ? 0 : 1)); - } - ancestor->pending.height = ancestor->pending.width = 0; - ancestor->height_fraction = ancestor->width_fraction = 0; - if (old_parent) { - container_reap_empty(old_parent); - } - workspace_squash(container->pending.workspace); - return true; - } -} - -static struct cmd_results *cmd_move_to_scratchpad(void); - -static struct cmd_results *cmd_move_container(bool no_auto_back_and_forth, - int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "move container/window", - EXPECTED_AT_LEAST, 2))) { - return error; - } - - struct sway_node *node = config->handler_context.node; - struct sway_workspace *workspace = config->handler_context.workspace; - struct sway_container *container = config->handler_context.container; - if (node->type == N_WORKSPACE) { - if (workspace->tiling->length == 0) { - return cmd_results_new(CMD_FAILURE, - "Can't move an empty workspace"); - } - container = workspace_wrap_children(workspace); - } - - if (container->pending.fullscreen_mode == FULLSCREEN_GLOBAL) { - return cmd_results_new(CMD_FAILURE, - "Can't move fullscreen global container"); - } - - struct sway_seat *seat = config->handler_context.seat; - struct sway_container *old_parent = container->pending.parent; - struct sway_workspace *old_ws = container->pending.workspace; - struct sway_output *old_output = old_ws ? old_ws->output : NULL; - struct sway_node *destination = NULL; - - // determine destination - if (strcasecmp(argv[0], "workspace") == 0) { - // move container to workspace x - struct sway_workspace *ws = NULL; - char *ws_name = NULL; - if (strcasecmp(argv[1], "next") == 0 || - strcasecmp(argv[1], "prev") == 0 || - strcasecmp(argv[1], "next_on_output") == 0 || - strcasecmp(argv[1], "prev_on_output") == 0 || - strcasecmp(argv[1], "current") == 0) { - ws = workspace_by_name(argv[1]); - } else if (strcasecmp(argv[1], "back_and_forth") == 0) { - if (!(ws = workspace_by_name(argv[1]))) { - if (seat->prev_workspace_name) { - ws_name = strdup(seat->prev_workspace_name); - } else { - return cmd_results_new(CMD_FAILURE, - "No workspace was previously active."); - } - } - } else { - if (strcasecmp(argv[1], "number") == 0) { - // move [window|container] [to] "workspace number x" - if (argc < 3) { - return cmd_results_new(CMD_INVALID, "%s", expected_syntax); - } - if (!isdigit(argv[2][0])) { - return cmd_results_new(CMD_INVALID, - "Invalid workspace number '%s'", argv[2]); - } - ws_name = join_args(argv + 2, argc - 2); - ws = workspace_by_number(ws_name); - } else { - ws_name = join_args(argv + 1, argc - 1); - ws = workspace_by_name(ws_name); - } - - if (!no_auto_back_and_forth && config->auto_back_and_forth && - seat->prev_workspace_name) { - // auto back and forth move - if (old_ws && old_ws->name && - strcmp(old_ws->name, ws_name) == 0) { - // if target workspace is the current one - free(ws_name); - ws_name = strdup(seat->prev_workspace_name); - ws = workspace_by_name(ws_name); - } - } - } - if (!ws) { - // We have to create the workspace, but if the container is - // sticky and the workspace is going to be created on the same - // output, we'll bail out first. - if (container_is_sticky_or_child(container)) { - struct sway_output *new_output = - workspace_get_initial_output(ws_name); - if (old_output == new_output) { - free(ws_name); - return cmd_results_new(CMD_FAILURE, - "Can't move sticky container to another workspace " - "on the same output"); - } - } - ws = workspace_create(NULL, ws_name); - } - free(ws_name); - struct sway_container *dst = seat_get_focus_inactive_tiling(seat, ws); - destination = dst ? &dst->node : &ws->node; - } else if (strcasecmp(argv[0], "output") == 0) { - struct sway_output *new_output = output_in_direction(argv[1], - old_output, container->pending.x, container->pending.y); - if (!new_output) { - return cmd_results_new(CMD_FAILURE, - "Can't find output with name/direction '%s'", argv[1]); - } - destination = seat_get_focus_inactive(seat, &new_output->node); - } else if (strcasecmp(argv[0], "mark") == 0) { - struct sway_container *dest_con = container_find_mark(argv[1]); - if (dest_con == NULL) { - return cmd_results_new(CMD_FAILURE, - "Mark '%s' not found", argv[1]); - } - destination = &dest_con->node; - } else { - return cmd_results_new(CMD_INVALID, "%s", expected_syntax); - } - - if (destination->type == N_CONTAINER && - container_is_scratchpad_hidden(destination->sway_container)) { - return cmd_move_to_scratchpad(); - } - - if (container_is_sticky_or_child(container) && old_output && - node_has_ancestor(destination, &old_output->node)) { - return cmd_results_new(CMD_FAILURE, "Can't move sticky " - "container to another workspace on the same output"); - } - - struct sway_output *new_output = node_get_output(destination); - struct sway_workspace *new_output_last_ws = NULL; - if (new_output && old_output != new_output) { - new_output_last_ws = output_get_active_workspace(new_output); - } - - // save focus, in case it needs to be restored - struct sway_node *focus = seat_get_focus(seat); - - // move container - if (container_is_scratchpad_hidden_or_child(container)) { - container_detach(container); - root_scratchpad_show(container); - } - switch (destination->type) { - case N_WORKSPACE: - container_move_to_workspace(container, destination->sway_workspace); - break; - case N_OUTPUT: { - struct sway_output *output = destination->sway_output; - struct sway_workspace *ws = output_get_active_workspace(output); - if (!sway_assert(ws, "Expected output to have a workspace")) { - return cmd_results_new(CMD_FAILURE, - "Expected output to have a workspace"); - } - container_move_to_workspace(container, ws); - } - break; - case N_CONTAINER: - container_move_to_container(container, destination->sway_container); - break; - case N_ROOT: - break; - } - - // restore focus on destination output back to its last active workspace - struct sway_workspace *new_workspace = new_output ? - output_get_active_workspace(new_output) : NULL; - if (new_output && - !sway_assert(new_workspace, "Expected output to have a workspace")) { - return cmd_results_new(CMD_FAILURE, - "Expected output to have a workspace"); - } - - if (new_output_last_ws && new_output_last_ws != new_workspace) { - struct sway_node *new_output_last_focus = - seat_get_focus_inactive(seat, &new_output_last_ws->node); - seat_set_raw_focus(seat, new_output_last_focus); - } - - // restore focus - if (focus == &container->node) { - focus = NULL; - if (old_parent) { - focus = seat_get_focus_inactive(seat, &old_parent->node); - } - if (!focus && old_ws) { - focus = seat_get_focus_inactive(seat, &old_ws->node); - } - } - seat_set_focus(seat, focus); - - // clean-up, destroying parents if the container was the last child - if (old_parent) { - container_reap_empty(old_parent); - } else if (old_ws) { - workspace_consider_destroy(old_ws); - } - - // arrange windows - if (root->fullscreen_global) { - arrange_root(); - } else { - if (old_ws && !old_ws->node.destroying) { - arrange_workspace(old_ws); - } - arrange_node(node_get_parent(destination)); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} - -static void workspace_move_to_output(struct sway_workspace *workspace, - struct sway_output *output) { - if (workspace->output == output) { - return; - } - struct sway_output *old_output = workspace->output; - workspace_detach(workspace); - struct sway_workspace *new_output_old_ws = - output_get_active_workspace(output); - if (!sway_assert(new_output_old_ws, "Expected output to have a workspace")) { - return; - } - - output_add_workspace(output, workspace); - - // If moving the last workspace from the old output, create a new workspace - // on the old output - struct sway_seat *seat = config->handler_context.seat; - if (old_output->workspaces->length == 0) { - char *ws_name = workspace_next_name(old_output->wlr_output->name); - struct sway_workspace *ws = workspace_create(old_output, ws_name); - free(ws_name); - seat_set_raw_focus(seat, &ws->node); - } - - workspace_consider_destroy(new_output_old_ws); - - output_sort_workspaces(output); - struct sway_node *focus = seat_get_focus_inactive(seat, &workspace->node); - seat_set_focus(seat, focus); - workspace_output_raise_priority(workspace, old_output, output); - ipc_event_workspace(NULL, workspace, "move"); -} - -static struct cmd_results *cmd_move_workspace(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "move workspace", EXPECTED_AT_LEAST, 1))) { - return error; - } - - if (strcasecmp(argv[0], "output") == 0) { - --argc; ++argv; - } - - if (!argc) { - return cmd_results_new(CMD_INVALID, - "Expected 'move workspace to [output] '"); - } - - struct sway_workspace *workspace = config->handler_context.workspace; - if (!workspace) { - return cmd_results_new(CMD_FAILURE, "No workspace to move"); - } - - struct sway_output *old_output = workspace->output; - int center_x = workspace->width / 2 + workspace->x, - center_y = workspace->height / 2 + workspace->y; - struct sway_output *new_output = output_in_direction(argv[0], - old_output, center_x, center_y); - if (!new_output) { - return cmd_results_new(CMD_FAILURE, - "Can't find output with name/direction '%s'", argv[0]); - } - workspace_move_to_output(workspace, new_output); - - arrange_output(old_output); - arrange_output(new_output); - - struct sway_seat *seat = config->handler_context.seat; - seat_consider_warp_to_focus(seat); - - return cmd_results_new(CMD_SUCCESS, NULL); -} - -static struct cmd_results *cmd_move_in_direction( - enum wlr_direction direction, int argc, char **argv) { - int move_amt = 10; - if (argc) { - char *inv; - move_amt = (int)strtol(argv[0], &inv, 10); - if (*inv != '\0' && strcasecmp(inv, "px") != 0) { - return cmd_results_new(CMD_FAILURE, "Invalid distance specified"); - } - } - - struct sway_container *container = config->handler_context.container; - if (!container) { - return cmd_results_new(CMD_FAILURE, - "Cannot move workspaces in a direction"); - } - if (container_is_floating(container)) { - if (container->pending.fullscreen_mode) { - return cmd_results_new(CMD_FAILURE, - "Cannot move fullscreen floating container"); - } - double lx = container->pending.x; - double ly = container->pending.y; - switch (direction) { - case WLR_DIRECTION_LEFT: - lx -= move_amt; - break; - case WLR_DIRECTION_RIGHT: - lx += move_amt; - break; - case WLR_DIRECTION_UP: - ly -= move_amt; - break; - case WLR_DIRECTION_DOWN: - ly += move_amt; - break; - } - container_floating_move_to(container, lx, ly); - return cmd_results_new(CMD_SUCCESS, NULL); - } - struct sway_workspace *old_ws = container->pending.workspace; - struct sway_container *old_parent = container->pending.parent; - - if (!container_move_in_direction(container, direction)) { - // Container didn't move - return cmd_results_new(CMD_SUCCESS, NULL); - } - - // clean-up, destroying parents if the container was the last child - if (old_parent) { - container_reap_empty(old_parent); - } else if (old_ws) { - workspace_consider_destroy(old_ws); - } - - struct sway_workspace *new_ws = container->pending.workspace; - - if (root->fullscreen_global) { - arrange_root(); - } else { - arrange_workspace(old_ws); - if (new_ws != old_ws) { - arrange_workspace(new_ws); - } - } - - if (container->view) { - ipc_event_window(container, "move"); - } - - // Hack to re-focus container - seat_set_raw_focus(config->handler_context.seat, &new_ws->node); - seat_set_focus_container(config->handler_context.seat, container); - - if (old_ws != new_ws) { - ipc_event_workspace(old_ws, new_ws, "focus"); - workspace_detect_urgent(old_ws); - workspace_detect_urgent(new_ws); - } - container_end_mouse_operation(container); - - return cmd_results_new(CMD_SUCCESS, NULL); -} - -static struct cmd_results *cmd_move_to_position_pointer( - struct sway_container *container) { - struct sway_seat *seat = config->handler_context.seat; - if (!seat->cursor) { - return cmd_results_new(CMD_FAILURE, "No cursor device"); - } - struct wlr_cursor *cursor = seat->cursor->cursor; - /* Determine where to put the window. */ - double lx = cursor->x - container->pending.width / 2; - double ly = cursor->y - container->pending.height / 2; - - /* Correct target coordinates to be in bounds (on screen). */ - struct wlr_output *output = wlr_output_layout_output_at( - root->output_layout, cursor->x, cursor->y); - if (output) { - struct wlr_box box; - wlr_output_layout_get_box(root->output_layout, output, &box); - lx = fmax(lx, box.x); - ly = fmax(ly, box.y); - if (lx + container->pending.width > box.x + box.width) { - lx = box.x + box.width - container->pending.width; - } - if (ly + container->pending.height > box.y + box.height) { - ly = box.y + box.height - container->pending.height; - } - } - - /* Actually move the container. */ - container_floating_move_to(container, lx, ly); - return cmd_results_new(CMD_SUCCESS, NULL); -} - -static const char expected_position_syntax[] = - "Expected 'move [absolute] position [px] [px]' or " - "'move [absolute] position center' or " - "'move position cursor|mouse|pointer'"; - -static struct cmd_results *cmd_move_to_position(int argc, char **argv) { - struct sway_container *container = config->handler_context.container; - if (!container || !container_is_floating(container)) { - return cmd_results_new(CMD_FAILURE, "Only floating containers " - "can be moved to an absolute position"); - } - - if (!argc) { - return cmd_results_new(CMD_INVALID, "%s", expected_position_syntax); - } - - bool absolute = false; - if (strcmp(argv[0], "absolute") == 0) { - absolute = true; - --argc; - ++argv; - } - if (!argc) { - return cmd_results_new(CMD_INVALID, "%s", expected_position_syntax); - } - if (strcmp(argv[0], "position") == 0) { - --argc; - ++argv; - } - if (!argc) { - return cmd_results_new(CMD_INVALID, "%s", expected_position_syntax); - } - if (strcmp(argv[0], "cursor") == 0 || strcmp(argv[0], "mouse") == 0 || - strcmp(argv[0], "pointer") == 0) { - if (absolute) { - return cmd_results_new(CMD_INVALID, "%s", expected_position_syntax); - } - return cmd_move_to_position_pointer(container); - } else if (strcmp(argv[0], "center") == 0) { - double lx, ly; - if (absolute) { - lx = root->x + (root->width - container->pending.width) / 2; - ly = root->y + (root->height - container->pending.height) / 2; - } else { - struct sway_workspace *ws = container->pending.workspace; - if (!ws) { - struct sway_seat *seat = config->handler_context.seat; - ws = seat_get_focused_workspace(seat); - } - lx = ws->x + (ws->width - container->pending.width) / 2; - ly = ws->y + (ws->height - container->pending.height) / 2; - } - container_floating_move_to(container, lx, ly); - return cmd_results_new(CMD_SUCCESS, NULL); - } - - if (argc < 2) { - return cmd_results_new(CMD_FAILURE, "%s", expected_position_syntax); - } - - struct movement_amount lx = { .amount = 0, .unit = MOVEMENT_UNIT_INVALID }; - // X direction - int num_consumed_args = parse_movement_amount(argc, argv, &lx); - argc -= num_consumed_args; - argv += num_consumed_args; - if (lx.unit == MOVEMENT_UNIT_INVALID) { - return cmd_results_new(CMD_INVALID, "Invalid x position specified"); - } - - if (argc < 1) { - return cmd_results_new(CMD_FAILURE, "%s", expected_position_syntax); - } - - struct movement_amount ly = { .amount = 0, .unit = MOVEMENT_UNIT_INVALID }; - // Y direction - num_consumed_args = parse_movement_amount(argc, argv, &ly); - argc -= num_consumed_args; - argv += num_consumed_args; - if (argc > 0) { - return cmd_results_new(CMD_INVALID, "%s", expected_position_syntax); - } - if (ly.unit == MOVEMENT_UNIT_INVALID) { - return cmd_results_new(CMD_INVALID, "Invalid y position specified"); - } - - struct sway_workspace *ws = container->pending.workspace; - if (!ws) { - struct sway_seat *seat = config->handler_context.seat; - ws = seat_get_focused_workspace(seat); - } - - switch (lx.unit) { - case MOVEMENT_UNIT_PPT: - if (container_is_scratchpad_hidden(container)) { - return cmd_results_new(CMD_FAILURE, - "Cannot move a hidden scratchpad container by ppt"); - } - if (absolute) { - return cmd_results_new(CMD_FAILURE, - "Cannot move to absolute positions by ppt"); - } - // Convert to px - lx.amount = ws->width * lx.amount / 100; - lx.unit = MOVEMENT_UNIT_PX; - // Falls through - case MOVEMENT_UNIT_PX: - case MOVEMENT_UNIT_DEFAULT: - break; - case MOVEMENT_UNIT_INVALID: - sway_assert(false, "invalid x unit"); - break; - } - - switch (ly.unit) { - case MOVEMENT_UNIT_PPT: - if (container_is_scratchpad_hidden(container)) { - return cmd_results_new(CMD_FAILURE, - "Cannot move a hidden scratchpad container by ppt"); - } - if (absolute) { - return cmd_results_new(CMD_FAILURE, - "Cannot move to absolute positions by ppt"); - } - // Convert to px - ly.amount = ws->height * ly.amount / 100; - ly.unit = MOVEMENT_UNIT_PX; - // Falls through - case MOVEMENT_UNIT_PX: - case MOVEMENT_UNIT_DEFAULT: - break; - case MOVEMENT_UNIT_INVALID: - sway_assert(false, "invalid y unit"); - break; - } - if (!absolute) { - lx.amount += ws->x; - ly.amount += ws->y; - } - container_floating_move_to(container, lx.amount, ly.amount); - return cmd_results_new(CMD_SUCCESS, NULL); -} - -static struct cmd_results *cmd_move_to_scratchpad(void) { - struct sway_node *node = config->handler_context.node; - struct sway_container *con = config->handler_context.container; - struct sway_workspace *ws = config->handler_context.workspace; - if (node->type == N_WORKSPACE && ws->tiling->length == 0) { - return cmd_results_new(CMD_INVALID, - "Can't move an empty workspace to the scratchpad"); - } - if (node->type == N_WORKSPACE) { - // Wrap the workspace's children in a container - con = workspace_wrap_children(ws); - ws->layout = L_HORIZ; - } - - // If the container is in a floating split container, - // operate on the split container instead of the child. - if (container_is_floating_or_child(con)) { - while (con->pending.parent) { - con = con->pending.parent; - } - } - - if (!con->scratchpad) { - root_scratchpad_add_container(con, NULL); - } else if (con->pending.workspace) { - root_scratchpad_hide(con); - } - return cmd_results_new(CMD_SUCCESS, NULL); -} - -static const char expected_full_syntax[] = "Expected " - "'move left|right|up|down [ [px]]'" - " or 'move [--no-auto-back-and-forth] [window|container] [to] workspace" - " |next|prev|next_on_output|prev_on_output|current|(number )'" - " or 'move [window|container] [to] output |left|right|up|down'" - " or 'move [window|container] [to] mark '" - " or 'move [window|container] [to] scratchpad'" - " or 'move workspace to [output] |left|right|up|down'" - " or 'move [window|container] [to] [absolute] position [px] [px]'" - " or 'move [window|container] [to] [absolute] position center'" - " or 'move [window|container] [to] position mouse|cursor|pointer'"; - -struct cmd_results *cmd_move(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) { - return error; - } - if (!root->outputs->length) { - return cmd_results_new(CMD_INVALID, - "Can't run this command while there's no outputs connected."); - } - - if (strcasecmp(argv[0], "left") == 0) { - return cmd_move_in_direction(WLR_DIRECTION_LEFT, --argc, ++argv); - } else if (strcasecmp(argv[0], "right") == 0) { - return cmd_move_in_direction(WLR_DIRECTION_RIGHT, --argc, ++argv); - } else if (strcasecmp(argv[0], "up") == 0) { - return cmd_move_in_direction(WLR_DIRECTION_UP, --argc, ++argv); - } else if (strcasecmp(argv[0], "down") == 0) { - return cmd_move_in_direction(WLR_DIRECTION_DOWN, --argc, ++argv); - } else if (strcasecmp(argv[0], "workspace") == 0 && argc >= 2 - && (strcasecmp(argv[1], "to") == 0 || - strcasecmp(argv[1], "output") == 0)) { - argc -= 2; argv += 2; - return cmd_move_workspace(argc, argv); - } - - bool no_auto_back_and_forth = false; - if (strcasecmp(argv[0], "--no-auto-back-and-forth") == 0) { - no_auto_back_and_forth = true; - --argc; ++argv; - } - - if (argc > 0 && (strcasecmp(argv[0], "window") == 0 || - strcasecmp(argv[0], "container") == 0)) { - --argc; ++argv; - } - - if (argc > 0 && strcasecmp(argv[0], "to") == 0) { - --argc; ++argv; - } - - if (!argc) { - return cmd_results_new(CMD_INVALID, "%s", expected_full_syntax); - } - - // Only `move [window|container] [to] workspace` supports - // `--no-auto-back-and-forth` so treat others as invalid syntax - if (no_auto_back_and_forth && strcasecmp(argv[0], "workspace") != 0) { - return cmd_results_new(CMD_INVALID, "%s", expected_full_syntax); - } - - if (strcasecmp(argv[0], "workspace") == 0 || - strcasecmp(argv[0], "output") == 0 || - strcasecmp(argv[0], "mark") == 0) { - return cmd_move_container(no_auto_back_and_forth, argc, argv); - } else if (strcasecmp(argv[0], "scratchpad") == 0) { - return cmd_move_to_scratchpad(); - } else if (strcasecmp(argv[0], "position") == 0 || - (argc > 1 && strcasecmp(argv[0], "absolute") == 0 && - strcasecmp(argv[1], "position") == 0)) { - return cmd_move_to_position(argc, argv); - } - return cmd_results_new(CMD_INVALID, "%s", expected_full_syntax); -} diff --git a/sway/commands/new_float.c b/sway/commands/new_float.c deleted file mode 100644 index 4fedb4cb8..000000000 --- a/sway/commands/new_float.c +++ /dev/null @@ -1,13 +0,0 @@ -#include "log.h" -#include "sway/commands.h" -#include "sway/config.h" - -struct cmd_results *cmd_new_float(int argc, char **argv) { - sway_log(SWAY_INFO, "Warning: new_float is deprecated. " - "Use default_floating_border instead."); - if (config->reading) { - config_add_swaynag_warning("new_float is deprecated. " - "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 e8caa4873..000000000 --- a/sway/commands/new_window.c +++ /dev/null @@ -1,13 +0,0 @@ -#include "log.h" -#include "sway/commands.h" -#include "sway/config.h" - -struct cmd_results *cmd_new_window(int argc, char **argv) { - sway_log(SWAY_INFO, "Warning: new_window is deprecated. " - "Use default_border instead."); - if (config->reading) { - config_add_swaynag_warning("new_window is deprecated. " - "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 ccfdec824..000000000 --- a/sway/commands/no_focus.c +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/criteria.h" -#include "list.h" -#include "log.h" - -struct cmd_results *cmd_no_focus(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "no_focus", EXPECTED_AT_LEAST, 1))) { - return error; - } - - char *err_str = NULL; - struct criteria *criteria = criteria_parse(argv[0], &err_str); - if (!criteria) { - error = cmd_results_new(CMD_INVALID, "%s", err_str); - free(err_str); - return error; - } - - - criteria->type = CT_NO_FOCUS; - - // Check if it already exists - if (criteria_already_exists(criteria)) { - sway_log(SWAY_DEBUG, "no_focus already exists: '%s'", criteria->raw); - criteria_destroy(criteria); - return cmd_results_new(CMD_SUCCESS, NULL); - } - - list_add(config->criteria, criteria); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/nop.c b/sway/commands/nop.c deleted file mode 100644 index 973ade0e0..000000000 --- a/sway/commands/nop.c +++ /dev/null @@ -1,5 +0,0 @@ -#include "sway/commands.h" - -struct cmd_results *cmd_nop(int argc, char **argv) { - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/opacity.c b/sway/commands/opacity.c deleted file mode 100644 index 96e6228ed..000000000 --- a/sway/commands/opacity.c +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include -#include -#include "sway/commands.h" -#include "sway/tree/view.h" -#include "log.h" - -struct cmd_results *cmd_opacity(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "opacity", EXPECTED_AT_LEAST, 1))) { - return error; - } - - struct sway_container *con = config->handler_context.container; - - if (con == NULL) { - return cmd_results_new(CMD_FAILURE, "No current container"); - } - - char *err; - float val = strtof(argc == 1 ? argv[0] : argv[1], &err); - if (*err) { - return cmd_results_new(CMD_INVALID, "opacity float invalid"); - } - - if (!strcasecmp(argv[0], "plus")) { - val = con->alpha + val; - } else if (!strcasecmp(argv[0], "minus")) { - val = con->alpha - val; - } else if (argc > 1 && strcasecmp(argv[0], "set")) { - return cmd_results_new(CMD_INVALID, - "Expected: set|plus|minus <0..1>: %s", argv[0]); - } - - if (val < 0 || val > 1) { - return cmd_results_new(CMD_FAILURE, "opacity value out of bounds"); - } - - con->alpha = val; - container_damage_whole(con); - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/output.c b/sway/commands/output.c deleted file mode 100644 index 462dffd23..000000000 --- a/sway/commands/output.c +++ /dev/null @@ -1,127 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/output.h" -#include "list.h" -#include "log.h" - -// must be in order for the bsearch -static const struct cmd_handler output_handlers[] = { - { "adaptive_sync", output_cmd_adaptive_sync }, - { "background", output_cmd_background }, - { "bg", output_cmd_background }, - { "disable", output_cmd_disable }, - { "dpms", output_cmd_dpms }, - { "enable", output_cmd_enable }, - { "max_render_time", output_cmd_max_render_time }, - { "mode", output_cmd_mode }, - { "modeline", output_cmd_modeline }, - { "pos", output_cmd_position }, - { "position", output_cmd_position }, - { "power", output_cmd_power }, - { "render_bit_depth", output_cmd_render_bit_depth }, - { "res", output_cmd_mode }, - { "resolution", output_cmd_mode }, - { "scale", output_cmd_scale }, - { "scale_filter", output_cmd_scale_filter }, - { "subpixel", output_cmd_subpixel }, - { "toggle", output_cmd_toggle }, - { "transform", output_cmd_transform }, - { "unplug", output_cmd_unplug }, -}; - -struct cmd_results *cmd_output(int argc, char **argv) { - struct cmd_results *error = checkarg(argc, "output", EXPECTED_AT_LEAST, 1); - if (error != NULL) { - return error; - } - - // The HEADLESS-1 output is a dummy output used when there's no outputs - // connected. It should never be configured. - if (strcasecmp(argv[0], root->fallback_output->wlr_output->name) == 0) { - return cmd_results_new(CMD_FAILURE, - "Refusing to configure the no op output"); - } - - struct output_config *output = NULL; - if (strcmp(argv[0], "-") == 0 || strcmp(argv[0], "--") == 0) { - if (config->reading) { - return cmd_results_new(CMD_FAILURE, - "Current output alias (%s) cannot be used in the config", - argv[0]); - } - struct sway_output *sway_output = config->handler_context.node ? - node_get_output(config->handler_context.node) : NULL; - if (!sway_output) { - return cmd_results_new(CMD_FAILURE, "Unknown output"); - } - if (sway_output == root->fallback_output) { - return cmd_results_new(CMD_FAILURE, - "Refusing to configure the no op output"); - } - if (strcmp(argv[0], "-") == 0) { - output = new_output_config(sway_output->wlr_output->name); - } else { - char identifier[128]; - output_get_identifier(identifier, 128, sway_output); - output = new_output_config(identifier); - } - } else { - output = new_output_config(argv[0]); - } - if (!output) { - sway_log(SWAY_ERROR, "Failed to allocate output config"); - return NULL; - } - argc--; argv++; - - config->handler_context.output_config = output; - - while (argc > 0) { - config->handler_context.leftovers.argc = 0; - config->handler_context.leftovers.argv = NULL; - - if (find_handler(*argv, output_handlers, sizeof(output_handlers))) { - error = config_subcommand(argv, argc, output_handlers, - sizeof(output_handlers)); - } else { - error = cmd_results_new(CMD_INVALID, - "Invalid output subcommand: %s.", *argv); - } - - if (error != NULL) { - goto fail; - } - - argc = config->handler_context.leftovers.argc; - argv = config->handler_context.leftovers.argv; - } - - config->handler_context.output_config = NULL; - config->handler_context.leftovers.argc = 0; - config->handler_context.leftovers.argv = NULL; - - bool background = output->background; - - output = store_output_config(output); - - // If reloading, the output configs will be applied after reading the - // entire config and before the deferred commands so that an auto generated - // workspace name is not given to re-enabled outputs. - if (!config->reloading && !config->validating) { - apply_output_config_to_outputs(output); - if (background) { - if (!spawn_swaybg()) { - return cmd_results_new(CMD_FAILURE, - "Failed to apply background configuration"); - } - } - } - - return cmd_results_new(CMD_SUCCESS, NULL); - -fail: - config->handler_context.output_config = NULL; - free_output_config(output); - return error; -} diff --git a/sway/commands/output/adaptive_sync.c b/sway/commands/output/adaptive_sync.c deleted file mode 100644 index 7382e2ee3..000000000 --- a/sway/commands/output/adaptive_sync.c +++ /dev/null @@ -1,22 +0,0 @@ -#include "sway/commands.h" -#include "sway/config.h" -#include "util.h" - -struct cmd_results *output_cmd_adaptive_sync(int argc, char **argv) { - if (!config->handler_context.output_config) { - return cmd_results_new(CMD_FAILURE, "Missing output config"); - } - if (argc == 0) { - return cmd_results_new(CMD_INVALID, "Missing adaptive_sync argument"); - } - - if (parse_boolean(argv[0], true)) { - config->handler_context.output_config->adaptive_sync = 1; - } else { - config->handler_context.output_config->adaptive_sync = 0; - } - - config->handler_context.leftovers.argc = argc - 1; - config->handler_context.leftovers.argv = argv + 1; - return NULL; -} diff --git a/sway/commands/output/background.c b/sway/commands/output/background.c deleted file mode 100644 index d691295f4..000000000 --- a/sway/commands/output/background.c +++ /dev/null @@ -1,157 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/swaynag.h" -#include "log.h" -#include "stringop.h" - -static const char *bg_options[] = { - "stretch", - "center", - "fill", - "fit", - "tile", -}; - -static bool validate_color(const char *color) { - if (strlen(color) != 7 || color[0] != '#') { - return false; - } - - char *ptr = NULL; - strtol(&color[1], &ptr, 16); - return *ptr == '\0'; -} - -struct cmd_results *output_cmd_background(int argc, char **argv) { - if (!config->handler_context.output_config) { - return cmd_results_new(CMD_FAILURE, "Missing output config"); - } - if (!argc) { - return cmd_results_new(CMD_INVALID, - "Missing background file or color specification."); - } - if (argc < 2) { - return cmd_results_new(CMD_INVALID, - "Missing background scaling mode or `solid_color`."); - } - - struct output_config *output = config->handler_context.output_config; - - if (strcasecmp(argv[1], "solid_color") == 0) { - if (!validate_color(argv[0])) { - return cmd_results_new(CMD_INVALID, - "Colors should be of the form #RRGGBB"); - } - output->background = strdup(argv[0]); - output->background_option = strdup("solid_color"); - output->background_fallback = NULL; - argc -= 2; argv += 2; - } else { - bool valid = false; - char *mode; - size_t j; - for (j = 0; j < (size_t)argc; ++j) { - mode = argv[j]; - size_t n = sizeof(bg_options) / sizeof(char *); - for (size_t k = 0; k < n; ++k) { - if (strcasecmp(mode, bg_options[k]) == 0) { - valid = true; - break; - } - } - if (valid) { - break; - } - } - if (!valid) { - return cmd_results_new(CMD_INVALID, - "Missing background scaling mode."); - } - if (j == 0) { - return cmd_results_new(CMD_INVALID, "Missing background file"); - } - - char *src = join_args(argv, j); - if (!expand_path(&src)) { - struct cmd_results *cmd_res = cmd_results_new(CMD_INVALID, - "Invalid syntax (%s)", src); - free(src); - return cmd_res; - } - if (!src) { - sway_log(SWAY_ERROR, "Failed to allocate expanded path"); - return cmd_results_new(CMD_FAILURE, "Unable to allocate resource"); - } - - if (config->reading && *src != '/') { - // src file is inside configuration dir - - char *conf = strdup(config->current_config_path); - if (!conf) { - sway_log(SWAY_ERROR, "Failed to duplicate string"); - free(src); - return cmd_results_new(CMD_FAILURE, - "Unable to allocate resources"); - } - - char *conf_path = dirname(conf); - char *real_src = malloc(strlen(conf_path) + strlen(src) + 2); - if (!real_src) { - free(src); - free(conf); - sway_log(SWAY_ERROR, "Unable to allocate memory"); - return cmd_results_new(CMD_FAILURE, - "Unable to allocate resources"); - } - - snprintf(real_src, strlen(conf_path) + strlen(src) + 2, "%s/%s", conf_path, src); - free(src); - free(conf); - src = real_src; - } - - bool can_access = access(src, F_OK) != -1; - if (!can_access) { - sway_log_errno(SWAY_ERROR, "Unable to access background file '%s'", - src); - config_add_swaynag_warning("Unable to access background file '%s'", - src); - struct cmd_results *result = cmd_results_new(CMD_FAILURE, - "unable to access background file '%s'", src); - free(src); - return result; - } else { - output->background = src; - output->background_option = strdup(mode); - } - argc -= j + 1; argv += j + 1; - - output->background_fallback = NULL; - if (argc && *argv[0] == '#') { - if (!validate_color(argv[0])) { - return cmd_results_new(CMD_INVALID, - "fallback color should be of the form #RRGGBB"); - } - - output->background_fallback = strdup(argv[0]); - argc--; argv++; - - if (!can_access) { - output->background = output->background_fallback; - output->background_option = strdup("solid_color"); - output->background_fallback = NULL; - } - } - } - - config->handler_context.leftovers.argc = argc; - config->handler_context.leftovers.argv = argv; - return NULL; -} diff --git a/sway/commands/output/disable.c b/sway/commands/output/disable.c deleted file mode 100644 index 624f4056d..000000000 --- a/sway/commands/output/disable.c +++ /dev/null @@ -1,13 +0,0 @@ -#include "sway/commands.h" -#include "sway/config.h" - -struct cmd_results *output_cmd_disable(int argc, char **argv) { - if (!config->handler_context.output_config) { - return cmd_results_new(CMD_FAILURE, "Missing output config"); - } - config->handler_context.output_config->enabled = 0; - - config->handler_context.leftovers.argc = argc; - config->handler_context.leftovers.argv = argv; - return NULL; -} diff --git a/sway/commands/output/dpms.c b/sway/commands/output/dpms.c deleted file mode 100644 index c7adbd585..000000000 --- a/sway/commands/output/dpms.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "log.h" -#include "sway/commands.h" - -struct cmd_results *output_cmd_dpms(int argc, char **argv) { - sway_log(SWAY_INFO, "The \"output dpms\" command is deprecated, " - "use \"output power\" instead"); - return output_cmd_power(argc, argv); -} diff --git a/sway/commands/output/enable.c b/sway/commands/output/enable.c deleted file mode 100644 index bae3961f8..000000000 --- a/sway/commands/output/enable.c +++ /dev/null @@ -1,15 +0,0 @@ -#include "sway/commands.h" -#include "sway/config.h" - -struct cmd_results *output_cmd_enable(int argc, char **argv) { - if (!config->handler_context.output_config) { - return cmd_results_new(CMD_FAILURE, "Missing output config"); - } - - config->handler_context.output_config->enabled = 1; - - config->handler_context.leftovers.argc = argc; - config->handler_context.leftovers.argv = argv; - return NULL; -} - diff --git a/sway/commands/output/max_render_time.c b/sway/commands/output/max_render_time.c deleted file mode 100644 index 2d3cebe30..000000000 --- a/sway/commands/output/max_render_time.c +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" - -struct cmd_results *output_cmd_max_render_time(int argc, char **argv) { - if (!config->handler_context.output_config) { - return cmd_results_new(CMD_FAILURE, "Missing output config"); - } - if (!argc) { - return cmd_results_new(CMD_INVALID, "Missing max render time argument."); - } - - int max_render_time; - if (!strcmp(*argv, "off")) { - max_render_time = 0; - } else { - char *end; - max_render_time = strtol(*argv, &end, 10); - if (*end || max_render_time <= 0) { - return cmd_results_new(CMD_INVALID, "Invalid max render time."); - } - } - config->handler_context.output_config->max_render_time = max_render_time; - - config->handler_context.leftovers.argc = argc - 1; - config->handler_context.leftovers.argv = argv + 1; - return NULL; -} diff --git a/sway/commands/output/mode.c b/sway/commands/output/mode.c deleted file mode 100644 index 019d625a7..000000000 --- a/sway/commands/output/mode.c +++ /dev/null @@ -1,118 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" - -struct cmd_results *output_cmd_mode(int argc, char **argv) { - if (!config->handler_context.output_config) { - return cmd_results_new(CMD_FAILURE, "Missing output config"); - } - if (!argc) { - return cmd_results_new(CMD_INVALID, "Missing mode argument."); - } - - struct output_config *output = config->handler_context.output_config; - - if (strcmp(argv[0], "--custom") == 0) { - argv++; - argc--; - output->custom_mode = 1; - } else { - output->custom_mode = 0; - } - - // Reset custom modeline, if any - output->drm_mode.type = 0; - - char *end; - output->width = strtol(*argv, &end, 10); - if (*end) { - // Format is 1234x4321 - if (*end != 'x') { - return cmd_results_new(CMD_INVALID, "Invalid mode width."); - } - ++end; - output->height = strtol(end, &end, 10); - if (*end) { - if (*end != '@') { - return cmd_results_new(CMD_INVALID, "Invalid mode height."); - } - ++end; - output->refresh_rate = strtof(end, &end); - if (strcasecmp("Hz", end) != 0) { - return cmd_results_new(CMD_INVALID, - "Invalid mode refresh rate."); - } - } - } else { - // Format is 1234 4321 - argc--; argv++; - if (!argc) { - return cmd_results_new(CMD_INVALID, - "Missing mode argument (height)."); - } - output->height = strtol(*argv, &end, 10); - if (*end) { - return cmd_results_new(CMD_INVALID, "Invalid mode height."); - } - } - - config->handler_context.leftovers.argc = argc - 1; - config->handler_context.leftovers.argv = argv + 1; - return NULL; -} - -static bool parse_modeline(char **argv, drmModeModeInfo *mode) { - mode->type = DRM_MODE_TYPE_USERDEF; - mode->clock = strtof(argv[0], NULL) * 1000; - mode->hdisplay = strtol(argv[1], NULL, 10); - mode->hsync_start = strtol(argv[2], NULL, 10); - mode->hsync_end = strtol(argv[3], NULL, 10); - mode->htotal = strtol(argv[4], NULL, 10); - mode->vdisplay = strtol(argv[5], NULL, 10); - mode->vsync_start = strtol(argv[6], NULL, 10); - mode->vsync_end = strtol(argv[7], NULL, 10); - mode->vtotal = strtol(argv[8], NULL, 10); - - mode->vrefresh = mode->clock * 1000.0 * 1000.0 - / mode->htotal / mode->vtotal; - if (strcasecmp(argv[9], "+hsync") == 0) { - mode->flags |= DRM_MODE_FLAG_PHSYNC; - } else if (strcasecmp(argv[9], "-hsync") == 0) { - mode->flags |= DRM_MODE_FLAG_NHSYNC; - } else { - return false; - } - - if (strcasecmp(argv[10], "+vsync") == 0) { - mode->flags |= DRM_MODE_FLAG_PVSYNC; - } else if (strcasecmp(argv[10], "-vsync") == 0) { - mode->flags |= DRM_MODE_FLAG_NVSYNC; - } else { - return false; - } - - snprintf(mode->name, sizeof(mode->name), "%dx%d@%d", - mode->hdisplay, mode->vdisplay, mode->vrefresh / 1000); - - return true; -} - -struct cmd_results *output_cmd_modeline(int argc, char **argv) { - if (!config->handler_context.output_config) { - return cmd_results_new(CMD_FAILURE, "Missing output config"); - } - if (!argc) { - return cmd_results_new(CMD_INVALID, "Missing modeline argument."); - } - - struct output_config *output = config->handler_context.output_config; - - if (argc != 11 || !parse_modeline(argv, &output->drm_mode)) { - return cmd_results_new(CMD_INVALID, "Invalid modeline"); - } - - config->handler_context.leftovers.argc = argc - 12; - config->handler_context.leftovers.argv = argv + 12; - return NULL; -} - diff --git a/sway/commands/output/position.c b/sway/commands/output/position.c deleted file mode 100644 index 689462cb9..000000000 --- a/sway/commands/output/position.c +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" - -struct cmd_results *output_cmd_position(int argc, char **argv) { - if (!config->handler_context.output_config) { - return cmd_results_new(CMD_FAILURE, "Missing output config"); - } - if (!argc) { - return cmd_results_new(CMD_INVALID, "Missing position argument."); - } - - char *end; - config->handler_context.output_config->x = strtol(*argv, &end, 10); - if (*end) { - // Format is 1234,4321 - if (*end != ',') { - return cmd_results_new(CMD_INVALID, "Invalid position x."); - } - ++end; - config->handler_context.output_config->y = strtol(end, &end, 10); - if (*end) { - return cmd_results_new(CMD_INVALID, "Invalid position y."); - } - } else { - // Format is 1234 4321 (legacy) - argc--; argv++; - if (!argc) { - return cmd_results_new(CMD_INVALID, "Missing position argument (y)."); - } - config->handler_context.output_config->y = strtol(*argv, &end, 10); - if (*end) { - return cmd_results_new(CMD_INVALID, "Invalid position y."); - } - } - - config->handler_context.leftovers.argc = argc - 1; - config->handler_context.leftovers.argv = argv + 1; - return NULL; -} - diff --git a/sway/commands/output/power.c b/sway/commands/output/power.c deleted file mode 100644 index e6ae28520..000000000 --- a/sway/commands/output/power.c +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/output.h" -#include "util.h" - -struct cmd_results *output_cmd_power(int argc, char **argv) { - if (!config->handler_context.output_config) { - return cmd_results_new(CMD_FAILURE, "Missing output config"); - } - if (argc == 0) { - return cmd_results_new(CMD_INVALID, "Missing power argument"); - } - - bool current = true; - if (strcasecmp(argv[0], "toggle") == 0) { - const char *oc_name = config->handler_context.output_config->name; - if (strcmp(oc_name, "*") == 0) { - return cmd_results_new(CMD_INVALID, - "Cannot apply toggle to all outputs"); - } - - struct sway_output *sway_output = all_output_by_name_or_id(oc_name); - if (!sway_output || !sway_output->wlr_output) { - return cmd_results_new(CMD_FAILURE, - "Cannot apply toggle to unknown output %s", oc_name); - } - - if (sway_output->enabled && !sway_output->wlr_output->enabled) { - current = false; - } - } - - if (parse_boolean(argv[0], current)) { - config->handler_context.output_config->power = 1; - } else { - config->handler_context.output_config->power = 0; - } - - config->handler_context.leftovers.argc = argc - 1; - config->handler_context.leftovers.argv = argv + 1; - return NULL; -} diff --git a/sway/commands/output/render_bit_depth.c b/sway/commands/output/render_bit_depth.c deleted file mode 100644 index c419321ea..000000000 --- a/sway/commands/output/render_bit_depth.c +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "sway/config.h" - -struct cmd_results *output_cmd_render_bit_depth(int argc, char **argv) { - if (!config->handler_context.output_config) { - return cmd_results_new(CMD_FAILURE, "Missing output config"); - } - if (!argc) { - return cmd_results_new(CMD_INVALID, "Missing bit depth argument."); - } - - if (strcmp(*argv, "8") == 0) { - config->handler_context.output_config->render_bit_depth = - RENDER_BIT_DEPTH_8; - } else if (strcmp(*argv, "10") == 0) { - config->handler_context.output_config->render_bit_depth = - RENDER_BIT_DEPTH_10; - } else { - return cmd_results_new(CMD_INVALID, - "Invalid bit depth. Must be a value in (8|10)."); - } - - config->handler_context.leftovers.argc = argc - 1; - config->handler_context.leftovers.argv = argv + 1; - return NULL; -} - diff --git a/sway/commands/output/scale.c b/sway/commands/output/scale.c deleted file mode 100644 index 9398e06ac..000000000 --- a/sway/commands/output/scale.c +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" - -struct cmd_results *output_cmd_scale(int argc, char **argv) { - if (!config->handler_context.output_config) { - return cmd_results_new(CMD_FAILURE, "Missing output config"); - } - if (!argc) { - return cmd_results_new(CMD_INVALID, "Missing scale argument."); - } - - char *end; - config->handler_context.output_config->scale = strtof(*argv, &end); - if (*end) { - return cmd_results_new(CMD_INVALID, "Invalid scale."); - } - - config->handler_context.leftovers.argc = argc - 1; - config->handler_context.leftovers.argv = argv + 1; - return NULL; -} diff --git a/sway/commands/output/scale_filter.c b/sway/commands/output/scale_filter.c deleted file mode 100644 index fa1e8e0d5..000000000 --- a/sway/commands/output/scale_filter.c +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include "log.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/output.h" - -struct cmd_results *output_cmd_scale_filter(int argc, char **argv) { - if (!config->handler_context.output_config) { - return cmd_results_new(CMD_FAILURE, "Missing output config"); - } - - if (!argc) { - return cmd_results_new(CMD_INVALID, "Missing scale_filter argument."); - } - - - enum scale_filter_mode scale_filter; - if (strcmp(*argv, "linear") == 0) { - scale_filter = SCALE_FILTER_LINEAR; - } else if (strcmp(*argv, "nearest") == 0) { - scale_filter = SCALE_FILTER_NEAREST; - } else if (strcmp(*argv, "smart") == 0) { - scale_filter = SCALE_FILTER_SMART; - } else { - return cmd_results_new(CMD_INVALID, "Invalid output scale_filter."); - } - - struct output_config *oc = config->handler_context.output_config; - config->handler_context.leftovers.argc = argc - 1; - config->handler_context.leftovers.argv = argv + 1; - - oc->scale_filter = scale_filter; - return NULL; -} diff --git a/sway/commands/output/subpixel.c b/sway/commands/output/subpixel.c deleted file mode 100644 index 63191ee62..000000000 --- a/sway/commands/output/subpixel.c +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include "log.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/output.h" - -struct cmd_results *output_cmd_subpixel(int argc, char **argv) { - if (!config->handler_context.output_config) { - return cmd_results_new(CMD_FAILURE, "Missing output config"); - } - if (!argc) { - return cmd_results_new(CMD_INVALID, "Missing subpixel argument."); - } - enum wl_output_subpixel subpixel; - - if (strcmp(*argv, "rgb") == 0) { - subpixel = WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB; - } else if (strcmp(*argv, "bgr") == 0) { - subpixel = WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR; - } else if (strcmp(*argv, "vrgb") == 0) { - subpixel = WL_OUTPUT_SUBPIXEL_VERTICAL_RGB; - } else if (strcmp(*argv, "vbgr") == 0) { - subpixel = WL_OUTPUT_SUBPIXEL_VERTICAL_BGR; - } else if (strcmp(*argv, "none") == 0) { - subpixel = WL_OUTPUT_SUBPIXEL_NONE; - } else { - return cmd_results_new(CMD_INVALID, "Invalid output subpixel."); - } - - struct output_config *oc = config->handler_context.output_config; - config->handler_context.leftovers.argc = argc - 1; - config->handler_context.leftovers.argv = argv + 1; - - oc->subpixel = subpixel; - return NULL; -} diff --git a/sway/commands/output/toggle.c b/sway/commands/output/toggle.c deleted file mode 100644 index 6342d526b..000000000 --- a/sway/commands/output/toggle.c +++ /dev/null @@ -1,37 +0,0 @@ -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/output.h" - -struct cmd_results *output_cmd_toggle(int argc, char **argv) { - if (!config->handler_context.output_config) { - return cmd_results_new(CMD_FAILURE, "Missing output config"); - } - - struct output_config *oc = config->handler_context.output_config; - - if (strcmp(oc->name, "*") == 0) { - return cmd_results_new(CMD_INVALID, - "Cannot apply toggle to all outputs."); - } - - struct sway_output *sway_output = all_output_by_name_or_id(oc->name); - - if (sway_output == NULL) { - return cmd_results_new(CMD_FAILURE, - "Cannot apply toggle to unknown output %s", oc->name); - } - - oc = find_output_config(sway_output); - - if (!oc || oc->enabled != 0) { - config->handler_context.output_config->enabled = 0; - } else { - config->handler_context.output_config->enabled = 1; - } - - free(oc); - config->handler_context.leftovers.argc = argc; - config->handler_context.leftovers.argv = argv; - return NULL; -} - diff --git a/sway/commands/output/transform.c b/sway/commands/output/transform.c deleted file mode 100644 index f4fcc8c99..000000000 --- a/sway/commands/output/transform.c +++ /dev/null @@ -1,89 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "log.h" -#include "sway/output.h" - -static enum wl_output_transform invert_rotation_direction( - enum wl_output_transform t) { - switch (t) { - case WL_OUTPUT_TRANSFORM_90: - return WL_OUTPUT_TRANSFORM_270; - case WL_OUTPUT_TRANSFORM_270: - return WL_OUTPUT_TRANSFORM_90; - case WL_OUTPUT_TRANSFORM_FLIPPED_90: - return WL_OUTPUT_TRANSFORM_FLIPPED_270; - case WL_OUTPUT_TRANSFORM_FLIPPED_270: - return WL_OUTPUT_TRANSFORM_FLIPPED_90; - default: - return t; - } -} - -struct cmd_results *output_cmd_transform(int argc, char **argv) { - if (!config->handler_context.output_config) { - return cmd_results_new(CMD_FAILURE, "Missing output config"); - } - if (!argc) { - return cmd_results_new(CMD_INVALID, "Missing transform argument."); - } - - enum wl_output_transform transform; - if (strcmp(*argv, "normal") == 0 || - strcmp(*argv, "0") == 0) { - transform = WL_OUTPUT_TRANSFORM_NORMAL; - } else if (strcmp(*argv, "90") == 0) { - transform = WL_OUTPUT_TRANSFORM_90; - } else if (strcmp(*argv, "180") == 0) { - transform = WL_OUTPUT_TRANSFORM_180; - } else if (strcmp(*argv, "270") == 0) { - transform = WL_OUTPUT_TRANSFORM_270; - } else if (strcmp(*argv, "flipped") == 0) { - transform = WL_OUTPUT_TRANSFORM_FLIPPED; - } else if (strcmp(*argv, "flipped-90") == 0) { - transform = WL_OUTPUT_TRANSFORM_FLIPPED_90; - } else if (strcmp(*argv, "flipped-180") == 0) { - transform = WL_OUTPUT_TRANSFORM_FLIPPED_180; - } else if (strcmp(*argv, "flipped-270") == 0) { - transform = WL_OUTPUT_TRANSFORM_FLIPPED_270; - } else { - return cmd_results_new(CMD_INVALID, "Invalid output transform."); - } - - // Sway uses clockwise transforms, while WL_OUTPUT_TRANSFORM_* describe - // anti-clockwise transforms - transform = invert_rotation_direction(transform); - - struct output_config *output = config->handler_context.output_config; - config->handler_context.leftovers.argc = argc - 1; - config->handler_context.leftovers.argv = argv + 1; - if (argc > 1 && - (strcmp(argv[1], "clockwise") == 0 || strcmp(argv[1], "anticlockwise") == 0)) { - if (config->reloading) { - return cmd_results_new(CMD_INVALID, - "Relative transforms cannot be used in the configuration file"); - } - if (!sway_assert(output->name != NULL, "Output config name not set")) { - return NULL; - } - if (strcmp(output->name, "*") == 0) { - return cmd_results_new(CMD_INVALID, - "Cannot apply relative transform to all outputs."); - } - struct sway_output *s_output = output_by_name_or_id(output->name); - if (s_output == NULL) { - return cmd_results_new(CMD_INVALID, - "Cannot apply relative transform to unknown output %s", output->name); - } - if (strcmp(argv[1], "anticlockwise") == 0) { - transform = invert_rotation_direction(transform); - } - struct wlr_output *w_output = s_output->wlr_output; - transform = wlr_output_transform_compose(w_output->transform, transform); - config->handler_context.leftovers.argv += 1; - config->handler_context.leftovers.argc -= 1; - } - - output->transform = transform; - return NULL; -} diff --git a/sway/commands/output/unplug.c b/sway/commands/output/unplug.c deleted file mode 100644 index dfef626f1..000000000 --- a/sway/commands/output/unplug.c +++ /dev/null @@ -1,54 +0,0 @@ -#include -#include -#include -#include -#if WLR_HAS_X11_BACKEND -#include -#endif -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/output.h" - -static bool is_backend_allowed(struct wlr_backend *backend) { - if (wlr_backend_is_headless(backend)) { - return true; - } - if (wlr_backend_is_wl(backend)) { - return true; - } -#if WLR_HAS_X11_BACKEND - if (wlr_backend_is_x11(backend)) { - return true; - } -#endif - return false; -} - -/** - * This command is intended for developer use only. - */ -struct cmd_results *output_cmd_unplug(int argc, char **argv) { - if (!config->handler_context.output_config) { - return cmd_results_new(CMD_FAILURE, "Missing output config"); - } - - const char *oc_name = config->handler_context.output_config->name; - if (strcmp(oc_name, "*") == 0) { - return cmd_results_new(CMD_INVALID, "Won't unplug all outputs"); - } - - struct sway_output *sway_output = all_output_by_name_or_id(oc_name); - if (!sway_output) { - return cmd_results_new(CMD_INVALID, - "Cannot unplug unknown output %s", oc_name); - } - - if (!is_backend_allowed(sway_output->wlr_output->backend)) { - return cmd_results_new(CMD_INVALID, - "Can only unplug outputs with headless, wayland or x11 backend"); - } - - wlr_output_destroy(sway_output->wlr_output); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/popup_during_fullscreen.c b/sway/commands/popup_during_fullscreen.c deleted file mode 100644 index e81562623..000000000 --- a/sway/commands/popup_during_fullscreen.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" - -struct cmd_results *cmd_popup_during_fullscreen(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "popup_during_fullscreen", - EXPECTED_EQUAL_TO, 1))) { - return error; - } - - if (strcasecmp(argv[0], "smart") == 0) { - config->popup_during_fullscreen = POPUP_SMART; - } else if (strcasecmp(argv[0], "ignore") == 0) { - config->popup_during_fullscreen = POPUP_IGNORE; - } else if (strcasecmp(argv[0], "leave_fullscreen") == 0) { - config->popup_during_fullscreen = POPUP_LEAVE; - } else { - return cmd_results_new(CMD_INVALID, "Expected " - "'popup_during_fullscreen smart|ignore|leave_fullscreen'"); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/primary_selection.c b/sway/commands/primary_selection.c deleted file mode 100644 index 585b079d4..000000000 --- a/sway/commands/primary_selection.c +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include -#include "sway/config.h" -#include "sway/commands.h" -#include "util.h" - -struct cmd_results *cmd_primary_selection(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "primary_selection", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - bool primary_selection = parse_boolean(argv[0], true); - - if (config->reloading && config->primary_selection != primary_selection) { - return cmd_results_new(CMD_FAILURE, - "primary_selection can only be enabled/disabled at launch"); - } - - config->primary_selection = parse_boolean(argv[0], true); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/reload.c b/sway/commands/reload.c deleted file mode 100644 index 76f14bba3..000000000 --- a/sway/commands/reload.c +++ /dev/null @@ -1,76 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/ipc-server.h" -#include "sway/server.h" -#include "sway/tree/arrange.h" -#include "sway/tree/view.h" -#include "list.h" -#include "log.h" - -static void rebuild_textures_iterator(struct sway_container *con, void *data) { - container_update_marks_textures(con); - container_update_title_textures(con); -} - -static void do_reload(void *data) { - // store bar ids to check against new bars for barconfig_update events - list_t *bar_ids = create_list(); - for (int i = 0; i < config->bars->length; ++i) { - struct bar_config *bar = config->bars->items[i]; - list_add(bar_ids, strdup(bar->id)); - } - - const char *path = NULL; - if (config->user_config_path) { - path = config->current_config_path; - } - - if (!load_main_config(path, true, false)) { - sway_log(SWAY_ERROR, "Error(s) reloading config"); - list_free_items_and_destroy(bar_ids); - return; - } - - ipc_event_workspace(NULL, NULL, "reload"); - - load_swaybars(); - - for (int i = 0; i < config->bars->length; ++i) { - struct bar_config *bar = config->bars->items[i]; - for (int j = 0; j < bar_ids->length; ++j) { - if (strcmp(bar->id, bar_ids->items[j]) == 0) { - ipc_event_barconfig_update(bar); - break; - } - } - } - list_free_items_and_destroy(bar_ids); - - root_for_each_container(rebuild_textures_iterator, NULL); - - arrange_root(); -} - -struct cmd_results *cmd_reload(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) { - return error; - } - - const char *path = NULL; - if (config->user_config_path) { - path = config->current_config_path; - } - - if (!load_main_config(path, true, true)) { - return cmd_results_new(CMD_FAILURE, "Error(s) reloading config."); - } - - // The reload command frees a lot of stuff, so to avoid use-after-frees - // we schedule the reload to happen using an idle event. - wl_event_loop_add_idle(server.wl_event_loop, do_reload, NULL); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/rename.c b/sway/commands/rename.c deleted file mode 100644 index 0d36cc21e..000000000 --- a/sway/commands/rename.c +++ /dev/null @@ -1,102 +0,0 @@ -#include -#include -#include -#include "log.h" -#include "stringop.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/ipc-server.h" -#include "sway/output.h" -#include "sway/desktop/launcher.h" -#include "sway/tree/container.h" -#include "sway/tree/workspace.h" -#include "sway/tree/root.h" - -static const char expected_syntax[] = - "Expected 'rename workspace to ' or " - "'rename workspace to '"; - -struct cmd_results *cmd_rename(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "rename", EXPECTED_AT_LEAST, 3))) { - return error; - } - if (!root->outputs->length) { - return cmd_results_new(CMD_INVALID, - "Can't run this command while there's no outputs connected."); - } - if (strcasecmp(argv[0], "workspace") != 0) { - return cmd_results_new(CMD_INVALID, "%s", expected_syntax); - } - - int argn = 1; - struct sway_workspace *workspace = NULL; - - if (strcasecmp(argv[1], "to") == 0) { - // 'rename workspace to new_name' - workspace = config->handler_context.workspace; - } else if (strcasecmp(argv[1], "number") == 0) { - // 'rename workspace number x to new_name' - if (!isdigit(argv[2][0])) { - return cmd_results_new(CMD_INVALID, - "Invalid workspace number '%s'", argv[2]); - } - workspace = workspace_by_number(argv[2]); - while (argn < argc && strcasecmp(argv[argn], "to") != 0) { - ++argn; - } - } else { - // 'rename workspace old_name to new_name' - int end = argn; - while (end < argc && strcasecmp(argv[end], "to") != 0) { - ++end; - } - char *old_name = join_args(argv + argn, end - argn); - workspace = workspace_by_name(old_name); - free(old_name); - argn = end; - } - - if (!workspace) { - return cmd_results_new(CMD_INVALID, - "There is no workspace with that name"); - } - - ++argn; // move past "to" - - if (argn >= argc) { - return cmd_results_new(CMD_INVALID, "%s", expected_syntax); - } - - char *new_name = join_args(argv + argn, argc - argn); - if (strcasecmp(new_name, "next") == 0 || - strcasecmp(new_name, "prev") == 0 || - strcasecmp(new_name, "next_on_output") == 0 || - strcasecmp(new_name, "prev_on_output") == 0 || - strcasecmp(new_name, "back_and_forth") == 0 || - strcasecmp(new_name, "current") == 0 || - strcasecmp(new_name, "number") == 0) { - free(new_name); - return cmd_results_new(CMD_INVALID, - "Cannot use special workspace name '%s'", argv[argn]); - } - struct sway_workspace *tmp_workspace = workspace_by_name(new_name); - if (tmp_workspace) { - free(new_name); - if (tmp_workspace == workspace) { - return cmd_results_new(CMD_SUCCESS, NULL); - } else { - return cmd_results_new(CMD_INVALID, "Workspace already exists"); - } - } - - sway_log(SWAY_DEBUG, "renaming workspace '%s' to '%s'", workspace->name, new_name); - - free(workspace->name); - workspace->name = new_name; - - output_sort_workspaces(workspace->output); - ipc_event_workspace(NULL, workspace, "rename"); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/resize.c b/sway/commands/resize.c deleted file mode 100644 index 32b746eaf..000000000 --- a/sway/commands/resize.c +++ /dev/null @@ -1,598 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include "sway/commands.h" -#include "sway/tree/arrange.h" -#include "sway/tree/view.h" -#include "sway/tree/workspace.h" -#include "log.h" -#include "util.h" - -#define AXIS_HORIZONTAL (WLR_EDGE_LEFT | WLR_EDGE_RIGHT) -#define AXIS_VERTICAL (WLR_EDGE_TOP | WLR_EDGE_BOTTOM) - -static uint32_t parse_resize_axis(const char *axis) { - if (strcasecmp(axis, "width") == 0 || strcasecmp(axis, "horizontal") == 0) { - return AXIS_HORIZONTAL; - } - if (strcasecmp(axis, "height") == 0 || strcasecmp(axis, "vertical") == 0) { - return AXIS_VERTICAL; - } - if (strcasecmp(axis, "up") == 0) { - return WLR_EDGE_TOP; - } - if (strcasecmp(axis, "down") == 0) { - return WLR_EDGE_BOTTOM; - } - if (strcasecmp(axis, "left") == 0) { - return WLR_EDGE_LEFT; - } - if (strcasecmp(axis, "right") == 0) { - return WLR_EDGE_RIGHT; - } - return WLR_EDGE_NONE; -} - -static bool is_horizontal(uint32_t axis) { - return axis & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT); -} - -struct sway_container *container_find_resize_parent(struct sway_container *con, - uint32_t axis) { - enum sway_container_layout parallel_layout = - is_horizontal(axis) ? L_HORIZ : L_VERT; - bool allow_first = axis != WLR_EDGE_TOP && axis != WLR_EDGE_LEFT; - bool allow_last = axis != WLR_EDGE_RIGHT && axis != WLR_EDGE_BOTTOM; - - while (con) { - list_t *siblings = container_get_siblings(con); - int index = container_sibling_index(con); - if (container_parent_layout(con) == parallel_layout && - siblings->length > 1 && (allow_first || index > 0) && - (allow_last || index < siblings->length - 1)) { - return con; - } - con = con->pending.parent; - } - - return NULL; -} - -void container_resize_tiled(struct sway_container *con, - uint32_t axis, int amount) { - if (!con) { - return; - } - - con = container_find_resize_parent(con, axis); - if (!con) { - // Can't resize in this direction - return; - } - - if (container_is_scratchpad_hidden_or_child(con)) { - return; - } - - // For HORIZONTAL or VERTICAL, we are growing in two directions so select - // both adjacent siblings. For RIGHT or DOWN, just select the next sibling. - // For LEFT or UP, convert it to a RIGHT or DOWN resize and reassign con to - // the previous sibling. - struct sway_container *prev = NULL; - struct sway_container *next = NULL; - list_t *siblings = container_get_siblings(con); - int index = container_sibling_index(con); - - if (axis == AXIS_HORIZONTAL || axis == AXIS_VERTICAL) { - if (index == 0) { - next = siblings->items[1]; - } else if (index == siblings->length - 1) { - // Convert edge to top/left - next = con; - con = siblings->items[index - 1]; - amount = -amount; - } else { - prev = siblings->items[index - 1]; - next = siblings->items[index + 1]; - } - } else if (axis == WLR_EDGE_TOP || axis == WLR_EDGE_LEFT) { - if (!sway_assert(index > 0, "Didn't expect first child")) { - return; - } - next = con; - con = siblings->items[index - 1]; - amount = -amount; - } else { - if (!sway_assert(index < siblings->length - 1, - "Didn't expect last child")) { - return; - } - next = siblings->items[index + 1]; - } - - // Apply new dimensions - int sibling_amount = prev ? ceil((double)amount / 2.0) : amount; - - if (is_horizontal(axis)) { - if (con->pending.width + amount < MIN_SANE_W) { - return; - } - if (next->pending.width - sibling_amount < MIN_SANE_W) { - return; - } - if (prev && prev->pending.width - sibling_amount < MIN_SANE_W) { - return; - } - if (con->child_total_width <= 0) { - return; - } - - // We're going to resize so snap all the width fractions to full pixels - // to avoid rounding issues - list_t *siblings = container_get_siblings(con); - for (int i = 0; i < siblings->length; ++i) { - struct sway_container *con = siblings->items[i]; - con->width_fraction = con->pending.width / con->child_total_width; - } - - double amount_fraction = (double)amount / con->child_total_width; - double sibling_amount_fraction = - prev ? amount_fraction / 2.0 : amount_fraction; - - con->width_fraction += amount_fraction; - next->width_fraction -= sibling_amount_fraction; - if (prev) { - prev->width_fraction -= sibling_amount_fraction; - } - } else { - if (con->pending.height + amount < MIN_SANE_H) { - return; - } - if (next->pending.height - sibling_amount < MIN_SANE_H) { - return; - } - if (prev && prev->pending.height - sibling_amount < MIN_SANE_H) { - return; - } - if (con->child_total_height <= 0) { - return; - } - - // We're going to resize so snap all the height fractions to full pixels - // to avoid rounding issues - list_t *siblings = container_get_siblings(con); - for (int i = 0; i < siblings->length; ++i) { - struct sway_container *con = siblings->items[i]; - con->height_fraction = con->pending.height / con->child_total_height; - } - - double amount_fraction = (double)amount / con->child_total_height; - double sibling_amount_fraction = - prev ? amount_fraction / 2.0 : amount_fraction; - - con->height_fraction += amount_fraction; - next->height_fraction -= sibling_amount_fraction; - if (prev) { - prev->height_fraction -= sibling_amount_fraction; - } - } - - if (con->pending.parent) { - arrange_container(con->pending.parent); - } else { - arrange_workspace(con->pending.workspace); - } -} - -/** - * Implement `resize ` for a floating container. - */ -static struct cmd_results *resize_adjust_floating(uint32_t axis, - struct movement_amount *amount) { - struct sway_container *con = config->handler_context.container; - int grow_width = 0, grow_height = 0; - - if (is_horizontal(axis)) { - grow_width = amount->amount; - } else { - grow_height = amount->amount; - } - - // Make sure we're not adjusting beyond floating min/max size - int min_width, max_width, min_height, max_height; - floating_calculate_constraints(&min_width, &max_width, - &min_height, &max_height); - if (con->pending.width + grow_width < min_width) { - grow_width = min_width - con->pending.width; - } else if (con->pending.width + grow_width > max_width) { - grow_width = max_width - con->pending.width; - } - if (con->pending.height + grow_height < min_height) { - grow_height = min_height - con->pending.height; - } else if (con->pending.height + grow_height > max_height) { - grow_height = max_height - con->pending.height; - } - int grow_x = 0, grow_y = 0; - - if (axis == AXIS_HORIZONTAL) { - grow_x = -grow_width / 2; - } else if (axis == AXIS_VERTICAL) { - grow_y = -grow_height / 2; - } else if (axis == WLR_EDGE_TOP) { - grow_y = -grow_height; - } else if (axis == WLR_EDGE_LEFT) { - grow_x = -grow_width; - } - if (grow_width == 0 && grow_height == 0) { - return cmd_results_new(CMD_INVALID, "Cannot resize any further"); - } - con->pending.x += grow_x; - con->pending.y += grow_y; - con->pending.width += grow_width; - con->pending.height += grow_height; - - con->pending.content_x += grow_x; - con->pending.content_y += grow_y; - con->pending.content_width += grow_width; - con->pending.content_height += grow_height; - - arrange_container(con); - - return cmd_results_new(CMD_SUCCESS, NULL); -} - -/** - * Implement `resize ` for a tiled container. - */ -static struct cmd_results *resize_adjust_tiled(uint32_t axis, - struct movement_amount *amount) { - struct sway_container *current = config->handler_context.container; - - if (container_is_scratchpad_hidden_or_child(current)) { - return cmd_results_new(CMD_FAILURE, "Cannot resize a hidden scratchpad container"); - } - - if (amount->unit == MOVEMENT_UNIT_DEFAULT) { - amount->unit = MOVEMENT_UNIT_PPT; - } - if (amount->unit == MOVEMENT_UNIT_PPT) { - struct sway_container *parent = current->pending.parent; - float pct = amount->amount / 100.0f; - - if (is_horizontal(axis)) { - while (parent && parent->pending.layout != L_HORIZ) { - parent = parent->pending.parent; - } - if (parent) { - amount->amount = (float)parent->pending.width * pct; - } else { - amount->amount = (float)current->pending.workspace->width * pct; - } - } else { - while (parent && parent->pending.layout != L_VERT) { - parent = parent->pending.parent; - } - if (parent) { - amount->amount = (float)parent->pending.height * pct; - } else { - amount->amount = (float)current->pending.workspace->height * pct; - } - } - } - - double old_width = current->width_fraction; - double old_height = current->height_fraction; - container_resize_tiled(current, axis, amount->amount); - if (current->width_fraction == old_width && - current->height_fraction == old_height) { - return cmd_results_new(CMD_INVALID, "Cannot resize any further"); - } - return cmd_results_new(CMD_SUCCESS, NULL); -} - -/** - * Implement `resize set` for a tiled container. - */ -static struct cmd_results *resize_set_tiled(struct sway_container *con, - struct movement_amount *width, struct movement_amount *height) { - - if (container_is_scratchpad_hidden_or_child(con)) { - return cmd_results_new(CMD_FAILURE, "Cannot resize a hidden scratchpad container"); - } - - if (width->amount) { - if (width->unit == MOVEMENT_UNIT_PPT || - width->unit == MOVEMENT_UNIT_DEFAULT) { - // Convert to px - struct sway_container *parent = con->pending.parent; - while (parent && parent->pending.layout != L_HORIZ) { - parent = parent->pending.parent; - } - if (parent) { - width->amount = parent->pending.width * width->amount / 100; - } else { - width->amount = con->pending.workspace->width * width->amount / 100; - } - width->unit = MOVEMENT_UNIT_PX; - } - if (width->unit == MOVEMENT_UNIT_PX) { - container_resize_tiled(con, AXIS_HORIZONTAL, - width->amount - con->pending.width); - } - } - - if (height->amount) { - if (height->unit == MOVEMENT_UNIT_PPT || - height->unit == MOVEMENT_UNIT_DEFAULT) { - // Convert to px - struct sway_container *parent = con->pending.parent; - while (parent && parent->pending.layout != L_VERT) { - parent = parent->pending.parent; - } - if (parent) { - height->amount = parent->pending.height * height->amount / 100; - } else { - height->amount = con->pending.workspace->height * height->amount / 100; - } - height->unit = MOVEMENT_UNIT_PX; - } - if (height->unit == MOVEMENT_UNIT_PX) { - container_resize_tiled(con, AXIS_VERTICAL, - height->amount - con->pending.height); - } - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} - -/** - * Implement `resize set` for a floating container. - */ -static struct cmd_results *resize_set_floating(struct sway_container *con, - struct movement_amount *width, struct movement_amount *height) { - int min_width, max_width, min_height, max_height, grow_width = 0, grow_height = 0; - floating_calculate_constraints(&min_width, &max_width, - &min_height, &max_height); - - if (width->amount) { - switch (width->unit) { - case MOVEMENT_UNIT_PPT: - if (container_is_scratchpad_hidden(con)) { - return cmd_results_new(CMD_FAILURE, - "Cannot resize a hidden scratchpad container by ppt"); - } - // Convert to px - width->amount = con->pending.workspace->width * width->amount / 100; - width->unit = MOVEMENT_UNIT_PX; - // Falls through - case MOVEMENT_UNIT_PX: - case MOVEMENT_UNIT_DEFAULT: - width->amount = fmax(min_width, fmin(width->amount, max_width)); - grow_width = width->amount - con->pending.width; - con->pending.x -= grow_width / 2; - con->pending.width = width->amount; - break; - case MOVEMENT_UNIT_INVALID: - sway_assert(false, "invalid width unit"); - break; - } - } - - if (height->amount) { - switch (height->unit) { - case MOVEMENT_UNIT_PPT: - if (container_is_scratchpad_hidden(con)) { - return cmd_results_new(CMD_FAILURE, - "Cannot resize a hidden scratchpad container by ppt"); - } - // Convert to px - height->amount = con->pending.workspace->height * height->amount / 100; - height->unit = MOVEMENT_UNIT_PX; - // Falls through - case MOVEMENT_UNIT_PX: - case MOVEMENT_UNIT_DEFAULT: - height->amount = fmax(min_height, fmin(height->amount, max_height)); - grow_height = height->amount - con->pending.height; - con->pending.y -= grow_height / 2; - con->pending.height = height->amount; - break; - case MOVEMENT_UNIT_INVALID: - sway_assert(false, "invalid height unit"); - break; - } - } - - con->pending.content_x -= grow_width / 2; - con->pending.content_y -= grow_height / 2; - con->pending.content_width += grow_width; - con->pending.content_height += grow_height; - - arrange_container(con); - - return cmd_results_new(CMD_SUCCESS, NULL); -} - -/** - * resize set - * - * args: [width] [px|ppt] - * : height [px|ppt] - * : [width] [px|ppt] [height] [px|ppt] - */ -static struct cmd_results *cmd_resize_set(int argc, char **argv) { - struct cmd_results *error; - if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 1))) { - return error; - } - const char usage[] = "Expected 'resize set [width] [px|ppt]' or " - "'resize set height [px|ppt]' or " - "'resize set [width] [px|ppt] [height] [px|ppt]'"; - - // Width - struct movement_amount width = {0}; - if (argc >= 2 && !strcmp(argv[0], "width") && strcmp(argv[1], "height")) { - argc--; argv++; - } - if (strcmp(argv[0], "height")) { - int num_consumed_args = parse_movement_amount(argc, argv, &width); - argc -= num_consumed_args; - argv += num_consumed_args; - if (width.unit == MOVEMENT_UNIT_INVALID) { - return cmd_results_new(CMD_INVALID, "%s", usage); - } - } - - // Height - struct movement_amount height = {0}; - if (argc) { - if (argc >= 2 && !strcmp(argv[0], "height")) { - argc--; argv++; - } - int num_consumed_args = parse_movement_amount(argc, argv, &height); - if (argc > num_consumed_args) { - return cmd_results_new(CMD_INVALID, "%s", usage); - } - if (width.unit == MOVEMENT_UNIT_INVALID) { - return cmd_results_new(CMD_INVALID, "%s", usage); - } - } - - // If 0, don't resize that dimension - struct sway_container *con = config->handler_context.container; - if (width.amount <= 0) { - width.amount = con->pending.width; - } - if (height.amount <= 0) { - height.amount = con->pending.height; - } - - if (container_is_floating(con)) { - return resize_set_floating(con, &width, &height); - } - return resize_set_tiled(con, &width, &height); -} - -/** - * resize - * - * args: - * args: - * args: or - */ -static struct cmd_results *cmd_resize_adjust(int argc, char **argv, - int multiplier) { - const char usage[] = "Expected 'resize grow|shrink " - "[ px|ppt [or px|ppt]]'"; - uint32_t axis = parse_resize_axis(*argv); - if (axis == WLR_EDGE_NONE) { - return cmd_results_new(CMD_INVALID, "%s", usage); - } - --argc; ++argv; - - // First amount - struct movement_amount first_amount; - if (argc) { - int num_consumed_args = parse_movement_amount(argc, argv, &first_amount); - argc -= num_consumed_args; - argv += num_consumed_args; - if (first_amount.unit == MOVEMENT_UNIT_INVALID) { - return cmd_results_new(CMD_INVALID, "%s", usage); - } - } else { - first_amount.amount = 10; - first_amount.unit = MOVEMENT_UNIT_DEFAULT; - } - - // "or" - if (argc) { - if (strcmp(*argv, "or") != 0) { - return cmd_results_new(CMD_INVALID, "%s", usage); - } - --argc; ++argv; - } - - // Second amount - struct movement_amount second_amount; - if (argc) { - int num_consumed_args = parse_movement_amount(argc, argv, &second_amount); - if (argc > num_consumed_args) { - return cmd_results_new(CMD_INVALID, "%s", usage); - } - if (second_amount.unit == MOVEMENT_UNIT_INVALID) { - return cmd_results_new(CMD_INVALID, "%s", usage); - } - } else { - second_amount.amount = 0; - second_amount.unit = MOVEMENT_UNIT_INVALID; - } - - first_amount.amount *= multiplier; - second_amount.amount *= multiplier; - - struct sway_container *con = config->handler_context.container; - if (container_is_floating(con)) { - // Floating containers can only resize in px. Choose an amount which - // uses px, with fallback to an amount that specified no unit. - if (first_amount.unit == MOVEMENT_UNIT_PX) { - return resize_adjust_floating(axis, &first_amount); - } else if (second_amount.unit == MOVEMENT_UNIT_PX) { - return resize_adjust_floating(axis, &second_amount); - } else if (first_amount.unit == MOVEMENT_UNIT_DEFAULT) { - return resize_adjust_floating(axis, &first_amount); - } else if (second_amount.unit == MOVEMENT_UNIT_DEFAULT) { - return resize_adjust_floating(axis, &second_amount); - } else { - return cmd_results_new(CMD_INVALID, - "Floating containers cannot use ppt measurements"); - } - } - - // For tiling, prefer ppt -> default -> px - if (first_amount.unit == MOVEMENT_UNIT_PPT) { - return resize_adjust_tiled(axis, &first_amount); - } else if (second_amount.unit == MOVEMENT_UNIT_PPT) { - return resize_adjust_tiled(axis, &second_amount); - } else if (first_amount.unit == MOVEMENT_UNIT_DEFAULT) { - return resize_adjust_tiled(axis, &first_amount); - } else if (second_amount.unit == MOVEMENT_UNIT_DEFAULT) { - return resize_adjust_tiled(axis, &second_amount); - } else { - return resize_adjust_tiled(axis, &first_amount); - } -} - -struct cmd_results *cmd_resize(int argc, char **argv) { - if (!root->outputs->length) { - return cmd_results_new(CMD_INVALID, - "Can't run this command while there's no outputs connected."); - } - struct sway_container *current = config->handler_context.container; - if (!current) { - return cmd_results_new(CMD_INVALID, "Cannot resize nothing"); - } - - struct cmd_results *error; - if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) { - return error; - } - - if (strcasecmp(argv[0], "set") == 0) { - return cmd_resize_set(argc - 1, &argv[1]); - } - if (strcasecmp(argv[0], "grow") == 0) { - return cmd_resize_adjust(argc - 1, &argv[1], 1); - } - if (strcasecmp(argv[0], "shrink") == 0) { - return cmd_resize_adjust(argc - 1, &argv[1], -1); - } - - const char usage[] = "Expected 'resize " - " [] [px|ppt]'"; - - return cmd_results_new(CMD_INVALID, "%s", usage); -} diff --git a/sway/commands/saturation.c b/sway/commands/saturation.c deleted file mode 100644 index 35f021288..000000000 --- a/sway/commands/saturation.c +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include -#include -#include -#include "sway/commands.h" -#include "sway/tree/view.h" -#include "log.h" - -struct cmd_results *cmd_saturation(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "saturation", EXPECTED_AT_LEAST, 1))) { - return error; - } - - struct sway_container *con = config->handler_context.container; - - if (con == NULL) { - return cmd_results_new(CMD_FAILURE, "No current container"); - } - - char *err; - float val = strtof(argc == 1 ? argv[0] : argv[1], &err); - if (*err) { - return cmd_results_new(CMD_INVALID, "saturation float invalid"); - } - - if (!strcasecmp(argv[0], "plus")) { - val = con->saturation + val; - } else if (!strcasecmp(argv[0], "minus")) { - val = con->saturation - val; - } else if (argc > 1 && strcasecmp(argv[0], "set")) { - return cmd_results_new(CMD_INVALID, - "Expected: set|plus|minus <0..2>: %s", argv[0]); - } - - if (val < 0 || val > 2) { - return cmd_results_new(CMD_FAILURE, "saturation value out of bounds"); - } - - con->saturation = val; - container_damage_whole(con); - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/scratchpad.c b/sway/commands/scratchpad.c deleted file mode 100644 index c995f2f08..000000000 --- a/sway/commands/scratchpad.c +++ /dev/null @@ -1,132 +0,0 @@ -#include "log.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/input/input-manager.h" -#include "sway/input/seat.h" -#include "sway/ipc-server.h" -#include "sway/tree/container.h" -#include "sway/tree/root.h" -#include "sway/tree/workspace.h" - -static void scratchpad_toggle_auto(void) { - struct sway_seat *seat = input_manager_current_seat(); - struct sway_container *focus = seat_get_focused_container(seat); - struct sway_workspace *ws = seat_get_focused_workspace(seat); - if (!ws) { - sway_log(SWAY_DEBUG, - "No focused workspace to toggle scratchpad windows on"); - return; - } - - // If the focus is in a floating split container, - // operate on the split container instead of the child. - if (focus && container_is_floating_or_child(focus)) { - while (focus->pending.parent) { - focus = focus->pending.parent; - } - } - - // Check if the currently focused window is a scratchpad window and should - // be hidden again. - if (focus && focus->scratchpad) { - sway_log(SWAY_DEBUG, "Focus is a scratchpad window - hiding %s", - focus->title); - root_scratchpad_hide(focus); - return; - } - - // Check if there is an unfocused scratchpad window on the current workspace - // and focus it. - for (int i = 0; i < ws->floating->length; ++i) { - struct sway_container *floater = ws->floating->items[i]; - if (floater->scratchpad && focus != floater) { - sway_log(SWAY_DEBUG, - "Focusing other scratchpad window (%s) in this workspace", - floater->title); - root_scratchpad_show(floater); - return; - } - } - - // Check if there is a visible scratchpad window on another workspace. - // In this case we move it to the current workspace. - for (int i = 0; i < root->scratchpad->length; ++i) { - struct sway_container *con = root->scratchpad->items[i]; - if (con->pending.parent) { - sway_log(SWAY_DEBUG, - "Moving a visible scratchpad window (%s) to this workspace", - con->title); - root_scratchpad_show(con); - ipc_event_window(con, "move"); - return; - } - } - - // Take the container at the bottom of the scratchpad list - if (!sway_assert(root->scratchpad->length, "Scratchpad is empty")) { - return; - } - struct sway_container *con = root->scratchpad->items[0]; - sway_log(SWAY_DEBUG, "Showing %s from list", con->title); - root_scratchpad_show(con); - ipc_event_window(con, "move"); -} - -static void scratchpad_toggle_container(struct sway_container *con) { - if (!sway_assert(con->scratchpad, "Container isn't in the scratchpad")) { - return; - } - - struct sway_seat *seat = input_manager_current_seat(); - struct sway_workspace *ws = seat_get_focused_workspace(seat); - // Check if it matches a currently visible scratchpad window and hide it. - if (con->pending.workspace && ws == con->pending.workspace) { - root_scratchpad_hide(con); - return; - } - - root_scratchpad_show(con); - ipc_event_window(con, "move"); -} - -struct cmd_results *cmd_scratchpad(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "scratchpad", EXPECTED_EQUAL_TO, 1))) { - return error; - } - if (strcmp(argv[0], "show") != 0) { - return cmd_results_new(CMD_INVALID, "Expected 'scratchpad show'"); - } - if (!root->outputs->length) { - return cmd_results_new(CMD_INVALID, - "Can't run this command while there's no outputs connected."); - } - if (!root->scratchpad->length) { - return cmd_results_new(CMD_INVALID, "Scratchpad is empty"); - } - - if (config->handler_context.node_overridden) { - struct sway_container *con = config->handler_context.container; - - // If the container is in a floating split container, - // operate on the split container instead of the child. - if (con && container_is_floating_or_child(con)) { - while (con->pending.parent) { - con = con->pending.parent; - } - } - - // If using criteria, this command is executed for every container which - // matches the criteria. If this container isn't in the scratchpad, - // we'll just silently return a success. The same is true if the - // overridden node is not a container. - if (!con || !con->scratchpad) { - return cmd_results_new(CMD_SUCCESS, NULL); - } - scratchpad_toggle_container(con); - } else { - scratchpad_toggle_auto(); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/scratchpad_minimize.c b/sway/commands/scratchpad_minimize.c deleted file mode 100644 index 1245e1d5f..000000000 --- a/sway/commands/scratchpad_minimize.c +++ /dev/null @@ -1,18 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "log.h" -#include "stringop.h" -#include "util.h" - -struct cmd_results *cmd_scratchpad_minimize(int argc, char **argv) { - struct cmd_results *error = checkarg(argc, "scratchpad_minimize", EXPECTED_AT_LEAST, 1); - - if (error) { - return error; - } - - config->scratchpad_minimize = parse_boolean(argv[0], config->scratchpad_minimize); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/seat.c b/sway/commands/seat.c deleted file mode 100644 index 2d197b692..000000000 --- a/sway/commands/seat.c +++ /dev/null @@ -1,81 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "sway/input/input-manager.h" -#include "sway/input/seat.h" -#include "log.h" -#include "stringop.h" - -// must be in order for the bsearch -// these handlers perform actions on the seat -static const struct cmd_handler seat_action_handlers[] = { - { "cursor", seat_cmd_cursor }, -}; - -// must be in order for the bsearch -// these handlers alter the seat config -static const struct cmd_handler seat_handlers[] = { - { "attach", seat_cmd_attach }, - { "fallback", seat_cmd_fallback }, - { "hide_cursor", seat_cmd_hide_cursor }, - { "idle_inhibit", seat_cmd_idle_inhibit }, - { "idle_wake", seat_cmd_idle_wake }, - { "keyboard_grouping", seat_cmd_keyboard_grouping }, - { "pointer_constraint", seat_cmd_pointer_constraint }, - { "shortcuts_inhibitor", seat_cmd_shortcuts_inhibitor }, - { "xcursor_theme", seat_cmd_xcursor_theme }, -}; - -static struct cmd_results *action_handlers(int argc, char **argv) { - struct cmd_results *res = config_subcommand(argv, argc, - seat_action_handlers, sizeof(seat_action_handlers)); - free_seat_config(config->handler_context.seat_config); - config->handler_context.seat_config = NULL; - return res; -} - -static struct cmd_results *config_handlers(int argc, char **argv) { - struct cmd_results *res = config_subcommand(argv, argc, - seat_handlers, sizeof(seat_handlers)); - if (res && res->status != CMD_SUCCESS) { - free_seat_config(config->handler_context.seat_config); - } else { - struct seat_config *sc = - store_seat_config(config->handler_context.seat_config); - if (!config->reading) { - input_manager_apply_seat_config(sc); - } - } - config->handler_context.seat_config = NULL; - return res; -} - -struct cmd_results *cmd_seat(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "seat", EXPECTED_AT_LEAST, 2))) { - return error; - } - - if (!strcmp(argv[0], "-")) { - if (config->reading) { - return cmd_results_new(CMD_FAILURE, - "Current seat alias (-) cannot be used in the config"); - } - config->handler_context.seat_config = - new_seat_config(config->handler_context.seat->wlr_seat->name); - } else { - config->handler_context.seat_config = new_seat_config(argv[0]); - } - if (!config->handler_context.seat_config) { - return cmd_results_new(CMD_FAILURE, "Couldn't allocate config"); - } - - struct cmd_results *res = NULL; - if (find_handler(argv[1], seat_action_handlers, - sizeof(seat_action_handlers))) { - res = action_handlers(argc - 1, argv + 1); - } else { - res = config_handlers(argc - 1, argv + 1); - } - return res ? res : cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/seat/attach.c b/sway/commands/seat/attach.c deleted file mode 100644 index 00bfdab69..000000000 --- a/sway/commands/seat/attach.c +++ /dev/null @@ -1,28 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "stringop.h" - -struct cmd_results *seat_cmd_attach(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "attach", EXPECTED_AT_LEAST, 1))) { - return error; - } - if (!config->handler_context.seat_config) { - return cmd_results_new(CMD_FAILURE, "No seat defined"); - } - if (!config->active) { - return cmd_results_new(CMD_DEFER, NULL); - } - - struct seat_attachment_config *attachment = seat_attachment_config_new(); - if (!attachment) { - return cmd_results_new(CMD_FAILURE, - "Failed to allocate seat attachment config"); - } - attachment->identifier = strdup(argv[0]); - list_add(config->handler_context.seat_config->attachments, attachment); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/seat/cursor.c b/sway/commands/seat/cursor.c deleted file mode 100644 index 5a8a3bc8f..000000000 --- a/sway/commands/seat/cursor.c +++ /dev/null @@ -1,131 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include - -#include -#include -#include -#include "sway/commands.h" -#include "sway/input/cursor.h" - -static struct cmd_results *press_or_release(struct sway_cursor *cursor, - char *action, char *button_str); - -static const char expected_syntax[] = "Expected 'cursor ' or " - "'cursor ' or " - "'cursor '"; - -static struct cmd_results *handle_command(struct sway_cursor *cursor, - int argc, char **argv) { - if (strcasecmp(argv[0], "move") == 0) { - if (argc < 3) { - return cmd_results_new(CMD_INVALID, "%s", expected_syntax); - } - int delta_x = strtol(argv[1], NULL, 10); - int delta_y = strtol(argv[2], NULL, 10); - wlr_cursor_move(cursor->cursor, NULL, delta_x, delta_y); - cursor_rebase(cursor); - wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); - } else if (strcasecmp(argv[0], "set") == 0) { - if (argc < 3) { - return cmd_results_new(CMD_INVALID, "%s", expected_syntax); - } - // map absolute coords (0..1,0..1) to root container coords - float x = strtof(argv[1], NULL) / root->width; - float y = strtof(argv[2], NULL) / root->height; - wlr_cursor_warp_absolute(cursor->cursor, NULL, x, y); - cursor_rebase(cursor); - wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); - } else { - if (argc < 2) { - return cmd_results_new(CMD_INVALID, "%s", expected_syntax); - } - struct cmd_results *error = NULL; - if ((error = press_or_release(cursor, argv[0], argv[1]))) { - return error; - } - } - - cursor_handle_activity_from_idle_source(cursor, IDLE_SOURCE_POINTER); - return cmd_results_new(CMD_SUCCESS, NULL); -} - -struct cmd_results *seat_cmd_cursor(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "cursor", EXPECTED_AT_LEAST, 2))) { - return error; - } - struct seat_config *sc = config->handler_context.seat_config; - if (!sc) { - return cmd_results_new(CMD_FAILURE, "No seat defined"); - } - - if (config->reading || !config->active) { - return cmd_results_new(CMD_DEFER, NULL); - } - - if (strcmp(sc->name, "*") != 0) { - struct sway_seat *seat = input_manager_get_seat(sc->name, false); - if (!seat) { - return cmd_results_new(CMD_FAILURE, - "Seat %s does not exist", sc->name); - } - error = handle_command(seat->cursor, argc, argv); - } else { - struct sway_seat *seat = NULL; - wl_list_for_each(seat, &server.input->seats, link) { - error = handle_command(seat->cursor, argc, argv); - if (error && error->status != CMD_SUCCESS) { - break; - } - } - } - - return error ? error : cmd_results_new(CMD_SUCCESS, NULL); -} - -static struct cmd_results *press_or_release(struct sway_cursor *cursor, - char *action, char *button_str) { - enum wlr_button_state state; - uint32_t button; - if (strcasecmp(action, "press") == 0) { - state = WLR_BUTTON_PRESSED; - } else if (strcasecmp(action, "release") == 0) { - state = WLR_BUTTON_RELEASED; - } else { - return cmd_results_new(CMD_INVALID, "%s", expected_syntax); - } - - char *message = NULL; - button = get_mouse_button(button_str, &message); - if (message) { - struct cmd_results *error = - cmd_results_new(CMD_INVALID, "%s", message); - free(message); - return error; - } else if (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_DOWN - || button == SWAY_SCROLL_LEFT || button == SWAY_SCROLL_RIGHT) { - // Dispatch axis event - enum wlr_axis_orientation orientation = - (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_DOWN) - ? WLR_AXIS_ORIENTATION_VERTICAL - : WLR_AXIS_ORIENTATION_HORIZONTAL; - double delta = (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_LEFT) - ? -1 : 1; - struct wlr_pointer_axis_event event = { - .pointer = NULL, - .time_msec = 0, - .source = WLR_AXIS_SOURCE_WHEEL, - .orientation = orientation, - .delta = delta * 15, - .delta_discrete = delta - }; - dispatch_cursor_axis(cursor, &event); - wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); - return cmd_results_new(CMD_SUCCESS, NULL); - } else if (!button) { - return cmd_results_new(CMD_INVALID, "Unknown button %s", button_str); - } - dispatch_cursor_button(cursor, NULL, 0, button, state); - wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/seat/fallback.c b/sway/commands/seat/fallback.c deleted file mode 100644 index 0330c3537..000000000 --- a/sway/commands/seat/fallback.c +++ /dev/null @@ -1,18 +0,0 @@ -#include "sway/config.h" -#include "sway/commands.h" -#include "util.h" - -struct cmd_results *seat_cmd_fallback(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "fallback", EXPECTED_EQUAL_TO, 1))) { - return error; - } - if (!config->handler_context.seat_config) { - return cmd_results_new(CMD_FAILURE, "No seat defined"); - } - - config->handler_context.seat_config->fallback = - parse_boolean(argv[0], false); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/seat/hide_cursor.c b/sway/commands/seat/hide_cursor.c deleted file mode 100644 index e09b82d99..000000000 --- a/sway/commands/seat/hide_cursor.c +++ /dev/null @@ -1,50 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/input/seat.h" -#include "sway/input/cursor.h" -#include "sway/server.h" -#include "stringop.h" -#include "util.h" - -struct cmd_results *seat_cmd_hide_cursor(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "hide_cursor", EXPECTED_AT_LEAST, 1))) { - return error; - } - if ((error = checkarg(argc, "hide_cursor", EXPECTED_AT_MOST, 2))) { - return error; - } - struct seat_config *seat_config = config->handler_context.seat_config; - if (!seat_config) { - return cmd_results_new(CMD_FAILURE, "No seat defined"); - } - - if (argc == 1) { - char *end; - int timeout = strtol(argv[0], &end, 10); - if (*end) { - return cmd_results_new(CMD_INVALID, "Expected an integer timeout"); - } - if (timeout < 100 && timeout != 0) { - timeout = 100; - } - seat_config->hide_cursor_timeout = timeout; - } else { - if (strcmp(argv[0], "when-typing") != 0) { - return cmd_results_new(CMD_INVALID, - "Expected 'hide_cursor |when-typing [enable|disable]'"); - } - seat_config->hide_cursor_when_typing = parse_boolean(argv[1], true) ? - HIDE_WHEN_TYPING_ENABLE : HIDE_WHEN_TYPING_DISABLE; - - // Invalidate all the caches for this config - struct sway_seat *seat = NULL; - wl_list_for_each(seat, &server.input->seats, link) { - seat->cursor->hide_when_typing = HIDE_WHEN_TYPING_DEFAULT; - } - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/seat/idle.c b/sway/commands/seat/idle.c deleted file mode 100644 index 62b94db21..000000000 --- a/sway/commands/seat/idle.c +++ /dev/null @@ -1,79 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include "log.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/input/seat.h" - -static const struct { - const char *name; - uint32_t value; -} idle_source_strings[] = { - { "keyboard", IDLE_SOURCE_KEYBOARD }, - { "pointer", IDLE_SOURCE_POINTER }, - { "touch", IDLE_SOURCE_TOUCH }, - { "tablet_pad", IDLE_SOURCE_TABLET_PAD }, - { "tablet_tool", IDLE_SOURCE_TABLET_TOOL }, - { "switch", IDLE_SOURCE_SWITCH }, -}; - -static uint32_t parse_sources(int argc, char **argv) { - uint32_t sources = 0; - for (int i = 0; i < argc; ++i) { - uint32_t value = 0; - for (size_t j = 0; j < sizeof(idle_source_strings) - / sizeof(idle_source_strings[0]); ++j) { - if (strcasecmp(idle_source_strings[j].name, argv[i]) == 0) { - value = idle_source_strings[j].value; - break; - } - } - if (value == 0) { - return UINT32_MAX; - } - sources |= value; - } - return sources; -} - -struct cmd_results *seat_cmd_idle_inhibit(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "idle_inhibit", EXPECTED_AT_LEAST, 1))) { - return error; - } - if (!config->handler_context.seat_config) { - return cmd_results_new(CMD_FAILURE, "No seat defined"); - } - - uint32_t sources = parse_sources(argc, argv); - if (sources == UINT32_MAX) { - return cmd_results_new(CMD_FAILURE, "Invalid idle source"); - } - config->handler_context.seat_config->idle_inhibit_sources = sources; - return cmd_results_new(CMD_SUCCESS, NULL); -} - -struct cmd_results *seat_cmd_idle_wake(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "idle_wake", EXPECTED_AT_LEAST, 1))) { - return error; - } - if (!config->handler_context.seat_config) { - return cmd_results_new(CMD_FAILURE, "No seat defined"); - } - - uint32_t sources = parse_sources(argc, argv); - if (sources == UINT32_MAX) { - return cmd_results_new(CMD_FAILURE, "Invalid idle source"); - } - config->handler_context.seat_config->idle_wake_sources = sources; - sway_log(SWAY_INFO, "Warning: seat idle_wake is deprecated"); - if (config->reading) { - config_add_swaynag_warning("seat idle_wake is deprecated. " - "Only seat idle_inhibit is supported."); - } - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/seat/keyboard_grouping.c b/sway/commands/seat/keyboard_grouping.c deleted file mode 100644 index 5ad0f4081..000000000 --- a/sway/commands/seat/keyboard_grouping.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "stringop.h" - -struct cmd_results *seat_cmd_keyboard_grouping(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "keyboard_grouping", EXPECTED_EQUAL_TO, 1))) { - return error; - } - if (!config->handler_context.seat_config) { - return cmd_results_new(CMD_INVALID, "No seat defined"); - } - - struct seat_config *seat_config = config->handler_context.seat_config; - if (strcmp(argv[0], "none") == 0) { - seat_config->keyboard_grouping = KEYBOARD_GROUP_NONE; - } else if (strcmp(argv[0], "smart") == 0) { - seat_config->keyboard_grouping = KEYBOARD_GROUP_SMART; - } else { - return cmd_results_new(CMD_INVALID, - "Expected syntax `keyboard_grouping none|smart`"); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/seat/pointer_constraint.c b/sway/commands/seat/pointer_constraint.c deleted file mode 100644 index 3890ebde0..000000000 --- a/sway/commands/seat/pointer_constraint.c +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/input/cursor.h" -#include "sway/input/seat.h" - -enum operation { - OP_ENABLE, - OP_DISABLE, - OP_ESCAPE, -}; - -// pointer_constraint [enable|disable|escape] -struct cmd_results *seat_cmd_pointer_constraint(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "pointer_constraint", EXPECTED_EQUAL_TO, 1))) { - return error; - } - if (!config->handler_context.seat_config) { - return cmd_results_new(CMD_FAILURE, "No seat defined"); - } - - enum operation op; - if (strcmp(argv[0], "enable") == 0) { - op = OP_ENABLE; - } else if (strcmp(argv[0], "disable") == 0) { - op = OP_DISABLE; - } else if (strcmp(argv[0], "escape") == 0) { - op = OP_ESCAPE; - } else { - return cmd_results_new(CMD_FAILURE, "Expected enable|disable|escape"); - } - - if (op == OP_ESCAPE && config->reading) { - return cmd_results_new(CMD_FAILURE, "Can only escape at runtime."); - } - - struct seat_config *seat_config = config->handler_context.seat_config; - switch (op) { - case OP_ENABLE: - seat_config->allow_constrain = CONSTRAIN_ENABLE; - break; - case OP_DISABLE: - seat_config->allow_constrain = CONSTRAIN_DISABLE; - /* fallthrough */ - case OP_ESCAPE:; - bool wildcard = !strcmp(seat_config->name, "*"); - struct sway_seat *seat = NULL; - wl_list_for_each(seat, &server.input->seats, link) { - if (wildcard || !strcmp(seat->wlr_seat->name, seat_config->name)) { - sway_cursor_constrain(seat->cursor, NULL); - } - } - break; - } - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/seat/shortcuts_inhibitor.c b/sway/commands/seat/shortcuts_inhibitor.c deleted file mode 100644 index 7c7f99cf0..000000000 --- a/sway/commands/seat/shortcuts_inhibitor.c +++ /dev/null @@ -1,96 +0,0 @@ -#include "log.h" -#include "sway/commands.h" -#include "sway/input/seat.h" -#include "sway/input/input-manager.h" -#include "util.h" - -static struct cmd_results *handle_action(struct seat_config *sc, - struct sway_seat *seat, const char *action) { - struct sway_keyboard_shortcuts_inhibitor *sway_inhibitor = NULL; - if (strcmp(action, "disable") == 0) { - sc->shortcuts_inhibit = SHORTCUTS_INHIBIT_DISABLE; - - wl_list_for_each(sway_inhibitor, - &seat->keyboard_shortcuts_inhibitors, link) { - wlr_keyboard_shortcuts_inhibitor_v1_deactivate( - sway_inhibitor->inhibitor); - } - - sway_log(SWAY_DEBUG, "Deactivated all keyboard shortcuts inhibitors"); - } else { - sway_inhibitor = keyboard_shortcuts_inhibitor_get_for_focused_surface(seat); - if (!sway_inhibitor) { - return cmd_results_new(CMD_FAILURE, - "No inhibitor found for focused surface"); - } - - struct wlr_keyboard_shortcuts_inhibitor_v1 *inhibitor = - sway_inhibitor->inhibitor; - bool inhibit; - if (strcmp(action, "activate") == 0) { - inhibit = true; - } else if (strcmp(action, "deactivate") == 0) { - inhibit = false; - } else if (strcmp(action, "toggle") == 0) { - inhibit = !inhibitor->active; - } else { - return cmd_results_new(CMD_INVALID, "Expected enable|" - "disable|activate|deactivate|toggle"); - } - - if (inhibit) { - wlr_keyboard_shortcuts_inhibitor_v1_activate(inhibitor); - } else { - wlr_keyboard_shortcuts_inhibitor_v1_deactivate(inhibitor); - } - - sway_log(SWAY_DEBUG, "%sctivated keyboard shortcuts inhibitor", - inhibit ? "A" : "Dea"); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} - -// shortcuts_inhibitor [enable|disable|activate|deactivate|toggle] -struct cmd_results *seat_cmd_shortcuts_inhibitor(int argc, char **argv) { - struct cmd_results *error = - checkarg(argc, "shortcuts_inhibitor", EXPECTED_EQUAL_TO, 1); - if (error) { - return error; - } - - struct seat_config *sc = config->handler_context.seat_config; - if (!sc) { - return cmd_results_new(CMD_FAILURE, "No seat defined"); - } - - if (strcmp(argv[0], "enable") == 0) { - sc->shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; - // at runtime disable is an action that also deactivates all active - // inhibitors handled in handle_action() - } else if (strcmp(argv[0], "disable") == 0 && !config->active) { - sc->shortcuts_inhibit = SHORTCUTS_INHIBIT_DISABLE; - } else if (!config->active) { - return cmd_results_new(CMD_INVALID, "only enable and disable " - "can be used in the config"); - } else { - if (strcmp(sc->name, "*") != 0) { - struct sway_seat *seat = input_manager_get_seat(sc->name, false); - if (!seat) { - return cmd_results_new(CMD_FAILURE, - "Seat %s does not exist", sc->name); - } - error = handle_action(sc, seat, argv[0]); - } else { - struct sway_seat *seat = NULL; - wl_list_for_each(seat, &server.input->seats, link) { - error = handle_action(sc, seat, argv[0]); - if (error && error->status != CMD_SUCCESS) { - break; - } - } - } - } - - return error ? error : cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/seat/xcursor_theme.c b/sway/commands/seat/xcursor_theme.c deleted file mode 100644 index 202f35b9e..000000000 --- a/sway/commands/seat/xcursor_theme.c +++ /dev/null @@ -1,33 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include "sway/commands.h" -#include "sway/config.h" - -struct cmd_results *seat_cmd_xcursor_theme(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "xcursor_theme", EXPECTED_AT_LEAST, 1)) || - (error = checkarg(argc, "xcursor_theme", EXPECTED_AT_MOST, 2))) { - return error; - } - if (!config->handler_context.seat_config) { - return cmd_results_new(CMD_FAILURE, "No seat defined"); - } - - const char *theme_name = argv[0]; - unsigned size = 24; - - if (argc == 2) { - char *end; - size = strtoul(argv[1], &end, 10); - if (*end) { - return cmd_results_new( - CMD_INVALID, "Expected a positive integer size"); - } - } - - free(config->handler_context.seat_config->xcursor_theme.name); - config->handler_context.seat_config->xcursor_theme.name = strdup(theme_name); - config->handler_context.seat_config->xcursor_theme.size = size; - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/set.c b/sway/commands/set.c deleted file mode 100644 index c539e9fc7..000000000 --- a/sway/commands/set.c +++ /dev/null @@ -1,60 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "list.h" -#include "log.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); -} - -void free_sway_variable(struct sway_variable *var) { - if (!var) { - return; - } - free(var->name); - free(var->value); - free(var); -} - -struct cmd_results *cmd_set(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "set", EXPECTED_AT_LEAST, 2))) { - return error; - } - - if (argv[0][0] != '$') { - return cmd_results_new(CMD_INVALID, "variable '%s' must start with $", argv[0]); - } - - 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, "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); -} diff --git a/sway/commands/shadow_blur_radius.c b/sway/commands/shadow_blur_radius.c deleted file mode 100644 index 036341f86..000000000 --- a/sway/commands/shadow_blur_radius.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/tree/arrange.h" -#include "sway/tree/container.h" -#include "log.h" - -struct cmd_results *cmd_shadow_blur_radius(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "shadow_blur_radius", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - char *inv; - int value = strtol(argv[0], &inv, 10); - if (*inv != '\0' || value < 0 || value > 99) { - return cmd_results_new(CMD_FAILURE, "Invalid size specified"); - } - - config->shadow_blur_sigma = value; - - arrange_root(); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/shadow_color.c b/sway/commands/shadow_color.c deleted file mode 100644 index d7c8fefa4..000000000 --- a/sway/commands/shadow_color.c +++ /dev/null @@ -1,28 +0,0 @@ -#include "log.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/output.h" -#include "sway/tree/arrange.h" -#include "sway/tree/container.h" -#include "util.h" - -struct cmd_results *cmd_shadow_color(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "shadow_color", EXPECTED_AT_LEAST, 1))) { - return error; - } - - uint32_t color; - if (!parse_color(argv[0], &color)) { - return cmd_results_new(CMD_INVALID, "Invalid %s color %s", - "shadow_color", argv[0]); - } - if (memcmp(config->shadow_color, config->shadow_inactive_color, sizeof(config->shadow_color)) == 0) { - color_to_rgba(config->shadow_inactive_color, color); - } - color_to_rgba(config->shadow_color, color); - - arrange_root(); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/shadow_inactive_color.c b/sway/commands/shadow_inactive_color.c deleted file mode 100644 index 6ad207e50..000000000 --- a/sway/commands/shadow_inactive_color.c +++ /dev/null @@ -1,25 +0,0 @@ -#include "log.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/output.h" -#include "sway/tree/arrange.h" -#include "sway/tree/container.h" -#include "util.h" - -struct cmd_results *cmd_shadow_inactive_color(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "shadow_inactive_color", EXPECTED_AT_LEAST, 1))) { - return error; - } - - uint32_t color; - if (!parse_color(argv[0], &color)) { - return cmd_results_new(CMD_INVALID, "Invalid %s color %s", - "shadow_inactive_color", argv[0]); - } - color_to_rgba(config->shadow_inactive_color, color); - - arrange_root(); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/shadow_offset.c b/sway/commands/shadow_offset.c deleted file mode 100644 index a73b54c9d..000000000 --- a/sway/commands/shadow_offset.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include "log.h" -#include "sway/commands.h" -#include "sway/config.h" - -struct cmd_results *cmd_shadow_offset(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "shadow_offset", EXPECTED_AT_LEAST, 2))) { - return error; - } - - char *err; - float offset_x = strtof(argv[0], &err); - float offset_y = strtof(argv[1], &err); - if (*err || offset_x < -99.9f || offset_x > 99.9f) { - return cmd_results_new(CMD_INVALID, "x offset float invalid"); - } - if (*err || offset_y < -99.9f || offset_y > 99.9f) { - return cmd_results_new(CMD_INVALID, "y offset float invalid"); - } - - config->shadow_offset_x = offset_x; - config->shadow_offset_y = offset_y; - - return cmd_results_new(CMD_SUCCESS, NULL); -} - diff --git a/sway/commands/shadows.c b/sway/commands/shadows.c deleted file mode 100644 index a213de8f2..000000000 --- a/sway/commands/shadows.c +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/tree/arrange.h" -#include "sway/tree/view.h" -#include "sway/tree/container.h" -#include "util.h" - -struct cmd_results *cmd_shadows(int argc, char **argv) { - struct cmd_results *error = checkarg(argc, "shadows", EXPECTED_AT_LEAST, 1); - - if (error) { - return error; - } - - struct sway_container *con = config->handler_context.container; - - bool result = parse_boolean(argv[0], true); - if (con == NULL) { - config->shadow_enabled = result; - } else { - con->shadow_enabled = result; - container_damage_whole(con); - } - - arrange_root(); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/shadows_on_csd.c b/sway/commands/shadows_on_csd.c deleted file mode 100644 index 24f2bea4b..000000000 --- a/sway/commands/shadows_on_csd.c +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/tree/arrange.h" -#include "util.h" - -struct cmd_results *cmd_shadows_on_csd(int argc, char **argv) { - struct cmd_results *error = checkarg(argc, "shadows_on_csd", EXPECTED_AT_LEAST, 1); - - if (error) { - return error; - } - - config->shadows_on_csd_enabled = parse_boolean(argv[0], config->shadows_on_csd_enabled); - - arrange_root(); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/shortcuts_inhibitor.c b/sway/commands/shortcuts_inhibitor.c deleted file mode 100644 index ffa1a5c99..000000000 --- a/sway/commands/shortcuts_inhibitor.c +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include "log.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/input/seat.h" -#include "sway/tree/container.h" -#include "sway/tree/view.h" - -struct cmd_results *cmd_shortcuts_inhibitor(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "shortcuts_inhibitor", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - struct sway_container *con = config->handler_context.container; - if (!con || !con->view) { - return cmd_results_new(CMD_INVALID, - "Only views can have shortcuts inhibitors"); - } - - struct sway_view *view = con->view; - if (strcmp(argv[0], "enable") == 0) { - view->shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; - } else if (strcmp(argv[0], "disable") == 0) { - view->shortcuts_inhibit = SHORTCUTS_INHIBIT_DISABLE; - - struct sway_seat *seat = NULL; - wl_list_for_each(seat, &server.input->seats, link) { - struct sway_keyboard_shortcuts_inhibitor *sway_inhibitor = - keyboard_shortcuts_inhibitor_get_for_surface( - seat, view->surface); - if (!sway_inhibitor) { - continue; - } - - wlr_keyboard_shortcuts_inhibitor_v1_deactivate( - sway_inhibitor->inhibitor); - sway_log(SWAY_DEBUG, "Deactivated keyboard shortcuts " - "inhibitor for seat %s on view", - seat->wlr_seat->name); - - } - } else { - return cmd_results_new(CMD_INVALID, - "Expected `shortcuts_inhibitor enable|disable`"); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/show_marks.c b/sway/commands/show_marks.c deleted file mode 100644 index 0d373b80c..000000000 --- a/sway/commands/show_marks.c +++ /dev/null @@ -1,35 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/tree/root.h" -#include "sway/tree/view.h" -#include "sway/output.h" -#include "list.h" -#include "log.h" -#include "stringop.h" -#include "util.h" - -static void rebuild_marks_iterator(struct sway_container *con, void *data) { - container_update_marks_textures(con); -} - -struct cmd_results *cmd_show_marks(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "show_marks", EXPECTED_AT_LEAST, 1))) { - return error; - } - - config->show_marks = parse_boolean(argv[0], config->show_marks); - - if (config->show_marks) { - root_for_each_container(rebuild_marks_iterator, NULL); - } - - for (int i = 0; i < root->outputs->length; ++i) { - struct sway_output *output = root->outputs->items[i]; - output_damage_whole(output); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/smart_borders.c b/sway/commands/smart_borders.c deleted file mode 100644 index 738786799..000000000 --- a/sway/commands/smart_borders.c +++ /dev/null @@ -1,23 +0,0 @@ -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/tree/arrange.h" -#include "sway/tree/view.h" -#include "util.h" - -struct cmd_results *cmd_smart_borders(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "smart_borders", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - if (strcmp(argv[0], "no_gaps") == 0) { - config->hide_edge_borders_smart = ESMART_NO_GAPS; - } else { - config->hide_edge_borders_smart = parse_boolean(argv[0], true) ? - ESMART_ON : ESMART_OFF; - } - - arrange_root(); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/smart_corner_radius.c b/sway/commands/smart_corner_radius.c deleted file mode 100644 index 4104cb4ba..000000000 --- a/sway/commands/smart_corner_radius.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/tree/arrange.h" -#include "util.h" - -struct cmd_results *cmd_smart_corner_radius(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "smart_corner_radius", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - config->smart_corner_radius = parse_boolean(argv[0], true); - - arrange_root(); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/smart_gaps.c b/sway/commands/smart_gaps.c deleted file mode 100644 index a6d165dc3..000000000 --- a/sway/commands/smart_gaps.c +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/tree/arrange.h" -#include "sway/tree/view.h" -#include "sway/tree/container.h" -#include "log.h" -#include "stringop.h" -#include "util.h" - -struct cmd_results *cmd_smart_gaps(int argc, char **argv) { - struct cmd_results *error = checkarg(argc, "smart_gaps", EXPECTED_AT_LEAST, 1); - - if (error) { - return error; - } - - if (strcmp(argv[0], "inverse_outer") == 0) { - config->smart_gaps = SMART_GAPS_INVERSE_OUTER; - } else { - config->smart_gaps = parse_boolean(argv[0], config->smart_gaps) - ? SMART_GAPS_ON : SMART_GAPS_OFF; - } - - arrange_root(); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/split.c b/sway/commands/split.c deleted file mode 100644 index 500a497db..000000000 --- a/sway/commands/split.c +++ /dev/null @@ -1,115 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "sway/tree/arrange.h" -#include "sway/tree/container.h" -#include "sway/tree/view.h" -#include "sway/tree/workspace.h" -#include "sway/input/input-manager.h" -#include "sway/input/seat.h" -#include "log.h" - -static struct cmd_results *do_split(int layout) { - struct sway_container *con = config->handler_context.container; - struct sway_workspace *ws = config->handler_context.workspace; - if (con) { - if (container_is_scratchpad_hidden_or_child(con) && - con->pending.fullscreen_mode != FULLSCREEN_GLOBAL) { - return cmd_results_new(CMD_FAILURE, - "Cannot split a hidden scratchpad container"); - } - container_split(con, layout); - } else { - workspace_split(ws, layout); - } - - if (root->fullscreen_global) { - arrange_root(); - } else { - arrange_workspace(ws); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} - -static struct cmd_results *do_unsplit(void) { - struct sway_container *con = config->handler_context.container; - struct sway_workspace *ws = config->handler_context.workspace; - - if (con && con->pending.parent && con->pending.parent->pending.children->length == 1) { - container_flatten(con->pending.parent); - } else { - return cmd_results_new(CMD_FAILURE, "Can only flatten a child container with no siblings"); - } - - if (root->fullscreen_global) { - arrange_root(); - } else { - arrange_workspace(ws); - } - return cmd_results_new(CMD_SUCCESS, NULL); -} - -struct cmd_results *cmd_split(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "split", EXPECTED_EQUAL_TO, 1))) { - return error; - } - if (!root->outputs->length) { - return cmd_results_new(CMD_INVALID, - "Can't run this command while there's no outputs connected."); - } - if (strcasecmp(argv[0], "v") == 0 || strcasecmp(argv[0], "vertical") == 0) { - return do_split(L_VERT); - } else if (strcasecmp(argv[0], "h") == 0 || - strcasecmp(argv[0], "horizontal") == 0) { - return do_split(L_HORIZ); - } else if (strcasecmp(argv[0], "t") == 0 || - strcasecmp(argv[0], "toggle") == 0) { - struct sway_container *focused = config->handler_context.container; - - if (focused && container_parent_layout(focused) == L_VERT) { - return do_split(L_HORIZ); - } else { - return do_split(L_VERT); - } - } else if (strcasecmp(argv[0], "n") == 0 || - strcasecmp(argv[0], "none") == 0) { - return do_unsplit(); - } else { - return cmd_results_new(CMD_FAILURE, - "Invalid split command (expected either horizontal or vertical)."); - } - return cmd_results_new(CMD_SUCCESS, NULL); -} - -struct cmd_results *cmd_splitv(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "splitv", EXPECTED_EQUAL_TO, 0))) { - return error; - } - return do_split(L_VERT); -} - -struct cmd_results *cmd_splith(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "splith", EXPECTED_EQUAL_TO, 0))) { - return error; - } - return do_split(L_HORIZ); -} - -struct cmd_results *cmd_splitt(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "splitt", EXPECTED_EQUAL_TO, 0))) { - return error; - } - - struct sway_container *con = config->handler_context.container; - - if (con && container_parent_layout(con) == L_VERT) { - return do_split(L_HORIZ); - } else { - return do_split(L_VERT); - } -} diff --git a/sway/commands/sticky.c b/sway/commands/sticky.c deleted file mode 100644 index 9b09a0f9d..000000000 --- a/sway/commands/sticky.c +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "sway/input/seat.h" -#include "sway/ipc-server.h" -#include "sway/output.h" -#include "sway/tree/arrange.h" -#include "sway/tree/container.h" -#include "sway/tree/view.h" -#include "sway/tree/workspace.h" -#include "list.h" -#include "log.h" -#include "util.h" - -struct cmd_results *cmd_sticky(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "sticky", EXPECTED_EQUAL_TO, 1))) { - return error; - } - struct sway_container *container = config->handler_context.container; - - if (container == NULL) { - return cmd_results_new(CMD_FAILURE, "No current container"); - }; - - container->is_sticky = parse_boolean(argv[0], container->is_sticky); - - if (container_is_sticky_or_child(container) && - !container_is_scratchpad_hidden(container)) { - // move container to active workspace - struct sway_workspace *active_workspace = - output_get_active_workspace(container->pending.workspace->output); - if (!sway_assert(active_workspace, - "Expected output to have a workspace")) { - return cmd_results_new(CMD_FAILURE, - "Expected output to have a workspace"); - } - if (container->pending.workspace != active_workspace) { - struct sway_workspace *old_workspace = container->pending.workspace; - container_detach(container); - workspace_add_floating(active_workspace, container); - container_handle_fullscreen_reparent(container); - arrange_workspace(active_workspace); - workspace_consider_destroy(old_workspace); - } - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/swap.c b/sway/commands/swap.c deleted file mode 100644 index d44eb006c..000000000 --- a/sway/commands/swap.c +++ /dev/null @@ -1,108 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include "config.h" -#include "log.h" -#include "sway/commands.h" -#include "sway/output.h" -#include "sway/tree/arrange.h" -#include "sway/tree/container.h" -#include "sway/tree/root.h" -#include "sway/tree/view.h" -#include "sway/tree/workspace.h" -#include "stringop.h" - -static const char expected_syntax[] = - "Expected 'swap container with id|con_id|mark '"; - -static bool test_con_id(struct sway_container *container, void *data) { - size_t *con_id = data; - return container->node.id == *con_id; -} - -#if HAVE_XWAYLAND -static bool test_id(struct sway_container *container, void *data) { - xcb_window_t *wid = data; - return (container->view && container->view->type == SWAY_VIEW_XWAYLAND - && container->view->wlr_xwayland_surface->window_id == *wid); -} -#endif - -static bool test_mark(struct sway_container *container, void *mark) { - if (container->marks->length) { - return list_seq_find(container->marks, - (int (*)(const void *, const void *))strcmp, mark) != -1; - } - return false; -} - -struct cmd_results *cmd_swap(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "swap", EXPECTED_AT_LEAST, 4))) { - return error; - } - if (!root->outputs->length) { - return cmd_results_new(CMD_INVALID, - "Can't run this command while there's no outputs connected."); - } - - if (strcasecmp(argv[0], "container") || strcasecmp(argv[1], "with")) { - return cmd_results_new(CMD_INVALID, "%s", expected_syntax); - } - - struct sway_container *current = config->handler_context.container; - struct sway_container *other = NULL; - - char *value = join_args(argv + 3, argc - 3); - if (strcasecmp(argv[2], "id") == 0) { -#if HAVE_XWAYLAND - xcb_window_t id = strtol(value, NULL, 0); - other = root_find_container(test_id, &id); -#endif - } else if (strcasecmp(argv[2], "con_id") == 0) { - size_t con_id = atoi(value); - other = root_find_container(test_con_id, &con_id); - } else if (strcasecmp(argv[2], "mark") == 0) { - other = root_find_container(test_mark, value); - } else { - free(value); - return cmd_results_new(CMD_INVALID, "%s", expected_syntax); - } - - if (!other) { - error = cmd_results_new(CMD_FAILURE, - "Failed to find %s '%s'", argv[2], value); - } else if (!current) { - error = cmd_results_new(CMD_FAILURE, - "Can only swap with containers and views"); - } else if (current == other) { - error = cmd_results_new(CMD_FAILURE, - "Cannot swap a container with itself"); - } else if (container_has_ancestor(current, other) - || container_has_ancestor(other, current)) { - error = cmd_results_new(CMD_FAILURE, - "Cannot swap ancestor and descendant"); - } - - free(value); - - if (error) { - return error; - } - - container_swap(current, other); - - if (root->fullscreen_global) { - arrange_root(); - } else { - struct sway_node *current_parent = node_get_parent(¤t->node); - struct sway_node *other_parent = node_get_parent(&other->node); - if (current_parent) { - arrange_node(current_parent); - } - if (other_parent && current_parent != other_parent) { - arrange_node(other_parent); - } - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/swaybg_command.c b/sway/commands/swaybg_command.c deleted file mode 100644 index 92e9bdfd6..000000000 --- a/sway/commands/swaybg_command.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include "sway/commands.h" -#include "log.h" -#include "stringop.h" - -struct cmd_results *cmd_swaybg_command(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "swaybg_command", EXPECTED_AT_LEAST, 1))) { - return error; - } - - free(config->swaybg_command); - config->swaybg_command = NULL; - - char *new_command = join_args(argv, argc); - if (strcmp(new_command, "-") != 0) { - config->swaybg_command = new_command; - sway_log(SWAY_DEBUG, "Using custom swaybg command: %s", - config->swaybg_command); - } else { - free(new_command); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/swaynag_command.c b/sway/commands/swaynag_command.c deleted file mode 100644 index f851d2234..000000000 --- a/sway/commands/swaynag_command.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include "sway/commands.h" -#include "log.h" -#include "stringop.h" - -struct cmd_results *cmd_swaynag_command(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "swaynag_command", EXPECTED_AT_LEAST, 1))) { - return error; - } - - free(config->swaynag_command); - config->swaynag_command = NULL; - - char *new_command = join_args(argv, argc); - if (strcmp(new_command, "-") != 0) { - config->swaynag_command = new_command; - sway_log(SWAY_DEBUG, "Using custom swaynag command: %s", - config->swaynag_command); - } else { - free(new_command); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/tiling_drag.c b/sway/commands/tiling_drag.c deleted file mode 100644 index e95526e80..000000000 --- a/sway/commands/tiling_drag.c +++ /dev/null @@ -1,13 +0,0 @@ -#include "sway/commands.h" -#include "util.h" - -struct cmd_results *cmd_tiling_drag(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "tiling_drag", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - config->tiling_drag = parse_boolean(argv[0], config->tiling_drag); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/tiling_drag_threshold.c b/sway/commands/tiling_drag_threshold.c deleted file mode 100644 index f11911182..000000000 --- a/sway/commands/tiling_drag_threshold.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "log.h" - -struct cmd_results *cmd_tiling_drag_threshold(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "tiling_drag_threshold", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - char *inv; - int value = strtol(argv[0], &inv, 10); - if (*inv != '\0' || value < 0) { - return cmd_results_new(CMD_INVALID, "Invalid threshold specified"); - } - - config->tiling_drag_threshold = value; - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/title_align.c b/sway/commands/title_align.c deleted file mode 100644 index c30355deb..000000000 --- a/sway/commands/title_align.c +++ /dev/null @@ -1,30 +0,0 @@ -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/output.h" -#include "sway/tree/container.h" -#include "sway/tree/root.h" - -struct cmd_results *cmd_title_align(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "title_align", EXPECTED_AT_LEAST, 1))) { - return error; - } - - if (strcmp(argv[0], "left") == 0) { - config->title_align = ALIGN_LEFT; - } else if (strcmp(argv[0], "center") == 0) { - config->title_align = ALIGN_CENTER; - } else if (strcmp(argv[0], "right") == 0) { - config->title_align = ALIGN_RIGHT; - } else { - return cmd_results_new(CMD_INVALID, - "Expected 'title_align left|center|right'"); - } - - for (int i = 0; i < root->outputs->length; ++i) { - struct sway_output *output = root->outputs->items[i]; - output_damage_whole(output); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/title_format.c b/sway/commands/title_format.c deleted file mode 100644 index a2446b7e4..000000000 --- a/sway/commands/title_format.c +++ /dev/null @@ -1,27 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/tree/view.h" -#include "log.h" -#include "stringop.h" - -struct cmd_results *cmd_title_format(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "title_format", EXPECTED_AT_LEAST, 1))) { - return error; - } - struct sway_container *container = config->handler_context.container; - if (!container || !container->view) { - return cmd_results_new(CMD_INVALID, - "Only views can have a title_format"); - } - struct sway_view *view = container->view; - char *format = join_args(argv, argc); - if (view->title_format) { - free(view->title_format); - } - view->title_format = format; - view_update_title(view, true); - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/titlebar_border_thickness.c b/sway/commands/titlebar_border_thickness.c deleted file mode 100644 index 7c27c163a..000000000 --- a/sway/commands/titlebar_border_thickness.c +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/output.h" -#include "sway/tree/arrange.h" -#include "log.h" - -struct cmd_results *cmd_titlebar_border_thickness(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "titlebar_border_thickness", EXPECTED_EQUAL_TO, 1))) { - return error; - } - - char *inv; - int value = strtol(argv[0], &inv, 10); - if (*inv != '\0' || value < 0 || value > config->titlebar_v_padding) { - return cmd_results_new(CMD_FAILURE, "Invalid size specified"); - } - - config->titlebar_border_thickness = value; - - for (int i = 0; i < root->outputs->length; ++i) { - struct sway_output *output = root->outputs->items[i]; - struct sway_workspace *ws = output_get_active_workspace(output); - if (!sway_assert(ws, "Expected output to have a workspace")) { - return cmd_results_new(CMD_FAILURE, - "Expected output to have a workspace"); - } - arrange_workspace(ws); - output_damage_whole(output); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/titlebar_padding.c b/sway/commands/titlebar_padding.c deleted file mode 100644 index affb6b508..000000000 --- a/sway/commands/titlebar_padding.c +++ /dev/null @@ -1,61 +0,0 @@ -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/output.h" -#include "sway/swaynag.h" -#include "sway/tree/arrange.h" -#include "log.h" - -struct cmd_results *cmd_titlebar_padding(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "titlebar_padding", EXPECTED_AT_LEAST, 1))) { - return error; - } - - char *inv; - int h_value = strtol(argv[0], &inv, 10); - if (*inv != '\0' || h_value < 0 || h_value < config->titlebar_border_thickness) { - return cmd_results_new(CMD_FAILURE, "Invalid size specified"); - } - - int v_value; - if (argc == 1) { - v_value = h_value; - } else { - v_value = strtol(argv[1], &inv, 10); - if (*inv != '\0' || v_value < 0 || v_value < config->titlebar_border_thickness) { - return cmd_results_new(CMD_FAILURE, "Invalid size specified"); - } - } - - /* - titlebar padding depends on corner_radius to - ensure that titlebars are rendered nicely - */ - if (v_value > (config->corner_radius - config->font_height) / 2) { - config->titlebar_v_padding = v_value; - } else { - config_add_swaynag_warning( - "titlebar_v_padding (%d) is too small for the current corner radius (%d)", - v_value, config->corner_radius - ); - return cmd_results_new(CMD_FAILURE, NULL); - } - if (h_value > config->corner_radius) { - config->titlebar_h_padding = h_value; - } else { - config_add_swaynag_warning( - "titlebar_h_padding (%d) is too small for the current corner radius (%d)", - h_value, config->corner_radius - ); - return cmd_results_new(CMD_FAILURE, NULL); - } - - for (int i = 0; i < root->outputs->length; ++i) { - struct sway_output *output = root->outputs->items[i]; - arrange_workspace(output_get_active_workspace(output)); - output_damage_whole(output); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/titlebar_separator.c b/sway/commands/titlebar_separator.c deleted file mode 100644 index a5ec97f60..000000000 --- a/sway/commands/titlebar_separator.c +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "util.h" - -struct cmd_results *cmd_titlebar_separator(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "titlebar_separator", EXPECTED_EQUAL_TO, 1))) { - return error; - } else if(strcmp(argv[0], "disable") == 0) { - config->titlebar_separator = false; - } else if(strcmp(argv[0], "enable") == 0) { - config->titlebar_separator = true; - } else { - return cmd_results_new(CMD_FAILURE, - "Expected 'titlebar_separator enable|disable'"); - } - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/unmark.c b/sway/commands/unmark.c deleted file mode 100644 index 19274dfbf..000000000 --- a/sway/commands/unmark.c +++ /dev/null @@ -1,53 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/tree/root.h" -#include "sway/tree/view.h" -#include "list.h" -#include "log.h" -#include "stringop.h" - -static void remove_all_marks_iterator(struct sway_container *con, void *data) { - container_clear_marks(con); - container_update_marks_textures(con); -} - -// unmark Remove all marks from all views -// unmark foo Remove single mark from whichever view has it -// [criteria] unmark Remove all marks from matched view -// [criteria] unmark foo Remove single mark from matched view - -struct cmd_results *cmd_unmark(int argc, char **argv) { - // Determine the container - struct sway_container *con = NULL; - if (config->handler_context.node_overridden) { - con = config->handler_context.container; - } - - // Determine the mark - char *mark = NULL; - if (argc > 0) { - mark = join_args(argv, argc); - } - - if (con && mark) { - // Remove the mark from the given container - if (container_has_mark(con, mark)) { - container_find_and_unmark(mark); - } - } else if (con && !mark) { - // Clear all marks from the given container - container_clear_marks(con); - container_update_marks_textures(con); - } else if (!con && mark) { - // Remove mark from whichever container has it - container_find_and_unmark(mark); - } else { - // Remove all marks from all containers - root_for_each_container(remove_all_marks_iterator, NULL); - } - free(mark); - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/urgent.c b/sway/commands/urgent.c deleted file mode 100644 index 3a2b00ed5..000000000 --- a/sway/commands/urgent.c +++ /dev/null @@ -1,32 +0,0 @@ -#include "log.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/tree/arrange.h" -#include "sway/tree/container.h" -#include "sway/tree/view.h" -#include "util.h" - -struct cmd_results *cmd_urgent(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "urgent", EXPECTED_EQUAL_TO, 1))) { - return error; - } - struct sway_container *container = config->handler_context.container; - if (!container) { - return cmd_results_new(CMD_FAILURE, "No current container"); - } - if (!container->view) { - return cmd_results_new(CMD_INVALID, "Only views can be urgent"); - } - struct sway_view *view = container->view; - - if (strcmp(argv[0], "allow") == 0) { - view->allow_request_urgent = true; - } else if (strcmp(argv[0], "deny") == 0) { - view->allow_request_urgent = false; - } else { - view_set_urgent(view, parse_boolean(argv[0], view_is_urgent(view))); - } - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c deleted file mode 100644 index 03e488ba9..000000000 --- a/sway/commands/workspace.c +++ /dev/null @@ -1,241 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/input/seat.h" -#include "sway/tree/workspace.h" -#include "list.h" -#include "log.h" -#include "stringop.h" - -static struct workspace_config *workspace_config_find_or_create(char *ws_name) { - struct workspace_config *wsc = workspace_find_config(ws_name); - if (wsc) { - return wsc; - } - wsc = calloc(1, sizeof(struct workspace_config)); - if (!wsc) { - return NULL; - } - wsc->workspace = strdup(ws_name); - wsc->outputs = create_list(); - wsc->gaps_inner = INT_MIN; - wsc->gaps_outer.top = INT_MIN; - wsc->gaps_outer.right = INT_MIN; - wsc->gaps_outer.bottom = INT_MIN; - wsc->gaps_outer.left = INT_MIN; - list_add(config->workspace_configs, wsc); - return wsc; -} - -void free_workspace_config(struct workspace_config *wsc) { - free(wsc->workspace); - list_free_items_and_destroy(wsc->outputs); - free(wsc); -} - -static void prevent_invalid_outer_gaps(struct workspace_config *wsc) { - if (wsc->gaps_outer.top != INT_MIN && - wsc->gaps_outer.top < -wsc->gaps_inner) { - wsc->gaps_outer.top = -wsc->gaps_inner; - } - if (wsc->gaps_outer.right != INT_MIN && - wsc->gaps_outer.right < -wsc->gaps_inner) { - wsc->gaps_outer.right = -wsc->gaps_inner; - } - if (wsc->gaps_outer.bottom != INT_MIN && - wsc->gaps_outer.bottom < -wsc->gaps_inner) { - wsc->gaps_outer.bottom = -wsc->gaps_inner; - } - if (wsc->gaps_outer.left != INT_MIN && - wsc->gaps_outer.left < -wsc->gaps_inner) { - wsc->gaps_outer.left = -wsc->gaps_inner; - } -} - -static struct cmd_results *cmd_workspace_gaps(int argc, char **argv, - int gaps_location) { - const char expected[] = "Expected 'workspace gaps " - "inner|outer|horizontal|vertical|top|right|bottom|left '"; - if (gaps_location == 0) { - return cmd_results_new(CMD_INVALID, "%s", expected); - } - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "workspace", EXPECTED_EQUAL_TO, - gaps_location + 3))) { - return error; - } - char *ws_name = join_args(argv, argc - 3); - struct workspace_config *wsc = workspace_config_find_or_create(ws_name); - free(ws_name); - if (!wsc) { - return cmd_results_new(CMD_FAILURE, - "Unable to allocate workspace output"); - } - - char *end; - int amount = strtol(argv[gaps_location + 2], &end, 10); - if (strlen(end)) { - return cmd_results_new(CMD_FAILURE, "%s", expected); - } - - bool valid = false; - char *type = argv[gaps_location + 1]; - if (!strcasecmp(type, "inner")) { - valid = true; - wsc->gaps_inner = (amount >= 0) ? amount : 0; - } else { - if (!strcasecmp(type, "outer") || !strcasecmp(type, "vertical") - || !strcasecmp(type, "top")) { - valid = true; - wsc->gaps_outer.top = amount; - } - if (!strcasecmp(type, "outer") || !strcasecmp(type, "horizontal") - || !strcasecmp(type, "right")) { - valid = true; - wsc->gaps_outer.right = amount; - } - if (!strcasecmp(type, "outer") || !strcasecmp(type, "vertical") - || !strcasecmp(type, "bottom")) { - valid = true; - wsc->gaps_outer.bottom = amount; - } - if (!strcasecmp(type, "outer") || !strcasecmp(type, "horizontal") - || !strcasecmp(type, "left")) { - valid = true; - wsc->gaps_outer.left = amount; - } - } - if (!valid) { - return cmd_results_new(CMD_INVALID, "%s", expected); - } - - // Prevent invalid gaps configurations. - if (wsc->gaps_inner != INT_MIN && wsc->gaps_inner < 0) { - wsc->gaps_inner = 0; - } - prevent_invalid_outer_gaps(wsc); - - return error; -} - -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; - int gaps_location = -1; - - for (int i = 0; i < argc; ++i) { - if (strcasecmp(argv[i], "output") == 0) { - output_location = i; - break; - } - } - for (int i = 0; i < argc; ++i) { - if (strcasecmp(argv[i], "gaps") == 0) { - gaps_location = i; - break; - } - } - if (output_location == 0) { - return cmd_results_new(CMD_INVALID, - "Expected 'workspace output '"); - } else if (output_location > 0) { - if ((error = checkarg(argc, "workspace", EXPECTED_AT_LEAST, - output_location + 2))) { - return error; - } - char *ws_name = join_args(argv, output_location); - struct workspace_config *wsc = workspace_config_find_or_create(ws_name); - free(ws_name); - if (!wsc) { - return cmd_results_new(CMD_FAILURE, - "Unable to allocate workspace output"); - } - for (int i = output_location + 1; i < argc; ++i) { - list_add(wsc->outputs, strdup(argv[i])); - } - } else if (gaps_location >= 0) { - if ((error = cmd_workspace_gaps(argc, argv, gaps_location))) { - return error; - } - } else { - if (config->reading || !config->active) { - return cmd_results_new(CMD_DEFER, NULL); - } else if (!root->outputs->length) { - return cmd_results_new(CMD_INVALID, - "Can't run this command while there's no outputs connected."); - } - - if (root->fullscreen_global) { - return cmd_results_new(CMD_FAILURE, - "Can't switch workspaces while fullscreen global"); - } - - bool auto_back_and_forth = true; - while (strcasecmp(argv[0], "--no-auto-back-and-forth") == 0) { - auto_back_and_forth = false; - if ((error = checkarg(--argc, "workspace", EXPECTED_AT_LEAST, 1))) { - return error; - } - ++argv; - } - - struct sway_seat *seat = config->handler_context.seat; - - struct sway_workspace *ws = NULL; - if (strcasecmp(argv[0], "number") == 0) { - if (argc < 2) { - return cmd_results_new(CMD_INVALID, - "Expected workspace number"); - } - if (!isdigit(argv[1][0])) { - return cmd_results_new(CMD_INVALID, - "Invalid workspace number '%s'", argv[1]); - } - if (!(ws = workspace_by_number(argv[1]))) { - char *name = join_args(argv + 1, argc - 1); - ws = workspace_create(NULL, name); - free(name); - } - if (ws && auto_back_and_forth) { - ws = workspace_auto_back_and_forth(ws); - } - } else if (strcasecmp(argv[0], "next") == 0 || - strcasecmp(argv[0], "prev") == 0 || - strcasecmp(argv[0], "next_on_output") == 0 || - strcasecmp(argv[0], "prev_on_output") == 0 || - strcasecmp(argv[0], "current") == 0) { - ws = workspace_by_name(argv[0]); - } else if (strcasecmp(argv[0], "back_and_forth") == 0) { - if (!seat->prev_workspace_name) { - return cmd_results_new(CMD_INVALID, - "There is no previous workspace"); - } - if (!(ws = workspace_by_name(argv[0]))) { - ws = workspace_create(NULL, seat->prev_workspace_name); - } - } else { - char *name = join_args(argv, argc); - if (!(ws = workspace_by_name(name))) { - ws = workspace_create(NULL, name); - } - free(name); - if (ws && auto_back_and_forth) { - ws = workspace_auto_back_and_forth(ws); - } - } - if (!ws) { - return cmd_results_new(CMD_FAILURE, "No workspace to switch to"); - } - workspace_switch(ws); - seat_consider_warp_to_focus(seat); - } - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/workspace_layout.c b/sway/commands/workspace_layout.c deleted file mode 100644 index 4fed05abf..000000000 --- a/sway/commands/workspace_layout.c +++ /dev/null @@ -1,21 +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_EQUAL_TO, 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 { - return cmd_results_new(CMD_INVALID, - "Expected 'workspace_layout '"); - } - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/ws_auto_back_and_forth.c b/sway/commands/ws_auto_back_and_forth.c deleted file mode 100644 index e4411c8ed..000000000 --- a/sway/commands/ws_auto_back_and_forth.c +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include -#include "sway/commands.h" -#include "util.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; - } - config->auto_back_and_forth = - parse_boolean(argv[0], config->auto_back_and_forth); - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/commands/xwayland.c b/sway/commands/xwayland.c deleted file mode 100644 index 6ca269231..000000000 --- a/sway/commands/xwayland.c +++ /dev/null @@ -1,34 +0,0 @@ -#include "sway/config.h" -#include "log.h" -#include "sway/commands.h" -#include "sway/server.h" -#include "util.h" - -struct cmd_results *cmd_xwayland(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "xwayland", EXPECTED_EQUAL_TO, 1))) { - return error; - } - -#ifdef HAVE_XWAYLAND - enum xwayland_mode xwayland; - if (strcmp(argv[0], "force") == 0) { - xwayland = XWAYLAND_MODE_IMMEDIATE; - } else if (parse_boolean(argv[0], true)) { - xwayland = XWAYLAND_MODE_LAZY; - } else { - xwayland = XWAYLAND_MODE_DISABLED; - } - - if (config->reloading && config->xwayland != xwayland) { - return cmd_results_new(CMD_FAILURE, - "xwayland can only be enabled/disabled at launch"); - } - config->xwayland = xwayland; -#else - sway_log(SWAY_INFO, "Ignoring `xwayland` command, " - "sway hasn't been built with Xwayland support"); -#endif - - return cmd_results_new(CMD_SUCCESS, NULL); -} diff --git a/sway/config.c b/sway/config.c deleted file mode 100644 index 616965c1e..000000000 --- a/sway/config.c +++ /dev/null @@ -1,1122 +0,0 @@ -#define _XOPEN_SOURCE 700 // for realpath -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sway/input/input-manager.h" -#include "sway/input/seat.h" -#include "sway/input/switch.h" -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/criteria.h" -#include "sway/layer_criteria.h" -#include "sway/desktop/transaction.h" -#include "sway/swaynag.h" -#include "sway/tree/arrange.h" -#include "sway/tree/root.h" -#include "sway/tree/workspace.h" -#include "cairo_util.h" -#include "pango.h" -#include "stringop.h" -#include "list.h" -#include "log.h" -#include "util.h" - -struct sway_config *config = NULL; - -static struct xkb_state *keysym_translation_state_create( - struct xkb_rule_names rules) { - struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_SECURE_GETENV); - struct xkb_keymap *xkb_keymap = xkb_keymap_new_from_names( - context, - &rules, - XKB_KEYMAP_COMPILE_NO_FLAGS); - - xkb_context_unref(context); - return xkb_state_new(xkb_keymap); -} - -static void keysym_translation_state_destroy( - struct xkb_state *state) { - xkb_keymap_unref(xkb_state_get_keymap(state)); - xkb_state_unref(state); -} - -static void free_mode(struct sway_mode *mode) { - if (!mode) { - return; - } - free(mode->name); - if (mode->keysym_bindings) { - for (int i = 0; i < mode->keysym_bindings->length; i++) { - free_sway_binding(mode->keysym_bindings->items[i]); - } - list_free(mode->keysym_bindings); - } - if (mode->keycode_bindings) { - for (int i = 0; i < mode->keycode_bindings->length; i++) { - free_sway_binding(mode->keycode_bindings->items[i]); - } - list_free(mode->keycode_bindings); - } - if (mode->mouse_bindings) { - for (int i = 0; i < mode->mouse_bindings->length; i++) { - free_sway_binding(mode->mouse_bindings->items[i]); - } - list_free(mode->mouse_bindings); - } - if (mode->switch_bindings) { - for (int i = 0; i < mode->switch_bindings->length; i++) { - free_switch_binding(mode->switch_bindings->items[i]); - } - list_free(mode->switch_bindings); - } - if (mode->gesture_bindings) { - for (int i = 0; i < mode->gesture_bindings->length; i++) { - free_gesture_binding(mode->gesture_bindings->items[i]); - } - list_free(mode->gesture_bindings); - } - free(mode); -} - -void free_config(struct sway_config *config) { - if (!config) { - return; - } - - memset(&config->handler_context, 0, sizeof(config->handler_context)); - - // TODO: handle all currently unhandled lists as we add implementations - if (config->symbols) { - for (int i = 0; i < config->symbols->length; ++i) { - free_sway_variable(config->symbols->items[i]); - } - list_free(config->symbols); - } - if (config->modes) { - for (int i = 0; i < config->modes->length; ++i) { - free_mode(config->modes->items[i]); - } - list_free(config->modes); - } - if (config->bars) { - for (int i = 0; i < config->bars->length; ++i) { - free_bar_config(config->bars->items[i]); - } - list_free(config->bars); - } - list_free(config->cmd_queue); - if (config->workspace_configs) { - for (int i = 0; i < config->workspace_configs->length; i++) { - free_workspace_config(config->workspace_configs->items[i]); - } - list_free(config->workspace_configs); - } - if (config->output_configs) { - for (int i = 0; i < config->output_configs->length; i++) { - free_output_config(config->output_configs->items[i]); - } - list_free(config->output_configs); - } - if (config->swaybg_client != NULL) { - wl_client_destroy(config->swaybg_client); - } - if (config->input_configs) { - for (int i = 0; i < config->input_configs->length; i++) { - free_input_config(config->input_configs->items[i]); - } - list_free(config->input_configs); - } - if (config->input_type_configs) { - for (int i = 0; i < config->input_type_configs->length; i++) { - free_input_config(config->input_type_configs->items[i]); - } - list_free(config->input_type_configs); - } - if (config->seat_configs) { - for (int i = 0; i < config->seat_configs->length; i++) { - free_seat_config(config->seat_configs->items[i]); - } - list_free(config->seat_configs); - } - if (config->criteria) { - for (int i = 0; i < config->criteria->length; ++i) { - criteria_destroy(config->criteria->items[i]); - } - list_free(config->criteria); - } - if (config->layer_criteria) { - for (int i = 0; i < config->layer_criteria->length; ++i) { - layer_criteria_destroy(config->layer_criteria->items[i]); - } - list_free(config->layer_criteria); - } - list_free(config->no_focus); - list_free(config->active_bar_modifiers); - list_free_items_and_destroy(config->config_chain); - 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->font); - free(config->swaybg_command); - free(config->swaynag_command); - free((char *)config->current_config_path); - free((char *)config->current_config); - keysym_translation_state_destroy(config->keysym_translation_state); - free(config); -} - -static void destroy_removed_seats(struct sway_config *old_config, - struct sway_config *new_config) { - struct seat_config *seat_config; - struct sway_seat *seat; - int i; - for (i = 0; i < old_config->seat_configs->length; i++) { - seat_config = old_config->seat_configs->items[i]; - // Skip the wildcard seat config, it won't have a matching real seat. - if (strcmp(seat_config->name, "*") == 0) { - continue; - } - - /* Also destroy seats that aren't present in new config */ - if (new_config && list_seq_find(new_config->seat_configs, - seat_name_cmp, seat_config->name) < 0) { - seat = input_manager_get_seat(seat_config->name, false); - if (seat) { - seat_destroy(seat); - } - } - } -} - -static void config_defaults(struct sway_config *config) { - if (!(config->swaynag_command = strdup("swaynag"))) goto cleanup; - config->swaynag_config_errors = (struct swaynag_instance){0}; - config->swaynag_config_errors.args = "--type error " - "--message 'There are errors in your config file' " - "--detailed-message " - "--button-no-terminal 'Exit sway' 'swaymsg exit' " - "--button-no-terminal 'Reload sway' 'swaymsg reload'"; - config->swaynag_config_errors.detailed = true; - - if (!(config->symbols = create_list())) goto cleanup; - if (!(config->modes = create_list())) goto cleanup; - if (!(config->bars = create_list())) goto cleanup; - if (!(config->workspace_configs = create_list())) goto cleanup; - if (!(config->criteria = create_list())) goto cleanup; - if (!(config->no_focus = create_list())) goto cleanup; - if (!(config->seat_configs = create_list())) goto cleanup; - if (!(config->output_configs = create_list())) goto cleanup; - - if (!(config->input_type_configs = create_list())) goto cleanup; - if (!(config->input_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->keysym_bindings = create_list())) goto cleanup; - if (!(config->current_mode->keycode_bindings = create_list())) goto cleanup; - if (!(config->current_mode->mouse_bindings = create_list())) goto cleanup; - if (!(config->current_mode->switch_bindings = create_list())) goto cleanup; - if (!(config->current_mode->gesture_bindings = create_list())) goto cleanup; - list_add(config->modes, config->current_mode); - - config->floating_mod = 0; - config->floating_mod_inverse = false; - config->dragging_key = BTN_LEFT; - config->resizing_key = BTN_RIGHT; - - 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_description = pango_font_description_from_string(config->font); - config->urgent_timeout = 500; - config->focus_on_window_activation = FOWA_URGENT; - config->popup_during_fullscreen = POPUP_SMART; - config->xwayland = XWAYLAND_MODE_LAZY; - - config->titlebar_border_thickness = 1; - config->titlebar_h_padding = 5; - config->titlebar_v_padding = 4; - - // 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 = FOLLOWS_YES; - config->mouse_warping = WARP_OUTPUT; - config->focus_wrapping = WRAP_YES; - config->validating = false; - config->reloading = false; - config->active = false; - config->failed = false; - config->auto_back_and_forth = false; - config->reading = false; - config->show_marks = true; - config->title_align = ALIGN_LEFT; - config->tiling_drag = true; - config->tiling_drag_threshold = 9; - config->primary_selection = true; - - config->smart_gaps = SMART_GAPS_OFF; - config->gaps_inner = 0; - config->gaps_outer.top = 0; - config->gaps_outer.right = 0; - config->gaps_outer.bottom = 0; - config->gaps_outer.left = 0; - - if (!(config->active_bar_modifiers = create_list())) goto cleanup; - - if (!(config->swaybg_command = strdup("swaybg"))) goto cleanup; - - if (!(config->config_chain = create_list())) goto cleanup; - config->current_config_path = NULL; - 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; - config->hide_edge_borders_smart = ESMART_OFF; - config->hide_lone_tab = false; - - config->has_focused_tab_title = false; - - // border colors - color_to_rgba(config->border_colors.focused.border, 0x4C7899FF); - color_to_rgba(config->border_colors.focused.background, 0x285577FF); - color_to_rgba(config->border_colors.focused.text, 0xFFFFFFFF); - color_to_rgba(config->border_colors.focused.indicator, 0x2E9EF4FF); - color_to_rgba(config->border_colors.focused.child_border, 0x285577FF); - - color_to_rgba(config->border_colors.focused_inactive.border, 0x333333FF); - color_to_rgba(config->border_colors.focused_inactive.background, 0x5F676AFF); - color_to_rgba(config->border_colors.focused_inactive.text, 0xFFFFFFFF); - color_to_rgba(config->border_colors.focused_inactive.indicator, 0x484E50FF); - color_to_rgba(config->border_colors.focused_inactive.child_border, 0x5F676AFF); - - color_to_rgba(config->border_colors.unfocused.border, 0x333333FF); - color_to_rgba(config->border_colors.unfocused.background, 0x222222FF); - color_to_rgba(config->border_colors.unfocused.text, 0x888888FF); - color_to_rgba(config->border_colors.unfocused.indicator, 0x292D2EFF); - color_to_rgba(config->border_colors.unfocused.child_border, 0x222222FF); - - color_to_rgba(config->border_colors.urgent.border, 0x2F343AFF); - color_to_rgba(config->border_colors.urgent.background, 0x900000FF); - color_to_rgba(config->border_colors.urgent.text, 0xFFFFFFFF); - color_to_rgba(config->border_colors.urgent.indicator, 0x900000FF); - color_to_rgba(config->border_colors.urgent.child_border, 0x900000FF); - - color_to_rgba(config->border_colors.placeholder.border, 0x000000FF); - color_to_rgba(config->border_colors.placeholder.background, 0x0C0C0CFF); - color_to_rgba(config->border_colors.placeholder.text, 0xFFFFFFFF); - color_to_rgba(config->border_colors.placeholder.indicator, 0x000000FF); - color_to_rgba(config->border_colors.placeholder.child_border, 0x0C0C0CFF); - - color_to_rgba(config->border_colors.background, 0xFFFFFFFF); - - // SwayFX defaults - config->corner_radius = 0; - config->smart_corner_radius = true; - - config->default_dim_inactive = 0.0f; - color_to_rgba(config->dim_inactive_colors.unfocused, 0x000000FF); - color_to_rgba(config->dim_inactive_colors.urgent, 0x900000FF); - - config->shadow_enabled = false; - config->shadows_on_csd_enabled = false; - config->shadow_blur_sigma = 20.0f; - config->shadow_offset_x = 0.0f; - config->shadow_offset_y = 0.0f; - color_to_rgba(config->shadow_color, 0x0000007F); - color_to_rgba(config->shadow_inactive_color, 0x0000007F); - - config->blur_enabled = false; - config->blur_xray = false; - config->blur_params.num_passes = 2; - config->blur_params.radius = 5; - config->blur_params.noise = 0.02; - config->blur_params.brightness = 0.9; - config->blur_params.contrast = 0.9; - config->blur_params.saturation = 1.1; - - config->titlebar_separator = true; - config->scratchpad_minimize = false; - - if (!(config->layer_criteria = create_list())) goto cleanup; - - // The keysym to keycode translation - struct xkb_rule_names rules = {0}; - config->keysym_translation_state = - keysym_translation_state_create(rules); - - return; -cleanup: - sway_abort("Unable to allocate config structures"); -} - -static bool file_exists(const char *path) { - return path && access(path, R_OK) != -1; -} - -static char *config_path(const char *prefix, const char *config_folder) { - if (!prefix || !prefix[0] || !config_folder || !config_folder[0]) { - return NULL; - } - - const char *filename = "config"; - - size_t size = 3 + strlen(prefix) + strlen(config_folder) + strlen(filename); - char *path = calloc(size, sizeof(char)); - snprintf(path, size, "%s/%s/%s", prefix, config_folder, filename); - return path; -} - -static char *get_config_path(void) { - char *path = NULL; - const char *home = getenv("HOME"); - char *config_home_fallback = NULL; - - const char *config_home = getenv("XDG_CONFIG_HOME"); - if ((config_home == NULL || config_home[0] == '\0') && home != NULL) { - size_t size_fallback = 1 + strlen(home) + strlen("/.config"); - config_home_fallback = calloc(size_fallback, sizeof(char)); - if (config_home_fallback != NULL) - snprintf(config_home_fallback, size_fallback, "%s/.config", home); - config_home = config_home_fallback; - } - - struct config_path { - const char *prefix; - const char *config_folder; - }; - - struct config_path config_paths[] = { - { .prefix = home, .config_folder = ".sway"}, - { .prefix = config_home, .config_folder = "sway"}, - { .prefix = home, .config_folder = ".i3"}, - { .prefix = config_home, .config_folder = "i3"}, - { .prefix = SYSCONFDIR, .config_folder = "sway"}, - { .prefix = SYSCONFDIR, .config_folder = "i3"} - }; - - size_t num_config_paths = sizeof(config_paths)/sizeof(config_paths[0]); - for (size_t i = 0; i < num_config_paths; i++) { - path = config_path(config_paths[i].prefix, config_paths[i].config_folder); - if (!path) { - continue; - } - if (file_exists(path)) { - break; - } - free(path); - path = NULL; - } - - free(config_home_fallback); - return path; -} - -static bool load_config(const char *path, struct sway_config *config, - struct swaynag_instance *swaynag) { - if (path == NULL) { - sway_log(SWAY_ERROR, "Unable to find a config file!"); - return false; - } - - sway_log(SWAY_INFO, "Loading config from %s", path); - - struct stat sb; - if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { - sway_log(SWAY_ERROR, "%s is a directory not a config file", path); - return false; - } - - FILE *f = fopen(path, "r"); - if (!f) { - sway_log(SWAY_ERROR, "Unable to open %s for reading", path); - return false; - } - - bool config_load_success = read_config(f, config, swaynag); - fclose(f); - - if (!config_load_success) { - sway_log(SWAY_ERROR, "Error(s) loading config!"); - } - - return config->active || !config->validating || config_load_success; -} - -bool load_main_config(const char *file, bool is_active, bool validating) { - char *path; - if (file != NULL) { - path = strdup(file); - } else { - path = get_config_path(); - } - if (path == NULL) { - sway_log(SWAY_ERROR, "Cannot find config file"); - return false; - } - - char *real_path = realpath(path, NULL); - if (real_path == NULL) { - sway_log(SWAY_ERROR, "%s not found", path); - free(path); - return false; - } - - struct sway_config *old_config = config; - config = calloc(1, sizeof(struct sway_config)); - if (!config) { - sway_abort("Unable to allocate config"); - } - - config_defaults(config); - config->validating = validating; - if (is_active) { - sway_log(SWAY_DEBUG, "Performing configuration file %s", - validating ? "validation" : "reload"); - config->reloading = true; - config->active = true; - - // xwayland can only be enabled/disabled at launch - sway_log(SWAY_DEBUG, "xwayland will remain %s", - old_config->xwayland ? "enabled" : "disabled"); - config->xwayland = old_config->xwayland; - - // primary_selection can only be enabled/disabled at launch - sway_log(SWAY_DEBUG, "primary_selection will remain %s", - old_config->primary_selection ? "enabled" : "disabled"); - config->primary_selection = old_config->primary_selection; - - if (!config->validating) { - if (old_config->swaybg_client != NULL) { - wl_client_destroy(old_config->swaybg_client); - } - - if (old_config->swaynag_config_errors.client != NULL) { - wl_client_destroy(old_config->swaynag_config_errors.client); - } - - input_manager_reset_all_inputs(); - } - } - - config->user_config_path = file ? true : false; - config->current_config_path = path; - list_add(config->config_chain, real_path); - - config->reading = true; - - // Read security configs - // TODO: Security - bool success = true; - /* - DIR *dir = opendir(SYSCONFDIR "/sway/security.d"); - if (!dir) { - sway_log(SWAY_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(SWAY_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); - } - } - - list_free_items_and_destroy(secconfigs); - } - */ - - success = success && load_config(path, config, - &config->swaynag_config_errors); - - if (validating) { - free_config(config); - config = old_config; - return success; - } - - // Only really necessary if not explicitly `font` is set in the config. - config_update_font_height(); - - if (is_active && !validating) { - input_manager_verify_fallback_seat(); - - for (int i = 0; i < config->input_configs->length; i++) { - input_manager_apply_input_config(config->input_configs->items[i]); - } - - for (int i = 0; i < config->input_type_configs->length; i++) { - input_manager_apply_input_config( - config->input_type_configs->items[i]); - } - - for (int i = 0; i < config->seat_configs->length; i++) { - input_manager_apply_seat_config(config->seat_configs->items[i]); - } - sway_switch_retrigger_bindings_for_all(); - - reset_outputs(); - spawn_swaybg(); - - config->reloading = false; - if (config->swaynag_config_errors.client != NULL) { - swaynag_show(&config->swaynag_config_errors); - } - } - - if (old_config) { - destroy_removed_seats(old_config, config); - free_config(old_config); - } - config->reading = false; - return success; -} - -static bool load_include_config(const char *path, const char *parent_dir, - struct sway_config *config, struct swaynag_instance *swaynag) { - // save parent config - const char *parent_config = config->current_config_path; - - char *full_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(SWAY_ERROR, - "Unable to allocate full path to included config"); - return false; - } - snprintf(full_path, len, "%s/%s", parent_dir, path); - } else { - full_path = strdup(path); - } - - char *real_path = realpath(full_path, NULL); - free(full_path); - - if (real_path == NULL) { - sway_log(SWAY_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(SWAY_DEBUG, - "%s already included once, won't be included again.", - real_path); - free(real_path); - return false; - } - } - - config->current_config_path = real_path; - list_add(config->config_chain, real_path); - int index = config->config_chain->length - 1; - - if (!load_config(real_path, config, swaynag)) { - free(real_path); - config->current_config_path = parent_config; - list_del(config->config_chain, index); - return false; - } - - // restore current_config_path - config->current_config_path = parent_config; - return true; -} - -void load_include_configs(const char *path, struct sway_config *config, - struct swaynag_instance *swaynag) { - char *wd = getcwd(NULL, 0); - char *parent_path = strdup(config->current_config_path); - const char *parent_dir = dirname(parent_path); - - if (chdir(parent_dir) < 0) { - sway_log(SWAY_ERROR, "failed to change working directory"); - goto cleanup; - } - - wordexp_t p; - if (wordexp(path, &p, 0) == 0) { - char **w = p.we_wordv; - size_t i; - for (i = 0; i < p.we_wordc; ++i) { - load_include_config(w[i], parent_dir, config, swaynag); - } - wordfree(&p); - } - - // Attempt to restore working directory before returning. - if (chdir(wd) < 0) { - sway_log(SWAY_ERROR, "failed to change working directory"); - } -cleanup: - free(parent_path); - free(wd); -} - -void run_deferred_commands(void) { - if (!config->cmd_queue->length) { - return; - } - sway_log(SWAY_DEBUG, "Running deferred commands"); - while (config->cmd_queue->length) { - char *line = config->cmd_queue->items[0]; - list_t *res_list = execute_command(line, NULL, NULL); - for (int i = 0; i < res_list->length; ++i) { - struct cmd_results *res = res_list->items[i]; - if (res->status != CMD_SUCCESS) { - sway_log(SWAY_ERROR, "Error on line '%s': %s", - line, res->error); - } - free_cmd_results(res); - } - list_del(config->cmd_queue, 0); - list_free(res_list); - free(line); - } -} - -void run_deferred_bindings(void) { - struct sway_seat *seat; - wl_list_for_each(seat, &(server.input->seats), link) { - if (!seat->deferred_bindings->length) { - continue; - } - sway_log(SWAY_DEBUG, "Running deferred bindings for seat %s", - seat->wlr_seat->name); - while (seat->deferred_bindings->length) { - struct sway_binding *binding = seat->deferred_bindings->items[0]; - seat_execute_command(seat, binding); - list_del(seat->deferred_bindings, 0); - free_sway_binding(binding); - } - } -} - -// get line, with backslash continuation -static ssize_t getline_with_cont(char **lineptr, size_t *line_size, FILE *file, - int *nlines) { - char *next_line = NULL; - size_t next_line_size = 0; - ssize_t nread = getline(lineptr, line_size, file); - *nlines = nread == -1 ? 0 : 1; - while (nread >= 2 && strcmp(&(*lineptr)[nread - 2], "\\\n") == 0 && (*lineptr)[0] != '#') { - ssize_t next_nread = getline(&next_line, &next_line_size, file); - if (next_nread == -1) { - break; - } - (*nlines)++; - - nread += next_nread - 2; - if ((ssize_t) *line_size < nread + 1) { - *line_size = nread + 1; - char *old_ptr = *lineptr; - *lineptr = realloc(*lineptr, *line_size); - if (!*lineptr) { - free(old_ptr); - nread = -1; - break; - } - } - strcpy(&(*lineptr)[nread - next_nread], next_line); - } - free(next_line); - return nread; -} - -static int detect_brace(FILE *file) { - int ret = 0; - int lines = 0; - long pos = ftell(file); - char *line = NULL; - size_t line_size = 0; - while ((getline(&line, &line_size, file)) != -1) { - lines++; - strip_whitespace(line); - if (*line) { - if (strcmp(line, "{") == 0) { - ret = lines; - } - break; - } - } - free(line); - if (ret == 0) { - fseek(file, pos, SEEK_SET); - } - return ret; -} - -static char *expand_line(const char *block, const char *line, bool add_brace) { - int size = (block ? strlen(block) + 1 : 0) + strlen(line) - + (add_brace ? 2 : 0) + 1; - char *expanded = calloc(1, size); - if (!expanded) { - sway_log(SWAY_ERROR, "Cannot allocate expanded line buffer"); - return NULL; - } - snprintf(expanded, size, "%s%s%s%s", block ? block : "", - block ? " " : "", line, add_brace ? " {" : ""); - return expanded; -} - -bool read_config(FILE *file, struct sway_config *config, - struct swaynag_instance *swaynag) { - bool reading_main_config = false; - char *this_config = NULL; - size_t config_size = 0; - if (config->current_config == NULL) { - reading_main_config = true; - - int ret_seek = fseek(file, 0, SEEK_END); - long ret_tell = ftell(file); - if (ret_seek == -1 || ret_tell == -1) { - sway_log(SWAY_ERROR, "Unable to get size of config file"); - return false; - } - config_size = ret_tell; - rewind(file); - - config->current_config = this_config = calloc(1, config_size + 1); - if (this_config == NULL) { - sway_log(SWAY_ERROR, "Unable to allocate buffer for config contents"); - return false; - } - } - - bool success = true; - int line_number = 0; - char *line = NULL; - size_t line_size = 0; - ssize_t nread; - list_t *stack = create_list(); - size_t read = 0; - int nlines = 0; - while ((nread = getline_with_cont(&line, &line_size, file, &nlines)) != -1) { - if (reading_main_config) { - if (read + nread > config_size) { - sway_log(SWAY_ERROR, "Config file changed during reading"); - success = false; - break; - } - - strcpy(&this_config[read], line); - read += nread; - } - - if (line[nread - 1] == '\n') { - line[nread - 1] = '\0'; - } - - line_number += nlines; - sway_log(SWAY_DEBUG, "Read line %d: %s", line_number, line); - - strip_whitespace(line); - if (!*line || line[0] == '#') { - continue; - } - int brace_detected = 0; - if (line[strlen(line) - 1] != '{' && line[strlen(line) - 1] != '}') { - brace_detected = detect_brace(file); - if (brace_detected > 0) { - line_number += brace_detected; - sway_log(SWAY_DEBUG, "Detected open brace on line %d", line_number); - } - } - char *block = stack->length ? stack->items[0] : NULL; - char *expanded = expand_line(block, line, brace_detected > 0); - if (!expanded) { - success = false; - break; - } - config->current_config_line_number = line_number; - config->current_config_line = line; - struct cmd_results *res; - char *new_block = NULL; - if (block && strcmp(block, "") == 0) { - // Special case - res = config_commands_command(expanded); - } else { - res = config_command(expanded, &new_block); - } - switch(res->status) { - case CMD_FAILURE: - case CMD_INVALID: - sway_log(SWAY_ERROR, "Error on line %i '%s': %s (%s)", line_number, - line, res->error, config->current_config_path); - if (!config->validating) { - swaynag_log(config->swaynag_command, swaynag, - "Error on line %i (%s) '%s': %s", line_number, - config->current_config_path, line, res->error); - } - success = false; - break; - - case CMD_DEFER: - sway_log(SWAY_DEBUG, "Deferring command `%s'", line); - list_add(config->cmd_queue, strdup(expanded)); - break; - - case CMD_BLOCK_COMMANDS: - sway_log(SWAY_DEBUG, "Entering commands block"); - list_insert(stack, 0, ""); - break; - - case CMD_BLOCK: - sway_log(SWAY_DEBUG, "Entering block '%s'", new_block); - list_insert(stack, 0, strdup(new_block)); - if (strcmp(new_block, "bar") == 0) { - config->current_bar = NULL; - } - break; - - case CMD_BLOCK_END: - if (!block) { - sway_log(SWAY_DEBUG, "Unmatched '}' on line %i", line_number); - success = false; - break; - } - if (strcmp(block, "bar") == 0) { - config->current_bar = NULL; - } - - sway_log(SWAY_DEBUG, "Exiting block '%s'", block); - list_del(stack, 0); - free(block); - memset(&config->handler_context, 0, - sizeof(config->handler_context)); - default:; - } - free(new_block); - free(expanded); - free_cmd_results(res); - } - free(line); - list_free_items_and_destroy(stack); - config->current_config_line_number = 0; - config->current_config_line = NULL; - - return success; -} - -void config_add_swaynag_warning(char *fmt, ...) { - if (config->reading && !config->validating) { - va_list args; - va_start(args, fmt); - char *str = vformat_str(fmt, args); - va_end(args); - if (str == NULL) { - return; - } - - swaynag_log(config->swaynag_command, &config->swaynag_config_errors, - "Warning on line %i (%s) '%s': %s", - config->current_config_line_number, config->current_config_path, - config->current_config_line, str); - - free(str); - } -} - -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; - } - } - // Unescape double $ and move on - if (find[1] == '$') { - size_t length = strlen(find + 1); - memmove(find, find + 1, length); - find[length] = '\0'; - ++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(SWAY_ERROR, - "Unable to allocate replacement " - "during variable expansion"); - break; - } - char *newptr = newstr; - int offset = find - str; - strncpy(newptr, str, offset); - newptr += offset; - memcpy(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_config *wsa = a, *wsb = b; - return lenient_strcmp(wsa->workspace, wsb->workspace); -} - - -void config_update_font_height(void) { - int prev_max_height = config->font_height; - - get_text_metrics(config->font_description, &config->font_height, &config->font_baseline); - - if (config->font_height != prev_max_height) { - arrange_root(); - } -} - -static void translate_binding_list(list_t *bindings, list_t *bindsyms, - list_t *bindcodes) { - for (int i = 0; i < bindings->length; ++i) { - struct sway_binding *binding = bindings->items[i]; - translate_binding(binding); - - switch (binding->type) { - case BINDING_KEYSYM: - binding_add_translated(binding, bindsyms); - break; - case BINDING_KEYCODE: - binding_add_translated(binding, bindcodes); - break; - default: - sway_assert(false, "unexpected translated binding type: %d", - binding->type); - break; - } - - } -} - -void translate_keysyms(struct input_config *input_config) { - keysym_translation_state_destroy(config->keysym_translation_state); - - struct xkb_rule_names rules = {0}; - input_config_fill_rule_names(input_config, &rules); - config->keysym_translation_state = - keysym_translation_state_create(rules); - - for (int i = 0; i < config->modes->length; ++i) { - struct sway_mode *mode = config->modes->items[i]; - - list_t *bindsyms = create_list(); - list_t *bindcodes = create_list(); - - translate_binding_list(mode->keysym_bindings, bindsyms, bindcodes); - translate_binding_list(mode->keycode_bindings, bindsyms, bindcodes); - - list_free(mode->keysym_bindings); - list_free(mode->keycode_bindings); - - mode->keysym_bindings = bindsyms; - mode->keycode_bindings = bindcodes; - } - - sway_log(SWAY_DEBUG, "Translated keysyms using config for device '%s'", - input_config->identifier); -} - -int config_get_blur_size() { - return pow(2, config->blur_params.num_passes + 1) * config->blur_params.radius; -} - -bool config_should_parameters_blur() { - return config->blur_params.radius > 0 && config->blur_params.num_passes > 0; -} - -bool config_should_parameters_blur_effects() { - return config->blur_params.brightness != 1.0f - || config->blur_params.saturation != 1.0f - || config->blur_params.contrast != 1.0f - || config->blur_params.noise > 0.0f; -} - -bool config_should_parameters_shadow() { - return config->shadow_blur_sigma > 0 && config->shadow_color[3] > 0.0; -} diff --git a/sway/config/bar.c b/sway/config/bar.c deleted file mode 100644 index a8389244f..000000000 --- a/sway/config/bar.c +++ /dev/null @@ -1,274 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sway/config.h" -#include "sway/input/keyboard.h" -#include "sway/output.h" -#include "config.h" -#include "list.h" -#include "log.h" -#include "stringop.h" -#include "util.h" - -void free_bar_binding(struct bar_binding *binding) { - if (!binding) { - return; - } - free(binding->command); - free(binding); -} - -void free_bar_config(struct bar_config *bar) { - if (!bar) { - return; - } - free(bar->id); - free(bar->mode); - free(bar->position); - free(bar->hidden_state); - free(bar->status_command); - free(bar->swaybar_command); - free(bar->font); - free(bar->separator_symbol); - if (bar->bindings) { - for (int i = 0; i < bar->bindings->length; i++) { - free_bar_binding(bar->bindings->items[i]); - } - } - list_free(bar->bindings); - list_free_items_and_destroy(bar->outputs); - if (bar->client != NULL) { - wl_client_destroy(bar->client); - } - 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); -#if HAVE_TRAY - list_free_items_and_destroy(bar->tray_outputs); - free(bar->icon_theme); - - struct tray_binding *tray_bind = NULL, *tmp_tray_bind = NULL; - wl_list_for_each_safe(tray_bind, tmp_tray_bind, &bar->tray_bindings, link) { - wl_list_remove(&tray_bind->link); - free(tray_bind); - } -#endif - free(bar); -} - -struct bar_config *default_bar_config(void) { - struct bar_config *bar = NULL; - bar = calloc(1, sizeof(struct bar_config)); - if (!bar) { - return NULL; - } - bar->outputs = NULL; - bar->position = strdup("bottom"); - bar->pango_markup = PANGO_MARKUP_DEFAULT; - bar->swaybar_command = NULL; - bar->font = NULL; - bar->height = 0; - bar->workspace_buttons = true; - bar->wrap_scroll = false; - bar->separator_symbol = NULL; - bar->strip_workspace_numbers = false; - bar->strip_workspace_name = false; - bar->binding_mode_indicator = true; - bar->verbose = false; - bar->modifier = get_modifier_mask_by_name("Mod4"); - bar->status_padding = 1; - bar->status_edge_padding = 3; - bar->workspace_min_width = 0; - if (!(bar->mode = strdup("dock"))) { - goto cleanup; - } - if (!(bar->hidden_state = strdup("hide"))) { - goto cleanup; - } - if (!(bar->bindings = create_list())) { - goto cleanup; - } - // 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; - -#if HAVE_TRAY - bar->tray_padding = 2; - wl_list_init(&bar->tray_bindings); -#endif - - return bar; -cleanup: - free_bar_config(bar); - return NULL; -} - -static void handle_swaybar_client_destroy(struct wl_listener *listener, - void *data) { - struct bar_config *bar = wl_container_of(listener, bar, client_destroy); - wl_list_remove(&bar->client_destroy.link); - wl_list_init(&bar->client_destroy.link); - bar->client = NULL; -} - -static void invoke_swaybar(struct bar_config *bar) { - int sockets[2]; - if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) != 0) { - sway_log_errno(SWAY_ERROR, "socketpair failed"); - return; - } - if (!sway_set_cloexec(sockets[0], true) || !sway_set_cloexec(sockets[1], true)) { - return; - } - - bar->client = wl_client_create(server.wl_display, sockets[0]); - if (bar->client == NULL) { - sway_log_errno(SWAY_ERROR, "wl_client_create failed"); - return; - } - - bar->client_destroy.notify = handle_swaybar_client_destroy; - wl_client_add_destroy_listener(bar->client, &bar->client_destroy); - - pid_t pid = fork(); - if (pid < 0) { - sway_log(SWAY_ERROR, "Failed to create fork for swaybar"); - return; - } else if (pid == 0) { - // Remove the SIGUSR1 handler that wlroots adds for xwayland - sigset_t set; - sigemptyset(&set); - sigprocmask(SIG_SETMASK, &set, NULL); - signal(SIGPIPE, SIG_DFL); - - restore_nofile_limit(); - - pid = fork(); - if (pid < 0) { - sway_log_errno(SWAY_ERROR, "fork failed"); - _exit(EXIT_FAILURE); - } else if (pid == 0) { - if (!sway_set_cloexec(sockets[1], false)) { - _exit(EXIT_FAILURE); - } - - char wayland_socket_str[16]; - snprintf(wayland_socket_str, sizeof(wayland_socket_str), - "%d", sockets[1]); - setenv("WAYLAND_SOCKET", wayland_socket_str, true); - - // run custom swaybar - char *const cmd[] = { - bar->swaybar_command ? bar->swaybar_command : "swaybar", - "-b", bar->id, NULL}; - execvp(cmd[0], cmd); - _exit(EXIT_FAILURE); - } - _exit(EXIT_SUCCESS); - } - - if (close(sockets[1]) != 0) { - sway_log_errno(SWAY_ERROR, "close failed"); - return; - } - - if (waitpid(pid, NULL, 0) < 0) { - sway_log_errno(SWAY_ERROR, "waitpid failed"); - return; - } - - sway_log(SWAY_DEBUG, "Spawned swaybar %s", bar->id); -} - -void load_swaybar(struct bar_config *bar) { - if (bar->client != NULL) { - wl_client_destroy(bar->client); - } - sway_log(SWAY_DEBUG, "Invoking swaybar for bar id '%s'", bar->id); - invoke_swaybar(bar); -} - -void load_swaybars(void) { - for (int i = 0; i < config->bars->length; ++i) { - struct bar_config *bar = config->bars->items[i]; - load_swaybar(bar); - } -} diff --git a/sway/config/input.c b/sway/config/input.c deleted file mode 100644 index 44c2be289..000000000 --- a/sway/config/input.c +++ /dev/null @@ -1,398 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include "sway/config.h" -#include "sway/input/keyboard.h" -#include "log.h" - -struct input_config *new_input_config(const char* identifier) { - struct input_config *input = calloc(1, sizeof(struct input_config)); - if (!input) { - sway_log(SWAY_DEBUG, "Unable to allocate input config"); - return NULL; - } - sway_log(SWAY_DEBUG, "new_input_config(%s)", identifier); - if (!(input->identifier = strdup(identifier))) { - free(input); - sway_log(SWAY_DEBUG, "Unable to allocate input config"); - return NULL; - } - - input->input_type = NULL; - input->tap = INT_MIN; - input->tap_button_map = INT_MIN; - input->drag = INT_MIN; - input->drag_lock = INT_MIN; - input->dwt = INT_MIN; - input->dwtp = INT_MIN; - input->send_events = INT_MIN; - input->click_method = INT_MIN; - input->middle_emulation = INT_MIN; - input->natural_scroll = INT_MIN; - input->accel_profile = INT_MIN; - input->rotation_angle = FLT_MIN; - input->pointer_accel = FLT_MIN; - input->scroll_factor = FLT_MIN; - input->scroll_button = INT_MIN; - input->scroll_button_lock = INT_MIN; - input->scroll_method = INT_MIN; - input->left_handed = INT_MIN; - input->repeat_delay = INT_MIN; - input->repeat_rate = INT_MIN; - input->xkb_numlock = INT_MIN; - input->xkb_capslock = INT_MIN; - input->xkb_file_is_set = false; - input->tools = create_list(); - - return input; -} - -void merge_input_config(struct input_config *dst, struct input_config *src) { - 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 != INT_MIN) { - dst->drag = src->drag; - } - if (src->drag_lock != INT_MIN) { - dst->drag_lock = src->drag_lock; - } - if (src->dwt != INT_MIN) { - dst->dwt = src->dwt; - } - if (src->dwtp != INT_MIN) { - dst->dwtp = src->dwtp; - } - if (src->left_handed != INT_MIN) { - dst->left_handed = src->left_handed; - } - 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->rotation_angle != FLT_MIN) { - dst->rotation_angle = src->rotation_angle; - } - if (src->pointer_accel != FLT_MIN) { - dst->pointer_accel = src->pointer_accel; - } - if (src->scroll_factor != FLT_MIN) { - dst->scroll_factor = src->scroll_factor; - } - if (src->repeat_delay != INT_MIN) { - dst->repeat_delay = src->repeat_delay; - } - if (src->repeat_rate != INT_MIN) { - dst->repeat_rate = src->repeat_rate; - } - if (src->scroll_method != INT_MIN) { - dst->scroll_method = src->scroll_method; - } - if (src->scroll_button != INT_MIN) { - dst->scroll_button = src->scroll_button; - } - if (src->scroll_button_lock != INT_MIN) { - dst->scroll_button_lock = src->scroll_button_lock; - } - if (src->send_events != INT_MIN) { - dst->send_events = src->send_events; - } - if (src->tap != INT_MIN) { - dst->tap = src->tap; - } - if (src->tap_button_map != INT_MIN) { - dst->tap_button_map = src->tap_button_map; - } - if (src->xkb_file_is_set) { - free(dst->xkb_file); - dst->xkb_file = src->xkb_file ? strdup(src->xkb_file) : NULL; - dst->xkb_file_is_set = dst->xkb_file != NULL; - } - if (src->xkb_layout) { - free(dst->xkb_layout); - dst->xkb_layout = strdup(src->xkb_layout); - } - if (src->xkb_model) { - free(dst->xkb_model); - dst->xkb_model = strdup(src->xkb_model); - } - if (src->xkb_options) { - free(dst->xkb_options); - dst->xkb_options = strdup(src->xkb_options); - } - if (src->xkb_rules) { - free(dst->xkb_rules); - dst->xkb_rules = strdup(src->xkb_rules); - } - if (src->xkb_variant) { - free(dst->xkb_variant); - dst->xkb_variant = strdup(src->xkb_variant); - } - if (src->xkb_numlock != INT_MIN) { - dst->xkb_numlock = src->xkb_numlock; - } - if (src->xkb_capslock != INT_MIN) { - dst->xkb_capslock = src->xkb_capslock; - } - if (src->mapped_from_region) { - free(dst->mapped_from_region); - dst->mapped_from_region = - malloc(sizeof(struct input_config_mapped_from_region)); - memcpy(dst->mapped_from_region, src->mapped_from_region, - sizeof(struct input_config_mapped_from_region)); - } - if (src->mapped_to) { - dst->mapped_to = src->mapped_to; - } - if (src->mapped_to_output) { - free(dst->mapped_to_output); - dst->mapped_to_output = strdup(src->mapped_to_output); - } - if (src->mapped_to_region) { - free(dst->mapped_to_region); - dst->mapped_to_region = - malloc(sizeof(struct wlr_box)); - memcpy(dst->mapped_to_region, src->mapped_to_region, - sizeof(struct wlr_box)); - } - if (src->calibration_matrix.configured) { - dst->calibration_matrix.configured = src->calibration_matrix.configured; - memcpy(dst->calibration_matrix.matrix, src->calibration_matrix.matrix, - sizeof(src->calibration_matrix.matrix)); - } - for (int i = 0; i < src->tools->length; i++) { - struct input_config_tool *src_tool = src->tools->items[i]; - for (int j = 0; j < dst->tools->length; j++) { - struct input_config_tool *dst_tool = dst->tools->items[j]; - if (src_tool->type == dst_tool->type) { - dst_tool->mode = src_tool->mode; - goto tool_merge_outer; - } - } - - struct input_config_tool *dst_tool = malloc(sizeof(*dst_tool)); - memcpy(dst_tool, src_tool, sizeof(*dst_tool)); - list_add(dst->tools, dst_tool); - - tool_merge_outer:; - } -} - -static bool validate_xkb_merge(struct input_config *dest, - struct input_config *src, char **xkb_error) { - struct input_config *temp = new_input_config("temp"); - if (dest) { - merge_input_config(temp, dest); - } - merge_input_config(temp, src); - - struct xkb_keymap *keymap = sway_keyboard_compile_keymap(temp, xkb_error); - free_input_config(temp); - if (!keymap) { - return false; - } - - xkb_keymap_unref(keymap); - return true; -} - -static bool validate_wildcard_on_all(struct input_config *wildcard, - char **error) { - for (int i = 0; i < config->input_configs->length; i++) { - struct input_config *ic = config->input_configs->items[i]; - if (strcmp(wildcard->identifier, ic->identifier) != 0) { - sway_log(SWAY_DEBUG, "Validating xkb merge of * on %s", - ic->identifier); - if (!validate_xkb_merge(ic, wildcard, error)) { - return false; - } - } - } - - for (int i = 0; i < config->input_type_configs->length; i++) { - struct input_config *ic = config->input_type_configs->items[i]; - sway_log(SWAY_DEBUG, "Validating xkb merge of * config on %s", - ic->identifier); - if (!validate_xkb_merge(ic, wildcard, error)) { - return false; - } - } - - return true; -} - -static void merge_wildcard_on_all(struct input_config *wildcard) { - for (int i = 0; i < config->input_configs->length; i++) { - struct input_config *ic = config->input_configs->items[i]; - if (strcmp(wildcard->identifier, ic->identifier) != 0) { - sway_log(SWAY_DEBUG, "Merging input * config on %s", ic->identifier); - merge_input_config(ic, wildcard); - } - } - - for (int i = 0; i < config->input_type_configs->length; i++) { - struct input_config *ic = config->input_type_configs->items[i]; - sway_log(SWAY_DEBUG, "Merging input * config on %s", ic->identifier); - merge_input_config(ic, wildcard); - } -} - -static bool validate_type_on_existing(struct input_config *type_wildcard, - char **error) { - for (int i = 0; i < config->input_configs->length; i++) { - struct input_config *ic = config->input_configs->items[i]; - if (ic->input_type == NULL) { - continue; - } - - if (strcmp(ic->input_type, type_wildcard->identifier + 5) == 0) { - sway_log(SWAY_DEBUG, "Validating merge of %s on %s", - type_wildcard->identifier, ic->identifier); - if (!validate_xkb_merge(ic, type_wildcard, error)) { - return false; - } - } - } - return true; -} - -static void merge_type_on_existing(struct input_config *type_wildcard) { - for (int i = 0; i < config->input_configs->length; i++) { - struct input_config *ic = config->input_configs->items[i]; - if (ic->input_type == NULL) { - continue; - } - - if (strcmp(ic->input_type, type_wildcard->identifier + 5) == 0) { - sway_log(SWAY_DEBUG, "Merging %s top of %s", - type_wildcard->identifier, - ic->identifier); - merge_input_config(ic, type_wildcard); - } - } -} - -static const char *set_input_type(struct input_config *ic) { - struct sway_input_device *input_device; - wl_list_for_each(input_device, &server.input->devices, link) { - if (strcmp(input_device->identifier, ic->identifier) == 0) { - ic->input_type = input_device_get_type(input_device); - break; - } - } - return ic->input_type; -} - -struct input_config *store_input_config(struct input_config *ic, - char **error) { - bool wildcard = strcmp(ic->identifier, "*") == 0; - if (wildcard && error && !validate_wildcard_on_all(ic, error)) { - return NULL; - } - - bool type = strncmp(ic->identifier, "type:", strlen("type:")) == 0; - if (type && error && !validate_type_on_existing(ic, error)) { - return NULL; - } - - list_t *config_list = type ? config->input_type_configs - : config->input_configs; - - struct input_config *current = NULL; - bool new_current = false; - - int i = list_seq_find(config_list, input_identifier_cmp, ic->identifier); - if (i >= 0) { - current = config_list->items[i]; - } - - if (!current && !wildcard && !type && set_input_type(ic)) { - for (i = 0; i < config->input_type_configs->length; i++) { - struct input_config *tc = config->input_type_configs->items[i]; - if (strcmp(ic->input_type, tc->identifier + 5) == 0) { - current = new_input_config(ic->identifier); - current->input_type = ic->input_type; - merge_input_config(current, tc); - new_current = true; - break; - } - } - } - - i = list_seq_find(config->input_configs, input_identifier_cmp, "*"); - if (!current && i >= 0) { - current = new_input_config(ic->identifier); - merge_input_config(current, config->input_configs->items[i]); - new_current = true; - } - - if (error && !validate_xkb_merge(current, ic, error)) { - if (new_current) { - free_input_config(current); - } - return NULL; - } - - if (wildcard) { - merge_wildcard_on_all(ic); - } - - if (type) { - merge_type_on_existing(ic); - } - - if (current) { - merge_input_config(current, ic); - free_input_config(ic); - ic = current; - } - - ic->xkb_file_is_set = ic->xkb_file != NULL; - - if (!current || new_current) { - list_add(config_list, ic); - } - - sway_log(SWAY_DEBUG, "Config stored for input %s", ic->identifier); - - return ic; -} - -void input_config_fill_rule_names(struct input_config *ic, - struct xkb_rule_names *rules) { - rules->layout = ic->xkb_layout; - rules->model = ic->xkb_model; - rules->options = ic->xkb_options; - rules->rules = ic->xkb_rules; - rules->variant = ic->xkb_variant; -} - -void free_input_config(struct input_config *ic) { - if (!ic) { - return; - } - free(ic->identifier); - free(ic->xkb_file); - free(ic->xkb_layout); - free(ic->xkb_model); - free(ic->xkb_options); - free(ic->xkb_rules); - free(ic->xkb_variant); - free(ic->mapped_from_region); - free(ic->mapped_to_output); - free(ic->mapped_to_region); - list_free_items_and_destroy(ic->tools); - free(ic); -} - -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); -} diff --git a/sway/config/output.c b/sway/config/output.c deleted file mode 100644 index 3c1822d87..000000000 --- a/sway/config/output.c +++ /dev/null @@ -1,909 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sway/config.h" -#include "sway/input/cursor.h" -#include "sway/output.h" -#include "sway/tree/root.h" -#include "log.h" -#include "util.h" - -#if WLR_HAS_DRM_BACKEND -#include -#endif - -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 output_get_identifier(char *identifier, size_t len, - struct sway_output *output) { - struct wlr_output *wlr_output = output->wlr_output; - snprintf(identifier, len, "%s %s %s", - wlr_output->make ? wlr_output->make : "Unknown", - wlr_output->model ? wlr_output->model : "Unknown", - wlr_output->serial ? wlr_output->serial : "Unknown"); -} - -const char *sway_output_scale_filter_to_string(enum scale_filter_mode scale_filter) { - switch (scale_filter) { - case SCALE_FILTER_DEFAULT: - return "smart"; - case SCALE_FILTER_LINEAR: - return "linear"; - case SCALE_FILTER_NEAREST: - return "nearest"; - case SCALE_FILTER_SMART: - return "smart"; - } - sway_assert(false, "Unknown value for scale_filter."); - return NULL; -} - -struct output_config *new_output_config(const char *name) { - struct output_config *oc = calloc(1, sizeof(struct output_config)); - if (oc == NULL) { - return NULL; - } - oc->name = strdup(name); - if (oc->name == NULL) { - free(oc); - return NULL; - } - oc->enabled = -1; - oc->width = oc->height = -1; - oc->refresh_rate = -1; - oc->custom_mode = -1; - oc->drm_mode.type = -1; - oc->x = oc->y = -1; - oc->scale = -1; - oc->scale_filter = SCALE_FILTER_DEFAULT; - oc->transform = -1; - oc->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN; - oc->max_render_time = -1; - oc->adaptive_sync = -1; - oc->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT; - oc->power = -1; - return oc; -} - -void merge_output_config(struct output_config *dst, struct output_config *src) { - 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->scale_filter != SCALE_FILTER_DEFAULT) { - dst->scale_filter = src->scale_filter; - } - if (src->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN) { - dst->subpixel = src->subpixel; - } - if (src->refresh_rate != -1) { - dst->refresh_rate = src->refresh_rate; - } - if (src->custom_mode != -1) { - dst->custom_mode = src->custom_mode; - } - if (src->drm_mode.type != (uint32_t) -1) { - memcpy(&dst->drm_mode, &src->drm_mode, sizeof(src->drm_mode)); - } - if (src->transform != -1) { - dst->transform = src->transform; - } - if (src->max_render_time != -1) { - dst->max_render_time = src->max_render_time; - } - if (src->adaptive_sync != -1) { - dst->adaptive_sync = src->adaptive_sync; - } - if (src->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) { - dst->render_bit_depth = src->render_bit_depth; - } - if (src->background) { - free(dst->background); - dst->background = strdup(src->background); - } - if (src->background_option) { - free(dst->background_option); - dst->background_option = strdup(src->background_option); - } - if (src->background_fallback) { - free(dst->background_fallback); - dst->background_fallback = strdup(src->background_fallback); - } - if (src->power != -1) { - dst->power = src->power; - } -} - -static void merge_wildcard_on_all(struct output_config *wildcard) { - for (int i = 0; i < config->output_configs->length; i++) { - struct output_config *oc = config->output_configs->items[i]; - if (strcmp(wildcard->name, oc->name) != 0) { - sway_log(SWAY_DEBUG, "Merging output * config on %s", oc->name); - merge_output_config(oc, wildcard); - } - } -} - -static void merge_id_on_name(struct output_config *oc) { - struct sway_output *output = all_output_by_name_or_id(oc->name); - if (output == NULL) { - return; - } - - const char *name = output->wlr_output->name; - char id[128]; - output_get_identifier(id, sizeof(id), output); - - char *id_on_name = format_str("%s on %s", id, name); - if (!id_on_name) { - return; - } - - int i = list_seq_find(config->output_configs, output_name_cmp, id_on_name); - if (i >= 0) { - sway_log(SWAY_DEBUG, "Merging on top of existing id on name config"); - merge_output_config(config->output_configs->items[i], oc); - } else { - // If both a name and identifier config, exist generate an id on name - int ni = list_seq_find(config->output_configs, output_name_cmp, name); - int ii = list_seq_find(config->output_configs, output_name_cmp, id); - if ((ni >= 0 && ii >= 0) || (ni >= 0 && strcmp(oc->name, id) == 0) - || (ii >= 0 && strcmp(oc->name, name) == 0)) { - struct output_config *ion_oc = new_output_config(id_on_name); - if (ni >= 0) { - merge_output_config(ion_oc, config->output_configs->items[ni]); - } - if (ii >= 0) { - merge_output_config(ion_oc, config->output_configs->items[ii]); - } - merge_output_config(ion_oc, oc); - list_add(config->output_configs, ion_oc); - sway_log(SWAY_DEBUG, "Generated id on name output config \"%s\"" - " (enabled: %d) (%dx%d@%fHz position %d,%d scale %f " - "transform %d) (bg %s %s) (power %d) (max render time: %d)", - ion_oc->name, ion_oc->enabled, ion_oc->width, ion_oc->height, - ion_oc->refresh_rate, ion_oc->x, ion_oc->y, ion_oc->scale, - ion_oc->transform, ion_oc->background, - ion_oc->background_option, ion_oc->power, - ion_oc->max_render_time); - } - } - free(id_on_name); -} - -struct output_config *store_output_config(struct output_config *oc) { - bool wildcard = strcmp(oc->name, "*") == 0; - if (wildcard) { - merge_wildcard_on_all(oc); - } else { - merge_id_on_name(oc); - } - - int i = list_seq_find(config->output_configs, output_name_cmp, oc->name); - if (i >= 0) { - sway_log(SWAY_DEBUG, "Merging on top of existing output config"); - struct output_config *current = config->output_configs->items[i]; - merge_output_config(current, oc); - free_output_config(oc); - oc = current; - } else if (!wildcard) { - sway_log(SWAY_DEBUG, "Adding non-wildcard output config"); - i = list_seq_find(config->output_configs, output_name_cmp, "*"); - if (i >= 0) { - sway_log(SWAY_DEBUG, "Merging on top of output * config"); - struct output_config *current = new_output_config(oc->name); - merge_output_config(current, config->output_configs->items[i]); - merge_output_config(current, oc); - free_output_config(oc); - oc = current; - } - list_add(config->output_configs, oc); - } else { - // New wildcard config. Just add it - sway_log(SWAY_DEBUG, "Adding output * config"); - list_add(config->output_configs, oc); - } - - sway_log(SWAY_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz " - "position %d,%d scale %f subpixel %s transform %d) (bg %s %s) (power %d) " - "(max render time: %d)", - oc->name, oc->enabled, oc->width, oc->height, oc->refresh_rate, - oc->x, oc->y, oc->scale, sway_wl_output_subpixel_to_string(oc->subpixel), - oc->transform, oc->background, oc->background_option, oc->power, - oc->max_render_time); - - return oc; -} - -static void set_mode(struct wlr_output *output, struct wlr_output_state *pending, - int width, int height, float refresh_rate, bool custom) { - // Not all floating point integers can be represented exactly - // as (int)(1000 * mHz / 1000.f) - // round() the result to avoid any error - int mhz = (int)roundf(refresh_rate * 1000); - // If no target refresh rate is given, match highest available - mhz = mhz <= 0 ? INT_MAX : mhz; - - if (wl_list_empty(&output->modes) || custom) { - sway_log(SWAY_DEBUG, "Assigning custom mode to %s", output->name); - wlr_output_state_set_custom_mode(pending, width, height, - refresh_rate > 0 ? mhz : 0); - return; - } - - struct wlr_output_mode *mode, *best = NULL; - int best_diff_mhz = INT_MAX; - wl_list_for_each(mode, &output->modes, link) { - if (mode->width == width && mode->height == height) { - int diff_mhz = abs(mode->refresh - mhz); - if (diff_mhz < best_diff_mhz) { - best_diff_mhz = diff_mhz; - best = mode; - if (best_diff_mhz == 0) { - break; - } - } - } - } - if (best) { - sway_log(SWAY_INFO, "Assigning configured mode (%dx%d@%.3fHz) to %s", - best->width, best->height, best->refresh / 1000.f, output->name); - } else { - best = wlr_output_preferred_mode(output); - sway_log(SWAY_INFO, "Configured mode (%dx%d@%.3fHz) not available, " - "applying preferred mode (%dx%d@%.3fHz)", - width, height, refresh_rate, - best->width, best->height, best->refresh / 1000.f); - } - wlr_output_state_set_mode(pending, best); -} - -static void set_modeline(struct wlr_output *output, - struct wlr_output_state *pending, drmModeModeInfo *drm_mode) { -#if WLR_HAS_DRM_BACKEND - if (!wlr_output_is_drm(output)) { - sway_log(SWAY_ERROR, "Modeline can only be set to DRM output"); - return; - } - sway_log(SWAY_DEBUG, "Assigning custom modeline to %s", output->name); - struct wlr_output_mode *mode = wlr_drm_connector_add_mode(output, drm_mode); - if (mode) { - wlr_output_state_set_mode(pending, mode); - } -#else - sway_log(SWAY_ERROR, "Modeline can only be set to DRM output"); -#endif -} - -/* Some manufacturers hardcode the aspect-ratio of the output in the physical - * size field. */ -static bool phys_size_is_aspect_ratio(struct wlr_output *output) { - return (output->phys_width == 1600 && output->phys_height == 900) || - (output->phys_width == 1600 && output->phys_height == 1000) || - (output->phys_width == 160 && output->phys_height == 90) || - (output->phys_width == 160 && output->phys_height == 100) || - (output->phys_width == 16 && output->phys_height == 9) || - (output->phys_width == 16 && output->phys_height == 10); -} - -// The minimum DPI at which we turn on a scale of 2 -#define HIDPI_DPI_LIMIT (2 * 96) -// The minimum screen height at which we turn on a scale of 2 -#define HIDPI_MIN_HEIGHT 1200 -// 1 inch = 25.4 mm -#define MM_PER_INCH 25.4 - -static int compute_default_scale(struct wlr_output *output, - struct wlr_output_state *pending) { - struct wlr_box box = { .width = output->width, .height = output->height }; - if (pending->committed & WLR_OUTPUT_STATE_MODE) { - switch (pending->mode_type) { - case WLR_OUTPUT_STATE_MODE_FIXED: - box.width = pending->mode->width; - box.height = pending->mode->height; - break; - case WLR_OUTPUT_STATE_MODE_CUSTOM: - box.width = pending->custom_mode.width; - box.height = pending->custom_mode.height; - break; - } - } - enum wl_output_transform transform = output->transform; - if (pending->committed & WLR_OUTPUT_STATE_TRANSFORM) { - transform = pending->transform; - } - wlr_box_transform(&box, &box, transform, box.width, box.height); - - int width = box.width; - int height = box.height; - - if (height < HIDPI_MIN_HEIGHT) { - return 1; - } - - if (output->phys_width == 0 || output->phys_height == 0) { - return 1; - } - - if (phys_size_is_aspect_ratio(output)) { - return 1; - } - - double dpi_x = (double) width / (output->phys_width / MM_PER_INCH); - double dpi_y = (double) height / (output->phys_height / MM_PER_INCH); - sway_log(SWAY_DEBUG, "Output DPI: %fx%f", dpi_x, dpi_y); - if (dpi_x <= HIDPI_DPI_LIMIT || dpi_y <= HIDPI_DPI_LIMIT) { - return 1; - } - - return 2; -} - -/* Lists of formats to try, in order, when a specific render bit depth has - * been asked for. The second to last format in each list should always - * be XRGB8888, as a reliable backup in case the others are not available; - * the last should be DRM_FORMAT_INVALID, to indicate the end of the list. */ -static const uint32_t *bit_depth_preferences[] = { - [RENDER_BIT_DEPTH_8] = (const uint32_t []){ - DRM_FORMAT_XRGB8888, - DRM_FORMAT_INVALID, - }, - [RENDER_BIT_DEPTH_10] = (const uint32_t []){ - DRM_FORMAT_XRGB2101010, - DRM_FORMAT_XBGR2101010, - DRM_FORMAT_XRGB8888, - DRM_FORMAT_INVALID, - }, -}; - -static void queue_output_config(struct output_config *oc, - struct sway_output *output, struct wlr_output_state *pending) { - if (output == root->fallback_output) { - return; - } - - struct wlr_output *wlr_output = output->wlr_output; - - if (oc && (!oc->enabled || oc->power == 0)) { - sway_log(SWAY_DEBUG, "Turning off output %s", wlr_output->name); - wlr_output_state_set_enabled(pending, false); - return; - } - - sway_log(SWAY_DEBUG, "Turning on output %s", wlr_output->name); - wlr_output_state_set_enabled(pending, true); - - if (oc && oc->drm_mode.type != 0 && oc->drm_mode.type != (uint32_t) -1) { - sway_log(SWAY_DEBUG, "Set %s modeline", - wlr_output->name); - set_modeline(wlr_output, pending, &oc->drm_mode); - } else if (oc && oc->width > 0 && oc->height > 0) { - sway_log(SWAY_DEBUG, "Set %s mode to %dx%d (%f Hz)", - wlr_output->name, oc->width, oc->height, oc->refresh_rate); - set_mode(wlr_output, pending, oc->width, oc->height, - oc->refresh_rate, oc->custom_mode == 1); - } else if (!wl_list_empty(&wlr_output->modes)) { - sway_log(SWAY_DEBUG, "Set preferred mode"); - struct wlr_output_mode *preferred_mode = - wlr_output_preferred_mode(wlr_output); - wlr_output_state_set_mode(pending, preferred_mode); - - if (!wlr_output_test_state(wlr_output, pending)) { - sway_log(SWAY_DEBUG, "Preferred mode rejected, " - "falling back to another mode"); - struct wlr_output_mode *mode; - wl_list_for_each(mode, &wlr_output->modes, link) { - if (mode == preferred_mode) { - continue; - } - - wlr_output_state_set_mode(pending, mode); - if (wlr_output_test_state(wlr_output, pending)) { - break; - } - } - } - } - - if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) { - sway_log(SWAY_DEBUG, "Set %s subpixel to %s", oc->name, - sway_wl_output_subpixel_to_string(oc->subpixel)); - wlr_output_state_set_subpixel(pending, oc->subpixel); - } - - enum wl_output_transform tr = WL_OUTPUT_TRANSFORM_NORMAL; - if (oc && oc->transform >= 0) { - tr = oc->transform; -#if WLR_HAS_DRM_BACKEND - } else if (wlr_output_is_drm(wlr_output)) { - tr = wlr_drm_connector_get_panel_orientation(wlr_output); - sway_log(SWAY_DEBUG, "Auto-detected output transform: %d", tr); -#endif - } - if (wlr_output->transform != tr) { - sway_log(SWAY_DEBUG, "Set %s transform to %d", oc->name, tr); - wlr_output_state_set_transform(pending, tr); - } - - // Apply the scale last before the commit, because the scale auto-detection - // reads the pending output size - float scale; - if (oc && oc->scale > 0) { - scale = oc->scale; - - // The factional-scale-v1 protocol uses increments of 120ths to send - // the scale factor to the client. Adjust the scale so that we use the - // same value as the clients'. - float adjusted_scale = round(scale * 120) / 120; - if (scale != adjusted_scale) { - sway_log(SWAY_INFO, "Adjusting output scale from %f to %f", - scale, adjusted_scale); - scale = adjusted_scale; - } - } else { - scale = compute_default_scale(wlr_output, pending); - sway_log(SWAY_DEBUG, "Auto-detected output scale: %f", scale); - } - if (scale != wlr_output->scale) { - sway_log(SWAY_DEBUG, "Set %s scale to %f", wlr_output->name, scale); - wlr_output_state_set_scale(pending, scale); - } - - if (oc && oc->adaptive_sync != -1) { - sway_log(SWAY_DEBUG, "Set %s adaptive sync to %d", wlr_output->name, - oc->adaptive_sync); - wlr_output_state_set_adaptive_sync_enabled(pending, oc->adaptive_sync == 1); - if (oc->adaptive_sync == 1 && !wlr_output_test_state(wlr_output, pending)) { - sway_log(SWAY_DEBUG, "Adaptive sync failed, ignoring"); - wlr_output_state_set_adaptive_sync_enabled(pending, false); - } - } - - if (oc && oc->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) { - const uint32_t *fmts = bit_depth_preferences[oc->render_bit_depth]; - assert(fmts); - - for (size_t i = 0; fmts[i] != DRM_FORMAT_INVALID; i++) { - wlr_output_state_set_render_format(pending, fmts[i]); - if (wlr_output_test_state(wlr_output, pending)) { - break; - } - - sway_log(SWAY_DEBUG, "Preferred output format 0x%08x " - "failed to work, falling back to next in " - "list, 0x%08x", fmts[i], fmts[i + 1]); - } - } -} - -bool apply_output_config(struct output_config *oc, struct sway_output *output) { - if (output == root->fallback_output) { - return false; - } - - struct wlr_output *wlr_output = output->wlr_output; - - // Flag to prevent the output mode event handler from calling us - output->enabling = (!oc || oc->enabled); - - struct wlr_output_state pending = {0}; - queue_output_config(oc, output, &pending); - - sway_log(SWAY_DEBUG, "Committing output %s", wlr_output->name); - if (!wlr_output_commit_state(wlr_output, &pending)) { - // Failed to commit output changes, maybe the output is missing a CRTC. - // Leave the output disabled for now and try again when the output gets - // the mode we asked for. - sway_log(SWAY_ERROR, "Failed to commit output %s", wlr_output->name); - output->enabling = false; - return false; - } - - output->enabling = false; - - if (oc && !oc->enabled) { - sway_log(SWAY_DEBUG, "Disabling output %s", oc->name); - if (output->enabled) { - output_disable(output); - wlr_output_layout_remove(root->output_layout, wlr_output); - } - return true; - } - - if (config->reloading) { - output_damage_whole(output); - } - - if (oc) { - enum scale_filter_mode scale_filter_old = output->scale_filter; - switch (oc->scale_filter) { - case SCALE_FILTER_DEFAULT: - case SCALE_FILTER_SMART: - output->scale_filter = ceilf(wlr_output->scale) == wlr_output->scale ? - SCALE_FILTER_NEAREST : SCALE_FILTER_LINEAR; - break; - case SCALE_FILTER_LINEAR: - case SCALE_FILTER_NEAREST: - output->scale_filter = oc->scale_filter; - break; - } - if (scale_filter_old != output->scale_filter) { - sway_log(SWAY_DEBUG, "Set %s scale_filter to %s", oc->name, - sway_output_scale_filter_to_string(output->scale_filter)); - } - } - - // Find position for it - if (oc && (oc->x != -1 || oc->y != -1)) { - sway_log(SWAY_DEBUG, "Set %s position to %d, %d", oc->name, oc->x, oc->y); - wlr_output_layout_add(root->output_layout, wlr_output, oc->x, oc->y); - } else { - wlr_output_layout_add_auto(root->output_layout, wlr_output); - } - - // Update output->{lx, ly, width, height} - struct wlr_box output_box; - wlr_output_layout_get_box(root->output_layout, wlr_output, &output_box); - output->lx = output_box.x; - output->ly = output_box.y; - output->width = output_box.width; - output->height = output_box.height; - - if (!output->enabled) { - output_enable(output); - } - - if (oc && oc->max_render_time >= 0) { - sway_log(SWAY_DEBUG, "Set %s max render time to %d", - oc->name, oc->max_render_time); - output->max_render_time = oc->max_render_time; - } - - // Reconfigure all devices, since input config may have been applied before - // this output came online, and some config items (like map_to_output) are - // dependent on an output being present. - input_manager_configure_all_input_mappings(); - // Reconfigure the cursor images, since the scale may have changed. - input_manager_configure_xcursor(); - return true; -} - -bool test_output_config(struct output_config *oc, struct sway_output *output) { - if (output == root->fallback_output) { - return false; - } - - struct wlr_output_state pending = {0}; - queue_output_config(oc, output, &pending); - return wlr_output_test_state(output->wlr_output, &pending); -} - -static void default_output_config(struct output_config *oc, - struct wlr_output *wlr_output) { - oc->enabled = 1; - oc->power = 1; - struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output); - if (mode != NULL) { - oc->width = mode->width; - oc->height = mode->height; - oc->refresh_rate = mode->refresh / 1000.f; - } - oc->x = oc->y = -1; - oc->scale = 0; // auto - oc->scale_filter = SCALE_FILTER_DEFAULT; - struct sway_output *output = wlr_output->data; - oc->subpixel = output->detected_subpixel; - oc->transform = WL_OUTPUT_TRANSFORM_NORMAL; - oc->max_render_time = 0; -} - -static struct output_config *get_output_config(char *identifier, - struct sway_output *sway_output) { - const char *name = sway_output->wlr_output->name; - - struct output_config *oc_id_on_name = NULL; - struct output_config *oc_name = NULL; - struct output_config *oc_id = NULL; - - char *id_on_name = format_str("%s on %s", identifier, name); - int i = list_seq_find(config->output_configs, output_name_cmp, id_on_name); - if (i >= 0) { - oc_id_on_name = config->output_configs->items[i]; - } else { - i = list_seq_find(config->output_configs, output_name_cmp, name); - if (i >= 0) { - oc_name = config->output_configs->items[i]; - } - - i = list_seq_find(config->output_configs, output_name_cmp, identifier); - if (i >= 0) { - oc_id = config->output_configs->items[i]; - } - } - - struct output_config *result = new_output_config("temp"); - if (config->reloading) { - default_output_config(result, sway_output->wlr_output); - } - if (oc_id_on_name) { - // Already have an identifier on name config, use that - free(result->name); - result->name = strdup(id_on_name); - merge_output_config(result, oc_id_on_name); - } else if (oc_name && oc_id) { - // Generate a config named ` on ` which contains a - // merged copy of the identifier on name. This will make sure that both - // identifier and name configs are respected, with identifier getting - // priority - struct output_config *temp = new_output_config(id_on_name); - merge_output_config(temp, oc_name); - merge_output_config(temp, oc_id); - list_add(config->output_configs, temp); - - free(result->name); - result->name = strdup(id_on_name); - merge_output_config(result, temp); - - sway_log(SWAY_DEBUG, "Generated output config \"%s\" (enabled: %d)" - " (%dx%d@%fHz position %d,%d scale %f transform %d) (bg %s %s)" - " (power %d) (max render time: %d)", result->name, result->enabled, - result->width, result->height, result->refresh_rate, - result->x, result->y, result->scale, result->transform, - result->background, result->background_option, result->power, - result->max_render_time); - } else if (oc_name) { - // No identifier config, just return a copy of the name config - free(result->name); - result->name = strdup(name); - merge_output_config(result, oc_name); - } else if (oc_id) { - // No name config, just return a copy of the identifier config - free(result->name); - result->name = strdup(identifier); - merge_output_config(result, oc_id); - } else { - i = list_seq_find(config->output_configs, output_name_cmp, "*"); - if (i >= 0) { - // No name or identifier config, but there is a wildcard config - free(result->name); - result->name = strdup("*"); - merge_output_config(result, config->output_configs->items[i]); - } else if (!config->reloading) { - // No name, identifier, or wildcard config. Since we are not - // reloading with defaults, the output config will be empty, so - // just return NULL - free_output_config(result); - result = NULL; - } - } - - free(id_on_name); - return result; -} - -struct output_config *find_output_config(struct sway_output *output) { - char id[128]; - output_get_identifier(id, sizeof(id), output); - return get_output_config(id, output); -} - -void apply_output_config_to_outputs(struct output_config *oc) { - // 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 wlroots. - bool wildcard = strcmp(oc->name, "*") == 0; - struct sway_output *sway_output, *tmp; - wl_list_for_each_safe(sway_output, tmp, &root->all_outputs, link) { - if (output_match_name_or_id(sway_output, oc->name)) { - char id[128]; - output_get_identifier(id, sizeof(id), sway_output); - struct output_config *current = get_output_config(id, sway_output); - if (!current) { - // No stored output config matched, apply oc directly - sway_log(SWAY_DEBUG, "Applying oc directly"); - current = new_output_config(oc->name); - merge_output_config(current, oc); - } - apply_output_config(current, sway_output); - free_output_config(current); - - if (!wildcard) { - // Stop looking if the output config isn't applicable to all - // outputs - break; - } - } - } - - struct sway_seat *seat; - wl_list_for_each(seat, &server.input->seats, link) { - wlr_seat_pointer_notify_clear_focus(seat->wlr_seat); - cursor_rebase(seat->cursor); - } -} - -void reset_outputs(void) { - struct output_config *oc = NULL; - int i = list_seq_find(config->output_configs, output_name_cmp, "*"); - if (i >= 0) { - oc = config->output_configs->items[i]; - } else { - oc = store_output_config(new_output_config("*")); - } - apply_output_config_to_outputs(oc); -} - -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 handle_swaybg_client_destroy(struct wl_listener *listener, - void *data) { - struct sway_config *sway_config = - wl_container_of(listener, sway_config, swaybg_client_destroy); - wl_list_remove(&sway_config->swaybg_client_destroy.link); - wl_list_init(&sway_config->swaybg_client_destroy.link); - sway_config->swaybg_client = NULL; -} - -static bool _spawn_swaybg(char **command) { - if (config->swaybg_client != NULL) { - wl_client_destroy(config->swaybg_client); - } - int sockets[2]; - if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) != 0) { - sway_log_errno(SWAY_ERROR, "socketpair failed"); - return false; - } - if (!sway_set_cloexec(sockets[0], true) || !sway_set_cloexec(sockets[1], true)) { - return false; - } - - config->swaybg_client = wl_client_create(server.wl_display, sockets[0]); - if (config->swaybg_client == NULL) { - sway_log_errno(SWAY_ERROR, "wl_client_create failed"); - return false; - } - - config->swaybg_client_destroy.notify = handle_swaybg_client_destroy; - wl_client_add_destroy_listener(config->swaybg_client, - &config->swaybg_client_destroy); - - pid_t pid = fork(); - if (pid < 0) { - sway_log_errno(SWAY_ERROR, "fork failed"); - return false; - } else if (pid == 0) { - restore_nofile_limit(); - - pid = fork(); - if (pid < 0) { - sway_log_errno(SWAY_ERROR, "fork failed"); - _exit(EXIT_FAILURE); - } else if (pid == 0) { - if (!sway_set_cloexec(sockets[1], false)) { - _exit(EXIT_FAILURE); - } - - char wayland_socket_str[16]; - snprintf(wayland_socket_str, sizeof(wayland_socket_str), - "%d", sockets[1]); - setenv("WAYLAND_SOCKET", wayland_socket_str, true); - - execvp(command[0], command); - sway_log_errno(SWAY_ERROR, "failed to execute '%s' " - "(background configuration probably not applied)", - command[0]); - _exit(EXIT_FAILURE); - } - _exit(EXIT_SUCCESS); - } - - if (close(sockets[1]) != 0) { - sway_log_errno(SWAY_ERROR, "close failed"); - return false; - } - int fork_status = 0; - if (waitpid(pid, &fork_status, 0) < 0) { - sway_log_errno(SWAY_ERROR, "waitpid failed"); - return false; - } - - return WIFEXITED(fork_status) && WEXITSTATUS(fork_status) == EXIT_SUCCESS; -} - -bool spawn_swaybg(void) { - if (!config->swaybg_command) { - return true; - } - - size_t length = 2; - for (int i = 0; i < config->output_configs->length; i++) { - struct output_config *oc = config->output_configs->items[i]; - if (!oc->background) { - continue; - } - if (strcmp(oc->background_option, "solid_color") == 0) { - length += 4; - } else if (oc->background_fallback) { - length += 8; - } else { - length += 6; - } - } - - char **cmd = calloc(length, sizeof(char *)); - if (!cmd) { - sway_log(SWAY_ERROR, "Failed to allocate spawn_swaybg command"); - return false; - } - - size_t i = 0; - cmd[i++] = config->swaybg_command; - for (int j = 0; j < config->output_configs->length; j++) { - struct output_config *oc = config->output_configs->items[j]; - if (!oc->background) { - continue; - } - if (strcmp(oc->background_option, "solid_color") == 0) { - cmd[i++] = "-o"; - cmd[i++] = oc->name; - cmd[i++] = "-c"; - cmd[i++] = oc->background; - } else { - cmd[i++] = "-o"; - cmd[i++] = oc->name; - cmd[i++] = "-i"; - cmd[i++] = oc->background; - cmd[i++] = "-m"; - cmd[i++] = oc->background_option; - if (oc->background_fallback) { - cmd[i++] = "-c"; - cmd[i++] = oc->background_fallback; - } - } - assert(i <= length); - } - - for (size_t k = 0; k < i; k++) { - sway_log(SWAY_DEBUG, "spawn_swaybg cmd[%zd] = %s", k, cmd[k]); - } - - bool result = _spawn_swaybg(cmd); - free(cmd); - return result; -} diff --git a/sway/config/seat.c b/sway/config/seat.c deleted file mode 100644 index 6d5d91ae4..000000000 --- a/sway/config/seat.c +++ /dev/null @@ -1,227 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include "sway/config.h" -#include "log.h" - -struct seat_config *new_seat_config(const char* name) { - struct seat_config *seat = calloc(1, sizeof(struct seat_config)); - if (!seat) { - sway_log(SWAY_DEBUG, "Unable to allocate seat config"); - return NULL; - } - - seat->name = strdup(name); - if (!sway_assert(seat->name, "could not allocate name for seat")) { - free(seat); - return NULL; - } - - seat->idle_inhibit_sources = seat->idle_wake_sources = UINT32_MAX; - - seat->fallback = -1; - seat->attachments = create_list(); - if (!sway_assert(seat->attachments, - "could not allocate seat attachments list")) { - free(seat->name); - free(seat); - return NULL; - } - seat->hide_cursor_timeout = -1; - seat->hide_cursor_when_typing = HIDE_WHEN_TYPING_DEFAULT; - seat->allow_constrain = CONSTRAIN_DEFAULT; - seat->shortcuts_inhibit = SHORTCUTS_INHIBIT_DEFAULT; - seat->keyboard_grouping = KEYBOARD_GROUP_DEFAULT; - seat->xcursor_theme.name = NULL; - seat->xcursor_theme.size = 24; - - return seat; -} - -static void merge_wildcard_on_all(struct seat_config *wildcard) { - for (int i = 0; i < config->seat_configs->length; i++) { - struct seat_config *sc = config->seat_configs->items[i]; - if (strcmp(wildcard->name, sc->name) != 0) { - sway_log(SWAY_DEBUG, "Merging seat * config on %s", sc->name); - merge_seat_config(sc, wildcard); - } - } -} - -struct seat_config *store_seat_config(struct seat_config *sc) { - bool wildcard = strcmp(sc->name, "*") == 0; - if (wildcard) { - merge_wildcard_on_all(sc); - } - - int i = list_seq_find(config->seat_configs, seat_name_cmp, sc->name); - if (i >= 0) { - sway_log(SWAY_DEBUG, "Merging on top of existing seat config"); - struct seat_config *current = config->seat_configs->items[i]; - merge_seat_config(current, sc); - free_seat_config(sc); - sc = current; - } else if (!wildcard) { - sway_log(SWAY_DEBUG, "Adding non-wildcard seat config"); - i = list_seq_find(config->seat_configs, seat_name_cmp, "*"); - if (i >= 0) { - sway_log(SWAY_DEBUG, "Merging on top of seat * config"); - struct seat_config *current = new_seat_config(sc->name); - merge_seat_config(current, config->seat_configs->items[i]); - merge_seat_config(current, sc); - free_seat_config(sc); - sc = current; - } - list_add(config->seat_configs, sc); - } else { - // New wildcard config. Just add it - sway_log(SWAY_DEBUG, "Adding seat * config"); - list_add(config->seat_configs, sc); - } - - sway_log(SWAY_DEBUG, "Config stored for seat %s", sc->name); - - return sc; -} - -struct seat_attachment_config *seat_attachment_config_new(void) { - struct seat_attachment_config *attachment = - calloc(1, sizeof(struct seat_attachment_config)); - if (!attachment) { - sway_log(SWAY_DEBUG, "cannot allocate attachment config"); - return NULL; - } - return attachment; -} - -static void seat_attachment_config_free( - struct seat_attachment_config *attachment) { - free(attachment->identifier); - free(attachment); -} - -static struct seat_attachment_config *seat_attachment_config_copy( - struct seat_attachment_config *attachment) { - struct seat_attachment_config *copy = seat_attachment_config_new(); - if (!copy) { - return NULL; - } - - copy->identifier = strdup(attachment->identifier); - - return copy; -} - -static void merge_seat_attachment_config(struct seat_attachment_config *dest, - struct seat_attachment_config *source) { - // nothing to merge yet, but there will be some day -} - -void merge_seat_config(struct seat_config *dest, struct seat_config *source) { - if (source->fallback != -1) { - dest->fallback = source->fallback; - } - - for (int i = 0; i < source->attachments->length; ++i) { - struct seat_attachment_config *source_attachment = - source->attachments->items[i]; - bool found = false; - for (int j = 0; j < dest->attachments->length; ++j) { - struct seat_attachment_config *dest_attachment = - dest->attachments->items[j]; - if (strcmp(source_attachment->identifier, - dest_attachment->identifier) == 0) { - merge_seat_attachment_config(dest_attachment, - source_attachment); - found = true; - } - } - - if (!found) { - struct seat_attachment_config *copy = - seat_attachment_config_copy(source_attachment); - if (copy) { - list_add(dest->attachments, copy); - } - } - } - - if (source->hide_cursor_timeout != -1) { - dest->hide_cursor_timeout = source->hide_cursor_timeout; - } - - if (source->hide_cursor_when_typing != HIDE_WHEN_TYPING_DEFAULT) { - dest->hide_cursor_when_typing = source->hide_cursor_when_typing; - } - - if (source->allow_constrain != CONSTRAIN_DEFAULT) { - dest->allow_constrain = source->allow_constrain; - } - - if (source->shortcuts_inhibit != SHORTCUTS_INHIBIT_DEFAULT) { - dest->shortcuts_inhibit = source->shortcuts_inhibit; - } - - if (source->keyboard_grouping != KEYBOARD_GROUP_DEFAULT) { - dest->keyboard_grouping = source->keyboard_grouping; - } - - if (source->xcursor_theme.name != NULL) { - free(dest->xcursor_theme.name); - dest->xcursor_theme.name = strdup(source->xcursor_theme.name); - dest->xcursor_theme.size = source->xcursor_theme.size; - } - - if (source->idle_inhibit_sources != UINT32_MAX) { - dest->idle_inhibit_sources = source->idle_inhibit_sources; - } - - if (source->idle_wake_sources != UINT32_MAX) { - dest->idle_wake_sources = source->idle_wake_sources; - } -} - -struct seat_config *copy_seat_config(struct seat_config *seat) { - struct seat_config *copy = new_seat_config(seat->name); - if (copy == NULL) { - return NULL; - } - - merge_seat_config(copy, seat); - - return copy; -} - -void free_seat_config(struct seat_config *seat) { - if (!seat) { - return; - } - - free(seat->name); - for (int i = 0; i < seat->attachments->length; ++i) { - seat_attachment_config_free(seat->attachments->items[i]); - } - list_free(seat->attachments); - free(seat->xcursor_theme.name); - free(seat); -} - -int seat_name_cmp(const void *item, const void *data) { - const struct seat_config *sc = item; - const char *name = data; - return strcmp(sc->name, name); -} - -struct seat_attachment_config *seat_config_get_attachment( - struct seat_config *seat_config, char *identifier) { - for (int i = 0; i < seat_config->attachments->length; ++i) { - struct seat_attachment_config *attachment = - seat_config->attachments->items[i]; - if (strcmp(attachment->identifier, identifier) == 0) { - return attachment; - } - } - - return NULL; -} diff --git a/sway/criteria.c b/sway/criteria.c deleted file mode 100644 index 78ea8b8a4..000000000 --- a/sway/criteria.c +++ /dev/null @@ -1,792 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#define PCRE2_CODE_UNIT_WIDTH 8 -#include -#include "sway/criteria.h" -#include "sway/tree/container.h" -#include "sway/config.h" -#include "sway/tree/root.h" -#include "sway/tree/view.h" -#include "sway/tree/workspace.h" -#include "stringop.h" -#include "list.h" -#include "log.h" -#include "config.h" - -bool criteria_is_empty(struct criteria *criteria) { - return !criteria->title - && !criteria->shell - && !criteria->all - && !criteria->app_id - && !criteria->con_mark - && !criteria->con_id -#if HAVE_XWAYLAND - && !criteria->class - && !criteria->id - && !criteria->instance - && !criteria->window_role - && criteria->window_type == ATOM_LAST -#endif - && !criteria->floating - && !criteria->tiling - && !criteria->urgent - && !criteria->workspace - && !criteria->pid; -} - -// The error pointer is used for parsing functions, and saves having to pass it -// as an argument in several places. -char *error = NULL; - -// Returns error string on failure or NULL otherwise. -static bool generate_regex(pcre2_code **regex, char *value) { - int errorcode; - PCRE2_SIZE offset; - - *regex = pcre2_compile((PCRE2_SPTR)value, PCRE2_ZERO_TERMINATED, PCRE2_UTF | PCRE2_UCP, &errorcode, &offset, NULL); - if (!*regex) { - PCRE2_UCHAR buffer[256]; - pcre2_get_error_message(errorcode, buffer, sizeof(buffer)); - - const char *fmt = "Regex compilation for '%s' failed: %s"; - int len = strlen(fmt) + strlen(value) + strlen((char*) buffer) - 3; - error = malloc(len); - snprintf(error, len, fmt, value, buffer); - return false; - } - - return true; -} - -static bool pattern_create(struct pattern **pattern, char *value) { - *pattern = calloc(1, sizeof(struct pattern)); - if (!*pattern) { - sway_log(SWAY_ERROR, "Failed to allocate pattern"); - } - - if (strcmp(value, "__focused__") == 0) { - (*pattern)->match_type = PATTERN_FOCUSED; - } else { - (*pattern)->match_type = PATTERN_PCRE2; - if (!generate_regex(&(*pattern)->regex, value)) { - return false; - }; - } - return true; -} - -static void pattern_destroy(struct pattern *pattern) { - if (pattern) { - if (pattern->regex) { - pcre2_code_free(pattern->regex); - } - free(pattern); - } -} - -void criteria_destroy(struct criteria *criteria) { - pattern_destroy(criteria->title); - pattern_destroy(criteria->shell); - pattern_destroy(criteria->app_id); -#if HAVE_XWAYLAND - pattern_destroy(criteria->class); - pattern_destroy(criteria->instance); - pattern_destroy(criteria->window_role); -#endif - pattern_destroy(criteria->con_mark); - pattern_destroy(criteria->workspace); - free(criteria->target); - free(criteria->cmdlist); - free(criteria->raw); - free(criteria); -} - -static int regex_cmp(const char *item, const pcre2_code *regex) { - pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(regex, NULL); - int result = pcre2_match(regex, (PCRE2_SPTR)item, strlen(item), 0, 0, match_data, NULL); - pcre2_match_data_free(match_data); - return result; -} - -#if HAVE_XWAYLAND -static bool view_has_window_type(struct sway_view *view, enum atom_name name) { - if (view->type != SWAY_VIEW_XWAYLAND) { - return false; - } - struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface; - struct sway_xwayland *xwayland = &server.xwayland; - xcb_atom_t desired_atom = xwayland->atoms[name]; - for (size_t i = 0; i < surface->window_type_len; ++i) { - if (surface->window_type[i] == desired_atom) { - return true; - } - } - return false; -} -#endif - -static int cmp_urgent(const void *_a, const void *_b) { - struct sway_view *a = *(void **)_a; - struct sway_view *b = *(void **)_b; - - if (a->urgent.tv_sec < b->urgent.tv_sec) { - return -1; - } else if (a->urgent.tv_sec > b->urgent.tv_sec) { - return 1; - } - if (a->urgent.tv_nsec < b->urgent.tv_nsec) { - return -1; - } else if (a->urgent.tv_nsec > b->urgent.tv_nsec) { - return 1; - } - return 0; -} - -static void find_urgent_iterator(struct sway_container *con, void *data) { - if (!con->view || !view_is_urgent(con->view)) { - return; - } - list_t *urgent_views = data; - list_add(urgent_views, con->view); -} - -static bool has_container_criteria(struct criteria *criteria) { - return criteria->con_mark || criteria->con_id; -} - -static bool criteria_matches_container(struct criteria *criteria, - struct sway_container *container) { - if (criteria->con_mark) { - bool exists = false; - struct sway_container *con = container; - for (int i = 0; i < con->marks->length; ++i) { - if (regex_cmp(con->marks->items[i], criteria->con_mark->regex) >= 0) { - exists = true; - break; - } - } - if (!exists) { - return false; - } - } - - if (criteria->con_id) { // Internal ID - if (container->node.id != criteria->con_id) { - return false; - } - } - - return true; -} - -static bool criteria_matches_view(struct criteria *criteria, - struct sway_view *view) { - struct sway_seat *seat = input_manager_current_seat(); - struct sway_container *focus = seat_get_focused_container(seat); - struct sway_view *focused = focus ? focus->view : NULL; - - if (criteria->title) { - const char *title = view_get_title(view); - if (!title) { - title = ""; - } - - switch (criteria->title->match_type) { - case PATTERN_FOCUSED: - if (focused && lenient_strcmp(title, view_get_title(focused))) { - return false; - } - break; - case PATTERN_PCRE2: - if (regex_cmp(title, criteria->title->regex) < 0) { - return false; - } - break; - } - } - - if (criteria->shell) { - const char *shell = view_get_shell(view); - if (!shell) { - shell = ""; - } - - switch (criteria->shell->match_type) { - case PATTERN_FOCUSED: - if (focused && strcmp(shell, view_get_shell(focused))) { - return false; - } - break; - case PATTERN_PCRE2: - if (regex_cmp(shell, criteria->shell->regex) < 0) { - return false; - } - break; - } - } - - if (criteria->app_id) { - const char *app_id = view_get_app_id(view); - if (!app_id) { - app_id = ""; - } - - switch (criteria->app_id->match_type) { - case PATTERN_FOCUSED: - if (focused && lenient_strcmp(app_id, view_get_app_id(focused))) { - return false; - } - break; - case PATTERN_PCRE2: - if (regex_cmp(app_id, criteria->app_id->regex) < 0) { - return false; - } - break; - } - } - - if (!criteria_matches_container(criteria, view->container)) { - return false; - } - -#if HAVE_XWAYLAND - if (criteria->id) { // X11 window ID - uint32_t x11_window_id = view_get_x11_window_id(view); - if (!x11_window_id || x11_window_id != criteria->id) { - return false; - } - } - - if (criteria->class) { - const char *class = view_get_class(view); - if (!class) { - class = ""; - } - - switch (criteria->class->match_type) { - case PATTERN_FOCUSED: - if (focused && lenient_strcmp(class, view_get_class(focused))) { - return false; - } - break; - case PATTERN_PCRE2: - if (regex_cmp(class, criteria->class->regex) < 0) { - return false; - } - break; - } - } - - if (criteria->instance) { - const char *instance = view_get_instance(view); - if (!instance) { - instance = ""; - } - - switch (criteria->instance->match_type) { - case PATTERN_FOCUSED: - if (focused && lenient_strcmp(instance, view_get_instance(focused))) { - return false; - } - break; - case PATTERN_PCRE2: - if (regex_cmp(instance, criteria->instance->regex) < 0) { - return false; - } - break; - } - } - - if (criteria->window_role) { - const char *window_role = view_get_window_role(view); - if (!window_role) { - window_role = ""; - } - - switch (criteria->window_role->match_type) { - case PATTERN_FOCUSED: - if (focused && lenient_strcmp(window_role, view_get_window_role(focused))) { - return false; - } - break; - case PATTERN_PCRE2: - if (regex_cmp(window_role, criteria->window_role->regex) < 0) { - return false; - } - break; - } - } - - if (criteria->window_type != ATOM_LAST) { - if (!view_has_window_type(view, criteria->window_type)) { - return false; - } - } -#endif - - if (criteria->floating) { - if (!container_is_floating(view->container)) { - return false; - } - } - - if (criteria->tiling) { - if (container_is_floating(view->container)) { - return false; - } - } - - if (criteria->urgent) { - if (!view_is_urgent(view)) { - return false; - } - list_t *urgent_views = create_list(); - root_for_each_container(find_urgent_iterator, urgent_views); - list_stable_sort(urgent_views, cmp_urgent); - struct sway_view *target; - if (criteria->urgent == 'o') { // oldest - target = urgent_views->items[0]; - } else { // latest - target = urgent_views->items[urgent_views->length - 1]; - } - list_free(urgent_views); - if (view != target) { - return false; - } - } - - if (criteria->workspace) { - struct sway_workspace *ws = view->container->pending.workspace; - if (!ws) { - return false; - } - - switch (criteria->workspace->match_type) { - case PATTERN_FOCUSED: - if (focused && - strcmp(ws->name, focused->container->pending.workspace->name)) { - return false; - } - break; - case PATTERN_PCRE2: - if (regex_cmp(ws->name, criteria->workspace->regex) < 0) { - return false; - } - break; - } - } - - if (criteria->pid) { - if (criteria->pid != view->pid) { - return false; - } - } - - return true; -} - -list_t *criteria_for_view(struct sway_view *view, enum criteria_type types) { - list_t *criterias = config->criteria; - list_t *matches = create_list(); - for (int i = 0; i < criterias->length; ++i) { - struct criteria *criteria = criterias->items[i]; - if ((criteria->type & types) && criteria_matches_view(criteria, view)) { - list_add(matches, criteria); - } - } - return matches; -} - -struct match_data { - struct criteria *criteria; - list_t *matches; -}; - -static void criteria_get_containers_iterator(struct sway_container *container, - void *data) { - struct match_data *match_data = data; - if (container->view) { - if (criteria_matches_view(match_data->criteria, container->view)) { - list_add(match_data->matches, container); - } - } else if (has_container_criteria(match_data->criteria)) { - if (criteria_matches_container(match_data->criteria, container)) { - list_add(match_data->matches, container); - } - } -} - -list_t *criteria_get_containers(struct criteria *criteria) { - list_t *matches = create_list(); - struct match_data data = { - .criteria = criteria, - .matches = matches, - }; - root_for_each_container(criteria_get_containers_iterator, &data); - return matches; -} - -#if HAVE_XWAYLAND -static enum atom_name parse_window_type(const char *type) { - if (strcasecmp(type, "normal") == 0) { - return NET_WM_WINDOW_TYPE_NORMAL; - } else if (strcasecmp(type, "dialog") == 0) { - return NET_WM_WINDOW_TYPE_DIALOG; - } else if (strcasecmp(type, "utility") == 0) { - return NET_WM_WINDOW_TYPE_UTILITY; - } else if (strcasecmp(type, "toolbar") == 0) { - return NET_WM_WINDOW_TYPE_TOOLBAR; - } else if (strcasecmp(type, "splash") == 0) { - return NET_WM_WINDOW_TYPE_SPLASH; - } else if (strcasecmp(type, "menu") == 0) { - return NET_WM_WINDOW_TYPE_MENU; - } else if (strcasecmp(type, "dropdown_menu") == 0) { - return NET_WM_WINDOW_TYPE_DROPDOWN_MENU; - } else if (strcasecmp(type, "popup_menu") == 0) { - return NET_WM_WINDOW_TYPE_POPUP_MENU; - } else if (strcasecmp(type, "tooltip") == 0) { - return NET_WM_WINDOW_TYPE_TOOLTIP; - } else if (strcasecmp(type, "notification") == 0) { - return NET_WM_WINDOW_TYPE_NOTIFICATION; - } - return ATOM_LAST; // ie. invalid -} -#endif - -enum criteria_token { - T_ALL, - T_APP_ID, - T_CON_ID, - T_CON_MARK, - T_FLOATING, -#if HAVE_XWAYLAND - T_CLASS, - T_ID, - T_INSTANCE, - T_WINDOW_ROLE, - T_WINDOW_TYPE, -#endif - T_SHELL, - T_TILING, - T_TITLE, - T_URGENT, - T_WORKSPACE, - T_PID, - - T_INVALID, -}; - -static enum criteria_token token_from_name(char *name) { - if (strcmp(name, "all") == 0) { - return T_ALL; - } else if (strcmp(name, "app_id") == 0) { - return T_APP_ID; - } else if (strcmp(name, "con_id") == 0) { - return T_CON_ID; - } else if (strcmp(name, "con_mark") == 0) { - return T_CON_MARK; -#if HAVE_XWAYLAND - } else if (strcmp(name, "class") == 0) { - return T_CLASS; - } else if (strcmp(name, "id") == 0) { - return T_ID; - } else if (strcmp(name, "instance") == 0) { - return T_INSTANCE; - } else if (strcmp(name, "window_role") == 0) { - return T_WINDOW_ROLE; - } else if (strcmp(name, "window_type") == 0) { - return T_WINDOW_TYPE; -#endif - } else if (strcmp(name, "shell") == 0) { - return T_SHELL; - } else if (strcmp(name, "title") == 0) { - return T_TITLE; - } else if (strcmp(name, "urgent") == 0) { - return T_URGENT; - } else if (strcmp(name, "workspace") == 0) { - return T_WORKSPACE; - } else if (strcmp(name, "tiling") == 0) { - return T_TILING; - } else if (strcmp(name, "floating") == 0) { - return T_FLOATING; - } else if (strcmp(name, "pid") == 0) { - return T_PID; - } - return T_INVALID; -} - -static bool parse_token(struct criteria *criteria, char *name, char *value) { - enum criteria_token token = token_from_name(name); - if (token == T_INVALID) { - const char *fmt = "Token '%s' is not recognized"; - int len = strlen(fmt) + strlen(name) - 1; - error = malloc(len); - snprintf(error, len, fmt, name); - return false; - } - - // Require value, unless token is all, floating or tiled - if (!value && token != T_ALL && token != T_FLOATING && token != T_TILING) { - const char *fmt = "Token '%s' requires a value"; - int len = strlen(fmt) + strlen(name) - 1; - error = malloc(len); - snprintf(error, len, fmt, name); - return false; - } - - char *endptr = NULL; - switch (token) { - case T_ALL: - criteria->all = true; - break; - case T_TITLE: - pattern_create(&criteria->title, value); - break; - case T_SHELL: - pattern_create(&criteria->shell, value); - break; - case T_APP_ID: - pattern_create(&criteria->app_id, value); - break; - case T_CON_ID: - if (strcmp(value, "__focused__") == 0) { - struct sway_seat *seat = input_manager_current_seat(); - struct sway_container *focus = seat_get_focused_container(seat); - struct sway_view *view = focus ? focus->view : NULL; - criteria->con_id = view ? view->container->node.id : 0; - } else { - criteria->con_id = strtoul(value, &endptr, 10); - if (*endptr != 0) { - error = strdup("The value for 'con_id' should be '__focused__' or numeric"); - } - } - break; - case T_CON_MARK: - pattern_create(&criteria->con_mark, value); - break; -#if HAVE_XWAYLAND - case T_CLASS: - pattern_create(&criteria->class, value); - break; - case T_ID: - criteria->id = strtoul(value, &endptr, 10); - if (*endptr != 0) { - error = strdup("The value for 'id' should be numeric"); - } - break; - case T_INSTANCE: - pattern_create(&criteria->instance, value); - break; - case T_WINDOW_ROLE: - pattern_create(&criteria->window_role, value); - break; - case T_WINDOW_TYPE: - criteria->window_type = parse_window_type(value); - break; -#endif - case T_FLOATING: - criteria->floating = true; - break; - case T_TILING: - criteria->tiling = true; - break; - case T_URGENT: - if (strcmp(value, "latest") == 0 || - strcmp(value, "newest") == 0 || - strcmp(value, "last") == 0 || - strcmp(value, "recent") == 0) { - criteria->urgent = 'l'; - } else if (strcmp(value, "oldest") == 0 || - strcmp(value, "first") == 0) { - criteria->urgent = 'o'; - } else { - error = - strdup("The value for 'urgent' must be 'first', 'last', " - "'latest', 'newest', 'oldest' or 'recent'"); - } - break; - case T_WORKSPACE: - pattern_create(&criteria->workspace, value); - break; - case T_PID: - criteria->pid = strtoul(value, &endptr, 10); - if (*endptr != 0) { - error = strdup("The value for 'pid' should be numeric"); - } - break; - case T_INVALID: - break; - } - - if (error) { - return false; - } - - return true; -} - -static void skip_spaces(char **head) { - while (**head == ' ') { - ++*head; - } -} - -// Remove escaping slashes from value -static void unescape(char *value) { - if (!strchr(value, '\\')) { - return; - } - char *copy = calloc(strlen(value) + 1, 1); - char *readhead = value; - char *writehead = copy; - while (*readhead) { - if (*readhead == '\\' && *(readhead + 1) == '"') { - // skip the slash - ++readhead; - } - *writehead = *readhead; - ++writehead; - ++readhead; - } - strcpy(value, copy); - free(copy); -} - -/** - * Parse a raw criteria string such as [class="foo" instance="bar"] into a - * criteria struct. - * - * If errors are found, NULL will be returned and the error argument will be - * populated with an error string. It is up to the caller to free the error. - */ -struct criteria *criteria_parse(char *raw, char **error_arg) { - *error_arg = NULL; - error = NULL; - - char *head = raw; - skip_spaces(&head); - if (*head != '[') { - *error_arg = strdup("No criteria"); - return NULL; - } - ++head; - - struct criteria *criteria = calloc(1, sizeof(struct criteria)); -#if HAVE_XWAYLAND - criteria->window_type = ATOM_LAST; // default value -#endif - char *name = NULL, *value = NULL; - bool in_quotes = false; - - while (*head && *head != ']') { - skip_spaces(&head); - // Parse token name - char *namestart = head; - while ((*head >= 'a' && *head <= 'z') || *head == '_') { - ++head; - } - name = calloc(head - namestart + 1, 1); - if (head != namestart) { - memcpy(name, namestart, head - namestart); - } - // Parse token value - skip_spaces(&head); - value = NULL; - if (*head == '=') { - ++head; - skip_spaces(&head); - if (*head == '"') { - in_quotes = true; - ++head; - } - char *valuestart = head; - if (in_quotes) { - while (*head && (*head != '"' || *(head - 1) == '\\')) { - ++head; - } - if (!*head) { - *error_arg = strdup("Quote mismatch in criteria"); - goto cleanup; - } - } else { - while (*head && *head != ' ' && *head != ']') { - ++head; - } - } - value = calloc(head - valuestart + 1, 1); - memcpy(value, valuestart, head - valuestart); - if (in_quotes) { - ++head; - in_quotes = false; - } - unescape(value); - sway_log(SWAY_DEBUG, "Found pair: %s=%s", name, value); - } - if (!parse_token(criteria, name, value)) { - *error_arg = error; - goto cleanup; - } - skip_spaces(&head); - free(name); - free(value); - name = NULL; - value = NULL; - } - if (*head != ']') { - *error_arg = strdup("No closing brace found in criteria"); - goto cleanup; - } - - if (criteria_is_empty(criteria)) { - *error_arg = strdup("Criteria is empty"); - goto cleanup; - } - - ++head; - int len = head - raw; - criteria->raw = calloc(len + 1, 1); - memcpy(criteria->raw, raw, len); - return criteria; - -cleanup: - free(name); - free(value); - criteria_destroy(criteria); - return NULL; -} - -bool criteria_is_equal(struct criteria *left, struct criteria *right) { - if (left->type != right->type) { - return false; - } - // XXX Only implemented for CT_NO_FOCUS for now. - if (left->type == CT_NO_FOCUS) { - return strcmp(left->raw, right->raw) == 0; - } - if (left->type == CT_COMMAND) { - return strcmp(left->raw, right->raw) == 0 - && strcmp(left->cmdlist, right->cmdlist) == 0; - } - return false; -} - -bool criteria_already_exists(struct criteria *criteria) { - // XXX Only implemented for CT_NO_FOCUS and CT_COMMAND for now. - // While criteria_is_equal also obeys this limitation, this is a shortcut - // to avoid processing the list. - if (criteria->type != CT_NO_FOCUS && criteria->type != CT_COMMAND) { - return false; - } - - list_t *criterias = config->criteria; - for (int i = 0; i < criterias->length; ++i) { - struct criteria *existing = criterias->items[i]; - if (criteria_is_equal(criteria, existing)) { - return true; - } - } - return false; -} diff --git a/sway/decoration.c b/sway/decoration.c deleted file mode 100644 index 849fa89c9..000000000 --- a/sway/decoration.c +++ /dev/null @@ -1,65 +0,0 @@ -#include -#include "sway/decoration.h" -#include "sway/desktop/transaction.h" -#include "sway/server.h" -#include "sway/tree/arrange.h" -#include "sway/tree/view.h" -#include "log.h" - -static void server_decoration_handle_destroy(struct wl_listener *listener, - void *data) { - struct sway_server_decoration *deco = - wl_container_of(listener, deco, destroy); - wl_list_remove(&deco->destroy.link); - wl_list_remove(&deco->mode.link); - wl_list_remove(&deco->link); - free(deco); -} - -static void server_decoration_handle_mode(struct wl_listener *listener, - void *data) { - struct sway_server_decoration *deco = - wl_container_of(listener, deco, mode); - struct sway_view *view = - view_from_wlr_surface(deco->wlr_server_decoration->surface); - if (view == NULL || view->surface != deco->wlr_server_decoration->surface) { - return; - } - - bool csd = deco->wlr_server_decoration->mode == - WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT; - view_update_csd_from_client(view, csd); - - arrange_container(view->container); - transaction_commit_dirty(); -} - -void handle_server_decoration(struct wl_listener *listener, void *data) { - struct wlr_server_decoration *wlr_deco = data; - - struct sway_server_decoration *deco = calloc(1, sizeof(*deco)); - if (deco == NULL) { - return; - } - - deco->wlr_server_decoration = wlr_deco; - - wl_signal_add(&wlr_deco->events.destroy, &deco->destroy); - deco->destroy.notify = server_decoration_handle_destroy; - - wl_signal_add(&wlr_deco->events.mode, &deco->mode); - deco->mode.notify = server_decoration_handle_mode; - - wl_list_insert(&server.decorations, &deco->link); -} - -struct sway_server_decoration *decoration_from_surface( - struct wlr_surface *surface) { - struct sway_server_decoration *deco; - wl_list_for_each(deco, &server.decorations, link) { - if (deco->wlr_server_decoration->surface == surface) { - return deco; - } - } - return NULL; -} diff --git a/sway/desktop/desktop.c b/sway/desktop/desktop.c deleted file mode 100644 index c8d4502cd..000000000 --- a/sway/desktop/desktop.c +++ /dev/null @@ -1,40 +0,0 @@ -#include "sway/tree/container.h" -#include "sway/desktop.h" -#include "sway/output.h" - -void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly, - bool whole) { - for (int i = 0; i < root->outputs->length; ++i) { - struct sway_output *output = root->outputs->items[i]; - struct wlr_box output_box; - wlr_output_layout_get_box(root->output_layout, - output->wlr_output, &output_box); - output_damage_surface(output, lx - output_box.x, - ly - output_box.y, surface, whole); - } -} - -void desktop_damage_whole_container(struct sway_container *con) { - for (int i = 0; i < root->outputs->length; ++i) { - struct sway_output *output = root->outputs->items[i]; - output_damage_whole_container(output, con); - } -} - -void desktop_damage_box(struct wlr_box *box) { - for (int i = 0; i < root->outputs->length; ++i) { - struct sway_output *output = root->outputs->items[i]; - output_damage_box(output, box); - } -} - -void desktop_damage_view(struct sway_view *view) { - desktop_damage_whole_container(view->container); - struct wlr_box box = { - .x = view->container->current.content_x - view->geometry.x, - .y = view->container->current.content_y - view->geometry.y, - .width = view->surface->current.width, - .height = view->surface->current.height, - }; - desktop_damage_box(&box); -} diff --git a/sway/desktop/idle_inhibit_v1.c b/sway/desktop/idle_inhibit_v1.c deleted file mode 100644 index f3af7aa1b..000000000 --- a/sway/desktop/idle_inhibit_v1.c +++ /dev/null @@ -1,159 +0,0 @@ -#include -#include -#include "log.h" -#include "sway/desktop/idle_inhibit_v1.h" -#include "sway/input/seat.h" -#include "sway/tree/container.h" -#include "sway/tree/view.h" -#include "sway/server.h" - - -static void destroy_inhibitor(struct sway_idle_inhibitor_v1 *inhibitor) { - wl_list_remove(&inhibitor->link); - wl_list_remove(&inhibitor->destroy.link); - sway_idle_inhibit_v1_check_active(); - free(inhibitor); -} - -static void handle_destroy(struct wl_listener *listener, void *data) { - struct sway_idle_inhibitor_v1 *inhibitor = - wl_container_of(listener, inhibitor, destroy); - sway_log(SWAY_DEBUG, "Sway idle inhibitor destroyed"); - destroy_inhibitor(inhibitor); -} - -void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) { - struct wlr_idle_inhibitor_v1 *wlr_inhibitor = data; - struct sway_idle_inhibit_manager_v1 *manager = - wl_container_of(listener, manager, new_idle_inhibitor_v1); - sway_log(SWAY_DEBUG, "New sway idle inhibitor"); - - struct sway_idle_inhibitor_v1 *inhibitor = - calloc(1, sizeof(struct sway_idle_inhibitor_v1)); - if (!inhibitor) { - return; - } - - inhibitor->mode = INHIBIT_IDLE_APPLICATION; - inhibitor->wlr_inhibitor = wlr_inhibitor; - wl_list_insert(&manager->inhibitors, &inhibitor->link); - - inhibitor->destroy.notify = handle_destroy; - wl_signal_add(&wlr_inhibitor->events.destroy, &inhibitor->destroy); - - sway_idle_inhibit_v1_check_active(); -} - -void sway_idle_inhibit_v1_user_inhibitor_register(struct sway_view *view, - enum sway_idle_inhibit_mode mode) { - struct sway_idle_inhibit_manager_v1 *manager = &server.idle_inhibit_manager_v1; - - struct sway_idle_inhibitor_v1 *inhibitor = - calloc(1, sizeof(struct sway_idle_inhibitor_v1)); - if (!inhibitor) { - return; - } - - inhibitor->mode = mode; - inhibitor->view = view; - wl_list_insert(&manager->inhibitors, &inhibitor->link); - - inhibitor->destroy.notify = handle_destroy; - wl_signal_add(&view->events.unmap, &inhibitor->destroy); - - sway_idle_inhibit_v1_check_active(); -} - -struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_user_inhibitor_for_view( - struct sway_view *view) { - struct sway_idle_inhibit_manager_v1 *manager = &server.idle_inhibit_manager_v1; - struct sway_idle_inhibitor_v1 *inhibitor; - wl_list_for_each(inhibitor, &manager->inhibitors, link) { - if (inhibitor->mode != INHIBIT_IDLE_APPLICATION && - inhibitor->view == view) { - return inhibitor; - } - } - return NULL; -} - -struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_application_inhibitor_for_view( - struct sway_view *view) { - struct sway_idle_inhibit_manager_v1 *manager = &server.idle_inhibit_manager_v1; - struct sway_idle_inhibitor_v1 *inhibitor; - wl_list_for_each(inhibitor, &manager->inhibitors, link) { - if (inhibitor->mode == INHIBIT_IDLE_APPLICATION && - view_from_wlr_surface(inhibitor->wlr_inhibitor->surface) == view) { - return inhibitor; - } - } - return NULL; -} - -void sway_idle_inhibit_v1_user_inhibitor_destroy( - struct sway_idle_inhibitor_v1 *inhibitor) { - if (!inhibitor) { - return; - } - if (!sway_assert(inhibitor->mode != INHIBIT_IDLE_APPLICATION, - "User should not be able to destroy application inhibitor")) { - return; - } - destroy_inhibitor(inhibitor); -} - -bool sway_idle_inhibit_v1_is_active(struct sway_idle_inhibitor_v1 *inhibitor) { - switch (inhibitor->mode) { - case INHIBIT_IDLE_APPLICATION:; - // If there is no view associated with the inhibitor, assume visible - struct sway_view *view = view_from_wlr_surface(inhibitor->wlr_inhibitor->surface); - return !view || !view->container || view_is_visible(view); - case INHIBIT_IDLE_FOCUS:; - struct sway_seat *seat = NULL; - wl_list_for_each(seat, &server.input->seats, link) { - struct sway_container *con = seat_get_focused_container(seat); - if (con && con->view && con->view == inhibitor->view) { - return true; - } - } - return false; - case INHIBIT_IDLE_FULLSCREEN: - return inhibitor->view->container && - container_is_fullscreen_or_child(inhibitor->view->container) && - view_is_visible(inhibitor->view); - case INHIBIT_IDLE_OPEN: - // Inhibitor is destroyed on unmap so it must be open/mapped - return true; - case INHIBIT_IDLE_VISIBLE: - return view_is_visible(inhibitor->view); - } - return false; -} - -void sway_idle_inhibit_v1_check_active(void) { - struct sway_idle_inhibit_manager_v1 *manager = &server.idle_inhibit_manager_v1; - struct sway_idle_inhibitor_v1 *inhibitor; - bool inhibited = false; - wl_list_for_each(inhibitor, &manager->inhibitors, link) { - if ((inhibited = sway_idle_inhibit_v1_is_active(inhibitor))) { - break; - } - } - wlr_idle_notifier_v1_set_inhibited(server.idle_notifier_v1, inhibited); -} - -bool sway_idle_inhibit_manager_v1_init(void) { - struct sway_idle_inhibit_manager_v1 *manager = &server.idle_inhibit_manager_v1; - - manager->wlr_manager = wlr_idle_inhibit_v1_create(server.wl_display); - if (!manager->wlr_manager) { - return false; - } - - wl_signal_add(&manager->wlr_manager->events.new_inhibitor, - &manager->new_idle_inhibitor_v1); - manager->new_idle_inhibitor_v1.notify = handle_idle_inhibitor_v1; - wl_list_init(&manager->inhibitors); - - return true; -} diff --git a/sway/desktop/launcher.c b/sway/desktop/launcher.c deleted file mode 100644 index 0c02b997d..000000000 --- a/sway/desktop/launcher.c +++ /dev/null @@ -1,268 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include "sway/input/seat.h" -#include "sway/output.h" -#include "sway/desktop/launcher.h" -#include "sway/tree/node.h" -#include "sway/tree/container.h" -#include "sway/tree/workspace.h" -#include "sway/tree/root.h" -#include "log.h" - -/** - * Get the pid of a parent process given the pid of a child process. - * - * Returns the parent pid or NULL if the parent pid cannot be determined. - */ -static pid_t get_parent_pid(pid_t child) { - pid_t parent = -1; - char file_name[100]; - char *buffer = NULL; - const char *sep = " "; - FILE *stat = NULL; - size_t buf_size = 0; - - snprintf(file_name, sizeof(file_name), "/proc/%d/stat", child); - - if ((stat = fopen(file_name, "r"))) { - if (getline(&buffer, &buf_size, stat) != -1) { - strtok(buffer, sep); // pid - strtok(NULL, sep); // executable name - strtok(NULL, sep); // state - char *token = strtok(NULL, sep); // parent pid - parent = strtol(token, NULL, 10); - } - free(buffer); - fclose(stat); - } - - if (parent) { - return (parent == child) ? -1 : parent; - } - - return -1; -} - -void launcher_ctx_consume(struct launcher_ctx *ctx) { - // The view is now responsible for destroying this ctx - wl_list_remove(&ctx->token_destroy.link); - wl_list_init(&ctx->token_destroy.link); - - if (!ctx->activated) { - // An unactivated token hasn't been destroyed yet - wlr_xdg_activation_token_v1_destroy(ctx->token); - } - ctx->token = NULL; - - // Prevent additional matches - wl_list_remove(&ctx->link); - wl_list_init(&ctx->link); -} - -void launcher_ctx_destroy(struct launcher_ctx *ctx) { - if (ctx == NULL) { - return; - } - wl_list_remove(&ctx->node_destroy.link); - wl_list_remove(&ctx->token_destroy.link); - if (ctx->seat) { - wl_list_remove(&ctx->seat_destroy.link); - } - wl_list_remove(&ctx->link); - wlr_xdg_activation_token_v1_destroy(ctx->token); - free(ctx->fallback_name); - free(ctx); -} - -struct launcher_ctx *launcher_ctx_find_pid(pid_t pid) { - if (wl_list_empty(&server.pending_launcher_ctxs)) { - return NULL; - } - - struct launcher_ctx *ctx = NULL; - sway_log(SWAY_DEBUG, "Looking up workspace for pid %d", pid); - - do { - struct launcher_ctx *_ctx = NULL; - wl_list_for_each(_ctx, &server.pending_launcher_ctxs, link) { - if (pid == _ctx->pid) { - ctx = _ctx; - sway_log(SWAY_DEBUG, - "found %s match for pid %d: %s", - node_type_to_str(ctx->node->type), pid, node_get_name(ctx->node)); - break; - } - } - pid = get_parent_pid(pid); - } while (pid > 1); - - return ctx; -} - -struct sway_workspace *launcher_ctx_get_workspace( - struct launcher_ctx *ctx) { - struct sway_workspace *ws = NULL; - struct sway_output *output = NULL; - - switch (ctx->node->type) { - case N_CONTAINER: - // Unimplemented - // TODO: add container matching? - ws = ctx->node->sway_container->pending.workspace; - break; - case N_WORKSPACE: - ws = ctx->node->sway_workspace; - break; - case N_OUTPUT: - output = ctx->node->sway_output; - ws = workspace_by_name(ctx->fallback_name); - if (!ws) { - sway_log(SWAY_DEBUG, - "Creating workspace %s for pid %d because it disappeared", - ctx->fallback_name, ctx->pid); - if (!output->enabled) { - sway_log(SWAY_DEBUG, - "Workspace output %s is disabled, trying another one", - output->wlr_output->name); - output = NULL; - } - ws = workspace_create(output, ctx->fallback_name); - } - break; - case N_ROOT: - ws = workspace_create(NULL, ctx->fallback_name); - break; - } - - return ws; -} - -static void ctx_handle_node_destroy(struct wl_listener *listener, void *data) { - struct launcher_ctx *ctx = wl_container_of(listener, ctx, node_destroy); - switch (ctx->node->type) { - case N_CONTAINER: - // Unimplemented - break; - case N_WORKSPACE:; - struct sway_workspace *ws = ctx->node->sway_workspace; - wl_list_remove(&ctx->node_destroy.link); - wl_list_init(&ctx->node_destroy.link); - // We want to save this ws name to recreate later, hopefully on the - // same output - free(ctx->fallback_name); - ctx->fallback_name = strdup(ws->name); - if (!ws->output || ws->output->node.destroying) { - // If the output is being destroyed it would be pointless to track - // If the output is being disabled, we'll find out if it's still - // disabled when we try to match it. - ctx->node = &root->node; - break; - } - ctx->node = &ws->output->node; - wl_signal_add(&ctx->node->events.destroy, &ctx->node_destroy); - break; - case N_OUTPUT: - wl_list_remove(&ctx->node_destroy.link); - wl_list_init(&ctx->node_destroy.link); - // We'll make the ws ctx->name somewhere else - ctx->node = &root->node; - break; - case N_ROOT: - // Unreachable - break; - } -} - -static void token_handle_destroy(struct wl_listener *listener, void *data) { - struct launcher_ctx *ctx = wl_container_of(listener, ctx, token_destroy); - ctx->token = NULL; - launcher_ctx_destroy(ctx); -} - -struct launcher_ctx *launcher_ctx_create(struct wlr_xdg_activation_token_v1 *token, - struct sway_node *node) { - struct launcher_ctx *ctx = calloc(1, sizeof(struct launcher_ctx)); - - const char *fallback_name = NULL; - struct sway_workspace *ws = NULL; - switch (node->type) { - case N_CONTAINER: - // Unimplemented - free(ctx); - return NULL; - case N_WORKSPACE: - ws = node->sway_workspace; - fallback_name = ws->name; - break; - case N_OUTPUT:; - struct sway_output *output = node->sway_output; - ws = output_get_active_workspace(output); - fallback_name = ws ? ws->name : NULL; - break; - case N_ROOT: - // Unimplemented - free(ctx); - return NULL; - } - - if (!fallback_name) { - // TODO: implement a better fallback. - free(ctx); - return NULL; - } - - ctx->fallback_name = strdup(fallback_name); - ctx->token = token; - ctx->node = node; - // Having surface set means that the focus check in wlroots has passed - ctx->had_focused_surface = token->surface != NULL; - - ctx->node_destroy.notify = ctx_handle_node_destroy; - wl_signal_add(&ctx->node->events.destroy, &ctx->node_destroy); - - ctx->token_destroy.notify = token_handle_destroy; - wl_signal_add(&token->events.destroy, &ctx->token_destroy); - - wl_list_init(&ctx->link); - wl_list_insert(&server.pending_launcher_ctxs, &ctx->link); - - token->data = ctx; - return ctx; -} - -static void launch_ctx_handle_seat_destroy(struct wl_listener *listener, void *data) { - struct launcher_ctx *ctx = wl_container_of(listener, ctx, seat_destroy); - ctx->seat = NULL; - wl_list_remove(&ctx->seat_destroy.link); -} - -// Creates a context with a new token for the internal launcher -struct launcher_ctx *launcher_ctx_create_internal(void) { - struct sway_seat *seat = input_manager_current_seat(); - struct sway_workspace *ws = seat_get_focused_workspace(seat); - if (!ws) { - sway_log(SWAY_DEBUG, "Failed to create launch context. No workspace."); - return NULL; - } - - struct wlr_xdg_activation_token_v1 *token = - wlr_xdg_activation_token_v1_create(server.xdg_activation_v1); - - struct launcher_ctx *ctx = launcher_ctx_create(token, &ws->node); - if (!ctx) { - wlr_xdg_activation_token_v1_destroy(token); - return NULL; - } - ctx->seat = seat; - ctx->seat_destroy.notify = launch_ctx_handle_seat_destroy; - wl_signal_add(&seat->wlr_seat->events.destroy, &ctx->seat_destroy); - - return ctx; -} - -const char *launcher_ctx_get_token_name(struct launcher_ctx *ctx) { - const char *token = wlr_xdg_activation_token_v1_get_name(ctx->token); - return token; -} diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c deleted file mode 100644 index 814290536..000000000 --- a/sway/desktop/layer_shell.c +++ /dev/null @@ -1,773 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include "log.h" -#include "sway/layer_criteria.h" -#include "sway/desktop/transaction.h" -#include "sway/input/cursor.h" -#include "sway/input/input-manager.h" -#include "sway/input/seat.h" -#include "sway/layers.h" -#include "sway/output.h" -#include "sway/server.h" -#include "sway/surface.h" -#include "sway/tree/arrange.h" -#include "sway/tree/workspace.h" -#include "wlr-layer-shell-unstable-v1-protocol.h" - -struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface( - struct wlr_surface *surface) { - struct wlr_layer_surface_v1 *layer; - do { - if (!surface) { - return NULL; - } - // Topmost layer surface - if ((layer = wlr_layer_surface_v1_try_from_wlr_surface(surface))) { - return layer; - } - // Layer subsurface - if (wlr_subsurface_try_from_wlr_surface(surface)) { - surface = wlr_surface_get_root_surface(surface); - continue; - } - - // Layer surface popup - struct wlr_xdg_surface *xdg_surface = NULL; - if ((xdg_surface = wlr_xdg_surface_try_from_wlr_surface(surface)) && - xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP && xdg_surface->popup != NULL) { - if (!xdg_surface->popup->parent) { - return NULL; - } - surface = wlr_surface_get_root_surface(xdg_surface->popup->parent); - continue; - } - - // Return early if the surface is not a layer/xdg_popup/sub surface - return NULL; - } while (true); -} - -static void layer_parse_criteria(struct sway_layer_surface *sway_layer) { - enum zwlr_layer_shell_v1_layer layer = sway_layer->layer; - if (layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND) { - return; - } - - list_t *criterias = layer_criterias_for_sway_layer_surface(sway_layer); - for (int i = 0; i < criterias->length; i++) { - struct layer_criteria *criteria = criterias->items[i]; - layer_criteria_parse(sway_layer, criteria); - } - list_free(criterias); -} - -static void apply_exclusive(struct wlr_box *usable_area, - uint32_t anchor, int32_t exclusive, - int32_t margin_top, int32_t margin_right, - int32_t margin_bottom, int32_t margin_left) { - if (exclusive <= 0) { - return; - } - struct { - uint32_t singular_anchor; - uint32_t anchor_triplet; - int *positive_axis; - int *negative_axis; - int margin; - } edges[] = { - // Top - { - .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, - .anchor_triplet = - ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, - .positive_axis = &usable_area->y, - .negative_axis = &usable_area->height, - .margin = margin_top, - }, - // Bottom - { - .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, - .anchor_triplet = - ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, - .positive_axis = NULL, - .negative_axis = &usable_area->height, - .margin = margin_bottom, - }, - // Left - { - .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT, - .anchor_triplet = - ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, - .positive_axis = &usable_area->x, - .negative_axis = &usable_area->width, - .margin = margin_left, - }, - // Right - { - .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, - .anchor_triplet = - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, - .positive_axis = NULL, - .negative_axis = &usable_area->width, - .margin = margin_right, - }, - }; - for (size_t i = 0; i < sizeof(edges) / sizeof(edges[0]); ++i) { - if ((anchor == edges[i].singular_anchor || anchor == edges[i].anchor_triplet) - && exclusive + edges[i].margin > 0) { - if (edges[i].positive_axis) { - *edges[i].positive_axis += exclusive + edges[i].margin; - } - if (edges[i].negative_axis) { - *edges[i].negative_axis -= exclusive + edges[i].margin; - } - break; - } - } -} - -static void arrange_layer(struct sway_output *output, struct wl_list *list, - struct wlr_box *usable_area, bool exclusive) { - struct sway_layer_surface *sway_layer; - struct wlr_box full_area = { 0 }; - wlr_output_effective_resolution(output->wlr_output, - &full_area.width, &full_area.height); - wl_list_for_each(sway_layer, list, link) { - struct wlr_layer_surface_v1 *layer = sway_layer->layer_surface; - struct wlr_layer_surface_v1_state *state = &layer->current; - if (exclusive != (state->exclusive_zone > 0)) { - continue; - } - struct wlr_box bounds; - if (state->exclusive_zone == -1) { - bounds = full_area; - } else { - bounds = *usable_area; - } - struct wlr_box box = { - .width = state->desired_width, - .height = state->desired_height - }; - // Horizontal axis - const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT - | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; - if (box.width == 0) { - box.x = bounds.x; - } else if ((state->anchor & both_horiz) == both_horiz) { - box.x = bounds.x + ((bounds.width / 2) - (box.width / 2)); - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { - box.x = bounds.x; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { - box.x = bounds.x + (bounds.width - box.width); - } else { - box.x = bounds.x + ((bounds.width / 2) - (box.width / 2)); - } - // Vertical axis - const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP - | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; - if (box.height == 0) { - box.y = bounds.y; - } else if ((state->anchor & both_vert) == both_vert) { - box.y = bounds.y + ((bounds.height / 2) - (box.height / 2)); - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { - box.y = bounds.y; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { - box.y = bounds.y + (bounds.height - box.height); - } else { - box.y = bounds.y + ((bounds.height / 2) - (box.height / 2)); - } - // Margin - if (box.width == 0) { - box.x += state->margin.left; - box.width = bounds.width - - (state->margin.left + state->margin.right); - } else if ((state->anchor & both_horiz) == both_horiz) { - // don't apply margins - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { - box.x += state->margin.left; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { - box.x -= state->margin.right; - } - if (box.height == 0) { - box.y += state->margin.top; - box.height = bounds.height - - (state->margin.top + state->margin.bottom); - } else if ((state->anchor & both_vert) == both_vert) { - // don't apply margins - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { - box.y += state->margin.top; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { - box.y -= state->margin.bottom; - } - if (!sway_assert(box.width >= 0 && box.height >= 0, - "Expected layer surface to have positive size")) { - continue; - } - // Apply - sway_layer->geo = box; - apply_exclusive(usable_area, state->anchor, state->exclusive_zone, - state->margin.top, state->margin.right, - state->margin.bottom, state->margin.left); - wlr_layer_surface_v1_configure(layer, box.width, box.height); - } -} - -void arrange_layers(struct sway_output *output) { - struct wlr_box usable_area = { 0 }; - wlr_output_effective_resolution(output->wlr_output, - &usable_area.width, &usable_area.height); - - // Arrange exclusive surfaces from top->bottom - arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], - &usable_area, true); - arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], - &usable_area, true); - arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], - &usable_area, true); - arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], - &usable_area, true); - - if (memcmp(&usable_area, &output->usable_area, - sizeof(struct wlr_box)) != 0) { - sway_log(SWAY_DEBUG, "Usable area changed, rearranging output"); - memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_box)); - arrange_output(output); - } - - // Arrange non-exclusive surfaces from top->bottom - arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], - &usable_area, false); - arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], - &usable_area, false); - arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], - &usable_area, false); - arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], - &usable_area, false); - - // Find topmost keyboard interactive layer, if such a layer exists - uint32_t layers_above_shell[] = { - ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, - ZWLR_LAYER_SHELL_V1_LAYER_TOP, - }; - size_t nlayers = sizeof(layers_above_shell) / sizeof(layers_above_shell[0]); - struct sway_layer_surface *layer, *topmost = NULL; - for (size_t i = 0; i < nlayers; ++i) { - wl_list_for_each_reverse(layer, - &output->layers[layers_above_shell[i]], link) { - if (layer->layer_surface->current.keyboard_interactive - == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE && - layer->layer_surface->surface->mapped) { - topmost = layer; - break; - } - } - if (topmost != NULL) { - break; - } - } - - struct sway_seat *seat; - wl_list_for_each(seat, &server.input->seats, link) { - seat->has_exclusive_layer = false; - if (topmost != NULL) { - seat_set_focus_layer(seat, topmost->layer_surface); - } else if (seat->focused_layer && - seat->focused_layer->current.keyboard_interactive - != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) { - seat_set_focus_layer(seat, NULL); - } - } -} - -static struct sway_layer_surface *find_mapped_layer_by_client( - struct wl_client *client, struct wlr_output *ignore_output) { - for (int i = 0; i < root->outputs->length; ++i) { - struct sway_output *output = root->outputs->items[i]; - if (output->wlr_output == ignore_output) { - continue; - } - // For now we'll only check the overlay layer - struct sway_layer_surface *lsurface; - wl_list_for_each(lsurface, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], link) { - struct wl_resource *resource = lsurface->layer_surface->resource; - if (wl_resource_get_client(resource) == client - && lsurface->layer_surface->surface->mapped) { - return lsurface; - } - } - } - return NULL; -} - -static void handle_output_destroy(struct wl_listener *listener, void *data) { - struct sway_layer_surface *sway_layer = - wl_container_of(listener, sway_layer, output_destroy); - // Determine if this layer is being used by an exclusive client. If it is, - // try and find another layer owned by this client to pass focus to. - struct sway_seat *seat = input_manager_get_default_seat(); - struct wl_client *client = - wl_resource_get_client(sway_layer->layer_surface->resource); - bool set_focus = seat->exclusive_client == client; - - if (set_focus) { - struct sway_layer_surface *layer = - find_mapped_layer_by_client(client, sway_layer->layer_surface->output); - if (layer) { - seat_set_focus_layer(seat, layer->layer_surface); - } - } - - wlr_layer_surface_v1_destroy(sway_layer->layer_surface); -} - -static void handle_surface_commit(struct wl_listener *listener, void *data) { - struct sway_layer_surface *layer = - wl_container_of(listener, layer, surface_commit); - struct wlr_layer_surface_v1 *layer_surface = layer->layer_surface; - struct wlr_output *wlr_output = layer_surface->output; - sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); - struct sway_output *output = wlr_output->data; - struct wlr_box old_extent = layer->extent; - - // Rerender the static blur on change - if (layer->layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND - || layer->layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM) { - struct fx_effect_framebuffers *effect_fbos = - fx_effect_framebuffers_try_get(output->wlr_output); - effect_fbos->blur_buffer_dirty = true; - } - - bool layer_changed = false; - if (layer_surface->current.committed != 0 - || layer->mapped != layer_surface->surface->mapped) { - layer->mapped = layer_surface->surface->mapped; - layer_changed = layer->layer != layer_surface->current.layer; - if (layer_changed) { - wl_list_remove(&layer->link); - wl_list_insert(&output->layers[layer_surface->current.layer], - &layer->link); - layer->layer = layer_surface->current.layer; - layer_parse_criteria(layer); - } - arrange_layers(output); - } - - wlr_surface_get_extends(layer_surface->surface, &layer->extent); - layer->extent.x += layer->geo.x; - layer->extent.y += layer->geo.y; - - bool extent_changed = - memcmp(&old_extent, &layer->extent, sizeof(struct wlr_box)) != 0; - if (extent_changed || layer_changed) { - int blur_size = layer->has_blur? config_get_blur_size(): 0; - int shadow_sigma = layer->has_shadow? config->shadow_blur_sigma: 0; - int effect_size = MAX(blur_size, shadow_sigma); - old_extent.x += output->lx - effect_size; - old_extent.y += output->ly - effect_size; - old_extent.width += effect_size * 2; - old_extent.height += effect_size * 2; - output_damage_box(output, &old_extent); - output_damage_surface(output, layer->geo.x, layer->geo.y, - layer_surface->surface, true); - } else { - output_damage_surface(output, layer->geo.x, layer->geo.y, - layer_surface->surface, false); - } - - transaction_commit_dirty(); -} - -static void unmap(struct sway_layer_surface *sway_layer) { - struct sway_seat *seat; - wl_list_for_each(seat, &server.input->seats, link) { - if (seat->focused_layer == sway_layer->layer_surface) { - seat_set_focus_layer(seat, NULL); - } - } - - cursor_rebase_all(); - - struct wlr_output *wlr_output = sway_layer->layer_surface->output; - sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); - struct sway_output *output = wlr_output->data; - output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y, - sway_layer->layer_surface->surface, true); -} - -static void layer_subsurface_destroy(struct sway_layer_subsurface *subsurface); - -static void handle_destroy(struct wl_listener *listener, void *data) { - struct sway_layer_surface *sway_layer = - wl_container_of(listener, sway_layer, destroy); - sway_log(SWAY_DEBUG, "Layer surface destroyed (%s)", - sway_layer->layer_surface->namespace); - if (sway_layer->layer_surface->surface->mapped) { - unmap(sway_layer); - } - - struct sway_layer_subsurface *subsurface, *subsurface_tmp; - wl_list_for_each_safe(subsurface, subsurface_tmp, &sway_layer->subsurfaces, link) { - layer_subsurface_destroy(subsurface); - } - - wl_list_remove(&sway_layer->link); - wl_list_remove(&sway_layer->destroy.link); - wl_list_remove(&sway_layer->map.link); - wl_list_remove(&sway_layer->unmap.link); - wl_list_remove(&sway_layer->surface_commit.link); - wl_list_remove(&sway_layer->new_popup.link); - wl_list_remove(&sway_layer->new_subsurface.link); - - struct wlr_output *wlr_output = sway_layer->layer_surface->output; - sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); - struct sway_output *output = wlr_output->data; - - // Rerender the static blur - if (sway_layer->layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND - || sway_layer->layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM) { - struct fx_effect_framebuffers *effect_fbos = - fx_effect_framebuffers_try_get(output->wlr_output); - effect_fbos->blur_buffer_dirty = true; - } - - arrange_layers(output); - transaction_commit_dirty(); - wl_list_remove(&sway_layer->output_destroy.link); - sway_layer->layer_surface->output = NULL; - - free(sway_layer); -} - -static void handle_map(struct wl_listener *listener, void *data) { - struct sway_layer_surface *sway_layer = wl_container_of(listener, - sway_layer, map); - struct wlr_output *wlr_output = sway_layer->layer_surface->output; - sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); - struct sway_output *output = wlr_output->data; - layer_parse_criteria(sway_layer); - output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y, - sway_layer->layer_surface->surface, true); - cursor_rebase_all(); -} - -static void handle_unmap(struct wl_listener *listener, void *data) { - struct sway_layer_surface *sway_layer = wl_container_of( - listener, sway_layer, unmap); - unmap(sway_layer); -} - -static void subsurface_damage(struct sway_layer_subsurface *subsurface, - bool whole) { - struct sway_layer_surface *layer = subsurface->layer_surface; - struct wlr_output *wlr_output = layer->layer_surface->output; - sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); - struct sway_output *output = wlr_output->data; - int ox = subsurface->wlr_subsurface->current.x + layer->geo.x; - int oy = subsurface->wlr_subsurface->current.y + layer->geo.y; - output_damage_surface( - output, ox, oy, subsurface->wlr_subsurface->surface, whole); -} - -static void subsurface_handle_unmap(struct wl_listener *listener, void *data) { - struct sway_layer_subsurface *subsurface = - wl_container_of(listener, subsurface, unmap); - subsurface_damage(subsurface, true); -} - -static void subsurface_handle_map(struct wl_listener *listener, void *data) { - struct sway_layer_subsurface *subsurface = - wl_container_of(listener, subsurface, map); - subsurface_damage(subsurface, true); -} - -static void subsurface_handle_commit(struct wl_listener *listener, void *data) { - struct sway_layer_subsurface *subsurface = - wl_container_of(listener, subsurface, commit); - subsurface_damage(subsurface, false); -} - -static void layer_subsurface_destroy(struct sway_layer_subsurface *subsurface) { - wl_list_remove(&subsurface->link); - wl_list_remove(&subsurface->map.link); - wl_list_remove(&subsurface->unmap.link); - wl_list_remove(&subsurface->destroy.link); - wl_list_remove(&subsurface->commit.link); - free(subsurface); -} - -static void subsurface_handle_destroy(struct wl_listener *listener, - void *data) { - struct sway_layer_subsurface *subsurface = - wl_container_of(listener, subsurface, destroy); - layer_subsurface_destroy(subsurface); -} - -static struct sway_layer_subsurface *create_subsurface( - struct wlr_subsurface *wlr_subsurface, - struct sway_layer_surface *layer_surface) { - struct sway_layer_subsurface *subsurface = - calloc(1, sizeof(struct sway_layer_subsurface)); - if (subsurface == NULL) { - return NULL; - } - - subsurface->wlr_subsurface = wlr_subsurface; - subsurface->layer_surface = layer_surface; - wl_list_insert(&layer_surface->subsurfaces, &subsurface->link); - - subsurface->map.notify = subsurface_handle_map; - wl_signal_add(&wlr_subsurface->surface->events.map, &subsurface->map); - subsurface->unmap.notify = subsurface_handle_unmap; - wl_signal_add(&wlr_subsurface->surface->events.unmap, &subsurface->unmap); - subsurface->destroy.notify = subsurface_handle_destroy; - wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy); - subsurface->commit.notify = subsurface_handle_commit; - wl_signal_add(&wlr_subsurface->surface->events.commit, &subsurface->commit); - - return subsurface; -} - -static void handle_new_subsurface(struct wl_listener *listener, void *data) { - struct sway_layer_surface *sway_layer_surface = - wl_container_of(listener, sway_layer_surface, new_subsurface); - struct wlr_subsurface *wlr_subsurface = data; - create_subsurface(wlr_subsurface, sway_layer_surface); -} - - -static struct sway_layer_surface *popup_get_layer( - struct sway_layer_popup *popup) { - while (popup->parent_type == LAYER_PARENT_POPUP) { - popup = popup->parent_popup; - } - return popup->parent_layer; -} - -static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) { - struct wlr_xdg_popup *popup = layer_popup->wlr_popup; - struct wlr_surface *surface = popup->base->surface; - int popup_sx = popup->current.geometry.x - popup->base->current.geometry.x; - int popup_sy = popup->current.geometry.y - popup->base->current.geometry.y; - int ox = popup_sx, oy = popup_sy; - struct sway_layer_surface *layer; - while (true) { - if (layer_popup->parent_type == LAYER_PARENT_POPUP) { - layer_popup = layer_popup->parent_popup; - ox += layer_popup->wlr_popup->current.geometry.x; - oy += layer_popup->wlr_popup->current.geometry.y; - } else { - layer = layer_popup->parent_layer; - ox += layer->geo.x; - oy += layer->geo.y; - break; - } - } - struct wlr_output *wlr_output = layer->layer_surface->output; - sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); - struct sway_output *output = wlr_output->data; - output_damage_surface(output, ox, oy, surface, whole); -} - -static void popup_handle_map(struct wl_listener *listener, void *data) { - struct sway_layer_popup *popup = wl_container_of(listener, popup, map); - struct sway_layer_surface *layer = popup_get_layer(popup); - struct wlr_output *wlr_output = layer->layer_surface->output; - sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); - surface_enter_output(popup->wlr_popup->base->surface, wlr_output->data); - popup_damage(popup, true); -} - -static void popup_handle_unmap(struct wl_listener *listener, void *data) { - struct sway_layer_popup *popup = wl_container_of(listener, popup, unmap); - popup_damage(popup, true); -} - -static void popup_handle_commit(struct wl_listener *listener, void *data) { - struct sway_layer_popup *popup = wl_container_of(listener, popup, commit); - popup_damage(popup, false); -} - -static void popup_handle_destroy(struct wl_listener *listener, void *data) { - struct sway_layer_popup *popup = - wl_container_of(listener, popup, destroy); - - wl_list_remove(&popup->map.link); - wl_list_remove(&popup->unmap.link); - wl_list_remove(&popup->destroy.link); - wl_list_remove(&popup->commit.link); - free(popup); -} - -static void popup_unconstrain(struct sway_layer_popup *popup) { - struct sway_layer_surface *layer = popup_get_layer(popup); - struct wlr_xdg_popup *wlr_popup = popup->wlr_popup; - - struct wlr_output *wlr_output = layer->layer_surface->output; - sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); - struct sway_output *output = wlr_output->data; - - // the output box expressed in the coordinate system of the toplevel parent - // of the popup - struct wlr_box output_toplevel_sx_box = { - .x = -layer->geo.x, - .y = -layer->geo.y, - .width = output->width, - .height = output->height, - }; - - wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); -} - -static void popup_handle_new_popup(struct wl_listener *listener, void *data); - -static struct sway_layer_popup *create_popup(struct wlr_xdg_popup *wlr_popup, - enum layer_parent parent_type, void *parent) { - struct sway_layer_popup *popup = - calloc(1, sizeof(struct sway_layer_popup)); - if (popup == NULL) { - return NULL; - } - - popup->wlr_popup = wlr_popup; - popup->parent_type = parent_type; - popup->parent_layer = parent; - - popup->map.notify = popup_handle_map; - wl_signal_add(&wlr_popup->base->surface->events.map, &popup->map); - popup->unmap.notify = popup_handle_unmap; - wl_signal_add(&wlr_popup->base->surface->events.unmap, &popup->unmap); - popup->destroy.notify = popup_handle_destroy; - wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy); - popup->commit.notify = popup_handle_commit; - wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit); - popup->new_popup.notify = popup_handle_new_popup; - wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup); - - popup_unconstrain(popup); - - return popup; -} - -static void popup_handle_new_popup(struct wl_listener *listener, void *data) { - struct sway_layer_popup *sway_layer_popup = - wl_container_of(listener, sway_layer_popup, new_popup); - struct wlr_xdg_popup *wlr_popup = data; - create_popup(wlr_popup, LAYER_PARENT_POPUP, sway_layer_popup); -} - -static void handle_new_popup(struct wl_listener *listener, void *data) { - struct sway_layer_surface *sway_layer_surface = - wl_container_of(listener, sway_layer_surface, new_popup); - struct wlr_xdg_popup *wlr_popup = data; - create_popup(wlr_popup, LAYER_PARENT_LAYER, sway_layer_surface); -} - -struct sway_layer_surface *layer_from_wlr_layer_surface_v1( - struct wlr_layer_surface_v1 *layer_surface) { - return layer_surface->data; -} - -void handle_layer_shell_surface(struct wl_listener *listener, void *data) { - struct wlr_layer_surface_v1 *layer_surface = data; - sway_log(SWAY_DEBUG, "new layer surface: namespace %s layer %d anchor %" PRIu32 - " size %" PRIu32 "x%" PRIu32 " margin %" PRIu32 ",%" PRIu32 ",%" PRIu32 ",%" PRIu32 ",", - layer_surface->namespace, - layer_surface->pending.layer, - layer_surface->pending.anchor, - layer_surface->pending.desired_width, - layer_surface->pending.desired_height, - layer_surface->pending.margin.top, - layer_surface->pending.margin.right, - layer_surface->pending.margin.bottom, - layer_surface->pending.margin.left); - - if (!layer_surface->output) { - // Assign last active output - struct sway_output *output = NULL; - struct sway_seat *seat = input_manager_get_default_seat(); - if (seat) { - struct sway_workspace *ws = seat_get_focused_workspace(seat); - if (ws != NULL) { - output = ws->output; - } - } - if (!output || output == root->fallback_output) { - if (!root->outputs->length) { - sway_log(SWAY_ERROR, - "no output to auto-assign layer surface '%s' to", - layer_surface->namespace); - // Note that layer_surface->output can be NULL - // here, but none of our destroy callbacks are - // registered yet so we don't have to make them - // handle that case. - wlr_layer_surface_v1_destroy(layer_surface); - return; - } - output = root->outputs->items[0]; - } - layer_surface->output = output->wlr_output; - } - - struct sway_layer_surface *sway_layer = - calloc(1, sizeof(struct sway_layer_surface)); - if (!sway_layer) { - return; - } - - wl_list_init(&sway_layer->subsurfaces); - - sway_layer->surface_commit.notify = handle_surface_commit; - wl_signal_add(&layer_surface->surface->events.commit, - &sway_layer->surface_commit); - - sway_layer->destroy.notify = handle_destroy; - wl_signal_add(&layer_surface->events.destroy, &sway_layer->destroy); - sway_layer->map.notify = handle_map; - wl_signal_add(&layer_surface->surface->events.map, &sway_layer->map); - sway_layer->unmap.notify = handle_unmap; - wl_signal_add(&layer_surface->surface->events.unmap, &sway_layer->unmap); - sway_layer->new_popup.notify = handle_new_popup; - wl_signal_add(&layer_surface->events.new_popup, &sway_layer->new_popup); - sway_layer->new_subsurface.notify = handle_new_subsurface; - wl_signal_add(&layer_surface->surface->events.new_subsurface, - &sway_layer->new_subsurface); - - sway_layer->layer_surface = layer_surface; - layer_surface->data = sway_layer; - - sway_layer->has_blur = false; - sway_layer->blur_ignore_transparent = false; - sway_layer->has_shadow = false; - sway_layer->corner_radius = 0; - - struct sway_output *output = layer_surface->output->data; - sway_layer->output_destroy.notify = handle_output_destroy; - wl_signal_add(&output->events.disable, &sway_layer->output_destroy); - - wl_list_insert(&output->layers[layer_surface->pending.layer], - &sway_layer->link); - - surface_enter_output(layer_surface->surface, output); - - // Temporarily set the layer's current state to pending - // So that we can easily arrange it - struct wlr_layer_surface_v1_state old_state = layer_surface->current; - layer_surface->current = layer_surface->pending; - arrange_layers(output); - layer_surface->current = old_state; -} diff --git a/sway/desktop/output.c b/sway/desktop/output.c deleted file mode 100644 index 3e6b1a2de..000000000 --- a/sway/desktop/output.c +++ /dev/null @@ -1,1295 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "config.h" -#include "log.h" -#include "scenefx/render/pass.h" -#include "sway/config.h" -#include "sway/desktop/transaction.h" -#include "sway/input/input-manager.h" -#include "sway/input/seat.h" -#include "sway/ipc-server.h" -#include "sway/input/text_input.h" -#include "sway/layers.h" -#include "sway/output.h" -#include "sway/server.h" -#include "sway/surface.h" -#include "sway/tree/arrange.h" -#include "sway/tree/container.h" -#include "sway/tree/root.h" -#include "sway/tree/view.h" -#include "sway/tree/workspace.h" - -#if WLR_HAS_DRM_BACKEND -#include -#include -#endif - -bool output_match_name_or_id(struct sway_output *output, - const char *name_or_id) { - if (strcmp(name_or_id, "*") == 0) { - return true; - } - - char identifier[128]; - output_get_identifier(identifier, sizeof(identifier), output); - return strcasecmp(identifier, name_or_id) == 0 - || strcasecmp(output->wlr_output->name, name_or_id) == 0; -} - -struct sway_output *output_by_name_or_id(const char *name_or_id) { - for (int i = 0; i < root->outputs->length; ++i) { - struct sway_output *output = root->outputs->items[i]; - if (output_match_name_or_id(output, name_or_id)) { - return output; - } - } - return NULL; -} - -struct sway_output *all_output_by_name_or_id(const char *name_or_id) { - struct sway_output *output; - wl_list_for_each(output, &root->all_outputs, link) { - if (output_match_name_or_id(output, name_or_id)) { - return output; - } - } - return NULL; -} - -struct surface_iterator_data { - sway_surface_iterator_func_t user_iterator; - void *user_data; - - struct sway_output *output; - struct sway_view *view; - double ox, oy; - int width, height; -}; - -static bool get_surface_box(struct surface_iterator_data *data, - struct wlr_surface *surface, int sx, int sy, - struct wlr_box *surface_box) { - struct sway_output *output = data->output; - - if (!wlr_surface_has_buffer(surface)) { - return false; - } - - int sw = surface->current.width; - int sh = surface->current.height; - - struct wlr_box box = { - .x = floor(data->ox + sx), - .y = floor(data->oy + sy), - .width = sw, - .height = sh, - }; - if (surface_box != NULL) { - memcpy(surface_box, &box, sizeof(struct wlr_box)); - } - - struct wlr_box output_box = { - .width = output->width, - .height = output->height, - }; - - struct wlr_box intersection; - return wlr_box_intersection(&intersection, &output_box, &box); -} - -static void output_for_each_surface_iterator(struct wlr_surface *surface, - int sx, int sy, void *_data) { - struct surface_iterator_data *data = _data; - - struct wlr_box box; - bool intersects = get_surface_box(data, surface, sx, sy, &box); - if (!intersects) { - return; - } - - data->user_iterator(data->output, data->view, surface, &box, - data->user_data); -} - -void output_surface_for_each_surface(struct sway_output *output, - struct wlr_surface *surface, double ox, double oy, - sway_surface_iterator_func_t iterator, void *user_data) { - struct surface_iterator_data data = { - .user_iterator = iterator, - .user_data = user_data, - .output = output, - .view = NULL, - .ox = ox, - .oy = oy, - .width = surface->current.width, - .height = surface->current.height, - }; - - wlr_surface_for_each_surface(surface, - output_for_each_surface_iterator, &data); -} - -void output_view_for_each_surface(struct sway_output *output, - struct sway_view *view, sway_surface_iterator_func_t iterator, - void *user_data) { - struct surface_iterator_data data = { - .user_iterator = iterator, - .user_data = user_data, - .output = output, - .view = view, - .ox = view->container->surface_x - output->lx - - view->geometry.x, - .oy = view->container->surface_y - output->ly - - view->geometry.y, - .width = view->container->current.content_width, - .height = view->container->current.content_height, - }; - - view_for_each_surface(view, output_for_each_surface_iterator, &data); -} - -void output_view_for_each_popup_surface(struct sway_output *output, - struct sway_view *view, sway_surface_iterator_func_t iterator, - void *user_data) { - struct surface_iterator_data data = { - .user_iterator = iterator, - .user_data = user_data, - .output = output, - .view = view, - .ox = view->container->surface_x - output->lx - - view->geometry.x, - .oy = view->container->surface_y - output->ly - - view->geometry.y, - .width = view->container->current.content_width, - .height = view->container->current.content_height, - }; - - view_for_each_popup_surface(view, output_for_each_surface_iterator, &data); -} - -void output_layer_for_each_surface(struct sway_output *output, - struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator, - void *user_data) { - struct sway_layer_surface *layer_surface; - wl_list_for_each(layer_surface, layer_surfaces, link) { - struct wlr_layer_surface_v1 *wlr_layer_surface_v1 = - layer_surface->layer_surface; - struct wlr_surface *surface = wlr_layer_surface_v1->surface; - struct surface_iterator_data data = { - .user_iterator = iterator, - .user_data = user_data, - .output = output, - .view = NULL, - .ox = layer_surface->geo.x, - .oy = layer_surface->geo.y, - .width = surface->current.width, - .height = surface->current.height, - }; - wlr_layer_surface_v1_for_each_surface(wlr_layer_surface_v1, - output_for_each_surface_iterator, &data); - } -} - -void output_layer_for_each_toplevel_surface(struct sway_output *output, - struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator, - void *user_data) { - struct sway_layer_surface *layer_surface; - wl_list_for_each(layer_surface, layer_surfaces, link) { - struct wlr_layer_surface_v1 *wlr_layer_surface_v1 = - layer_surface->layer_surface; - - struct render_data *data = user_data; - data->deco_data.blur = layer_surface->layer != ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND ? - layer_surface->has_blur : false; - data->deco_data.discard_transparent = layer_surface->blur_ignore_transparent; - data->deco_data.shadow = layer_surface->has_shadow; - data->deco_data.corner_radius = layer_surface->corner_radius; - - output_surface_for_each_surface(output, wlr_layer_surface_v1->surface, - layer_surface->geo.x, layer_surface->geo.y, iterator, - user_data); - } -} - - -void output_layer_for_each_popup_surface(struct sway_output *output, - struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator, - void *user_data) { - struct sway_layer_surface *layer_surface; - wl_list_for_each(layer_surface, layer_surfaces, link) { - struct wlr_layer_surface_v1 *wlr_layer_surface_v1 = - layer_surface->layer_surface; - struct wlr_surface *surface = wlr_layer_surface_v1->surface; - struct surface_iterator_data data = { - .user_iterator = iterator, - .user_data = user_data, - .output = output, - .view = NULL, - .ox = layer_surface->geo.x, - .oy = layer_surface->geo.y, - .width = surface->current.width, - .height = surface->current.height, - }; - wlr_layer_surface_v1_for_each_popup_surface(wlr_layer_surface_v1, - output_for_each_surface_iterator, &data); - } -} - -#if HAVE_XWAYLAND -void output_unmanaged_for_each_surface(struct sway_output *output, - struct wl_list *unmanaged, sway_surface_iterator_func_t iterator, - void *user_data) { - struct sway_xwayland_unmanaged *unmanaged_surface; - wl_list_for_each(unmanaged_surface, unmanaged, link) { - struct wlr_xwayland_surface *xsurface = - unmanaged_surface->wlr_xwayland_surface; - double ox = unmanaged_surface->lx - output->lx; - double oy = unmanaged_surface->ly - output->ly; - - output_surface_for_each_surface(output, xsurface->surface, ox, oy, - iterator, user_data); - } -} -#endif - -void output_input_popups_for_each_surface(struct sway_output *output, - struct wl_list *input_popups, sway_surface_iterator_func_t iterator, - void *user_data) { - struct sway_input_popup *popup; - wl_list_for_each(popup, input_popups, link) { - int lx, ly; - if (!sway_input_popup_get_position(popup, &lx, &ly)) { - continue; - } - if (!popup->popup_surface->surface->mapped || !popup->visible) { - continue; - } - - // damage the popup if surface is updated - sway_input_popup_damage(popup); - - double ox = lx - output->lx; - double oy = ly - output->ly; - - output_surface_for_each_surface(output, - popup->popup_surface->surface, ox, oy, - iterator, user_data); - } -} - -void output_drag_icons_for_each_surface(struct sway_output *output, - struct wl_list *drag_icons, sway_surface_iterator_func_t iterator, - void *user_data) { - struct sway_drag_icon *drag_icon; - wl_list_for_each(drag_icon, drag_icons, link) { - double ox = drag_icon->x - output->lx; - double oy = drag_icon->y - output->ly; - - if (drag_icon->wlr_drag_icon->surface->mapped) { - output_surface_for_each_surface(output, - drag_icon->wlr_drag_icon->surface, ox, oy, - iterator, user_data); - } - } -} - -static void for_each_surface_container_iterator(struct sway_container *con, - void *_data) { - if (!con->view || !view_is_visible(con->view)) { - return; - } - - struct surface_iterator_data *data = _data; - output_view_for_each_surface(data->output, con->view, - data->user_iterator, data->user_data); -} - -static void output_for_each_surface(struct sway_output *output, - sway_surface_iterator_func_t iterator, void *user_data) { - if (server.session_lock.locked) { - if (server.session_lock.lock == NULL) { - return; - } - struct wlr_session_lock_surface_v1 *lock_surface; - wl_list_for_each(lock_surface, &server.session_lock.lock->surfaces, link) { - if (lock_surface->output != output->wlr_output) { - continue; - } - if (!lock_surface->surface->mapped) { - continue; - } - - output_surface_for_each_surface(output, lock_surface->surface, - 0.0, 0.0, iterator, user_data); - } - return; - } - - if (output_has_opaque_overlay_layer_surface(output)) { - goto overlay; - } - - struct surface_iterator_data data = { - .user_iterator = iterator, - .user_data = user_data, - .output = output, - .view = NULL, - }; - - struct sway_workspace *workspace = output_get_active_workspace(output); - struct sway_container *fullscreen_con = root->fullscreen_global; - if (!fullscreen_con) { - if (!workspace) { - return; - } - fullscreen_con = workspace->current.fullscreen; - } - if (fullscreen_con) { - for_each_surface_container_iterator(fullscreen_con, &data); - container_for_each_child(fullscreen_con, - for_each_surface_container_iterator, &data); - - // TODO: Show transient containers for fullscreen global - if (fullscreen_con == workspace->current.fullscreen) { - for (int i = 0; i < workspace->current.floating->length; ++i) { - struct sway_container *floater = - workspace->current.floating->items[i]; - if (container_is_transient_for(floater, fullscreen_con)) { - for_each_surface_container_iterator(floater, &data); - } - } - } -#if HAVE_XWAYLAND - output_unmanaged_for_each_surface(output, &root->xwayland_unmanaged, - iterator, user_data); -#endif - } else { - output_layer_for_each_surface(output, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], - iterator, user_data); - output_layer_for_each_surface(output, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], - iterator, user_data); - - workspace_for_each_container(workspace, - for_each_surface_container_iterator, &data); - -#if HAVE_XWAYLAND - output_unmanaged_for_each_surface(output, &root->xwayland_unmanaged, - iterator, user_data); -#endif - output_layer_for_each_surface(output, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], - iterator, user_data); - } - -overlay: - output_layer_for_each_surface(output, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], - iterator, user_data); - output_input_popups_for_each_surface( - output, &input_manager_current_seat()->im_relay.input_popups, - iterator, user_data); - output_drag_icons_for_each_surface(output, &root->drag_icons, - iterator, user_data); -} - -static int scale_length(int length, int offset, float scale) { - return roundf((offset + length) * scale) - roundf(offset * scale); -} - -void scale_box(struct wlr_box *box, float scale) { - box->width = scale_length(box->width, box->x, scale); - box->height = scale_length(box->height, box->y, scale); - box->x = roundf(box->x * scale); - box->y = roundf(box->y * scale); -} - -struct sway_workspace *output_get_active_workspace(struct sway_output *output) { - struct sway_seat *seat = input_manager_current_seat(); - struct sway_node *focus = seat_get_active_tiling_child(seat, &output->node); - if (!focus) { - if (!output->workspaces->length) { - return NULL; - } - return output->workspaces->items[0]; - } - return focus->sway_workspace; -} - -bool output_has_opaque_overlay_layer_surface(struct sway_output *output) { - struct sway_layer_surface *sway_layer_surface; - wl_list_for_each(sway_layer_surface, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], link) { - struct wlr_surface *wlr_surface = sway_layer_surface->layer_surface->surface; - pixman_box32_t output_box = { - .x2 = output->width, - .y2 = output->height, - }; - pixman_region32_t surface_opaque_box; - pixman_region32_init(&surface_opaque_box); - pixman_region32_copy(&surface_opaque_box, &wlr_surface->opaque_region); - pixman_region32_translate(&surface_opaque_box, - sway_layer_surface->geo.x, sway_layer_surface->geo.y); - pixman_region_overlap_t contains = - pixman_region32_contains_rectangle(&surface_opaque_box, &output_box); - pixman_region32_fini(&surface_opaque_box); - - if (contains == PIXMAN_REGION_IN) { - return true; - } - } - return false; -} - -struct send_frame_done_data { - struct timespec when; - int msec_until_refresh; -}; - -static void send_frame_done_iterator(struct sway_output *output, - struct sway_view *view, struct wlr_surface *surface, - struct wlr_box *box, void *user_data) { - int view_max_render_time = 0; - if (view != NULL) { - view_max_render_time = view->max_render_time; - } - - struct send_frame_done_data *data = user_data; - - int delay = data->msec_until_refresh - output->max_render_time - - view_max_render_time; - - if (output->max_render_time == 0 || view_max_render_time == 0 || delay < 1) { - wlr_surface_send_frame_done(surface, &data->when); - } else { - struct sway_surface *sway_surface = surface->data; - wl_event_source_timer_update(sway_surface->frame_done_timer, delay); - } -} - -static void send_frame_done(struct sway_output *output, struct send_frame_done_data *data) { - output_for_each_surface(output, send_frame_done_iterator, data); -} - -static void count_surface_iterator(struct sway_output *output, - struct sway_view *view, struct wlr_surface *surface, - struct wlr_box *box, void *data) { - size_t *n = data; - (*n)++; -} - -static bool scan_out_fullscreen_view(struct sway_output *output, - struct wlr_output_state *pending, struct sway_view *view) { - struct wlr_output *wlr_output = output->wlr_output; - struct sway_workspace *workspace = output->current.active_workspace; - if (!sway_assert(workspace, "Expected an active workspace")) { - return false; - } - - if (server.session_lock.locked) { - return false; - } - - if (!wl_list_empty(&view->saved_buffers)) { - return false; - } - - for (int i = 0; i < workspace->current.floating->length; ++i) { - struct sway_container *floater = - workspace->current.floating->items[i]; - if (container_is_transient_for(floater, view->container)) { - return false; - } - } - -#if HAVE_XWAYLAND - if (!wl_list_empty(&root->xwayland_unmanaged)) { - return false; - } -#endif - - if (!wl_list_empty(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY])) { - return false; - } - if (!wl_list_empty(&root->drag_icons)) { - return false; - } - - struct wlr_surface *surface = view->surface; - if (surface == NULL) { - return false; - } - size_t n_surfaces = 0; - output_view_for_each_surface(output, view, - count_surface_iterator, &n_surfaces); - if (n_surfaces != 1) { - return false; - } - size_t n_popups = 0; - output_view_for_each_popup_surface(output, view, - count_surface_iterator, &n_popups); - if (n_popups > 0) { - return false; - } - - if (surface->buffer == NULL) { - return false; - } - - if ((float)surface->current.scale != wlr_output->scale || - surface->current.transform != wlr_output->transform) { - return false; - } - - if (!wlr_output_is_direct_scanout_allowed(wlr_output)) { - return false; - } - - wlr_output_state_set_buffer(pending, &surface->buffer->base); - - if (!wlr_output_test_state(wlr_output, pending)) { - return false; - } - - wlr_presentation_surface_scanned_out_on_output(server.presentation, surface, - wlr_output); - - return wlr_output_commit_state(wlr_output, pending); -} - -static void get_frame_damage(struct sway_output *output, - pixman_region32_t *frame_damage) { - struct wlr_output *wlr_output = output->wlr_output; - - int width, height; - wlr_output_transformed_resolution(wlr_output, &width, &height); - - pixman_region32_init(frame_damage); - - enum wl_output_transform transform = - wlr_output_transform_invert(wlr_output->transform); - wlr_region_transform(frame_damage, &output->damage_ring.current, - transform, width, height); - - if (debug.damage != DAMAGE_DEFAULT) { - pixman_region32_union_rect(frame_damage, frame_damage, - 0, 0, wlr_output->width, wlr_output->height); - } -} - -static int output_repaint_timer_handler(void *data) { - struct sway_output *output = data; - struct wlr_output *wlr_output = output->wlr_output; - if (wlr_output == NULL) { - return 0; - } - - wlr_output->frame_pending = false; - - if (!wlr_output->needs_frame && - !output->gamma_lut_changed && - !pixman_region32_not_empty(&output->damage_ring.current)) { - return 0; - } - - struct sway_workspace *workspace = output->current.active_workspace; - if (workspace == NULL) { - return 0; - } - - struct sway_container *fullscreen_con = root->fullscreen_global; - if (!fullscreen_con) { - fullscreen_con = workspace->current.fullscreen; - } - - struct wlr_output_state pending = {0}; - - if (output->gamma_lut_changed) { - output->gamma_lut_changed = false; - struct wlr_gamma_control_v1 *gamma_control = - wlr_gamma_control_manager_v1_get_control( - server.gamma_control_manager_v1, wlr_output); - if (!wlr_gamma_control_v1_apply(gamma_control, &pending)) { - goto out; - } - if (!wlr_output_test_state(wlr_output, &pending)) { - wlr_output_state_finish(&pending); - pending = (struct wlr_output_state){0}; - wlr_gamma_control_v1_send_failed_and_destroy(gamma_control); - } - } - - pending.committed |= WLR_OUTPUT_STATE_DAMAGE; - get_frame_damage(output, &pending.damage); - - if (fullscreen_con && fullscreen_con->view && !debug.noscanout - // Only output to monitor without compositing when saturation is changed - && fullscreen_con->saturation == 1.0f) { - // Try to scan-out the fullscreen view - static bool last_scanned_out = false; - bool scanned_out = - scan_out_fullscreen_view(output, &pending, fullscreen_con->view); - - if (scanned_out && !last_scanned_out) { - sway_log(SWAY_DEBUG, "Scanning out fullscreen view on %s", - output->wlr_output->name); - } - if (last_scanned_out && !scanned_out) { - sway_log(SWAY_DEBUG, "Stopping fullscreen view scan out on %s", - output->wlr_output->name); - output_damage_whole(output); - } - last_scanned_out = scanned_out; - - if (scanned_out) { - goto out; - } - } - - if (!wlr_output_configure_primary_swapchain(wlr_output, &pending, &wlr_output->swapchain)) { - goto out; - } - - int buffer_age; - struct wlr_buffer *buffer = wlr_swapchain_acquire(wlr_output->swapchain, &buffer_age); - if (buffer == NULL) { - goto out; - } - - struct fx_gles_render_pass *render_pass = fx_renderer_begin_buffer_pass( - wlr_output->renderer, buffer, wlr_output, - &(struct wlr_buffer_pass_options) { - .timer = NULL, - } - ); - if (render_pass == NULL) { - wlr_buffer_unlock(buffer); - goto out; - } - - pixman_region32_t damage; - pixman_region32_init(&damage); - wlr_damage_ring_get_buffer_damage(&output->damage_ring, buffer_age, &damage); - - if (debug.damage == DAMAGE_RERENDER) { - int width, height; - wlr_output_transformed_resolution(wlr_output, &width, &height); - pixman_region32_union_rect(&damage, &damage, 0, 0, width, height); - } - - struct fx_render_context ctx = { - .output_damage = &damage, - .renderer = wlr_output->renderer, - .output = output, - .pass = render_pass, - }; - - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - - output_render(&ctx); - - pixman_region32_fini(&damage); - - if (!wlr_render_pass_submit(&render_pass->base)) { - wlr_buffer_unlock(buffer); - goto out; - } - - wlr_output_state_set_buffer(&pending, buffer); - wlr_buffer_unlock(buffer); - - if (!wlr_output_commit_state(wlr_output, &pending)) { - goto out; - } - - wlr_damage_ring_rotate(&output->damage_ring); - output->last_frame = now; - -out: - wlr_output_state_finish(&pending); - return 0; -} - -static void handle_damage(struct wl_listener *listener, void *user_data) { - struct sway_output *output = - wl_container_of(listener, output, damage); - struct wlr_output_event_damage *event = user_data; - if (wlr_damage_ring_add(&output->damage_ring, event->damage)) { - wlr_output_schedule_frame(output->wlr_output); - } -} - -static void handle_frame(struct wl_listener *listener, void *user_data) { - struct sway_output *output = - wl_container_of(listener, output, frame); - if (!output->enabled || !output->wlr_output->enabled) { - return; - } - - // Compute predicted milliseconds until the next refresh. It's used for - // delaying both output rendering and surface frame callbacks. - int msec_until_refresh = 0; - - if (output->max_render_time != 0) { - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - - const long NSEC_IN_SECONDS = 1000000000; - struct timespec predicted_refresh = output->last_presentation; - predicted_refresh.tv_nsec += output->refresh_nsec % NSEC_IN_SECONDS; - predicted_refresh.tv_sec += output->refresh_nsec / NSEC_IN_SECONDS; - if (predicted_refresh.tv_nsec >= NSEC_IN_SECONDS) { - predicted_refresh.tv_sec += 1; - predicted_refresh.tv_nsec -= NSEC_IN_SECONDS; - } - - // If the predicted refresh time is before the current time then - // there's no point in delaying. - // - // We only check tv_sec because if the predicted refresh time is less - // than a second before the current time, then msec_until_refresh will - // end up slightly below zero, which will effectively disable the delay - // without potential disastrous negative overflows that could occur if - // tv_sec was not checked. - if (predicted_refresh.tv_sec >= now.tv_sec) { - long nsec_until_refresh - = (predicted_refresh.tv_sec - now.tv_sec) * NSEC_IN_SECONDS - + (predicted_refresh.tv_nsec - now.tv_nsec); - - // We want msec_until_refresh to be conservative, that is, floored. - // If we have 7.9 msec until refresh, we better compute the delay - // as if we had only 7 msec, so that we don't accidentally delay - // more than necessary and miss a frame. - msec_until_refresh = nsec_until_refresh / 1000000; - } - } - - int delay = msec_until_refresh - output->max_render_time; - - // If the delay is less than 1 millisecond (which is the least we can wait) - // then just render right away. - if (delay < 1) { - output_repaint_timer_handler(output); - } else { - output->wlr_output->frame_pending = true; - wl_event_source_timer_update(output->repaint_timer, delay); - } - - // Send frame done to all visible surfaces - struct send_frame_done_data data = {0}; - clock_gettime(CLOCK_MONOTONIC, &data.when); - data.msec_until_refresh = msec_until_refresh; - send_frame_done(output, &data); -} - -static void handle_needs_frame(struct wl_listener *listener, void *user_data) { - struct sway_output *output = - wl_container_of(listener, output, needs_frame); - wlr_output_schedule_frame(output->wlr_output); -} - -void output_damage_whole(struct sway_output *output) { - // The output can exist with no wlr_output if it's just been disconnected - // and the transaction to evacuate it has't completed yet. - if (output != NULL && output->wlr_output != NULL) { - wlr_damage_ring_add_whole(&output->damage_ring); - wlr_output_schedule_frame(output->wlr_output); - } -} - -static void damage_surface_iterator(struct sway_output *output, - struct sway_view *view, struct wlr_surface *surface, - struct wlr_box *_box, void *_data) { - bool *data = _data; - bool whole = *data; - - struct wlr_box box = *_box; - scale_box(&box, output->wlr_output->scale); - - pixman_region32_t damage; - pixman_region32_init(&damage); - wlr_surface_get_effective_damage(surface, &damage); - wlr_region_scale(&damage, &damage, output->wlr_output->scale); - if (ceilf(output->wlr_output->scale) > surface->current.scale) { - // When scaling up a surface, it'll become blurry so we need to - // expand the damage region - wlr_region_expand(&damage, &damage, - ceilf(output->wlr_output->scale) - surface->current.scale); - } - pixman_region32_translate(&damage, box.x, box.y); - if (wlr_damage_ring_add(&output->damage_ring, &damage)) { - wlr_output_schedule_frame(output->wlr_output); - } - pixman_region32_fini(&damage); - - if (whole) { - if (wlr_damage_ring_add_box(&output->damage_ring, &box)) { - wlr_output_schedule_frame(output->wlr_output); - } - } - - if (!wl_list_empty(&surface->current.frame_callback_list)) { - wlr_output_schedule_frame(output->wlr_output); - } -} - -void output_damage_surface(struct sway_output *output, double ox, double oy, - struct wlr_surface *surface, bool whole) { - output_surface_for_each_surface(output, surface, ox, oy, - damage_surface_iterator, &whole); -} - -void output_damage_from_view(struct sway_output *output, - struct sway_view *view) { - if (!view_is_visible(view)) { - return; - } - bool whole = false; - output_view_for_each_surface(output, view, damage_surface_iterator, &whole); -} - -// Expecting an unscaled box in layout coordinates -void output_damage_box(struct sway_output *output, struct wlr_box *_box) { - struct wlr_box box; - memcpy(&box, _box, sizeof(struct wlr_box)); - box.x -= output->lx; - box.y -= output->ly; - scale_box(&box, output->wlr_output->scale); - if (wlr_damage_ring_add_box(&output->damage_ring, &box)) { - wlr_output_schedule_frame(output->wlr_output); - } -} - -static void damage_child_views_iterator(struct sway_container *con, - void *data) { - if (!con->view || !view_is_visible(con->view)) { - return; - } - struct sway_output *output = data; - bool whole = true; - output_view_for_each_surface(output, con->view, damage_surface_iterator, - &whole); -} - -void output_damage_whole_container(struct sway_output *output, - struct sway_container *con) { - // Pad the box by 1px, because the width is a double and might be a fraction - struct wlr_box box = { - .x = con->current.x - output->lx - 1, - .y = con->current.y - output->ly - 1, - .width = con->current.width + 2, - .height = con->current.height + 2, - }; - scale_box(&box, output->wlr_output->scale); - if (wlr_damage_ring_add_box(&output->damage_ring, &box)) { - wlr_output_schedule_frame(output->wlr_output); - } - - // Shadow damage - if (con->shadow_enabled && config_should_parameters_shadow()) { - const int shadow_sigma = config->shadow_blur_sigma; - struct wlr_box shadow_box = { - .x = con->current.x - output->lx - 1 - shadow_sigma + config->shadow_offset_x, - .y = con->current.y - output->ly - 1 - shadow_sigma + config->shadow_offset_y, - .width = con->current.width + 2 + (shadow_sigma * 2), - .height = con->current.height + 2 + (shadow_sigma * 2), - }; - scale_box(&shadow_box, output->wlr_output->scale); - if (wlr_damage_ring_add_box(&output->damage_ring, &shadow_box)) { - wlr_output_schedule_frame(output->wlr_output); - } - } - - // Damage subsurfaces as well, which may extend outside the box - if (con->view) { - damage_child_views_iterator(con, output); - } else { - container_for_each_child(con, damage_child_views_iterator, output); - } -} - -static void update_output_manager_config(struct sway_server *server) { - struct wlr_output_configuration_v1 *config = - wlr_output_configuration_v1_create(); - - struct sway_output *output; - wl_list_for_each(output, &root->all_outputs, link) { - if (output == root->fallback_output) { - continue; - } - struct wlr_output_configuration_head_v1 *config_head = - wlr_output_configuration_head_v1_create(config, output->wlr_output); - struct wlr_box output_box; - wlr_output_layout_get_box(root->output_layout, - output->wlr_output, &output_box); - // We mark the output enabled when it's switched off but not disabled - config_head->state.enabled = !wlr_box_empty(&output_box); - config_head->state.x = output_box.x; - config_head->state.y = output_box.y; - } - - wlr_output_manager_v1_set_configuration(server->output_manager_v1, config); - - ipc_event_output(); -} - -static void begin_destroy(struct sway_output *output) { - struct sway_server *server = output->server; - - if (output->enabled) { - output_disable(output); - } - - output_begin_destroy(output); - - wl_list_remove(&output->link); - - wl_list_remove(&output->layout_destroy.link); - wl_list_remove(&output->destroy.link); - wl_list_remove(&output->commit.link); - wl_list_remove(&output->present.link); - wl_list_remove(&output->damage.link); - wl_list_remove(&output->frame.link); - wl_list_remove(&output->needs_frame.link); - wl_list_remove(&output->request_state.link); - - wlr_damage_ring_finish(&output->damage_ring); - - output->wlr_output->data = NULL; - output->wlr_output = NULL; - - transaction_commit_dirty(); - - update_output_manager_config(server); -} - -static void handle_destroy(struct wl_listener *listener, void *data) { - struct sway_output *output = wl_container_of(listener, output, destroy); - begin_destroy(output); -} - -static void handle_layout_destroy(struct wl_listener *listener, void *data) { - struct sway_output *output = wl_container_of(listener, output, layout_destroy); - begin_destroy(output); -} - -static void update_textures(struct sway_container *con, void *data) { - container_update_title_textures(con); - container_update_marks_textures(con); -} - -static void update_output_scale_iterator(struct sway_output *output, - struct sway_view *view, struct wlr_surface *surface, - struct wlr_box *box, void *user_data) { - surface_update_outputs(surface); -} - -static void update_im_scale(struct sway_output *output) { - struct sway_seat* im_seat = input_manager_current_seat(); - if (im_seat == NULL) { - return; - } - struct sway_input_method_relay* relay = &im_seat->im_relay; - struct sway_input_popup *popup; - wl_list_for_each(popup, &relay->input_popups, link) { - struct wl_list current_outputs = popup->popup_surface->surface->current_outputs; - struct wlr_surface_output *current_output; - wl_list_for_each(current_output, ¤t_outputs, link) { - if (current_output->output == output->wlr_output) { - double scale = current_output->output->scale; - wlr_fractional_scale_v1_notify_scale(popup->popup_surface->surface, scale); - wlr_surface_set_preferred_buffer_scale(popup->popup_surface->surface, ceil(scale)); - break; - } - } - } -} - -static void handle_commit(struct wl_listener *listener, void *data) { - struct sway_output *output = wl_container_of(listener, output, commit); - struct wlr_output_event_commit *event = data; - - if (!output->enabled) { - return; - } - - if (event->state->committed & WLR_OUTPUT_STATE_SCALE) { - output_for_each_container(output, update_textures, NULL); - output_for_each_surface(output, update_output_scale_iterator, NULL); - update_im_scale(output); - } - - if (event->state->committed & ( - WLR_OUTPUT_STATE_MODE | - WLR_OUTPUT_STATE_TRANSFORM | - WLR_OUTPUT_STATE_SCALE)) { - // Mark optimized blur as dirty - struct fx_effect_framebuffers *effect_fbos = - fx_effect_framebuffers_try_get(output->wlr_output); - effect_fbos->blur_buffer_dirty = true; - - arrange_layers(output); - arrange_output(output); - transaction_commit_dirty(); - - update_output_manager_config(output->server); - } - - if (event->state->committed & ( - WLR_OUTPUT_STATE_MODE | - WLR_OUTPUT_STATE_TRANSFORM)) { - int width, height; - wlr_output_transformed_resolution(output->wlr_output, &width, &height); - wlr_damage_ring_set_bounds(&output->damage_ring, width, height); - wlr_output_schedule_frame(output->wlr_output); - } - - // Next time the output is enabled, try to re-apply the gamma LUT - if ((event->state->committed & WLR_OUTPUT_STATE_ENABLED) && !output->wlr_output->enabled) { - output->gamma_lut_changed = true; - } -} - -static void handle_present(struct wl_listener *listener, void *data) { - struct sway_output *output = wl_container_of(listener, output, present); - struct wlr_output_event_present *output_event = data; - - if (!output->enabled || !output_event->presented) { - return; - } - - output->last_presentation = *output_event->when; - output->refresh_nsec = output_event->refresh; -} - -static void handle_request_state(struct wl_listener *listener, void *data) { - struct sway_output *output = - wl_container_of(listener, output, request_state); - const struct wlr_output_event_request_state *event = data; - wlr_output_commit_state(output->wlr_output, event->state); -} - -static unsigned int last_headless_num = 0; - -void handle_new_output(struct wl_listener *listener, void *data) { - struct sway_server *server = wl_container_of(listener, server, new_output); - struct wlr_output *wlr_output = data; - - if (wlr_output == root->fallback_output->wlr_output) { - return; - } - - if (wlr_output_is_headless(wlr_output)) { - char name[64]; - snprintf(name, sizeof(name), "HEADLESS-%u", ++last_headless_num); - wlr_output_set_name(wlr_output, name); - } - - sway_log(SWAY_DEBUG, "New output %p: %s (non-desktop: %d)", - wlr_output, wlr_output->name, wlr_output->non_desktop); - - if (wlr_output->non_desktop) { - sway_log(SWAY_DEBUG, "Not configuring non-desktop output"); - struct sway_output_non_desktop *non_desktop = output_non_desktop_create(wlr_output); -#if WLR_HAS_DRM_BACKEND - if (server->drm_lease_manager) { - wlr_drm_lease_v1_manager_offer_output(server->drm_lease_manager, - wlr_output); - } -#endif - list_add(root->non_desktop_outputs, non_desktop); - return; - } - - if (!wlr_output_init_render(wlr_output, server->allocator, - server->renderer)) { - sway_log(SWAY_ERROR, "Failed to init output render"); - return; - } - - struct sway_output *output = output_create(wlr_output); - if (!output) { - return; - } - output->server = server; - wlr_damage_ring_init(&output->damage_ring); - - wl_signal_add(&root->output_layout->events.destroy, &output->layout_destroy); - output->layout_destroy.notify = handle_layout_destroy; - wl_signal_add(&wlr_output->events.destroy, &output->destroy); - output->destroy.notify = handle_destroy; - wl_signal_add(&wlr_output->events.commit, &output->commit); - output->commit.notify = handle_commit; - wl_signal_add(&wlr_output->events.present, &output->present); - output->present.notify = handle_present; - wl_signal_add(&wlr_output->events.damage, &output->damage); - output->damage.notify = handle_damage; - wl_signal_add(&wlr_output->events.frame, &output->frame); - output->frame.notify = handle_frame; - wl_signal_add(&wlr_output->events.needs_frame, &output->needs_frame); - output->needs_frame.notify = handle_needs_frame; - wl_signal_add(&wlr_output->events.request_state, &output->request_state); - output->request_state.notify = handle_request_state; - - output->repaint_timer = wl_event_loop_add_timer(server->wl_event_loop, - output_repaint_timer_handler, output); - - struct output_config *oc = find_output_config(output); - apply_output_config(oc, output); - free_output_config(oc); - - transaction_commit_dirty(); - - int width, height; - wlr_output_transformed_resolution(output->wlr_output, &width, &height); - wlr_damage_ring_set_bounds(&output->damage_ring, width, height); - update_output_manager_config(server); -} - -void handle_output_layout_change(struct wl_listener *listener, - void *data) { - struct sway_server *server = - wl_container_of(listener, server, output_layout_change); - update_output_manager_config(server); -} - -void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data) { - struct sway_server *server = - wl_container_of(listener, server, gamma_control_set_gamma); - const struct wlr_gamma_control_manager_v1_set_gamma_event *event = data; - - struct sway_output *output = event->output->data; - - if(!output) { - return; - } - - output->gamma_lut_changed = true; - wlr_output_schedule_frame(output->wlr_output); -} - -static void output_manager_apply(struct sway_server *server, - struct wlr_output_configuration_v1 *config, bool test_only) { - // TODO: perform atomic tests on the whole backend atomically - - struct wlr_output_configuration_head_v1 *config_head; - // First disable outputs we need to disable - bool ok = true; - wl_list_for_each(config_head, &config->heads, link) { - struct wlr_output *wlr_output = config_head->state.output; - struct sway_output *output = wlr_output->data; - if (!output->enabled || config_head->state.enabled) { - continue; - } - struct output_config *oc = new_output_config(output->wlr_output->name); - oc->enabled = false; - - if (test_only) { - ok &= test_output_config(oc, output); - } else { - oc = store_output_config(oc); - ok &= apply_output_config(oc, output); - } - } - - // Then enable outputs that need to - wl_list_for_each(config_head, &config->heads, link) { - struct wlr_output *wlr_output = config_head->state.output; - struct sway_output *output = wlr_output->data; - if (!config_head->state.enabled) { - continue; - } - struct output_config *oc = new_output_config(output->wlr_output->name); - oc->enabled = true; - if (config_head->state.mode != NULL) { - struct wlr_output_mode *mode = config_head->state.mode; - oc->width = mode->width; - oc->height = mode->height; - oc->refresh_rate = mode->refresh / 1000.f; - } else { - oc->width = config_head->state.custom_mode.width; - oc->height = config_head->state.custom_mode.height; - oc->refresh_rate = - config_head->state.custom_mode.refresh / 1000.f; - } - oc->x = config_head->state.x; - oc->y = config_head->state.y; - oc->transform = config_head->state.transform; - oc->scale = config_head->state.scale; - oc->adaptive_sync = config_head->state.adaptive_sync_enabled; - - if (test_only) { - ok &= test_output_config(oc, output); - } else { - oc = store_output_config(oc); - ok &= apply_output_config(oc, output); - } - } - - if (ok) { - wlr_output_configuration_v1_send_succeeded(config); - } else { - wlr_output_configuration_v1_send_failed(config); - } - wlr_output_configuration_v1_destroy(config); - - if (!test_only) { - update_output_manager_config(server); - } -} - -void handle_output_manager_apply(struct wl_listener *listener, void *data) { - struct sway_server *server = - wl_container_of(listener, server, output_manager_apply); - struct wlr_output_configuration_v1 *config = data; - - output_manager_apply(server, config, false); -} - -void handle_output_manager_test(struct wl_listener *listener, void *data) { - struct sway_server *server = - wl_container_of(listener, server, output_manager_test); - struct wlr_output_configuration_v1 *config = data; - - output_manager_apply(server, config, true); -} - -void handle_output_power_manager_set_mode(struct wl_listener *listener, - void *data) { - struct wlr_output_power_v1_set_mode_event *event = data; - struct sway_output *output = event->output->data; - - struct output_config *oc = new_output_config(output->wlr_output->name); - switch (event->mode) { - case ZWLR_OUTPUT_POWER_V1_MODE_OFF: - oc->power = 0; - break; - case ZWLR_OUTPUT_POWER_V1_MODE_ON: - oc->power = 1; - break; - } - oc = store_output_config(oc); - apply_output_config(oc, output); -} diff --git a/sway/desktop/render.c b/sway/desktop/render.c deleted file mode 100644 index a43797bb1..000000000 --- a/sway/desktop/render.c +++ /dev/null @@ -1,1848 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "config.h" -#include "sway/config.h" -#include "sway/input/input-manager.h" -#include "sway/input/seat.h" -#include "sway/layers.h" -#include "sway/output.h" -#include "sway/server.h" -#include "sway/tree/arrange.h" -#include "sway/tree/container.h" -#include "sway/tree/root.h" -#include "sway/tree/view.h" -#include "sway/tree/workspace.h" - -static void transform_output_damage(pixman_region32_t *damage, struct wlr_output *output) { - int ow, oh; - wlr_output_transformed_resolution(output, &ow, &oh); - enum wl_output_transform transform = - wlr_output_transform_invert(output->transform); - wlr_region_transform(damage, damage, transform, ow, oh); -} - -static void transform_output_box(struct wlr_box *box, struct wlr_output *output) { - int ow, oh; - wlr_output_transformed_resolution(output, &ow, &oh); - enum wl_output_transform transform = - wlr_output_transform_invert(output->transform); - wlr_box_transform(box, box, transform, ow, oh); -} - -// TODO: Remove this ugly abomination with a complete border rework... -static void transform_corner_location(enum corner_location *corner_location, struct wlr_output *output) { - if (*corner_location == ALL) { - return; - } - switch (wlr_output_transform_invert(output->transform)) { - case WL_OUTPUT_TRANSFORM_NORMAL: - return; - case WL_OUTPUT_TRANSFORM_90: - *corner_location = (*corner_location + 1) % 4; - return; - case WL_OUTPUT_TRANSFORM_180: - *corner_location = (*corner_location + 2) % 4; - return; - case WL_OUTPUT_TRANSFORM_270: - *corner_location = (*corner_location + 3) % 4; - return; - case WL_OUTPUT_TRANSFORM_FLIPPED: - *corner_location = (*corner_location + (1 - 2 * (*corner_location % 2))) % 4; - return; - case WL_OUTPUT_TRANSFORM_FLIPPED_90: - *corner_location = (*corner_location + (4 - 2 * (*corner_location % 2))) % 4; - return; - case WL_OUTPUT_TRANSFORM_FLIPPED_180: - *corner_location = (*corner_location + (3 - 2 * (*corner_location % 2))) % 4; - return; - case WL_OUTPUT_TRANSFORM_FLIPPED_270: - *corner_location = (*corner_location + (2 - 2 * (*corner_location % 2))) % 4; - return; - default: - return; - } -} - -struct decoration_data get_undecorated_decoration_data() { - return (struct decoration_data) { - .alpha = 1.0f, - .dim = 0.0f, - .dim_color = config->dim_inactive_colors.unfocused, - .corner_radius = 0, - .saturation = 1.0f, - .has_titlebar = false, - .blur = false, - .discard_transparent = false, - .shadow = false, - }; -} - -/** - * Apply scale to a width or height. - * - * One does not simply multiply the width by the scale. We allow fractional - * scaling, which means the resulting scaled width might be a decimal. - * So we round it. - * - * But even this can produce undesirable results depending on the X or Y offset - * of the box. For example, with a scale of 1.5, a box with width=1 should not - * scale to 2px if its X coordinate is 1, because the X coordinate would have - * scaled to 2px. - */ -static int scale_length(int length, int offset, float scale) { - return roundf((offset + length) * scale) - roundf(offset * scale); -} - -static enum wlr_scale_filter_mode get_scale_filter(struct sway_output *output) { - switch (output->scale_filter) { - case SCALE_FILTER_LINEAR: - return WLR_SCALE_FILTER_BILINEAR; - case SCALE_FILTER_NEAREST: - return WLR_SCALE_FILTER_NEAREST; - default: - abort(); // unreachable - } -} - -static void render_texture(struct fx_render_context *ctx, struct wlr_texture *texture, - const struct wlr_fbox *_src_box, const struct wlr_box *dst_box, - const struct wlr_box *_clip_box, enum wl_output_transform transform, - struct decoration_data deco_data) { - struct sway_output *output = ctx->output; - - struct wlr_box proj_box = *dst_box; - - struct wlr_fbox src_box = {0}; - if (_src_box) { - src_box = *_src_box; - } - - pixman_region32_t damage; - pixman_region32_init_rect(&damage, proj_box.x, proj_box.y, - proj_box.width, proj_box.height); - pixman_region32_intersect(&damage, &damage, ctx->output_damage); - - struct wlr_box clip_box = {0}; - if (_clip_box) { - pixman_region32_intersect_rect(&damage, &damage, - _clip_box->x, _clip_box->y, _clip_box->width, _clip_box->height); - - clip_box = *_clip_box; - } - - bool damaged = pixman_region32_not_empty(&damage); - if (!damaged) { - goto damage_finish; - } - - transform_output_box(&proj_box, output->wlr_output); - transform_output_box(&clip_box, output->wlr_output); - transform_output_damage(&damage, output->wlr_output); - transform = wlr_output_transform_compose(transform, output->wlr_output->transform); - - fx_render_pass_add_texture(ctx->pass, &(struct fx_render_texture_options) { - .base = { - .texture = texture, - .src_box = src_box, - .dst_box = proj_box, - .transform = transform, - .alpha = &deco_data.alpha, - .clip = &damage, - .filter_mode = get_scale_filter(output), - }, - .clip_box = &clip_box, - .corner_radius = deco_data.corner_radius, - .has_titlebar = deco_data.has_titlebar, - .dim = deco_data.dim, - .dim_color = { - .r = deco_data.dim_color[0], - .g = deco_data.dim_color[1], - .b = deco_data.dim_color[2], - .a = deco_data.dim_color[3], - } - }); - -damage_finish: - pixman_region32_fini(&damage); -} - -void render_blur(struct fx_render_context *ctx, struct wlr_texture *texture, - const struct wlr_fbox *src_box, const struct wlr_box *dst_box, - bool optimized_blur, pixman_region32_t *opaque_region, - struct decoration_data deco_data) { - struct sway_output *output = ctx->output; - - struct wlr_box proj_box = *dst_box; - - pixman_region32_t damage; - pixman_region32_init_rect(&damage, proj_box.x, proj_box.y, - proj_box.width, proj_box.height); - pixman_region32_intersect(&damage, &damage, ctx->output_damage); - - if (!pixman_region32_not_empty(&damage)) { - goto damage_finish; - } - - transform_output_box(&proj_box, output->wlr_output); - transform_output_damage(&damage, output->wlr_output); - - struct fx_render_blur_pass_options blur_options = { - .tex_options = { - .base = { - .texture = texture, - .src_box = *src_box, - .dst_box = proj_box, - .transform = WL_OUTPUT_TRANSFORM_NORMAL, - .clip = &damage, - .filter_mode = WLR_SCALE_FILTER_BILINEAR, - }, - .clip_box = &proj_box, - .corner_radius = deco_data.corner_radius, - .discard_transparent = false, - }, - .opaque_region = opaque_region, - .use_optimized_blur = optimized_blur, - .blur_data = &config->blur_params, - .ignore_transparent = deco_data.discard_transparent, - }; - // Render the actual blur behind the surface - fx_render_pass_add_blur(ctx->pass, &blur_options); - -damage_finish: - pixman_region32_fini(&damage); -} - -// _box.x and .y are expected to be layout-local -// _box.width and .height are expected to be output-buffer-local -void render_box_shadow(struct fx_render_context *ctx, const struct wlr_box *_box, - const float color[static 4], float blur_sigma, float corner_radius, - float offset_x, float offset_y) { - struct wlr_output *wlr_output = ctx->output->wlr_output; - - struct wlr_box box; - memcpy(&box, _box, sizeof(struct wlr_box)); - - // Extend the size of the box while also considering the shadow offset - struct wlr_box shadow_box; - memcpy(&shadow_box, _box, sizeof(struct wlr_box)); - shadow_box.x -= blur_sigma - offset_x; - shadow_box.y -= blur_sigma - offset_y; - shadow_box.width += blur_sigma * 2; - shadow_box.height += blur_sigma * 2; - - pixman_region32_t damage; - pixman_region32_init_rect(&damage, shadow_box.x, shadow_box.y, - shadow_box.width, shadow_box.height); - pixman_region32_intersect(&damage, &damage, ctx->output_damage); - if (!pixman_region32_not_empty(&damage)) { - goto damage_finish; - } - - transform_output_damage(&damage, wlr_output); - transform_output_box(&box, wlr_output); - transform_output_box(&shadow_box, wlr_output); - - struct shadow_data shadow_data = { - .enabled = true, - .offset_x = offset_x, - .offset_y = offset_y, - .color = { - .r = color[0], - .g = color[1], - .b = color[2], - .a = color[3], - }, - .blur_sigma = blur_sigma, - }; - struct fx_render_box_shadow_options shadow_options = { - .shadow_box = shadow_box, - .clip_box = box, - .clip = &damage, - .shadow_data = &shadow_data, - .corner_radius = corner_radius, - }; - fx_render_pass_add_box_shadow(ctx->pass, &shadow_options); - -damage_finish: - pixman_region32_fini(&damage); -} - -// _box.x and .y are expected to be layout-local -// _box.width and .height are expected to be output-buffer-local -void render_rounded_border_corner(struct fx_render_context *ctx, const struct wlr_box *_box, - const float color[static 4], int corner_radius, int border_thickness, - enum corner_location location) { - struct wlr_output *wlr_output = ctx->output->wlr_output; - - struct wlr_box box = *_box; - const int size = MAX(box.width, box.height); - box.width = size; - box.height = size; - box.x -= ctx->output->lx * wlr_output->scale; - box.y -= ctx->output->ly * wlr_output->scale; - - pixman_region32_t damage; - pixman_region32_init_rect(&damage, box.x, box.y, box.width, box.height); - pixman_region32_intersect(&damage, &damage, ctx->output_damage); - if (!pixman_region32_not_empty(&damage)) { - goto damage_finish; - } - - transform_output_damage(&damage, wlr_output); - transform_output_box(&box, wlr_output); - transform_corner_location(&location, wlr_output); - - struct fx_render_rounded_border_corner_options border_corner_options = { - .base = { - .box = box, - .color = { - .r = color[0], - .g = color[1], - .b = color[2], - .a = color[3], - }, - .clip = &damage, // Render with the original extended clip region - }, - .corner_radius = corner_radius, - .border_thickness = border_thickness, - .corner_location = location - }; - fx_render_pass_add_rounded_border_corner(ctx->pass, &border_corner_options); - -damage_finish: - pixman_region32_fini(&damage); -} - -static void render_surface_iterator(struct sway_output *output, - struct sway_view *_view, struct wlr_surface *surface, - struct wlr_box *_box, void *_data) { - struct render_data *data = _data; - struct wlr_output *wlr_output = output->wlr_output; - - struct wlr_texture *texture = wlr_surface_get_texture(surface); - if (!texture) { - return; - } - - struct wlr_fbox src_box; - wlr_surface_get_buffer_source_box(surface, &src_box); - - struct wlr_box dst_box = *_box; - struct wlr_box clip_box = *_box; - if (data->clip_box != NULL) { - clip_box.width = fmin(dst_box.width, data->clip_box->width); - clip_box.height = fmin(dst_box.height, data->clip_box->height); - clip_box.x = fmax(dst_box.x, data->clip_box->x); - clip_box.y = fmax(dst_box.y, data->clip_box->y); - } - scale_box(&dst_box, wlr_output->scale); - scale_box(&clip_box, wlr_output->scale); - - struct decoration_data deco_data = data->deco_data; - deco_data.corner_radius *= wlr_output->scale; - - // render blur - struct sway_view *view = data->view; - bool is_subsurface = view ? view->surface != surface : false; - if (deco_data.blur && config_should_parameters_blur() && !is_subsurface) { - pixman_region32_t opaque_region; - pixman_region32_init(&opaque_region); - - bool has_alpha = false; - if (deco_data.alpha < 1.0 || deco_data.dim_color[3] < 1.0) { - has_alpha = true; - pixman_region32_union_rect(&opaque_region, &opaque_region, 0, 0, 0, 0); - } else { - has_alpha = !surface->opaque; - pixman_region32_copy(&opaque_region, &surface->opaque_region); - } - - if (has_alpha) { - bool should_optimize_blur = view ? - !container_is_floating_or_child(view->container) || config->blur_xray - : false; - render_blur(data->ctx, texture, &src_box, &clip_box, - should_optimize_blur, &opaque_region, deco_data); - } - - pixman_region32_fini(&opaque_region); - } - - deco_data.discard_transparent = false; - - render_texture(data->ctx, texture, - &src_box, &dst_box, &clip_box, surface->current.transform, deco_data); - - wlr_presentation_surface_textured_on_output(server.presentation, surface, - wlr_output); -} - -// view will be NULL every time -static void render_layer_iterator(struct sway_output *output, - struct sway_view *view, struct wlr_surface *surface, - struct wlr_box *_box, void *_data) { - // render the layer's surface - render_surface_iterator(output, view, surface, _box, _data); - - struct render_data *data = _data; - struct decoration_data deco_data = data->deco_data; - - // Ignore effects if this is a subsurface - if (!wlr_layer_surface_v1_try_from_wlr_surface(surface)) { - deco_data = get_undecorated_decoration_data(); - } - - // render shadow - if (deco_data.shadow && config_should_parameters_shadow()) { - float output_scale = output->wlr_output->scale; - struct wlr_box box = *_box; - scale_box(&box, output_scale); - render_box_shadow(data->ctx, &box, config->shadow_color, config->shadow_blur_sigma * output_scale, - deco_data.corner_radius * output_scale, config->shadow_offset_x * output_scale, config->shadow_offset_y * output_scale); - } -} - -static void render_layer_toplevel(struct fx_render_context *ctx, struct wl_list *layer_surfaces) { - struct render_data data = { - .deco_data = get_undecorated_decoration_data(), - .ctx = ctx, - }; - output_layer_for_each_toplevel_surface(ctx->output, layer_surfaces, - render_layer_iterator, &data); -} - - static void render_layer_popups(struct fx_render_context *ctx, struct wl_list *layer_surfaces) { - struct render_data data = { - .deco_data = get_undecorated_decoration_data(), - .ctx = ctx, - }; - output_layer_for_each_popup_surface(ctx->output, layer_surfaces, - render_layer_iterator, &data); -} - -#if HAVE_XWAYLAND -static void render_unmanaged(struct fx_render_context *ctx, struct wl_list *unmanaged) { - struct render_data data = { - .deco_data = get_undecorated_decoration_data(), - .ctx = ctx, - }; - output_unmanaged_for_each_surface(ctx->output, unmanaged, - render_surface_iterator, &data); -} -#endif - -static void render_input_popups(struct fx_render_context *ctx, struct wl_list *input_popups) { - struct render_data data = { - .deco_data = get_undecorated_decoration_data(), - .ctx = ctx, - }; - output_input_popups_for_each_surface(ctx->output, input_popups, - render_surface_iterator, &data); -} - -static void render_drag_icons(struct fx_render_context *ctx, struct wl_list *drag_icons) { - struct render_data data = { - .deco_data = get_undecorated_decoration_data(), - .ctx = ctx, - }; - output_drag_icons_for_each_surface(ctx->output, drag_icons, - render_surface_iterator, &data); -} - -// _box.x and .y are expected to be layout-local -// _box.width and .height are expected to be output-buffer-local -void render_rect(struct fx_render_context *ctx, const struct wlr_box *_box, - float color[static 4]) { - struct wlr_output *wlr_output = ctx->output->wlr_output; - - struct wlr_box box = *_box; - box.x -= ctx->output->lx * wlr_output->scale; - box.y -= ctx->output->ly * wlr_output->scale; - - pixman_region32_t damage; - pixman_region32_init_rect(&damage, box.x, box.y, - box.width, box.height); - pixman_region32_intersect(&damage, &damage, ctx->output_damage); - bool damaged = pixman_region32_not_empty(&damage); - if (!damaged) { - goto damage_finish; - } - - transform_output_damage(&damage, wlr_output); - transform_output_box(&box, wlr_output); - - fx_render_pass_add_rect(ctx->pass, &(struct fx_render_rect_options){ - .base = { - .box = box, - .color = { - .r = color[0], - .g = color[1], - .b = color[2], - .a = color[3], - }, - .clip = &damage, - }, - }); - -damage_finish: - pixman_region32_fini(&damage); -} - -void render_rounded_rect(struct fx_render_context *ctx, const struct wlr_box *_box, - float color[static 4], int corner_radius, enum corner_location corner_location) { - if (!corner_radius) { - render_rect(ctx, _box, color); - return; - } - - struct wlr_output *wlr_output = ctx->output->wlr_output; - - struct wlr_box box = *_box; - box.x -= ctx->output->lx * wlr_output->scale; - box.y -= ctx->output->ly * wlr_output->scale; - - pixman_region32_t damage; - pixman_region32_init_rect(&damage, box.x, box.y, - box.width, box.height); - pixman_region32_intersect(&damage, &damage, ctx->output_damage); - bool damaged = pixman_region32_not_empty(&damage); - if (!damaged) { - goto damage_finish; - } - - transform_output_damage(&damage, wlr_output); - transform_output_box(&box, wlr_output); - transform_corner_location(&corner_location, wlr_output); - - fx_render_pass_add_rounded_rect(ctx->pass, &(struct fx_render_rounded_rect_options){ - .base = { - .box = box, - .color = { - .r = color[0], - .g = color[1], - .b = color[2], - .a = color[3], - }, - .clip = &damage, - }, - .corner_radius = corner_radius, - .corner_location = corner_location - }); - -damage_finish: - pixman_region32_fini(&damage); -} - -void premultiply_alpha(float color[4], float opacity) { - color[3] *= opacity; - color[0] *= color[3]; - color[1] *= color[3]; - color[2] *= color[3]; -} - -static void render_view_toplevels(struct fx_render_context *ctx, - struct sway_view *view, struct decoration_data deco_data) { - struct render_data data = { - .deco_data = deco_data, - .view = view, - .ctx = ctx, - }; - // Clip the window to its view size, ignoring CSD - struct wlr_box clip_box; - struct sway_container_state state = view->container->current; - clip_box.x = floor(state.x) - ctx->output->lx; - clip_box.y = floor(state.y) - ctx->output->ly; - clip_box.width = state.width; - clip_box.height = state.height; - - bool smart = config->hide_edge_borders_smart == ESMART_ON || - (config->hide_edge_borders_smart == ESMART_NO_GAPS && - !gaps_to_edge(view)); - - if (state.fullscreen_mode == FULLSCREEN_NONE - && (state.border == B_PIXEL || state.border == B_NORMAL) - && !smart) { - clip_box.x += state.border_thickness; - clip_box.width -= state.border_thickness * 2; - - if (deco_data.has_titlebar) { - // Shift the box downward to compensate for the titlebar - int titlebar_thickness = container_titlebar_height(); - clip_box.y += titlebar_thickness; - clip_box.height -= state.border_thickness + titlebar_thickness; - } else { - // Regular border - clip_box.y += state.border_thickness; - clip_box.height -= state.border_thickness * 2; - } - } - data.clip_box = &clip_box; - - // Render all toplevels without descending into popups - double ox = view->container->surface_x - - ctx->output->lx - view->geometry.x; - double oy = view->container->surface_y - - ctx->output->ly - view->geometry.y; - output_surface_for_each_surface(ctx->output, view->surface, ox, oy, - render_surface_iterator, &data); -} - -static void render_view_popups(struct fx_render_context *ctx, struct sway_view *view, - struct decoration_data deco_data) { - struct render_data data = { - .deco_data = deco_data, - .view = view, - .ctx = ctx, - }; - output_view_for_each_popup_surface(ctx->output, view, - render_surface_iterator, &data); -} - -static void render_saved_view(struct fx_render_context *ctx, struct sway_view *view, struct decoration_data deco_data) { - struct sway_output *output = ctx->output; - struct wlr_output *wlr_output = output->wlr_output; - - if (wl_list_empty(&view->saved_buffers)) { - return; - } - - deco_data.corner_radius *= wlr_output->scale; - - struct sway_saved_buffer *saved_buf; - wl_list_for_each(saved_buf, &view->saved_buffers, link) { - if (!saved_buf->buffer->texture) { - continue; - } - - struct wlr_box proj_box = { - .x = saved_buf->x - view->saved_geometry.x - output->lx, - .y = saved_buf->y - view->saved_geometry.y - output->ly, - .width = saved_buf->width, - .height = saved_buf->height, - }; - - struct wlr_box output_box = { - .width = output->width, - .height = output->height, - }; - - struct wlr_box intersection; - bool intersects = wlr_box_intersection(&intersection, &output_box, &proj_box); - if (!intersects) { - continue; - } - - struct wlr_box dst_box = proj_box; - struct wlr_box clip_box = proj_box; - - // Clip to actual geometry, clipping the CSD - struct sway_container_state state = view->container->current; - clip_box.x = state.x - output->lx; - clip_box.y = state.y - output->ly; - clip_box.width = state.width; - clip_box.height = state.height; - if (state.border == B_PIXEL || state.border == B_NORMAL) { - clip_box.x += state.border_thickness; - clip_box.width -= state.border_thickness * 2; - - if (deco_data.has_titlebar) { - // Shift the box downward to compensate for the titlebar - int titlebar_thickness = container_titlebar_height(); - clip_box.y += titlebar_thickness; - clip_box.height -= state.border_thickness + titlebar_thickness; - } else { - // Regular border - clip_box.y += state.border_thickness; - clip_box.height -= state.border_thickness * 2; - } - } - - scale_box(&dst_box, wlr_output->scale); - scale_box(&clip_box, wlr_output->scale); - - // render blur - if (deco_data.blur && config_should_parameters_blur()) { - struct fx_texture_attribs attribs; - fx_texture_get_attribs(saved_buf->buffer->texture, &attribs); - if (deco_data.alpha < 1.0 || attribs.has_alpha) { - pixman_region32_t opaque_region; - pixman_region32_init(&opaque_region); - pixman_region32_union_rect(&opaque_region, &opaque_region, 0, 0, 0, 0); - - bool should_optimize_blur = !container_is_floating_or_child(view->container) || config->blur_xray; - render_blur(ctx, saved_buf->buffer->texture, - &saved_buf->source_box, &clip_box, should_optimize_blur, - &opaque_region, deco_data); - - pixman_region32_fini(&opaque_region); - } - } - - deco_data.discard_transparent = false; - - render_texture(ctx, saved_buf->buffer->texture, - &saved_buf->source_box, &dst_box, &clip_box, saved_buf->transform, deco_data); - - // FIXME: we should set the surface that this saved buffer originates from - // as sampled here. - // https://github.com/swaywm/sway/pull/4465#discussion_r321082059 - } -} - -/** - * Render a view's surface, shadow, and left/bottom/right borders. - */ -static void render_view(struct fx_render_context *ctx, struct sway_container *con, - struct border_colors *colors, struct decoration_data deco_data) { - struct sway_view *view = con->view; - - if (!wl_list_empty(&view->saved_buffers)) { - render_saved_view(ctx, view, deco_data); - } else if (view->surface) { - render_view_toplevels(ctx, view, deco_data); - } - - struct sway_container_state *state = &con->current; - - if (state->border == B_CSD && !config->shadows_on_csd_enabled) { - return; - } - - struct wlr_box box; - int corner_radius = deco_data.corner_radius; - float output_scale = ctx->output->wlr_output->scale; - - // render shadow - if (con->shadow_enabled && config_should_parameters_shadow()) { - box.x = floor(state->x) - ctx->output->lx; - box.y = floor(state->y) - ctx->output->ly; - box.width = state->width; - box.height = state->height; - scale_box(&box, output_scale); - int shadow_corner_radius = corner_radius == 0 ? 0 : corner_radius + state->border_thickness; - float* shadow_color = view_is_urgent(view) || state->focused ? - config->shadow_color : config->shadow_inactive_color; - - render_box_shadow(ctx, &box, shadow_color, config->shadow_blur_sigma * output_scale, - shadow_corner_radius * output_scale, config->shadow_offset_x * output_scale, - config->shadow_offset_y * output_scale); - } - - if (state->border == B_NONE || state->border == B_CSD) { - return; - } - - float color[4]; - - if (state->border_left) { - memcpy(&color, colors->child_border, sizeof(float) * 4); - premultiply_alpha(color, con->alpha); - box.x = floor(state->x); - box.y = floor(state->content_y); - box.width = state->border_thickness; - box.height = state->content_height - corner_radius; - if (corner_radius && !deco_data.has_titlebar) { - box.y += corner_radius; - box.height -= corner_radius; - } - scale_box(&box, output_scale); - render_rect(ctx, &box, color); - } - - list_t *siblings = container_get_current_siblings(con); - enum sway_container_layout layout = - container_current_parent_layout(con); - - if (state->border_right) { - if (!container_is_current_floating(con) && siblings->length == 1 && layout == L_HORIZ) { - memcpy(&color, colors->indicator, sizeof(float) * 4); - } else { - memcpy(&color, colors->child_border, sizeof(float) * 4); - } - premultiply_alpha(color, con->alpha); - box.x = floor(state->content_x + state->content_width); - box.y = floor(state->content_y); - box.width = state->border_thickness; - box.height = state->content_height - corner_radius; - if (corner_radius && !deco_data.has_titlebar) { - box.y += corner_radius; - box.height -= corner_radius; - } - scale_box(&box, output_scale); - render_rect(ctx, &box, color); - } - - if (state->border_bottom) { - if (!container_is_current_floating(con) && siblings->length == 1 && layout == L_VERT) { - memcpy(&color, colors->indicator, sizeof(float) * 4); - } else { - memcpy(&color, colors->child_border, sizeof(float) * 4); - } - premultiply_alpha(color, con->alpha); - box.x = floor(state->x); - box.y = floor(state->content_y + state->content_height); - box.width = state->width; - box.height = state->border_thickness; - // adjust sizing for rounded border corners - if (deco_data.corner_radius) { - box.x += corner_radius + state->border_thickness; - box.width -= 2 * (corner_radius + state->border_thickness); - } - scale_box(&box, output_scale); - render_rect(ctx, &box, color); - - if (corner_radius && state->border_thickness > 0) { - int size = 2 * (corner_radius + state->border_thickness); - int scaled_corner_radius = corner_radius * output_scale; - int scaled_border_thickness = state->border_thickness * output_scale; - if (state->border_left) { - box.x = floor(state->x); - box.y = floor(state->y + state->height - size); - box.width = size; - box.height = size; - scale_box(&box, output_scale); - render_rounded_border_corner(ctx, &box, color, scaled_corner_radius, - scaled_border_thickness, BOTTOM_LEFT); - } - if (state->border_right) { - box.x = floor(state->x + state->width - size); - box.y = floor(state->y + state->height - size); - box.width = size; - box.height = size; - scale_box(&box, output_scale); - render_rounded_border_corner(ctx, &box, color, scaled_corner_radius, - scaled_border_thickness, BOTTOM_RIGHT); - } - } - } -} - -/** - * Render a titlebar. - * - * Care must be taken not to render over the same pixel multiple times, - * otherwise the colors will be incorrect when using opacity. - * - * The height is: 1px border, 3px padding, font height, 3px padding, 1px border - * The left side is: 1px border, 2px padding, title - */ -static void render_titlebar(struct fx_render_context *ctx, struct sway_container *con, - int x, int y, int width, struct border_colors *colors, int corner_radius, - enum corner_location corner_location, struct wlr_texture *title_texture, - struct wlr_texture *marks_texture) { - struct wlr_box box; - float color[4]; - struct sway_output *output = ctx->output; - float output_scale = output->wlr_output->scale; - double output_x = output->lx; - double output_y = output->ly; - int titlebar_border_thickness = config->titlebar_border_thickness; - int titlebar_h_padding = config->titlebar_h_padding; - int titlebar_v_padding = config->titlebar_v_padding; - enum alignment title_align = config->title_align; - // value by which all heights should be adjusted to counteract removed bottom border - int bottom_border_compensation = config->titlebar_separator ? 0 : titlebar_border_thickness; - corner_radius *= output_scale; - - // Single pixel bar above title - memcpy(&color, colors->border, sizeof(float) * 4); - premultiply_alpha(color, con->alpha); - box.x = x; - box.y = y; - box.width = width; - box.height = titlebar_border_thickness; - if (corner_radius) { - if (corner_location != TOP_RIGHT) { - box.x += corner_radius; - } - if (corner_location == ALL) { - box.width -= corner_radius * 2; - } else { - box.width -= corner_radius; - } - } - scale_box(&box, output_scale); - render_rect(ctx, &box, color); - - // Single pixel bar below title - if (!bottom_border_compensation) { - box.x = x; - box.y = y + container_titlebar_height() - titlebar_border_thickness; - box.width = width; - box.height = titlebar_border_thickness; - scale_box(&box, output_scale); - render_rect(ctx, &box, color); - } - - // Single pixel left edge - box.x = x; - box.y = y; - box.width = titlebar_border_thickness; - box.height = container_titlebar_height() - titlebar_border_thickness + bottom_border_compensation; - if (corner_radius && corner_location != TOP_RIGHT) { - box.height -= corner_radius; - box.y += corner_radius; - } - scale_box(&box, output_scale); - render_rect(ctx, &box, color); - - // Single pixel right edge - box.x = x + width - titlebar_border_thickness; - box.y = y; - box.width = titlebar_border_thickness; - box.height = container_titlebar_height() - titlebar_border_thickness + bottom_border_compensation; - if (corner_radius && corner_location != TOP_LEFT) { - box.height -= corner_radius; - box.y += corner_radius; - } - scale_box(&box, output_scale); - render_rect(ctx, &box, color); - - // if corner_radius: single pixel corners - if (corner_radius) { - // left corner - if (corner_location != TOP_RIGHT) { - box.x = x; - box.y = y; - box.width = corner_radius * 2; - box.height = corner_radius * 2; - scale_box(&box, output_scale); - render_rounded_border_corner(ctx, &box, color, corner_radius, - titlebar_border_thickness * output_scale, TOP_LEFT); - } - - // right corner - if (corner_location != TOP_LEFT) { - box.x = x + width - corner_radius * 2; - box.y = y; - box.width = corner_radius * 2; - box.height = corner_radius * 2; - scale_box(&box, output_scale); - render_rounded_border_corner(ctx, &box, color, corner_radius, - titlebar_border_thickness * output_scale, TOP_RIGHT); - } - } - - int inner_x = x - output_x + titlebar_h_padding; - int bg_y = y + titlebar_border_thickness; - size_t inner_width = width - titlebar_h_padding * 2; - - // output-buffer local - int ob_inner_x = roundf(inner_x * output_scale); - int ob_inner_width = scale_length(inner_width, inner_x, output_scale); - int ob_bg_height = scale_length( - (titlebar_v_padding - titlebar_border_thickness) * 2 + - config->font_height, bg_y, output_scale); - - // title marks textures should have no eyecandy - struct decoration_data deco_data = get_undecorated_decoration_data(); - deco_data.alpha = con->alpha; - - // Marks - int ob_marks_x = 0; // output-buffer-local - int ob_marks_width = 0; // output-buffer-local - if (config->show_marks && marks_texture) { - struct wlr_box texture_box = { - .width = marks_texture->width, - .height = marks_texture->height, - }; - ob_marks_width = texture_box.width; - - // The marks texture might be shorter than the config->font_height, in - // which case we need to pad it as evenly as possible above and below. - int ob_padding_total = ob_bg_height - texture_box.height; - int ob_padding_above = floor(ob_padding_total / 2.0); - int ob_padding_below = ceil(ob_padding_total / 2.0); - - // Render texture. If the title is on the right, the marks will be on - // the left. Otherwise, they will be on the right. - if (title_align == ALIGN_RIGHT || texture_box.width > ob_inner_width) { - texture_box.x = ob_inner_x; - } else { - texture_box.x = ob_inner_x + ob_inner_width - texture_box.width; - } - ob_marks_x = texture_box.x; - - texture_box.y = round((bg_y - output_y) * output_scale) + - ob_padding_above; - - struct wlr_box clip_box = texture_box; - if (ob_inner_width < clip_box.width) { - clip_box.width = ob_inner_width; - } - render_texture(ctx, marks_texture, - NULL, &texture_box, &clip_box, WL_OUTPUT_TRANSFORM_NORMAL, deco_data); - - // Padding above - memcpy(&color, colors->background, sizeof(float) * 4); - premultiply_alpha(color, con->alpha); - box.x = clip_box.x + round(output_x * output_scale); - box.y = roundf((y + titlebar_border_thickness) * output_scale); - box.width = clip_box.width; - box.height = ob_padding_above; - render_rect(ctx, &box, color); - - // Padding below - box.y += ob_padding_above + clip_box.height; - box.height = ob_padding_below + bottom_border_compensation; - render_rect(ctx, &box, color); - } - - // Title text - int ob_title_x = 0; // output-buffer-local - int ob_title_width = 0; // output-buffer-local - if (title_texture) { - struct wlr_box texture_box = { - .width = title_texture->width, - .height = title_texture->height, - }; - - // The effective output may be NULL when con is not on any output. - // This can happen because we render all children of containers, - // even those that are out of the bounds of any output. - struct sway_output *effective = container_get_effective_output(con); - float title_scale = effective ? effective->wlr_output->scale : output_scale; - texture_box.width = texture_box.width * output_scale / title_scale; - texture_box.height = texture_box.height * output_scale / title_scale; - ob_title_width = texture_box.width; - - // The title texture might be shorter than the config->font_height, - // in which case we need to pad it above and below. - int ob_padding_above = roundf((titlebar_v_padding - - titlebar_border_thickness) * output_scale); - int ob_padding_below = ob_bg_height - ob_padding_above - - texture_box.height; - - // Render texture - if (texture_box.width > ob_inner_width - ob_marks_width) { - texture_box.x = (title_align == ALIGN_RIGHT && ob_marks_width) - ? ob_marks_x + ob_marks_width : ob_inner_x; - } else if (title_align == ALIGN_LEFT) { - texture_box.x = ob_inner_x; - } else if (title_align == ALIGN_CENTER) { - // If there are marks visible, center between the edge and marks. - // Otherwise, center in the inner area. - if (ob_marks_width) { - texture_box.x = (ob_inner_x + ob_marks_x) / 2 - - texture_box.width / 2; - } else { - texture_box.x = ob_inner_x + ob_inner_width / 2 - - texture_box.width / 2; - } - } else { - texture_box.x = ob_inner_x + ob_inner_width - texture_box.width; - } - ob_title_x = texture_box.x; - - texture_box.y = - round((bg_y - output_y) * output_scale) + ob_padding_above; - - struct wlr_box clip_box = texture_box; - if (ob_inner_width - ob_marks_width < clip_box.width) { - clip_box.width = ob_inner_width - ob_marks_width; - } - - render_texture(ctx, title_texture, - NULL, &texture_box, &clip_box, WL_OUTPUT_TRANSFORM_NORMAL, deco_data); - - // Padding above - memcpy(&color, colors->background, sizeof(float) * 4); - premultiply_alpha(color, con->alpha); - box.x = clip_box.x + round(output_x * output_scale); - box.y = roundf((y + titlebar_border_thickness) * output_scale); - box.width = clip_box.width; - box.height = ob_padding_above; - render_rect(ctx, &box, color); - - // Padding below - box.y += ob_padding_above + clip_box.height; - box.height = ob_padding_below + bottom_border_compensation; - render_rect(ctx, &box, color); - } - - // Determine the left + right extends of the textures (output-buffer local) - int ob_left_x, ob_left_width, ob_right_x, ob_right_width; - if (ob_title_width == 0 && ob_marks_width == 0) { - ob_left_x = ob_inner_x; - ob_left_width = 0; - ob_right_x = ob_inner_x; - ob_right_width = 0; - } else if (ob_title_x < ob_marks_x) { - ob_left_x = ob_title_x; - ob_left_width = ob_title_width; - ob_right_x = ob_marks_x; - ob_right_width = ob_marks_width; - } else { - ob_left_x = ob_marks_x; - ob_left_width = ob_marks_width; - ob_right_x = ob_title_x; - ob_right_width = ob_title_width; - } - if (ob_left_x < ob_inner_x) { - ob_left_x = ob_inner_x; - } else if (ob_left_x + ob_left_width > ob_right_x + ob_right_width) { - ob_right_x = ob_left_x; - ob_right_width = ob_left_width; - } - - // Filler between title and marks - box.width = ob_right_x - ob_left_x - ob_left_width; - if (box.width > 0) { - box.x = ob_left_x + ob_left_width + round(output_x * output_scale); - box.y = roundf(bg_y * output_scale); - box.height = ob_bg_height + bottom_border_compensation; - render_rect(ctx, &box, color); - } - - // Padding on left side - box.x = x + titlebar_border_thickness; - box.y = y + titlebar_border_thickness; - box.width = titlebar_h_padding - titlebar_border_thickness; - box.height = (titlebar_v_padding - titlebar_border_thickness) * 2 + - config->font_height + bottom_border_compensation; - scale_box(&box, output_scale); - int left_x = ob_left_x + round(output_x * output_scale); - if (box.x + box.width < left_x) { - box.width += left_x - box.x - box.width; - } - if (corner_radius && (corner_location == TOP_LEFT || corner_location == ALL)) { - render_rounded_rect(ctx, &box, color, corner_radius, TOP_LEFT); - } else { - render_rect(ctx, &box, color); - } - - // Padding on right side - box.x = x + width - titlebar_h_padding; - box.y = y + titlebar_border_thickness; - box.width = titlebar_h_padding - titlebar_border_thickness; - box.height = (titlebar_v_padding - titlebar_border_thickness) * 2 + - config->font_height + bottom_border_compensation; - scale_box(&box, output_scale); - int right_rx = ob_right_x + ob_right_width + round(output_x * output_scale); - if (right_rx < box.x) { - box.width += box.x - right_rx; - box.x = right_rx; - } - if (corner_radius && (corner_location == TOP_RIGHT || corner_location == ALL)) { - render_rounded_rect(ctx, &box, color, corner_radius, TOP_RIGHT); - } else { - render_rect(ctx, &box, color); - } -} - -/** - * Render the top border line for a view using "border pixel". - */ -static void render_top_border(struct fx_render_context *ctx, struct sway_container *con, - struct border_colors *colors, int corner_radius) { - struct sway_container_state *state = &con->current; - if (!state->border_top) { - return; - } - struct wlr_box box; - float color[4]; - float output_scale = ctx->output->wlr_output->scale; - - // Child border - top edge - memcpy(&color, colors->child_border, sizeof(float) * 4); - premultiply_alpha(color, con->alpha); - box.x = floor(state->x) + - (corner_radius != 0) * (corner_radius + state->border_thickness); - box.y = floor(state->y); - box.width = state->width - - ((corner_radius != 0) * 2 * (corner_radius + state->border_thickness)); - box.height = state->border_thickness; - scale_box(&box, output_scale); - render_rect(ctx, &box, color); - - if (corner_radius && state->border_thickness > 0) { - int size = 2 * (corner_radius + state->border_thickness); - int scaled_corner_radius = corner_radius * output_scale; - int scaled_border_thickness = state->border_thickness * output_scale; - if (state->border_left) { - box.x = floor(state->x); - box.y = floor(state->y); - box.width = size; - box.height = size; - scale_box(&box, output_scale); - render_rounded_border_corner(ctx, &box, color, scaled_corner_radius, - scaled_border_thickness, TOP_LEFT); - } - if (state->border_right) { - box.x = floor(state->x + state->width - size); - box.y = floor(state->y); - box.width = size; - box.height = size; - scale_box(&box, output_scale); - render_rounded_border_corner(ctx, &box, color, scaled_corner_radius, - scaled_border_thickness, TOP_RIGHT); - } - } -} - -struct parent_data { - enum sway_container_layout layout; - struct wlr_box box; - list_t *children; - bool focused; - struct sway_container *active_child; -}; - -static void render_container(struct fx_render_context *ctx, - struct sway_container *con, bool parent_focused); - -// TODO: no rounding top corners when rendering with titlebar -/** - * Render a container's children using a L_HORIZ or L_VERT layout. - * - * Wrap child views in borders and leave child containers borderless because - * they'll apply their own borders to their children. - */ -static void render_containers_linear(struct fx_render_context *ctx, struct parent_data *parent) { - for (int i = 0; i < parent->children->length; ++i) { - struct sway_container *child = parent->children->items[i]; - - if (container_is_scratchpad_hidden(child)) { - continue; - } - - if (child->view) { - struct sway_view *view = child->view; - struct border_colors *colors; - struct wlr_texture *title_texture; - struct wlr_texture *marks_texture; - struct sway_container_state *state = &child->current; - - if (view_is_urgent(view)) { - colors = &config->border_colors.urgent; - title_texture = child->title_urgent; - marks_texture = child->marks_urgent; - } else if (state->focused || parent->focused) { - colors = &config->border_colors.focused; - title_texture = child->title_focused; - marks_texture = child->marks_focused; - } else if (child == parent->active_child) { - colors = &config->border_colors.focused_inactive; - title_texture = child->title_focused_inactive; - marks_texture = child->marks_focused_inactive; - } else { - colors = &config->border_colors.unfocused; - title_texture = child->title_unfocused; - marks_texture = child->marks_unfocused; - } - - bool has_titlebar = state->border == B_NORMAL; - - struct decoration_data deco_data = { - .alpha = child->alpha, - .dim_color = view_is_urgent(view) - ? config->dim_inactive_colors.urgent - : config->dim_inactive_colors.unfocused, - .dim = child->current.focused || parent->focused ? 0.0f : child->dim, - // no corner radius if no gaps (allows smart_gaps to work as expected) - .corner_radius = config->smart_corner_radius && - ctx->output->current.active_workspace->current_gaps.top == 0 - ? 0 : child->corner_radius, - .saturation = child->saturation, - .has_titlebar = has_titlebar, - .blur = child->blur_enabled, - .discard_transparent = false, - .shadow = child->shadow_enabled, - }; - render_view(ctx, child, colors, deco_data); - if (has_titlebar) { - render_titlebar(ctx, child, floor(state->x), floor(state->y), - state->width, colors, deco_data.corner_radius, - ALL, title_texture, marks_texture); - } else if (state->border == B_PIXEL) { - render_top_border(ctx, child, colors, deco_data.corner_radius); - } - } else { - render_container(ctx, child, - parent->focused || child->current.focused); - } - } -} - -static bool container_is_focused(struct sway_container *con, void *data) { - return con->current.focused; -} - -static bool container_has_focused_child(struct sway_container *con) { - return container_find_child(con, container_is_focused, NULL); -} - -/** - * Render a container's children using the L_TABBED layout. - */ -static void render_containers_tabbed(struct fx_render_context *ctx, struct parent_data *parent) { - if (!parent->children->length) { - return; - } - struct sway_container *current = parent->active_child; - struct border_colors *current_colors = &config->border_colors.unfocused; - int tab_width = parent->box.width / parent->children->length; - - struct decoration_data deco_data = { - .alpha = current->alpha, - .dim_color = current->view && view_is_urgent(current->view) - ? config->dim_inactive_colors.urgent - : config->dim_inactive_colors.unfocused, - .dim = current->current.focused || parent->focused ? 0.0f : current->dim, - // no corner radius if no gaps (allows smart_gaps to work as expected) - .corner_radius = config->smart_corner_radius && - ctx->output->current.active_workspace->current_gaps.top == 0 - ? 0 : current->corner_radius, - .saturation = current->saturation, - .has_titlebar = true, - .blur = current->blur_enabled, - .discard_transparent = false, - .shadow = current->shadow_enabled, - }; - - // Render tabs - for (int i = 0; i < parent->children->length; ++i) { - struct sway_container *child = parent->children->items[i]; - struct sway_view *view = child->view; - struct sway_container_state *cstate = &child->current; - struct border_colors *colors; - struct wlr_texture *title_texture; - struct wlr_texture *marks_texture; - bool urgent = view ? - view_is_urgent(view) : container_has_urgent_child(child); - - if (urgent) { - colors = &config->border_colors.urgent; - title_texture = child->title_urgent; - marks_texture = child->marks_urgent; - } else if (cstate->focused || parent->focused) { - colors = &config->border_colors.focused; - title_texture = child->title_focused; - marks_texture = child->marks_focused; - } else if (config->has_focused_tab_title && container_has_focused_child(child)) { - colors = &config->border_colors.focused_tab_title; - title_texture = child->title_focused_tab_title; - marks_texture = child->marks_focused_tab_title; - } else if (child == parent->active_child) { - colors = &config->border_colors.focused_inactive; - title_texture = child->title_focused_inactive; - marks_texture = child->marks_focused_inactive; - } else { - colors = &config->border_colors.unfocused; - title_texture = child->title_unfocused; - marks_texture = child->marks_unfocused; - } - - int x = floor(cstate->x + tab_width * i); - - // Make last tab use the remaining width of the parent - if (i == parent->children->length - 1) { - tab_width = parent->box.width - tab_width * i; - } - - // only round outer corners - int corner_radius = deco_data.corner_radius; - enum corner_location corner_location = ALL; - if (parent->children->length > 1) { - if (i == 0) { - corner_location = TOP_LEFT; - } else if (i == parent->children->length - 1) { - corner_location = TOP_RIGHT; - } else { - corner_radius = 0; - } - } - - render_titlebar(ctx, child, x, parent->box.y, tab_width, colors, - corner_radius, corner_location, title_texture, marks_texture); - - if (child == current) { - current_colors = colors; - } - } - - // Render surface and left/right/bottom borders - if (current->view) { - render_view(ctx, current, current_colors, deco_data); - } else { - render_container(ctx, current, - parent->focused || current->current.focused); - } -} - -/** - * Render a container's children using the L_STACKED layout. - */ -static void render_containers_stacked(struct fx_render_context *ctx, struct parent_data *parent) { - if (!parent->children->length) { - return; - } - struct sway_container *current = parent->active_child; - struct border_colors *current_colors = &config->border_colors.unfocused; - size_t titlebar_height = container_titlebar_height(); - - struct decoration_data deco_data = { - .alpha = current->alpha, - .dim_color = current->view && view_is_urgent(current->view) - ? config->dim_inactive_colors.urgent - : config->dim_inactive_colors.unfocused, - .dim = current->current.focused || parent->focused ? 0.0f : current->dim, - .saturation = current->saturation, - .corner_radius = config->smart_corner_radius && - ctx->output->current.active_workspace->current_gaps.top == 0 - ? 0 : current->corner_radius, - .has_titlebar = true, - .blur = current->blur_enabled, - .discard_transparent = false, - .shadow = current->shadow_enabled, - }; - - // Render titles - for (int i = 0; i < parent->children->length; ++i) { - struct sway_container *child = parent->children->items[i]; - struct sway_view *view = child->view; - struct sway_container_state *cstate = &child->current; - struct border_colors *colors; - struct wlr_texture *title_texture; - struct wlr_texture *marks_texture; - bool urgent = view ? - view_is_urgent(view) : container_has_urgent_child(child); - - if (urgent) { - colors = &config->border_colors.urgent; - title_texture = child->title_urgent; - marks_texture = child->marks_urgent; - } else if (cstate->focused || parent->focused) { - colors = &config->border_colors.focused; - title_texture = child->title_focused; - marks_texture = child->marks_focused; - } else if (config->has_focused_tab_title && container_has_focused_child(child)) { - colors = &config->border_colors.focused_tab_title; - title_texture = child->title_focused_tab_title; - marks_texture = child->marks_focused_tab_title; - } else if (child == parent->active_child) { - colors = &config->border_colors.focused_inactive; - title_texture = child->title_focused_inactive; - marks_texture = child->marks_focused_inactive; - } else { - colors = &config->border_colors.unfocused; - title_texture = child->title_unfocused; - marks_texture = child->marks_unfocused; - } - - int y = parent->box.y + titlebar_height * i; - int corner_radius = i != 0 ? 0 : deco_data.corner_radius; - render_titlebar(ctx, child, parent->box.x, y, parent->box.width, colors, - corner_radius, ALL, title_texture, marks_texture); - - if (child == current) { - current_colors = colors; - } - } - - // Render surface and left/right/bottom borders - if (current->view) { - render_view(ctx, current, current_colors, deco_data); - } else { - render_container(ctx, current, - parent->focused || current->current.focused); - } -} - -static void render_containers(struct fx_render_context *ctx, struct parent_data *parent) { - if (config->hide_lone_tab && parent->children->length == 1) { - struct sway_container *child = parent->children->items[0]; - if (child->view) { - render_containers_linear(ctx, parent); - return; - } - } - - switch (parent->layout) { - case L_NONE: - case L_HORIZ: - case L_VERT: - render_containers_linear(ctx, parent); - break; - case L_STACKED: - render_containers_stacked(ctx, parent); - break; - case L_TABBED: - render_containers_tabbed(ctx, parent); - break; - } -} - -static void render_container(struct fx_render_context *ctx, - struct sway_container *con, bool focused) { - struct parent_data data = { - .layout = con->current.layout, - .box = { - .x = floor(con->current.x), - .y = floor(con->current.y), - .width = con->current.width, - .height = con->current.height, - }, - .children = con->current.children, - .focused = focused, - .active_child = con->current.focused_inactive_child, - }; - render_containers(ctx, &data); -} - -static void render_workspace(struct fx_render_context *ctx, - struct sway_workspace *ws, bool focused) { - struct parent_data data = { - .layout = ws->current.layout, - .box = { - .x = floor(ws->current.x), - .y = floor(ws->current.y), - .width = ws->current.width, - .height = ws->current.height, - }, - .children = ws->current.tiling, - .focused = focused, - .active_child = ws->current.focused_inactive_child, - }; - render_containers(ctx, &data); -} - -static void render_floating_container(struct fx_render_context *ctx, - struct sway_container *con) { - struct sway_container_state *state = &con->current; - if (con->view) { - struct sway_view *view = con->view; - struct border_colors *colors; - struct wlr_texture *title_texture; - struct wlr_texture *marks_texture; - - if (view_is_urgent(view)) { - colors = &config->border_colors.urgent; - title_texture = con->title_urgent; - marks_texture = con->marks_urgent; - } else if (state->focused) { - colors = &config->border_colors.focused; - title_texture = con->title_focused; - marks_texture = con->marks_focused; - } else { - colors = &config->border_colors.unfocused; - title_texture = con->title_unfocused; - marks_texture = con->marks_unfocused; - } - - bool has_titlebar = state->border == B_NORMAL; - struct decoration_data deco_data = { - .alpha = con->alpha, - .dim_color = view_is_urgent(view) - ? config->dim_inactive_colors.urgent - : config->dim_inactive_colors.unfocused, - .dim = con->current.focused ? 0.0f : con->dim, - .saturation = con->saturation, - .corner_radius = con->corner_radius, - .has_titlebar = has_titlebar, - .blur = con->blur_enabled, - .discard_transparent = false, - .shadow = con->shadow_enabled, - }; - render_view(ctx, con, colors, deco_data); - if (has_titlebar) { - render_titlebar(ctx, con, floor(con->current.x), floor(con->current.y), con->current.width, - colors, deco_data.corner_radius, ALL, title_texture, marks_texture); - } else if (state->border == B_PIXEL) { - render_top_border(ctx, con, colors, deco_data.corner_radius); - } - } else { - render_container(ctx, con, state->focused); - } -} - -static void render_floating(struct fx_render_context *ctx) { - for (int i = 0; i < root->outputs->length; ++i) { - struct sway_output *output = root->outputs->items[i]; - for (int j = 0; j < output->current.workspaces->length; ++j) { - struct sway_workspace *ws = output->current.workspaces->items[j]; - if (!workspace_is_visible(ws)) { - continue; - } - for (int k = 0; k < ws->current.floating->length; ++k) { - struct sway_container *floater = ws->current.floating->items[k]; - if (floater->current.fullscreen_mode != FULLSCREEN_NONE) { - continue; - } - render_floating_container(ctx, floater); - } - } - } -} - -static void render_seatops(struct fx_render_context *ctx) { - struct sway_seat *seat; - wl_list_for_each(seat, &server.input->seats, link) { - seatop_render(seat, ctx); - } -} - -void output_render(struct fx_render_context *ctx) { - struct wlr_output *wlr_output = ctx->output->wlr_output; - struct sway_output *output = ctx->output; - pixman_region32_t *damage = ctx->output_damage; - - struct fx_effect_framebuffers *effect_fbos = ctx->pass->fx_effect_framebuffers; - - struct sway_workspace *workspace = output->current.active_workspace; - if (workspace == NULL) { - return; - } - - struct sway_container *fullscreen_con = root->fullscreen_global; - if (!fullscreen_con) { - fullscreen_con = workspace->current.fullscreen; - } - - if (!pixman_region32_not_empty(damage)) { - // Output isn't damaged but needs buffer swap - return; - } - - if (debug.damage == DAMAGE_HIGHLIGHT) { - fx_render_pass_add_rect(ctx->pass, &(struct fx_render_rect_options){ - .base = { - .box = { .width = wlr_output->width, .height = wlr_output->height }, - .color = { .r = 1, .g = 1, .b = 0, .a = 1 }, - }, - }); - } - - pixman_region32_t transformed_damage; - pixman_region32_init(&transformed_damage); - pixman_region32_copy(&transformed_damage, damage); - transform_output_damage(&transformed_damage, wlr_output); - - if (server.session_lock.locked) { - struct wlr_render_color clear_color = { - .a = 1.0f - }; - if (server.session_lock.lock == NULL) { - // abandoned lock -> red BG - clear_color.r = 1.f; - } - - fx_render_pass_add_rect(ctx->pass, &(struct fx_render_rect_options){ - .base = { - .box = { .width = wlr_output->width, .height = wlr_output->height }, - .color = clear_color, - .clip = &transformed_damage, - }, - }); - - if (server.session_lock.lock != NULL) { - struct render_data data = { - .deco_data = get_undecorated_decoration_data(), - .ctx = ctx, - }; - - struct wlr_session_lock_surface_v1 *lock_surface; - wl_list_for_each(lock_surface, &server.session_lock.lock->surfaces, link) { - if (lock_surface->output != wlr_output) { - continue; - } - if (!lock_surface->surface->mapped) { - continue; - } - - output_surface_for_each_surface(output, lock_surface->surface, - 0.0, 0.0, render_surface_iterator, &data); - } - } - goto renderer_end; - } - - struct sway_seat *seat = input_manager_current_seat(); - struct sway_container *focus = seat_get_focused_container(seat); - - if (output_has_opaque_overlay_layer_surface(output)) { - goto render_overlay; - } - - if (fullscreen_con) { - fx_render_pass_add_rect(ctx->pass, &(struct fx_render_rect_options){ - .base = { - .box = { .width = wlr_output->width, .height = wlr_output->height }, - .color = { .r = 0, .g = 0, .b = 0, .a = 1 }, - .clip = &transformed_damage, - }, - }); - - if (fullscreen_con->view) { - struct decoration_data deco_data = get_undecorated_decoration_data(); - deco_data.saturation = fullscreen_con->saturation; - if (!wl_list_empty(&fullscreen_con->view->saved_buffers)) { - render_saved_view(ctx, fullscreen_con->view, deco_data); - } else if (fullscreen_con->view->surface) { - render_view_toplevels(ctx, fullscreen_con->view, deco_data); - } - } else { - render_container(ctx, fullscreen_con, fullscreen_con->current.focused); - } - - for (int i = 0; i < workspace->current.floating->length; ++i) { - struct sway_container *floater = - workspace->current.floating->items[i]; - if (container_is_transient_for(floater, fullscreen_con)) { - render_floating_container(ctx, floater); - } - } -#if HAVE_XWAYLAND - render_unmanaged(ctx, &root->xwayland_unmanaged); -#endif - } else { - int output_width, output_height; - wlr_output_transformed_resolution(wlr_output, &output_width, &output_height); - - pixman_region32_t blur_region; - pixman_region32_init(&blur_region); - bool workspace_has_blur = workspace_get_blur_info(workspace, &blur_region); - // Expand the damage to compensate for blur - if (effect_fbos && workspace_has_blur) { - // Skip the blur artifact prevention if damaging the whole viewport - if (effect_fbos->blur_buffer_dirty) { - // Needs to be extended before clearing - pixman_region32_union_rect(damage, damage, - 0, 0, output_width, output_height); - } else { - // copy the surrounding content where the blur would display artifacts - // and draw it above the artifacts - - // Expand the original damage to compensate for surrounding - // blurred views to avoid sharp edges between damage regions - wlr_region_expand(damage, damage, config_get_blur_size()); - - pixman_region32_t extended_damage; - pixman_region32_init(&extended_damage); - pixman_region32_intersect(&extended_damage, damage, &blur_region); - // Expand the region to compensate for blur artifacts - wlr_region_expand(&extended_damage, &extended_damage, config_get_blur_size()); - // Limit to the monitors viewport - pixman_region32_intersect_rect(&extended_damage, &extended_damage, - 0, 0, output_width, output_height); - - // capture the padding pixels around the blur where artifacts will be drawn - pixman_region32_subtract(&effect_fbos->blur_padding_region, - &extended_damage, damage); - // Combine into the surface damage (we need to redraw the padding area as well) - pixman_region32_union(damage, damage, &extended_damage); - pixman_region32_fini(&extended_damage); - - // Copy the new extended damage into the transformed damage - pixman_region32_copy(&transformed_damage, damage); - transform_output_damage(&transformed_damage, wlr_output); - - // Capture the padding pixels before blur for later use - fx_renderer_read_to_buffer(ctx->pass, &effect_fbos->blur_padding_region, - effect_fbos->blur_saved_pixels_buffer, - ctx->pass->buffer, true); - } - } - pixman_region32_fini(&blur_region); - - fx_render_pass_add_rect(ctx->pass, &(struct fx_render_rect_options){ - .base = { - .box = { .width = wlr_output->width, .height = wlr_output->height }, - .color = { .r = 0.25f, .g = 0.25f, .b = 0.25f, .a = 1 }, - .clip = &transformed_damage, - }, - }); - - render_layer_toplevel(ctx, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); - render_layer_toplevel(ctx, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); - - // Check if the background needs to be blurred. - // Render optimized/x-ray blur - if (effect_fbos && workspace_has_blur && effect_fbos->blur_buffer_dirty) { - const float opacity = 1.0f; - struct fx_render_blur_pass_options blur_options = { - .tex_options = { - .base = { - .transform = WL_OUTPUT_TRANSFORM_NORMAL, - .alpha = &opacity, - .blend_mode = WLR_RENDER_BLEND_MODE_NONE, - }, - .corner_radius = 0, - .discard_transparent = false, - }, - .blur_data = &config->blur_params, - }; - fx_render_pass_add_optimized_blur(ctx->pass, &blur_options); - } - - render_workspace(ctx, workspace, workspace->current.focused); - render_floating(ctx); -#if HAVE_XWAYLAND - render_unmanaged(ctx, &root->xwayland_unmanaged); -#endif - render_layer_toplevel(ctx, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); - - render_layer_popups(ctx, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); - render_layer_popups(ctx, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); - render_layer_popups(ctx, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); - } - - render_seatops(ctx); - - if (focus && focus->view) { - struct decoration_data deco_data = { - .alpha = focus->alpha, - .dim_color = view_is_urgent(focus->view) - ? config->dim_inactive_colors.urgent - : config->dim_inactive_colors.unfocused, - .dim = focus->current.focused ? 0.0f : focus->dim, - .corner_radius = 0, - .saturation = focus->saturation, - .has_titlebar = false, - .blur = false, - .discard_transparent = false, - .shadow = false, - }; - render_view_popups(ctx, focus->view, deco_data); - } - -render_overlay: - render_layer_toplevel(ctx, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); - render_layer_popups(ctx, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); - render_input_popups(ctx, &seat->im_relay.input_popups); - render_drag_icons(ctx, &root->drag_icons); - -renderer_end: - // Not needed if we damaged the whole viewport - if (effect_fbos && !effect_fbos->blur_buffer_dirty) { - // Render the saved pixels over the blur artifacts - fx_renderer_read_to_buffer(ctx->pass, &effect_fbos->blur_padding_region, - ctx->pass->buffer, effect_fbos->blur_saved_pixels_buffer, true); - } - - pixman_region32_fini(&transformed_damage); - wlr_output_add_software_cursors_to_render_pass(wlr_output, &ctx->pass->base, damage); -} diff --git a/sway/desktop/surface.c b/sway/desktop/surface.c deleted file mode 100644 index 5932eaa23..000000000 --- a/sway/desktop/surface.c +++ /dev/null @@ -1,72 +0,0 @@ -#define _POSIX_C_SOURCE 200112L -#include -#include -#include -#include -#include "sway/server.h" -#include "sway/surface.h" -#include "sway/output.h" - -static void handle_destroy(struct wl_listener *listener, void *data) { - struct sway_surface *surface = wl_container_of(listener, surface, destroy); - - surface->wlr_surface->data = NULL; - wl_list_remove(&surface->destroy.link); - - if (surface->frame_done_timer) { - wl_event_source_remove(surface->frame_done_timer); - } - - free(surface); -} - -static int surface_frame_done_timer_handler(void *data) { - struct sway_surface *surface = data; - - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - wlr_surface_send_frame_done(surface->wlr_surface, &now); - - return 0; -} - -void handle_compositor_new_surface(struct wl_listener *listener, void *data) { - struct wlr_surface *wlr_surface = data; - - struct sway_surface *surface = calloc(1, sizeof(struct sway_surface)); - surface->wlr_surface = wlr_surface; - wlr_surface->data = surface; - - surface->destroy.notify = handle_destroy; - wl_signal_add(&wlr_surface->events.destroy, &surface->destroy); - - surface->frame_done_timer = wl_event_loop_add_timer(server.wl_event_loop, - surface_frame_done_timer_handler, surface); - if (!surface->frame_done_timer) { - wl_resource_post_no_memory(wlr_surface->resource); - } -} - -void surface_update_outputs(struct wlr_surface *surface) { - float scale = 1; - struct wlr_surface_output *surface_output; - wl_list_for_each(surface_output, &surface->current_outputs, link) { - if (surface_output->output->scale > scale) { - scale = surface_output->output->scale; - } - } - wlr_fractional_scale_v1_notify_scale(surface, scale); - wlr_surface_set_preferred_buffer_scale(surface, ceil(scale)); -} - -void surface_enter_output(struct wlr_surface *surface, - struct sway_output *output) { - wlr_surface_send_enter(surface, output->wlr_output); - surface_update_outputs(surface); -} - -void surface_leave_output(struct wlr_surface *surface, - struct sway_output *output) { - wlr_surface_send_leave(surface, output->wlr_output); - surface_update_outputs(surface); -} diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c deleted file mode 100644 index 6947e1384..000000000 --- a/sway/desktop/transaction.c +++ /dev/null @@ -1,552 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include "sway/config.h" -#include "sway/desktop.h" -#include "sway/desktop/idle_inhibit_v1.h" -#include "sway/desktop/transaction.h" -#include "sway/input/cursor.h" -#include "sway/input/input-manager.h" -#include "sway/output.h" -#include "sway/tree/container.h" -#include "sway/tree/node.h" -#include "sway/tree/view.h" -#include "sway/tree/workspace.h" -#include "list.h" -#include "log.h" - -struct sway_transaction { - struct wl_event_source *timer; - list_t *instructions; // struct sway_transaction_instruction * - size_t num_waiting; - size_t num_configures; - struct timespec commit_time; -}; - -struct sway_transaction_instruction { - struct sway_transaction *transaction; - struct sway_node *node; - union { - struct sway_output_state output_state; - struct sway_workspace_state workspace_state; - struct sway_container_state container_state; - }; - uint32_t serial; - bool server_request; - bool waiting; -}; - -static struct sway_transaction *transaction_create(void) { - struct sway_transaction *transaction = - calloc(1, sizeof(struct sway_transaction)); - if (!sway_assert(transaction, "Unable to allocate transaction")) { - return NULL; - } - transaction->instructions = create_list(); - return transaction; -} - -static void transaction_destroy(struct sway_transaction *transaction) { - // Free instructions - for (int i = 0; i < transaction->instructions->length; ++i) { - struct sway_transaction_instruction *instruction = - transaction->instructions->items[i]; - struct sway_node *node = instruction->node; - node->ntxnrefs--; - if (node->instruction == instruction) { - node->instruction = NULL; - } - if (node->destroying && node->ntxnrefs == 0) { - switch (node->type) { - case N_ROOT: - sway_assert(false, "Never reached"); - break; - case N_OUTPUT: - output_destroy(node->sway_output); - break; - case N_WORKSPACE: - workspace_destroy(node->sway_workspace); - break; - case N_CONTAINER: - container_destroy(node->sway_container); - break; - } - } - free(instruction); - } - list_free(transaction->instructions); - - if (transaction->timer) { - wl_event_source_remove(transaction->timer); - } - free(transaction); -} - -static void copy_output_state(struct sway_output *output, - struct sway_transaction_instruction *instruction) { - struct sway_output_state *state = &instruction->output_state; - if (state->workspaces) { - state->workspaces->length = 0; - } else { - state->workspaces = create_list(); - } - list_cat(state->workspaces, output->workspaces); - - state->active_workspace = output_get_active_workspace(output); -} - -static void copy_workspace_state(struct sway_workspace *ws, - struct sway_transaction_instruction *instruction) { - struct sway_workspace_state *state = &instruction->workspace_state; - - state->fullscreen = ws->fullscreen; - state->x = ws->x; - state->y = ws->y; - state->width = ws->width; - state->height = ws->height; - state->layout = ws->layout; - - state->output = ws->output; - if (state->floating) { - state->floating->length = 0; - } else { - state->floating = create_list(); - } - if (state->tiling) { - state->tiling->length = 0; - } else { - state->tiling = create_list(); - } - list_cat(state->floating, ws->floating); - list_cat(state->tiling, ws->tiling); - - struct sway_seat *seat = input_manager_current_seat(); - state->focused = seat_get_focus(seat) == &ws->node; - - // Set focused_inactive_child to the direct tiling child - struct sway_container *focus = seat_get_focus_inactive_tiling(seat, ws); - if (focus) { - while (focus->pending.parent) { - focus = focus->pending.parent; - } - } - state->focused_inactive_child = focus; -} - -static void copy_container_state(struct sway_container *container, - struct sway_transaction_instruction *instruction) { - struct sway_container_state *state = &instruction->container_state; - - if (state->children) { - list_free(state->children); - } - - memcpy(state, &container->pending, sizeof(struct sway_container_state)); - - if (!container->view) { - // We store a copy of the child list to avoid having it mutated after - // we copy the state. - state->children = create_list(); - list_cat(state->children, container->pending.children); - } else { - state->children = NULL; - } - - struct sway_seat *seat = input_manager_current_seat(); - state->focused = seat_get_focus(seat) == &container->node; - - if (!container->view) { - struct sway_node *focus = - seat_get_active_tiling_child(seat, &container->node); - state->focused_inactive_child = focus ? focus->sway_container : NULL; - } -} - -static void transaction_add_node(struct sway_transaction *transaction, - struct sway_node *node, bool server_request) { - struct sway_transaction_instruction *instruction = NULL; - - // Check if we have an instruction for this node already, in which case we - // update that instead of creating a new one. - if (node->ntxnrefs > 0) { - for (int idx = 0; idx < transaction->instructions->length; idx++) { - struct sway_transaction_instruction *other = - transaction->instructions->items[idx]; - if (other->node == node) { - instruction = other; - break; - } - } - } - - if (!instruction) { - instruction = calloc(1, sizeof(struct sway_transaction_instruction)); - if (!sway_assert(instruction, "Unable to allocate instruction")) { - return; - } - instruction->transaction = transaction; - instruction->node = node; - instruction->server_request = server_request; - - list_add(transaction->instructions, instruction); - node->ntxnrefs++; - } else if (server_request) { - instruction->server_request = true; - } - - switch (node->type) { - case N_ROOT: - break; - case N_OUTPUT: - copy_output_state(node->sway_output, instruction); - break; - case N_WORKSPACE: - copy_workspace_state(node->sway_workspace, instruction); - break; - case N_CONTAINER: - copy_container_state(node->sway_container, instruction); - break; - } -} - -static void apply_output_state(struct sway_output *output, - struct sway_output_state *state) { - output_damage_whole(output); - list_free(output->current.workspaces); - memcpy(&output->current, state, sizeof(struct sway_output_state)); - output_damage_whole(output); -} - -static void apply_workspace_state(struct sway_workspace *ws, - struct sway_workspace_state *state) { - output_damage_whole(ws->current.output); - list_free(ws->current.floating); - list_free(ws->current.tiling); - memcpy(&ws->current, state, sizeof(struct sway_workspace_state)); - output_damage_whole(ws->current.output); -} - -static void apply_container_state(struct sway_container *container, - struct sway_container_state *state) { - struct sway_view *view = container->view; - // Damage the old location - desktop_damage_whole_container(container); - if (view && !wl_list_empty(&view->saved_buffers)) { - struct sway_saved_buffer *saved_buf; - wl_list_for_each(saved_buf, &view->saved_buffers, link) { - struct wlr_box box = { - .x = saved_buf->x - view->saved_geometry.x, - .y = saved_buf->y - view->saved_geometry.y, - .width = saved_buf->width, - .height = saved_buf->height, - }; - desktop_damage_box(&box); - } - } - - // There are separate children lists for each instruction state, the - // container's current state and the container's pending state - // (ie. con->children). The list itself needs to be freed here. - // Any child containers which are being deleted will be cleaned up in - // transaction_destroy(). - list_free(container->current.children); - - memcpy(&container->current, state, sizeof(struct sway_container_state)); - - if (view && !wl_list_empty(&view->saved_buffers)) { - if (!container->node.destroying || container->node.ntxnrefs == 1) { - view_remove_saved_buffer(view); - } - } - - // If the view hasn't responded to the configure, center it within - // the container. This is important for fullscreen views which - // refuse to resize to the size of the output. - if (view && view->surface) { - view_center_surface(view); - } - - // Damage the new location - desktop_damage_whole_container(container); - if (view && view->surface) { - struct wlr_surface *surface = view->surface; - struct wlr_box box = { - .x = container->current.content_x - view->geometry.x, - .y = container->current.content_y - view->geometry.y, - .width = surface->current.width, - .height = surface->current.height, - }; - desktop_damage_box(&box); - } - - if (!container->node.destroying) { - container_discover_outputs(container); - } -} - -/** - * Apply a transaction to the "current" state of the tree. - */ -static void transaction_apply(struct sway_transaction *transaction) { - sway_log(SWAY_DEBUG, "Applying transaction %p", transaction); - if (debug.txn_timings) { - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - struct timespec *commit = &transaction->commit_time; - float ms = (now.tv_sec - commit->tv_sec) * 1000 + - (now.tv_nsec - commit->tv_nsec) / 1000000.0; - sway_log(SWAY_DEBUG, "Transaction %p: %.1fms waiting " - "(%.1f frames if 60Hz)", transaction, ms, ms / (1000.0f / 60)); - } - - // Apply the instruction state to the node's current state - for (int i = 0; i < transaction->instructions->length; ++i) { - struct sway_transaction_instruction *instruction = - transaction->instructions->items[i]; - struct sway_node *node = instruction->node; - - switch (node->type) { - case N_ROOT: - break; - case N_OUTPUT: - apply_output_state(node->sway_output, &instruction->output_state); - break; - case N_WORKSPACE: - apply_workspace_state(node->sway_workspace, - &instruction->workspace_state); - break; - case N_CONTAINER: - apply_container_state(node->sway_container, - &instruction->container_state); - break; - } - - node->instruction = NULL; - } - - cursor_rebase_all(); -} - -static void transaction_commit_pending(void); - -static void transaction_progress(void) { - if (!server.queued_transaction) { - return; - } - if (server.queued_transaction->num_waiting > 0) { - return; - } - transaction_apply(server.queued_transaction); - transaction_destroy(server.queued_transaction); - server.queued_transaction = NULL; - - if (!server.pending_transaction) { - sway_idle_inhibit_v1_check_active(); - return; - } - - transaction_commit_pending(); -} - -static int handle_timeout(void *data) { - struct sway_transaction *transaction = data; - sway_log(SWAY_DEBUG, "Transaction %p timed out (%zi waiting)", - transaction, transaction->num_waiting); - transaction->num_waiting = 0; - transaction_progress(); - return 0; -} - -static bool should_configure(struct sway_node *node, - struct sway_transaction_instruction *instruction) { - if (!node_is_view(node)) { - return false; - } - if (node->destroying) { - return false; - } - if (!instruction->server_request) { - return false; - } - struct sway_container_state *cstate = &node->sway_container->current; - struct sway_container_state *istate = &instruction->container_state; -#if HAVE_XWAYLAND - // Xwayland views are position-aware and need to be reconfigured - // when their position changes. - if (node->sway_container->view->type == SWAY_VIEW_XWAYLAND) { - // Sway logical coordinates are doubles, but they get truncated to - // integers when sent to Xwayland through `xcb_configure_window`. - // X11 apps will not respond to duplicate configure requests (from their - // truncated point of view) and cause transactions to time out. - if ((int)cstate->content_x != (int)istate->content_x || - (int)cstate->content_y != (int)istate->content_y) { - return true; - } - } -#endif - if (cstate->content_width == istate->content_width && - cstate->content_height == istate->content_height) { - return false; - } - return true; -} - -static void transaction_commit(struct sway_transaction *transaction) { - sway_log(SWAY_DEBUG, "Transaction %p committing with %i instructions", - transaction, transaction->instructions->length); - transaction->num_waiting = 0; - for (int i = 0; i < transaction->instructions->length; ++i) { - struct sway_transaction_instruction *instruction = - transaction->instructions->items[i]; - struct sway_node *node = instruction->node; - bool hidden = node_is_view(node) && !node->destroying && - !view_is_visible(node->sway_container->view); - if (should_configure(node, instruction)) { - instruction->serial = view_configure(node->sway_container->view, - instruction->container_state.content_x, - instruction->container_state.content_y, - instruction->container_state.content_width, - instruction->container_state.content_height); - if (!hidden) { - instruction->waiting = true; - ++transaction->num_waiting; - } - - // From here on we are rendering a saved buffer of the view, which - // means we can send a frame done event to make the client redraw it - // as soon as possible. Additionally, this is required if a view is - // mapping and its default geometry doesn't intersect an output. - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - wlr_surface_send_frame_done( - node->sway_container->view->surface, &now); - } - if (!hidden && node_is_view(node) && - wl_list_empty(&node->sway_container->view->saved_buffers)) { - view_save_buffer(node->sway_container->view); - memcpy(&node->sway_container->view->saved_geometry, - &node->sway_container->view->geometry, - sizeof(struct wlr_box)); - } - node->instruction = instruction; - } - transaction->num_configures = transaction->num_waiting; - if (debug.txn_timings) { - clock_gettime(CLOCK_MONOTONIC, &transaction->commit_time); - } - if (debug.noatomic) { - transaction->num_waiting = 0; - } else if (debug.txn_wait) { - // Force the transaction to time out even if all views are ready. - // We do this by inflating the waiting counter. - transaction->num_waiting += 1000000; - } - - if (transaction->num_waiting) { - // Set up a timer which the views must respond within - transaction->timer = wl_event_loop_add_timer(server.wl_event_loop, - handle_timeout, transaction); - if (transaction->timer) { - wl_event_source_timer_update(transaction->timer, - server.txn_timeout_ms); - } else { - sway_log_errno(SWAY_ERROR, "Unable to create transaction timer " - "(some imperfect frames might be rendered)"); - transaction->num_waiting = 0; - } - } -} - -static void transaction_commit_pending(void) { - if (server.queued_transaction) { - return; - } - struct sway_transaction *transaction = server.pending_transaction; - server.pending_transaction = NULL; - server.queued_transaction = transaction; - transaction_commit(transaction); - transaction_progress(); -} - -static void set_instruction_ready( - struct sway_transaction_instruction *instruction) { - struct sway_transaction *transaction = instruction->transaction; - - if (debug.txn_timings) { - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - struct timespec *start = &transaction->commit_time; - float ms = (now.tv_sec - start->tv_sec) * 1000 + - (now.tv_nsec - start->tv_nsec) / 1000000.0; - sway_log(SWAY_DEBUG, "Transaction %p: %zi/%zi ready in %.1fms (%s)", - transaction, - transaction->num_configures - transaction->num_waiting + 1, - transaction->num_configures, ms, - instruction->node->sway_container->title); - } - - // If the transaction has timed out then its num_waiting will be 0 already. - if (instruction->waiting && transaction->num_waiting > 0 && - --transaction->num_waiting == 0) { - sway_log(SWAY_DEBUG, "Transaction %p is ready", transaction); - wl_event_source_timer_update(transaction->timer, 0); - } - - instruction->node->instruction = NULL; - transaction_progress(); -} - -void transaction_notify_view_ready_by_serial(struct sway_view *view, - uint32_t serial) { - struct sway_transaction_instruction *instruction = - view->container->node.instruction; - if (instruction != NULL && instruction->serial == serial) { - set_instruction_ready(instruction); - } -} - -void transaction_notify_view_ready_by_geometry(struct sway_view *view, - double x, double y, int width, int height) { - struct sway_transaction_instruction *instruction = - view->container->node.instruction; - if (instruction != NULL && - (int)instruction->container_state.content_x == (int)x && - (int)instruction->container_state.content_y == (int)y && - instruction->container_state.content_width == width && - instruction->container_state.content_height == height) { - set_instruction_ready(instruction); - } -} - -static void _transaction_commit_dirty(bool server_request) { - if (!server.dirty_nodes->length) { - return; - } - - if (!server.pending_transaction) { - server.pending_transaction = transaction_create(); - if (!server.pending_transaction) { - return; - } - } - - for (int i = 0; i < server.dirty_nodes->length; ++i) { - struct sway_node *node = server.dirty_nodes->items[i]; - transaction_add_node(server.pending_transaction, node, server_request); - node->dirty = false; - } - server.dirty_nodes->length = 0; - - transaction_commit_pending(); -} - -void transaction_commit_dirty(void) { - _transaction_commit_dirty(true); -} - -void transaction_commit_dirty_client(void) { - _transaction_commit_dirty(false); -} diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c deleted file mode 100644 index 6dde98bda..000000000 --- a/sway/desktop/xdg_shell.c +++ /dev/null @@ -1,580 +0,0 @@ -#define _POSIX_C_SOURCE 199309L -#include -#include -#include -#include -#include -#include -#include "log.h" -#include "sway/decoration.h" -#include "sway/desktop.h" -#include "sway/desktop/transaction.h" -#include "sway/input/cursor.h" -#include "sway/input/input-manager.h" -#include "sway/input/seat.h" -#include "sway/output.h" -#include "sway/tree/arrange.h" -#include "sway/tree/container.h" -#include "sway/tree/view.h" -#include "sway/tree/workspace.h" -#include "sway/xdg_decoration.h" - -static const struct sway_view_child_impl popup_impl; - -static void popup_get_view_coords(struct sway_view_child *child, - int *sx, int *sy) { - struct sway_xdg_popup *popup = (struct sway_xdg_popup *)child; - struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_popup; - - wlr_xdg_popup_get_toplevel_coords(wlr_popup, - wlr_popup->current.geometry.x - wlr_popup->base->current.geometry.x, - wlr_popup->current.geometry.y - wlr_popup->base->current.geometry.y, - sx, sy); -} - -static void popup_destroy(struct sway_view_child *child) { - if (!sway_assert(child->impl == &popup_impl, - "Expected an xdg_shell popup")) { - return; - } - struct sway_xdg_popup *popup = (struct sway_xdg_popup *)child; - wl_list_remove(&popup->new_popup.link); - wl_list_remove(&popup->destroy.link); - free(popup); -} - -static const struct sway_view_child_impl popup_impl = { - .get_view_coords = popup_get_view_coords, - .destroy = popup_destroy, -}; - -static struct sway_xdg_popup *popup_create( - struct wlr_xdg_popup *wlr_popup, struct sway_view *view); - -static void popup_handle_new_popup(struct wl_listener *listener, void *data) { - struct sway_xdg_popup *popup = - wl_container_of(listener, popup, new_popup); - struct wlr_xdg_popup *wlr_popup = data; - popup_create(wlr_popup, popup->child.view); -} - -static void popup_handle_destroy(struct wl_listener *listener, void *data) { - struct sway_xdg_popup *popup = wl_container_of(listener, popup, destroy); - view_child_destroy(&popup->child); -} - -static void popup_unconstrain(struct sway_xdg_popup *popup) { - struct sway_view *view = popup->child.view; - struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_popup; - - struct sway_workspace *workspace = view->container->pending.workspace; - if (!workspace) { - // is null if in the scratchpad - return; - } - - struct sway_output *output = workspace->output; - - // the output box expressed in the coordinate system of the toplevel parent - // of the popup - struct wlr_box output_toplevel_sx_box = { - .x = output->lx - view->container->pending.content_x + view->geometry.x, - .y = output->ly - view->container->pending.content_y + view->geometry.y, - .width = output->width, - .height = output->height, - }; - - wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); -} - -static struct sway_xdg_popup *popup_create( - struct wlr_xdg_popup *wlr_popup, struct sway_view *view) { - struct wlr_xdg_surface *xdg_surface = wlr_popup->base; - - struct sway_xdg_popup *popup = - calloc(1, sizeof(struct sway_xdg_popup)); - if (popup == NULL) { - return NULL; - } - view_child_init(&popup->child, &popup_impl, view, xdg_surface->surface); - popup->wlr_xdg_popup = xdg_surface->popup; - - wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup); - popup->new_popup.notify = popup_handle_new_popup; - wl_signal_add(&xdg_surface->events.destroy, &popup->destroy); - popup->destroy.notify = popup_handle_destroy; - - wl_signal_add(&xdg_surface->surface->events.map, &popup->child.surface_map); - wl_signal_add(&xdg_surface->surface->events.unmap, &popup->child.surface_unmap); - - popup_unconstrain(popup); - - return popup; -} - - -static struct sway_xdg_shell_view *xdg_shell_view_from_view( - struct sway_view *view) { - if (!sway_assert(view->type == SWAY_VIEW_XDG_SHELL, - "Expected xdg_shell view")) { - return NULL; - } - return (struct sway_xdg_shell_view *)view; -} - -static void get_constraints(struct sway_view *view, double *min_width, - double *max_width, double *min_height, double *max_height) { - struct wlr_xdg_toplevel_state *state = - &view->wlr_xdg_toplevel->current; - *min_width = state->min_width > 0 ? state->min_width : DBL_MIN; - *max_width = state->max_width > 0 ? state->max_width : DBL_MAX; - *min_height = state->min_height > 0 ? state->min_height : DBL_MIN; - *max_height = state->max_height > 0 ? state->max_height : DBL_MAX; -} - -static const char *get_string_prop(struct sway_view *view, - enum sway_view_prop prop) { - if (xdg_shell_view_from_view(view) == NULL) { - return NULL; - } - switch (prop) { - case VIEW_PROP_TITLE: - return view->wlr_xdg_toplevel->title; - case VIEW_PROP_APP_ID: - return view->wlr_xdg_toplevel->app_id; - default: - return NULL; - } -} - -static uint32_t configure(struct sway_view *view, double lx, double ly, - int width, int height) { - struct sway_xdg_shell_view *xdg_shell_view = - xdg_shell_view_from_view(view); - if (xdg_shell_view == NULL) { - return 0; - } - return wlr_xdg_toplevel_set_size(view->wlr_xdg_toplevel, - width, height); -} - -static void set_activated(struct sway_view *view, bool activated) { - if (xdg_shell_view_from_view(view) == NULL) { - return; - } - wlr_xdg_toplevel_set_activated(view->wlr_xdg_toplevel, activated); -} - -static void set_tiled(struct sway_view *view, bool tiled) { - if (xdg_shell_view_from_view(view) == NULL) { - return; - } - if (wl_resource_get_version(view->wlr_xdg_toplevel->resource) >= - XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION) { - enum wlr_edges edges = WLR_EDGE_NONE; - if (tiled) { - edges = WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP | - WLR_EDGE_BOTTOM; - } - wlr_xdg_toplevel_set_tiled(view->wlr_xdg_toplevel, edges); - } else { - // The version is too low for the tiled state; configure as maximized instead - // to stop the client from drawing decorations outside of the toplevel geometry. - wlr_xdg_toplevel_set_maximized(view->wlr_xdg_toplevel, tiled); - } -} - -static void set_fullscreen(struct sway_view *view, bool fullscreen) { - if (xdg_shell_view_from_view(view) == NULL) { - return; - } - wlr_xdg_toplevel_set_fullscreen(view->wlr_xdg_toplevel, fullscreen); -} - -static void set_resizing(struct sway_view *view, bool resizing) { - if (xdg_shell_view_from_view(view) == NULL) { - return; - } - wlr_xdg_toplevel_set_resizing(view->wlr_xdg_toplevel, resizing); -} - -static bool wants_floating(struct sway_view *view) { - struct wlr_xdg_toplevel *toplevel = view->wlr_xdg_toplevel; - struct wlr_xdg_toplevel_state *state = &toplevel->current; - return (state->min_width != 0 && state->min_height != 0 - && (state->min_width == state->max_width - || state->min_height == state->max_height)) - || toplevel->parent; -} - -static void for_each_surface(struct sway_view *view, - wlr_surface_iterator_func_t iterator, void *user_data) { - if (xdg_shell_view_from_view(view) == NULL) { - return; - } - wlr_xdg_surface_for_each_surface(view->wlr_xdg_toplevel->base, iterator, - user_data); -} - -static void for_each_popup_surface(struct sway_view *view, - wlr_surface_iterator_func_t iterator, void *user_data) { - if (xdg_shell_view_from_view(view) == NULL) { - return; - } - wlr_xdg_surface_for_each_popup_surface(view->wlr_xdg_toplevel->base, - iterator, user_data); -} - -static bool is_transient_for(struct sway_view *child, - struct sway_view *ancestor) { - if (xdg_shell_view_from_view(child) == NULL) { - return false; - } - struct wlr_xdg_toplevel *toplevel = child->wlr_xdg_toplevel; - while (toplevel) { - if (toplevel->parent == ancestor->wlr_xdg_toplevel) { - return true; - } - toplevel = toplevel->parent; - } - return false; -} - -static void _close(struct sway_view *view) { - if (xdg_shell_view_from_view(view) == NULL) { - return; - } - wlr_xdg_toplevel_send_close(view->wlr_xdg_toplevel); -} - -static void close_popups(struct sway_view *view) { - struct wlr_xdg_popup *popup, *tmp; - wl_list_for_each_safe(popup, tmp, &view->wlr_xdg_toplevel->base->popups, link) { - wlr_xdg_popup_destroy(popup); - } -} - -static void destroy(struct sway_view *view) { - struct sway_xdg_shell_view *xdg_shell_view = - xdg_shell_view_from_view(view); - if (xdg_shell_view == NULL) { - return; - } - free(xdg_shell_view); -} - -static const struct sway_view_impl view_impl = { - .get_constraints = get_constraints, - .get_string_prop = get_string_prop, - .configure = configure, - .set_activated = set_activated, - .set_tiled = set_tiled, - .set_fullscreen = set_fullscreen, - .set_resizing = set_resizing, - .wants_floating = wants_floating, - .for_each_surface = for_each_surface, - .for_each_popup_surface = for_each_popup_surface, - .is_transient_for = is_transient_for, - .close = _close, - .close_popups = close_popups, - .destroy = destroy, -}; - -static void handle_commit(struct wl_listener *listener, void *data) { - struct sway_xdg_shell_view *xdg_shell_view = - wl_container_of(listener, xdg_shell_view, commit); - struct sway_view *view = &xdg_shell_view->view; - struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_toplevel->base; - - struct wlr_box new_geo; - wlr_xdg_surface_get_geometry(xdg_surface, &new_geo); - bool new_size = new_geo.width != view->geometry.width || - new_geo.height != view->geometry.height || - new_geo.x != view->geometry.x || - new_geo.y != view->geometry.y; - - if (new_size) { - // The client changed its surface size in this commit. For floating - // containers, we resize the container to match. For tiling containers, - // we only recenter the surface. - desktop_damage_view(view); - memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); - if (container_is_floating(view->container)) { - view_update_size(view); - // Only set the toplevel size the current container actually has a size. - if (view->container->current.width) { - wlr_xdg_toplevel_set_size(view->wlr_xdg_toplevel, view->geometry.width, - view->geometry.height); - } - transaction_commit_dirty_client(); - } else { - view_center_surface(view); - } - desktop_damage_view(view); - } - - if (view->container->node.instruction) { - transaction_notify_view_ready_by_serial(view, - xdg_surface->current.configure_serial); - } - - view_damage_from(view); -} - -static void handle_set_title(struct wl_listener *listener, void *data) { - struct sway_xdg_shell_view *xdg_shell_view = - wl_container_of(listener, xdg_shell_view, set_title); - struct sway_view *view = &xdg_shell_view->view; - view_update_title(view, false); - view_execute_criteria(view); -} - -static void handle_set_app_id(struct wl_listener *listener, void *data) { - struct sway_xdg_shell_view *xdg_shell_view = - wl_container_of(listener, xdg_shell_view, set_app_id); - struct sway_view *view = &xdg_shell_view->view; - view_execute_criteria(view); -} - -static void handle_new_popup(struct wl_listener *listener, void *data) { - struct sway_xdg_shell_view *xdg_shell_view = - wl_container_of(listener, xdg_shell_view, new_popup); - struct wlr_xdg_popup *wlr_popup = data; - popup_create(wlr_popup, &xdg_shell_view->view); -} - -static void handle_request_maximize(struct wl_listener *listener, void *data) { - struct sway_xdg_shell_view *xdg_shell_view = - wl_container_of(listener, xdg_shell_view, request_maximize); - struct wlr_xdg_toplevel *toplevel = xdg_shell_view->view.wlr_xdg_toplevel; - wlr_xdg_surface_schedule_configure(toplevel->base); -} - -/* Minimize to scratchpad */ -static void handle_request_minimize(struct wl_listener *listener, void *data) { - struct sway_xdg_shell_view *xdg_shell_view = - wl_container_of(listener, xdg_shell_view, request_minimize); - struct sway_container *container = xdg_shell_view->view.container; - if (!container->pending.workspace) { - while (container->pending.parent) { - container = container->pending.parent; - } - } - if (!container->scratchpad) { - root_scratchpad_add_container(container, NULL); - } else if (container->pending.workspace) { - root_scratchpad_hide(container); - } - transaction_commit_dirty(); -} - -static void handle_request_fullscreen(struct wl_listener *listener, void *data) { - struct sway_xdg_shell_view *xdg_shell_view = - wl_container_of(listener, xdg_shell_view, request_fullscreen); - struct wlr_xdg_toplevel *toplevel = xdg_shell_view->view.wlr_xdg_toplevel; - struct sway_view *view = &xdg_shell_view->view; - - if (!toplevel->base->surface->mapped) { - return; - } - - struct sway_container *container = view->container; - struct wlr_xdg_toplevel_requested *req = &toplevel->requested; - if (req->fullscreen && req->fullscreen_output && req->fullscreen_output->data) { - struct sway_output *output = req->fullscreen_output->data; - struct sway_workspace *ws = output_get_active_workspace(output); - if (ws && !container_is_scratchpad_hidden(container) && - container->pending.workspace != ws) { - if (container_is_floating(container)) { - workspace_add_floating(ws, container); - } else { - container = workspace_add_tiling(ws, container); - } - } - } - - container_set_fullscreen(container, req->fullscreen); - - arrange_root(); - transaction_commit_dirty(); -} - -static void handle_request_move(struct wl_listener *listener, void *data) { - struct sway_xdg_shell_view *xdg_shell_view = - wl_container_of(listener, xdg_shell_view, request_move); - struct sway_view *view = &xdg_shell_view->view; - if (!container_is_floating(view->container) || - view->container->pending.fullscreen_mode) { - return; - } - struct wlr_xdg_toplevel_move_event *e = data; - struct sway_seat *seat = e->seat->seat->data; - if (e->serial == seat->last_button_serial) { - seatop_begin_move_floating(seat, view->container); - } -} - -static void handle_request_resize(struct wl_listener *listener, void *data) { - struct sway_xdg_shell_view *xdg_shell_view = - wl_container_of(listener, xdg_shell_view, request_resize); - struct sway_view *view = &xdg_shell_view->view; - if (!container_is_floating(view->container)) { - return; - } - struct wlr_xdg_toplevel_resize_event *e = data; - struct sway_seat *seat = e->seat->seat->data; - if (e->serial == seat->last_button_serial) { - seatop_begin_resize_floating(seat, view->container, e->edges); - } -} - -static void handle_unmap(struct wl_listener *listener, void *data) { - struct sway_xdg_shell_view *xdg_shell_view = - wl_container_of(listener, xdg_shell_view, unmap); - struct sway_view *view = &xdg_shell_view->view; - - if (!sway_assert(view->surface, "Cannot unmap unmapped view")) { - return; - } - - view_unmap(view); - - wl_list_remove(&xdg_shell_view->commit.link); - wl_list_remove(&xdg_shell_view->new_popup.link); - wl_list_remove(&xdg_shell_view->request_maximize.link); - if (xdg_shell_view->request_minimize.notify) { - wl_list_remove(&xdg_shell_view->request_minimize.link); - } - wl_list_remove(&xdg_shell_view->request_fullscreen.link); - wl_list_remove(&xdg_shell_view->request_move.link); - wl_list_remove(&xdg_shell_view->request_resize.link); - wl_list_remove(&xdg_shell_view->set_title.link); - wl_list_remove(&xdg_shell_view->set_app_id.link); -} - -static void handle_map(struct wl_listener *listener, void *data) { - struct sway_xdg_shell_view *xdg_shell_view = - wl_container_of(listener, xdg_shell_view, map); - struct sway_view *view = &xdg_shell_view->view; - struct wlr_xdg_toplevel *toplevel = view->wlr_xdg_toplevel; - - view->natural_width = toplevel->base->current.geometry.width; - view->natural_height = toplevel->base->current.geometry.height; - if (!view->natural_width && !view->natural_height) { - view->natural_width = toplevel->base->surface->current.width; - view->natural_height = toplevel->base->surface->current.height; - } - - bool csd = false; - - if (view->xdg_decoration) { - enum wlr_xdg_toplevel_decoration_v1_mode mode = - view->xdg_decoration->wlr_xdg_decoration->requested_mode; - csd = mode == WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; - } else { - struct sway_server_decoration *deco = - decoration_from_surface(toplevel->base->surface); - csd = !deco || deco->wlr_server_decoration->mode == - WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT; - } - - view_map(view, toplevel->base->surface, - toplevel->requested.fullscreen, - toplevel->requested.fullscreen_output, - csd); - - transaction_commit_dirty(); - - xdg_shell_view->commit.notify = handle_commit; - wl_signal_add(&toplevel->base->surface->events.commit, - &xdg_shell_view->commit); - - xdg_shell_view->new_popup.notify = handle_new_popup; - wl_signal_add(&toplevel->base->events.new_popup, - &xdg_shell_view->new_popup); - - xdg_shell_view->request_maximize.notify = handle_request_maximize; - wl_signal_add(&toplevel->events.request_maximize, - &xdg_shell_view->request_maximize); - - if (config->scratchpad_minimize) { - xdg_shell_view->request_minimize.notify = handle_request_minimize; - wl_signal_add(&toplevel->events.request_minimize, - &xdg_shell_view->request_minimize); - } - - xdg_shell_view->request_fullscreen.notify = handle_request_fullscreen; - wl_signal_add(&toplevel->events.request_fullscreen, - &xdg_shell_view->request_fullscreen); - - xdg_shell_view->request_move.notify = handle_request_move; - wl_signal_add(&toplevel->events.request_move, - &xdg_shell_view->request_move); - - xdg_shell_view->request_resize.notify = handle_request_resize; - wl_signal_add(&toplevel->events.request_resize, - &xdg_shell_view->request_resize); - - xdg_shell_view->set_title.notify = handle_set_title; - wl_signal_add(&toplevel->events.set_title, - &xdg_shell_view->set_title); - - xdg_shell_view->set_app_id.notify = handle_set_app_id; - wl_signal_add(&toplevel->events.set_app_id, - &xdg_shell_view->set_app_id); -} - -static void handle_destroy(struct wl_listener *listener, void *data) { - struct sway_xdg_shell_view *xdg_shell_view = - wl_container_of(listener, xdg_shell_view, destroy); - struct sway_view *view = &xdg_shell_view->view; - if (!sway_assert(view->surface == NULL, "Tried to destroy a mapped view")) { - return; - } - wl_list_remove(&xdg_shell_view->destroy.link); - wl_list_remove(&xdg_shell_view->map.link); - wl_list_remove(&xdg_shell_view->unmap.link); - view->wlr_xdg_toplevel = NULL; - if (view->xdg_decoration) { - view->xdg_decoration->view = NULL; - } - view_begin_destroy(view); -} - -struct sway_view *view_from_wlr_xdg_surface( - struct wlr_xdg_surface *xdg_surface) { - return xdg_surface->data; -} - -void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { - struct wlr_xdg_surface *xdg_surface = data; - - if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { - sway_log(SWAY_DEBUG, "New xdg_shell popup"); - return; - } - - sway_log(SWAY_DEBUG, "New xdg_shell toplevel title='%s' app_id='%s'", - xdg_surface->toplevel->title, xdg_surface->toplevel->app_id); - wlr_xdg_surface_ping(xdg_surface); - - struct sway_xdg_shell_view *xdg_shell_view = - calloc(1, sizeof(struct sway_xdg_shell_view)); - if (!sway_assert(xdg_shell_view, "Failed to allocate view")) { - return; - } - - view_init(&xdg_shell_view->view, SWAY_VIEW_XDG_SHELL, &view_impl); - xdg_shell_view->view.wlr_xdg_toplevel = xdg_surface->toplevel; - - xdg_shell_view->map.notify = handle_map; - wl_signal_add(&xdg_surface->surface->events.map, &xdg_shell_view->map); - - xdg_shell_view->unmap.notify = handle_unmap; - wl_signal_add(&xdg_surface->surface->events.unmap, &xdg_shell_view->unmap); - - xdg_shell_view->destroy.notify = handle_destroy; - wl_signal_add(&xdg_surface->events.destroy, &xdg_shell_view->destroy); - - xdg_surface->data = xdg_shell_view; -} diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c deleted file mode 100644 index 709795e8e..000000000 --- a/sway/desktop/xwayland.c +++ /dev/null @@ -1,937 +0,0 @@ -#define _POSIX_C_SOURCE 199309L -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "log.h" -#include "sway/desktop.h" -#include "sway/desktop/transaction.h" -#include "sway/input/cursor.h" -#include "sway/input/input-manager.h" -#include "sway/input/seat.h" -#include "sway/output.h" -#include "sway/tree/arrange.h" -#include "sway/tree/container.h" -#include "sway/server.h" -#include "sway/tree/view.h" -#include "sway/tree/workspace.h" - -static const char *atom_map[ATOM_LAST] = { - [NET_WM_WINDOW_TYPE_NORMAL] = "_NET_WM_WINDOW_TYPE_NORMAL", - [NET_WM_WINDOW_TYPE_DIALOG] = "_NET_WM_WINDOW_TYPE_DIALOG", - [NET_WM_WINDOW_TYPE_UTILITY] = "_NET_WM_WINDOW_TYPE_UTILITY", - [NET_WM_WINDOW_TYPE_TOOLBAR] = "_NET_WM_WINDOW_TYPE_TOOLBAR", - [NET_WM_WINDOW_TYPE_SPLASH] = "_NET_WM_WINDOW_TYPE_SPLASH", - [NET_WM_WINDOW_TYPE_MENU] = "_NET_WM_WINDOW_TYPE_MENU", - [NET_WM_WINDOW_TYPE_DROPDOWN_MENU] = "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", - [NET_WM_WINDOW_TYPE_POPUP_MENU] = "_NET_WM_WINDOW_TYPE_POPUP_MENU", - [NET_WM_WINDOW_TYPE_TOOLTIP] = "_NET_WM_WINDOW_TYPE_TOOLTIP", - [NET_WM_WINDOW_TYPE_NOTIFICATION] = "_NET_WM_WINDOW_TYPE_NOTIFICATION", - [NET_WM_STATE_MODAL] = "_NET_WM_STATE_MODAL", -}; - -static void unmanaged_handle_request_configure(struct wl_listener *listener, - void *data) { - struct sway_xwayland_unmanaged *surface = - wl_container_of(listener, surface, request_configure); - struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; - struct wlr_xwayland_surface_configure_event *ev = data; - wlr_xwayland_surface_configure(xsurface, ev->x, ev->y, - ev->width, ev->height); -} - -static void unmanaged_handle_commit(struct wl_listener *listener, void *data) { - struct sway_xwayland_unmanaged *surface = - wl_container_of(listener, surface, commit); - struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; - - desktop_damage_surface(xsurface->surface, surface->lx, surface->ly, - false); -} - -static void unmanaged_handle_set_geometry(struct wl_listener *listener, void *data) { - struct sway_xwayland_unmanaged *surface = - wl_container_of(listener, surface, set_geometry); - struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; - - if (xsurface->x != surface->lx || xsurface->y != surface->ly) { - // Surface has moved - desktop_damage_surface(xsurface->surface, surface->lx, surface->ly, - true); - surface->lx = xsurface->x; - surface->ly = xsurface->y; - desktop_damage_surface(xsurface->surface, surface->lx, surface->ly, - true); - } -} - -static void unmanaged_handle_map(struct wl_listener *listener, void *data) { - struct sway_xwayland_unmanaged *surface = - wl_container_of(listener, surface, map); - struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; - - wl_list_insert(root->xwayland_unmanaged.prev, &surface->link); - - wl_signal_add(&xsurface->events.set_geometry, &surface->set_geometry); - surface->set_geometry.notify = unmanaged_handle_set_geometry; - - wl_signal_add(&xsurface->surface->events.commit, &surface->commit); - surface->commit.notify = unmanaged_handle_commit; - - surface->lx = xsurface->x; - surface->ly = xsurface->y; - desktop_damage_surface(xsurface->surface, surface->lx, surface->ly, true); - - if (wlr_xwayland_or_surface_wants_focus(xsurface)) { - struct sway_seat *seat = input_manager_current_seat(); - struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland; - wlr_xwayland_set_seat(xwayland, seat->wlr_seat); - seat_set_focus_surface(seat, xsurface->surface, false); - } -} - -static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) { - struct sway_xwayland_unmanaged *surface = - wl_container_of(listener, surface, unmap); - struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; - desktop_damage_surface(xsurface->surface, xsurface->x, xsurface->y, true); - wl_list_remove(&surface->link); - wl_list_remove(&surface->set_geometry.link); - wl_list_remove(&surface->commit.link); - - struct sway_seat *seat = input_manager_current_seat(); - if (seat->wlr_seat->keyboard_state.focused_surface == xsurface->surface) { - // This simply returns focus to the parent surface if there's one available. - // This seems to handle JetBrains issues. - if (xsurface->parent && xsurface->parent->surface - && wlr_xwayland_or_surface_wants_focus(xsurface->parent)) { - seat_set_focus_surface(seat, xsurface->parent->surface, false); - return; - } - - // Restore focus - struct sway_node *previous = seat_get_focus_inactive(seat, &root->node); - if (previous) { - // Hack to get seat to re-focus the return value of get_focus - seat_set_focus(seat, NULL); - seat_set_focus(seat, previous); - } - } -} - -static void unmanaged_handle_request_activate(struct wl_listener *listener, void *data) { - struct sway_xwayland_unmanaged *surface = - wl_container_of(listener, surface, request_activate); - struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; - if (xsurface->surface == NULL || !xsurface->surface->mapped) { - return; - } - struct sway_seat *seat = input_manager_current_seat(); - struct sway_container *focus = seat_get_focused_container(seat); - if (focus && focus->view && focus->view->pid != xsurface->pid) { - return; - } - - seat_set_focus_surface(seat, xsurface->surface, false); -} - -static void unmanaged_handle_associate(struct wl_listener *listener, void *data) { - struct sway_xwayland_unmanaged *surface = - wl_container_of(listener, surface, associate); - struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; - wl_signal_add(&xsurface->surface->events.map, &surface->map); - surface->map.notify = unmanaged_handle_map; - wl_signal_add(&xsurface->surface->events.unmap, &surface->unmap); - surface->unmap.notify = unmanaged_handle_unmap; -} - -static void unmanaged_handle_dissociate(struct wl_listener *listener, void *data) { - struct sway_xwayland_unmanaged *surface = - wl_container_of(listener, surface, dissociate); - wl_list_remove(&surface->map.link); - wl_list_remove(&surface->unmap.link); -} - -static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) { - struct sway_xwayland_unmanaged *surface = - wl_container_of(listener, surface, destroy); - wl_list_remove(&surface->request_configure.link); - wl_list_remove(&surface->associate.link); - wl_list_remove(&surface->dissociate.link); - wl_list_remove(&surface->destroy.link); - wl_list_remove(&surface->override_redirect.link); - wl_list_remove(&surface->request_activate.link); - free(surface); -} - -static void handle_map(struct wl_listener *listener, void *data); -static void handle_associate(struct wl_listener *listener, void *data); - -struct sway_xwayland_view *create_xwayland_view(struct wlr_xwayland_surface *xsurface); - -static void unmanaged_handle_override_redirect(struct wl_listener *listener, void *data) { - struct sway_xwayland_unmanaged *surface = - wl_container_of(listener, surface, override_redirect); - struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; - - bool associated = xsurface->surface != NULL; - bool mapped = associated && xsurface->surface->mapped; - if (mapped) { - unmanaged_handle_unmap(&surface->unmap, NULL); - } - if (associated) { - unmanaged_handle_dissociate(&surface->dissociate, NULL); - } - - unmanaged_handle_destroy(&surface->destroy, NULL); - xsurface->data = NULL; - - struct sway_xwayland_view *xwayland_view = create_xwayland_view(xsurface); - if (associated) { - handle_associate(&xwayland_view->associate, NULL); - } - if (mapped) { - handle_map(&xwayland_view->map, xsurface); - } -} - -static struct sway_xwayland_unmanaged *create_unmanaged( - struct wlr_xwayland_surface *xsurface) { - struct sway_xwayland_unmanaged *surface = - calloc(1, sizeof(struct sway_xwayland_unmanaged)); - if (surface == NULL) { - sway_log(SWAY_ERROR, "Allocation failed"); - return NULL; - } - - surface->wlr_xwayland_surface = xsurface; - - wl_signal_add(&xsurface->events.request_configure, - &surface->request_configure); - surface->request_configure.notify = unmanaged_handle_request_configure; - wl_signal_add(&xsurface->events.associate, &surface->associate); - surface->associate.notify = unmanaged_handle_associate; - wl_signal_add(&xsurface->events.dissociate, &surface->dissociate); - surface->dissociate.notify = unmanaged_handle_dissociate; - wl_signal_add(&xsurface->events.destroy, &surface->destroy); - surface->destroy.notify = unmanaged_handle_destroy; - wl_signal_add(&xsurface->events.set_override_redirect, &surface->override_redirect); - surface->override_redirect.notify = unmanaged_handle_override_redirect; - wl_signal_add(&xsurface->events.request_activate, &surface->request_activate); - surface->request_activate.notify = unmanaged_handle_request_activate; - - return surface; -} - -static struct sway_xwayland_view *xwayland_view_from_view( - struct sway_view *view) { - if (!sway_assert(view->type == SWAY_VIEW_XWAYLAND, - "Expected xwayland view")) { - return NULL; - } - return (struct sway_xwayland_view *)view; -} - -static const char *get_string_prop(struct sway_view *view, enum sway_view_prop prop) { - if (xwayland_view_from_view(view) == NULL) { - return NULL; - } - switch (prop) { - case VIEW_PROP_TITLE: - return view->wlr_xwayland_surface->title; - case VIEW_PROP_CLASS: - return view->wlr_xwayland_surface->class; - case VIEW_PROP_INSTANCE: - return view->wlr_xwayland_surface->instance; - case VIEW_PROP_WINDOW_ROLE: - return view->wlr_xwayland_surface->role; - default: - return NULL; - } -} - -static uint32_t get_int_prop(struct sway_view *view, enum sway_view_prop prop) { - if (xwayland_view_from_view(view) == NULL) { - return 0; - } - switch (prop) { - case VIEW_PROP_X11_WINDOW_ID: - return view->wlr_xwayland_surface->window_id; - case VIEW_PROP_X11_PARENT_ID: - if (view->wlr_xwayland_surface->parent) { - return view->wlr_xwayland_surface->parent->window_id; - } - return 0; - case VIEW_PROP_WINDOW_TYPE: - if (view->wlr_xwayland_surface->window_type_len == 0) { - return 0; - } - return view->wlr_xwayland_surface->window_type[0]; - default: - return 0; - } -} - -static uint32_t configure(struct sway_view *view, double lx, double ly, int width, - int height) { - struct sway_xwayland_view *xwayland_view = xwayland_view_from_view(view); - if (xwayland_view == NULL) { - return 0; - } - struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - - wlr_xwayland_surface_configure(xsurface, lx, ly, width, height); - - // xwayland doesn't give us a serial for the configure - return 0; -} - -static void set_activated(struct sway_view *view, bool activated) { - if (xwayland_view_from_view(view) == NULL) { - return; - } - struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface; - - if (activated && surface->minimized) { - wlr_xwayland_surface_set_minimized(surface, false); - } - - wlr_xwayland_surface_activate(surface, activated); - wlr_xwayland_surface_restack(surface, NULL, XCB_STACK_MODE_ABOVE); -} - -static void set_tiled(struct sway_view *view, bool tiled) { - if (xwayland_view_from_view(view) == NULL) { - return; - } - struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface; - wlr_xwayland_surface_set_maximized(surface, tiled); -} - -static void set_fullscreen(struct sway_view *view, bool fullscreen) { - if (xwayland_view_from_view(view) == NULL) { - return; - } - struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface; - wlr_xwayland_surface_set_fullscreen(surface, fullscreen); -} - -static bool wants_floating(struct sway_view *view) { - if (xwayland_view_from_view(view) == NULL) { - return false; - } - struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface; - struct sway_xwayland *xwayland = &server.xwayland; - - if (surface->modal) { - return true; - } - - for (size_t i = 0; i < surface->window_type_len; ++i) { - xcb_atom_t type = surface->window_type[i]; - if (type == xwayland->atoms[NET_WM_WINDOW_TYPE_DIALOG] || - type == xwayland->atoms[NET_WM_WINDOW_TYPE_UTILITY] || - type == xwayland->atoms[NET_WM_WINDOW_TYPE_TOOLBAR] || - type == xwayland->atoms[NET_WM_WINDOW_TYPE_SPLASH]) { - return true; - } - } - - xcb_size_hints_t *size_hints = surface->size_hints; - if (size_hints != NULL && - size_hints->min_width > 0 && size_hints->min_height > 0 && - (size_hints->max_width == size_hints->min_width || - size_hints->max_height == size_hints->min_height)) { - return true; - } - - return false; -} - -static void handle_set_decorations(struct wl_listener *listener, void *data) { - struct sway_xwayland_view *xwayland_view = - wl_container_of(listener, xwayland_view, set_decorations); - struct sway_view *view = &xwayland_view->view; - struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - - bool csd = xsurface->decorations != WLR_XWAYLAND_SURFACE_DECORATIONS_ALL; - view_update_csd_from_client(view, csd); -} - -static bool is_transient_for(struct sway_view *child, - struct sway_view *ancestor) { - if (xwayland_view_from_view(child) == NULL) { - return false; - } - struct wlr_xwayland_surface *surface = child->wlr_xwayland_surface; - while (surface) { - if (surface->parent == ancestor->wlr_xwayland_surface) { - return true; - } - surface = surface->parent; - } - return false; -} - -static void _close(struct sway_view *view) { - if (xwayland_view_from_view(view) == NULL) { - return; - } - wlr_xwayland_surface_close(view->wlr_xwayland_surface); -} - -static void destroy(struct sway_view *view) { - struct sway_xwayland_view *xwayland_view = xwayland_view_from_view(view); - if (xwayland_view == NULL) { - return; - } - free(xwayland_view); -} - -static void get_constraints(struct sway_view *view, double *min_width, - double *max_width, double *min_height, double *max_height) { - struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface; - xcb_size_hints_t *size_hints = surface->size_hints; - - if (size_hints == NULL) { - *min_width = DBL_MIN; - *max_width = DBL_MAX; - *min_height = DBL_MIN; - *max_height = DBL_MAX; - return; - } - - *min_width = size_hints->min_width > 0 ? size_hints->min_width : DBL_MIN; - *max_width = size_hints->max_width > 0 ? size_hints->max_width : DBL_MAX; - *min_height = size_hints->min_height > 0 ? size_hints->min_height : DBL_MIN; - *max_height = size_hints->max_height > 0 ? size_hints->max_height : DBL_MAX; -} - -static const struct sway_view_impl view_impl = { - .get_constraints = get_constraints, - .get_string_prop = get_string_prop, - .get_int_prop = get_int_prop, - .configure = configure, - .set_activated = set_activated, - .set_tiled = set_tiled, - .set_fullscreen = set_fullscreen, - .wants_floating = wants_floating, - .is_transient_for = is_transient_for, - .close = _close, - .destroy = destroy, -}; - -static void get_geometry(struct sway_view *view, struct wlr_box *box) { - box->x = box->y = 0; - if (view->surface) { - box->width = view->surface->current.width; - box->height = view->surface->current.height; - } else { - box->width = 0; - box->height = 0; - } -} - -static void handle_commit(struct wl_listener *listener, void *data) { - struct sway_xwayland_view *xwayland_view = - wl_container_of(listener, xwayland_view, commit); - struct sway_view *view = &xwayland_view->view; - struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - struct wlr_surface_state *state = &xsurface->surface->current; - - struct wlr_box new_geo; - get_geometry(view, &new_geo); - bool new_size = new_geo.width != view->geometry.width || - new_geo.height != view->geometry.height || - new_geo.x != view->geometry.x || - new_geo.y != view->geometry.y; - - if (new_size) { - // The client changed its surface size in this commit. For floating - // containers, we resize the container to match. For tiling containers, - // we only recenter the surface. - desktop_damage_view(view); - memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); - if (container_is_floating(view->container)) { - view_update_size(view); - transaction_commit_dirty_client(); - } else { - view_center_surface(view); - } - desktop_damage_view(view); - } - - if (view->container->node.instruction) { - transaction_notify_view_ready_by_geometry(view, - xsurface->x, xsurface->y, state->width, state->height); - } - - view_damage_from(view); -} - -static void handle_destroy(struct wl_listener *listener, void *data) { - struct sway_xwayland_view *xwayland_view = - wl_container_of(listener, xwayland_view, destroy); - struct sway_view *view = &xwayland_view->view; - - if (view->surface) { - view_unmap(view); - wl_list_remove(&xwayland_view->commit.link); - } - - xwayland_view->view.wlr_xwayland_surface = NULL; - - wl_list_remove(&xwayland_view->destroy.link); - wl_list_remove(&xwayland_view->request_configure.link); - wl_list_remove(&xwayland_view->request_fullscreen.link); - wl_list_remove(&xwayland_view->request_minimize.link); - wl_list_remove(&xwayland_view->request_move.link); - wl_list_remove(&xwayland_view->request_resize.link); - wl_list_remove(&xwayland_view->request_activate.link); - wl_list_remove(&xwayland_view->set_title.link); - wl_list_remove(&xwayland_view->set_class.link); - wl_list_remove(&xwayland_view->set_role.link); - wl_list_remove(&xwayland_view->set_startup_id.link); - wl_list_remove(&xwayland_view->set_window_type.link); - wl_list_remove(&xwayland_view->set_hints.link); - wl_list_remove(&xwayland_view->set_decorations.link); - wl_list_remove(&xwayland_view->associate.link); - wl_list_remove(&xwayland_view->dissociate.link); - wl_list_remove(&xwayland_view->override_redirect.link); - view_begin_destroy(&xwayland_view->view); -} - -static void handle_unmap(struct wl_listener *listener, void *data) { - struct sway_xwayland_view *xwayland_view = - wl_container_of(listener, xwayland_view, unmap); - struct sway_view *view = &xwayland_view->view; - - if (!sway_assert(view->surface, "Cannot unmap unmapped view")) { - return; - } - - view_unmap(view); - - wl_list_remove(&xwayland_view->commit.link); -} - -static void handle_map(struct wl_listener *listener, void *data) { - struct sway_xwayland_view *xwayland_view = - wl_container_of(listener, xwayland_view, map); - struct sway_view *view = &xwayland_view->view; - struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - - view->natural_width = xsurface->width; - view->natural_height = xsurface->height; - - // Wire up the commit listener here, because xwayland map/unmap can change - // the underlying wlr_surface - wl_signal_add(&xsurface->surface->events.commit, &xwayland_view->commit); - xwayland_view->commit.notify = handle_commit; - - // Put it back into the tree - view_map(view, xsurface->surface, xsurface->fullscreen, NULL, false); - - transaction_commit_dirty(); -} - -static void handle_dissociate(struct wl_listener *listener, void *data); - -static void handle_override_redirect(struct wl_listener *listener, void *data) { - struct sway_xwayland_view *xwayland_view = - wl_container_of(listener, xwayland_view, override_redirect); - struct sway_view *view = &xwayland_view->view; - struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - - bool associated = xsurface->surface != NULL; - bool mapped = associated && xsurface->surface->mapped; - if (mapped) { - handle_unmap(&xwayland_view->unmap, NULL); - } - if (associated) { - handle_dissociate(&xwayland_view->dissociate, NULL); - } - - handle_destroy(&xwayland_view->destroy, view); - xsurface->data = NULL; - - struct sway_xwayland_unmanaged *unmanaged = create_unmanaged(xsurface); - if (associated) { - unmanaged_handle_associate(&unmanaged->associate, NULL); - } - if (mapped) { - unmanaged_handle_map(&unmanaged->map, xsurface); - } -} - -static void handle_request_configure(struct wl_listener *listener, void *data) { - struct sway_xwayland_view *xwayland_view = - wl_container_of(listener, xwayland_view, request_configure); - struct wlr_xwayland_surface_configure_event *ev = data; - struct sway_view *view = &xwayland_view->view; - struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (xsurface->surface == NULL || !xsurface->surface->mapped) { - wlr_xwayland_surface_configure(xsurface, ev->x, ev->y, - ev->width, ev->height); - return; - } - if (container_is_floating(view->container)) { - // Respect minimum and maximum sizes - view->natural_width = ev->width; - view->natural_height = ev->height; - container_floating_resize_and_center(view->container); - - configure(view, view->container->pending.content_x, - view->container->pending.content_y, - view->container->pending.content_width, - view->container->pending.content_height); - node_set_dirty(&view->container->node); - } else { - configure(view, view->container->current.content_x, - view->container->current.content_y, - view->container->current.content_width, - view->container->current.content_height); - } -} - -static void handle_request_fullscreen(struct wl_listener *listener, void *data) { - struct sway_xwayland_view *xwayland_view = - wl_container_of(listener, xwayland_view, request_fullscreen); - struct sway_view *view = &xwayland_view->view; - struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (xsurface->surface == NULL || !xsurface->surface->mapped) { - return; - } - container_set_fullscreen(view->container, xsurface->fullscreen); - - arrange_root(); - transaction_commit_dirty(); -} - -/* Minimize to scratchpad */ -static void handle_request_minimize(struct wl_listener *listener, void *data) { - struct sway_xwayland_view *xwayland_view = - wl_container_of(listener, xwayland_view, request_minimize); - struct sway_view *view = &xwayland_view->view; - struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (xsurface->surface == NULL || !xsurface->surface->mapped) { - return; - } - - struct wlr_xwayland_minimize_event *e = data; - if (config->scratchpad_minimize) { - struct sway_container *container = view->container; - if (!container->pending.workspace) { - while (container->pending.parent) { - container = container->pending.parent; - } - } - if(e->minimize) { - if (!container->scratchpad) { - root_scratchpad_add_container(container, NULL); - } else if (container->pending.workspace) { - root_scratchpad_hide(container); - } - } else { - if(container->scratchpad) { - root_scratchpad_show(container); - } - } - transaction_commit_dirty(); - return; - } - struct sway_seat *seat = input_manager_current_seat(); - bool focused = seat_get_focus(seat) == &view->container->node; - wlr_xwayland_surface_set_minimized(xsurface, !focused && e->minimize); -} - -static void handle_request_move(struct wl_listener *listener, void *data) { - struct sway_xwayland_view *xwayland_view = - wl_container_of(listener, xwayland_view, request_move); - struct sway_view *view = &xwayland_view->view; - struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (xsurface->surface == NULL || !xsurface->surface->mapped) { - return; - } - if (!container_is_floating(view->container) || - view->container->pending.fullscreen_mode) { - return; - } - struct sway_seat *seat = input_manager_current_seat(); - seatop_begin_move_floating(seat, view->container); -} - -static void handle_request_resize(struct wl_listener *listener, void *data) { - struct sway_xwayland_view *xwayland_view = - wl_container_of(listener, xwayland_view, request_resize); - struct sway_view *view = &xwayland_view->view; - struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (xsurface->surface == NULL || !xsurface->surface->mapped) { - return; - } - if (!container_is_floating(view->container)) { - return; - } - struct wlr_xwayland_resize_event *e = data; - struct sway_seat *seat = input_manager_current_seat(); - seatop_begin_resize_floating(seat, view->container, e->edges); -} - -static void handle_request_activate(struct wl_listener *listener, void *data) { - struct sway_xwayland_view *xwayland_view = - wl_container_of(listener, xwayland_view, request_activate); - struct sway_view *view = &xwayland_view->view; - struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (xsurface->surface == NULL || !xsurface->surface->mapped) { - return; - } - view_request_activate(view, NULL); - - transaction_commit_dirty(); -} - -static void handle_set_title(struct wl_listener *listener, void *data) { - struct sway_xwayland_view *xwayland_view = - wl_container_of(listener, xwayland_view, set_title); - struct sway_view *view = &xwayland_view->view; - struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (xsurface->surface == NULL || !xsurface->surface->mapped) { - return; - } - view_update_title(view, false); - view_execute_criteria(view); -} - -static void handle_set_class(struct wl_listener *listener, void *data) { - struct sway_xwayland_view *xwayland_view = - wl_container_of(listener, xwayland_view, set_class); - struct sway_view *view = &xwayland_view->view; - struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (xsurface->surface == NULL || !xsurface->surface->mapped) { - return; - } - view_execute_criteria(view); -} - -static void handle_set_role(struct wl_listener *listener, void *data) { - struct sway_xwayland_view *xwayland_view = - wl_container_of(listener, xwayland_view, set_role); - struct sway_view *view = &xwayland_view->view; - struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (xsurface->surface == NULL || !xsurface->surface->mapped) { - return; - } - view_execute_criteria(view); -} - -static void handle_set_startup_id(struct wl_listener *listener, void *data) { - struct sway_xwayland_view *xwayland_view = - wl_container_of(listener, xwayland_view, set_startup_id); - struct sway_view *view = &xwayland_view->view; - struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (xsurface->startup_id == NULL) { - return; - } - - struct wlr_xdg_activation_token_v1 *token = - wlr_xdg_activation_v1_find_token( - server.xdg_activation_v1, xsurface->startup_id); - if (token == NULL) { - // Tried to activate with an unknown or expired token - return; - } - - struct launcher_ctx *ctx = token->data; - if (token->data == NULL) { - // TODO: support external launchers in X - return; - } - view_assign_ctx(view, ctx); -} - -static void handle_set_window_type(struct wl_listener *listener, void *data) { - struct sway_xwayland_view *xwayland_view = - wl_container_of(listener, xwayland_view, set_window_type); - struct sway_view *view = &xwayland_view->view; - struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (xsurface->surface == NULL || !xsurface->surface->mapped) { - return; - } - view_execute_criteria(view); -} - -static void handle_set_hints(struct wl_listener *listener, void *data) { - struct sway_xwayland_view *xwayland_view = - wl_container_of(listener, xwayland_view, set_hints); - struct sway_view *view = &xwayland_view->view; - struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (xsurface->surface == NULL || !xsurface->surface->mapped) { - return; - } - const bool hints_urgency = xcb_icccm_wm_hints_get_urgency(xsurface->hints); - if (!hints_urgency && view->urgent_timer) { - // The view is in the timeout period. We'll ignore the request to - // unset urgency so that the view remains urgent until the timer clears - // it. - return; - } - if (view->allow_request_urgent) { - view_set_urgent(view, hints_urgency); - } -} - -static void handle_associate(struct wl_listener *listener, void *data) { - struct sway_xwayland_view *xwayland_view = - wl_container_of(listener, xwayland_view, associate); - struct wlr_xwayland_surface *xsurface = - xwayland_view->view.wlr_xwayland_surface; - wl_signal_add(&xsurface->surface->events.unmap, &xwayland_view->unmap); - xwayland_view->unmap.notify = handle_unmap; - wl_signal_add(&xsurface->surface->events.map, &xwayland_view->map); - xwayland_view->map.notify = handle_map; -} - -static void handle_dissociate(struct wl_listener *listener, void *data) { - struct sway_xwayland_view *xwayland_view = - wl_container_of(listener, xwayland_view, dissociate); - wl_list_remove(&xwayland_view->map.link); - wl_list_remove(&xwayland_view->unmap.link); -} - -struct sway_view *view_from_wlr_xwayland_surface( - struct wlr_xwayland_surface *xsurface) { - return xsurface->data; -} - -struct sway_xwayland_view *create_xwayland_view(struct wlr_xwayland_surface *xsurface) { - sway_log(SWAY_DEBUG, "New xwayland surface title='%s' class='%s'", - xsurface->title, xsurface->class); - - struct sway_xwayland_view *xwayland_view = - calloc(1, sizeof(struct sway_xwayland_view)); - if (!sway_assert(xwayland_view, "Failed to allocate view")) { - return NULL; - } - - view_init(&xwayland_view->view, SWAY_VIEW_XWAYLAND, &view_impl); - xwayland_view->view.wlr_xwayland_surface = xsurface; - - wl_signal_add(&xsurface->events.destroy, &xwayland_view->destroy); - xwayland_view->destroy.notify = handle_destroy; - - wl_signal_add(&xsurface->events.request_configure, - &xwayland_view->request_configure); - xwayland_view->request_configure.notify = handle_request_configure; - - wl_signal_add(&xsurface->events.request_fullscreen, - &xwayland_view->request_fullscreen); - xwayland_view->request_fullscreen.notify = handle_request_fullscreen; - - wl_signal_add(&xsurface->events.request_minimize, - &xwayland_view->request_minimize); - xwayland_view->request_minimize.notify = handle_request_minimize; - - wl_signal_add(&xsurface->events.request_activate, - &xwayland_view->request_activate); - xwayland_view->request_activate.notify = handle_request_activate; - - wl_signal_add(&xsurface->events.request_move, - &xwayland_view->request_move); - xwayland_view->request_move.notify = handle_request_move; - - wl_signal_add(&xsurface->events.request_resize, - &xwayland_view->request_resize); - xwayland_view->request_resize.notify = handle_request_resize; - - wl_signal_add(&xsurface->events.set_title, &xwayland_view->set_title); - xwayland_view->set_title.notify = handle_set_title; - - wl_signal_add(&xsurface->events.set_class, &xwayland_view->set_class); - xwayland_view->set_class.notify = handle_set_class; - - wl_signal_add(&xsurface->events.set_role, &xwayland_view->set_role); - xwayland_view->set_role.notify = handle_set_role; - - wl_signal_add(&xsurface->events.set_startup_id, - &xwayland_view->set_startup_id); - xwayland_view->set_startup_id.notify = handle_set_startup_id; - - wl_signal_add(&xsurface->events.set_window_type, - &xwayland_view->set_window_type); - xwayland_view->set_window_type.notify = handle_set_window_type; - - wl_signal_add(&xsurface->events.set_hints, &xwayland_view->set_hints); - xwayland_view->set_hints.notify = handle_set_hints; - - wl_signal_add(&xsurface->events.set_decorations, - &xwayland_view->set_decorations); - xwayland_view->set_decorations.notify = handle_set_decorations; - - wl_signal_add(&xsurface->events.associate, &xwayland_view->associate); - xwayland_view->associate.notify = handle_associate; - - wl_signal_add(&xsurface->events.dissociate, &xwayland_view->dissociate); - xwayland_view->dissociate.notify = handle_dissociate; - - wl_signal_add(&xsurface->events.set_override_redirect, - &xwayland_view->override_redirect); - xwayland_view->override_redirect.notify = handle_override_redirect; - - xsurface->data = xwayland_view; - - return xwayland_view; -} - -void handle_xwayland_surface(struct wl_listener *listener, void *data) { - struct wlr_xwayland_surface *xsurface = data; - - if (xsurface->override_redirect) { - sway_log(SWAY_DEBUG, "New xwayland unmanaged surface"); - create_unmanaged(xsurface); - return; - } - - create_xwayland_view(xsurface); -} - -void handle_xwayland_ready(struct wl_listener *listener, void *data) { - struct sway_server *server = - wl_container_of(listener, server, xwayland_ready); - struct sway_xwayland *xwayland = &server->xwayland; - - xcb_connection_t *xcb_conn = xcb_connect(NULL, NULL); - int err = xcb_connection_has_error(xcb_conn); - if (err) { - sway_log(SWAY_ERROR, "XCB connect failed: %d", err); - return; - } - - xcb_intern_atom_cookie_t cookies[ATOM_LAST]; - for (size_t i = 0; i < ATOM_LAST; i++) { - cookies[i] = - xcb_intern_atom(xcb_conn, 0, strlen(atom_map[i]), atom_map[i]); - } - for (size_t i = 0; i < ATOM_LAST; i++) { - xcb_generic_error_t *error = NULL; - xcb_intern_atom_reply_t *reply = - xcb_intern_atom_reply(xcb_conn, cookies[i], &error); - if (reply != NULL && error == NULL) { - xwayland->atoms[i] = reply->atom; - } - free(reply); - - if (error != NULL) { - sway_log(SWAY_ERROR, "could not resolve atom %s, X11 error code %d", - atom_map[i], error->error_code); - free(error); - break; - } - } - - xcb_disconnect(xcb_conn); -} diff --git a/sway/input/cursor.c b/sway/input/cursor.c deleted file mode 100644 index fa9d5b331..000000000 --- a/sway/input/cursor.c +++ /dev/null @@ -1,1522 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "config.h" -#include "log.h" -#include "util.h" -#include "sway/commands.h" -#include "sway/desktop.h" -#include "sway/input/cursor.h" -#include "sway/input/keyboard.h" -#include "sway/input/tablet.h" -#include "sway/layers.h" -#include "sway/output.h" -#include "sway/tree/container.h" -#include "sway/tree/root.h" -#include "sway/tree/view.h" -#include "sway/tree/workspace.h" -#include "wlr-layer-shell-unstable-v1-protocol.h" - -static uint32_t get_current_time_msec(void) { - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - return now.tv_sec * 1000 + now.tv_nsec / 1000000; -} - -static struct wlr_surface *input_popup_surface_at(struct sway_output *output, - struct sway_input_method_relay *relay, double ox, double oy, double *sx, double *sy) { - struct sway_input_popup *popup; - wl_list_for_each(popup, &relay->input_popups, link) { - int lx, ly; - if (!sway_input_popup_get_position(popup, &lx, &ly)) { - continue; - } - if (!popup->visible) { - continue; - } - double _sx = ox - lx; - double _sy = oy - ly; - struct wlr_surface *sub = wlr_surface_surface_at( - popup->popup_surface->surface, _sx, _sy, sx, sy); - if (sub) { - return sub; - } - } - return NULL; -} - -static struct wlr_surface *layer_surface_at(struct sway_output *output, - struct wl_list *layer, double ox, double oy, double *sx, double *sy) { - struct sway_layer_surface *sway_layer; - wl_list_for_each_reverse(sway_layer, layer, link) { - double _sx = ox - sway_layer->geo.x; - double _sy = oy - sway_layer->geo.y; - struct wlr_surface *sub = wlr_layer_surface_v1_surface_at( - sway_layer->layer_surface, _sx, _sy, sx, sy); - if (sub) { - return sub; - } - } - return NULL; -} - -static bool surface_is_xdg_popup(struct wlr_surface *surface) { - struct wlr_xdg_surface *xdg_surface = - wlr_xdg_surface_try_from_wlr_surface(surface); - return xdg_surface != NULL && xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP && - xdg_surface->popup != NULL; -} - -static struct wlr_surface *layer_surface_popup_at(struct sway_output *output, - struct wl_list *layer, double ox, double oy, double *sx, double *sy) { - struct sway_layer_surface *sway_layer; - wl_list_for_each_reverse(sway_layer, layer, link) { - double _sx = ox - sway_layer->geo.x; - double _sy = oy - sway_layer->geo.y; - struct wlr_surface *sub = wlr_layer_surface_v1_surface_at( - sway_layer->layer_surface, _sx, _sy, sx, sy); - if (sub && surface_is_xdg_popup(sub)) { - return sub; - } - } - return NULL; -} - -/** - * Returns the node at the cursor's position. If there is a surface at that - * location, it is stored in **surface (it may not be a view). - */ -struct sway_node *node_at_coords( - struct sway_seat *seat, double lx, double ly, - struct wlr_surface **surface, double *sx, double *sy) { - // find the output the cursor is on - struct wlr_output *wlr_output = wlr_output_layout_output_at( - root->output_layout, lx, ly); - if (wlr_output == NULL) { - return NULL; - } - struct sway_output *output = wlr_output->data; - if (!output || !output->enabled) { - // output is being destroyed or is being enabled - return NULL; - } - double ox = lx, oy = ly; - wlr_output_layout_output_coords(root->output_layout, wlr_output, &ox, &oy); - - if (server.session_lock.locked) { - if (server.session_lock.lock == NULL) { - return NULL; - } - struct wlr_session_lock_surface_v1 *lock_surf; - wl_list_for_each(lock_surf, &server.session_lock.lock->surfaces, link) { - if (lock_surf->output != wlr_output) { - continue; - } - - *surface = wlr_surface_surface_at(lock_surf->surface, ox, oy, sx, sy); - if (*surface != NULL) { - return NULL; - } - } - return NULL; - } - - // layer surfaces on the overlay layer are rendered on top - if ((*surface = layer_surface_at(output, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], - ox, oy, sx, sy))) { - return NULL; - } - - if ((*surface = input_popup_surface_at(output, - &seat->im_relay, ox, oy, sx, sy))) { - struct sway_cursor* cursor = seat->cursor; - // set cursot to left_ptr - cursor_set_image(cursor, "left_ptr", NULL); - return NULL; - } - // check for unmanaged views -#if HAVE_XWAYLAND - struct wl_list *unmanaged = &root->xwayland_unmanaged; - struct sway_xwayland_unmanaged *unmanaged_surface; - wl_list_for_each_reverse(unmanaged_surface, unmanaged, link) { - struct wlr_xwayland_surface *xsurface = - unmanaged_surface->wlr_xwayland_surface; - - double _sx = lx - unmanaged_surface->lx; - double _sy = ly - unmanaged_surface->ly; - if (wlr_surface_point_accepts_input(xsurface->surface, _sx, _sy)) { - *surface = xsurface->surface; - *sx = _sx; - *sy = _sy; - return NULL; - } - } -#endif - - if (root->fullscreen_global) { - // Try fullscreen container - struct sway_container *con = tiling_container_at( - &root->fullscreen_global->node, lx, ly, surface, sx, sy); - if (con) { - return &con->node; - } - return NULL; - } - - // find the focused workspace on the output for this seat - struct sway_workspace *ws = output_get_active_workspace(output); - if (!ws) { - return NULL; - } - - if (ws->fullscreen) { - // Try transient containers - for (int i = 0; i < ws->floating->length; ++i) { - struct sway_container *floater = ws->floating->items[i]; - if (container_is_transient_for(floater, ws->fullscreen)) { - struct sway_container *con = tiling_container_at( - &floater->node, lx, ly, surface, sx, sy); - if (con) { - return &con->node; - } - } - } - // Try fullscreen container - struct sway_container *con = - tiling_container_at(&ws->fullscreen->node, lx, ly, surface, sx, sy); - if (con) { - return &con->node; - } - return NULL; - } - if ((*surface = layer_surface_popup_at(output, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], - ox, oy, sx, sy))) { - return NULL; - } - if ((*surface = layer_surface_popup_at(output, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], - ox, oy, sx, sy))) { - return NULL; - } - if ((*surface = layer_surface_popup_at(output, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], - ox, oy, sx, sy))) { - return NULL; - } - if ((*surface = layer_surface_at(output, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], - ox, oy, sx, sy))) { - return NULL; - } - - struct sway_container *c; - if ((c = container_at(ws, lx, ly, surface, sx, sy))) { - return &c->node; - } - - if ((*surface = layer_surface_at(output, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], - ox, oy, sx, sy))) { - return NULL; - } - if ((*surface = layer_surface_at(output, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], - ox, oy, sx, sy))) { - return NULL; - } - - return &ws->node; -} - -void cursor_rebase(struct sway_cursor *cursor) { - uint32_t time_msec = get_current_time_msec(); - seatop_rebase(cursor->seat, time_msec); -} - -void cursor_rebase_all(void) { - if (!root->outputs->length) { - return; - } - - struct sway_seat *seat; - wl_list_for_each(seat, &server.input->seats, link) { - cursor_rebase(seat->cursor); - } -} - -void cursor_update_image(struct sway_cursor *cursor, - struct sway_node *node) { - if (node && node->type == N_CONTAINER) { - // Try a node's resize edge - enum wlr_edges edge = find_resize_edge(node->sway_container, NULL, cursor); - if (edge == WLR_EDGE_NONE) { - cursor_set_image(cursor, "default", NULL); - } else if (container_is_floating(node->sway_container)) { - cursor_set_image(cursor, wlr_xcursor_get_resize_name(edge), NULL); - } else { - if (edge & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)) { - cursor_set_image(cursor, "col-resize", NULL); - } else { - cursor_set_image(cursor, "row-resize", NULL); - } - } - } else { - cursor_set_image(cursor, "default", NULL); - } -} - -static void cursor_hide(struct sway_cursor *cursor) { - wlr_cursor_unset_image(cursor->cursor); - cursor->hidden = true; - wlr_seat_pointer_notify_clear_focus(cursor->seat->wlr_seat); -} - -static int hide_notify(void *data) { - struct sway_cursor *cursor = data; - cursor_hide(cursor); - return 1; -} - -int cursor_get_timeout(struct sway_cursor *cursor) { - if (cursor->pressed_button_count > 0) { - // Do not hide cursor unless all buttons are released - return 0; - } - - struct seat_config *sc = seat_get_config(cursor->seat); - if (!sc) { - sc = seat_get_config_by_name("*"); - } - int timeout = sc ? sc->hide_cursor_timeout : 0; - if (timeout < 0) { - timeout = 0; - } - return timeout; -} - -void cursor_notify_key_press(struct sway_cursor *cursor) { - if (cursor->hidden) { - return; - } - - if (cursor->hide_when_typing == HIDE_WHEN_TYPING_DEFAULT) { - // No cached value, need to lookup in the seat_config - const struct seat_config *seat_config = seat_get_config(cursor->seat); - if (!seat_config) { - seat_config = seat_get_config_by_name("*"); - if (!seat_config) { - return; - } - } - cursor->hide_when_typing = seat_config->hide_cursor_when_typing; - // The default is currently disabled - if (cursor->hide_when_typing == HIDE_WHEN_TYPING_DEFAULT) { - cursor->hide_when_typing = HIDE_WHEN_TYPING_DISABLE; - } - } - - if (cursor->hide_when_typing == HIDE_WHEN_TYPING_ENABLE) { - cursor_hide(cursor); - } -} - -static enum sway_input_idle_source idle_source_from_device( - struct wlr_input_device *device) { - switch (device->type) { - case WLR_INPUT_DEVICE_KEYBOARD: - return IDLE_SOURCE_KEYBOARD; - case WLR_INPUT_DEVICE_POINTER: - return IDLE_SOURCE_POINTER; - case WLR_INPUT_DEVICE_TOUCH: - return IDLE_SOURCE_TOUCH; - case WLR_INPUT_DEVICE_TABLET_TOOL: - return IDLE_SOURCE_TABLET_TOOL; - case WLR_INPUT_DEVICE_TABLET_PAD: - return IDLE_SOURCE_TABLET_PAD; - case WLR_INPUT_DEVICE_SWITCH: - return IDLE_SOURCE_SWITCH; - } - - abort(); -} - -void cursor_handle_activity_from_idle_source(struct sway_cursor *cursor, - enum sway_input_idle_source idle_source) { - wl_event_source_timer_update( - cursor->hide_source, cursor_get_timeout(cursor)); - - seat_idle_notify_activity(cursor->seat, idle_source); - if (idle_source != IDLE_SOURCE_TOUCH) { - cursor_unhide(cursor); - } -} - -void cursor_handle_activity_from_device(struct sway_cursor *cursor, - struct wlr_input_device *device) { - enum sway_input_idle_source idle_source = idle_source_from_device(device); - cursor_handle_activity_from_idle_source(cursor, idle_source); -} - -void cursor_unhide(struct sway_cursor *cursor) { - if (!cursor->hidden) { - return; - } - - cursor->hidden = false; - if (cursor->image_surface) { - cursor_set_image_surface(cursor, - cursor->image_surface, - cursor->hotspot_x, - cursor->hotspot_y, - cursor->image_client); - } else { - const char *image = cursor->image; - cursor->image = NULL; - cursor_set_image(cursor, image, cursor->image_client); - } - cursor_rebase(cursor); - wl_event_source_timer_update(cursor->hide_source, cursor_get_timeout(cursor)); -} - -void pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, - struct wlr_input_device *device, double dx, double dy, - double dx_unaccel, double dy_unaccel) { - wlr_relative_pointer_manager_v1_send_relative_motion( - server.relative_pointer_manager, - cursor->seat->wlr_seat, (uint64_t)time_msec * 1000, - dx, dy, dx_unaccel, dy_unaccel); - - // Only apply pointer constraints to real pointer input. - if (cursor->active_constraint && device->type == WLR_INPUT_DEVICE_POINTER) { - struct wlr_surface *surface = NULL; - double sx, sy; - node_at_coords(cursor->seat, - cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); - - if (cursor->active_constraint->surface != surface) { - return; - } - - double sx_confined, sy_confined; - if (!wlr_region_confine(&cursor->confine, sx, sy, sx + dx, sy + dy, - &sx_confined, &sy_confined)) { - return; - } - - dx = sx_confined - sx; - dy = sy_confined - sy; - } - - wlr_cursor_move(cursor->cursor, device, dx, dy); - - seatop_pointer_motion(cursor->seat, time_msec); -} - -static void handle_pointer_motion_relative( - struct wl_listener *listener, void *data) { - struct sway_cursor *cursor = wl_container_of(listener, cursor, motion); - struct wlr_pointer_motion_event *e = data; - cursor_handle_activity_from_device(cursor, &e->pointer->base); - - pointer_motion(cursor, e->time_msec, &e->pointer->base, e->delta_x, - e->delta_y, e->unaccel_dx, e->unaccel_dy); -} - -static void handle_pointer_motion_absolute( - struct wl_listener *listener, void *data) { - struct sway_cursor *cursor = - wl_container_of(listener, cursor, motion_absolute); - struct wlr_pointer_motion_absolute_event *event = data; - cursor_handle_activity_from_device(cursor, &event->pointer->base); - - double lx, ly; - wlr_cursor_absolute_to_layout_coords(cursor->cursor, &event->pointer->base, - event->x, event->y, &lx, &ly); - - double dx = lx - cursor->cursor->x; - double dy = ly - cursor->cursor->y; - - pointer_motion(cursor, event->time_msec, &event->pointer->base, dx, dy, - dx, dy); -} - -void dispatch_cursor_button(struct sway_cursor *cursor, - struct wlr_input_device *device, uint32_t time_msec, uint32_t button, - enum wlr_button_state state) { - if (time_msec == 0) { - time_msec = get_current_time_msec(); - } - - seatop_button(cursor->seat, time_msec, device, button, state); -} - -static void handle_pointer_button(struct wl_listener *listener, void *data) { - struct sway_cursor *cursor = wl_container_of(listener, cursor, button); - struct wlr_pointer_button_event *event = data; - - if (event->state == WLR_BUTTON_PRESSED) { - cursor->pressed_button_count++; - } else { - if (cursor->pressed_button_count > 0) { - cursor->pressed_button_count--; - } else { - sway_log(SWAY_ERROR, "Pressed button count was wrong"); - } - } - - cursor_handle_activity_from_device(cursor, &event->pointer->base); - dispatch_cursor_button(cursor, &event->pointer->base, - event->time_msec, event->button, event->state); -} - -void dispatch_cursor_axis(struct sway_cursor *cursor, - struct wlr_pointer_axis_event *event) { - seatop_pointer_axis(cursor->seat, event); -} - -static void handle_pointer_axis(struct wl_listener *listener, void *data) { - struct sway_cursor *cursor = wl_container_of(listener, cursor, axis); - struct wlr_pointer_axis_event *event = data; - cursor_handle_activity_from_device(cursor, &event->pointer->base); - dispatch_cursor_axis(cursor, event); -} - -static void handle_pointer_frame(struct wl_listener *listener, void *data) { - struct sway_cursor *cursor = wl_container_of(listener, cursor, frame); - wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); -} - -static void handle_touch_down(struct wl_listener *listener, void *data) { - struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_down); - struct wlr_touch_down_event *event = data; - cursor_handle_activity_from_device(cursor, &event->touch->base); - cursor_hide(cursor); - - struct sway_seat *seat = cursor->seat; - - double lx, ly; - wlr_cursor_absolute_to_layout_coords(cursor->cursor, &event->touch->base, - event->x, event->y, &lx, &ly); - - seat->touch_id = event->touch_id; - seat->touch_x = lx; - seat->touch_y = ly; - - seatop_touch_down(seat, event, lx, ly); -} - -static void handle_touch_up(struct wl_listener *listener, void *data) { - struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_up); - struct wlr_touch_up_event *event = data; - cursor_handle_activity_from_device(cursor, &event->touch->base); - - struct sway_seat *seat = cursor->seat; - - if (cursor->simulating_pointer_from_touch) { - if (cursor->pointer_touch_id == cursor->seat->touch_id) { - cursor->pointer_touch_up = true; - dispatch_cursor_button(cursor, &event->touch->base, - event->time_msec, BTN_LEFT, WLR_BUTTON_RELEASED); - } - } else { - seatop_touch_up(seat, event); - } -} - -static void handle_touch_cancel(struct wl_listener *listener, void *data) { - struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_cancel); - struct wlr_touch_cancel_event *event = data; - cursor_handle_activity_from_device(cursor, &event->touch->base); - - struct sway_seat *seat = cursor->seat; - - if (cursor->simulating_pointer_from_touch) { - if (cursor->pointer_touch_id == cursor->seat->touch_id) { - cursor->pointer_touch_up = true; - dispatch_cursor_button(cursor, &event->touch->base, - event->time_msec, BTN_LEFT, WLR_BUTTON_RELEASED); - } - } else { - seatop_touch_cancel(seat, event); - } -} - -static void handle_touch_motion(struct wl_listener *listener, void *data) { - struct sway_cursor *cursor = - wl_container_of(listener, cursor, touch_motion); - struct wlr_touch_motion_event *event = data; - cursor_handle_activity_from_device(cursor, &event->touch->base); - - struct sway_seat *seat = cursor->seat; - - double lx, ly; - wlr_cursor_absolute_to_layout_coords(cursor->cursor, &event->touch->base, - event->x, event->y, &lx, &ly); - - if (seat->touch_id == event->touch_id) { - seat->touch_x = lx; - seat->touch_y = ly; - struct sway_drag_icon *drag_icon; - wl_list_for_each(drag_icon, &root->drag_icons, link) { - if (drag_icon->seat == seat) { - drag_icon_update_position(drag_icon); - } - } - } - - if (cursor->simulating_pointer_from_touch) { - if (seat->touch_id == cursor->pointer_touch_id) { - double dx, dy; - dx = lx - cursor->cursor->x; - dy = ly - cursor->cursor->y; - pointer_motion(cursor, event->time_msec, &event->touch->base, - dx, dy, dx, dy); - } - } else { - seatop_touch_motion(seat, event, lx, ly); - } -} - -static void handle_touch_frame(struct wl_listener *listener, void *data) { - struct sway_cursor *cursor = - wl_container_of(listener, cursor, touch_frame); - - struct wlr_seat *wlr_seat = cursor->seat->wlr_seat; - - if (cursor->simulating_pointer_from_touch) { - wlr_seat_pointer_notify_frame(wlr_seat); - - if (cursor->pointer_touch_up) { - cursor->pointer_touch_up = false; - cursor->simulating_pointer_from_touch = false; - } - } else { - wlr_seat_touch_notify_frame(wlr_seat); - } -} - -static double apply_mapping_from_coord(double low, double high, double value) { - if (isnan(value)) { - return value; - } - - return (value - low) / (high - low); -} - -static void apply_mapping_from_region(struct wlr_input_device *device, - struct input_config_mapped_from_region *region, double *x, double *y) { - double x1 = region->x1, x2 = region->x2; - double y1 = region->y1, y2 = region->y2; - - if (region->mm && device->type == WLR_INPUT_DEVICE_TABLET_TOOL) { - struct wlr_tablet *tablet = wlr_tablet_from_input_device(device); - if (tablet->width_mm == 0 || tablet->height_mm == 0) { - return; - } - x1 /= tablet->width_mm; - x2 /= tablet->width_mm; - y1 /= tablet->height_mm; - y2 /= tablet->height_mm; - } - - *x = apply_mapping_from_coord(x1, x2, *x); - *y = apply_mapping_from_coord(y1, y2, *y); -} - -static void handle_tablet_tool_position(struct sway_cursor *cursor, - struct sway_tablet_tool *tool, - bool change_x, bool change_y, - double x, double y, double dx, double dy, - int32_t time_msec) { - - if (!change_x && !change_y) { - return; - } - - struct sway_tablet *tablet = tool->tablet; - struct sway_input_device *input_device = tablet->seat_device->input_device; - struct input_config *ic = input_device_get_config(input_device); - if (ic != NULL && ic->mapped_from_region != NULL) { - apply_mapping_from_region(input_device->wlr_device, - ic->mapped_from_region, &x, &y); - } - - switch (tool->mode) { - case SWAY_TABLET_TOOL_MODE_ABSOLUTE: - wlr_cursor_warp_absolute(cursor->cursor, input_device->wlr_device, - change_x ? x : NAN, change_y ? y : NAN); - break; - case SWAY_TABLET_TOOL_MODE_RELATIVE: - wlr_cursor_move(cursor->cursor, input_device->wlr_device, dx, dy); - break; - } - - double sx, sy; - struct wlr_surface *surface = NULL; - struct sway_seat *seat = cursor->seat; - node_at_coords(seat, cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); - - // The logic for whether we should send a tablet event or an emulated pointer - // event is tricky. It comes down to: - // * If we began a drag on a non-tablet surface (simulating_pointer_from_tool_tip), - // then we should continue sending emulated pointer events regardless of - // whether the surface currently under us accepts tablet or not. - // * Otherwise, if we are over a surface that accepts tablet, then we should - // send tablet events. - // * If we began a drag over a tablet surface, we should continue sending - // tablet events until the drag is released, even if we are now over a - // non-tablet surface. - if (!cursor->simulating_pointer_from_tool_tip && - ((surface && wlr_surface_accepts_tablet_v2(tablet->tablet_v2, surface)) || - wlr_tablet_tool_v2_has_implicit_grab(tool->tablet_v2_tool))) { - seatop_tablet_tool_motion(seat, tool, time_msec); - } else { - wlr_tablet_v2_tablet_tool_notify_proximity_out(tool->tablet_v2_tool); - pointer_motion(cursor, time_msec, input_device->wlr_device, dx, dy, dx, dy); - } -} - -static void handle_tool_axis(struct wl_listener *listener, void *data) { - struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_axis); - struct wlr_tablet_tool_axis_event *event = data; - cursor_handle_activity_from_device(cursor, &event->tablet->base); - - struct sway_tablet_tool *sway_tool = event->tool->data; - if (!sway_tool) { - sway_log(SWAY_DEBUG, "tool axis before proximity"); - return; - } - - handle_tablet_tool_position(cursor, sway_tool, - event->updated_axes & WLR_TABLET_TOOL_AXIS_X, - event->updated_axes & WLR_TABLET_TOOL_AXIS_Y, - event->x, event->y, event->dx, event->dy, event->time_msec); - - if (event->updated_axes & WLR_TABLET_TOOL_AXIS_PRESSURE) { - wlr_tablet_v2_tablet_tool_notify_pressure( - sway_tool->tablet_v2_tool, event->pressure); - } - - if (event->updated_axes & WLR_TABLET_TOOL_AXIS_DISTANCE) { - wlr_tablet_v2_tablet_tool_notify_distance( - sway_tool->tablet_v2_tool, event->distance); - } - - if (event->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_X) { - sway_tool->tilt_x = event->tilt_x; - } - - if (event->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_Y) { - sway_tool->tilt_y = event->tilt_y; - } - - if (event->updated_axes & (WLR_TABLET_TOOL_AXIS_TILT_X | WLR_TABLET_TOOL_AXIS_TILT_Y)) { - wlr_tablet_v2_tablet_tool_notify_tilt( - sway_tool->tablet_v2_tool, - sway_tool->tilt_x, sway_tool->tilt_y); - } - - if (event->updated_axes & WLR_TABLET_TOOL_AXIS_ROTATION) { - wlr_tablet_v2_tablet_tool_notify_rotation( - sway_tool->tablet_v2_tool, event->rotation); - } - - if (event->updated_axes & WLR_TABLET_TOOL_AXIS_SLIDER) { - wlr_tablet_v2_tablet_tool_notify_slider( - sway_tool->tablet_v2_tool, event->slider); - } - - if (event->updated_axes & WLR_TABLET_TOOL_AXIS_WHEEL) { - wlr_tablet_v2_tablet_tool_notify_wheel( - sway_tool->tablet_v2_tool, event->wheel_delta, 0); - } -} - -static void handle_tool_tip(struct wl_listener *listener, void *data) { - struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_tip); - struct wlr_tablet_tool_tip_event *event = data; - cursor_handle_activity_from_device(cursor, &event->tablet->base); - - struct sway_tablet_tool *sway_tool = event->tool->data; - struct wlr_tablet_v2_tablet *tablet_v2 = sway_tool->tablet->tablet_v2; - struct sway_seat *seat = cursor->seat; - - - double sx, sy; - struct wlr_surface *surface = NULL; - node_at_coords(seat, cursor->cursor->x, cursor->cursor->y, - &surface, &sx, &sy); - - if (cursor->simulating_pointer_from_tool_tip && - event->state == WLR_TABLET_TOOL_TIP_UP) { - cursor->simulating_pointer_from_tool_tip = false; - dispatch_cursor_button(cursor, &event->tablet->base, event->time_msec, - BTN_LEFT, WLR_BUTTON_RELEASED); - wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); - } else if (!surface || !wlr_surface_accepts_tablet_v2(tablet_v2, surface)) { - // If we started holding the tool tip down on a surface that accepts - // tablet v2, we should notify that surface if it gets released over a - // surface that doesn't support v2. - if (event->state == WLR_TABLET_TOOL_TIP_UP) { - seatop_tablet_tool_tip(seat, sway_tool, event->time_msec, - WLR_TABLET_TOOL_TIP_UP); - } else { - cursor->simulating_pointer_from_tool_tip = true; - dispatch_cursor_button(cursor, &event->tablet->base, - event->time_msec, BTN_LEFT, WLR_BUTTON_PRESSED); - wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); - } - } else { - seatop_tablet_tool_tip(seat, sway_tool, event->time_msec, event->state); - } -} - -static struct sway_tablet *get_tablet_for_device(struct sway_cursor *cursor, - struct wlr_input_device *device) { - struct sway_tablet *tablet; - wl_list_for_each(tablet, &cursor->tablets, link) { - if (tablet->seat_device->input_device->wlr_device == device) { - return tablet; - } - } - return NULL; -} - -static void handle_tool_proximity(struct wl_listener *listener, void *data) { - struct sway_cursor *cursor = - wl_container_of(listener, cursor, tool_proximity); - struct wlr_tablet_tool_proximity_event *event = data; - cursor_handle_activity_from_device(cursor, &event->tablet->base); - - struct wlr_tablet_tool *tool = event->tool; - if (!tool->data) { - struct sway_tablet *tablet = get_tablet_for_device(cursor, - &event->tablet->base); - if (!tablet) { - sway_log(SWAY_ERROR, "no tablet for tablet tool"); - return; - } - sway_tablet_tool_configure(tablet, tool); - } - - struct sway_tablet_tool *sway_tool = tool->data; - if (!sway_tool) { - sway_log(SWAY_ERROR, "tablet tool not initialized"); - return; - } - - if (event->state == WLR_TABLET_TOOL_PROXIMITY_OUT) { - wlr_tablet_v2_tablet_tool_notify_proximity_out(sway_tool->tablet_v2_tool); - return; - } - - handle_tablet_tool_position(cursor, sway_tool, true, true, event->x, event->y, - 0, 0, event->time_msec); -} - -static void handle_tool_button(struct wl_listener *listener, void *data) { - struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_button); - struct wlr_tablet_tool_button_event *event = data; - cursor_handle_activity_from_device(cursor, &event->tablet->base); - - struct sway_tablet_tool *sway_tool = event->tool->data; - if (!sway_tool) { - sway_log(SWAY_DEBUG, "tool button before proximity"); - return; - } - struct wlr_tablet_v2_tablet *tablet_v2 = sway_tool->tablet->tablet_v2; - - double sx, sy; - struct wlr_surface *surface = NULL; - - node_at_coords(cursor->seat, cursor->cursor->x, cursor->cursor->y, - &surface, &sx, &sy); - - // TODO: floating resize should support graphics tablet events - struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(cursor->seat->wlr_seat); - uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; - bool mod_pressed = modifiers & config->floating_mod; - - bool surface_supports_tablet_events = - surface && wlr_surface_accepts_tablet_v2(tablet_v2, surface); - - // Simulate pointer when: - // 1. The modifier key is pressed, OR - // 2. The surface under the cursor does not support tablet events. - bool should_simulate_pointer = mod_pressed || !surface_supports_tablet_events; - - // Similar to tool tip, we need to selectively simulate mouse events, but we - // want to make sure that it is always consistent. Because all tool buttons - // currently map to BTN_RIGHT, we need to keep count of how many tool - // buttons are currently pressed down so we can send consistent events. - // - // The logic follows: - // - If we are already simulating the pointer, we should continue to do so - // until at least no tool button is held down. - // - If we should simulate the pointer and no tool button is currently held - // down, begin simulating the pointer. - // - If neither of the above are true, send the tablet events. - if ((cursor->tool_buttons > 0 && cursor->simulating_pointer_from_tool_button) - || (cursor->tool_buttons == 0 && should_simulate_pointer)) { - cursor->simulating_pointer_from_tool_button = true; - - // TODO: the user may want to configure which tool buttons are mapped to - // which simulated pointer buttons - switch (event->state) { - case WLR_BUTTON_PRESSED: - if (cursor->tool_buttons == 0) { - dispatch_cursor_button(cursor, &event->tablet->base, - event->time_msec, BTN_RIGHT, event->state); - } - break; - case WLR_BUTTON_RELEASED: - if (cursor->tool_buttons <= 1) { - dispatch_cursor_button(cursor, &event->tablet->base, - event->time_msec, BTN_RIGHT, event->state); - } - break; - } - wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); - } else { - cursor->simulating_pointer_from_tool_button = false; - - wlr_tablet_v2_tablet_tool_notify_button(sway_tool->tablet_v2_tool, - event->button, (enum zwp_tablet_pad_v2_button_state)event->state); - } - - // Update tool button count. - switch (event->state) { - case WLR_BUTTON_PRESSED: - cursor->tool_buttons++; - break; - case WLR_BUTTON_RELEASED: - if (cursor->tool_buttons == 0) { - sway_log(SWAY_ERROR, "inconsistent tablet tool button events"); - } else { - cursor->tool_buttons--; - } - break; - } -} - -static void check_constraint_region(struct sway_cursor *cursor) { - struct wlr_pointer_constraint_v1 *constraint = cursor->active_constraint; - pixman_region32_t *region = &constraint->region; - struct sway_view *view = view_from_wlr_surface(constraint->surface); - if (cursor->active_confine_requires_warp && view) { - cursor->active_confine_requires_warp = false; - - struct sway_container *con = view->container; - - double sx = cursor->cursor->x - con->pending.content_x + view->geometry.x; - double sy = cursor->cursor->y - con->pending.content_y + view->geometry.y; - - if (!pixman_region32_contains_point(region, - floor(sx), floor(sy), NULL)) { - int nboxes; - pixman_box32_t *boxes = pixman_region32_rectangles(region, &nboxes); - if (nboxes > 0) { - double sx = (boxes[0].x1 + boxes[0].x2) / 2.; - double sy = (boxes[0].y1 + boxes[0].y2) / 2.; - - wlr_cursor_warp_closest(cursor->cursor, NULL, - sx + con->pending.content_x - view->geometry.x, - sy + con->pending.content_y - view->geometry.y); - - cursor_rebase(cursor); - } - } - } - - // A locked pointer will result in an empty region, thus disallowing all movement - if (constraint->type == WLR_POINTER_CONSTRAINT_V1_CONFINED) { - pixman_region32_copy(&cursor->confine, region); - } else { - pixman_region32_clear(&cursor->confine); - } -} - -static void handle_constraint_commit(struct wl_listener *listener, - void *data) { - struct sway_cursor *cursor = - wl_container_of(listener, cursor, constraint_commit); - struct wlr_pointer_constraint_v1 *constraint = cursor->active_constraint; - assert(constraint->surface == data); - - check_constraint_region(cursor); -} - -static void handle_pointer_constraint_set_region(struct wl_listener *listener, - void *data) { - struct sway_pointer_constraint *sway_constraint = - wl_container_of(listener, sway_constraint, set_region); - struct sway_cursor *cursor = sway_constraint->cursor; - - cursor->active_confine_requires_warp = true; -} - -static void handle_request_pointer_set_cursor(struct wl_listener *listener, - void *data) { - struct sway_cursor *cursor = - wl_container_of(listener, cursor, request_set_cursor); - if (!seatop_allows_set_cursor(cursor->seat)) { - return; - } - struct wlr_seat_pointer_request_set_cursor_event *event = data; - - struct wl_client *focused_client = NULL; - struct wlr_surface *focused_surface = - cursor->seat->wlr_seat->pointer_state.focused_surface; - if (focused_surface != NULL) { - focused_client = wl_resource_get_client(focused_surface->resource); - } - - // TODO: check cursor mode - if (focused_client == NULL || - event->seat_client->client != focused_client) { - sway_log(SWAY_DEBUG, "denying request to set cursor from unfocused client"); - return; - } - - cursor_set_image_surface(cursor, event->surface, event->hotspot_x, - event->hotspot_y, focused_client); -} - -static void handle_pointer_hold_begin(struct wl_listener *listener, void *data) { - struct sway_cursor *cursor = wl_container_of( - listener, cursor, hold_begin); - struct wlr_pointer_hold_begin_event *event = data; - cursor_handle_activity_from_device(cursor, &event->pointer->base); - seatop_hold_begin(cursor->seat, event); -} - -static void handle_pointer_hold_end(struct wl_listener *listener, void *data) { - struct sway_cursor *cursor = wl_container_of( - listener, cursor, hold_end); - struct wlr_pointer_hold_end_event *event = data; - cursor_handle_activity_from_device(cursor, &event->pointer->base); - seatop_hold_end(cursor->seat, event); -} - -static void handle_pointer_pinch_begin(struct wl_listener *listener, void *data) { - struct sway_cursor *cursor = wl_container_of( - listener, cursor, pinch_begin); - struct wlr_pointer_pinch_begin_event *event = data; - cursor_handle_activity_from_device(cursor, &event->pointer->base); - seatop_pinch_begin(cursor->seat, event); -} - -static void handle_pointer_pinch_update(struct wl_listener *listener, void *data) { - struct sway_cursor *cursor = wl_container_of( - listener, cursor, pinch_update); - struct wlr_pointer_pinch_update_event *event = data; - cursor_handle_activity_from_device(cursor, &event->pointer->base); - seatop_pinch_update(cursor->seat, event); -} - -static void handle_pointer_pinch_end(struct wl_listener *listener, void *data) { - struct sway_cursor *cursor = wl_container_of( - listener, cursor, pinch_end); - struct wlr_pointer_pinch_end_event *event = data; - cursor_handle_activity_from_device(cursor, &event->pointer->base); - seatop_pinch_end(cursor->seat, event); -} - -static void handle_pointer_swipe_begin(struct wl_listener *listener, void *data) { - struct sway_cursor *cursor = wl_container_of( - listener, cursor, swipe_begin); - struct wlr_pointer_swipe_begin_event *event = data; - cursor_handle_activity_from_device(cursor, &event->pointer->base); - seatop_swipe_begin(cursor->seat, event); -} - -static void handle_pointer_swipe_update(struct wl_listener *listener, void *data) { - struct sway_cursor *cursor = wl_container_of( - listener, cursor, swipe_update); - struct wlr_pointer_swipe_update_event *event = data; - cursor_handle_activity_from_device(cursor, &event->pointer->base); - seatop_swipe_update(cursor->seat, event); -} - -static void handle_pointer_swipe_end(struct wl_listener *listener, void *data) { - struct sway_cursor *cursor = wl_container_of( - listener, cursor, swipe_end); - struct wlr_pointer_swipe_end_event *event = data; - cursor_handle_activity_from_device(cursor, &event->pointer->base); - seatop_swipe_end(cursor->seat, event); -} - -static void handle_image_surface_destroy(struct wl_listener *listener, - void *data) { - struct sway_cursor *cursor = - wl_container_of(listener, cursor, image_surface_destroy); - cursor_set_image(cursor, NULL, cursor->image_client); - cursor_rebase(cursor); -} - -static void set_image_surface(struct sway_cursor *cursor, - struct wlr_surface *surface) { - wl_list_remove(&cursor->image_surface_destroy.link); - cursor->image_surface = surface; - if (surface) { - wl_signal_add(&surface->events.destroy, &cursor->image_surface_destroy); - } else { - wl_list_init(&cursor->image_surface_destroy.link); - } -} - -void cursor_set_image(struct sway_cursor *cursor, const char *image, - struct wl_client *client) { - if (!(cursor->seat->wlr_seat->capabilities & WL_SEAT_CAPABILITY_POINTER)) { - return; - } - - const char *current_image = cursor->image; - set_image_surface(cursor, NULL); - cursor->image = image; - cursor->hotspot_x = cursor->hotspot_y = 0; - cursor->image_client = client; - - if (cursor->hidden) { - return; - } - - if (!image) { - wlr_cursor_unset_image(cursor->cursor); - } else if (!current_image || strcmp(current_image, image) != 0) { - wlr_cursor_set_xcursor(cursor->cursor, cursor->xcursor_manager, image); - } -} - -void cursor_set_image_surface(struct sway_cursor *cursor, - struct wlr_surface *surface, int32_t hotspot_x, int32_t hotspot_y, - struct wl_client *client) { - if (!(cursor->seat->wlr_seat->capabilities & WL_SEAT_CAPABILITY_POINTER)) { - return; - } - - set_image_surface(cursor, surface); - cursor->image = NULL; - cursor->hotspot_x = hotspot_x; - cursor->hotspot_y = hotspot_y; - cursor->image_client = client; - - if (cursor->hidden) { - return; - } - - wlr_cursor_set_surface(cursor->cursor, surface, hotspot_x, hotspot_y); -} - -void sway_cursor_destroy(struct sway_cursor *cursor) { - if (!cursor) { - return; - } - - wl_event_source_remove(cursor->hide_source); - - wl_list_remove(&cursor->image_surface_destroy.link); - wl_list_remove(&cursor->hold_begin.link); - wl_list_remove(&cursor->hold_end.link); - wl_list_remove(&cursor->pinch_begin.link); - wl_list_remove(&cursor->pinch_update.link); - wl_list_remove(&cursor->pinch_end.link); - wl_list_remove(&cursor->swipe_begin.link); - wl_list_remove(&cursor->swipe_update.link); - wl_list_remove(&cursor->swipe_end.link); - wl_list_remove(&cursor->motion.link); - wl_list_remove(&cursor->motion_absolute.link); - wl_list_remove(&cursor->button.link); - wl_list_remove(&cursor->axis.link); - wl_list_remove(&cursor->frame.link); - wl_list_remove(&cursor->touch_down.link); - wl_list_remove(&cursor->touch_up.link); - wl_list_remove(&cursor->touch_cancel.link); - wl_list_remove(&cursor->touch_motion.link); - wl_list_remove(&cursor->touch_frame.link); - wl_list_remove(&cursor->tool_axis.link); - wl_list_remove(&cursor->tool_tip.link); - wl_list_remove(&cursor->tool_button.link); - wl_list_remove(&cursor->request_set_cursor.link); - - wlr_xcursor_manager_destroy(cursor->xcursor_manager); - wlr_cursor_destroy(cursor->cursor); - free(cursor); -} - -struct sway_cursor *sway_cursor_create(struct sway_seat *seat) { - struct sway_cursor *cursor = calloc(1, sizeof(struct sway_cursor)); - if (!sway_assert(cursor, "could not allocate sway cursor")) { - return NULL; - } - - struct wlr_cursor *wlr_cursor = wlr_cursor_create(); - if (!sway_assert(wlr_cursor, "could not allocate wlr cursor")) { - free(cursor); - return NULL; - } - - cursor->previous.x = wlr_cursor->x; - cursor->previous.y = wlr_cursor->y; - - cursor->seat = seat; - wlr_cursor_attach_output_layout(wlr_cursor, root->output_layout); - - cursor->hide_source = wl_event_loop_add_timer(server.wl_event_loop, - hide_notify, cursor); - - wl_list_init(&cursor->image_surface_destroy.link); - cursor->image_surface_destroy.notify = handle_image_surface_destroy; - - wl_signal_add(&wlr_cursor->events.hold_begin, &cursor->hold_begin); - cursor->hold_begin.notify = handle_pointer_hold_begin; - wl_signal_add(&wlr_cursor->events.hold_end, &cursor->hold_end); - cursor->hold_end.notify = handle_pointer_hold_end; - - wl_signal_add(&wlr_cursor->events.pinch_begin, &cursor->pinch_begin); - cursor->pinch_begin.notify = handle_pointer_pinch_begin; - wl_signal_add(&wlr_cursor->events.pinch_update, &cursor->pinch_update); - cursor->pinch_update.notify = handle_pointer_pinch_update; - wl_signal_add(&wlr_cursor->events.pinch_end, &cursor->pinch_end); - cursor->pinch_end.notify = handle_pointer_pinch_end; - - wl_signal_add(&wlr_cursor->events.swipe_begin, &cursor->swipe_begin); - cursor->swipe_begin.notify = handle_pointer_swipe_begin; - wl_signal_add(&wlr_cursor->events.swipe_update, &cursor->swipe_update); - cursor->swipe_update.notify = handle_pointer_swipe_update; - wl_signal_add(&wlr_cursor->events.swipe_end, &cursor->swipe_end); - cursor->swipe_end.notify = handle_pointer_swipe_end; - - // input events - wl_signal_add(&wlr_cursor->events.motion, &cursor->motion); - cursor->motion.notify = handle_pointer_motion_relative; - - wl_signal_add(&wlr_cursor->events.motion_absolute, - &cursor->motion_absolute); - cursor->motion_absolute.notify = handle_pointer_motion_absolute; - - wl_signal_add(&wlr_cursor->events.button, &cursor->button); - cursor->button.notify = handle_pointer_button; - - wl_signal_add(&wlr_cursor->events.axis, &cursor->axis); - cursor->axis.notify = handle_pointer_axis; - - wl_signal_add(&wlr_cursor->events.frame, &cursor->frame); - cursor->frame.notify = handle_pointer_frame; - - wl_signal_add(&wlr_cursor->events.touch_down, &cursor->touch_down); - cursor->touch_down.notify = handle_touch_down; - - wl_signal_add(&wlr_cursor->events.touch_up, &cursor->touch_up); - cursor->touch_up.notify = handle_touch_up; - - wl_signal_add(&wlr_cursor->events.touch_cancel, &cursor->touch_cancel); - cursor->touch_cancel.notify = handle_touch_cancel; - - wl_signal_add(&wlr_cursor->events.touch_motion, - &cursor->touch_motion); - cursor->touch_motion.notify = handle_touch_motion; - - wl_signal_add(&wlr_cursor->events.touch_frame, &cursor->touch_frame); - cursor->touch_frame.notify = handle_touch_frame; - - wl_signal_add(&wlr_cursor->events.tablet_tool_axis, - &cursor->tool_axis); - cursor->tool_axis.notify = handle_tool_axis; - - wl_signal_add(&wlr_cursor->events.tablet_tool_tip, &cursor->tool_tip); - cursor->tool_tip.notify = handle_tool_tip; - - wl_signal_add(&wlr_cursor->events.tablet_tool_proximity, &cursor->tool_proximity); - cursor->tool_proximity.notify = handle_tool_proximity; - - wl_signal_add(&wlr_cursor->events.tablet_tool_button, &cursor->tool_button); - cursor->tool_button.notify = handle_tool_button; - - wl_signal_add(&seat->wlr_seat->events.request_set_cursor, - &cursor->request_set_cursor); - cursor->request_set_cursor.notify = handle_request_pointer_set_cursor; - - wl_list_init(&cursor->constraint_commit.link); - wl_list_init(&cursor->tablets); - wl_list_init(&cursor->tablet_pads); - - cursor->cursor = wlr_cursor; - - return cursor; -} - -/** - * Warps the cursor to the middle of the container argument. - * Does nothing if the cursor is already inside the container and `force` is - * false. If container is NULL, returns without doing anything. - */ -void cursor_warp_to_container(struct sway_cursor *cursor, - struct sway_container *container, bool force) { - if (!container) { - return; - } - - struct wlr_box box; - container_get_box(container, &box); - if (!force && wlr_box_contains_point(&box, cursor->cursor->x, - cursor->cursor->y)) { - return; - } - - double x = container->pending.x + container->pending.width / 2.0; - double y = container->pending.y + container->pending.height / 2.0; - - wlr_cursor_warp(cursor->cursor, NULL, x, y); - cursor_unhide(cursor); -} - -/** - * Warps the cursor to the middle of the workspace argument. - * If workspace is NULL, returns without doing anything. - */ -void cursor_warp_to_workspace(struct sway_cursor *cursor, - struct sway_workspace *workspace) { - if (!workspace) { - return; - } - - double x = workspace->x + workspace->width / 2.0; - double y = workspace->y + workspace->height / 2.0; - - wlr_cursor_warp(cursor->cursor, NULL, x, y); - cursor_unhide(cursor); -} - -uint32_t get_mouse_bindsym(const char *name, char **error) { - if (strncasecmp(name, "button", strlen("button")) == 0) { - // Map to x11 mouse buttons - int number = name[strlen("button")] - '0'; - if (number < 1 || number > 9 || strlen(name) > strlen("button0")) { - *error = strdup("Only buttons 1-9 are supported. For other mouse " - "buttons, use the name of the event code."); - return 0; - } - static const uint32_t buttons[] = {BTN_LEFT, BTN_MIDDLE, BTN_RIGHT, - SWAY_SCROLL_UP, SWAY_SCROLL_DOWN, SWAY_SCROLL_LEFT, - SWAY_SCROLL_RIGHT, BTN_SIDE, BTN_EXTRA}; - return buttons[number - 1]; - } else if (strncmp(name, "BTN_", strlen("BTN_")) == 0) { - // Get event code from name - int code = libevdev_event_code_from_name(EV_KEY, name); - if (code == -1) { - *error = format_str("Unknown event %s", name); - return 0; - } - return code; - } - return 0; -} - -uint32_t get_mouse_bindcode(const char *name, char **error) { - // Validate event code - errno = 0; - char *endptr; - int code = strtol(name, &endptr, 10); - if (endptr == name && code <= 0) { - *error = strdup("Button event code must be a positive integer."); - return 0; - } else if (errno == ERANGE) { - *error = strdup("Button event code out of range."); - return 0; - } - const char *event = libevdev_event_code_get_name(EV_KEY, code); - if (!event || strncmp(event, "BTN_", strlen("BTN_")) != 0) { - *error = format_str("Event code %d (%s) is not a button", - code, event ? event : "(null)"); - return 0; - } - return code; -} - -uint32_t get_mouse_button(const char *name, char **error) { - uint32_t button = get_mouse_bindsym(name, error); - if (!button && !*error) { - button = get_mouse_bindcode(name, error); - } - return button; -} - -const char *get_mouse_button_name(uint32_t button) { - const char *name = libevdev_event_code_get_name(EV_KEY, button); - if (!name) { - if (button == SWAY_SCROLL_UP) { - name = "SWAY_SCROLL_UP"; - } else if (button == SWAY_SCROLL_DOWN) { - name = "SWAY_SCROLL_DOWN"; - } else if (button == SWAY_SCROLL_LEFT) { - name = "SWAY_SCROLL_LEFT"; - } else if (button == SWAY_SCROLL_RIGHT) { - name = "SWAY_SCROLL_RIGHT"; - } - } - return name; -} - -static void warp_to_constraint_cursor_hint(struct sway_cursor *cursor) { - struct wlr_pointer_constraint_v1 *constraint = cursor->active_constraint; - - if (constraint->current.committed & - WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT) { - double sx = constraint->current.cursor_hint.x; - double sy = constraint->current.cursor_hint.y; - - struct sway_view *view = view_from_wlr_surface(constraint->surface); - if (!view) { - return; - } - - struct sway_container *con = view->container; - - double lx = sx + con->pending.content_x - view->geometry.x; - double ly = sy + con->pending.content_y - view->geometry.y; - - wlr_cursor_warp(cursor->cursor, NULL, lx, ly); - - // Warp the pointer as well, so that on the next pointer rebase we don't - // send an unexpected synthetic motion event to clients. - wlr_seat_pointer_warp(constraint->seat, sx, sy); - } -} - -void handle_constraint_destroy(struct wl_listener *listener, void *data) { - struct sway_pointer_constraint *sway_constraint = - wl_container_of(listener, sway_constraint, destroy); - struct wlr_pointer_constraint_v1 *constraint = data; - struct sway_cursor *cursor = sway_constraint->cursor; - - wl_list_remove(&sway_constraint->set_region.link); - wl_list_remove(&sway_constraint->destroy.link); - - if (cursor->active_constraint == constraint) { - warp_to_constraint_cursor_hint(cursor); - - if (cursor->constraint_commit.link.next != NULL) { - wl_list_remove(&cursor->constraint_commit.link); - } - wl_list_init(&cursor->constraint_commit.link); - cursor->active_constraint = NULL; - } - - free(sway_constraint); -} - -void handle_pointer_constraint(struct wl_listener *listener, void *data) { - struct wlr_pointer_constraint_v1 *constraint = data; - struct sway_seat *seat = constraint->seat->data; - - struct sway_pointer_constraint *sway_constraint = - calloc(1, sizeof(struct sway_pointer_constraint)); - sway_constraint->cursor = seat->cursor; - sway_constraint->constraint = constraint; - - sway_constraint->set_region.notify = handle_pointer_constraint_set_region; - wl_signal_add(&constraint->events.set_region, &sway_constraint->set_region); - - sway_constraint->destroy.notify = handle_constraint_destroy; - wl_signal_add(&constraint->events.destroy, &sway_constraint->destroy); - - struct wlr_surface *surface = seat->wlr_seat->keyboard_state.focused_surface; - if (surface && surface == constraint->surface) { - sway_cursor_constrain(seat->cursor, constraint); - } -} - -void sway_cursor_constrain(struct sway_cursor *cursor, - struct wlr_pointer_constraint_v1 *constraint) { - struct seat_config *config = seat_get_config(cursor->seat); - if (!config) { - config = seat_get_config_by_name("*"); - } - - if (!config || config->allow_constrain == CONSTRAIN_DISABLE) { - return; - } - - if (cursor->active_constraint == constraint) { - return; - } - - wl_list_remove(&cursor->constraint_commit.link); - if (cursor->active_constraint) { - if (constraint == NULL) { - warp_to_constraint_cursor_hint(cursor); - } - wlr_pointer_constraint_v1_send_deactivated( - cursor->active_constraint); - } - - cursor->active_constraint = constraint; - - if (constraint == NULL) { - wl_list_init(&cursor->constraint_commit.link); - return; - } - - cursor->active_confine_requires_warp = true; - - // FIXME: Big hack, stolen from wlr_pointer_constraints_v1.c:121. - // This is necessary because the focus may be set before the surface - // has finished committing, which means that warping won't work properly, - // since this code will be run *after* the focus has been set. - // That is why we duplicate the code here. - if (pixman_region32_not_empty(&constraint->current.region)) { - pixman_region32_intersect(&constraint->region, - &constraint->surface->input_region, &constraint->current.region); - } else { - pixman_region32_copy(&constraint->region, - &constraint->surface->input_region); - } - - check_constraint_region(cursor); - - wlr_pointer_constraint_v1_send_activated(constraint); - - cursor->constraint_commit.notify = handle_constraint_commit; - wl_signal_add(&constraint->surface->events.commit, - &cursor->constraint_commit); -} - -void handle_request_set_cursor_shape(struct wl_listener *listener, void *data) { - const struct wlr_cursor_shape_manager_v1_request_set_shape_event *event = data; - struct sway_seat *seat = event->seat_client->seat->data; - - if (!seatop_allows_set_cursor(seat)) { - return; - } - - struct wl_client *focused_client = NULL; - struct wlr_surface *focused_surface = seat->wlr_seat->pointer_state.focused_surface; - if (focused_surface != NULL) { - focused_client = wl_resource_get_client(focused_surface->resource); - } - - // TODO: check cursor mode - if (focused_client == NULL || event->seat_client->client != focused_client) { - sway_log(SWAY_DEBUG, "denying request to set cursor from unfocused client"); - return; - } - - cursor_set_image(seat->cursor, wlr_cursor_shape_v1_name(event->shape), focused_client); -} diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c deleted file mode 100644 index 288fddc41..000000000 --- a/sway/input/input-manager.c +++ /dev/null @@ -1,732 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sway/config.h" -#include "sway/input/cursor.h" -#include "sway/input/input-manager.h" -#include "sway/input/keyboard.h" -#include "sway/input/libinput.h" -#include "sway/input/seat.h" -#include "sway/ipc-server.h" -#include "sway/server.h" -#include "sway/tree/view.h" -#include "stringop.h" -#include "list.h" -#include "log.h" - -#if WLR_HAS_LIBINPUT_BACKEND -#include -#endif - -#define DEFAULT_SEAT "seat0" - -struct input_config *current_input_config = NULL; -struct seat_config *current_seat_config = NULL; - -struct sway_seat *input_manager_current_seat(void) { - struct sway_seat *seat = config->handler_context.seat; - if (!seat) { - seat = input_manager_get_default_seat(); - } - return seat; -} - -struct sway_seat *input_manager_get_default_seat(void) { - return input_manager_get_seat(DEFAULT_SEAT, true); -} - -struct sway_seat *input_manager_get_seat(const char *seat_name, bool create) { - struct sway_seat *seat = NULL; - wl_list_for_each(seat, &server.input->seats, link) { - if (strcmp(seat->wlr_seat->name, seat_name) == 0) { - return seat; - } - } - - return create ? seat_create(seat_name) : NULL; -} - -struct sway_seat *input_manager_sway_seat_from_wlr_seat(struct wlr_seat *wlr_seat) { - struct sway_seat *seat = NULL; - - wl_list_for_each(seat, &server.input->seats, link) { - if (seat->wlr_seat == wlr_seat) { - return seat; - } - } - - return NULL; -} - -char *input_device_get_identifier(struct wlr_input_device *device) { - int vendor = device->vendor; - int product = device->product; - char *name = strdup(device->name ? device->name : ""); - strip_whitespace(name); - - char *p = name; - for (; *p; ++p) { - // There are in fact input devices with unprintable characters in its name - if (*p == ' ' || !isprint(*p)) { - *p = '_'; - } - } - - char *identifier = format_str("%d:%d:%s", vendor, product, name); - free(name); - return identifier; -} - -static bool device_is_touchpad(struct sway_input_device *device) { -#if WLR_HAS_LIBINPUT_BACKEND - if (device->wlr_device->type != WLR_INPUT_DEVICE_POINTER || - !wlr_input_device_is_libinput(device->wlr_device)) { - return false; - } - - struct libinput_device *libinput_device = - wlr_libinput_get_device_handle(device->wlr_device); - - return libinput_device_config_tap_get_finger_count(libinput_device) > 0; -#else - return false; -#endif -} - -const char *input_device_get_type(struct sway_input_device *device) { - switch (device->wlr_device->type) { - case WLR_INPUT_DEVICE_POINTER: - if (device_is_touchpad(device)) { - return "touchpad"; - } else { - return "pointer"; - } - case WLR_INPUT_DEVICE_KEYBOARD: - return "keyboard"; - case WLR_INPUT_DEVICE_TOUCH: - return "touch"; - case WLR_INPUT_DEVICE_TABLET_TOOL: - return "tablet_tool"; - case WLR_INPUT_DEVICE_TABLET_PAD: - return "tablet_pad"; - case WLR_INPUT_DEVICE_SWITCH: - return "switch"; - } - return "unknown"; -} - -static void apply_input_type_config(struct sway_input_device *input_device) { - const char *device_type = input_device_get_type(input_device); - struct input_config *type_config = NULL; - for (int i = 0; i < config->input_type_configs->length; i++) { - struct input_config *ic = config->input_type_configs->items[i]; - if (strcmp(ic->identifier + 5, device_type) == 0) { - type_config = ic; - break; - } - } - if (type_config == NULL) { - return; - } - - for (int i = 0; i < config->input_configs->length; i++) { - struct input_config *ic = config->input_configs->items[i]; - if (strcmp(input_device->identifier, ic->identifier) == 0) { - struct input_config *current = new_input_config(ic->identifier); - merge_input_config(current, type_config); - merge_input_config(current, ic); - - current->input_type = device_type; - config->input_configs->items[i] = current; - free_input_config(ic); - ic = NULL; - - break; - } - } -} - -static struct sway_input_device *input_sway_device_from_wlr( - struct wlr_input_device *device) { - struct sway_input_device *input_device = NULL; - wl_list_for_each(input_device, &server.input->devices, link) { - if (input_device->wlr_device == device) { - return input_device; - } - } - return NULL; -} - -static bool input_has_seat_fallback_configuration(void) { - struct sway_seat *seat = NULL; - wl_list_for_each(seat, &server.input->seats, link) { - struct seat_config *seat_config = seat_get_config(seat); - if (seat_config && strcmp(seat_config->name, "*") != 0 - && seat_config->fallback != -1) { - return true; - } - } - - return false; -} - -void input_manager_verify_fallback_seat(void) { - struct sway_seat *seat = NULL; - if (!input_has_seat_fallback_configuration()) { - sway_log(SWAY_DEBUG, "no fallback seat config - creating default"); - seat = input_manager_get_default_seat(); - struct seat_config *sc = new_seat_config(seat->wlr_seat->name); - sc->fallback = true; - sc = store_seat_config(sc); - input_manager_apply_seat_config(sc); - } -} - -static void handle_device_destroy(struct wl_listener *listener, void *data) { - struct wlr_input_device *device = data; - - struct sway_input_device *input_device = input_sway_device_from_wlr(device); - - if (!sway_assert(input_device, "could not find sway device")) { - return; - } - - sway_log(SWAY_DEBUG, "removing device: '%s'", - input_device->identifier); - - struct sway_seat *seat = NULL; - wl_list_for_each(seat, &server.input->seats, link) { - seat_remove_device(seat, input_device); - } - - ipc_event_input("removed", input_device); - - wl_list_remove(&input_device->link); - wl_list_remove(&input_device->device_destroy.link); - free(input_device->identifier); - free(input_device); -} - -static void handle_new_input(struct wl_listener *listener, void *data) { - struct sway_input_manager *input = - wl_container_of(listener, input, new_input); - struct wlr_input_device *device = data; - - struct sway_input_device *input_device = - calloc(1, sizeof(struct sway_input_device)); - if (!sway_assert(input_device, "could not allocate input device")) { - return; - } - device->data = input_device; - - input_device->wlr_device = device; - input_device->identifier = input_device_get_identifier(device); - wl_list_insert(&input->devices, &input_device->link); - - sway_log(SWAY_DEBUG, "adding device: '%s'", - input_device->identifier); - - apply_input_type_config(input_device); - -#if WLR_HAS_LIBINPUT_BACKEND - bool config_changed = sway_input_configure_libinput_device(input_device); -#else - bool config_changed = false; -#endif - - wl_signal_add(&device->events.destroy, &input_device->device_destroy); - input_device->device_destroy.notify = handle_device_destroy; - - input_manager_verify_fallback_seat(); - - bool added = false; - struct sway_seat *seat = NULL; - wl_list_for_each(seat, &input->seats, link) { - struct seat_config *seat_config = seat_get_config(seat); - bool has_attachment = seat_config && - (seat_config_get_attachment(seat_config, input_device->identifier) || - seat_config_get_attachment(seat_config, "*")); - - if (has_attachment) { - seat_add_device(seat, input_device); - added = true; - } - } - - if (!added) { - wl_list_for_each(seat, &input->seats, link) { - struct seat_config *seat_config = seat_get_config(seat); - if (seat_config && seat_config->fallback == 1) { - seat_add_device(seat, input_device); - added = true; - } - } - } - - if (!added) { - sway_log(SWAY_DEBUG, - "device '%s' is not configured on any seats", - input_device->identifier); - } - - ipc_event_input("added", input_device); - - if (config_changed) { - ipc_event_input("libinput_config", input_device); - } -} - -static void handle_inhibit_activate(struct wl_listener *listener, void *data) { - struct sway_input_manager *input_manager = wl_container_of( - listener, input_manager, inhibit_activate); - struct sway_seat *seat; - wl_list_for_each(seat, &input_manager->seats, link) { - seat_set_exclusive_client(seat, input_manager->inhibit->active_client); - } -} - -static void handle_inhibit_deactivate(struct wl_listener *listener, void *data) { - struct sway_input_manager *input_manager = wl_container_of( - listener, input_manager, inhibit_deactivate); - struct sway_seat *seat; - if (server.session_lock.locked) { - // Don't deactivate the grab of a screenlocker - return; - } - wl_list_for_each(seat, &input_manager->seats, link) { - seat_set_exclusive_client(seat, NULL); - struct sway_node *previous = seat_get_focus(seat); - if (previous) { - // Hack to get seat to re-focus the return value of get_focus - seat_set_focus(seat, NULL); - seat_set_focus(seat, previous); - } - } -} - -static void handle_keyboard_shortcuts_inhibitor_destroy( - struct wl_listener *listener, void *data) { - struct sway_keyboard_shortcuts_inhibitor *sway_inhibitor = - wl_container_of(listener, sway_inhibitor, destroy); - - sway_log(SWAY_DEBUG, "Removing keyboard shortcuts inhibitor"); - - // sway_seat::keyboard_shortcuts_inhibitors - wl_list_remove(&sway_inhibitor->link); - wl_list_remove(&sway_inhibitor->destroy.link); - free(sway_inhibitor); -} - -static void handle_keyboard_shortcuts_inhibit_new_inhibitor( - struct wl_listener *listener, void *data) { - struct sway_input_manager *input_manager = - wl_container_of(listener, input_manager, - keyboard_shortcuts_inhibit_new_inhibitor); - struct wlr_keyboard_shortcuts_inhibitor_v1 *inhibitor = data; - - sway_log(SWAY_DEBUG, "Adding keyboard shortcuts inhibitor"); - - struct sway_keyboard_shortcuts_inhibitor *sway_inhibitor = - calloc(1, sizeof(struct sway_keyboard_shortcuts_inhibitor)); - if (!sway_assert(sway_inhibitor, "could not allocate keyboard " - "shortcuts inhibitor")) { - return; - } - sway_inhibitor->inhibitor = inhibitor; - - sway_inhibitor->destroy.notify = handle_keyboard_shortcuts_inhibitor_destroy; - wl_signal_add(&inhibitor->events.destroy, &sway_inhibitor->destroy); - - // attach inhibitor to the seat it applies to - struct sway_seat *seat = inhibitor->seat->data; - wl_list_insert(&seat->keyboard_shortcuts_inhibitors, &sway_inhibitor->link); - - // per-view, seat-agnostic config via criteria - struct sway_view *view = view_from_wlr_surface(inhibitor->surface); - enum seat_config_shortcuts_inhibit inhibit = SHORTCUTS_INHIBIT_DEFAULT; - if (view) { - inhibit = view->shortcuts_inhibit; - } - - if (inhibit == SHORTCUTS_INHIBIT_DEFAULT) { - struct seat_config *config = seat_get_config(seat); - if (!config) { - config = seat_get_config_by_name("*"); - } - - if (config) { - inhibit = config->shortcuts_inhibit; - } - } - - if (inhibit == SHORTCUTS_INHIBIT_DISABLE) { - /** - * Here we deny to honour the inhibitor by never sending the - * activate signal. We can not, however, destroy the inhibitor - * because the protocol doesn't allow for it. So it will linger - * until the client removes it im- or explicitly. But at least - * it can only be one inhibitor per surface and seat at a time. - * - * We also want to allow the user to activate the inhibitor - * manually later which is why we do this check here where the - * inhibitor is already attached to its seat and ready for use. - */ - return; - } - - wlr_keyboard_shortcuts_inhibitor_v1_activate(inhibitor); -} - -void handle_virtual_keyboard(struct wl_listener *listener, void *data) { - struct sway_input_manager *input_manager = - wl_container_of(listener, input_manager, virtual_keyboard_new); - struct wlr_virtual_keyboard_v1 *keyboard = data; - struct wlr_input_device *device = &keyboard->keyboard.base; - - // TODO: Amend protocol to allow NULL seat - struct sway_seat *seat = keyboard->seat ? - input_manager_sway_seat_from_wlr_seat(keyboard->seat) : - input_manager_get_default_seat(); - - struct sway_input_device *input_device = - calloc(1, sizeof(struct sway_input_device)); - if (!sway_assert(input_device, "could not allocate input device")) { - return; - } - device->data = input_device; - - input_device->is_virtual = true; - input_device->wlr_device = device; - input_device->identifier = input_device_get_identifier(device); - wl_list_insert(&input_manager->devices, &input_device->link); - - sway_log(SWAY_DEBUG, "adding virtual keyboard: '%s'", - input_device->identifier); - - wl_signal_add(&device->events.destroy, &input_device->device_destroy); - input_device->device_destroy.notify = handle_device_destroy; - - seat_add_device(seat, input_device); -} - -void handle_virtual_pointer(struct wl_listener *listener, void *data) { - struct sway_input_manager *input_manager = - wl_container_of(listener, input_manager, virtual_pointer_new); - struct wlr_virtual_pointer_v1_new_pointer_event *event = data; - struct wlr_virtual_pointer_v1 *pointer = event->new_pointer; - struct wlr_input_device *device = &pointer->pointer.base; - - struct sway_seat *seat = event->suggested_seat ? - input_manager_sway_seat_from_wlr_seat(event->suggested_seat) : - input_manager_get_default_seat(); - - struct sway_input_device *input_device = - calloc(1, sizeof(struct sway_input_device)); - if (!sway_assert(input_device, "could not allocate input device")) { - return; - } - device->data = input_device; - - input_device->is_virtual = true; - input_device->wlr_device = device; - input_device->identifier = input_device_get_identifier(device); - wl_list_insert(&input_manager->devices, &input_device->link); - - sway_log(SWAY_DEBUG, "adding virtual pointer: '%s'", - input_device->identifier); - - wl_signal_add(&device->events.destroy, &input_device->device_destroy); - input_device->device_destroy.notify = handle_device_destroy; - - seat_add_device(seat, input_device); - - if (event->suggested_output) { - wlr_cursor_map_input_to_output(seat->cursor->cursor, device, - event->suggested_output); - } -} - -struct sway_input_manager *input_manager_create(struct sway_server *server) { - struct sway_input_manager *input = - calloc(1, sizeof(struct sway_input_manager)); - if (!input) { - return NULL; - } - - wl_list_init(&input->devices); - wl_list_init(&input->seats); - - input->new_input.notify = handle_new_input; - wl_signal_add(&server->backend->events.new_input, &input->new_input); - - input->virtual_keyboard = wlr_virtual_keyboard_manager_v1_create( - server->wl_display); - wl_signal_add(&input->virtual_keyboard->events.new_virtual_keyboard, - &input->virtual_keyboard_new); - input->virtual_keyboard_new.notify = handle_virtual_keyboard; - - input->virtual_pointer = wlr_virtual_pointer_manager_v1_create( - server->wl_display - ); - wl_signal_add(&input->virtual_pointer->events.new_virtual_pointer, - &input->virtual_pointer_new); - input->virtual_pointer_new.notify = handle_virtual_pointer; - - input->inhibit = wlr_input_inhibit_manager_create(server->wl_display); - input->inhibit_activate.notify = handle_inhibit_activate; - wl_signal_add(&input->inhibit->events.activate, - &input->inhibit_activate); - input->inhibit_deactivate.notify = handle_inhibit_deactivate; - wl_signal_add(&input->inhibit->events.deactivate, - &input->inhibit_deactivate); - - input->keyboard_shortcuts_inhibit = - wlr_keyboard_shortcuts_inhibit_v1_create(server->wl_display); - input->keyboard_shortcuts_inhibit_new_inhibitor.notify = - handle_keyboard_shortcuts_inhibit_new_inhibitor; - wl_signal_add(&input->keyboard_shortcuts_inhibit->events.new_inhibitor, - &input->keyboard_shortcuts_inhibit_new_inhibitor); - - input->pointer_gestures = wlr_pointer_gestures_v1_create(server->wl_display); - - return input; -} - -bool input_manager_has_focus(struct sway_node *node) { - struct sway_seat *seat = NULL; - wl_list_for_each(seat, &server.input->seats, link) { - if (seat_get_focus(seat) == node) { - return true; - } - } - - return false; -} - -void input_manager_set_focus(struct sway_node *node) { - struct sway_seat *seat; - wl_list_for_each(seat, &server.input->seats, link) { - seat_set_focus(seat, node); - seat_consider_warp_to_focus(seat); - } -} - -/** - * Re-translate keysyms if a change in the input config could affect them. - */ -static void retranslate_keysyms(struct input_config *input_config) { - for (int i = 0; i < config->input_configs->length; ++i) { - struct input_config *ic = config->input_configs->items[i]; - if (ic->xkb_layout || ic->xkb_file) { - // this is the first config with xkb_layout or xkb_file - if (ic->identifier == input_config->identifier) { - translate_keysyms(ic); - } - - return; - } - } - - for (int i = 0; i < config->input_type_configs->length; ++i) { - struct input_config *ic = config->input_type_configs->items[i]; - if (ic->xkb_layout || ic->xkb_file) { - // this is the first config with xkb_layout or xkb_file - if (ic->identifier == input_config->identifier) { - translate_keysyms(ic); - } - - return; - } - } -} - -static void input_manager_configure_input( - struct sway_input_device *input_device) { -#if WLR_HAS_LIBINPUT_BACKEND - bool config_changed = sway_input_configure_libinput_device(input_device); -#else - bool config_changed = false; -#endif - struct sway_seat *seat = NULL; - wl_list_for_each(seat, &server.input->seats, link) { - seat_configure_device(seat, input_device); - } - if (config_changed) { - ipc_event_input("libinput_config", input_device); - } -} - -void input_manager_configure_all_input_mappings(void) { - struct sway_input_device *input_device; - wl_list_for_each(input_device, &server.input->devices, link) { - struct sway_seat *seat; - wl_list_for_each(seat, &server.input->seats, link) { - seat_configure_device_mapping(seat, input_device); - } - -#if WLR_HAS_LIBINPUT_BACKEND - // Input devices mapped to unavailable outputs get their libinput - // send_events setting switched to false. We need to re-enable this - // when the output appears. - sway_input_configure_libinput_device_send_events(input_device); -#endif - } -} - -void input_manager_apply_input_config(struct input_config *input_config) { - struct sway_input_device *input_device = NULL; - bool wildcard = strcmp(input_config->identifier, "*") == 0; - bool type_wildcard = strncmp(input_config->identifier, "type:", 5) == 0; - wl_list_for_each(input_device, &server.input->devices, link) { - bool type_matches = type_wildcard && - strcmp(input_device_get_type(input_device), input_config->identifier + 5) == 0; - if (strcmp(input_device->identifier, input_config->identifier) == 0 - || wildcard - || type_matches) { - input_manager_configure_input(input_device); - } - } - - retranslate_keysyms(input_config); -} - -void input_manager_reset_input(struct sway_input_device *input_device) { -#if WLR_HAS_LIBINPUT_BACKEND - sway_input_reset_libinput_device(input_device); -#endif - struct sway_seat *seat = NULL; - wl_list_for_each(seat, &server.input->seats, link) { - seat_reset_device(seat, input_device); - } -} - -void input_manager_reset_all_inputs(void) { - // Set the active keyboard to NULL to avoid spamming configuration updates - // for all keyboard devices. - struct sway_seat *seat; - wl_list_for_each(seat, &server.input->seats, link) { - wlr_seat_set_keyboard(seat->wlr_seat, NULL); - } - - struct sway_input_device *input_device = NULL; - wl_list_for_each(input_device, &server.input->devices, link) { - input_manager_reset_input(input_device); - } - - // If there is at least one keyboard using the default keymap, repeat delay, - // and repeat rate, then it is possible that there is a keyboard group that - // need their keyboard disarmed. - wl_list_for_each(seat, &server.input->seats, link) { - struct sway_keyboard_group *group; - wl_list_for_each(group, &seat->keyboard_groups, link) { - sway_keyboard_disarm_key_repeat(group->seat_device->keyboard); - } - } -} - -void input_manager_apply_seat_config(struct seat_config *seat_config) { - sway_log(SWAY_DEBUG, "applying seat config for seat %s", seat_config->name); - if (strcmp(seat_config->name, "*") == 0) { - struct sway_seat *seat = NULL; - wl_list_for_each(seat, &server.input->seats, link) { - // Only apply the wildcard config directly if there is no seat - // specific config - struct seat_config *sc = seat_get_config(seat); - if (!sc) { - sc = seat_config; - } - seat_apply_config(seat, sc); - } - } else { - struct sway_seat *seat = - input_manager_get_seat(seat_config->name, true); - if (!seat) { - return; - } - seat_apply_config(seat, seat_config); - } - - // for every device, try to add it to a seat and if no seat has it - // attached, add it to the fallback seats. - struct sway_input_device *input_device = NULL; - wl_list_for_each(input_device, &server.input->devices, link) { - list_t *seat_list = create_list(); - struct sway_seat *seat = NULL; - wl_list_for_each(seat, &server.input->seats, link) { - struct seat_config *seat_config = seat_get_config(seat); - if (!seat_config) { - continue; - } - if (seat_config_get_attachment(seat_config, "*") || - seat_config_get_attachment(seat_config, - input_device->identifier)) { - list_add(seat_list, seat); - } - } - - if (seat_list->length) { - wl_list_for_each(seat, &server.input->seats, link) { - bool attached = false; - for (int i = 0; i < seat_list->length; ++i) { - if (seat == seat_list->items[i]) { - attached = true; - break; - } - } - if (attached) { - seat_add_device(seat, input_device); - } else { - seat_remove_device(seat, input_device); - } - } - } else { - wl_list_for_each(seat, &server.input->seats, link) { - struct seat_config *seat_config = seat_get_config(seat); - if (seat_config && seat_config->fallback == 1) { - seat_add_device(seat, input_device); - } else { - seat_remove_device(seat, input_device); - } - } - } - list_free(seat_list); - } -} - -void input_manager_configure_xcursor(void) { - struct sway_seat *seat = NULL; - wl_list_for_each(seat, &server.input->seats, link) { - seat_configure_xcursor(seat); - } -} - -struct input_config *input_device_get_config(struct sway_input_device *device) { - struct input_config *wildcard_config = NULL; - struct input_config *input_config = NULL; - for (int i = 0; i < config->input_configs->length; ++i) { - input_config = config->input_configs->items[i]; - if (strcmp(input_config->identifier, device->identifier) == 0) { - return input_config; - } else if (strcmp(input_config->identifier, "*") == 0) { - wildcard_config = input_config; - } - } - - const char *device_type = input_device_get_type(device); - for (int i = 0; i < config->input_type_configs->length; ++i) { - input_config = config->input_type_configs->items[i]; - if (strcmp(input_config->identifier + 5, device_type) == 0) { - return input_config; - } - } - - return wildcard_config; -} diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c deleted file mode 100644 index 8927287fb..000000000 --- a/sway/input/keyboard.c +++ /dev/null @@ -1,1099 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sway/commands.h" -#include "sway/input/input-manager.h" -#include "sway/input/keyboard.h" -#include "sway/input/seat.h" -#include "sway/input/cursor.h" -#include "sway/ipc-server.h" -#include "log.h" - -#if WLR_HAS_SESSION -#include -#endif - -static struct modifier_key { - char *name; - uint32_t mod; -} modifiers[] = { - { XKB_MOD_NAME_SHIFT, WLR_MODIFIER_SHIFT }, - { XKB_MOD_NAME_CAPS, WLR_MODIFIER_CAPS }, - { XKB_MOD_NAME_CTRL, WLR_MODIFIER_CTRL }, - { "Ctrl", WLR_MODIFIER_CTRL }, - { XKB_MOD_NAME_ALT, WLR_MODIFIER_ALT }, - { "Alt", WLR_MODIFIER_ALT }, - { XKB_MOD_NAME_NUM, WLR_MODIFIER_MOD2 }, - { "Mod3", WLR_MODIFIER_MOD3 }, - { XKB_MOD_NAME_LOGO, WLR_MODIFIER_LOGO }, - { "Mod5", WLR_MODIFIER_MOD5 }, -}; - -uint32_t get_modifier_mask_by_name(const char *name) { - int i; - for (i = 0; i < (int)(sizeof(modifiers) / sizeof(struct modifier_key)); ++i) { - if (strcasecmp(modifiers[i].name, name) == 0) { - return modifiers[i].mod; - } - } - - return 0; -} - -const char *get_modifier_name_by_mask(uint32_t modifier) { - int i; - for (i = 0; i < (int)(sizeof(modifiers) / sizeof(struct modifier_key)); ++i) { - if (modifiers[i].mod == modifier) { - return modifiers[i].name; - } - } - - return NULL; -} - -int get_modifier_names(const char **names, uint32_t modifier_masks) { - int length = 0; - int i; - for (i = 0; i < (int)(sizeof(modifiers) / sizeof(struct modifier_key)); ++i) { - if ((modifier_masks & modifiers[i].mod) != 0) { - names[length] = modifiers[i].name; - ++length; - modifier_masks ^= modifiers[i].mod; - } - } - - return length; -} - -/** - * Remove all key ids associated to a keycode from the list of pressed keys - */ -static bool state_erase_key(struct sway_shortcut_state *state, - uint32_t keycode) { - bool found = false; - size_t j = 0; - for (size_t i = 0; i < state->npressed; ++i) { - if (i > j) { - state->pressed_keys[j] = state->pressed_keys[i]; - state->pressed_keycodes[j] = state->pressed_keycodes[i]; - } - if (state->pressed_keycodes[i] != keycode) { - ++j; - } else { - found = true; - } - } - while(state->npressed > j) { - --state->npressed; - state->pressed_keys[state->npressed] = 0; - state->pressed_keycodes[state->npressed] = 0; - } - state->current_key = 0; - return found; -} - -/** - * Add a key id (with associated keycode) to the list of pressed keys, - * if the list is not full. - */ -static void state_add_key(struct sway_shortcut_state *state, - uint32_t keycode, uint32_t key_id) { - if (state->npressed >= SWAY_KEYBOARD_PRESSED_KEYS_CAP) { - return; - } - size_t i = 0; - while (i < state->npressed && state->pressed_keys[i] < key_id) { - ++i; - } - size_t j = state->npressed; - while (j > i) { - state->pressed_keys[j] = state->pressed_keys[j - 1]; - state->pressed_keycodes[j] = state->pressed_keycodes[j - 1]; - --j; - } - state->pressed_keys[i] = key_id; - state->pressed_keycodes[i] = keycode; - state->npressed++; - state->current_key = key_id; -} - -/** - * Update the shortcut model state in response to new input - */ -static bool update_shortcut_state(struct sway_shortcut_state *state, - uint32_t keycode, enum wl_keyboard_key_state keystate, uint32_t new_key, - uint32_t raw_modifiers) { - bool last_key_was_a_modifier = raw_modifiers != state->last_raw_modifiers; - state->last_raw_modifiers = raw_modifiers; - - if (last_key_was_a_modifier && state->last_keycode) { - // Last pressed key before this one was a modifier - state_erase_key(state, state->last_keycode); - } - - if (keystate == WL_KEYBOARD_KEY_STATE_PRESSED) { - // Add current key to set; there may be duplicates - state_add_key(state, keycode, new_key); - state->last_keycode = keycode; - } else { - return state_erase_key(state, keycode); - } - - return false; -} - -/** - * If one exists, finds a binding which matches the shortcut model state, - * current modifiers, release state, and locked state. - */ -static void get_active_binding(const struct sway_shortcut_state *state, - list_t *bindings, struct sway_binding **current_binding, - uint32_t modifiers, bool release, bool locked, bool inhibited, - const char *input, bool exact_input, xkb_layout_index_t group) { - for (int i = 0; i < bindings->length; ++i) { - struct sway_binding *binding = bindings->items[i]; - bool binding_locked = (binding->flags & BINDING_LOCKED) != 0; - bool binding_inhibited = (binding->flags & BINDING_INHIBITED) != 0; - bool binding_release = binding->flags & BINDING_RELEASE; - - if (modifiers ^ binding->modifiers || - release != binding_release || - locked > binding_locked || - inhibited > binding_inhibited || - (binding->group != XKB_LAYOUT_INVALID && - binding->group != group) || - (strcmp(binding->input, input) != 0 && - (strcmp(binding->input, "*") != 0 || exact_input))) { - continue; - } - - bool match = false; - if (state->npressed == (size_t)binding->keys->length) { - match = true; - for (size_t j = 0; j < state->npressed; j++) { - uint32_t key = *(uint32_t *)binding->keys->items[j]; - if (key != state->pressed_keys[j]) { - match = false; - break; - } - } - } else if (binding->keys->length == 1) { - /* - * If no multiple-key binding has matched, try looking for - * single-key bindings that match the newly-pressed key. - */ - match = state->current_key == *(uint32_t *)binding->keys->items[0]; - } - if (!match) { - continue; - } - - if (*current_binding) { - if (*current_binding == binding) { - continue; - } - - bool current_locked = - ((*current_binding)->flags & BINDING_LOCKED) != 0; - bool current_inhibited = - ((*current_binding)->flags & BINDING_INHIBITED) != 0; - bool current_input = strcmp((*current_binding)->input, input) == 0; - bool current_group_set = - (*current_binding)->group != XKB_LAYOUT_INVALID; - bool binding_input = strcmp(binding->input, input) == 0; - bool binding_group_set = binding->group != XKB_LAYOUT_INVALID; - - if (current_input == binding_input - && current_locked == binding_locked - && current_inhibited == binding_inhibited - && current_group_set == binding_group_set) { - sway_log(SWAY_DEBUG, - "Encountered conflicting bindings %d and %d", - (*current_binding)->order, binding->order); - continue; - } - - if (current_input && !binding_input) { - continue; // Prefer the correct input - } - - if (current_input == binding_input && - (*current_binding)->group == group) { - continue; // Prefer correct group for matching inputs - } - - if (current_input == binding_input && - current_group_set == binding_group_set && - current_locked == locked) { - continue; // Prefer correct lock state for matching input+group - } - - if (current_input == binding_input && - current_group_set == binding_group_set && - current_locked == binding_locked && - current_inhibited == inhibited) { - // Prefer correct inhibition state for matching - // input+group+locked - continue; - } - } - - *current_binding = binding; - if (strcmp((*current_binding)->input, input) == 0 && - (((*current_binding)->flags & BINDING_LOCKED) == locked) && - (((*current_binding)->flags & BINDING_INHIBITED) == inhibited) && - (*current_binding)->group == group) { - return; // If a perfect match is found, quit searching - } - } -} - -/** - * Execute a built-in, hardcoded compositor binding. These are triggered from a - * single keysym. - * - * Returns true if the keysym was handled by a binding and false if the event - * should be propagated to clients. - */ -static bool keyboard_execute_compositor_binding(struct sway_keyboard *keyboard, - const xkb_keysym_t *pressed_keysyms, uint32_t modifiers, size_t keysyms_len) { - for (size_t i = 0; i < keysyms_len; ++i) { - xkb_keysym_t keysym = pressed_keysyms[i]; - if (keysym >= XKB_KEY_XF86Switch_VT_1 && - keysym <= XKB_KEY_XF86Switch_VT_12) { -#if WLR_HAS_SESSION - if (server.session) { - unsigned vt = keysym - XKB_KEY_XF86Switch_VT_1 + 1; - wlr_session_change_vt(server.session, vt); - } -#endif - return true; - } - } - - return false; -} - -/** - * Get keysyms and modifiers from the keyboard as xkb sees them. - * - * This uses the xkb keysyms translation based on pressed modifiers and clears - * the consumed modifiers from the list of modifiers passed to keybind - * detection. - * - * On US layout, pressing Alt+Shift+2 will trigger Alt+@. - */ -static size_t keyboard_keysyms_translated(struct sway_keyboard *keyboard, - xkb_keycode_t keycode, const xkb_keysym_t **keysyms, - uint32_t *modifiers) { - *modifiers = wlr_keyboard_get_modifiers(keyboard->wlr); - xkb_mod_mask_t consumed = xkb_state_key_get_consumed_mods2( - keyboard->wlr->xkb_state, keycode, XKB_CONSUMED_MODE_XKB); - *modifiers = *modifiers & ~consumed; - - return xkb_state_key_get_syms(keyboard->wlr->xkb_state, - keycode, keysyms); -} - -/** - * Get keysyms and modifiers from the keyboard as if modifiers didn't change - * keysyms. - * - * This avoids the xkb keysym translation based on modifiers considered pressed - * in the state. - * - * This will trigger keybinds such as Alt+Shift+2. - */ -static size_t keyboard_keysyms_raw(struct sway_keyboard *keyboard, - xkb_keycode_t keycode, const xkb_keysym_t **keysyms, - uint32_t *modifiers) { - *modifiers = wlr_keyboard_get_modifiers(keyboard->wlr); - - xkb_layout_index_t layout_index = xkb_state_key_get_layout( - keyboard->wlr->xkb_state, keycode); - return xkb_keymap_key_get_syms_by_level(keyboard->wlr->keymap, - keycode, layout_index, 0, keysyms); -} - -void sway_keyboard_disarm_key_repeat(struct sway_keyboard *keyboard) { - if (!keyboard) { - return; - } - keyboard->repeat_binding = NULL; - if (wl_event_source_timer_update(keyboard->key_repeat_source, 0) < 0) { - sway_log(SWAY_DEBUG, "failed to disarm key repeat timer"); - } -} - -struct key_info { - uint32_t keycode; - uint32_t code_modifiers; - - const xkb_keysym_t *raw_keysyms; - uint32_t raw_modifiers; - size_t raw_keysyms_len; - - const xkb_keysym_t *translated_keysyms; - uint32_t translated_modifiers; - size_t translated_keysyms_len; -}; - -static void update_keyboard_state(struct sway_keyboard *keyboard, - uint32_t raw_keycode, enum wl_keyboard_key_state keystate, - struct key_info *keyinfo) { - // Identify new keycode, raw keysym(s), and translated keysym(s) - keyinfo->keycode = raw_keycode + 8; - - keyinfo->raw_keysyms_len = keyboard_keysyms_raw(keyboard, keyinfo->keycode, - &keyinfo->raw_keysyms, &keyinfo->raw_modifiers); - - keyinfo->translated_keysyms_len = keyboard_keysyms_translated(keyboard, - keyinfo->keycode, &keyinfo->translated_keysyms, - &keyinfo->translated_modifiers); - - keyinfo->code_modifiers = wlr_keyboard_get_modifiers(keyboard->wlr); - - // Update shortcut model keyinfo - update_shortcut_state(&keyboard->state_keycodes, raw_keycode, keystate, - keyinfo->keycode, keyinfo->code_modifiers); - for (size_t i = 0; i < keyinfo->raw_keysyms_len; ++i) { - update_shortcut_state(&keyboard->state_keysyms_raw, - raw_keycode, keystate, keyinfo->raw_keysyms[i], - keyinfo->code_modifiers); - } - for (size_t i = 0; i < keyinfo->translated_keysyms_len; ++i) { - update_shortcut_state(&keyboard->state_keysyms_translated, - raw_keycode, keystate, keyinfo->translated_keysyms[i], - keyinfo->code_modifiers); - } -} - -/** - * Get keyboard grab of the seat from sway_keyboard if we should forward events - * to it. - * - * Returns NULL if the keyboard is not grabbed by an input method, - * or if event is from virtual keyboard of the same client as grab. - * TODO: see swaywm/wlroots#2322 - */ -static struct wlr_input_method_keyboard_grab_v2 *keyboard_get_im_grab( - struct sway_keyboard *keyboard) { - struct wlr_input_method_v2 *input_method = keyboard->seat_device-> - sway_seat->im_relay.input_method; - struct wlr_virtual_keyboard_v1 *virtual_keyboard = - wlr_input_device_get_virtual_keyboard(keyboard->seat_device->input_device->wlr_device); - if (!input_method || !input_method->keyboard_grab || (virtual_keyboard && - wl_resource_get_client(virtual_keyboard->resource) == - wl_resource_get_client(input_method->keyboard_grab->resource))) { - return NULL; - } - return input_method->keyboard_grab; -} - -static void handle_key_event(struct sway_keyboard *keyboard, - struct wlr_keyboard_key_event *event) { - struct sway_seat *seat = keyboard->seat_device->sway_seat; - struct wlr_seat *wlr_seat = seat->wlr_seat; - struct wlr_input_device *wlr_device = - keyboard->seat_device->input_device->wlr_device; - char *device_identifier = input_device_get_identifier(wlr_device); - bool exact_identifier = keyboard->wlr->group != NULL; - seat_idle_notify_activity(seat, IDLE_SOURCE_KEYBOARD); - bool input_inhibited = seat->exclusive_client != NULL || - server.session_lock.locked; - struct sway_keyboard_shortcuts_inhibitor *sway_inhibitor = - keyboard_shortcuts_inhibitor_get_for_focused_surface(seat); - bool shortcuts_inhibited = sway_inhibitor && sway_inhibitor->inhibitor->active; - - if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { - cursor_notify_key_press(seat->cursor); - } - - // Identify new keycode, raw keysym(s), and translated keysym(s) - struct key_info keyinfo; - update_keyboard_state(keyboard, event->keycode, event->state, &keyinfo); - - bool handled = false; - // Identify active release binding - struct sway_binding *binding_released = NULL; - get_active_binding(&keyboard->state_keycodes, - config->current_mode->keycode_bindings, &binding_released, - keyinfo.code_modifiers, true, input_inhibited, - shortcuts_inhibited, device_identifier, - exact_identifier, keyboard->effective_layout); - get_active_binding(&keyboard->state_keysyms_raw, - config->current_mode->keysym_bindings, &binding_released, - keyinfo.raw_modifiers, true, input_inhibited, - shortcuts_inhibited, device_identifier, - exact_identifier, keyboard->effective_layout); - get_active_binding(&keyboard->state_keysyms_translated, - config->current_mode->keysym_bindings, &binding_released, - keyinfo.translated_modifiers, true, input_inhibited, - shortcuts_inhibited, device_identifier, - exact_identifier, keyboard->effective_layout); - - // Execute stored release binding once no longer active - if (keyboard->held_binding && binding_released != keyboard->held_binding && - event->state == WL_KEYBOARD_KEY_STATE_RELEASED) { - seat_execute_command(seat, keyboard->held_binding); - handled = true; - } - if (binding_released != keyboard->held_binding) { - keyboard->held_binding = NULL; - } - if (binding_released && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { - keyboard->held_binding = binding_released; - } - - // Identify and execute active pressed binding - struct sway_binding *binding = NULL; - if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { - get_active_binding(&keyboard->state_keycodes, - config->current_mode->keycode_bindings, &binding, - keyinfo.code_modifiers, false, input_inhibited, - shortcuts_inhibited, device_identifier, - exact_identifier, keyboard->effective_layout); - get_active_binding(&keyboard->state_keysyms_raw, - config->current_mode->keysym_bindings, &binding, - keyinfo.raw_modifiers, false, input_inhibited, - shortcuts_inhibited, device_identifier, - exact_identifier, keyboard->effective_layout); - get_active_binding(&keyboard->state_keysyms_translated, - config->current_mode->keysym_bindings, &binding, - keyinfo.translated_modifiers, false, input_inhibited, - shortcuts_inhibited, device_identifier, - exact_identifier, keyboard->effective_layout); - } - - // Set up (or clear) keyboard repeat for a pressed binding. Since the - // binding may remove the keyboard, the timer needs to be updated first - if (binding && !(binding->flags & BINDING_NOREPEAT) && - keyboard->wlr->repeat_info.delay > 0) { - keyboard->repeat_binding = binding; - if (wl_event_source_timer_update(keyboard->key_repeat_source, - keyboard->wlr->repeat_info.delay) < 0) { - sway_log(SWAY_DEBUG, "failed to set key repeat timer"); - } - } else if (keyboard->repeat_binding) { - sway_keyboard_disarm_key_repeat(keyboard); - } - - if (binding) { - seat_execute_command(seat, binding); - handled = true; - } - - if (!handled && keyboard->wlr->group) { - // Only handle device specific bindings for keyboards in a group - free(device_identifier); - return; - } - - // Compositor bindings - if (!handled && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { - handled = keyboard_execute_compositor_binding( - keyboard, keyinfo.translated_keysyms, - keyinfo.translated_modifiers, keyinfo.translated_keysyms_len); - } - if (!handled && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { - handled = keyboard_execute_compositor_binding( - keyboard, keyinfo.raw_keysyms, keyinfo.raw_modifiers, - keyinfo.raw_keysyms_len); - } - - if (event->state == WL_KEYBOARD_KEY_STATE_RELEASED) { - // If the pressed event was sent to a client, also send the released - // event. In particular, don't send the released event to the IM grab. - bool pressed_sent = update_shortcut_state( - &keyboard->state_pressed_sent, event->keycode, - event->state, keyinfo.keycode, 0); - if (pressed_sent) { - wlr_seat_set_keyboard(wlr_seat, keyboard->wlr); - wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, - event->keycode, event->state); - handled = true; - } - } - - if (!handled) { - struct wlr_input_method_keyboard_grab_v2 *kb_grab = keyboard_get_im_grab(keyboard); - - if (kb_grab) { - wlr_input_method_keyboard_grab_v2_set_keyboard(kb_grab, keyboard->wlr); - wlr_input_method_keyboard_grab_v2_send_key(kb_grab, - event->time_msec, event->keycode, event->state); - handled = true; - } - } - - if (!handled && event->state != WL_KEYBOARD_KEY_STATE_RELEASED) { - // If a released event failed pressed sent test, and not in sent to - // keyboard grab, it is still not handled. Don't handle released here. - update_shortcut_state( - &keyboard->state_pressed_sent, event->keycode, event->state, - keyinfo.keycode, 0); - wlr_seat_set_keyboard(wlr_seat, keyboard->wlr); - wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, - event->keycode, event->state); - } - - free(device_identifier); -} - -static void handle_keyboard_key(struct wl_listener *listener, void *data) { - struct sway_keyboard *keyboard = - wl_container_of(listener, keyboard, keyboard_key); - handle_key_event(keyboard, data); -} - -static void handle_keyboard_group_key(struct wl_listener *listener, - void *data) { - struct sway_keyboard_group *sway_group = - wl_container_of(listener, sway_group, keyboard_key); - handle_key_event(sway_group->seat_device->keyboard, data); -} - -static void handle_keyboard_group_enter(struct wl_listener *listener, - void *data) { - struct sway_keyboard_group *sway_group = - wl_container_of(listener, sway_group, enter); - struct sway_keyboard *keyboard = sway_group->seat_device->keyboard; - struct wl_array *keycodes = data; - - uint32_t *keycode; - wl_array_for_each(keycode, keycodes) { - struct key_info keyinfo; - update_keyboard_state(keyboard, *keycode, WL_KEYBOARD_KEY_STATE_PRESSED, &keyinfo); - } -} - -static void handle_keyboard_group_leave(struct wl_listener *listener, - void *data) { - struct sway_keyboard_group *sway_group = - wl_container_of(listener, sway_group, leave); - struct sway_keyboard *keyboard = sway_group->seat_device->keyboard; - struct wl_array *keycodes = data; - - bool pressed_sent = false; - - uint32_t *keycode; - wl_array_for_each(keycode, keycodes) { - struct key_info keyinfo; - update_keyboard_state(keyboard, *keycode, WL_KEYBOARD_KEY_STATE_RELEASED, &keyinfo); - - pressed_sent |= update_shortcut_state(&keyboard->state_pressed_sent, - *keycode, WL_KEYBOARD_KEY_STATE_RELEASED, keyinfo.keycode, 0); - } - - if (!pressed_sent) { - return; - } - - // Refocus the focused node, layer surface, or unmanaged surface so that - // it picks up the current keyboard state. - struct sway_seat *seat = keyboard->seat_device->sway_seat; - struct sway_node *focus = seat_get_focus(seat); - if (focus) { - seat_set_focus(seat, NULL); - seat_set_focus(seat, focus); - } else if (seat->focused_layer) { - struct wlr_layer_surface_v1 *layer = seat->focused_layer; - seat_set_focus_layer(seat, NULL); - seat_set_focus_layer(seat, layer); - } else { - struct wlr_surface *unmanaged = seat->wlr_seat->keyboard_state.focused_surface; - seat_set_focus_surface(seat, NULL, false); - seat_set_focus_surface(seat, unmanaged, false); - } -} - -static int handle_keyboard_repeat(void *data) { - struct sway_keyboard *keyboard = data; - if (keyboard->repeat_binding) { - if (keyboard->wlr->repeat_info.rate > 0) { - // We queue the next event first, as the command might cancel it - if (wl_event_source_timer_update(keyboard->key_repeat_source, - 1000 / keyboard->wlr->repeat_info.rate) < 0) { - sway_log(SWAY_DEBUG, "failed to update key repeat timer"); - } - } - - seat_execute_command(keyboard->seat_device->sway_seat, - keyboard->repeat_binding); - } - return 0; -} - -static void determine_bar_visibility(uint32_t modifiers) { - for (int i = 0; i < config->bars->length; ++i) { - struct bar_config *bar = config->bars->items[i]; - if (bar->modifier == 0) { - continue; - } - - bool vis_by_mod = (~modifiers & bar->modifier) == 0; - if (bar->visible_by_modifier != vis_by_mod) { - // If visible by modifier is set, send that it is no longer visible - // by modifier (regardless of bar mode and state). Otherwise, only - // send the visible by modifier status if mode and state are hide - if (bar->visible_by_modifier - || strcmp(bar->mode, bar->hidden_state) == 0) { - bar->visible_by_modifier = vis_by_mod; - ipc_event_bar_state_update(bar); - } - } - } -} - -static void handle_modifier_event(struct sway_keyboard *keyboard) { - if (!keyboard->wlr->group) { - struct wlr_input_method_keyboard_grab_v2 *kb_grab = keyboard_get_im_grab(keyboard); - - if (kb_grab) { - wlr_input_method_keyboard_grab_v2_set_keyboard(kb_grab, keyboard->wlr); - wlr_input_method_keyboard_grab_v2_send_modifiers(kb_grab, - &keyboard->wlr->modifiers); - } else { - struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat; - wlr_seat_set_keyboard(wlr_seat, keyboard->wlr); - wlr_seat_keyboard_notify_modifiers(wlr_seat, - &keyboard->wlr->modifiers); - } - - uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->wlr); - determine_bar_visibility(modifiers); - } - - if (keyboard->wlr->modifiers.group != keyboard->effective_layout) { - keyboard->effective_layout = keyboard->wlr->modifiers.group; - - if (!wlr_keyboard_group_from_wlr_keyboard(keyboard->wlr)) { - ipc_event_input("xkb_layout", keyboard->seat_device->input_device); - } - } -} - -static void handle_keyboard_modifiers(struct wl_listener *listener, - void *data) { - struct sway_keyboard *keyboard = - wl_container_of(listener, keyboard, keyboard_modifiers); - handle_modifier_event(keyboard); -} - -static void handle_keyboard_group_modifiers(struct wl_listener *listener, - void *data) { - struct sway_keyboard_group *group = - wl_container_of(listener, group, keyboard_modifiers); - handle_modifier_event(group->seat_device->keyboard); -} - -struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, - struct sway_seat_device *device) { - struct sway_keyboard *keyboard = - calloc(1, sizeof(struct sway_keyboard)); - if (!sway_assert(keyboard, "could not allocate sway keyboard")) { - return NULL; - } - - keyboard->seat_device = device; - keyboard->wlr = wlr_keyboard_from_input_device(device->input_device->wlr_device); - device->keyboard = keyboard; - - wl_list_init(&keyboard->keyboard_key.link); - wl_list_init(&keyboard->keyboard_modifiers.link); - - keyboard->key_repeat_source = wl_event_loop_add_timer(server.wl_event_loop, - handle_keyboard_repeat, keyboard); - - return keyboard; -} - -static void handle_xkb_context_log(struct xkb_context *context, - enum xkb_log_level level, const char *format, va_list args) { - char *error = vformat_str(format, args); - - size_t len = strlen(error); - if (error[len - 1] == '\n') { - error[len - 1] = '\0'; - } - - sway_log_importance_t importance = SWAY_DEBUG; - if (level <= XKB_LOG_LEVEL_ERROR) { // Critical and Error - importance = SWAY_ERROR; - } else if (level <= XKB_LOG_LEVEL_INFO) { // Warning and Info - importance = SWAY_INFO; - } - sway_log(importance, "[xkbcommon] %s", error); - - char **data = xkb_context_get_user_data(context); - if (importance == SWAY_ERROR && data && !*data) { - *data = error; - } else { - free(error); - } -} - -struct xkb_keymap *sway_keyboard_compile_keymap(struct input_config *ic, - char **error) { - struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_SECURE_GETENV); - if (!sway_assert(context, "cannot create XKB context")) { - return NULL; - } - xkb_context_set_user_data(context, error); - xkb_context_set_log_fn(context, handle_xkb_context_log); - - struct xkb_keymap *keymap = NULL; - - if (ic && ic->xkb_file) { - FILE *keymap_file = fopen(ic->xkb_file, "r"); - if (!keymap_file) { - sway_log_errno(SWAY_ERROR, "cannot read xkb file %s", ic->xkb_file); - if (error) { - *error = format_str("cannot read xkb file %s: %s", - ic->xkb_file, strerror(errno)); - } - goto cleanup; - } - - keymap = xkb_keymap_new_from_file(context, keymap_file, - XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); - - if (fclose(keymap_file) != 0) { - sway_log_errno(SWAY_ERROR, "Failed to close xkb file %s", - ic->xkb_file); - } - } else { - struct xkb_rule_names rules = {0}; - if (ic) { - input_config_fill_rule_names(ic, &rules); - } - keymap = xkb_keymap_new_from_names(context, &rules, - XKB_KEYMAP_COMPILE_NO_FLAGS); - } - -cleanup: - xkb_context_set_user_data(context, NULL); - xkb_context_unref(context); - return keymap; -} - -static bool repeat_info_match(struct sway_keyboard *a, struct wlr_keyboard *b) { - return a->repeat_rate == b->repeat_info.rate && - a->repeat_delay == b->repeat_info.delay; -} - -static void destroy_empty_wlr_keyboard_group(void *data) { - wlr_keyboard_group_destroy(data); -} - -static void sway_keyboard_group_remove(struct sway_keyboard *keyboard) { - struct sway_input_device *device = keyboard->seat_device->input_device; - struct wlr_keyboard_group *wlr_group = keyboard->wlr->group; - - sway_log(SWAY_DEBUG, "Removing keyboard %s from group %p", - device->identifier, wlr_group); - - wlr_keyboard_group_remove_keyboard(keyboard->wlr->group, keyboard->wlr); - - if (wl_list_empty(&wlr_group->devices)) { - sway_log(SWAY_DEBUG, "Destroying empty keyboard group %p", - wlr_group); - struct sway_keyboard_group *sway_group = wlr_group->data; - wlr_group->data = NULL; - wl_list_remove(&sway_group->link); - wl_list_remove(&sway_group->keyboard_key.link); - wl_list_remove(&sway_group->keyboard_modifiers.link); - wl_list_remove(&sway_group->enter.link); - wl_list_remove(&sway_group->leave.link); - sway_keyboard_destroy(sway_group->seat_device->keyboard); - free(sway_group->seat_device->input_device); - free(sway_group->seat_device); - free(sway_group); - - // To prevent use-after-free conditions when handling key events, defer - // freeing the wlr_keyboard_group until idle - wl_event_loop_add_idle(server.wl_event_loop, - destroy_empty_wlr_keyboard_group, wlr_group); - } -} - -static void sway_keyboard_group_remove_invalid(struct sway_keyboard *keyboard) { - if (!keyboard->wlr->group) { - return; - } - - struct sway_seat *seat = keyboard->seat_device->sway_seat; - struct seat_config *sc = seat_get_config(seat); - if (!sc) { - sc = seat_get_config_by_name("*"); - } - - switch (sc ? sc->keyboard_grouping : KEYBOARD_GROUP_DEFAULT) { - case KEYBOARD_GROUP_NONE: - sway_keyboard_group_remove(keyboard); - break; - case KEYBOARD_GROUP_DEFAULT: /* fallthrough */ - case KEYBOARD_GROUP_SMART:; - struct wlr_keyboard_group *group = keyboard->wlr->group; - if (!wlr_keyboard_keymaps_match(keyboard->keymap, group->keyboard.keymap) || - !repeat_info_match(keyboard, &group->keyboard)) { - sway_keyboard_group_remove(keyboard); - } - break; - } -} - -static void sway_keyboard_group_add(struct sway_keyboard *keyboard) { - struct sway_input_device *device = keyboard->seat_device->input_device; - struct sway_seat *seat = keyboard->seat_device->sway_seat; - struct seat_config *sc = seat_get_config(seat); - - if (device->is_virtual) { - // Virtual devices should not be grouped - return; - } - - if (!sc) { - sc = seat_get_config_by_name("*"); - } - - if (sc && sc->keyboard_grouping == KEYBOARD_GROUP_NONE) { - // Keyboard grouping is disabled for the seat - return; - } - - struct sway_keyboard_group *group; - wl_list_for_each(group, &seat->keyboard_groups, link) { - switch (sc ? sc->keyboard_grouping : KEYBOARD_GROUP_DEFAULT) { - case KEYBOARD_GROUP_NONE: - // Nothing to do. This shouldn't even be reached - return; - case KEYBOARD_GROUP_DEFAULT: /* fallthrough */ - case KEYBOARD_GROUP_SMART:; - struct wlr_keyboard_group *wlr_group = group->wlr_group; - if (wlr_keyboard_keymaps_match(keyboard->keymap, - wlr_group->keyboard.keymap) && - repeat_info_match(keyboard, &wlr_group->keyboard)) { - sway_log(SWAY_DEBUG, "Adding keyboard %s to group %p", - device->identifier, wlr_group); - wlr_keyboard_group_add_keyboard(wlr_group, keyboard->wlr); - return; - } - break; - } - } - - struct sway_keyboard_group *sway_group = - calloc(1, sizeof(struct sway_keyboard_group)); - if (!sway_group) { - sway_log(SWAY_ERROR, "Failed to allocate sway_keyboard_group"); - return; - } - - sway_group->wlr_group = wlr_keyboard_group_create(); - if (!sway_group->wlr_group) { - sway_log(SWAY_ERROR, "Failed to create keyboard group"); - goto cleanup; - } - sway_group->wlr_group->data = sway_group; - wlr_keyboard_set_keymap(&sway_group->wlr_group->keyboard, keyboard->keymap); - wlr_keyboard_set_repeat_info(&sway_group->wlr_group->keyboard, - keyboard->repeat_rate, keyboard->repeat_delay); - sway_log(SWAY_DEBUG, "Created keyboard group %p", sway_group->wlr_group); - - sway_group->seat_device = calloc(1, sizeof(struct sway_seat_device)); - if (!sway_group->seat_device) { - sway_log(SWAY_ERROR, "Failed to allocate sway_seat_device for group"); - goto cleanup; - } - sway_group->seat_device->sway_seat = seat; - - sway_group->seat_device->input_device = - calloc(1, sizeof(struct sway_input_device)); - if (!sway_group->seat_device->input_device) { - sway_log(SWAY_ERROR, "Failed to allocate sway_input_device for group"); - goto cleanup; - } - sway_group->seat_device->input_device->wlr_device = - &sway_group->wlr_group->keyboard.base; - - if (!sway_keyboard_create(seat, sway_group->seat_device)) { - sway_log(SWAY_ERROR, "Failed to allocate sway_keyboard for group"); - goto cleanup; - } - - sway_log(SWAY_DEBUG, "Adding keyboard %s to group %p", - device->identifier, sway_group->wlr_group); - wlr_keyboard_group_add_keyboard(sway_group->wlr_group, keyboard->wlr); - - wl_list_insert(&seat->keyboard_groups, &sway_group->link); - - wl_signal_add(&sway_group->wlr_group->keyboard.events.key, - &sway_group->keyboard_key); - sway_group->keyboard_key.notify = handle_keyboard_group_key; - - wl_signal_add(&sway_group->wlr_group->keyboard.events.modifiers, - &sway_group->keyboard_modifiers); - sway_group->keyboard_modifiers.notify = handle_keyboard_group_modifiers; - - wl_signal_add(&sway_group->wlr_group->events.enter, &sway_group->enter); - sway_group->enter.notify = handle_keyboard_group_enter; - - wl_signal_add(&sway_group->wlr_group->events.leave, &sway_group->leave); - sway_group->leave.notify = handle_keyboard_group_leave; - return; - -cleanup: - if (sway_group && sway_group->wlr_group) { - wlr_keyboard_group_destroy(sway_group->wlr_group); - } - free(sway_group->seat_device->keyboard); - free(sway_group->seat_device->input_device); - free(sway_group->seat_device); - free(sway_group); -} - -void sway_keyboard_configure(struct sway_keyboard *keyboard) { - struct input_config *input_config = - input_device_get_config(keyboard->seat_device->input_device); - - if (!sway_assert(!wlr_keyboard_group_from_wlr_keyboard(keyboard->wlr), - "sway_keyboard_configure should not be called with a " - "keyboard group's keyboard")) { - return; - } - - struct xkb_keymap *keymap = sway_keyboard_compile_keymap(input_config, NULL); - if (!keymap) { - sway_log(SWAY_ERROR, "Failed to compile keymap. Attempting defaults"); - keymap = sway_keyboard_compile_keymap(NULL, NULL); - if (!keymap) { - sway_log(SWAY_ERROR, - "Failed to compile default keymap. Aborting configure"); - return; - } - } - - bool keymap_changed = keyboard->keymap ? - !wlr_keyboard_keymaps_match(keyboard->keymap, keymap) : true; - bool effective_layout_changed = keyboard->effective_layout != 0; - - int repeat_rate = 25; - if (input_config && input_config->repeat_rate != INT_MIN) { - repeat_rate = input_config->repeat_rate; - } - int repeat_delay = 600; - if (input_config && input_config->repeat_delay != INT_MIN) { - repeat_delay = input_config->repeat_delay; - } - - bool repeat_info_changed = keyboard->repeat_rate != repeat_rate || - keyboard->repeat_delay != repeat_delay; - - if (keymap_changed || repeat_info_changed || config->reloading) { - xkb_keymap_unref(keyboard->keymap); - keyboard->keymap = keymap; - keyboard->effective_layout = 0; - keyboard->repeat_rate = repeat_rate; - keyboard->repeat_delay = repeat_delay; - - sway_keyboard_group_remove_invalid(keyboard); - - wlr_keyboard_set_keymap(keyboard->wlr, keyboard->keymap); - wlr_keyboard_set_repeat_info(keyboard->wlr, - keyboard->repeat_rate, keyboard->repeat_delay); - - if (!keyboard->wlr->group) { - sway_keyboard_group_add(keyboard); - } - - xkb_mod_mask_t locked_mods = 0; - if (input_config && input_config->xkb_numlock > 0) { - xkb_mod_index_t mod_index = xkb_map_mod_get_index(keymap, - XKB_MOD_NAME_NUM); - if (mod_index != XKB_MOD_INVALID) { - locked_mods |= (uint32_t)1 << mod_index; - } - } - if (input_config && input_config->xkb_capslock > 0) { - xkb_mod_index_t mod_index = xkb_map_mod_get_index(keymap, - XKB_MOD_NAME_CAPS); - if (mod_index != XKB_MOD_INVALID) { - locked_mods |= (uint32_t)1 << mod_index; - } - } - if (locked_mods) { - wlr_keyboard_notify_modifiers(keyboard->wlr, 0, 0, - locked_mods, 0); - uint32_t leds = 0; - for (uint32_t i = 0; i < WLR_LED_COUNT; ++i) { - if (xkb_state_led_index_is_active(keyboard->wlr->xkb_state, - keyboard->wlr->led_indexes[i])) { - leds |= (1 << i); - } - } - if (keyboard->wlr->group) { - wlr_keyboard_led_update(&keyboard->wlr->group->keyboard, leds); - } else { - wlr_keyboard_led_update(keyboard->wlr, leds); - } - } - } else { - xkb_keymap_unref(keymap); - sway_keyboard_group_remove_invalid(keyboard); - if (!keyboard->wlr->group) { - sway_keyboard_group_add(keyboard); - } - } - - // If the seat has no active keyboard, set this one - struct wlr_seat *seat = keyboard->seat_device->sway_seat->wlr_seat; - struct wlr_keyboard *current_keyboard = seat->keyboard_state.keyboard; - if (current_keyboard == NULL) { - wlr_seat_set_keyboard(seat, keyboard->wlr); - } - - wl_list_remove(&keyboard->keyboard_key.link); - wl_signal_add(&keyboard->wlr->events.key, &keyboard->keyboard_key); - keyboard->keyboard_key.notify = handle_keyboard_key; - - wl_list_remove(&keyboard->keyboard_modifiers.link); - wl_signal_add(&keyboard->wlr->events.modifiers, - &keyboard->keyboard_modifiers); - keyboard->keyboard_modifiers.notify = handle_keyboard_modifiers; - - if (keymap_changed) { - ipc_event_input("xkb_keymap", - keyboard->seat_device->input_device); - } else if (effective_layout_changed) { - ipc_event_input("xkb_layout", - keyboard->seat_device->input_device); - } -} - -void sway_keyboard_destroy(struct sway_keyboard *keyboard) { - if (!keyboard) { - return; - } - if (keyboard->wlr->group) { - sway_keyboard_group_remove(keyboard); - } - struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat; - if (wlr_seat_get_keyboard(wlr_seat) == keyboard->wlr) { - wlr_seat_set_keyboard(wlr_seat, NULL); - } - if (keyboard->keymap) { - xkb_keymap_unref(keyboard->keymap); - } - wl_list_remove(&keyboard->keyboard_key.link); - wl_list_remove(&keyboard->keyboard_modifiers.link); - sway_keyboard_disarm_key_repeat(keyboard); - wl_event_source_remove(keyboard->key_repeat_source); - free(keyboard); -} diff --git a/sway/input/libinput.c b/sway/input/libinput.c deleted file mode 100644 index 0266c7a93..000000000 --- a/sway/input/libinput.c +++ /dev/null @@ -1,406 +0,0 @@ -#include -#include -#include -#include -#include -#include "log.h" -#include "sway/config.h" -#include "sway/output.h" -#include "sway/input/input-manager.h" -#include "sway/ipc-server.h" - -static void log_status(enum libinput_config_status status) { - if (status != LIBINPUT_CONFIG_STATUS_SUCCESS) { - sway_log(SWAY_ERROR, "Failed to apply libinput config: %s", - libinput_config_status_to_str(status)); - } -} - -static bool set_send_events(struct libinput_device *device, uint32_t mode) { - if (libinput_device_config_send_events_get_mode(device) == mode) { - return false; - } - sway_log(SWAY_DEBUG, "send_events_set_mode(%" PRIu32 ")", mode); - log_status(libinput_device_config_send_events_set_mode(device, mode)); - return true; -} - -static bool set_tap(struct libinput_device *device, - enum libinput_config_tap_state tap) { - if (libinput_device_config_tap_get_finger_count(device) <= 0 || - libinput_device_config_tap_get_enabled(device) == tap) { - return false; - } - sway_log(SWAY_DEBUG, "tap_set_enabled(%d)", tap); - log_status(libinput_device_config_tap_set_enabled(device, tap)); - return true; -} - -static bool set_tap_button_map(struct libinput_device *device, - enum libinput_config_tap_button_map map) { - if (libinput_device_config_tap_get_finger_count(device) <= 0 || - libinput_device_config_tap_get_button_map(device) == map) { - return false; - } - sway_log(SWAY_DEBUG, "tap_set_button_map(%d)", map); - log_status(libinput_device_config_tap_set_button_map(device, map)); - return true; -} - -static bool set_tap_drag(struct libinput_device *device, - enum libinput_config_drag_state drag) { - if (libinput_device_config_tap_get_finger_count(device) <= 0 || - libinput_device_config_tap_get_drag_enabled(device) == drag) { - return false; - } - sway_log(SWAY_DEBUG, "tap_set_drag_enabled(%d)", drag); - log_status(libinput_device_config_tap_set_drag_enabled(device, drag)); - return true; -} - -static bool set_tap_drag_lock(struct libinput_device *device, - enum libinput_config_drag_lock_state lock) { - if (libinput_device_config_tap_get_finger_count(device) <= 0 || - libinput_device_config_tap_get_drag_lock_enabled(device) == lock) { - return false; - } - sway_log(SWAY_DEBUG, "tap_set_drag_lock_enabled(%d)", lock); - log_status(libinput_device_config_tap_set_drag_lock_enabled(device, lock)); - return true; -} - -static bool set_accel_speed(struct libinput_device *device, double speed) { - if (!libinput_device_config_accel_is_available(device) || - libinput_device_config_accel_get_speed(device) == speed) { - return false; - } - sway_log(SWAY_DEBUG, "accel_set_speed(%f)", speed); - log_status(libinput_device_config_accel_set_speed(device, speed)); - return true; -} - -static bool set_rotation_angle(struct libinput_device *device, double angle) { - if (!libinput_device_config_rotation_is_available(device) || - libinput_device_config_rotation_get_angle(device) == angle) { - return false; - } - sway_log(SWAY_DEBUG, "rotation_set_angle(%f)", angle); - log_status(libinput_device_config_rotation_set_angle(device, angle)); - return true; -} - -static bool set_accel_profile(struct libinput_device *device, - enum libinput_config_accel_profile profile) { - if (!libinput_device_config_accel_is_available(device) || - libinput_device_config_accel_get_profile(device) == profile) { - return false; - } - sway_log(SWAY_DEBUG, "accel_set_profile(%d)", profile); - log_status(libinput_device_config_accel_set_profile(device, profile)); - return true; -} - -static bool set_natural_scroll(struct libinput_device *d, bool n) { - if (!libinput_device_config_scroll_has_natural_scroll(d) || - libinput_device_config_scroll_get_natural_scroll_enabled(d) == n) { - return false; - } - sway_log(SWAY_DEBUG, "scroll_set_natural_scroll(%d)", n); - log_status(libinput_device_config_scroll_set_natural_scroll_enabled(d, n)); - return true; -} - -static bool set_left_handed(struct libinput_device *device, bool left) { - if (!libinput_device_config_left_handed_is_available(device) || - libinput_device_config_left_handed_get(device) == left) { - return false; - } - sway_log(SWAY_DEBUG, "left_handed_set(%d)", left); - log_status(libinput_device_config_left_handed_set(device, left)); - return true; -} - -static bool set_click_method(struct libinput_device *device, - enum libinput_config_click_method method) { - uint32_t click = libinput_device_config_click_get_methods(device); - if ((click & ~LIBINPUT_CONFIG_CLICK_METHOD_NONE) == 0 || - libinput_device_config_click_get_method(device) == method) { - return false; - } - sway_log(SWAY_DEBUG, "click_set_method(%d)", method); - log_status(libinput_device_config_click_set_method(device, method)); - return true; -} - -static bool set_middle_emulation(struct libinput_device *dev, - enum libinput_config_middle_emulation_state mid) { - if (!libinput_device_config_middle_emulation_is_available(dev) || - libinput_device_config_middle_emulation_get_enabled(dev) == mid) { - return false; - } - sway_log(SWAY_DEBUG, "middle_emulation_set_enabled(%d)", mid); - log_status(libinput_device_config_middle_emulation_set_enabled(dev, mid)); - return true; -} - -static bool set_scroll_method(struct libinput_device *device, - enum libinput_config_scroll_method method) { - uint32_t scroll = libinput_device_config_scroll_get_methods(device); - if ((scroll & ~LIBINPUT_CONFIG_SCROLL_NO_SCROLL) == 0 || - libinput_device_config_scroll_get_method(device) == method) { - return false; - } - sway_log(SWAY_DEBUG, "scroll_set_method(%d)", method); - log_status(libinput_device_config_scroll_set_method(device, method)); - return true; -} - -static bool set_scroll_button(struct libinput_device *dev, uint32_t button) { - uint32_t scroll = libinput_device_config_scroll_get_methods(dev); - if ((scroll & ~LIBINPUT_CONFIG_SCROLL_NO_SCROLL) == 0 || - libinput_device_config_scroll_get_button(dev) == button) { - return false; - } - sway_log(SWAY_DEBUG, "scroll_set_button(%" PRIu32 ")", button); - log_status(libinput_device_config_scroll_set_button(dev, button)); - return true; -} - -static bool set_scroll_button_lock(struct libinput_device *dev, - enum libinput_config_scroll_button_lock_state lock) { - uint32_t scroll = libinput_device_config_scroll_get_methods(dev); - if ((scroll & ~LIBINPUT_CONFIG_SCROLL_NO_SCROLL) == 0 || - libinput_device_config_scroll_get_button_lock(dev) == lock) { - return false; - } - sway_log(SWAY_DEBUG, "scroll_set_button_lock(%" PRIu32 ")", lock); - log_status(libinput_device_config_scroll_set_button_lock(dev, lock)); - return true; -} - -static bool set_dwt(struct libinput_device *device, bool dwt) { - if (!libinput_device_config_dwt_is_available(device) || - libinput_device_config_dwt_get_enabled(device) == dwt) { - return false; - } - sway_log(SWAY_DEBUG, "dwt_set_enabled(%d)", dwt); - log_status(libinput_device_config_dwt_set_enabled(device, dwt)); - return true; -} - -static bool set_dwtp(struct libinput_device *device, bool dwtp) { - if (!libinput_device_config_dwtp_is_available(device) || - libinput_device_config_dwtp_get_enabled(device) == dwtp) { - return false; - } - sway_log(SWAY_DEBUG, "dwtp_set_enabled(%d)", dwtp); - log_status(libinput_device_config_dwtp_set_enabled(device, dwtp)); - return true; -} - -static bool set_calibration_matrix(struct libinput_device *dev, float mat[6]) { - if (!libinput_device_config_calibration_has_matrix(dev)) { - return false; - } - bool changed = false; - float current[6]; - libinput_device_config_calibration_get_matrix(dev, current); - for (int i = 0; i < 6; i++) { - if (current[i] != mat[i]) { - changed = true; - break; - } - } - if (changed) { - sway_log(SWAY_DEBUG, "calibration_set_matrix(%f, %f, %f, %f, %f, %f)", - mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); - log_status(libinput_device_config_calibration_set_matrix(dev, mat)); - } - return changed; -} - -static bool configure_send_events(struct libinput_device *device, - struct input_config *ic) { - if (ic->mapped_to_output && - strcmp("*", ic->mapped_to_output) != 0 && - !output_by_name_or_id(ic->mapped_to_output)) { - sway_log(SWAY_DEBUG, - "%s '%s' is mapped to offline output '%s'; disabling input", - ic->input_type, ic->identifier, ic->mapped_to_output); - return set_send_events(device, LIBINPUT_CONFIG_SEND_EVENTS_DISABLED); - } else if (ic->send_events != INT_MIN) { - return set_send_events(device, ic->send_events); - } else { - // Have to reset to the default mode here, otherwise if ic->send_events - // is unset and a mapped output just came online after being disabled, - // we'd remain stuck sending no events. - return set_send_events(device, - libinput_device_config_send_events_get_default_mode(device)); - } -} - -bool sway_input_configure_libinput_device(struct sway_input_device *input_device) { - struct input_config *ic = input_device_get_config(input_device); - if (!ic || !wlr_input_device_is_libinput(input_device->wlr_device)) { - return false; - } - - struct libinput_device *device = - wlr_libinput_get_device_handle(input_device->wlr_device); - sway_log(SWAY_DEBUG, "sway_input_configure_libinput_device('%s' on '%s')", - ic->identifier, input_device->identifier); - - bool changed = configure_send_events(device, ic); - if (ic->tap != INT_MIN) { - changed |= set_tap(device, ic->tap); - } - if (ic->tap_button_map != INT_MIN) { - changed |= set_tap_button_map(device, ic->tap_button_map); - } - if (ic->drag != INT_MIN) { - changed |= set_tap_drag(device, ic->drag); - } - if (ic->drag_lock != INT_MIN) { - changed |= set_tap_drag_lock(device, ic->drag_lock); - } - if (ic->pointer_accel != FLT_MIN) { - changed |= set_accel_speed(device, ic->pointer_accel); - } - if (ic->rotation_angle != FLT_MIN) { - changed |= set_rotation_angle(device, ic->rotation_angle); - } - if (ic->accel_profile != INT_MIN) { - changed |= set_accel_profile(device, ic->accel_profile); - } - if (ic->natural_scroll != INT_MIN) { - changed |= set_natural_scroll(device, ic->natural_scroll); - } - if (ic->left_handed != INT_MIN) { - changed |= set_left_handed(device, ic->left_handed); - } - if (ic->click_method != INT_MIN) { - changed |= set_click_method(device, ic->click_method); - } - if (ic->middle_emulation != INT_MIN) { - changed |= set_middle_emulation(device, ic->middle_emulation); - } - if (ic->scroll_method != INT_MIN) { - changed |= set_scroll_method(device, ic->scroll_method); - } - if (ic->scroll_button != INT_MIN) { - changed |= set_scroll_button(device, ic->scroll_button); - } - if (ic->scroll_button_lock != INT_MIN) { - changed |= set_scroll_button_lock(device, ic->scroll_button_lock); - } - if (ic->dwt != INT_MIN) { - changed |= set_dwt(device, ic->dwt); - } - if (ic->dwtp != INT_MIN) { - changed |= set_dwtp(device, ic->dwtp); - } - if (ic->calibration_matrix.configured) { - changed |= set_calibration_matrix(device, ic->calibration_matrix.matrix); - } - - return changed; -} - -void sway_input_configure_libinput_device_send_events( - struct sway_input_device *input_device) { - struct input_config *ic = input_device_get_config(input_device); - if (!ic || !wlr_input_device_is_libinput(input_device->wlr_device)) { - return; - } - - struct libinput_device *device = - wlr_libinput_get_device_handle(input_device->wlr_device); - bool changed = configure_send_events(device, ic); - - if (changed) { - ipc_event_input("libinput_config", input_device); - } -} - -void sway_input_reset_libinput_device(struct sway_input_device *input_device) { - if (!wlr_input_device_is_libinput(input_device->wlr_device)) { - return; - } - - struct libinput_device *device = - wlr_libinput_get_device_handle(input_device->wlr_device); - sway_log(SWAY_DEBUG, "sway_input_reset_libinput_device(%s)", - input_device->identifier); - bool changed = false; - - changed |= set_send_events(device, - libinput_device_config_send_events_get_default_mode(device)); - changed |= set_tap(device, - libinput_device_config_tap_get_default_enabled(device)); - changed |= set_tap_button_map(device, - libinput_device_config_tap_get_default_button_map(device)); - changed |= set_tap_drag(device, - libinput_device_config_tap_get_default_drag_enabled(device)); - changed |= set_tap_drag_lock(device, - libinput_device_config_tap_get_default_drag_lock_enabled(device)); - changed |= set_accel_speed(device, - libinput_device_config_accel_get_default_speed(device)); - changed |= set_rotation_angle(device, - libinput_device_config_rotation_get_default_angle(device)); - changed |= set_accel_profile(device, - libinput_device_config_accel_get_default_profile(device)); - changed |= set_natural_scroll(device, - libinput_device_config_scroll_get_default_natural_scroll_enabled( - device)); - changed |= set_left_handed(device, - libinput_device_config_left_handed_get_default(device)); - changed |= set_click_method(device, - libinput_device_config_click_get_default_method(device)); - changed |= set_middle_emulation(device, - libinput_device_config_middle_emulation_get_default_enabled(device)); - changed |= set_scroll_method(device, - libinput_device_config_scroll_get_default_method(device)); - changed |= set_scroll_button(device, - libinput_device_config_scroll_get_default_button(device)); - changed |= set_dwt(device, - libinput_device_config_dwt_get_default_enabled(device)); - changed |= set_dwtp(device, - libinput_device_config_dwtp_get_default_enabled(device)); - - float matrix[6]; - libinput_device_config_calibration_get_default_matrix(device, matrix); - changed |= set_calibration_matrix(device, matrix); - - if (changed) { - ipc_event_input("libinput_config", input_device); - } -} - -bool sway_libinput_device_is_builtin(struct sway_input_device *sway_device) { - if (!wlr_input_device_is_libinput(sway_device->wlr_device)) { - return false; - } - - struct libinput_device *device = - wlr_libinput_get_device_handle(sway_device->wlr_device); - struct udev_device *udev_device = - libinput_device_get_udev_device(device); - if (!udev_device) { - return false; - } - - const char *id_path = udev_device_get_property_value(udev_device, "ID_PATH"); - if (!id_path) { - return false; - } - - const char prefix_platform[] = "platform-"; - if (strncmp(id_path, prefix_platform, strlen(prefix_platform)) != 0) { - return false; - } - - const char prefix_pci[] = "pci-"; - const char infix_platform[] = "-platform-"; - return (strncmp(id_path, prefix_pci, strlen(prefix_pci)) == 0) && - strstr(id_path, infix_platform); -} diff --git a/sway/input/seat.c b/sway/input/seat.c deleted file mode 100644 index 43289598c..000000000 --- a/sway/input/seat.c +++ /dev/null @@ -1,1777 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "config.h" -#include "list.h" -#include "log.h" -#include "sway/config.h" -#include "sway/desktop.h" -#include "sway/input/cursor.h" -#include "sway/input/input-manager.h" -#include "sway/input/keyboard.h" -#include "sway/input/libinput.h" -#include "sway/input/seat.h" -#include "sway/input/switch.h" -#include "sway/input/tablet.h" -#include "sway/ipc-server.h" -#include "sway/layers.h" -#include "sway/output.h" -#include "sway/server.h" -#include "sway/tree/arrange.h" -#include "sway/tree/container.h" -#include "sway/tree/root.h" -#include "sway/tree/view.h" -#include "sway/tree/workspace.h" - -static void seat_device_destroy(struct sway_seat_device *seat_device) { - if (!seat_device) { - return; - } - - sway_keyboard_destroy(seat_device->keyboard); - sway_tablet_destroy(seat_device->tablet); - sway_tablet_pad_destroy(seat_device->tablet_pad); - sway_switch_destroy(seat_device->switch_device); - wlr_cursor_detach_input_device(seat_device->sway_seat->cursor->cursor, - seat_device->input_device->wlr_device); - wl_list_remove(&seat_device->link); - free(seat_device); -} - -static void seat_node_destroy(struct sway_seat_node *seat_node) { - wl_list_remove(&seat_node->destroy.link); - wl_list_remove(&seat_node->link); - - /* - * This is the only time we remove items from the focus stack without - * immediately re-adding them. If we just removed the last thing, - * mark that nothing has focus anymore. - */ - if (wl_list_empty(&seat_node->seat->focus_stack)) { - seat_node->seat->has_focus = false; - } - - free(seat_node); -} - -void seat_destroy(struct sway_seat *seat) { - if (seat == config->handler_context.seat) { - config->handler_context.seat = input_manager_get_default_seat(); - } - struct sway_seat_device *seat_device, *next; - wl_list_for_each_safe(seat_device, next, &seat->devices, link) { - seat_device_destroy(seat_device); - } - struct sway_seat_node *seat_node, *next_seat_node; - wl_list_for_each_safe(seat_node, next_seat_node, &seat->focus_stack, - link) { - seat_node_destroy(seat_node); - } - sway_input_method_relay_finish(&seat->im_relay); - sway_cursor_destroy(seat->cursor); - wl_list_remove(&seat->new_node.link); - wl_list_remove(&seat->request_start_drag.link); - wl_list_remove(&seat->start_drag.link); - wl_list_remove(&seat->request_set_selection.link); - wl_list_remove(&seat->request_set_primary_selection.link); - wl_list_remove(&seat->link); - wlr_seat_destroy(seat->wlr_seat); - for (int i = 0; i < seat->deferred_bindings->length; i++) { - free_sway_binding(seat->deferred_bindings->items[i]); - } - list_free(seat->deferred_bindings); - free(seat->prev_workspace_name); - free(seat); -} - -void seat_idle_notify_activity(struct sway_seat *seat, - enum sway_input_idle_source source) { - if ((source & seat->idle_inhibit_sources) == 0) { - return; - } - wlr_idle_notifier_v1_notify_activity(server.idle_notifier_v1, seat->wlr_seat); -} - -/** - * Activate all views within this container recursively. - */ -static void seat_send_activate(struct sway_node *node, struct sway_seat *seat) { - if (node_is_view(node)) { - if (!seat_is_input_allowed(seat, node->sway_container->view->surface)) { - sway_log(SWAY_DEBUG, "Refusing to set focus, input is inhibited"); - return; - } - view_set_activated(node->sway_container->view, true); - } else { - list_t *children = node_get_children(node); - for (int i = 0; i < children->length; ++i) { - struct sway_container *child = children->items[i]; - seat_send_activate(&child->node, seat); - } - } -} - -static struct sway_keyboard *sway_keyboard_for_wlr_keyboard( - struct sway_seat *seat, struct wlr_keyboard *wlr_keyboard) { - struct sway_seat_device *seat_device; - wl_list_for_each(seat_device, &seat->devices, link) { - struct sway_input_device *input_device = seat_device->input_device; - if (input_device->wlr_device->type != WLR_INPUT_DEVICE_KEYBOARD) { - continue; - } - if (input_device->wlr_device == &wlr_keyboard->base) { - return seat_device->keyboard; - } - } - struct sway_keyboard_group *group; - wl_list_for_each(group, &seat->keyboard_groups, link) { - struct sway_input_device *input_device = - group->seat_device->input_device; - if (input_device->wlr_device == &wlr_keyboard->base) { - return group->seat_device->keyboard; - } - } - return NULL; -} - -static void seat_keyboard_notify_enter(struct sway_seat *seat, - struct wlr_surface *surface) { - struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); - if (!keyboard) { - wlr_seat_keyboard_notify_enter(seat->wlr_seat, surface, NULL, 0, NULL); - return; - } - - struct sway_keyboard *sway_keyboard = - sway_keyboard_for_wlr_keyboard(seat, keyboard); - assert(sway_keyboard && "Cannot find sway_keyboard for seat keyboard"); - - struct sway_shortcut_state *state = &sway_keyboard->state_pressed_sent; - wlr_seat_keyboard_notify_enter(seat->wlr_seat, surface, - state->pressed_keycodes, state->npressed, &keyboard->modifiers); -} - -static void seat_tablet_pads_set_focus(struct sway_seat *seat, - struct wlr_surface *surface) { - struct sway_seat_device *seat_device; - wl_list_for_each(seat_device, &seat->devices, link) { - sway_tablet_pad_set_focus(seat_device->tablet_pad, surface); - } -} - -/** - * If con is a view, set it as active and enable keyboard input. - * If con is a container, set all child views as active and don't enable - * keyboard input on any. - */ -static void seat_send_focus(struct sway_node *node, struct sway_seat *seat) { - seat_send_activate(node, seat); - - struct sway_view *view = node->type == N_CONTAINER ? - node->sway_container->view : NULL; - - if (view && seat_is_input_allowed(seat, view->surface)) { -#if HAVE_XWAYLAND - if (view->type == SWAY_VIEW_XWAYLAND) { - struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland; - wlr_xwayland_set_seat(xwayland, seat->wlr_seat); - } -#endif - - seat_keyboard_notify_enter(seat, view->surface); - seat_tablet_pads_set_focus(seat, view->surface); - sway_input_method_relay_set_focus(&seat->im_relay, view->surface); - - struct wlr_pointer_constraint_v1 *constraint = - wlr_pointer_constraints_v1_constraint_for_surface( - server.pointer_constraints, view->surface, seat->wlr_seat); - sway_cursor_constrain(seat->cursor, constraint); - } -} - -void seat_for_each_node(struct sway_seat *seat, - void (*f)(struct sway_node *node, void *data), void *data) { - struct sway_seat_node *current = NULL; - wl_list_for_each(current, &seat->focus_stack, link) { - f(current->node, data); - } -} - -struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat, - struct sway_node *ancestor) { - if (node_is_view(ancestor)) { - return ancestor->sway_container; - } - struct sway_seat_node *current; - wl_list_for_each(current, &seat->focus_stack, link) { - struct sway_node *node = current->node; - if (node_is_view(node) && node_has_ancestor(node, ancestor)) { - return node->sway_container; - } - } - return NULL; -} - -static void handle_seat_node_destroy(struct wl_listener *listener, void *data) { - struct sway_seat_node *seat_node = - wl_container_of(listener, seat_node, destroy); - struct sway_seat *seat = seat_node->seat; - struct sway_node *node = seat_node->node; - struct sway_node *parent = node_get_parent(node); - struct sway_node *focus = seat_get_focus(seat); - - if (node->type == N_WORKSPACE) { - seat_node_destroy(seat_node); - // If an unmanaged or layer surface is focused when an output gets - // disabled and an empty workspace on the output was focused by the - // seat, the seat needs to refocus its focus inactive to update the - // value of seat->workspace. - if (seat->workspace == node->sway_workspace) { - struct sway_node *node = seat_get_focus_inactive(seat, &root->node); - seat_set_focus(seat, NULL); - if (node) { - seat_set_focus(seat, node); - } else { - seat->workspace = NULL; - } - } - return; - } - - // Even though the container being destroyed might be nowhere near the - // focused container, we still need to set focus_inactive on a sibling of - // the container being destroyed. - bool needs_new_focus = focus && - (focus == node || node_has_ancestor(focus, node)); - - seat_node_destroy(seat_node); - - if (!parent && !needs_new_focus) { - // Destroying a container that is no longer in the tree - return; - } - - // Find new focus_inactive (ie. sibling, or workspace if no siblings left) - struct sway_node *next_focus = NULL; - while (next_focus == NULL && parent != NULL) { - struct sway_container *con = - seat_get_focus_inactive_view(seat, parent); - next_focus = con ? &con->node : NULL; - - if (next_focus == NULL && parent->type == N_WORKSPACE) { - next_focus = parent; - break; - } - - parent = node_get_parent(parent); - } - - if (!next_focus) { - struct sway_workspace *ws = seat_get_last_known_workspace(seat); - if (!ws) { - return; - } - struct sway_container *con = - seat_get_focus_inactive_view(seat, &ws->node); - next_focus = con ? &(con->node) : &(ws->node); - } - - if (next_focus->type == N_WORKSPACE && - !workspace_is_visible(next_focus->sway_workspace)) { - // Do not change focus to a non-visible workspace - return; - } - - if (needs_new_focus) { - // Make sure the workspace IPC event gets sent - if (node->type == N_CONTAINER && node->sway_container->scratchpad) { - seat_set_focus(seat, NULL); - } - // The structure change might have caused it to move up to the top of - // the focus stack without sending focus notifications to the view - if (seat_get_focus(seat) == next_focus) { - seat_send_focus(next_focus, seat); - } else { - seat_set_focus(seat, next_focus); - } - } else { - // Setting focus_inactive - focus = seat_get_focus_inactive(seat, &root->node); - seat_set_raw_focus(seat, next_focus); - if (focus->type == N_CONTAINER && focus->sway_container->pending.workspace) { - seat_set_raw_focus(seat, &focus->sway_container->pending.workspace->node); - } - seat_set_raw_focus(seat, focus); - } -} - -static struct sway_seat_node *seat_node_from_node( - struct sway_seat *seat, struct sway_node *node) { - if (node->type == N_ROOT || node->type == N_OUTPUT) { - // these don't get seat nodes ever - return NULL; - } - - struct sway_seat_node *seat_node = NULL; - wl_list_for_each(seat_node, &seat->focus_stack, link) { - if (seat_node->node == node) { - return seat_node; - } - } - - seat_node = calloc(1, sizeof(struct sway_seat_node)); - if (seat_node == NULL) { - sway_log(SWAY_ERROR, "could not allocate seat node"); - return NULL; - } - - seat_node->node = node; - seat_node->seat = seat; - wl_list_insert(seat->focus_stack.prev, &seat_node->link); - wl_signal_add(&node->events.destroy, &seat_node->destroy); - seat_node->destroy.notify = handle_seat_node_destroy; - - return seat_node; -} - -static void handle_new_node(struct wl_listener *listener, void *data) { - struct sway_seat *seat = wl_container_of(listener, seat, new_node); - struct sway_node *node = data; - seat_node_from_node(seat, node); -} - -static void drag_icon_damage_whole(struct sway_drag_icon *icon) { - if (!icon->wlr_drag_icon->surface->mapped) { - return; - } - desktop_damage_surface(icon->wlr_drag_icon->surface, icon->x, icon->y, true); -} - -void drag_icon_update_position(struct sway_drag_icon *icon) { - drag_icon_damage_whole(icon); - - struct wlr_drag_icon *wlr_icon = icon->wlr_drag_icon; - struct sway_seat *seat = icon->seat; - struct wlr_cursor *cursor = seat->cursor->cursor; - switch (wlr_icon->drag->grab_type) { - case WLR_DRAG_GRAB_KEYBOARD: - return; - case WLR_DRAG_GRAB_KEYBOARD_POINTER: - icon->x = cursor->x + icon->dx; - icon->y = cursor->y + icon->dy; - break; - case WLR_DRAG_GRAB_KEYBOARD_TOUCH:; - struct wlr_touch_point *point = - wlr_seat_touch_get_point(seat->wlr_seat, wlr_icon->drag->touch_id); - if (point == NULL) { - return; - } - icon->x = seat->touch_x + icon->dx; - icon->y = seat->touch_y + icon->dy; - } - - drag_icon_damage_whole(icon); -} - -static void drag_icon_handle_surface_commit(struct wl_listener *listener, - void *data) { - struct sway_drag_icon *icon = - wl_container_of(listener, icon, surface_commit); - struct wlr_drag_icon *wlr_icon = icon->wlr_drag_icon; - icon->dx += wlr_icon->surface->current.dx; - icon->dy += wlr_icon->surface->current.dy; - drag_icon_update_position(icon); -} - -static void drag_icon_handle_map(struct wl_listener *listener, void *data) { - struct sway_drag_icon *icon = wl_container_of(listener, icon, map); - drag_icon_damage_whole(icon); -} - -static void drag_icon_handle_unmap(struct wl_listener *listener, void *data) { - struct sway_drag_icon *icon = wl_container_of(listener, icon, unmap); - drag_icon_damage_whole(icon); -} - -static void drag_icon_handle_destroy(struct wl_listener *listener, void *data) { - struct sway_drag_icon *icon = wl_container_of(listener, icon, destroy); - icon->wlr_drag_icon->data = NULL; - wl_list_remove(&icon->link); - wl_list_remove(&icon->surface_commit.link); - wl_list_remove(&icon->unmap.link); - wl_list_remove(&icon->map.link); - wl_list_remove(&icon->destroy.link); - free(icon); -} - -static void drag_handle_destroy(struct wl_listener *listener, void *data) { - struct sway_drag *drag = wl_container_of(listener, drag, destroy); - - // Focus enter isn't sent during drag, so refocus the focused node, layer - // surface or unmanaged surface. - struct sway_seat *seat = drag->seat; - struct sway_node *focus = seat_get_focus(seat); - if (focus) { - seat_set_focus(seat, NULL); - seat_set_focus(seat, focus); - } else if (seat->focused_layer) { - struct wlr_layer_surface_v1 *layer = seat->focused_layer; - seat_set_focus_layer(seat, NULL); - seat_set_focus_layer(seat, layer); - } else { - struct wlr_surface *unmanaged = seat->wlr_seat->keyboard_state.focused_surface; - seat_set_focus_surface(seat, NULL, false); - seat_set_focus_surface(seat, unmanaged, false); - } - - drag->wlr_drag->data = NULL; - wl_list_remove(&drag->destroy.link); - free(drag); -} - -static void handle_request_start_drag(struct wl_listener *listener, - void *data) { - struct sway_seat *seat = wl_container_of(listener, seat, request_start_drag); - struct wlr_seat_request_start_drag_event *event = data; - - if (wlr_seat_validate_pointer_grab_serial(seat->wlr_seat, - event->origin, event->serial)) { - wlr_seat_start_pointer_drag(seat->wlr_seat, event->drag, event->serial); - return; - } - - struct wlr_touch_point *point; - if (wlr_seat_validate_touch_grab_serial(seat->wlr_seat, - event->origin, event->serial, &point)) { - wlr_seat_start_touch_drag(seat->wlr_seat, - event->drag, event->serial, point); - return; - } - - // TODO: tablet grabs - - sway_log(SWAY_DEBUG, "Ignoring start_drag request: " - "could not validate pointer or touch serial %" PRIu32, event->serial); - wlr_data_source_destroy(event->drag->source); -} - -static void handle_start_drag(struct wl_listener *listener, void *data) { - struct sway_seat *seat = wl_container_of(listener, seat, start_drag); - struct wlr_drag *wlr_drag = data; - - struct sway_drag *drag = calloc(1, sizeof(struct sway_drag)); - if (drag == NULL) { - sway_log(SWAY_ERROR, "Allocation failed"); - return; - } - drag->seat = seat; - drag->wlr_drag = wlr_drag; - wlr_drag->data = drag; - - drag->destroy.notify = drag_handle_destroy; - wl_signal_add(&wlr_drag->events.destroy, &drag->destroy); - - struct wlr_drag_icon *wlr_drag_icon = wlr_drag->icon; - if (wlr_drag_icon != NULL) { - struct sway_drag_icon *icon = calloc(1, sizeof(struct sway_drag_icon)); - if (icon == NULL) { - sway_log(SWAY_ERROR, "Allocation failed"); - return; - } - icon->seat = seat; - icon->wlr_drag_icon = wlr_drag_icon; - wlr_drag_icon->data = icon; - - icon->surface_commit.notify = drag_icon_handle_surface_commit; - wl_signal_add(&wlr_drag_icon->surface->events.commit, &icon->surface_commit); - icon->unmap.notify = drag_icon_handle_unmap; - wl_signal_add(&wlr_drag_icon->surface->events.unmap, &icon->unmap); - icon->map.notify = drag_icon_handle_map; - wl_signal_add(&wlr_drag_icon->surface->events.map, &icon->map); - icon->destroy.notify = drag_icon_handle_destroy; - wl_signal_add(&wlr_drag_icon->events.destroy, &icon->destroy); - - wl_list_insert(&root->drag_icons, &icon->link); - - drag_icon_update_position(icon); - } - seatop_begin_default(seat); -} - -static void handle_request_set_selection(struct wl_listener *listener, - void *data) { - struct sway_seat *seat = - wl_container_of(listener, seat, request_set_selection); - struct wlr_seat_request_set_selection_event *event = data; - wlr_seat_set_selection(seat->wlr_seat, event->source, event->serial); -} - -static void handle_request_set_primary_selection(struct wl_listener *listener, - void *data) { - struct sway_seat *seat = - wl_container_of(listener, seat, request_set_primary_selection); - struct wlr_seat_request_set_primary_selection_event *event = data; - wlr_seat_set_primary_selection(seat->wlr_seat, event->source, event->serial); -} - -static void collect_focus_iter(struct sway_node *node, void *data) { - struct sway_seat *seat = data; - struct sway_seat_node *seat_node = seat_node_from_node(seat, node); - if (!seat_node) { - return; - } - wl_list_remove(&seat_node->link); - wl_list_insert(&seat->focus_stack, &seat_node->link); -} - -static void collect_focus_workspace_iter(struct sway_workspace *workspace, - void *data) { - collect_focus_iter(&workspace->node, data); -} - -static void collect_focus_container_iter(struct sway_container *container, - void *data) { - collect_focus_iter(&container->node, data); -} - -struct sway_seat *seat_create(const char *seat_name) { - struct sway_seat *seat = calloc(1, sizeof(struct sway_seat)); - if (!seat) { - return NULL; - } - - seat->wlr_seat = wlr_seat_create(server.wl_display, seat_name); - if (!sway_assert(seat->wlr_seat, "could not allocate seat")) { - free(seat); - return NULL; - } - seat->wlr_seat->data = seat; - - seat->cursor = sway_cursor_create(seat); - if (!seat->cursor) { - wlr_seat_destroy(seat->wlr_seat); - free(seat); - return NULL; - } - - seat->idle_inhibit_sources = seat->idle_wake_sources = - IDLE_SOURCE_KEYBOARD | - IDLE_SOURCE_POINTER | - IDLE_SOURCE_TOUCH | - IDLE_SOURCE_TABLET_PAD | - IDLE_SOURCE_TABLET_TOOL | - IDLE_SOURCE_SWITCH; - - // init the focus stack - wl_list_init(&seat->focus_stack); - - wl_list_init(&seat->devices); - - root_for_each_workspace(collect_focus_workspace_iter, seat); - root_for_each_container(collect_focus_container_iter, seat); - - seat->deferred_bindings = create_list(); - - wl_signal_add(&root->events.new_node, &seat->new_node); - seat->new_node.notify = handle_new_node; - - wl_signal_add(&seat->wlr_seat->events.request_start_drag, - &seat->request_start_drag); - seat->request_start_drag.notify = handle_request_start_drag; - - wl_signal_add(&seat->wlr_seat->events.start_drag, &seat->start_drag); - seat->start_drag.notify = handle_start_drag; - - wl_signal_add(&seat->wlr_seat->events.request_set_selection, - &seat->request_set_selection); - seat->request_set_selection.notify = handle_request_set_selection; - - wl_signal_add(&seat->wlr_seat->events.request_set_primary_selection, - &seat->request_set_primary_selection); - seat->request_set_primary_selection.notify = - handle_request_set_primary_selection; - - wl_list_init(&seat->keyboard_groups); - wl_list_init(&seat->keyboard_shortcuts_inhibitors); - - sway_input_method_relay_init(seat, &seat->im_relay); - - bool first = wl_list_empty(&server.input->seats); - wl_list_insert(&server.input->seats, &seat->link); - - if (!first) { - // Since this is not the first seat, attempt to set initial focus - struct sway_seat *current_seat = input_manager_current_seat(); - struct sway_node *current_focus = - seat_get_focus_inactive(current_seat, &root->node); - seat_set_focus(seat, current_focus); - } - - seatop_begin_default(seat); - - return seat; -} - -static void seat_update_capabilities(struct sway_seat *seat) { - uint32_t caps = 0; - uint32_t previous_caps = seat->wlr_seat->capabilities; - struct sway_seat_device *seat_device; - wl_list_for_each(seat_device, &seat->devices, link) { - switch (seat_device->input_device->wlr_device->type) { - case WLR_INPUT_DEVICE_KEYBOARD: - caps |= WL_SEAT_CAPABILITY_KEYBOARD; - break; - case WLR_INPUT_DEVICE_POINTER: - caps |= WL_SEAT_CAPABILITY_POINTER; - break; - case WLR_INPUT_DEVICE_TOUCH: - caps |= WL_SEAT_CAPABILITY_TOUCH; - break; - case WLR_INPUT_DEVICE_TABLET_TOOL: - caps |= WL_SEAT_CAPABILITY_POINTER; - break; - case WLR_INPUT_DEVICE_SWITCH: - case WLR_INPUT_DEVICE_TABLET_PAD: - break; - } - } - - // Hide cursor if seat doesn't have pointer capability. - // We must call cursor_set_image while the wlr_seat has the capabilities - // otherwise it's a no op. - if ((caps & WL_SEAT_CAPABILITY_POINTER) == 0) { - cursor_set_image(seat->cursor, NULL, NULL); - wlr_seat_set_capabilities(seat->wlr_seat, caps); - } else { - wlr_seat_set_capabilities(seat->wlr_seat, caps); - if ((previous_caps & WL_SEAT_CAPABILITY_POINTER) == 0) { - cursor_set_image(seat->cursor, "default", NULL); - } - } -} - -static void seat_reset_input_config(struct sway_seat *seat, - struct sway_seat_device *sway_device) { - sway_log(SWAY_DEBUG, "Resetting output mapping for input device %s", - sway_device->input_device->identifier); - wlr_cursor_map_input_to_output(seat->cursor->cursor, - sway_device->input_device->wlr_device, NULL); -} - -static bool has_prefix(const char *str, const char *prefix) { - return strncmp(str, prefix, strlen(prefix)) == 0; -} - -/** - * Get the name of the built-in output, if any. Returns NULL if there isn't - * exactly one built-in output. - */ -static const char *get_builtin_output_name(void) { - const char *match = NULL; - for (int i = 0; i < root->outputs->length; ++i) { - struct sway_output *output = root->outputs->items[i]; - const char *name = output->wlr_output->name; - if (has_prefix(name, "eDP-") || has_prefix(name, "LVDS-") || - has_prefix(name, "DSI-")) { - if (match != NULL) { - return NULL; - } - match = name; - } - } - return match; -} - -static bool is_touch_or_tablet_tool(struct sway_seat_device *seat_device) { - switch (seat_device->input_device->wlr_device->type) { - case WLR_INPUT_DEVICE_TOUCH: - case WLR_INPUT_DEVICE_TABLET_TOOL: - return true; - default: - return false; - } -} - -static void seat_apply_input_mapping(struct sway_seat *seat, - struct sway_seat_device *sway_device) { - struct input_config *ic = - input_device_get_config(sway_device->input_device); - - switch (sway_device->input_device->wlr_device->type) { - case WLR_INPUT_DEVICE_POINTER: - case WLR_INPUT_DEVICE_TOUCH: - case WLR_INPUT_DEVICE_TABLET_TOOL: - break; - default: - return; // these devices don't support mappings - } - - sway_log(SWAY_DEBUG, "Applying input mapping to %s", - sway_device->input_device->identifier); - - const char *mapped_to_output = ic == NULL ? NULL : ic->mapped_to_output; - struct wlr_box *mapped_to_region = ic == NULL ? NULL : ic->mapped_to_region; - enum input_config_mapped_to mapped_to = - ic == NULL ? MAPPED_TO_DEFAULT : ic->mapped_to; - - switch (mapped_to) { - case MAPPED_TO_DEFAULT:; - /* - * If the wlroots backend provides an output name, use that. - * - * Otherwise, try to map built-in touch and pointer devices to the - * built-in output. - */ - struct wlr_input_device *dev = sway_device->input_device->wlr_device; - switch (dev->type) { - case WLR_INPUT_DEVICE_POINTER: - mapped_to_output = wlr_pointer_from_input_device(dev)->output_name; - break; - case WLR_INPUT_DEVICE_TOUCH: - mapped_to_output = wlr_touch_from_input_device(dev)->output_name; - break; - default: - mapped_to_output = NULL; - break; - } -#if WLR_HAS_LIBINPUT_BACKEND - if (mapped_to_output == NULL && is_touch_or_tablet_tool(sway_device) && - sway_libinput_device_is_builtin(sway_device->input_device)) { - mapped_to_output = get_builtin_output_name(); - if (mapped_to_output) { - sway_log(SWAY_DEBUG, "Auto-detected output '%s' for device '%s'", - mapped_to_output, sway_device->input_device->identifier); - } - } -#else - (void)is_touch_or_tablet_tool; - (void)get_builtin_output_name; -#endif - if (mapped_to_output == NULL) { - return; - } - /* fallthrough */ - case MAPPED_TO_OUTPUT: - sway_log(SWAY_DEBUG, "Mapping input device %s to output %s", - sway_device->input_device->identifier, mapped_to_output); - if (strcmp("*", mapped_to_output) == 0) { - wlr_cursor_map_input_to_output(seat->cursor->cursor, - sway_device->input_device->wlr_device, NULL); - wlr_cursor_map_input_to_region(seat->cursor->cursor, - sway_device->input_device->wlr_device, NULL); - sway_log(SWAY_DEBUG, "Reset output mapping"); - return; - } - struct sway_output *output = output_by_name_or_id(mapped_to_output); - if (!output) { - sway_log(SWAY_DEBUG, "Requested output %s for device %s isn't present", - mapped_to_output, sway_device->input_device->identifier); - return; - } - wlr_cursor_map_input_to_output(seat->cursor->cursor, - sway_device->input_device->wlr_device, output->wlr_output); - wlr_cursor_map_input_to_region(seat->cursor->cursor, - sway_device->input_device->wlr_device, NULL); - sway_log(SWAY_DEBUG, - "Mapped to output %s", output->wlr_output->name); - return; - case MAPPED_TO_REGION: - sway_log(SWAY_DEBUG, "Mapping input device %s to %d,%d %dx%d", - sway_device->input_device->identifier, - mapped_to_region->x, mapped_to_region->y, - mapped_to_region->width, mapped_to_region->height); - wlr_cursor_map_input_to_output(seat->cursor->cursor, - sway_device->input_device->wlr_device, NULL); - wlr_cursor_map_input_to_region(seat->cursor->cursor, - sway_device->input_device->wlr_device, mapped_to_region); - return; - } -} - -static void seat_configure_pointer(struct sway_seat *seat, - struct sway_seat_device *sway_device) { - seat_configure_xcursor(seat); - wlr_cursor_attach_input_device(seat->cursor->cursor, - sway_device->input_device->wlr_device); - wl_event_source_timer_update( - seat->cursor->hide_source, cursor_get_timeout(seat->cursor)); -} - -static void seat_configure_keyboard(struct sway_seat *seat, - struct sway_seat_device *seat_device) { - if (!seat_device->keyboard) { - sway_keyboard_create(seat, seat_device); - } - sway_keyboard_configure(seat_device->keyboard); - - // We only need to update the current keyboard, as the rest will be updated - // as they are activated. - struct wlr_keyboard *wlr_keyboard = - wlr_keyboard_from_input_device(seat_device->input_device->wlr_device); - struct wlr_keyboard *current_keyboard = seat->wlr_seat->keyboard_state.keyboard; - if (wlr_keyboard != current_keyboard) { - return; - } - - // force notify reenter to pick up the new configuration. This reuses - // the current focused surface to avoid breaking input grabs. - struct wlr_surface *surface = seat->wlr_seat->keyboard_state.focused_surface; - if (surface) { - wlr_seat_keyboard_notify_clear_focus(seat->wlr_seat); - seat_keyboard_notify_enter(seat, surface); - } -} - -static void seat_configure_switch(struct sway_seat *seat, - struct sway_seat_device *seat_device) { - if (!seat_device->switch_device) { - sway_switch_create(seat, seat_device); - } - sway_switch_configure(seat_device->switch_device); -} - -static void seat_configure_touch(struct sway_seat *seat, - struct sway_seat_device *sway_device) { - wlr_cursor_attach_input_device(seat->cursor->cursor, - sway_device->input_device->wlr_device); -} - -static void seat_configure_tablet_tool(struct sway_seat *seat, - struct sway_seat_device *sway_device) { - if (!sway_device->tablet) { - sway_device->tablet = sway_tablet_create(seat, sway_device); - } - sway_configure_tablet(sway_device->tablet); - wlr_cursor_attach_input_device(seat->cursor->cursor, - sway_device->input_device->wlr_device); -} - -static void seat_configure_tablet_pad(struct sway_seat *seat, - struct sway_seat_device *sway_device) { - if (!sway_device->tablet_pad) { - sway_device->tablet_pad = sway_tablet_pad_create(seat, sway_device); - } - sway_configure_tablet_pad(sway_device->tablet_pad); -} - -static struct sway_seat_device *seat_get_device(struct sway_seat *seat, - struct sway_input_device *input_device) { - struct sway_seat_device *seat_device = NULL; - wl_list_for_each(seat_device, &seat->devices, link) { - if (seat_device->input_device == input_device) { - return seat_device; - } - } - - struct sway_keyboard_group *group = NULL; - wl_list_for_each(group, &seat->keyboard_groups, link) { - if (group->seat_device->input_device == input_device) { - return group->seat_device; - } - } - - return NULL; -} - -void seat_configure_device(struct sway_seat *seat, - struct sway_input_device *input_device) { - struct sway_seat_device *seat_device = seat_get_device(seat, input_device); - if (!seat_device) { - return; - } - - switch (input_device->wlr_device->type) { - case WLR_INPUT_DEVICE_POINTER: - seat_configure_pointer(seat, seat_device); - break; - case WLR_INPUT_DEVICE_KEYBOARD: - seat_configure_keyboard(seat, seat_device); - break; - case WLR_INPUT_DEVICE_SWITCH: - seat_configure_switch(seat, seat_device); - break; - case WLR_INPUT_DEVICE_TOUCH: - seat_configure_touch(seat, seat_device); - break; - case WLR_INPUT_DEVICE_TABLET_TOOL: - seat_configure_tablet_tool(seat, seat_device); - break; - case WLR_INPUT_DEVICE_TABLET_PAD: - seat_configure_tablet_pad(seat, seat_device); - break; - } - - seat_apply_input_mapping(seat, seat_device); -} - -void seat_configure_device_mapping(struct sway_seat *seat, - struct sway_input_device *input_device) { - struct sway_seat_device *seat_device = seat_get_device(seat, input_device); - if (!seat_device) { - return; - } - - seat_apply_input_mapping(seat, seat_device); -} - -void seat_reset_device(struct sway_seat *seat, - struct sway_input_device *input_device) { - struct sway_seat_device *seat_device = seat_get_device(seat, input_device); - if (!seat_device) { - return; - } - - switch (input_device->wlr_device->type) { - case WLR_INPUT_DEVICE_POINTER: - seat_reset_input_config(seat, seat_device); - break; - case WLR_INPUT_DEVICE_KEYBOARD: - sway_keyboard_disarm_key_repeat(seat_device->keyboard); - sway_keyboard_configure(seat_device->keyboard); - break; - case WLR_INPUT_DEVICE_TOUCH: - seat_reset_input_config(seat, seat_device); - break; - case WLR_INPUT_DEVICE_TABLET_TOOL: - seat_reset_input_config(seat, seat_device); - break; - case WLR_INPUT_DEVICE_TABLET_PAD: - sway_log(SWAY_DEBUG, "TODO: reset tablet pad"); - break; - case WLR_INPUT_DEVICE_SWITCH: - sway_log(SWAY_DEBUG, "TODO: reset switch device"); - break; - } -} - -void seat_add_device(struct sway_seat *seat, - struct sway_input_device *input_device) { - if (seat_get_device(seat, input_device)) { - seat_configure_device(seat, input_device); - return; - } - - struct sway_seat_device *seat_device = - calloc(1, sizeof(struct sway_seat_device)); - if (!seat_device) { - sway_log(SWAY_DEBUG, "could not allocate seat device"); - return; - } - - sway_log(SWAY_DEBUG, "adding device %s to seat %s", - input_device->identifier, seat->wlr_seat->name); - - seat_device->sway_seat = seat; - seat_device->input_device = input_device; - wl_list_insert(&seat->devices, &seat_device->link); - - seat_configure_device(seat, input_device); - - seat_update_capabilities(seat); -} - -void seat_remove_device(struct sway_seat *seat, - struct sway_input_device *input_device) { - struct sway_seat_device *seat_device = seat_get_device(seat, input_device); - - if (!seat_device) { - return; - } - - sway_log(SWAY_DEBUG, "removing device %s from seat %s", - input_device->identifier, seat->wlr_seat->name); - - seat_device_destroy(seat_device); - - seat_update_capabilities(seat); -} - -static bool xcursor_manager_is_named(const struct wlr_xcursor_manager *manager, - const char *name) { - return (!manager->name && !name) || - (name && manager->name && strcmp(name, manager->name) == 0); -} - -void seat_configure_xcursor(struct sway_seat *seat) { - unsigned cursor_size = 24; - const char *cursor_theme = NULL; - - const struct seat_config *seat_config = seat_get_config(seat); - if (!seat_config) { - seat_config = seat_get_config_by_name("*"); - } - if (seat_config) { - cursor_size = seat_config->xcursor_theme.size; - cursor_theme = seat_config->xcursor_theme.name; - } - - if (seat == input_manager_get_default_seat()) { - char cursor_size_fmt[16]; - snprintf(cursor_size_fmt, sizeof(cursor_size_fmt), "%u", cursor_size); - setenv("XCURSOR_SIZE", cursor_size_fmt, 1); - if (cursor_theme != NULL) { - setenv("XCURSOR_THEME", cursor_theme, 1); - } - -#if HAVE_XWAYLAND - if (server.xwayland.wlr_xwayland && (!server.xwayland.xcursor_manager || - !xcursor_manager_is_named(server.xwayland.xcursor_manager, - cursor_theme) || - server.xwayland.xcursor_manager->size != cursor_size)) { - - wlr_xcursor_manager_destroy(server.xwayland.xcursor_manager); - - server.xwayland.xcursor_manager = - wlr_xcursor_manager_create(cursor_theme, cursor_size); - sway_assert(server.xwayland.xcursor_manager, - "Cannot create XCursor manager for theme"); - - wlr_xcursor_manager_load(server.xwayland.xcursor_manager, 1); - struct wlr_xcursor *xcursor = wlr_xcursor_manager_get_xcursor( - server.xwayland.xcursor_manager, "default", 1); - if (xcursor != NULL) { - struct wlr_xcursor_image *image = xcursor->images[0]; - wlr_xwayland_set_cursor( - server.xwayland.wlr_xwayland, image->buffer, - image->width * 4, image->width, image->height, - image->hotspot_x, image->hotspot_y); - } - } -#endif - } - - /* Create xcursor manager if we don't have one already, or if the - * theme has changed */ - if (!seat->cursor->xcursor_manager || - !xcursor_manager_is_named( - seat->cursor->xcursor_manager, cursor_theme) || - seat->cursor->xcursor_manager->size != cursor_size) { - - wlr_xcursor_manager_destroy(seat->cursor->xcursor_manager); - seat->cursor->xcursor_manager = - wlr_xcursor_manager_create(cursor_theme, cursor_size); - if (!seat->cursor->xcursor_manager) { - sway_log(SWAY_ERROR, - "Cannot create XCursor manager for theme '%s'", cursor_theme); - } - - - for (int i = 0; i < root->outputs->length; ++i) { - struct sway_output *sway_output = root->outputs->items[i]; - struct wlr_output *output = sway_output->wlr_output; - bool result = - wlr_xcursor_manager_load(seat->cursor->xcursor_manager, - output->scale); - if (!result) { - sway_log(SWAY_ERROR, - "Cannot load xcursor theme for output '%s' with scale %f", - output->name, output->scale); - } - } - - // Reset the cursor so that we apply it to outputs that just appeared - cursor_set_image(seat->cursor, NULL, NULL); - cursor_set_image(seat->cursor, "default", NULL); - wlr_cursor_warp(seat->cursor->cursor, NULL, seat->cursor->cursor->x, - seat->cursor->cursor->y); - } -} - -bool seat_is_input_allowed(struct sway_seat *seat, - struct wlr_surface *surface) { - if (server.session_lock.locked) { - if (server.session_lock.lock == NULL) { - return false; - } - struct wlr_session_lock_surface_v1 *lock_surf; - wl_list_for_each(lock_surf, &server.session_lock.lock->surfaces, link) { - if (lock_surf->surface == surface) { - return true; - } - } - return false; - } - struct wl_client *client = wl_resource_get_client(surface->resource); - return seat->exclusive_client == client || seat->exclusive_client == NULL; -} - -static void send_unfocus(struct sway_container *con, void *data) { - if (con->view) { - view_set_activated(con->view, false); - } -} - -// Unfocus the container and any children (eg. when leaving `focus parent`) -static void seat_send_unfocus(struct sway_node *node, struct sway_seat *seat) { - sway_cursor_constrain(seat->cursor, NULL); - wlr_seat_keyboard_notify_clear_focus(seat->wlr_seat); - if (node->type == N_WORKSPACE) { - workspace_for_each_container(node->sway_workspace, send_unfocus, seat); - } else { - send_unfocus(node->sway_container, seat); - container_for_each_child(node->sway_container, send_unfocus, seat); - } -} - -static int handle_urgent_timeout(void *data) { - struct sway_view *view = data; - view_set_urgent(view, false); - return 0; -} - -static void set_workspace(struct sway_seat *seat, - struct sway_workspace *new_ws) { - if (seat->workspace == new_ws) { - return; - } - - if (seat->workspace) { - free(seat->prev_workspace_name); - seat->prev_workspace_name = strdup(seat->workspace->name); - if (!seat->prev_workspace_name) { - sway_log(SWAY_ERROR, "Unable to allocate previous workspace name"); - } - } - - ipc_event_workspace(seat->workspace, new_ws, "focus"); - seat->workspace = new_ws; -} - -void seat_set_raw_focus(struct sway_seat *seat, struct sway_node *node) { - struct sway_seat_node *seat_node = seat_node_from_node(seat, node); - wl_list_remove(&seat_node->link); - wl_list_insert(&seat->focus_stack, &seat_node->link); - node_set_dirty(node); - - // If focusing a scratchpad container that is fullscreen global, parent - // will be NULL - struct sway_node *parent = node_get_parent(node); - if (parent) { - node_set_dirty(parent); - } -} - -static void seat_set_workspace_focus(struct sway_seat *seat, struct sway_node *node) { - struct sway_node *last_focus = seat_get_focus(seat); - if (last_focus == node) { - return; - } - - struct sway_workspace *last_workspace = seat_get_focused_workspace(seat); - - if (node == NULL) { - // Close any popups on the old focus - if (node_is_view(last_focus)) { - view_close_popups(last_focus->sway_container->view); - } - seat_send_unfocus(last_focus, seat); - sway_input_method_relay_set_focus(&seat->im_relay, NULL); - seat->has_focus = false; - return; - } - - struct sway_workspace *new_workspace = node->type == N_WORKSPACE ? - node->sway_workspace : node->sway_container->pending.workspace; - struct sway_container *container = node->type == N_CONTAINER ? - node->sway_container : NULL; - - // Deny setting focus to a view which is hidden by a fullscreen container or global - if (container && container_obstructing_fullscreen_container(container)) { - return; - } - - // Deny setting focus to a workspace node when using fullscreen global - if (root->fullscreen_global && !container && new_workspace) { - return; - } - - struct sway_output *new_output = - new_workspace ? new_workspace->output : NULL; - - if (last_workspace != new_workspace && new_output) { - node_set_dirty(&new_output->node); - } - - // find new output's old workspace, which might have to be removed if empty - struct sway_workspace *new_output_last_ws = - new_output ? output_get_active_workspace(new_output) : NULL; - - // Unfocus the previous focus - if (last_focus) { - seat_send_unfocus(last_focus, seat); - node_set_dirty(last_focus); - struct sway_node *parent = node_get_parent(last_focus); - if (parent) { - node_set_dirty(parent); - } - } - - // Put the container parents on the focus stack, then the workspace, then - // the focused container. - if (container) { - struct sway_container *parent = container->pending.parent; - while (parent) { - seat_set_raw_focus(seat, &parent->node); - parent = parent->pending.parent; - } - } - if (new_workspace) { - seat_set_raw_focus(seat, &new_workspace->node); - } - if (container) { - seat_set_raw_focus(seat, &container->node); - seat_send_focus(&container->node, seat); - } - - // emit ipc events - set_workspace(seat, new_workspace); - if (container && container->view) { - ipc_event_window(container, "focus"); - } - - // Move sticky containers to new workspace - if (new_workspace && new_output_last_ws - && new_workspace != new_output_last_ws) { - for (int i = 0; i < new_output_last_ws->floating->length; ++i) { - struct sway_container *floater = - new_output_last_ws->floating->items[i]; - if (container_is_sticky(floater)) { - container_detach(floater); - workspace_add_floating(new_workspace, floater); - --i; - } - } - } - - // Close any popups on the old focus - if (last_focus && node_is_view(last_focus)) { - view_close_popups(last_focus->sway_container->view); - } - - // If urgent, either unset the urgency or start a timer to unset it - if (container && container->view && view_is_urgent(container->view) && - !container->view->urgent_timer) { - struct sway_view *view = container->view; - if (last_workspace && last_workspace != new_workspace && - config->urgent_timeout > 0) { - view->urgent_timer = wl_event_loop_add_timer(server.wl_event_loop, - handle_urgent_timeout, view); - if (view->urgent_timer) { - wl_event_source_timer_update(view->urgent_timer, - config->urgent_timeout); - } else { - sway_log_errno(SWAY_ERROR, "Unable to create urgency timer"); - handle_urgent_timeout(view); - } - } else { - view_set_urgent(view, false); - } - } - - if (new_output_last_ws) { - workspace_consider_destroy(new_output_last_ws); - } - if (last_workspace && last_workspace != new_output_last_ws) { - workspace_consider_destroy(last_workspace); - } - - seat->has_focus = true; - - if (config->smart_gaps && new_workspace) { - // When smart gaps is on, gaps may change when the focus changes so - // the workspace needs to be arranged - arrange_workspace(new_workspace); - } -} - -void seat_set_focus(struct sway_seat *seat, struct sway_node *node) { - // Prevents the layer from losing focus if it has keyboard exclusivity - if (seat->has_exclusive_layer) { - struct wlr_layer_surface_v1 *layer = seat->focused_layer; - seat_set_focus_layer(seat, NULL); - seat_set_workspace_focus(seat, node); - seat_set_focus_layer(seat, layer); - } else if (seat->focused_layer) { - seat_set_focus_layer(seat, NULL); - seat_set_workspace_focus(seat, node); - } else { - seat_set_workspace_focus(seat, node); - } - if (server.session_lock.locked) { - seat_set_focus_surface(seat, server.session_lock.focused, false); - } -} - -void seat_set_focus_container(struct sway_seat *seat, - struct sway_container *con) { - seat_set_focus(seat, con ? &con->node : NULL); -} - -void seat_set_focus_workspace(struct sway_seat *seat, - struct sway_workspace *ws) { - seat_set_focus(seat, ws ? &ws->node : NULL); -} - -void seat_set_focus_surface(struct sway_seat *seat, - struct wlr_surface *surface, bool unfocus) { - if (seat->has_focus && unfocus) { - struct sway_node *focus = seat_get_focus(seat); - seat_send_unfocus(focus, seat); - seat->has_focus = false; - } - - if (surface) { - seat_keyboard_notify_enter(seat, surface); - } else { - wlr_seat_keyboard_notify_clear_focus(seat->wlr_seat); - } - - sway_input_method_relay_set_focus(&seat->im_relay, surface); - seat_tablet_pads_set_focus(seat, surface); -} - -void seat_set_focus_layer(struct sway_seat *seat, - struct wlr_layer_surface_v1 *layer) { - if (!layer && seat->focused_layer) { - seat->focused_layer = NULL; - struct sway_node *previous = seat_get_focus_inactive(seat, &root->node); - if (previous) { - // Hack to get seat to re-focus the return value of get_focus - seat_set_focus(seat, NULL); - seat_set_focus(seat, previous); - } - return; - } else if (!layer) { - return; - } - assert(layer->surface->mapped); - if (layer->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP && - layer->current.keyboard_interactive - == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) { - seat->has_exclusive_layer = true; - } - if (seat->focused_layer == layer) { - return; - } - seat_set_focus_surface(seat, layer->surface, true); - seat->focused_layer = layer; -} - -void seat_set_exclusive_client(struct sway_seat *seat, - struct wl_client *client) { - if (!client) { - seat->exclusive_client = client; - // Triggers a refocus of the topmost surface layer if necessary - // TODO: Make layer surface focus per-output based on cursor position - for (int i = 0; i < root->outputs->length; ++i) { - struct sway_output *output = root->outputs->items[i]; - arrange_layers(output); - } - return; - } - if (seat->focused_layer) { - if (wl_resource_get_client(seat->focused_layer->resource) != client) { - seat_set_focus_layer(seat, NULL); - } - } - if (seat->has_focus) { - struct sway_node *focus = seat_get_focus(seat); - if (node_is_view(focus) && wl_resource_get_client( - focus->sway_container->view->surface->resource) != client) { - seat_set_focus(seat, NULL); - } - } - if (seat->wlr_seat->pointer_state.focused_client) { - if (seat->wlr_seat->pointer_state.focused_client->client != client) { - wlr_seat_pointer_notify_clear_focus(seat->wlr_seat); - } - } - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - struct wlr_touch_point *point; - wl_list_for_each(point, &seat->wlr_seat->touch_state.touch_points, link) { - if (point->client->client != client) { - wlr_seat_touch_point_clear_focus(seat->wlr_seat, - now.tv_nsec / 1000, point->touch_id); - } - } - seat->exclusive_client = client; -} - -struct sway_node *seat_get_focus_inactive(struct sway_seat *seat, - struct sway_node *node) { - if (node_is_view(node)) { - return node; - } - struct sway_seat_node *current; - wl_list_for_each(current, &seat->focus_stack, link) { - if (node_has_ancestor(current->node, node)) { - return current->node; - } - } - if (node->type == N_WORKSPACE) { - return node; - } - return NULL; -} - -struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat, - struct sway_workspace *workspace) { - if (!workspace->tiling->length) { - return NULL; - } - struct sway_seat_node *current; - wl_list_for_each(current, &seat->focus_stack, link) { - struct sway_node *node = current->node; - if (node->type == N_CONTAINER && - !container_is_floating_or_child(node->sway_container) && - node->sway_container->pending.workspace == workspace) { - return node->sway_container; - } - } - return NULL; -} - -struct sway_container *seat_get_focus_inactive_floating(struct sway_seat *seat, - struct sway_workspace *workspace) { - if (!workspace->floating->length) { - return NULL; - } - struct sway_seat_node *current; - wl_list_for_each(current, &seat->focus_stack, link) { - struct sway_node *node = current->node; - if (node->type == N_CONTAINER && - container_is_floating_or_child(node->sway_container) && - node->sway_container->pending.workspace == workspace) { - return node->sway_container; - } - } - return NULL; -} - -struct sway_node *seat_get_active_tiling_child(struct sway_seat *seat, - struct sway_node *parent) { - if (node_is_view(parent)) { - return parent; - } - struct sway_seat_node *current; - wl_list_for_each(current, &seat->focus_stack, link) { - struct sway_node *node = current->node; - if (node_get_parent(node) != parent) { - continue; - } - if (parent->type == N_WORKSPACE) { - // Only consider tiling children - struct sway_workspace *ws = parent->sway_workspace; - if (list_find(ws->tiling, node->sway_container) == -1) { - continue; - } - } - return node; - } - return NULL; -} - -struct sway_node *seat_get_focus(struct sway_seat *seat) { - if (!seat->has_focus) { - return NULL; - } - sway_assert(!wl_list_empty(&seat->focus_stack), - "focus_stack is empty, but has_focus is true"); - struct sway_seat_node *current = - wl_container_of(seat->focus_stack.next, current, link); - return current->node; -} - -struct sway_workspace *seat_get_focused_workspace(struct sway_seat *seat) { - struct sway_node *focus = seat_get_focus_inactive(seat, &root->node); - if (!focus) { - return NULL; - } - if (focus->type == N_CONTAINER) { - return focus->sway_container->pending.workspace; - } - if (focus->type == N_WORKSPACE) { - return focus->sway_workspace; - } - return NULL; // output doesn't have a workspace yet -} - -struct sway_workspace *seat_get_last_known_workspace(struct sway_seat *seat) { - struct sway_seat_node *current; - wl_list_for_each(current, &seat->focus_stack, link) { - struct sway_node *node = current->node; - if (node->type == N_CONTAINER && - node->sway_container->pending.workspace) { - return node->sway_container->pending.workspace; - } else if (node->type == N_WORKSPACE) { - return node->sway_workspace; - } - } - return NULL; -} - -struct sway_container *seat_get_focused_container(struct sway_seat *seat) { - struct sway_node *focus = seat_get_focus(seat); - if (focus && focus->type == N_CONTAINER) { - return focus->sway_container; - } - return NULL; -} - -void seat_apply_config(struct sway_seat *seat, - struct seat_config *seat_config) { - struct sway_seat_device *seat_device = NULL; - - if (!seat_config) { - return; - } - - seat->idle_inhibit_sources = seat_config->idle_inhibit_sources; - seat->idle_wake_sources = seat_config->idle_wake_sources; - - wl_list_for_each(seat_device, &seat->devices, link) { - seat_configure_device(seat, seat_device->input_device); - cursor_handle_activity_from_device(seat->cursor, - seat_device->input_device->wlr_device); - } -} - -struct seat_config *seat_get_config(struct sway_seat *seat) { - struct seat_config *seat_config = NULL; - for (int i = 0; i < config->seat_configs->length; ++i ) { - seat_config = config->seat_configs->items[i]; - if (strcmp(seat->wlr_seat->name, seat_config->name) == 0) { - return seat_config; - } - } - - return NULL; -} - -struct seat_config *seat_get_config_by_name(const char *name) { - struct seat_config *seat_config = NULL; - for (int i = 0; i < config->seat_configs->length; ++i ) { - seat_config = config->seat_configs->items[i]; - if (strcmp(name, seat_config->name) == 0) { - return seat_config; - } - } - - return NULL; -} - -void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec, - uint32_t button, enum wlr_button_state state) { - seat->last_button_serial = wlr_seat_pointer_notify_button(seat->wlr_seat, - time_msec, button, state); -} - -void seat_consider_warp_to_focus(struct sway_seat *seat) { - struct sway_node *focus = seat_get_focus(seat); - if (config->mouse_warping == WARP_NO || !focus) { - return; - } - if (config->mouse_warping == WARP_OUTPUT) { - struct sway_output *output = node_get_output(focus); - if (output) { - struct wlr_box box; - output_get_box(output, &box); - if (wlr_box_contains_point(&box, - seat->cursor->cursor->x, seat->cursor->cursor->y)) { - return; - } - } - } - - if (focus->type == N_CONTAINER) { - cursor_warp_to_container(seat->cursor, focus->sway_container, false); - } else { - cursor_warp_to_workspace(seat->cursor, focus->sway_workspace); - } -} - -void seatop_unref(struct sway_seat *seat, struct sway_container *con) { - if (seat->seatop_impl->unref) { - seat->seatop_impl->unref(seat, con); - } -} - -void seatop_button(struct sway_seat *seat, uint32_t time_msec, - struct wlr_input_device *device, uint32_t button, - enum wlr_button_state state) { - if (seat->seatop_impl->button) { - seat->seatop_impl->button(seat, time_msec, device, button, state); - } -} - -void seatop_pointer_motion(struct sway_seat *seat, uint32_t time_msec) { - if (seat->seatop_impl->pointer_motion) { - seat->seatop_impl->pointer_motion(seat, time_msec); - } -} - -void seatop_pointer_axis(struct sway_seat *seat, - struct wlr_pointer_axis_event *event) { - if (seat->seatop_impl->pointer_axis) { - seat->seatop_impl->pointer_axis(seat, event); - } -} - -void seatop_touch_motion(struct sway_seat *seat, struct wlr_touch_motion_event *event, - double lx, double ly) { - if (seat->seatop_impl->touch_motion) { - seat->seatop_impl->touch_motion(seat, event, lx, ly); - } -} - -void seatop_touch_up(struct sway_seat *seat, struct wlr_touch_up_event *event) { - if (seat->seatop_impl->touch_up) { - seat->seatop_impl->touch_up(seat, event); - } -} - -void seatop_touch_down(struct sway_seat *seat, struct wlr_touch_down_event *event, - double lx, double ly) { - if (seat->seatop_impl->touch_down) { - seat->seatop_impl->touch_down(seat, event, lx, ly); - } -} - -void seatop_touch_cancel(struct sway_seat *seat, struct wlr_touch_cancel_event *event) { - if (seat->seatop_impl->touch_cancel) { - seat->seatop_impl->touch_cancel(seat, event); - } -} - -void seatop_tablet_tool_tip(struct sway_seat *seat, - struct sway_tablet_tool *tool, uint32_t time_msec, - enum wlr_tablet_tool_tip_state state) { - if (seat->seatop_impl->tablet_tool_tip) { - seat->seatop_impl->tablet_tool_tip(seat, tool, time_msec, state); - } -} - -void seatop_tablet_tool_motion(struct sway_seat *seat, - struct sway_tablet_tool *tool, uint32_t time_msec) { - if (seat->seatop_impl->tablet_tool_motion) { - seat->seatop_impl->tablet_tool_motion(seat, tool, time_msec); - } else { - seatop_pointer_motion(seat, time_msec); - } -} - -void seatop_hold_begin(struct sway_seat *seat, - struct wlr_pointer_hold_begin_event *event) { - if (seat->seatop_impl->hold_begin) { - seat->seatop_impl->hold_begin(seat, event); - } -} - -void seatop_hold_end(struct sway_seat *seat, - struct wlr_pointer_hold_end_event *event) { - if (seat->seatop_impl->hold_end) { - seat->seatop_impl->hold_end(seat, event); - } -} - -void seatop_pinch_begin(struct sway_seat *seat, - struct wlr_pointer_pinch_begin_event *event) { - if (seat->seatop_impl->pinch_begin) { - seat->seatop_impl->pinch_begin(seat, event); - } -} - -void seatop_pinch_update(struct sway_seat *seat, - struct wlr_pointer_pinch_update_event *event) { - if (seat->seatop_impl->pinch_update) { - seat->seatop_impl->pinch_update(seat, event); - } -} - -void seatop_pinch_end(struct sway_seat *seat, - struct wlr_pointer_pinch_end_event *event) { - if (seat->seatop_impl->pinch_end) { - seat->seatop_impl->pinch_end(seat, event); - } -} - -void seatop_swipe_begin(struct sway_seat *seat, - struct wlr_pointer_swipe_begin_event *event) { - if (seat->seatop_impl->swipe_begin) { - seat->seatop_impl->swipe_begin(seat, event); - } -} - -void seatop_swipe_update(struct sway_seat *seat, - struct wlr_pointer_swipe_update_event *event) { - if (seat->seatop_impl->swipe_update) { - seat->seatop_impl->swipe_update(seat, event); - } -} - -void seatop_swipe_end(struct sway_seat *seat, - struct wlr_pointer_swipe_end_event *event) { - if (seat->seatop_impl->swipe_end) { - seat->seatop_impl->swipe_end(seat, event); - } -} - -void seatop_rebase(struct sway_seat *seat, uint32_t time_msec) { - if (seat->seatop_impl->rebase) { - seat->seatop_impl->rebase(seat, time_msec); - } -} - -void seatop_end(struct sway_seat *seat) { - if (seat->seatop_impl && seat->seatop_impl->end) { - seat->seatop_impl->end(seat); - } - free(seat->seatop_data); - seat->seatop_data = NULL; - seat->seatop_impl = NULL; -} - -void seatop_render(struct sway_seat *seat, struct fx_render_context *ctx) { - if (seat->seatop_impl->render) { - seat->seatop_impl->render(seat, ctx); - } -} - -bool seatop_allows_set_cursor(struct sway_seat *seat) { - return seat->seatop_impl->allow_set_cursor; -} - -struct sway_keyboard_shortcuts_inhibitor * -keyboard_shortcuts_inhibitor_get_for_surface( - const struct sway_seat *seat, - const struct wlr_surface *surface) { - struct sway_keyboard_shortcuts_inhibitor *sway_inhibitor = NULL; - wl_list_for_each(sway_inhibitor, &seat->keyboard_shortcuts_inhibitors, link) { - if (sway_inhibitor->inhibitor->surface == surface) { - return sway_inhibitor; - } - } - - return NULL; -} - -struct sway_keyboard_shortcuts_inhibitor * -keyboard_shortcuts_inhibitor_get_for_focused_surface( - const struct sway_seat *seat) { - return keyboard_shortcuts_inhibitor_get_for_surface(seat, - seat->wlr_seat->keyboard_state.focused_surface); -} diff --git a/sway/input/seatop_default.c b/sway/input/seatop_default.c deleted file mode 100644 index 1dce6dae2..000000000 --- a/sway/input/seatop_default.c +++ /dev/null @@ -1,1160 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include "gesture.h" -#include "sway/desktop/transaction.h" -#include "sway/input/cursor.h" -#include "sway/input/seat.h" -#include "sway/input/tablet.h" -#include "sway/layers.h" -#include "sway/output.h" -#include "sway/tree/view.h" -#include "sway/tree/workspace.h" -#include "log.h" -#if HAVE_XWAYLAND -#include "sway/xwayland.h" -#endif - -struct seatop_default_event { - struct sway_node *previous_node; - uint32_t pressed_buttons[SWAY_CURSOR_PRESSED_BUTTONS_CAP]; - size_t pressed_button_count; - struct gesture_tracker gestures; -}; - -/*-----------------------------------------\ - * Functions shared by multiple callbacks / - *---------------------------------------*/ - -/** - * Determine if the edge of the given container is on the edge of the - * workspace/output. - */ -static bool edge_is_external(struct sway_container *cont, enum wlr_edges edge) { - enum sway_container_layout layout = L_NONE; - switch (edge) { - case WLR_EDGE_TOP: - case WLR_EDGE_BOTTOM: - layout = L_VERT; - break; - case WLR_EDGE_LEFT: - case WLR_EDGE_RIGHT: - layout = L_HORIZ; - break; - case WLR_EDGE_NONE: - sway_assert(false, "Never reached"); - return false; - } - - // Iterate the parents until we find one with the layout we want, - // then check if the child has siblings between it and the edge. - while (cont) { - if (container_parent_layout(cont) == layout) { - list_t *siblings = container_get_siblings(cont); - int index = list_find(siblings, cont); - if (index > 0 && (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_TOP)) { - return false; - } - if (index < siblings->length - 1 && - (edge == WLR_EDGE_RIGHT || edge == WLR_EDGE_BOTTOM)) { - return false; - } - } - cont = cont->pending.parent; - } - return true; -} - -static enum wlr_edges find_edge(struct sway_container *cont, - struct wlr_surface *surface, struct sway_cursor *cursor) { - if (!cont->view || (surface && cont->view->surface != surface)) { - return WLR_EDGE_NONE; - } - if (cont->pending.border == B_NONE || !cont->pending.border_thickness || - cont->pending.border == B_CSD) { - return WLR_EDGE_NONE; - } - if (cont->pending.fullscreen_mode) { - return WLR_EDGE_NONE; - } - - enum wlr_edges edge = 0; - if (cursor->cursor->x < cont->pending.x + cont->pending.border_thickness) { - edge |= WLR_EDGE_LEFT; - } - if (cursor->cursor->y < cont->pending.y + cont->pending.border_thickness) { - edge |= WLR_EDGE_TOP; - } - if (cursor->cursor->x >= cont->pending.x + cont->pending.width - cont->pending.border_thickness) { - edge |= WLR_EDGE_RIGHT; - } - if (cursor->cursor->y >= cont->pending.y + cont->pending.height - cont->pending.border_thickness) { - edge |= WLR_EDGE_BOTTOM; - } - - return edge; -} - -/** - * If the cursor is over a _resizable_ edge, return the edge. - * Edges that can't be resized are edges of the workspace. - */ -enum wlr_edges find_resize_edge(struct sway_container *cont, - struct wlr_surface *surface, struct sway_cursor *cursor) { - enum wlr_edges edge = find_edge(cont, surface, cursor); - if (edge && !container_is_floating(cont) && edge_is_external(cont, edge)) { - return WLR_EDGE_NONE; - } - return edge; -} - -/** - * Return the mouse binding which matches modifier, click location, release, - * and pressed button state, otherwise return null. - */ -static struct sway_binding* get_active_mouse_binding( - struct seatop_default_event *e, list_t *bindings, uint32_t modifiers, - bool release, bool on_titlebar, bool on_border, bool on_content, - bool on_workspace, const char *identifier) { - uint32_t click_region = - ((on_titlebar || on_workspace) ? BINDING_TITLEBAR : 0) | - ((on_border || on_workspace) ? BINDING_BORDER : 0) | - ((on_content || on_workspace) ? BINDING_CONTENTS : 0); - - struct sway_binding *current = NULL; - for (int i = 0; i < bindings->length; ++i) { - struct sway_binding *binding = bindings->items[i]; - if (modifiers ^ binding->modifiers || - e->pressed_button_count != (size_t)binding->keys->length || - release != (binding->flags & BINDING_RELEASE) || - !(click_region & binding->flags) || - (on_workspace && - (click_region & binding->flags) != click_region) || - (strcmp(binding->input, identifier) != 0 && - strcmp(binding->input, "*") != 0)) { - continue; - } - - bool match = true; - for (size_t j = 0; j < e->pressed_button_count; j++) { - uint32_t key = *(uint32_t *)binding->keys->items[j]; - if (key != e->pressed_buttons[j]) { - match = false; - break; - } - } - if (!match) { - continue; - } - - if (!current || strcmp(current->input, "*") == 0) { - current = binding; - if (strcmp(current->input, identifier) == 0) { - // If a binding is found for the exact input, quit searching - break; - } - } - } - return current; -} - -/** - * Remove a button (and duplicates) from the sorted list of currently pressed - * buttons. - */ -static void state_erase_button(struct seatop_default_event *e, - uint32_t button) { - size_t j = 0; - for (size_t i = 0; i < e->pressed_button_count; ++i) { - if (i > j) { - e->pressed_buttons[j] = e->pressed_buttons[i]; - } - if (e->pressed_buttons[i] != button) { - ++j; - } - } - while (e->pressed_button_count > j) { - --e->pressed_button_count; - e->pressed_buttons[e->pressed_button_count] = 0; - } -} - -/** - * Add a button to the sorted list of currently pressed buttons, if there - * is space. - */ -static void state_add_button(struct seatop_default_event *e, uint32_t button) { - if (e->pressed_button_count >= SWAY_CURSOR_PRESSED_BUTTONS_CAP) { - return; - } - size_t i = 0; - while (i < e->pressed_button_count && e->pressed_buttons[i] < button) { - ++i; - } - size_t j = e->pressed_button_count; - while (j > i) { - e->pressed_buttons[j] = e->pressed_buttons[j - 1]; - --j; - } - e->pressed_buttons[i] = button; - e->pressed_button_count++; -} - -/*-------------------------------------------\ - * Functions used by handle_tablet_tool_tip / - *-----------------------------------------*/ - -static void handle_tablet_tool_tip(struct sway_seat *seat, - struct sway_tablet_tool *tool, uint32_t time_msec, - enum wlr_tablet_tool_tip_state state) { - if (state == WLR_TABLET_TOOL_TIP_UP) { - wlr_tablet_v2_tablet_tool_notify_up(tool->tablet_v2_tool); - return; - } - - struct sway_cursor *cursor = seat->cursor; - struct wlr_surface *surface = NULL; - double sx, sy; - struct sway_node *node = node_at_coords(seat, - cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); - - if (!sway_assert(surface, - "Expected null-surface tablet input to route through pointer emulation")) { - return; - } - - struct sway_container *cont = node && node->type == N_CONTAINER ? - node->sway_container : NULL; - - struct wlr_layer_surface_v1 *layer; -#if HAVE_XWAYLAND - struct wlr_xwayland_surface *xsurface; -#endif - if ((layer = wlr_layer_surface_v1_try_from_wlr_surface(surface)) && - layer->current.keyboard_interactive) { - // Handle tapping a layer surface - seat_set_focus_layer(seat, layer); - transaction_commit_dirty(); - } else if (cont) { - bool is_floating_or_child = container_is_floating_or_child(cont); - bool is_fullscreen_or_child = container_is_fullscreen_or_child(cont); - struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); - bool mod_pressed = keyboard && - (wlr_keyboard_get_modifiers(keyboard) & config->floating_mod); - - // Handle beginning floating move - if (is_floating_or_child && !is_fullscreen_or_child && mod_pressed) { - seat_set_focus_container(seat, - seat_get_focus_inactive_view(seat, &cont->node)); - seatop_begin_move_floating(seat, container_toplevel_ancestor(cont)); - return; - } - - // Handle moving a tiling container - if (config->tiling_drag && mod_pressed && !is_floating_or_child && - cont->pending.fullscreen_mode == FULLSCREEN_NONE) { - seatop_begin_move_tiling(seat, cont); - return; - } - - // Handle tapping on a container surface - seat_set_focus_container(seat, cont); - seatop_begin_down(seat, node->sway_container, sx, sy); - } -#if HAVE_XWAYLAND - // Handle tapping on an xwayland unmanaged view - else if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(surface)) && - xsurface->override_redirect && - wlr_xwayland_or_surface_wants_focus(xsurface)) { - struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland; - wlr_xwayland_set_seat(xwayland, seat->wlr_seat); - seat_set_focus_surface(seat, xsurface->surface, false); - transaction_commit_dirty(); - } -#endif - - wlr_tablet_v2_tablet_tool_notify_down(tool->tablet_v2_tool); - wlr_tablet_tool_v2_start_implicit_grab(tool->tablet_v2_tool); -} - -/*----------------------------------\ - * Functions used by handle_button / - *--------------------------------*/ - -static bool trigger_pointer_button_binding(struct sway_seat *seat, - struct wlr_input_device *device, uint32_t button, - enum wlr_button_state state, uint32_t modifiers, - bool on_titlebar, bool on_border, bool on_contents, bool on_workspace) { - // We can reach this for non-pointer devices if we're currently emulating - // pointer input for one. Emulated input should not trigger bindings. The - // device can be NULL if this is synthetic (e.g. swaymsg-generated) input. - if (device && device->type != WLR_INPUT_DEVICE_POINTER) { - return false; - } - - struct seatop_default_event *e = seat->seatop_data; - - char *device_identifier = device ? input_device_get_identifier(device) - : strdup("*"); - struct sway_binding *binding = NULL; - if (state == WLR_BUTTON_PRESSED) { - state_add_button(e, button); - binding = get_active_mouse_binding(e, - config->current_mode->mouse_bindings, modifiers, false, - on_titlebar, on_border, on_contents, on_workspace, - device_identifier); - } else { - binding = get_active_mouse_binding(e, - config->current_mode->mouse_bindings, modifiers, true, - on_titlebar, on_border, on_contents, on_workspace, - device_identifier); - state_erase_button(e, button); - } - - free(device_identifier); - if (binding) { - seat_execute_command(seat, binding); - return true; - } - - return false; -} - -static void handle_button(struct sway_seat *seat, uint32_t time_msec, - struct wlr_input_device *device, uint32_t button, - enum wlr_button_state state) { - struct sway_cursor *cursor = seat->cursor; - - // Determine what's under the cursor - struct wlr_surface *surface = NULL; - double sx, sy; - struct sway_node *node = node_at_coords(seat, - cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); - - struct sway_container *cont = node && node->type == N_CONTAINER ? - node->sway_container : NULL; - bool is_floating = cont && container_is_floating(cont); - bool is_floating_or_child = cont && container_is_floating_or_child(cont); - bool is_fullscreen_or_child = cont && container_is_fullscreen_or_child(cont); - enum wlr_edges edge = cont ? find_edge(cont, surface, cursor) : WLR_EDGE_NONE; - enum wlr_edges resize_edge = cont && edge ? - find_resize_edge(cont, surface, cursor) : WLR_EDGE_NONE; - bool on_border = edge != WLR_EDGE_NONE; - bool on_contents = cont && !on_border && surface; - bool on_workspace = node && node->type == N_WORKSPACE; - bool on_titlebar = cont && !on_border && !surface; - - struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); - uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; - - // Handle mouse bindings - if (trigger_pointer_button_binding(seat, device, button, state, modifiers, - on_titlebar, on_border, on_contents, on_workspace)) { - return; - } - - // Handle clicking an empty workspace - if (node && node->type == N_WORKSPACE) { - if (state == WLR_BUTTON_PRESSED) { - seat_set_focus(seat, node); - transaction_commit_dirty(); - } - seat_pointer_notify_button(seat, time_msec, button, state); - return; - } - - // Handle clicking a layer surface and its popups/subsurfaces - struct wlr_layer_surface_v1 *layer = NULL; - if ((layer = toplevel_layer_surface_from_surface(surface))) { - if (layer->current.keyboard_interactive) { - seat_set_focus_layer(seat, layer); - transaction_commit_dirty(); - } - if (state == WLR_BUTTON_PRESSED) { - seatop_begin_down_on_surface(seat, surface, sx, sy); - } - seat_pointer_notify_button(seat, time_msec, button, state); - return; - } - - // Handle tiling resize via border - if (cont && resize_edge && button == BTN_LEFT && - state == WLR_BUTTON_PRESSED && !is_floating) { - // If a resize is triggered on a tabbed or stacked container, change - // focus to the tab which already had inactive focus -- otherwise, we'd - // change the active tab when the user probably just wanted to resize. - struct sway_container *cont_to_focus = cont; - enum sway_container_layout layout = container_parent_layout(cont); - if (layout == L_TABBED || layout == L_STACKED) { - cont_to_focus = seat_get_focus_inactive_view(seat, &cont->pending.parent->node); - } - - seat_set_focus_container(seat, cont_to_focus); - seatop_begin_resize_tiling(seat, cont, edge); - return; - } - - // Handle tiling resize via mod - bool mod_pressed = modifiers & config->floating_mod; - if (cont && !is_floating_or_child && mod_pressed && - state == WLR_BUTTON_PRESSED) { - uint32_t btn_resize = config->floating_mod_inverse ? - BTN_LEFT : BTN_RIGHT; - if (button == btn_resize) { - edge = 0; - edge |= cursor->cursor->x > cont->pending.x + cont->pending.width / 2 ? - WLR_EDGE_RIGHT : WLR_EDGE_LEFT; - edge |= cursor->cursor->y > cont->pending.y + cont->pending.height / 2 ? - WLR_EDGE_BOTTOM : WLR_EDGE_TOP; - - const char *image = NULL; - if (edge == (WLR_EDGE_LEFT | WLR_EDGE_TOP)) { - image = "nw-resize"; - } else if (edge == (WLR_EDGE_TOP | WLR_EDGE_RIGHT)) { - image = "ne-resize"; - } else if (edge == (WLR_EDGE_RIGHT | WLR_EDGE_BOTTOM)) { - image = "se-resize"; - } else if (edge == (WLR_EDGE_BOTTOM | WLR_EDGE_LEFT)) { - image = "sw-resize"; - } - cursor_set_image(seat->cursor, image, NULL); - seat_set_focus_container(seat, cont); - seatop_begin_resize_tiling(seat, cont, edge); - return; - } - } - - // Handle changing focus when clicking on a container - if (cont && state == WLR_BUTTON_PRESSED) { - // Default case: focus the container that was just clicked. - node = &cont->node; - - // If the container is a tab/stacked container and the click happened - // on a tab, switch to the tab. If the tab contents were already - // focused, focus the tab container itself. If the tab container was - // already focused, cycle back to focusing the tab contents. - if (on_titlebar) { - struct sway_container *focus = seat_get_focused_container(seat); - if (focus == cont || !container_has_ancestor(focus, cont)) { - node = seat_get_focus_inactive(seat, &cont->node); - } - } - - seat_set_focus(seat, node); - transaction_commit_dirty(); - } - - // Handle beginning floating move - if (cont && is_floating_or_child && !is_fullscreen_or_child && - state == WLR_BUTTON_PRESSED) { - uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT; - if (button == btn_move && (mod_pressed || on_titlebar)) { - seatop_begin_move_floating(seat, container_toplevel_ancestor(cont)); - return; - } - } - - // Handle beginning floating resize - if (cont && is_floating_or_child && !is_fullscreen_or_child && - state == WLR_BUTTON_PRESSED) { - // Via border - if (button == BTN_LEFT && resize_edge != WLR_EDGE_NONE) { - seat_set_focus_container(seat, cont); - seatop_begin_resize_floating(seat, cont, resize_edge); - return; - } - - // Via mod+click - uint32_t btn_resize = config->floating_mod_inverse ? - BTN_LEFT : BTN_RIGHT; - if (mod_pressed && button == btn_resize) { - struct sway_container *floater = container_toplevel_ancestor(cont); - edge = 0; - edge |= cursor->cursor->x > floater->pending.x + floater->pending.width / 2 ? - WLR_EDGE_RIGHT : WLR_EDGE_LEFT; - edge |= cursor->cursor->y > floater->pending.y + floater->pending.height / 2 ? - WLR_EDGE_BOTTOM : WLR_EDGE_TOP; - seat_set_focus_container(seat, floater); - seatop_begin_resize_floating(seat, floater, edge); - return; - } - } - - // Handle moving a tiling container - if (config->tiling_drag && (mod_pressed || on_titlebar) && - state == WLR_BUTTON_PRESSED && !is_floating_or_child && - cont && cont->pending.fullscreen_mode == FULLSCREEN_NONE) { - // If moving a container by its title bar, use a threshold for the drag - if (!mod_pressed && config->tiling_drag_threshold > 0) { - seatop_begin_move_tiling_threshold(seat, cont); - } else { - seatop_begin_move_tiling(seat, cont); - } - - return; - } - - // Handle mousedown on a container surface - if (surface && cont && state == WLR_BUTTON_PRESSED) { - seatop_begin_down(seat, cont, sx, sy); - seat_pointer_notify_button(seat, time_msec, button, WLR_BUTTON_PRESSED); - return; - } - - // Handle clicking a container surface or decorations - if (cont && state == WLR_BUTTON_PRESSED) { - seat_pointer_notify_button(seat, time_msec, button, state); - return; - } - -#if HAVE_XWAYLAND - // Handle clicking on xwayland unmanaged view - struct wlr_xwayland_surface *xsurface; - if (surface && - (xsurface = wlr_xwayland_surface_try_from_wlr_surface(surface)) && - xsurface->override_redirect && - wlr_xwayland_or_surface_wants_focus(xsurface)) { - struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland; - wlr_xwayland_set_seat(xwayland, seat->wlr_seat); - seat_set_focus_surface(seat, xsurface->surface, false); - transaction_commit_dirty(); - seat_pointer_notify_button(seat, time_msec, button, state); - } -#endif - - seat_pointer_notify_button(seat, time_msec, button, state); -} - -/*------------------------------------------\ - * Functions used by handle_pointer_motion / - *----------------------------------------*/ - -static void check_focus_follows_mouse(struct sway_seat *seat, - struct seatop_default_event *e, struct sway_node *hovered_node) { - struct sway_node *focus = seat_get_focus(seat); - - // This is the case if a layer-shell surface is hovered. - // If it's on another output, focus the active workspace there. - if (!hovered_node) { - struct wlr_output *wlr_output = wlr_output_layout_output_at( - root->output_layout, seat->cursor->cursor->x, seat->cursor->cursor->y); - if (wlr_output == NULL) { - return; - } - - struct wlr_surface *surface = NULL; - double sx, sy; - node_at_coords(seat, seat->cursor->cursor->x, seat->cursor->cursor->y, - &surface, &sx, &sy); - - // Focus topmost layer surface - struct wlr_layer_surface_v1 *layer = NULL; - if ((layer = toplevel_layer_surface_from_surface(surface)) && - layer->current.keyboard_interactive) { - seat_set_focus_layer(seat, layer); - transaction_commit_dirty(); - return; - } - - struct sway_output *hovered_output = wlr_output->data; - if (focus && hovered_output != node_get_output(focus)) { - struct sway_workspace *ws = output_get_active_workspace(hovered_output); - seat_set_focus(seat, &ws->node); - transaction_commit_dirty(); - } - return; - } - - // If a workspace node is hovered (eg. in the gap area), only set focus if - // the workspace is on a different output to the previous focus. - if (focus && hovered_node->type == N_WORKSPACE) { - struct sway_output *focused_output = node_get_output(focus); - struct sway_output *hovered_output = node_get_output(hovered_node); - if (hovered_output != focused_output) { - seat_set_focus(seat, seat_get_focus_inactive(seat, hovered_node)); - transaction_commit_dirty(); - } - return; - } - - // This is where we handle the common case. We don't want to focus inactive - // tabs, hence the view_is_visible check. - if (node_is_view(hovered_node) && - view_is_visible(hovered_node->sway_container->view)) { - // e->previous_node is the node which the cursor was over previously. - // If focus_follows_mouse is yes and the cursor got over the view due - // to, say, a workspace switch, we don't want to set the focus. - // But if focus_follows_mouse is "always", we do. - if (hovered_node != e->previous_node || - config->focus_follows_mouse == FOLLOWS_ALWAYS) { - seat_set_focus(seat, hovered_node); - transaction_commit_dirty(); - } - } -} - -static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) { - struct seatop_default_event *e = seat->seatop_data; - struct sway_cursor *cursor = seat->cursor; - - struct wlr_surface *surface = NULL; - double sx, sy; - struct sway_node *node = node_at_coords(seat, - cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); - - if (config->focus_follows_mouse != FOLLOWS_NO) { - check_focus_follows_mouse(seat, e, node); - } - - if (surface) { - if (seat_is_input_allowed(seat, surface)) { - wlr_seat_pointer_notify_enter(seat->wlr_seat, surface, sx, sy); - wlr_seat_pointer_notify_motion(seat->wlr_seat, time_msec, sx, sy); - } - } else { - cursor_update_image(cursor, node); - wlr_seat_pointer_notify_clear_focus(seat->wlr_seat); - } - - struct sway_drag_icon *drag_icon; - wl_list_for_each(drag_icon, &root->drag_icons, link) { - if (drag_icon->seat == seat) { - drag_icon_update_position(drag_icon); - } - } - - e->previous_node = node; -} - -static void handle_tablet_tool_motion(struct sway_seat *seat, - struct sway_tablet_tool *tool, uint32_t time_msec) { - struct seatop_default_event *e = seat->seatop_data; - struct sway_cursor *cursor = seat->cursor; - - struct wlr_surface *surface = NULL; - double sx, sy; - struct sway_node *node = node_at_coords(seat, - cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); - - if (config->focus_follows_mouse != FOLLOWS_NO) { - check_focus_follows_mouse(seat, e, node); - } - - if (surface) { - if (seat_is_input_allowed(seat, surface)) { - wlr_tablet_v2_tablet_tool_notify_proximity_in(tool->tablet_v2_tool, - tool->tablet->tablet_v2, surface); - wlr_tablet_v2_tablet_tool_notify_motion(tool->tablet_v2_tool, sx, sy); - } - } else { - cursor_update_image(cursor, node); - wlr_tablet_v2_tablet_tool_notify_proximity_out(tool->tablet_v2_tool); - } - - struct sway_drag_icon *drag_icon; - wl_list_for_each(drag_icon, &root->drag_icons, link) { - if (drag_icon->seat == seat) { - drag_icon_update_position(drag_icon); - } - } - - e->previous_node = node; -} - -static void handle_touch_down(struct sway_seat *seat, - struct wlr_touch_down_event *event, double lx, double ly) { - struct wlr_surface *surface = NULL; - struct wlr_seat *wlr_seat = seat->wlr_seat; - struct sway_cursor *cursor = seat->cursor; - double sx, sy; - node_at_coords(seat, seat->touch_x, seat->touch_y, &surface, &sx, &sy); - - if (surface && wlr_surface_accepts_touch(wlr_seat, surface)) { - if (seat_is_input_allowed(seat, surface)) { - cursor->simulating_pointer_from_touch = false; - seatop_begin_touch_down(seat, surface, event, sx, sy, lx, ly); - } - } else if (!cursor->simulating_pointer_from_touch && - (!surface || seat_is_input_allowed(seat, surface))) { - // Fallback to cursor simulation. - // The pointer_touch_id state is needed, so drags are not aborted when over - // a surface supporting touch and multi touch events don't interfere. - cursor->simulating_pointer_from_touch = true; - cursor->pointer_touch_id = seat->touch_id; - double dx, dy; - dx = seat->touch_x - cursor->cursor->x; - dy = seat->touch_y - cursor->cursor->y; - pointer_motion(cursor, event->time_msec, &event->touch->base, dx, dy, - dx, dy); - dispatch_cursor_button(cursor, &event->touch->base, event->time_msec, - BTN_LEFT, WLR_BUTTON_PRESSED); - } -} - -/*----------------------------------------\ - * Functions used by handle_pointer_axis / - *--------------------------------------*/ - -static uint32_t wl_axis_to_button(struct wlr_pointer_axis_event *event) { - switch (event->orientation) { - case WLR_AXIS_ORIENTATION_VERTICAL: - return event->delta < 0 ? SWAY_SCROLL_UP : SWAY_SCROLL_DOWN; - case WLR_AXIS_ORIENTATION_HORIZONTAL: - return event->delta < 0 ? SWAY_SCROLL_LEFT : SWAY_SCROLL_RIGHT; - default: - sway_log(SWAY_DEBUG, "Unknown axis orientation"); - return 0; - } -} - -static void handle_pointer_axis(struct sway_seat *seat, - struct wlr_pointer_axis_event *event) { - struct sway_input_device *input_device = - event->pointer ? event->pointer->base.data : NULL; - struct input_config *ic = - input_device ? input_device_get_config(input_device) : NULL; - struct sway_cursor *cursor = seat->cursor; - struct seatop_default_event *e = seat->seatop_data; - - // Determine what's under the cursor - struct wlr_surface *surface = NULL; - double sx, sy; - struct sway_node *node = node_at_coords(seat, - cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); - struct sway_container *cont = node && node->type == N_CONTAINER ? - node->sway_container : NULL; - enum wlr_edges edge = cont ? find_edge(cont, surface, cursor) : WLR_EDGE_NONE; - bool on_border = edge != WLR_EDGE_NONE; - bool on_titlebar = cont && !on_border && !surface; - bool on_titlebar_border = cont && on_border && - cursor->cursor->y < cont->pending.content_y; - bool on_contents = cont && !on_border && surface; - bool on_workspace = node && node->type == N_WORKSPACE; - float scroll_factor = - (ic == NULL || ic->scroll_factor == FLT_MIN) ? 1.0f : ic->scroll_factor; - - bool handled = false; - - // Gather information needed for mouse bindings - struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); - uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; - struct wlr_input_device *device = - input_device ? input_device->wlr_device : NULL; - char *dev_id = device ? input_device_get_identifier(device) : strdup("*"); - uint32_t button = wl_axis_to_button(event); - - // Handle mouse bindings - x11 mouse buttons 4-7 - press event - struct sway_binding *binding = NULL; - state_add_button(e, button); - binding = get_active_mouse_binding(e, config->current_mode->mouse_bindings, - modifiers, false, on_titlebar, on_border, on_contents, on_workspace, - dev_id); - if (binding) { - seat_execute_command(seat, binding); - handled = true; - } - - // Scrolling on a tabbed or stacked title bar (handled as press event) - if (!handled && (on_titlebar || on_titlebar_border)) { - struct sway_node *new_focus; - enum sway_container_layout layout = container_parent_layout(cont); - if (layout == L_TABBED || layout == L_STACKED) { - struct sway_node *tabcontainer = node_get_parent(node); - struct sway_node *active = - seat_get_active_tiling_child(seat, tabcontainer); - list_t *siblings = container_get_siblings(cont); - int desired = list_find(siblings, active->sway_container) + - roundf(scroll_factor * event->delta_discrete / WLR_POINTER_AXIS_DISCRETE_STEP); - if (desired < 0) { - desired = 0; - } else if (desired >= siblings->length) { - desired = siblings->length - 1; - } - - struct sway_container *new_sibling_con = siblings->items[desired]; - struct sway_node *new_sibling = &new_sibling_con->node; - // Use the focused child of the tabbed/stacked container, not the - // container the user scrolled on. - new_focus = seat_get_focus_inactive(seat, new_sibling); - } else { - new_focus = seat_get_focus_inactive(seat, &cont->node); - } - - seat_set_focus(seat, new_focus); - transaction_commit_dirty(); - handled = true; - } - - // Handle mouse bindings - x11 mouse buttons 4-7 - release event - binding = get_active_mouse_binding(e, config->current_mode->mouse_bindings, - modifiers, true, on_titlebar, on_border, on_contents, on_workspace, - dev_id); - state_erase_button(e, button); - if (binding) { - seat_execute_command(seat, binding); - handled = true; - } - free(dev_id); - - if (!handled) { - wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec, - event->orientation, scroll_factor * event->delta, - roundf(scroll_factor * event->delta_discrete), event->source); - } -} - -/*------------------------------------\ - * Functions used by gesture support / - *----------------------------------*/ - -/** - * Check gesture binding for a specific gesture type and finger count. - * Returns true if binding is present, false otherwise - */ -static bool gesture_binding_check(list_t *bindings, enum gesture_type type, - uint8_t fingers, struct sway_input_device *device) { - char *input = - device ? input_device_get_identifier(device->wlr_device) : strdup("*"); - - for (int i = 0; i < bindings->length; ++i) { - struct sway_gesture_binding *binding = bindings->items[i]; - - // Check type and finger count - if (!gesture_check(&binding->gesture, type, fingers)) { - continue; - } - - // Check that input matches - if (strcmp(binding->input, "*") != 0 && - strcmp(binding->input, input) != 0) { - continue; - } - - free(input); - - return true; - } - - free(input); - - return false; -} - -/** - * Return the gesture binding which matches gesture type, finger count - * and direction, otherwise return null. - */ -static struct sway_gesture_binding* gesture_binding_match( - list_t *bindings, struct gesture *gesture, const char *input) { - struct sway_gesture_binding *current = NULL; - - // Find best matching binding - for (int i = 0; i < bindings->length; ++i) { - struct sway_gesture_binding *binding = bindings->items[i]; - bool exact = binding->flags & BINDING_EXACT; - - // Check gesture matching - if (!gesture_match(&binding->gesture, gesture, exact)) { - continue; - } - - // Check input matching - if (strcmp(binding->input, "*") != 0 && - strcmp(binding->input, input) != 0) { - continue; - } - - // If we already have a match ... - if (current) { - // ... check if input matching is equivalent - if (strcmp(current->input, binding->input) == 0) { - - // ... - do not override an exact binding - if (!exact && current->flags & BINDING_EXACT) { - continue; - } - - // ... - and ensure direction matching is better or equal - if (gesture_compare(¤t->gesture, &binding->gesture) > 0) { - continue; - } - } else if (strcmp(binding->input, "*") == 0) { - // ... do not accept worse input match - continue; - } - } - - // Accept newer or better match - current = binding; - - // If exact binding and input is found, quit search - if (strcmp(current->input, input) == 0 && - gesture_compare(¤t->gesture, gesture) == 0) { - break; - } - } // for all gesture bindings - - return current; -} - -// Wrapper around gesture_tracker_end to use tracker with sway bindings -static struct sway_gesture_binding* gesture_tracker_end_and_match( - struct gesture_tracker *tracker, struct sway_input_device* device) { - // Determine name of input that received gesture - char *input = device - ? input_device_get_identifier(device->wlr_device) - : strdup("*"); - - // Match tracking result to binding - struct gesture *gesture = gesture_tracker_end(tracker); - struct sway_gesture_binding *binding = gesture_binding_match( - config->current_mode->gesture_bindings, gesture, input); - free(gesture); - free(input); - - return binding; -} - -// Small wrapper around seat_execute_command to work on gesture bindings -static void gesture_binding_execute(struct sway_seat *seat, - struct sway_gesture_binding *binding) { - struct sway_binding *dummy_binding = - calloc(1, sizeof(struct sway_binding)); - dummy_binding->type = BINDING_GESTURE; - dummy_binding->command = binding->command; - - char *description = gesture_to_string(&binding->gesture); - sway_log(SWAY_DEBUG, "executing gesture binding: %s", description); - free(description); - - seat_execute_command(seat, dummy_binding); - - free(dummy_binding); -} - -static void handle_hold_begin(struct sway_seat *seat, - struct wlr_pointer_hold_begin_event *event) { - // Start tracking gesture if there is a matching binding ... - struct sway_input_device *device = - event->pointer ? event->pointer->base.data : NULL; - list_t *bindings = config->current_mode->gesture_bindings; - if (gesture_binding_check(bindings, GESTURE_TYPE_HOLD, event->fingers, device)) { - struct seatop_default_event *seatop = seat->seatop_data; - gesture_tracker_begin(&seatop->gestures, GESTURE_TYPE_HOLD, event->fingers); - } else { - // ... otherwise forward to client - struct sway_cursor *cursor = seat->cursor; - wlr_pointer_gestures_v1_send_hold_begin( - server.input->pointer_gestures, cursor->seat->wlr_seat, - event->time_msec, event->fingers); - } -} - -static void handle_hold_end(struct sway_seat *seat, - struct wlr_pointer_hold_end_event *event) { - // Ensure that gesture is being tracked and was not cancelled - struct seatop_default_event *seatop = seat->seatop_data; - if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_HOLD)) { - struct sway_cursor *cursor = seat->cursor; - wlr_pointer_gestures_v1_send_hold_end( - server.input->pointer_gestures, cursor->seat->wlr_seat, - event->time_msec, event->cancelled); - return; - } - if (event->cancelled) { - gesture_tracker_cancel(&seatop->gestures); - return; - } - - // End gesture tracking and execute matched binding - struct sway_input_device *device = - event->pointer ? event->pointer->base.data : NULL; - struct sway_gesture_binding *binding = gesture_tracker_end_and_match( - &seatop->gestures, device); - - if (binding) { - gesture_binding_execute(seat, binding); - } -} - -static void handle_pinch_begin(struct sway_seat *seat, - struct wlr_pointer_pinch_begin_event *event) { - // Start tracking gesture if there is a matching binding ... - struct sway_input_device *device = - event->pointer ? event->pointer->base.data : NULL; - list_t *bindings = config->current_mode->gesture_bindings; - if (gesture_binding_check(bindings, GESTURE_TYPE_PINCH, event->fingers, device)) { - struct seatop_default_event *seatop = seat->seatop_data; - gesture_tracker_begin(&seatop->gestures, GESTURE_TYPE_PINCH, event->fingers); - } else { - // ... otherwise forward to client - struct sway_cursor *cursor = seat->cursor; - wlr_pointer_gestures_v1_send_pinch_begin( - server.input->pointer_gestures, cursor->seat->wlr_seat, - event->time_msec, event->fingers); - } -} - -static void handle_pinch_update(struct sway_seat *seat, - struct wlr_pointer_pinch_update_event *event) { - // Update any ongoing tracking ... - struct seatop_default_event *seatop = seat->seatop_data; - if (gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_PINCH)) { - gesture_tracker_update(&seatop->gestures, event->dx, event->dy, - event->scale, event->rotation); - } else { - // ... otherwise forward to client - struct sway_cursor *cursor = seat->cursor; - wlr_pointer_gestures_v1_send_pinch_update( - server.input->pointer_gestures, - cursor->seat->wlr_seat, - event->time_msec, event->dx, event->dy, - event->scale, event->rotation); - } -} - -static void handle_pinch_end(struct sway_seat *seat, - struct wlr_pointer_pinch_end_event *event) { - // Ensure that gesture is being tracked and was not cancelled - struct seatop_default_event *seatop = seat->seatop_data; - if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_PINCH)) { - struct sway_cursor *cursor = seat->cursor; - wlr_pointer_gestures_v1_send_pinch_end( - server.input->pointer_gestures, cursor->seat->wlr_seat, - event->time_msec, event->cancelled); - return; - } - if (event->cancelled) { - gesture_tracker_cancel(&seatop->gestures); - return; - } - - // End gesture tracking and execute matched binding - struct sway_input_device *device = - event->pointer ? event->pointer->base.data : NULL; - struct sway_gesture_binding *binding = gesture_tracker_end_and_match( - &seatop->gestures, device); - - if (binding) { - gesture_binding_execute(seat, binding); - } -} - -static void handle_swipe_begin(struct sway_seat *seat, - struct wlr_pointer_swipe_begin_event *event) { - // Start tracking gesture if there is a matching binding ... - struct sway_input_device *device = - event->pointer ? event->pointer->base.data : NULL; - list_t *bindings = config->current_mode->gesture_bindings; - if (gesture_binding_check(bindings, GESTURE_TYPE_SWIPE, event->fingers, device)) { - struct seatop_default_event *seatop = seat->seatop_data; - gesture_tracker_begin(&seatop->gestures, GESTURE_TYPE_SWIPE, event->fingers); - } else { - // ... otherwise forward to client - struct sway_cursor *cursor = seat->cursor; - wlr_pointer_gestures_v1_send_swipe_begin( - server.input->pointer_gestures, cursor->seat->wlr_seat, - event->time_msec, event->fingers); - } -} - -static void handle_swipe_update(struct sway_seat *seat, - struct wlr_pointer_swipe_update_event *event) { - - // Update any ongoing tracking ... - struct seatop_default_event *seatop = seat->seatop_data; - if (gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_SWIPE)) { - gesture_tracker_update(&seatop->gestures, - event->dx, event->dy, NAN, NAN); - } else { - // ... otherwise forward to client - struct sway_cursor *cursor = seat->cursor; - wlr_pointer_gestures_v1_send_swipe_update( - server.input->pointer_gestures, cursor->seat->wlr_seat, - event->time_msec, event->dx, event->dy); - } -} - -static void handle_swipe_end(struct sway_seat *seat, - struct wlr_pointer_swipe_end_event *event) { - // Ensure gesture is being tracked and was not cancelled - struct seatop_default_event *seatop = seat->seatop_data; - if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_SWIPE)) { - struct sway_cursor *cursor = seat->cursor; - wlr_pointer_gestures_v1_send_swipe_end(server.input->pointer_gestures, - cursor->seat->wlr_seat, event->time_msec, event->cancelled); - return; - } - if (event->cancelled) { - gesture_tracker_cancel(&seatop->gestures); - return; - } - - // End gesture tracking and execute matched binding - struct sway_input_device *device = - event->pointer ? event->pointer->base.data : NULL; - struct sway_gesture_binding *binding = gesture_tracker_end_and_match( - &seatop->gestures, device); - - if (binding) { - gesture_binding_execute(seat, binding); - } -} - -/*----------------------------------\ - * Functions used by handle_rebase / - *--------------------------------*/ - -static void handle_rebase(struct sway_seat *seat, uint32_t time_msec) { - struct seatop_default_event *e = seat->seatop_data; - struct sway_cursor *cursor = seat->cursor; - struct wlr_surface *surface = NULL; - double sx = 0.0, sy = 0.0; - e->previous_node = node_at_coords(seat, - cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); - - if (surface) { - if (seat_is_input_allowed(seat, surface)) { - wlr_seat_pointer_notify_enter(seat->wlr_seat, surface, sx, sy); - wlr_seat_pointer_notify_motion(seat->wlr_seat, time_msec, sx, sy); - } - } else { - cursor_update_image(cursor, e->previous_node); - wlr_seat_pointer_notify_clear_focus(seat->wlr_seat); - } -} - -static const struct sway_seatop_impl seatop_impl = { - .button = handle_button, - .pointer_motion = handle_pointer_motion, - .pointer_axis = handle_pointer_axis, - .tablet_tool_tip = handle_tablet_tool_tip, - .tablet_tool_motion = handle_tablet_tool_motion, - .hold_begin = handle_hold_begin, - .hold_end = handle_hold_end, - .pinch_begin = handle_pinch_begin, - .pinch_update = handle_pinch_update, - .pinch_end = handle_pinch_end, - .swipe_begin = handle_swipe_begin, - .swipe_update = handle_swipe_update, - .swipe_end = handle_swipe_end, - .touch_down = handle_touch_down, - .rebase = handle_rebase, - .allow_set_cursor = true, -}; - -void seatop_begin_default(struct sway_seat *seat) { - seatop_end(seat); - - struct seatop_default_event *e = - calloc(1, sizeof(struct seatop_default_event)); - sway_assert(e, "Unable to allocate seatop_default_event"); - - seat->seatop_impl = &seatop_impl; - seat->seatop_data = e; - seatop_rebase(seat, 0); -} diff --git a/sway/input/seatop_down.c b/sway/input/seatop_down.c deleted file mode 100644 index 36f9bb608..000000000 --- a/sway/input/seatop_down.c +++ /dev/null @@ -1,259 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include "sway/input/cursor.h" -#include "sway/input/seat.h" -#include "sway/tree/view.h" -#include "sway/desktop/transaction.h" -#include "log.h" - -struct seatop_touch_point_event { - double ref_lx, ref_ly; // touch's x/y at start of op - double ref_con_lx, ref_con_ly; // container's x/y at start of op - int32_t touch_id; - struct wl_list link; -}; - -struct seatop_down_event { - struct sway_container *con; - struct sway_seat *seat; - struct wl_listener surface_destroy; - struct wlr_surface *surface; - double ref_lx, ref_ly; // cursor's x/y at start of op - double ref_con_lx, ref_con_ly; // container's x/y at start of op - struct wl_list point_events; // seatop_touch_point_event::link -}; - -static void handle_touch_motion(struct sway_seat *seat, - struct wlr_touch_motion_event *event, double lx, double ly) { - struct seatop_down_event *e = seat->seatop_data; - - struct seatop_touch_point_event *point_event; - bool found = false; - wl_list_for_each(point_event, &e->point_events, link) { - if (point_event->touch_id == event->touch_id) { - found = true; - break; - } - } - if (!found) { - return; // Probably not a point_event from this seatop_down - } - - double moved_x = lx - point_event->ref_lx; - double moved_y = ly - point_event->ref_ly; - double sx = point_event->ref_con_lx + moved_x; - double sy = point_event->ref_con_ly + moved_y; - - wlr_seat_touch_notify_motion(seat->wlr_seat, event->time_msec, - event->touch_id, sx, sy); -} - -static void handle_touch_up(struct sway_seat *seat, - struct wlr_touch_up_event *event) { - struct seatop_down_event *e = seat->seatop_data; - struct seatop_touch_point_event *point_event, *tmp; - - wl_list_for_each_safe(point_event, tmp, &e->point_events, link) { - if (point_event->touch_id == event->touch_id) { - wl_list_remove(&point_event->link); - free(point_event); - break; - } - } - - wlr_seat_touch_notify_up(seat->wlr_seat, event->time_msec, event->touch_id); - - if (wl_list_empty(&e->point_events)) { - seatop_begin_default(seat); - } -} - -static void handle_touch_down(struct sway_seat *seat, - struct wlr_touch_down_event *event, double lx, double ly) { - struct seatop_down_event *e = seat->seatop_data; - double sx, sy; - struct wlr_surface *surface = NULL; - struct sway_node *focused_node = node_at_coords(seat, seat->touch_x, - seat->touch_y, &surface, &sx, &sy); - - if (!surface || surface != e->surface) { // Must start from the initial surface - return; - } - - struct seatop_touch_point_event *point_event = - calloc(1, sizeof(struct seatop_touch_point_event)); - if (!sway_assert(point_event, "Unable to allocate point_event")) { - return; - } - point_event->touch_id = event->touch_id; - point_event->ref_lx = lx; - point_event->ref_ly = ly; - point_event->ref_con_lx = sx; - point_event->ref_con_ly = sy; - - wl_list_insert(&e->point_events, &point_event->link); - - wlr_seat_touch_notify_down(seat->wlr_seat, surface, event->time_msec, - event->touch_id, sx, sy); - - if (focused_node) { - seat_set_focus(seat, focused_node); - } -} - -static void handle_touch_cancel(struct sway_seat *seat, - struct wlr_touch_cancel_event *event) { - struct seatop_down_event *e = seat->seatop_data; - struct seatop_touch_point_event *point_event, *tmp; - - wl_list_for_each_safe(point_event, tmp, &e->point_events, link) { - if (point_event->touch_id == event->touch_id) { - wl_list_remove(&point_event->link); - free(point_event); - break; - } - } - - if (e->surface) { - wlr_seat_touch_notify_cancel(seat->wlr_seat, e->surface); - } - - if (wl_list_empty(&e->point_events)) { - seatop_begin_default(seat); - } -} - -static void handle_pointer_axis(struct sway_seat *seat, - struct wlr_pointer_axis_event *event) { - struct sway_input_device *input_device = - event->pointer ? event->pointer->base.data : NULL; - struct input_config *ic = - input_device ? input_device_get_config(input_device) : NULL; - float scroll_factor = - (ic == NULL || ic->scroll_factor == FLT_MIN) ? 1.0f : ic->scroll_factor; - - wlr_seat_pointer_notify_axis(seat->wlr_seat, event->time_msec, - event->orientation, scroll_factor * event->delta, - roundf(scroll_factor * event->delta_discrete), event->source); -} - -static void handle_button(struct sway_seat *seat, uint32_t time_msec, - struct wlr_input_device *device, uint32_t button, - enum wlr_button_state state) { - seat_pointer_notify_button(seat, time_msec, button, state); - - if (seat->cursor->pressed_button_count == 0) { - seatop_begin_default(seat); - } -} - -static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) { - struct seatop_down_event *e = seat->seatop_data; - if (seat_is_input_allowed(seat, e->surface)) { - double moved_x = seat->cursor->cursor->x - e->ref_lx; - double moved_y = seat->cursor->cursor->y - e->ref_ly; - double sx = e->ref_con_lx + moved_x; - double sy = e->ref_con_ly + moved_y; - wlr_seat_pointer_notify_motion(seat->wlr_seat, time_msec, sx, sy); - } -} - -static void handle_tablet_tool_tip(struct sway_seat *seat, - struct sway_tablet_tool *tool, uint32_t time_msec, - enum wlr_tablet_tool_tip_state state) { - if (state == WLR_TABLET_TOOL_TIP_UP) { - wlr_tablet_v2_tablet_tool_notify_up(tool->tablet_v2_tool); - seatop_begin_default(seat); - } -} - -static void handle_tablet_tool_motion(struct sway_seat *seat, - struct sway_tablet_tool *tool, uint32_t time_msec) { - struct seatop_down_event *e = seat->seatop_data; - if (seat_is_input_allowed(seat, e->surface)) { - double moved_x = seat->cursor->cursor->x - e->ref_lx; - double moved_y = seat->cursor->cursor->y - e->ref_ly; - double sx = e->ref_con_lx + moved_x; - double sy = e->ref_con_ly + moved_y; - wlr_tablet_v2_tablet_tool_notify_motion(tool->tablet_v2_tool, sx, sy); - } -} - -static void handle_destroy(struct wl_listener *listener, void *data) { - struct seatop_down_event *e = - wl_container_of(listener, e, surface_destroy); - if (e) { - seatop_begin_default(e->seat); - } -} - -static void handle_unref(struct sway_seat *seat, struct sway_container *con) { - struct seatop_down_event *e = seat->seatop_data; - if (e->con == con) { - seatop_begin_default(seat); - } -} - -static void handle_end(struct sway_seat *seat) { - struct seatop_down_event *e = seat->seatop_data; - wl_list_remove(&e->surface_destroy.link); -} - -static const struct sway_seatop_impl seatop_impl = { - .button = handle_button, - .pointer_motion = handle_pointer_motion, - .pointer_axis = handle_pointer_axis, - .tablet_tool_tip = handle_tablet_tool_tip, - .tablet_tool_motion = handle_tablet_tool_motion, - .touch_motion = handle_touch_motion, - .touch_up = handle_touch_up, - .touch_down = handle_touch_down, - .touch_cancel = handle_touch_cancel, - .unref = handle_unref, - .end = handle_end, - .allow_set_cursor = true, -}; - -void seatop_begin_down(struct sway_seat *seat, struct sway_container *con, - double sx, double sy) { - seatop_begin_down_on_surface(seat, con->view->surface, sx, sy); - struct seatop_down_event *e = seat->seatop_data; - e->con = con; - - container_raise_floating(con); - transaction_commit_dirty(); -} - -void seatop_begin_touch_down(struct sway_seat *seat, - struct wlr_surface *surface, struct wlr_touch_down_event *event, - double sx, double sy, double lx, double ly) { - seatop_begin_down_on_surface(seat, surface, sx, sy); - handle_touch_down(seat, event, lx, ly); -} - -void seatop_begin_down_on_surface(struct sway_seat *seat, - struct wlr_surface *surface, double sx, double sy) { - seatop_end(seat); - - struct seatop_down_event *e = - calloc(1, sizeof(struct seatop_down_event)); - if (!sway_assert(e, "Unable to allocate e")) { - return; - } - e->con = NULL; - e->seat = seat; - e->surface = surface; - wl_signal_add(&e->surface->events.destroy, &e->surface_destroy); - e->surface_destroy.notify = handle_destroy; - e->ref_lx = seat->cursor->cursor->x; - e->ref_ly = seat->cursor->cursor->y; - e->ref_con_lx = sx; - e->ref_con_ly = sy; - wl_list_init(&e->point_events); - - seat->seatop_impl = &seatop_impl; - seat->seatop_data = e; -} diff --git a/sway/input/seatop_move_floating.c b/sway/input/seatop_move_floating.c deleted file mode 100644 index ddcd4c53e..000000000 --- a/sway/input/seatop_move_floating.c +++ /dev/null @@ -1,84 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include "sway/desktop.h" -#include "sway/desktop/transaction.h" -#include "sway/input/cursor.h" -#include "sway/input/seat.h" - -struct seatop_move_floating_event { - struct sway_container *con; - double dx, dy; // cursor offset in container -}; - -static void finalize_move(struct sway_seat *seat) { - struct seatop_move_floating_event *e = seat->seatop_data; - - // We "move" the container to its own location - // so it discovers its output again. - container_floating_move_to(e->con, e->con->pending.x, e->con->pending.y); - transaction_commit_dirty(); - - seatop_begin_default(seat); -} - -static void handle_button(struct sway_seat *seat, uint32_t time_msec, - struct wlr_input_device *device, uint32_t button, - enum wlr_button_state state) { - if (seat->cursor->pressed_button_count == 0) { - finalize_move(seat); - } -} - -static void handle_tablet_tool_tip(struct sway_seat *seat, - struct sway_tablet_tool *tool, uint32_t time_msec, - enum wlr_tablet_tool_tip_state state) { - if (state == WLR_TABLET_TOOL_TIP_UP) { - finalize_move(seat); - } -} -static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) { - struct seatop_move_floating_event *e = seat->seatop_data; - struct wlr_cursor *cursor = seat->cursor->cursor; - desktop_damage_whole_container(e->con); - container_floating_move_to(e->con, cursor->x - e->dx, cursor->y - e->dy); - desktop_damage_whole_container(e->con); - transaction_commit_dirty(); -} - -static void handle_unref(struct sway_seat *seat, struct sway_container *con) { - struct seatop_move_floating_event *e = seat->seatop_data; - if (e->con == con) { - seatop_begin_default(seat); - } -} - -static const struct sway_seatop_impl seatop_impl = { - .button = handle_button, - .pointer_motion = handle_pointer_motion, - .tablet_tool_tip = handle_tablet_tool_tip, - .unref = handle_unref, -}; - -void seatop_begin_move_floating(struct sway_seat *seat, - struct sway_container *con) { - seatop_end(seat); - - struct sway_cursor *cursor = seat->cursor; - struct seatop_move_floating_event *e = - calloc(1, sizeof(struct seatop_move_floating_event)); - if (!e) { - return; - } - e->con = con; - e->dx = cursor->cursor->x - con->pending.x; - e->dy = cursor->cursor->y - con->pending.y; - - seat->seatop_impl = &seatop_impl; - seat->seatop_data = e; - - container_raise_floating(con); - transaction_commit_dirty(); - - cursor_set_image(cursor, "grab", NULL); - wlr_seat_pointer_notify_clear_focus(seat->wlr_seat); -} diff --git a/sway/input/seatop_move_tiling.c b/sway/input/seatop_move_tiling.c deleted file mode 100644 index a8cc5f757..000000000 --- a/sway/input/seatop_move_tiling.c +++ /dev/null @@ -1,494 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include "sway/desktop.h" -#include "sway/desktop/transaction.h" -#include "sway/input/cursor.h" -#include "sway/input/seat.h" -#include "sway/ipc-server.h" -#include "sway/output.h" -#include "sway/tree/arrange.h" -#include "sway/tree/node.h" -#include "sway/tree/view.h" -#include "sway/tree/workspace.h" - -// Thickness of the dropzone when dragging to the edge of a layout container -#define DROP_LAYOUT_BORDER 30 - -// Thickness of indicator when dropping onto a titlebar. This should be a -// multiple of 2. -#define DROP_SPLIT_INDICATOR 10 - -struct seatop_move_tiling_event { - struct sway_container *con; - struct sway_node *target_node; - enum wlr_edges target_edge; - struct wlr_box drop_box; - double ref_lx, ref_ly; // cursor's x/y at start of op - bool threshold_reached; - bool split_target; - bool insert_after_target; -}; - -static void handle_render(struct sway_seat *seat, struct fx_render_context *ctx) { - struct seatop_move_tiling_event *e = seat->seatop_data; - if (!e->threshold_reached) { - return; - } - if (e->target_node && node_get_output(e->target_node) == ctx->output) { - float color[4]; - memcpy(&color, config->border_colors.focused.indicator, - sizeof(float) * 4); - premultiply_alpha(color, 0.5); - struct wlr_box box; - memcpy(&box, &e->drop_box, sizeof(struct wlr_box)); - scale_box(&box, ctx->output->wlr_output->scale); - - struct decoration_data deco_data = get_undecorated_decoration_data(); - deco_data.blur = e->con->blur_enabled; - deco_data.corner_radius = e->con->corner_radius * ctx->output->wlr_output->scale; - - // Render blur - if (deco_data.blur && color[3] < 1.0f) { - pixman_region32_t opaque_region; - pixman_region32_init(&opaque_region); - struct wlr_fbox src_box = {0}; - struct wlr_box blur_box; - memcpy(&blur_box, &e->drop_box, sizeof(struct wlr_box)); - // The render_blur function doesn't use root-relative coordinates - blur_box.x -= ctx->output->lx; - blur_box.y -= ctx->output->ly; - scale_box(&blur_box, ctx->output->wlr_output->scale); - - render_blur(ctx, NULL, &src_box, &blur_box, false, &opaque_region, deco_data); - pixman_region32_fini(&opaque_region); - } - - render_rounded_rect(ctx, &box, color, deco_data.corner_radius, ALL); - } -} - -static void handle_motion_prethreshold(struct sway_seat *seat) { - struct seatop_move_tiling_event *e = seat->seatop_data; - double cx = seat->cursor->cursor->x; - double cy = seat->cursor->cursor->y; - double sx = e->ref_lx; - double sy = e->ref_ly; - - // Get the scaled threshold for the output. Even if the operation goes - // across multiple outputs of varying scales, just use the scale for the - // output that the cursor is currently on for simplicity. - struct wlr_output *wlr_output = wlr_output_layout_output_at( - root->output_layout, cx, cy); - double output_scale = wlr_output ? wlr_output->scale : 1; - double threshold = config->tiling_drag_threshold * output_scale; - threshold *= threshold; - - // If the threshold has been exceeded, start the actual drag - if ((cx - sx) * (cx - sx) + (cy - sy) * (cy - sy) > threshold) { - e->threshold_reached = true; - cursor_set_image(seat->cursor, "grab", NULL); - } -} - -static void resize_box(struct wlr_box *box, enum wlr_edges edge, - int thickness) { - switch (edge) { - case WLR_EDGE_TOP: - box->height = thickness; - break; - case WLR_EDGE_LEFT: - box->width = thickness; - break; - case WLR_EDGE_RIGHT: - box->x = box->x + box->width - thickness; - box->width = thickness; - break; - case WLR_EDGE_BOTTOM: - box->y = box->y + box->height - thickness; - box->height = thickness; - break; - case WLR_EDGE_NONE: - box->x += thickness; - box->y += thickness; - box->width -= thickness * 2; - box->height -= thickness * 2; - break; - } -} - -static void split_border(double pos, int offset, int len, int n_children, - int avoid, int *out_pos, bool *out_after) { - int region = 2 * n_children * (pos - offset) / len; - // If the cursor is over the right side of a left-adjacent titlebar, or the - // left side of a right-adjacent titlebar, it's position when dropped will - // be the same. To avoid this, shift the region for adjacent containers. - if (avoid >= 0) { - if (region == 2 * avoid - 1 || region == 2 * avoid) { - region--; - } else if (region == 2 * avoid + 1 || region == 2 * avoid + 2) { - region++; - } - } - - int child_index = (region + 1) / 2; - *out_after = region % 2; - // When dropping at the beginning or end of a container, show the drop - // region within the container boundary, otherwise show it on top of the - // border between two titlebars. - if (child_index == 0) { - *out_pos = offset; - } else if (child_index == n_children) { - *out_pos = offset + len - DROP_SPLIT_INDICATOR; - } else { - *out_pos = offset + child_index * len / n_children - - DROP_SPLIT_INDICATOR / 2; - } -} - -static bool split_titlebar(struct sway_node *node, struct sway_container *avoid, - struct wlr_cursor *cursor, struct wlr_box *title_box, bool *after) { - struct sway_container *con = node->sway_container; - struct sway_node *parent = &con->pending.parent->node; - int title_height = container_titlebar_height(); - struct wlr_box box; - int n_children, avoid_index; - enum sway_container_layout layout = - parent ? node_get_layout(parent) : L_NONE; - if (layout == L_TABBED || layout == L_STACKED) { - node_get_box(parent, &box); - n_children = node_get_children(parent)->length; - avoid_index = list_find(node_get_children(parent), avoid); - } else { - node_get_box(node, &box); - n_children = 1; - avoid_index = -1; - } - if (layout == L_STACKED && cursor->y < box.y + title_height * n_children) { - // Drop into stacked titlebars. - title_box->width = box.width; - title_box->height = DROP_SPLIT_INDICATOR; - title_box->x = box.x; - split_border(cursor->y, box.y, title_height * n_children, - n_children, avoid_index, &title_box->y, after); - return true; - } else if (layout != L_STACKED && cursor->y < box.y + title_height) { - // Drop into side-by-side titlebars. - title_box->width = DROP_SPLIT_INDICATOR; - title_box->height = title_height; - title_box->y = box.y; - split_border(cursor->x, box.x, box.width, n_children, - avoid_index, &title_box->x, after); - return true; - } - return false; -} - -static void handle_motion_postthreshold(struct sway_seat *seat) { - struct seatop_move_tiling_event *e = seat->seatop_data; - e->split_target = false; - struct wlr_surface *surface = NULL; - double sx, sy; - struct sway_cursor *cursor = seat->cursor; - struct sway_node *node = node_at_coords(seat, - cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); - // Damage the old location - desktop_damage_box(&e->drop_box); - - if (!node) { - // Eg. hovered over a layer surface such as swaybar - e->target_node = NULL; - e->target_edge = WLR_EDGE_NONE; - return; - } - - if (node->type == N_WORKSPACE) { - // Empty workspace - e->target_node = node; - e->target_edge = WLR_EDGE_NONE; - workspace_get_box(node->sway_workspace, &e->drop_box); - desktop_damage_box(&e->drop_box); - return; - } - - // Deny moving within own workspace if this is the only child - struct sway_container *con = node->sway_container; - if (workspace_num_tiling_views(e->con->pending.workspace) == 1 && - con->pending.workspace == e->con->pending.workspace) { - e->target_node = NULL; - e->target_edge = WLR_EDGE_NONE; - return; - } - - // Check if the cursor is over a tilebar only if the destination - // container is not a descendant of the source container. - if (!surface && !container_has_ancestor(con, e->con) && - split_titlebar(node, e->con, cursor->cursor, - &e->drop_box, &e->insert_after_target)) { - // Don't allow dropping over the source container's titlebar - // to give users a chance to cancel a drag operation. - if (con == e->con) { - e->target_node = NULL; - } else { - e->target_node = node; - e->split_target = true; - } - e->target_edge = WLR_EDGE_NONE; - return; - } - - // Traverse the ancestors, trying to find a layout container perpendicular - // to the edge. Eg. close to the top or bottom of a horiz layout. - int thresh_top = con->pending.content_y + DROP_LAYOUT_BORDER; - int thresh_bottom = con->pending.content_y + - con->pending.content_height - DROP_LAYOUT_BORDER; - int thresh_left = con->pending.content_x + DROP_LAYOUT_BORDER; - int thresh_right = con->pending.content_x + - con->pending.content_width - DROP_LAYOUT_BORDER; - while (con) { - enum wlr_edges edge = WLR_EDGE_NONE; - enum sway_container_layout layout = container_parent_layout(con); - struct wlr_box box; - node_get_box(node_get_parent(&con->node), &box); - if (layout == L_HORIZ || layout == L_TABBED) { - if (cursor->cursor->y < thresh_top) { - edge = WLR_EDGE_TOP; - box.height = thresh_top - box.y; - } else if (cursor->cursor->y > thresh_bottom) { - edge = WLR_EDGE_BOTTOM; - box.height = box.y + box.height - thresh_bottom; - box.y = thresh_bottom; - } - } else if (layout == L_VERT || layout == L_STACKED) { - if (cursor->cursor->x < thresh_left) { - edge = WLR_EDGE_LEFT; - box.width = thresh_left - box.x; - } else if (cursor->cursor->x > thresh_right) { - edge = WLR_EDGE_RIGHT; - box.width = box.x + box.width - thresh_right; - box.x = thresh_right; - } - } - if (edge) { - e->target_node = node_get_parent(&con->node); - if (e->target_node == &e->con->node) { - e->target_node = node_get_parent(e->target_node); - } - e->target_edge = edge; - e->drop_box = box; - desktop_damage_box(&e->drop_box); - return; - } - con = con->pending.parent; - } - - // Use the hovered view - but we must be over the actual surface - con = node->sway_container; - if (!con->view || !con->view->surface || node == &e->con->node - || node_has_ancestor(node, &e->con->node)) { - e->target_node = NULL; - e->target_edge = WLR_EDGE_NONE; - return; - } - - // Find the closest edge - size_t thickness = fmin(con->pending.content_width, con->pending.content_height) * 0.3; - size_t closest_dist = INT_MAX; - size_t dist; - e->target_edge = WLR_EDGE_NONE; - if ((dist = cursor->cursor->y - con->pending.y) < closest_dist) { - closest_dist = dist; - e->target_edge = WLR_EDGE_TOP; - } - if ((dist = cursor->cursor->x - con->pending.x) < closest_dist) { - closest_dist = dist; - e->target_edge = WLR_EDGE_LEFT; - } - if ((dist = con->pending.x + con->pending.width - cursor->cursor->x) < closest_dist) { - closest_dist = dist; - e->target_edge = WLR_EDGE_RIGHT; - } - if ((dist = con->pending.y + con->pending.height - cursor->cursor->y) < closest_dist) { - closest_dist = dist; - e->target_edge = WLR_EDGE_BOTTOM; - } - - if (closest_dist > thickness) { - e->target_edge = WLR_EDGE_NONE; - } - - e->target_node = node; - e->drop_box.x = con->pending.content_x; - e->drop_box.y = con->pending.content_y; - e->drop_box.width = con->pending.content_width; - e->drop_box.height = con->pending.content_height; - resize_box(&e->drop_box, e->target_edge, thickness); - desktop_damage_box(&e->drop_box); -} - -static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) { - struct seatop_move_tiling_event *e = seat->seatop_data; - if (e->threshold_reached) { - handle_motion_postthreshold(seat); - } else { - handle_motion_prethreshold(seat); - } - transaction_commit_dirty(); -} - -static bool is_parallel(enum sway_container_layout layout, - enum wlr_edges edge) { - bool layout_is_horiz = layout == L_HORIZ || layout == L_TABBED; - bool edge_is_horiz = edge == WLR_EDGE_LEFT || edge == WLR_EDGE_RIGHT; - return layout_is_horiz == edge_is_horiz; -} - -static void finalize_move(struct sway_seat *seat) { - struct seatop_move_tiling_event *e = seat->seatop_data; - - if (!e->target_node) { - seatop_begin_default(seat); - return; - } - - struct sway_container *con = e->con; - struct sway_container *old_parent = con->pending.parent; - struct sway_workspace *old_ws = con->pending.workspace; - struct sway_node *target_node = e->target_node; - struct sway_workspace *new_ws = target_node->type == N_WORKSPACE ? - target_node->sway_workspace : target_node->sway_container->pending.workspace; - enum wlr_edges edge = e->target_edge; - int after = edge != WLR_EDGE_TOP && edge != WLR_EDGE_LEFT; - bool swap = edge == WLR_EDGE_NONE && target_node->type == N_CONTAINER && - !e->split_target; - - if (!swap) { - container_detach(con); - } - - // Moving container into empty workspace - if (target_node->type == N_WORKSPACE && edge == WLR_EDGE_NONE) { - con = workspace_add_tiling(new_ws, con); - } else if (e->split_target) { - struct sway_container *target = target_node->sway_container; - enum sway_container_layout layout = container_parent_layout(target); - if (layout != L_TABBED && layout != L_STACKED) { - container_split(target, L_TABBED); - } - container_add_sibling(target, con, e->insert_after_target); - ipc_event_window(con, "move"); - } else if (target_node->type == N_CONTAINER) { - // Moving container before/after another - struct sway_container *target = target_node->sway_container; - if (swap) { - container_swap(target_node->sway_container, con); - } else { - enum sway_container_layout layout = container_parent_layout(target); - if (edge && !is_parallel(layout, edge)) { - enum sway_container_layout new_layout = edge == WLR_EDGE_TOP || - edge == WLR_EDGE_BOTTOM ? L_VERT : L_HORIZ; - container_split(target, new_layout); - } - container_add_sibling(target, con, after); - ipc_event_window(con, "move"); - } - } else { - // Target is a workspace which requires splitting - enum sway_container_layout new_layout = edge == WLR_EDGE_TOP || - edge == WLR_EDGE_BOTTOM ? L_VERT : L_HORIZ; - workspace_split(new_ws, new_layout); - workspace_insert_tiling(new_ws, con, after); - } - - if (old_parent) { - container_reap_empty(old_parent); - } - - // This is a bit dirty, but we'll set the dimensions to that of a sibling. - // I don't think there's any other way to make it consistent without - // changing how we auto-size containers. - list_t *siblings = container_get_siblings(con); - if (siblings->length > 1) { - int index = list_find(siblings, con); - struct sway_container *sibling = index == 0 ? - siblings->items[1] : siblings->items[index - 1]; - con->pending.width = sibling->pending.width; - con->pending.height = sibling->pending.height; - con->width_fraction = sibling->width_fraction; - con->height_fraction = sibling->height_fraction; - } - - arrange_workspace(old_ws); - if (new_ws != old_ws) { - arrange_workspace(new_ws); - } - - transaction_commit_dirty(); - seatop_begin_default(seat); -} - -static void handle_button(struct sway_seat *seat, uint32_t time_msec, - struct wlr_input_device *device, uint32_t button, - enum wlr_button_state state) { - if (seat->cursor->pressed_button_count == 0) { - finalize_move(seat); - } -} - -static void handle_tablet_tool_tip(struct sway_seat *seat, - struct sway_tablet_tool *tool, uint32_t time_msec, - enum wlr_tablet_tool_tip_state state) { - if (state == WLR_TABLET_TOOL_TIP_UP) { - finalize_move(seat); - } -} - -static void handle_unref(struct sway_seat *seat, struct sway_container *con) { - struct seatop_move_tiling_event *e = seat->seatop_data; - if (e->target_node == &con->node) { // Drop target - e->target_node = NULL; - } - if (e->con == con) { // The container being moved - seatop_begin_default(seat); - } -} - -static const struct sway_seatop_impl seatop_impl = { - .button = handle_button, - .pointer_motion = handle_pointer_motion, - .tablet_tool_tip = handle_tablet_tool_tip, - .unref = handle_unref, - .render = handle_render, -}; - -void seatop_begin_move_tiling_threshold(struct sway_seat *seat, - struct sway_container *con) { - seatop_end(seat); - - struct seatop_move_tiling_event *e = - calloc(1, sizeof(struct seatop_move_tiling_event)); - if (!e) { - return; - } - e->con = con; - e->ref_lx = seat->cursor->cursor->x; - e->ref_ly = seat->cursor->cursor->y; - - seat->seatop_impl = &seatop_impl; - seat->seatop_data = e; - - container_raise_floating(con); - transaction_commit_dirty(); - wlr_seat_pointer_notify_clear_focus(seat->wlr_seat); -} - -void seatop_begin_move_tiling(struct sway_seat *seat, - struct sway_container *con) { - seatop_begin_move_tiling_threshold(seat, con); - struct seatop_move_tiling_event *e = seat->seatop_data; - if (e) { - e->threshold_reached = true; - cursor_set_image(seat->cursor, "grab", NULL); - } -} diff --git a/sway/input/seatop_resize_floating.c b/sway/input/seatop_resize_floating.c deleted file mode 100644 index df6830266..000000000 --- a/sway/input/seatop_resize_floating.c +++ /dev/null @@ -1,196 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include "sway/desktop/transaction.h" -#include "sway/input/cursor.h" -#include "sway/input/seat.h" -#include "sway/tree/arrange.h" -#include "sway/tree/view.h" -#include "sway/tree/workspace.h" -#include "sway/tree/container.h" - -struct seatop_resize_floating_event { - struct sway_container *con; - enum wlr_edges edge; - bool preserve_ratio; - double ref_lx, ref_ly; // cursor's x/y at start of op - double ref_width, ref_height; // container's size at start of op - double ref_con_lx, ref_con_ly; // container's x/y at start of op -}; - -static void handle_button(struct sway_seat *seat, uint32_t time_msec, - struct wlr_input_device *device, uint32_t button, - enum wlr_button_state state) { - struct seatop_resize_floating_event *e = seat->seatop_data; - struct sway_container *con = e->con; - - if (seat->cursor->pressed_button_count == 0) { - container_set_resizing(con, false); - arrange_container(con); // Send configure w/o resizing hint - transaction_commit_dirty(); - seatop_begin_default(seat); - } -} - -static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) { - struct seatop_resize_floating_event *e = seat->seatop_data; - struct sway_container *con = e->con; - enum wlr_edges edge = e->edge; - struct sway_cursor *cursor = seat->cursor; - - // The amount the mouse has moved since the start of the resize operation - // Positive is down/right - double mouse_move_x = cursor->cursor->x - e->ref_lx; - double mouse_move_y = cursor->cursor->y - e->ref_ly; - - if (edge == WLR_EDGE_TOP || edge == WLR_EDGE_BOTTOM) { - mouse_move_x = 0; - } - if (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_RIGHT) { - mouse_move_y = 0; - } - - double grow_width = edge & WLR_EDGE_LEFT ? -mouse_move_x : mouse_move_x; - double grow_height = edge & WLR_EDGE_TOP ? -mouse_move_y : mouse_move_y; - - if (e->preserve_ratio) { - double x_multiplier = grow_width / e->ref_width; - double y_multiplier = grow_height / e->ref_height; - double max_multiplier = fmax(x_multiplier, y_multiplier); - grow_width = e->ref_width * max_multiplier; - grow_height = e->ref_height * max_multiplier; - } - - struct sway_container_state *state = &con->current; - double border_width = 0.0; - if (con->current.border == B_NORMAL || con->current.border == B_PIXEL) { - border_width = state->border_thickness * 2; - } - double border_height = 0.0; - if (con->current.border == B_NORMAL) { - border_height += container_titlebar_height(); - border_height += state->border_thickness; - } else if (con->current.border == B_PIXEL) { - border_height += state->border_thickness * 2; - } - - // Determine new width/height, and accommodate for floating min/max values - double width = e->ref_width + grow_width; - double height = e->ref_height + grow_height; - int min_width, max_width, min_height, max_height; - floating_calculate_constraints(&min_width, &max_width, - &min_height, &max_height); - width = fmin(width, max_width - border_width); - width = fmax(width, min_width + border_width); - width = fmax(width, 1); - height = fmin(height, max_height - border_height); - height = fmax(height, min_height + border_height); - height = fmax(height, 1); - - // Apply the view's min/max size - if (con->view) { - double view_min_width, view_max_width, view_min_height, view_max_height; - view_get_constraints(con->view, &view_min_width, &view_max_width, - &view_min_height, &view_max_height); - width = fmin(width, view_max_width - border_width); - width = fmax(width, view_min_width + border_width); - width = fmax(width, 1); - height = fmin(height, view_max_height - border_height); - height = fmax(height, view_min_height + border_height); - height = fmax(height, 1); - - } - - // Recalculate these, in case we hit a min/max limit - grow_width = width - e->ref_width; - grow_height = height - e->ref_height; - - // Determine grow x/y values - these are relative to the container's x/y at - // the start of the resize operation. - double grow_x = 0, grow_y = 0; - if (edge & WLR_EDGE_LEFT) { - grow_x = -grow_width; - } else if (edge & WLR_EDGE_RIGHT) { - grow_x = 0; - } else { - grow_x = -grow_width / 2; - } - if (edge & WLR_EDGE_TOP) { - grow_y = -grow_height; - } else if (edge & WLR_EDGE_BOTTOM) { - grow_y = 0; - } else { - grow_y = -grow_height / 2; - } - - // Determine the amounts we need to bump everything relative to the current - // size. - int relative_grow_width = width - con->pending.width; - int relative_grow_height = height - con->pending.height; - int relative_grow_x = (e->ref_con_lx + grow_x) - con->pending.x; - int relative_grow_y = (e->ref_con_ly + grow_y) - con->pending.y; - - // Actually resize stuff - con->pending.x += relative_grow_x; - con->pending.y += relative_grow_y; - con->pending.width += relative_grow_width; - con->pending.height += relative_grow_height; - - con->pending.content_x += relative_grow_x; - con->pending.content_y += relative_grow_y; - con->pending.content_width += relative_grow_width; - con->pending.content_height += relative_grow_height; - - arrange_container(con); - transaction_commit_dirty(); -} - -static void handle_unref(struct sway_seat *seat, struct sway_container *con) { - struct seatop_resize_floating_event *e = seat->seatop_data; - if (e->con == con) { - seatop_begin_default(seat); - } -} - -static const struct sway_seatop_impl seatop_impl = { - .button = handle_button, - .pointer_motion = handle_pointer_motion, - .unref = handle_unref, -}; - -void seatop_begin_resize_floating(struct sway_seat *seat, - struct sway_container *con, enum wlr_edges edge) { - seatop_end(seat); - - struct seatop_resize_floating_event *e = - calloc(1, sizeof(struct seatop_resize_floating_event)); - if (!e) { - return; - } - e->con = con; - - struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); - e->preserve_ratio = keyboard && - (wlr_keyboard_get_modifiers(keyboard) & WLR_MODIFIER_SHIFT); - - e->edge = edge == WLR_EDGE_NONE ? WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT : edge; - e->ref_lx = seat->cursor->cursor->x; - e->ref_ly = seat->cursor->cursor->y; - e->ref_con_lx = con->pending.x; - e->ref_con_ly = con->pending.y; - e->ref_width = con->pending.width; - e->ref_height = con->pending.height; - - seat->seatop_impl = &seatop_impl; - seat->seatop_data = e; - - container_set_resizing(con, true); - container_raise_floating(con); - transaction_commit_dirty(); - - const char *image = edge == WLR_EDGE_NONE ? - "se-resize" : wlr_xcursor_get_resize_name(edge); - cursor_set_image(seat->cursor, image, NULL); - wlr_seat_pointer_notify_clear_focus(seat->wlr_seat); -} diff --git a/sway/input/seatop_resize_tiling.c b/sway/input/seatop_resize_tiling.c deleted file mode 100644 index 869d11b50..000000000 --- a/sway/input/seatop_resize_tiling.c +++ /dev/null @@ -1,166 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include "sway/commands.h" -#include "sway/desktop/transaction.h" -#include "sway/input/cursor.h" -#include "sway/input/seat.h" -#include "sway/tree/arrange.h" -#include "sway/tree/container.h" -#include "sway/tree/view.h" - -struct seatop_resize_tiling_event { - struct sway_container *con; // leaf container - - // con, or ancestor of con which will be resized horizontally/vertically - struct sway_container *h_con; - struct sway_container *v_con; - - // sibling con(s) that will be resized to accommodate - struct sway_container *h_sib; - struct sway_container *v_sib; - - enum wlr_edges edge; - enum wlr_edges edge_x, edge_y; - double ref_lx, ref_ly; // cursor's x/y at start of op - double h_con_orig_width; // width of the horizontal ancestor at start - double v_con_orig_height; // height of the vertical ancestor at start -}; - -static struct sway_container *container_get_resize_sibling( - struct sway_container *con, uint32_t edge) { - if (!con) { - return NULL; - } - - list_t *siblings = container_get_siblings(con); - int index = container_sibling_index(con); - int offset = edge & (WLR_EDGE_TOP | WLR_EDGE_LEFT) ? -1 : 1; - - if (siblings->length == 1) { - return NULL; - } else { - return siblings->items[index + offset]; - } -} - -static void handle_button(struct sway_seat *seat, uint32_t time_msec, - struct wlr_input_device *device, uint32_t button, - enum wlr_button_state state) { - struct seatop_resize_tiling_event *e = seat->seatop_data; - - if (seat->cursor->pressed_button_count == 0) { - if (e->h_con) { - container_set_resizing(e->h_con, false); - container_set_resizing(e->h_sib, false); - if (e->h_con->pending.parent) { - arrange_container(e->h_con->pending.parent); - } else { - arrange_workspace(e->h_con->pending.workspace); - } - } - if (e->v_con) { - container_set_resizing(e->v_con, false); - container_set_resizing(e->v_sib, false); - if (e->v_con->pending.parent) { - arrange_container(e->v_con->pending.parent); - } else { - arrange_workspace(e->v_con->pending.workspace); - } - } - transaction_commit_dirty(); - seatop_begin_default(seat); - } -} - -static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) { - struct seatop_resize_tiling_event *e = seat->seatop_data; - int amount_x = 0; - int amount_y = 0; - int moved_x = seat->cursor->cursor->x - e->ref_lx; - int moved_y = seat->cursor->cursor->y - e->ref_ly; - - if (e->h_con) { - if (e->edge & WLR_EDGE_LEFT) { - amount_x = (e->h_con_orig_width - moved_x) - e->h_con->pending.width; - } else if (e->edge & WLR_EDGE_RIGHT) { - amount_x = (e->h_con_orig_width + moved_x) - e->h_con->pending.width; - } - } - if (e->v_con) { - if (e->edge & WLR_EDGE_TOP) { - amount_y = (e->v_con_orig_height - moved_y) - e->v_con->pending.height; - } else if (e->edge & WLR_EDGE_BOTTOM) { - amount_y = (e->v_con_orig_height + moved_y) - e->v_con->pending.height; - } - } - - if (amount_x != 0) { - container_resize_tiled(e->h_con, e->edge_x, amount_x); - } - if (amount_y != 0) { - container_resize_tiled(e->v_con, e->edge_y, amount_y); - } - transaction_commit_dirty(); -} - -static void handle_unref(struct sway_seat *seat, struct sway_container *con) { - struct seatop_resize_tiling_event *e = seat->seatop_data; - if (e->con == con) { - seatop_begin_default(seat); - } - if (e->h_sib == con || e->v_sib == con) { - seatop_begin_default(seat); - } -} - -static const struct sway_seatop_impl seatop_impl = { - .button = handle_button, - .pointer_motion = handle_pointer_motion, - .unref = handle_unref, -}; - -void seatop_begin_resize_tiling(struct sway_seat *seat, - struct sway_container *con, enum wlr_edges edge) { - seatop_end(seat); - - struct seatop_resize_tiling_event *e = - calloc(1, sizeof(struct seatop_resize_tiling_event)); - if (!e) { - return; - } - e->con = con; - e->edge = edge; - - e->ref_lx = seat->cursor->cursor->x; - e->ref_ly = seat->cursor->cursor->y; - - if (edge & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)) { - e->edge_x = edge & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT); - e->h_con = container_find_resize_parent(e->con, e->edge_x); - e->h_sib = container_get_resize_sibling(e->h_con, e->edge_x); - - if (e->h_con) { - container_set_resizing(e->h_con, true); - container_set_resizing(e->h_sib, true); - e->h_con_orig_width = e->h_con->pending.width; - } - } - if (edge & (WLR_EDGE_TOP | WLR_EDGE_BOTTOM)) { - e->edge_y = edge & (WLR_EDGE_TOP | WLR_EDGE_BOTTOM); - e->v_con = container_find_resize_parent(e->con, e->edge_y); - e->v_sib = container_get_resize_sibling(e->v_con, e->edge_y); - - if (e->v_con) { - container_set_resizing(e->v_con, true); - container_set_resizing(e->v_sib, true); - e->v_con_orig_height = e->v_con->pending.height; - } - } - - seat->seatop_impl = &seatop_impl; - seat->seatop_data = e; - - transaction_commit_dirty(); - wlr_seat_pointer_notify_clear_focus(seat->wlr_seat); -} diff --git a/sway/input/switch.c b/sway/input/switch.c deleted file mode 100644 index 7a5398014..000000000 --- a/sway/input/switch.c +++ /dev/null @@ -1,125 +0,0 @@ -#include "sway/config.h" -#include "sway/input/switch.h" -#include "log.h" - -struct sway_switch *sway_switch_create(struct sway_seat *seat, - struct sway_seat_device *device) { - struct sway_switch *switch_device = - calloc(1, sizeof(struct sway_switch)); - if (!sway_assert(switch_device, "could not allocate switch")) { - return NULL; - } - device->switch_device = switch_device; - switch_device->wlr = wlr_switch_from_input_device(device->input_device->wlr_device); - switch_device->seat_device = device; - switch_device->state = WLR_SWITCH_STATE_OFF; - wl_list_init(&switch_device->switch_toggle.link); - sway_log(SWAY_DEBUG, "Allocated switch for device"); - - return switch_device; -} - -static bool sway_switch_trigger_test(enum sway_switch_trigger trigger, - enum wlr_switch_state state) { - switch (trigger) { - case SWAY_SWITCH_TRIGGER_ON: - return state == WLR_SWITCH_STATE_ON; - case SWAY_SWITCH_TRIGGER_OFF: - return state == WLR_SWITCH_STATE_OFF; - case SWAY_SWITCH_TRIGGER_TOGGLE: - return true; - } - abort(); // unreachable -} - -static void execute_binding(struct sway_switch *sway_switch) { - struct sway_seat* seat = sway_switch->seat_device->sway_seat; - bool input_inhibited = seat->exclusive_client != NULL || - server.session_lock.locked; - - list_t *bindings = config->current_mode->switch_bindings; - struct sway_switch_binding *matched_binding = NULL; - for (int i = 0; i < bindings->length; ++i) { - struct sway_switch_binding *binding = bindings->items[i]; - if (binding->type != sway_switch->type) { - continue; - } - if (!sway_switch_trigger_test(binding->trigger, sway_switch->state)) { - continue; - } - if (config->reloading && (binding->trigger == SWAY_SWITCH_TRIGGER_TOGGLE - || (binding->flags & BINDING_RELOAD) == 0)) { - continue; - } - bool binding_locked = binding->flags & BINDING_LOCKED; - if (!binding_locked && input_inhibited) { - continue; - } - - matched_binding = binding; - - if (binding_locked == input_inhibited) { - break; - } - } - - if (matched_binding) { - struct sway_binding *dummy_binding = - calloc(1, sizeof(struct sway_binding)); - dummy_binding->type = BINDING_SWITCH; - dummy_binding->flags = matched_binding->flags; - dummy_binding->command = matched_binding->command; - - seat_execute_command(seat, dummy_binding); - free(dummy_binding); - } -} - -static void handle_switch_toggle(struct wl_listener *listener, void *data) { - struct sway_switch *sway_switch = - wl_container_of(listener, sway_switch, switch_toggle); - struct wlr_switch_toggle_event *event = data; - struct sway_seat *seat = sway_switch->seat_device->sway_seat; - seat_idle_notify_activity(seat, IDLE_SOURCE_SWITCH); - - struct wlr_input_device *wlr_device = - sway_switch->seat_device->input_device->wlr_device; - char *device_identifier = input_device_get_identifier(wlr_device); - sway_log(SWAY_DEBUG, "%s: type %d state %d", device_identifier, - event->switch_type, event->switch_state); - free(device_identifier); - - sway_switch->type = event->switch_type; - sway_switch->state = event->switch_state; - execute_binding(sway_switch); -} - -void sway_switch_configure(struct sway_switch *sway_switch) { - wl_list_remove(&sway_switch->switch_toggle.link); - wl_signal_add(&sway_switch->wlr->events.toggle, - &sway_switch->switch_toggle); - sway_switch->switch_toggle.notify = handle_switch_toggle; - sway_log(SWAY_DEBUG, "Configured switch for device"); -} - -void sway_switch_destroy(struct sway_switch *sway_switch) { - if (!sway_switch) { - return; - } - wl_list_remove(&sway_switch->switch_toggle.link); - free(sway_switch); -} - -void sway_switch_retrigger_bindings_for_all(void) { - struct sway_seat *seat; - wl_list_for_each(seat, &server.input->seats, link) { - struct sway_seat_device *seat_device; - wl_list_for_each(seat_device, &seat->devices, link) { - struct sway_input_device *input_device = seat_device->input_device; - if (input_device->wlr_device->type != WLR_INPUT_DEVICE_SWITCH) { - continue; - } - execute_binding(seat_device->switch_device); - }; - } -} diff --git a/sway/input/tablet.c b/sway/input/tablet.c deleted file mode 100644 index 902cb7eda..000000000 --- a/sway/input/tablet.c +++ /dev/null @@ -1,376 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include "log.h" -#include "sway/input/cursor.h" -#include "sway/input/seat.h" -#include "sway/input/tablet.h" - -#if WLR_HAS_LIBINPUT_BACKEND -#include -#endif - -static void handle_pad_tablet_destroy(struct wl_listener *listener, void *data) { - struct sway_tablet_pad *pad = - wl_container_of(listener, pad, tablet_destroy); - - pad->tablet = NULL; - - wl_list_remove(&pad->tablet_destroy.link); - wl_list_init(&pad->tablet_destroy.link); -} - -static void attach_tablet_pad(struct sway_tablet_pad *tablet_pad, - struct sway_tablet *tablet) { - sway_log(SWAY_DEBUG, "Attaching tablet pad \"%s\" to tablet tool \"%s\"", - tablet_pad->seat_device->input_device->wlr_device->name, - tablet->seat_device->input_device->wlr_device->name); - - tablet_pad->tablet = tablet; - - wl_list_remove(&tablet_pad->tablet_destroy.link); - tablet_pad->tablet_destroy.notify = handle_pad_tablet_destroy; - wl_signal_add(&tablet->seat_device->input_device->wlr_device->events.destroy, - &tablet_pad->tablet_destroy); -} - -struct sway_tablet *sway_tablet_create(struct sway_seat *seat, - struct sway_seat_device *device) { - struct sway_tablet *tablet = - calloc(1, sizeof(struct sway_tablet)); - if (!sway_assert(tablet, "could not allocate sway tablet for seat")) { - return NULL; - } - - wl_list_insert(&seat->cursor->tablets, &tablet->link); - - device->tablet = tablet; - tablet->seat_device = device; - - return tablet; -} - -void sway_configure_tablet(struct sway_tablet *tablet) { - struct wlr_input_device *device = - tablet->seat_device->input_device->wlr_device; - struct sway_seat *seat = tablet->seat_device->sway_seat; - - seat_configure_xcursor(seat); - - if (!tablet->tablet_v2) { - tablet->tablet_v2 = - wlr_tablet_create(server.tablet_v2, seat->wlr_seat, device); - } - -#if WLR_HAS_LIBINPUT_BACKEND - /* Search for a sibling tablet pad */ - if (!wlr_input_device_is_libinput(device)) { - /* We can only do this on libinput devices */ - return; - } - - struct libinput_device_group *group = - libinput_device_get_device_group(wlr_libinput_get_device_handle(device)); - struct sway_tablet_pad *tablet_pad; - wl_list_for_each(tablet_pad, &seat->cursor->tablet_pads, link) { - struct wlr_input_device *pad_device = - tablet_pad->seat_device->input_device->wlr_device; - if (!wlr_input_device_is_libinput(pad_device)) { - continue; - } - - struct libinput_device_group *pad_group = - libinput_device_get_device_group(wlr_libinput_get_device_handle(pad_device)); - - if (pad_group == group) { - attach_tablet_pad(tablet_pad, tablet); - break; - } - } -#endif -} - -void sway_tablet_destroy(struct sway_tablet *tablet) { - if (!tablet) { - return; - } - wl_list_remove(&tablet->link); - free(tablet); -} - -static void handle_tablet_tool_set_cursor(struct wl_listener *listener, void *data) { - struct sway_tablet_tool *tool = - wl_container_of(listener, tool, set_cursor); - struct wlr_tablet_v2_event_cursor *event = data; - - struct sway_cursor *cursor = tool->seat->cursor; - if (!seatop_allows_set_cursor(cursor->seat)) { - return; - } - - struct wl_client *focused_client = NULL; - struct wlr_surface *focused_surface = tool->tablet_v2_tool->focused_surface; - if (focused_surface != NULL) { - focused_client = wl_resource_get_client(focused_surface->resource); - } - - // TODO: check cursor mode - if (focused_client == NULL || - event->seat_client->client != focused_client) { - sway_log(SWAY_DEBUG, "denying request to set cursor from unfocused client"); - return; - } - - cursor_set_image_surface(cursor, event->surface, event->hotspot_x, - event->hotspot_y, focused_client); -} - -static void handle_tablet_tool_destroy(struct wl_listener *listener, void *data) { - struct sway_tablet_tool *tool = - wl_container_of(listener, tool, tool_destroy); - - wl_list_remove(&tool->tool_destroy.link); - wl_list_remove(&tool->set_cursor.link); - - free(tool); -} - -void sway_tablet_tool_configure(struct sway_tablet *tablet, - struct wlr_tablet_tool *wlr_tool) { - struct sway_tablet_tool *tool = - calloc(1, sizeof(struct sway_tablet_tool)); - if (!sway_assert(tool, "could not allocate sway tablet tool for tablet")) { - return; - } - - switch (wlr_tool->type) { - case WLR_TABLET_TOOL_TYPE_LENS: - case WLR_TABLET_TOOL_TYPE_MOUSE: - tool->mode = SWAY_TABLET_TOOL_MODE_RELATIVE; - break; - default: - tool->mode = SWAY_TABLET_TOOL_MODE_ABSOLUTE; - - struct input_config *ic = input_device_get_config( - tablet->seat_device->input_device); - if (!ic) { - break; - } - - for (int i = 0; i < ic->tools->length; i++) { - struct input_config_tool *tool_config = ic->tools->items[i]; - if (tool_config->type == wlr_tool->type) { - tool->mode = tool_config->mode; - break; - } - } - } - - tool->seat = tablet->seat_device->sway_seat; - tool->tablet = tablet; - tool->tablet_v2_tool = - wlr_tablet_tool_create(server.tablet_v2, - tablet->seat_device->sway_seat->wlr_seat, wlr_tool); - - tool->tool_destroy.notify = handle_tablet_tool_destroy; - wl_signal_add(&wlr_tool->events.destroy, &tool->tool_destroy); - - tool->set_cursor.notify = handle_tablet_tool_set_cursor; - wl_signal_add(&tool->tablet_v2_tool->events.set_cursor, - &tool->set_cursor); - - wlr_tool->data = tool; -} - -static void handle_tablet_pad_attach(struct wl_listener *listener, - void *data) { - struct sway_tablet_pad *pad = wl_container_of(listener, pad, attach); - struct wlr_tablet_tool *wlr_tool = data; - struct sway_tablet_tool *tool = wlr_tool->data; - - if (!tool) { - return; - } - - attach_tablet_pad(pad, tool->tablet); -} - -static void handle_tablet_pad_ring(struct wl_listener *listener, void *data) { - struct sway_tablet_pad *pad = wl_container_of(listener, pad, ring); - struct wlr_tablet_pad_ring_event *event = data; - - if (!pad->current_surface) { - return; - } - - wlr_tablet_v2_tablet_pad_notify_ring(pad->tablet_v2_pad, - event->ring, event->position, - event->source == WLR_TABLET_PAD_RING_SOURCE_FINGER, - event->time_msec); -} - -static void handle_tablet_pad_strip(struct wl_listener *listener, void *data) { - struct sway_tablet_pad *pad = wl_container_of(listener, pad, strip); - struct wlr_tablet_pad_strip_event *event = data; - - if (!pad->current_surface) { - return; - } - - wlr_tablet_v2_tablet_pad_notify_strip(pad->tablet_v2_pad, - event->strip, event->position, - event->source == WLR_TABLET_PAD_STRIP_SOURCE_FINGER, - event->time_msec); -} - -static void handle_tablet_pad_button(struct wl_listener *listener, void *data) { - struct sway_tablet_pad *pad = wl_container_of(listener, pad, button); - struct wlr_tablet_pad_button_event *event = data; - - if (!pad->current_surface) { - return; - } - - wlr_tablet_v2_tablet_pad_notify_mode(pad->tablet_v2_pad, - event->group, event->mode, event->time_msec); - - wlr_tablet_v2_tablet_pad_notify_button(pad->tablet_v2_pad, - event->button, event->time_msec, - (enum zwp_tablet_pad_v2_button_state)event->state); -} - -struct sway_tablet_pad *sway_tablet_pad_create(struct sway_seat *seat, - struct sway_seat_device *device) { - struct sway_tablet_pad *tablet_pad = - calloc(1, sizeof(struct sway_tablet_pad)); - if (!sway_assert(tablet_pad, "could not allocate sway tablet")) { - return NULL; - } - - tablet_pad->wlr = wlr_tablet_pad_from_input_device(device->input_device->wlr_device); - tablet_pad->seat_device = device; - wl_list_init(&tablet_pad->attach.link); - wl_list_init(&tablet_pad->button.link); - wl_list_init(&tablet_pad->strip.link); - wl_list_init(&tablet_pad->ring.link); - wl_list_init(&tablet_pad->surface_destroy.link); - wl_list_init(&tablet_pad->tablet_destroy.link); - - wl_list_insert(&seat->cursor->tablet_pads, &tablet_pad->link); - - return tablet_pad; -} - -void sway_configure_tablet_pad(struct sway_tablet_pad *tablet_pad) { - struct wlr_input_device *wlr_device = - tablet_pad->seat_device->input_device->wlr_device; - struct sway_seat *seat = tablet_pad->seat_device->sway_seat; - - if (!tablet_pad->tablet_v2_pad) { - tablet_pad->tablet_v2_pad = - wlr_tablet_pad_create(server.tablet_v2, seat->wlr_seat, wlr_device); - } - - wl_list_remove(&tablet_pad->attach.link); - tablet_pad->attach.notify = handle_tablet_pad_attach; - wl_signal_add(&tablet_pad->wlr->events.attach_tablet, - &tablet_pad->attach); - - wl_list_remove(&tablet_pad->button.link); - tablet_pad->button.notify = handle_tablet_pad_button; - wl_signal_add(&tablet_pad->wlr->events.button, &tablet_pad->button); - - wl_list_remove(&tablet_pad->strip.link); - tablet_pad->strip.notify = handle_tablet_pad_strip; - wl_signal_add(&tablet_pad->wlr->events.strip, &tablet_pad->strip); - - wl_list_remove(&tablet_pad->ring.link); - tablet_pad->ring.notify = handle_tablet_pad_ring; - wl_signal_add(&tablet_pad->wlr->events.ring, &tablet_pad->ring); - -#if WLR_HAS_LIBINPUT_BACKEND - /* Search for a sibling tablet */ - if (!wlr_input_device_is_libinput(wlr_device)) { - /* We can only do this on libinput devices */ - return; - } - - struct libinput_device_group *group = - libinput_device_get_device_group(wlr_libinput_get_device_handle(wlr_device)); - struct sway_tablet *tool; - wl_list_for_each(tool, &seat->cursor->tablets, link) { - struct wlr_input_device *tablet = - tool->seat_device->input_device->wlr_device; - if (!wlr_input_device_is_libinput(tablet)) { - continue; - } - - struct libinput_device_group *tablet_group = - libinput_device_get_device_group(wlr_libinput_get_device_handle(tablet)); - - if (tablet_group == group) { - attach_tablet_pad(tablet_pad, tool); - break; - } - } -#endif -} - -void sway_tablet_pad_destroy(struct sway_tablet_pad *tablet_pad) { - if (!tablet_pad) { - return; - } - - wl_list_remove(&tablet_pad->link); - wl_list_remove(&tablet_pad->attach.link); - wl_list_remove(&tablet_pad->button.link); - wl_list_remove(&tablet_pad->strip.link); - wl_list_remove(&tablet_pad->ring.link); - wl_list_remove(&tablet_pad->surface_destroy.link); - wl_list_remove(&tablet_pad->tablet_destroy.link); - - free(tablet_pad); -} - -static void handle_pad_tablet_surface_destroy(struct wl_listener *listener, - void *data) { - struct sway_tablet_pad *tablet_pad = - wl_container_of(listener, tablet_pad, surface_destroy); - - sway_tablet_pad_set_focus(tablet_pad, NULL); -} - -void sway_tablet_pad_set_focus(struct sway_tablet_pad *tablet_pad, - struct wlr_surface *surface) { - if (!tablet_pad || !tablet_pad->tablet) { - return; - } - - if (surface == tablet_pad->current_surface) { - return; - } - - /* Leave current surface */ - if (tablet_pad->current_surface) { - wlr_tablet_v2_tablet_pad_notify_leave(tablet_pad->tablet_v2_pad, - tablet_pad->current_surface); - wl_list_remove(&tablet_pad->surface_destroy.link); - wl_list_init(&tablet_pad->surface_destroy.link); - tablet_pad->current_surface = NULL; - } - - if (surface == NULL || - !wlr_surface_accepts_tablet_v2(tablet_pad->tablet->tablet_v2, surface)) { - return; - } - - wlr_tablet_v2_tablet_pad_notify_enter(tablet_pad->tablet_v2_pad, - tablet_pad->tablet->tablet_v2, surface); - - tablet_pad->current_surface = surface; - tablet_pad->surface_destroy.notify = handle_pad_tablet_surface_destroy; - wl_signal_add(&surface->events.destroy, &tablet_pad->surface_destroy); -} diff --git a/sway/input/text_input.c b/sway/input/text_input.c deleted file mode 100644 index fec11e776..000000000 --- a/sway/input/text_input.c +++ /dev/null @@ -1,684 +0,0 @@ -#include -#include -#include -#include "log.h" -#include "sway/input/seat.h" -#include "sway/input/text_input.h" -#include "sway/tree/view.h" -#include "sway/tree/container.h" -#include "sway/desktop.h" -#include "sway/output.h" -#include "sway/layers.h" - -static struct sway_text_input *relay_get_focusable_text_input( - struct sway_input_method_relay *relay) { - struct sway_text_input *text_input = NULL; - wl_list_for_each(text_input, &relay->text_inputs, link) { - if (text_input->pending_focused_surface) { - return text_input; - } - } - return NULL; -} - -static struct sway_text_input *relay_get_focused_text_input( - struct sway_input_method_relay *relay) { - struct sway_text_input *text_input = NULL; - wl_list_for_each(text_input, &relay->text_inputs, link) { - if (text_input->input->focused_surface) { - return text_input; - } - } - return NULL; -} - -// damage the popup -void sway_input_popup_damage(struct sway_input_popup *popup) { - if (!popup->visible) { - return; - } - - struct sway_text_input *text_input = - relay_get_focused_text_input(popup->relay); - if (text_input == NULL || text_input->input->focused_surface == NULL) { - return; - } - - struct wlr_surface *focused_surface = text_input->input->focused_surface; - struct wlr_layer_surface_v1 *layer_surface = - wlr_layer_surface_v1_try_from_wlr_surface(focused_surface); - if (layer_surface != NULL) { - struct sway_layer_surface *layer = - layer_from_wlr_layer_surface_v1(layer_surface); - output_damage_surface(layer->layer_surface->output->data, - layer->geo.x + popup->x, layer->geo.y + popup->y, - popup->popup_surface->surface, true); - return; - } - - struct sway_view *view = view_from_wlr_surface( - text_input->input->focused_surface); - if (view->container == NULL) { - sway_log(SWAY_INFO, "Tried to damage popup, but view is gone"); - return; - } - desktop_damage_surface(popup->popup_surface->surface, - view->container->surface_x - view->geometry.x + popup->x, - view->container->surface_y - view->geometry.y + popup->y, true); -} - -static void input_popup_update(struct sway_input_popup *popup) { - sway_input_popup_damage(popup); - - struct sway_text_input *text_input = - relay_get_focused_text_input(popup->relay); - - if (text_input == NULL || text_input->input->focused_surface == NULL) { - return; - } - - if (!popup->popup_surface->surface->mapped) { - return; - } - - bool cursor_rect = text_input->input->current.features - & WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE; - struct wlr_surface *focused_surface = text_input->input->focused_surface; - struct wlr_box cursor = text_input->input->current.cursor_rectangle; - - struct wlr_output *output; - struct wlr_box output_box; - struct wlr_box parent; - struct wlr_layer_surface_v1 *layer_surface = - wlr_layer_surface_v1_try_from_wlr_surface(focused_surface); - if (layer_surface != NULL) { - struct sway_layer_surface *layer = - layer_from_wlr_layer_surface_v1(layer_surface); - output = layer->layer_surface->output; - wlr_output_layout_get_box(root->output_layout, output, &output_box); - parent = layer->geo; - parent.x += output_box.x; - parent.y += output_box.y; - } else { - struct sway_view *view = view_from_wlr_surface(focused_surface); - output = wlr_output_layout_output_at(root->output_layout, - view->container->surface_x + view->geometry.x, - view->container->surface_y + view->geometry.y); - wlr_output_layout_get_box(root->output_layout, output, &output_box); - parent.x = view->container->surface_x + view->geometry.x; - parent.y = view->container->surface_y + view->geometry.y; - parent.width = view->geometry.width; - parent.height = view->geometry.height; - } - - if (!cursor_rect) { - cursor.x = 0; - cursor.y = 0; - cursor.width = parent.width; - cursor.height = parent.height; - } - - int popup_width = popup->popup_surface->surface->current.width; - int popup_height = popup->popup_surface->surface->current.height; - int x1 = parent.x + cursor.x; - int x2 = parent.x + cursor.x + cursor.width; - int y1 = parent.y + cursor.y; - int y2 = parent.y + cursor.y + cursor.height; - int x = x1; - int y = y2; - - int available_right = output_box.x + output_box.width - x1; - int available_left = x2 - output_box.x; - if (available_right < popup_width && available_left > available_right) { - x = x2 - popup_width; - } - - int available_down = output_box.y + output_box.height - y2; - int available_up = y1 - output_box.y; - if (available_down < popup_height && available_up > available_down) { - y = y1 - popup_height; - } - - popup->x = x - parent.x; - popup->y = y - parent.y; - - // Hide popup if cursor position is completely out of bounds - bool x1_in_bounds = (cursor.x >= 0 && cursor.x < parent.width); - bool y1_in_bounds = (cursor.y >= 0 && cursor.y < parent.height); - bool x2_in_bounds = (cursor.x + cursor.width >= 0 - && cursor.x + cursor.width < parent.width); - bool y2_in_bounds = (cursor.y + cursor.height >= 0 - && cursor.y + cursor.height < parent.height); - popup->visible = - (x1_in_bounds && y1_in_bounds) || (x2_in_bounds && y2_in_bounds); - - if (cursor_rect) { - struct wlr_box box = { - .x = x1 - x, - .y = y1 - y, - .width = cursor.width, - .height = cursor.height, - }; - wlr_input_popup_surface_v2_send_text_input_rectangle( - popup->popup_surface, &box); - } - - sway_input_popup_damage(popup); -} - -static void surface_send_enter_iterator(struct wlr_surface *surface, - int x, int y, void *data) { - struct wlr_output *wlr_output = data; - float scale = wlr_output->scale; - wlr_surface_send_enter(surface, wlr_output); - - wlr_fractional_scale_v1_notify_scale(surface, scale); - wlr_surface_set_preferred_buffer_scale(surface, ceil(scale)); -} - -static void surface_send_leave_iterator(struct wlr_surface *surface, - int x, int y, void *data) { - struct wlr_output *wlr_output = data; - wlr_surface_send_leave(surface, wlr_output); -} - -static void input_popup_send_outputs(struct sway_input_popup *popup, - wlr_surface_iterator_func_t iterator) { - struct sway_text_input *text_input = - relay_get_focused_text_input(popup->relay); - if (text_input == NULL || text_input->input->focused_surface == NULL) { - return; - } - struct wlr_surface *focused_surface = text_input->input->focused_surface; - struct wlr_layer_surface_v1 *layer_surface = - wlr_layer_surface_v1_try_from_wlr_surface(focused_surface); - if (layer_surface != NULL) { - struct sway_layer_surface *layer = - layer_from_wlr_layer_surface_v1(layer_surface); - wlr_surface_for_each_surface(popup->popup_surface->surface, - iterator, layer->layer_surface->output); - return; - } - struct sway_view *view = view_from_wlr_surface(focused_surface); - for (int i = 0; i < view->container->outputs->length; i++) { - struct sway_output *output = view->container->outputs->items[i]; - wlr_surface_for_each_surface(popup->popup_surface->surface, - iterator, output->wlr_output); - } -} - -static void handle_im_popup_map(struct wl_listener *listener, void *data) { - struct sway_input_popup *popup = - wl_container_of(listener, popup, popup_map); - input_popup_send_outputs(popup, surface_send_enter_iterator); - input_popup_update(popup); -} - -static void handle_im_popup_unmap(struct wl_listener *listener, void *data) { - struct sway_input_popup *popup = - wl_container_of(listener, popup, popup_unmap); - input_popup_send_outputs(popup, surface_send_leave_iterator); - input_popup_update(popup); -} - -static void handle_im_popup_destroy(struct wl_listener *listener, void *data) { - struct sway_input_popup *popup = - wl_container_of(listener, popup, popup_destroy); - wl_list_remove(&popup->focused_surface_unmap.link); - wl_list_remove(&popup->popup_surface_commit.link); - wl_list_remove(&popup->popup_destroy.link); - wl_list_remove(&popup->popup_unmap.link); - wl_list_remove(&popup->popup_map.link); - wl_list_remove(&popup->link); - free(popup); -} - -static void handle_im_popup_surface_commit(struct wl_listener *listener, - void *data) { - struct sway_input_popup *popup = - wl_container_of(listener, popup, popup_surface_commit); - input_popup_update(popup); -} - -static void handle_im_focused_surface_unmap( - struct wl_listener *listener, void *data) { - struct sway_input_popup *popup = - wl_container_of(listener, popup, focused_surface_unmap); - input_popup_update(popup); -} - -static void input_popup_set_focus(struct sway_input_popup *popup, - struct wlr_surface *surface) { - wl_list_remove(&popup->focused_surface_unmap.link); - - if (surface == NULL) { - wl_list_init(&popup->focused_surface_unmap.link); - input_popup_update(popup); - return; - } - struct wlr_layer_surface_v1 *layer_surface = - wlr_layer_surface_v1_try_from_wlr_surface(surface); - if (layer_surface != NULL) { - struct sway_layer_surface *layer = - layer_from_wlr_layer_surface_v1(layer_surface); - wl_signal_add( - &layer->layer_surface->surface->events.unmap, &popup->focused_surface_unmap); - input_popup_update(popup); - return; - } - - struct sway_view *view = view_from_wlr_surface(surface); - wl_signal_add(&view->events.unmap, &popup->focused_surface_unmap); - - // Since the focus has changed, the popup may have to adjust -} - -static void handle_im_new_popup_surface(struct wl_listener *listener, - void *data) { - struct sway_input_method_relay *relay = wl_container_of(listener, relay, - input_method_new_popup_surface); - struct sway_input_popup *popup = calloc(1, sizeof(*popup)); - popup->relay = relay; - popup->popup_surface = data; - popup->popup_surface->data = popup; - - wl_signal_add(&popup->popup_surface->surface->events.map, &popup->popup_map); - popup->popup_map.notify = handle_im_popup_map; - wl_signal_add( - &popup->popup_surface->surface->events.unmap, &popup->popup_unmap); - popup->popup_unmap.notify = handle_im_popup_unmap; - wl_signal_add( - &popup->popup_surface->events.destroy, &popup->popup_destroy); - popup->popup_destroy.notify = handle_im_popup_destroy; - wl_signal_add(&popup->popup_surface->surface->events.commit, - &popup->popup_surface_commit); - popup->popup_surface_commit.notify = handle_im_popup_surface_commit; - wl_list_init(&popup->focused_surface_unmap.link); - popup->focused_surface_unmap.notify = handle_im_focused_surface_unmap; - - struct sway_text_input *text_input = relay_get_focused_text_input(relay); - if (text_input != NULL) { - input_popup_set_focus(popup, text_input->input->focused_surface); - } else { - input_popup_set_focus(popup, NULL); - } - - wl_list_insert(&relay->input_popups, &popup->link); -} - -bool sway_input_popup_get_position( - struct sway_input_popup *popup, int *lx, int *ly) { - struct sway_text_input *text_input = - relay_get_focused_text_input(popup->relay); - if (text_input == NULL || text_input->input->focused_surface == NULL) { - *lx = 0; - *ly = 0; - return false; - } - - struct wlr_surface *focused_surface = text_input->input->focused_surface; - struct wlr_layer_surface_v1 *layer_surface = - wlr_layer_surface_v1_try_from_wlr_surface(focused_surface); - if (layer_surface != NULL) { - struct sway_layer_surface *layer = - layer_from_wlr_layer_surface_v1(layer_surface); - *lx = layer->geo.x + popup->x; - *ly = layer->geo.y + popup->y; - return true; - } - - - struct sway_view *view = view_from_wlr_surface( - text_input->input->focused_surface); - if (view->container == NULL || view == NULL) { - sway_log(SWAY_INFO, "Tried to find popup, but view is gone"); - return false; - } - *lx = view->container->surface_x - view->geometry.x + popup->x; - *ly = view->container->surface_y - view->geometry.y + popup->y; - return true; -} - -static void text_input_send_enter(struct sway_text_input *text_input, - struct wlr_surface *surface) { - wlr_text_input_v3_send_enter(text_input->input, surface); - struct sway_input_popup *popup; - wl_list_for_each(popup, &text_input->relay->input_popups, link) { - input_popup_set_focus(popup, surface); - } -} - -static void text_input_send_leave(struct sway_text_input *text_input, - struct wlr_surface *surface) { - wlr_text_input_v3_send_leave(text_input->input); - if (text_input->input->focused_surface == surface) { - struct sway_input_popup *popup; - wl_list_for_each(popup, &text_input->relay->input_popups, link) { - input_popup_set_focus(popup, NULL); - } - } -} - -static void handle_im_commit(struct wl_listener *listener, void *data) { - struct sway_input_method_relay *relay = wl_container_of(listener, relay, - input_method_commit); - - struct sway_text_input *text_input = relay_get_focused_text_input(relay); - if (!text_input) { - return; - } - struct wlr_input_method_v2 *context = data; - assert(context == relay->input_method); - if (context->current.preedit.text) { - wlr_text_input_v3_send_preedit_string(text_input->input, - context->current.preedit.text, - context->current.preedit.cursor_begin, - context->current.preedit.cursor_end); - } - if (context->current.commit_text) { - wlr_text_input_v3_send_commit_string(text_input->input, - context->current.commit_text); - } - if (context->current.delete.before_length - || context->current.delete.after_length) { - wlr_text_input_v3_send_delete_surrounding_text(text_input->input, - context->current.delete.before_length, - context->current.delete.after_length); - } - wlr_text_input_v3_send_done(text_input->input); -} - -static void handle_im_keyboard_grab_destroy(struct wl_listener *listener, void *data) { - struct sway_input_method_relay *relay = wl_container_of(listener, relay, - input_method_keyboard_grab_destroy); - struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data; - wl_list_remove(&relay->input_method_keyboard_grab_destroy.link); - - if (keyboard_grab->keyboard) { - // send modifier state to original client - wlr_seat_keyboard_notify_modifiers(keyboard_grab->input_method->seat, - &keyboard_grab->keyboard->modifiers); - } -} - -static void handle_im_grab_keyboard(struct wl_listener *listener, void *data) { - struct sway_input_method_relay *relay = wl_container_of(listener, relay, - input_method_grab_keyboard); - struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data; - - // send modifier state to grab - struct wlr_keyboard *active_keyboard = wlr_seat_get_keyboard(relay->seat->wlr_seat); - wlr_input_method_keyboard_grab_v2_set_keyboard(keyboard_grab, - active_keyboard); - - wl_signal_add(&keyboard_grab->events.destroy, - &relay->input_method_keyboard_grab_destroy); - relay->input_method_keyboard_grab_destroy.notify = - handle_im_keyboard_grab_destroy; -} - -static void text_input_set_pending_focused_surface( - struct sway_text_input *text_input, struct wlr_surface *surface) { - wl_list_remove(&text_input->pending_focused_surface_destroy.link); - text_input->pending_focused_surface = surface; - - if (surface) { - wl_signal_add(&surface->events.destroy, - &text_input->pending_focused_surface_destroy); - } else { - wl_list_init(&text_input->pending_focused_surface_destroy.link); - } -} - -static void handle_im_destroy(struct wl_listener *listener, void *data) { - struct sway_input_method_relay *relay = wl_container_of(listener, relay, - input_method_destroy); - struct wlr_input_method_v2 *context = data; - assert(context == relay->input_method); - relay->input_method = NULL; - struct sway_text_input *text_input = relay_get_focused_text_input(relay); - if (text_input) { - // keyboard focus is still there, so keep the surface at hand in case - // the input method returns - text_input_set_pending_focused_surface(text_input, - text_input->input->focused_surface); - text_input_send_leave(text_input, text_input->input->focused_surface); - } -} - -static void relay_send_im_state(struct sway_input_method_relay *relay, - struct wlr_text_input_v3 *input) { - struct wlr_input_method_v2 *input_method = relay->input_method; - if (!input_method) { - sway_log(SWAY_INFO, "Sending IM_DONE but im is gone"); - return; - } - // TODO: only send each of those if they were modified - if (input->active_features & WLR_TEXT_INPUT_V3_FEATURE_SURROUNDING_TEXT) { - wlr_input_method_v2_send_surrounding_text(input_method, - input->current.surrounding.text, input->current.surrounding.cursor, - input->current.surrounding.anchor); - } - wlr_input_method_v2_send_text_change_cause(input_method, - input->current.text_change_cause); - if (input->active_features & WLR_TEXT_INPUT_V3_FEATURE_CONTENT_TYPE) { - wlr_input_method_v2_send_content_type(input_method, - input->current.content_type.hint, - input->current.content_type.purpose); - } - struct sway_input_popup *popup; - wl_list_for_each(popup, &relay->input_popups, link) { - // send_text_input_rectangle is called in this function - input_popup_update(popup); - } - wlr_input_method_v2_send_done(input_method); - // TODO: pass intent -} - -static void handle_text_input_enable(struct wl_listener *listener, void *data) { - struct sway_text_input *text_input = wl_container_of(listener, text_input, - text_input_enable); - if (text_input->relay->input_method == NULL) { - sway_log(SWAY_INFO, "Enabling text input when input method is gone"); - return; - } - wlr_input_method_v2_send_activate(text_input->relay->input_method); - relay_send_im_state(text_input->relay, text_input->input); -} - -static void handle_text_input_commit(struct wl_listener *listener, - void *data) { - struct sway_text_input *text_input = wl_container_of(listener, text_input, - text_input_commit); - if (!text_input->input->current_enabled) { - sway_log(SWAY_INFO, "Inactive text input tried to commit an update"); - return; - } - sway_log(SWAY_DEBUG, "Text input committed update"); - if (text_input->relay->input_method == NULL) { - sway_log(SWAY_INFO, "Text input committed, but input method is gone"); - return; - } - relay_send_im_state(text_input->relay, text_input->input); -} - -static void relay_disable_text_input(struct sway_input_method_relay *relay, - struct sway_text_input *text_input) { - if (relay->input_method == NULL) { - sway_log(SWAY_DEBUG, "Disabling text input, but input method is gone"); - return; - } - wlr_input_method_v2_send_deactivate(relay->input_method); - relay_send_im_state(relay, text_input->input); -} - -static void handle_text_input_disable(struct wl_listener *listener, - void *data) { - struct sway_text_input *text_input = wl_container_of(listener, text_input, - text_input_disable); - if (text_input->input->focused_surface == NULL) { - sway_log(SWAY_DEBUG, "Disabling text input, but no longer focused"); - return; - } - relay_disable_text_input(text_input->relay, text_input); -} - -static void handle_text_input_destroy(struct wl_listener *listener, - void *data) { - struct sway_text_input *text_input = wl_container_of(listener, text_input, - text_input_destroy); - - if (text_input->input->current_enabled) { - relay_disable_text_input(text_input->relay, text_input); - } - text_input_set_pending_focused_surface(text_input, NULL); - wl_list_remove(&text_input->text_input_commit.link); - wl_list_remove(&text_input->text_input_destroy.link); - wl_list_remove(&text_input->text_input_disable.link); - wl_list_remove(&text_input->text_input_enable.link); - wl_list_remove(&text_input->link); - free(text_input); -} - -static void handle_pending_focused_surface_destroy(struct wl_listener *listener, - void *data) { - struct sway_text_input *text_input = wl_container_of(listener, text_input, - pending_focused_surface_destroy); - struct wlr_surface *surface = data; - assert(text_input->pending_focused_surface == surface); - text_input->pending_focused_surface = NULL; - wl_list_remove(&text_input->pending_focused_surface_destroy.link); - wl_list_init(&text_input->pending_focused_surface_destroy.link); -} - -struct sway_text_input *sway_text_input_create( - struct sway_input_method_relay *relay, - struct wlr_text_input_v3 *text_input) { - struct sway_text_input *input = calloc(1, sizeof(struct sway_text_input)); - if (!input) { - return NULL; - } - input->input = text_input; - input->relay = relay; - - wl_list_insert(&relay->text_inputs, &input->link); - - input->text_input_enable.notify = handle_text_input_enable; - wl_signal_add(&text_input->events.enable, &input->text_input_enable); - - input->text_input_commit.notify = handle_text_input_commit; - wl_signal_add(&text_input->events.commit, &input->text_input_commit); - - input->text_input_disable.notify = handle_text_input_disable; - wl_signal_add(&text_input->events.disable, &input->text_input_disable); - - input->text_input_destroy.notify = handle_text_input_destroy; - wl_signal_add(&text_input->events.destroy, &input->text_input_destroy); - - input->pending_focused_surface_destroy.notify = - handle_pending_focused_surface_destroy; - wl_list_init(&input->pending_focused_surface_destroy.link); - return input; -} - -static void relay_handle_text_input(struct wl_listener *listener, - void *data) { - struct sway_input_method_relay *relay = wl_container_of(listener, relay, - text_input_new); - struct wlr_text_input_v3 *wlr_text_input = data; - if (relay->seat->wlr_seat != wlr_text_input->seat) { - return; - } - - sway_text_input_create(relay, wlr_text_input); -} - -static void relay_handle_input_method(struct wl_listener *listener, - void *data) { - struct sway_input_method_relay *relay = wl_container_of(listener, relay, - input_method_new); - struct wlr_input_method_v2 *input_method = data; - if (relay->seat->wlr_seat != input_method->seat) { - return; - } - - if (relay->input_method != NULL) { - sway_log(SWAY_INFO, "Attempted to connect second input method to a seat"); - wlr_input_method_v2_send_unavailable(input_method); - return; - } - - relay->input_method = input_method; - wl_signal_add(&relay->input_method->events.commit, - &relay->input_method_commit); - relay->input_method_commit.notify = handle_im_commit; - wl_signal_add(&relay->input_method->events.new_popup_surface, - &relay->input_method_new_popup_surface); - relay->input_method_new_popup_surface.notify = handle_im_new_popup_surface; - wl_signal_add(&relay->input_method->events.grab_keyboard, - &relay->input_method_grab_keyboard); - relay->input_method_grab_keyboard.notify = handle_im_grab_keyboard; - wl_signal_add(&relay->input_method->events.destroy, - &relay->input_method_destroy); - relay->input_method_destroy.notify = handle_im_destroy; - - struct sway_text_input *text_input = relay_get_focusable_text_input(relay); - if (text_input) { - text_input_send_enter(text_input, text_input->pending_focused_surface); - text_input_set_pending_focused_surface(text_input, NULL); - } -} - -void sway_input_method_relay_init(struct sway_seat *seat, - struct sway_input_method_relay *relay) { - relay->seat = seat; - wl_list_init(&relay->text_inputs); - wl_list_init(&relay->input_popups); - - relay->text_input_new.notify = relay_handle_text_input; - wl_signal_add(&server.text_input->events.text_input, - &relay->text_input_new); - - relay->input_method_new.notify = relay_handle_input_method; - wl_signal_add( - &server.input_method->events.input_method, - &relay->input_method_new); -} - -void sway_input_method_relay_finish(struct sway_input_method_relay *relay) { - wl_list_remove(&relay->input_method_new.link); - wl_list_remove(&relay->text_input_new.link); -} - -void sway_input_method_relay_set_focus(struct sway_input_method_relay *relay, - struct wlr_surface *surface) { - struct sway_text_input *text_input; - wl_list_for_each(text_input, &relay->text_inputs, link) { - if (text_input->pending_focused_surface) { - assert(text_input->input->focused_surface == NULL); - if (surface != text_input->pending_focused_surface) { - text_input_set_pending_focused_surface(text_input, NULL); - } - } else if (text_input->input->focused_surface) { - assert(text_input->pending_focused_surface == NULL); - if (surface != text_input->input->focused_surface) { - text_input_send_leave( - text_input, text_input->input->focused_surface); - relay_disable_text_input(relay, text_input); - } else { - sway_log(SWAY_DEBUG, "IM relay set_focus already focused"); - continue; - } - } - - if (surface - && wl_resource_get_client(text_input->input->resource) - == wl_resource_get_client(surface->resource)) { - if (relay->input_method) { - text_input_send_enter(text_input, surface); - } else { - text_input_set_pending_focused_surface(text_input, surface); - } - } - } -} diff --git a/sway/ipc-json.c b/sway/ipc-json.c deleted file mode 100644 index d5866ef6b..000000000 --- a/sway/ipc-json.c +++ /dev/null @@ -1,1481 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "config.h" -#include "log.h" -#include "sway/config.h" -#include "sway/ipc-json.h" -#include "sway/layers.h" -#include "sway/tree/container.h" -#include "sway/tree/view.h" -#include "sway/tree/workspace.h" -#include "sway/output.h" -#include "sway/input/input-manager.h" -#include "sway/input/cursor.h" -#include "sway/input/seat.h" -#include "wlr-layer-shell-unstable-v1-protocol.h" -#include "sway/desktop/idle_inhibit_v1.h" - -#if WLR_HAS_LIBINPUT_BACKEND -#include -#endif - -static const int i3_output_id = INT32_MAX; -static const int i3_scratch_id = INT32_MAX - 1; - -static const char *ipc_json_node_type_description(enum sway_node_type node_type) { - switch (node_type) { - case N_ROOT: - return "root"; - case N_OUTPUT: - return "output"; - case N_WORKSPACE: - return "workspace"; - case N_CONTAINER: - return "con"; - } - return "none"; -} - -static const char *ipc_json_layout_description(enum sway_container_layout l) { - switch (l) { - case L_VERT: - return "splitv"; - case L_HORIZ: - return "splith"; - case L_TABBED: - return "tabbed"; - case L_STACKED: - return "stacked"; - case L_NONE: - break; - } - return "none"; -} - -static const char *ipc_json_orientation_description(enum sway_container_layout l) { - switch (l) { - case L_VERT: - return "vertical"; - case L_HORIZ: - return "horizontal"; - default: - return "none"; - } -} - -static const char *ipc_json_border_description(enum sway_container_border border) { - switch (border) { - case B_NONE: - return "none"; - case B_PIXEL: - return "pixel"; - case B_NORMAL: - return "normal"; - case B_CSD: - return "csd"; - } - return "unknown"; -} - -static const char *ipc_json_output_transform_description(enum wl_output_transform transform) { - switch (transform) { - case WL_OUTPUT_TRANSFORM_NORMAL: - return "normal"; - case WL_OUTPUT_TRANSFORM_90: - // Sway uses clockwise transforms, while WL_OUTPUT_TRANSFORM_* describes - // anti-clockwise transforms. - return "270"; - case WL_OUTPUT_TRANSFORM_180: - return "180"; - case WL_OUTPUT_TRANSFORM_270: - // Transform also inverted here. - return "90"; - case WL_OUTPUT_TRANSFORM_FLIPPED: - return "flipped"; - case WL_OUTPUT_TRANSFORM_FLIPPED_90: - // Inverted. - return "flipped-270"; - case WL_OUTPUT_TRANSFORM_FLIPPED_180: - return "flipped-180"; - case WL_OUTPUT_TRANSFORM_FLIPPED_270: - // Inverted. - return "flipped-90"; - } - return NULL; -} - -static const char *ipc_json_output_adaptive_sync_status_description( - enum wlr_output_adaptive_sync_status status) { - switch (status) { - case WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED: - return "disabled"; - case WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED: - return "enabled"; - } - return NULL; -} - -static const char *ipc_json_output_mode_aspect_ratio_description( - enum wlr_output_mode_aspect_ratio aspect_ratio) { - switch (aspect_ratio) { - case WLR_OUTPUT_MODE_ASPECT_RATIO_NONE: - return "none"; - case WLR_OUTPUT_MODE_ASPECT_RATIO_4_3: - return "4:3"; - case WLR_OUTPUT_MODE_ASPECT_RATIO_16_9: - return "16:9"; - case WLR_OUTPUT_MODE_ASPECT_RATIO_64_27: - return "64:27"; - case WLR_OUTPUT_MODE_ASPECT_RATIO_256_135: - return "256:135"; - } - return NULL; -} - -static json_object *ipc_json_output_mode_description( - const struct wlr_output_mode *mode) { - const char *pic_ar = - ipc_json_output_mode_aspect_ratio_description(mode->picture_aspect_ratio); - json_object *mode_object = json_object_new_object(); - json_object_object_add(mode_object, "width", - json_object_new_int(mode->width)); - json_object_object_add(mode_object, "height", - json_object_new_int(mode->height)); - json_object_object_add(mode_object, "refresh", - json_object_new_int(mode->refresh)); - json_object_object_add(mode_object, "picture_aspect_ratio", - json_object_new_string(pic_ar)); - return mode_object; -} - -#if HAVE_XWAYLAND -static const char *ipc_json_xwindow_type_description(struct sway_view *view) { - struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface; - struct sway_xwayland *xwayland = &server.xwayland; - - for (size_t i = 0; i < surface->window_type_len; ++i) { - xcb_atom_t type = surface->window_type[i]; - if (type == xwayland->atoms[NET_WM_WINDOW_TYPE_NORMAL]) { - return "normal"; - } else if (type == xwayland->atoms[NET_WM_WINDOW_TYPE_DIALOG]) { - return "dialog"; - } else if (type == xwayland->atoms[NET_WM_WINDOW_TYPE_UTILITY]) { - return "utility"; - } else if (type == xwayland->atoms[NET_WM_WINDOW_TYPE_TOOLBAR]) { - return "toolbar"; - } else if (type == xwayland->atoms[NET_WM_WINDOW_TYPE_SPLASH]) { - return "splash"; - } else if (type == xwayland->atoms[NET_WM_WINDOW_TYPE_MENU]) { - return "menu"; - } else if (type == xwayland->atoms[NET_WM_WINDOW_TYPE_DROPDOWN_MENU]) { - return "dropdown_menu"; - } else if (type == xwayland->atoms[NET_WM_WINDOW_TYPE_POPUP_MENU]) { - return "popup_menu"; - } else if (type == xwayland->atoms[NET_WM_WINDOW_TYPE_TOOLTIP]) { - return "tooltip"; - } else if (type == xwayland->atoms[NET_WM_WINDOW_TYPE_NOTIFICATION]) { - return "notification"; - } else { - return "unknown"; - } - } - - return "unknown"; -} -#endif - -static const char *ipc_json_user_idle_inhibitor_description(enum sway_idle_inhibit_mode mode) { - switch (mode) { - case INHIBIT_IDLE_FOCUS: - return "focus"; - case INHIBIT_IDLE_FULLSCREEN: - return "fullscreen"; - case INHIBIT_IDLE_OPEN: - return "open"; - case INHIBIT_IDLE_VISIBLE: - return "visible"; - case INHIBIT_IDLE_APPLICATION: - return NULL; - } - return NULL; -} - -static const char *ipc_json_content_type_description(enum wp_content_type_v1_type type) { - switch (type) { - case WP_CONTENT_TYPE_V1_TYPE_NONE: - return "none"; - case WP_CONTENT_TYPE_V1_TYPE_PHOTO: - return "photo"; - case WP_CONTENT_TYPE_V1_TYPE_VIDEO: - return "video"; - case WP_CONTENT_TYPE_V1_TYPE_GAME: - return "game"; - } - return NULL; -} - -json_object *ipc_json_get_version(void) { - int major = 0, minor = 0, patch = 0; - json_object *version = json_object_new_object(); - - sscanf(SWAY_VERSION, "%d.%d.%d", &major, &minor, &patch); - - json_object_object_add(version, "human_readable", json_object_new_string(SWAY_VERSION)); - json_object_object_add(version, "sway_original_version", json_object_new_string(SWAY_ORIGINAL_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)); - json_object_object_add(version, "loaded_config_file_name", json_object_new_string(config->current_config_path)); - - return version; -} - -static json_object *ipc_json_create_rect(struct wlr_box *box) { - json_object *rect = json_object_new_object(); - - json_object_object_add(rect, "x", json_object_new_int(box->x)); - json_object_object_add(rect, "y", json_object_new_int(box->y)); - json_object_object_add(rect, "width", json_object_new_int(box->width)); - json_object_object_add(rect, "height", json_object_new_int(box->height)); - - return rect; -} - -static json_object *ipc_json_create_empty_rect(void) { - struct wlr_box empty = {0, 0, 0, 0}; - - return ipc_json_create_rect(&empty); -} - -static json_object *ipc_json_create_node(int id, const char* type, char *name, - bool focused, json_object *focus, struct wlr_box *box) { - json_object *object = json_object_new_object(); - - json_object_object_add(object, "id", json_object_new_int(id)); - json_object_object_add(object, "type", json_object_new_string(type)); - json_object_object_add(object, "orientation", - json_object_new_string( - ipc_json_orientation_description(L_HORIZ))); - json_object_object_add(object, "percent", NULL); - json_object_object_add(object, "urgent", json_object_new_boolean(false)); - json_object_object_add(object, "marks", json_object_new_array()); - json_object_object_add(object, "focused", json_object_new_boolean(focused)); - json_object_object_add(object, "layout", - json_object_new_string( - ipc_json_layout_description(L_HORIZ))); - - // set default values to be compatible with i3 - json_object_object_add(object, "border", - json_object_new_string( - ipc_json_border_description(B_NONE))); - json_object_object_add(object, "current_border_width", - json_object_new_int(0)); - json_object_object_add(object, "rect", ipc_json_create_rect(box)); - json_object_object_add(object, "deco_rect", ipc_json_create_empty_rect()); - json_object_object_add(object, "window_rect", ipc_json_create_empty_rect()); - json_object_object_add(object, "geometry", ipc_json_create_empty_rect()); - json_object_object_add(object, "name", - name ? json_object_new_string(name) : NULL); - json_object_object_add(object, "window", NULL); - json_object_object_add(object, "nodes", json_object_new_array()); - json_object_object_add(object, "floating_nodes", json_object_new_array()); - json_object_object_add(object, "focus", focus); - json_object_object_add(object, "fullscreen_mode", json_object_new_int(0)); - json_object_object_add(object, "sticky", json_object_new_boolean(false)); - - return object; -} - -static void ipc_json_describe_wlr_output(struct wlr_output *wlr_output, - struct sway_output *output, json_object *object) { - json_object_object_add(object, "primary", json_object_new_boolean(false)); - json_object_object_add(object, "make", - json_object_new_string(wlr_output->make ? wlr_output->make : "Unknown")); - json_object_object_add(object, "model", - json_object_new_string(wlr_output->model ? wlr_output->model : "Unknown")); - json_object_object_add(object, "serial", - json_object_new_string(wlr_output->serial ? wlr_output->serial : "Unknown")); - - json_object *modes_array = json_object_new_array(); - struct wlr_output_mode *mode; - wl_list_for_each(mode, &wlr_output->modes, link) { - json_object *mode_object = json_object_new_object(); - json_object_object_add(mode_object, "width", - json_object_new_int(mode->width)); - json_object_object_add(mode_object, "height", - json_object_new_int(mode->height)); - json_object_object_add(mode_object, "refresh", - json_object_new_int(mode->refresh)); - json_object_array_add(modes_array, mode_object); - } - json_object_object_add(object, "modes", modes_array); -} - -static void ipc_json_describe_output(struct sway_output *output, - json_object *object) { - ipc_json_describe_wlr_output(output->wlr_output, output, object); -} - -static void ipc_json_describe_enabled_output(struct sway_output *output, - json_object *object) { - ipc_json_describe_output(output, object); - - struct wlr_output *wlr_output = output->wlr_output; - json_object_object_add(object, "non_desktop", json_object_new_boolean(false)); - json_object_object_add(object, "active", json_object_new_boolean(true)); - json_object_object_add(object, "dpms", - json_object_new_boolean(wlr_output->enabled)); - json_object_object_add(object, "power", - json_object_new_boolean(wlr_output->enabled)); - json_object_object_add(object, "layout", json_object_new_string("output")); - json_object_object_add(object, "orientation", - json_object_new_string( - ipc_json_orientation_description(L_NONE))); - json_object_object_add(object, "scale", - json_object_new_double(wlr_output->scale)); - json_object_object_add(object, "scale_filter", - json_object_new_string( - sway_output_scale_filter_to_string(output->scale_filter))); - json_object_object_add(object, "transform", - json_object_new_string( - ipc_json_output_transform_description(wlr_output->transform))); - const char *adaptive_sync_status = - ipc_json_output_adaptive_sync_status_description( - wlr_output->adaptive_sync_status); - json_object_object_add(object, "adaptive_sync_status", - json_object_new_string(adaptive_sync_status)); - - struct json_object *layers = json_object_new_array(); - size_t len = sizeof(output->layers) / sizeof(output->layers[0]); - for (size_t i = 0; i < len; ++i) { - struct sway_layer_surface *lsurface; - wl_list_for_each(lsurface, &output->layers[i], link) { - json_object *layer = json_object_new_object(); - - json_object_object_add(layer, "namespace", - json_object_new_string(lsurface->layer_surface->namespace)); - - char *layer_name = NULL; - switch (lsurface->layer) { - case ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND: - layer_name = "background"; - break; - case ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM: - layer_name = "bottom"; - break; - case ZWLR_LAYER_SHELL_V1_LAYER_TOP: - layer_name = "top"; - break; - case ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY: - layer_name = "overlay"; - break; - } - - json_object_object_add(layer, "layer", - json_object_new_string(layer_name)); - - json_object *extent = json_object_new_object(); - json_object_object_add(extent, "width", - json_object_new_int(lsurface->extent.width)); - json_object_object_add(extent, "height", - json_object_new_int(lsurface->extent.height)); - json_object_object_add(extent, "x", - json_object_new_int(lsurface->extent.x)); - json_object_object_add(extent, "y", - json_object_new_int(lsurface->extent.y)); - json_object_object_add(layer, "extent", extent); - - json_object *effects = json_object_new_array(); - if (lsurface->has_blur) { - json_object_array_add(effects, json_object_new_string("blur")); - } - if (lsurface->blur_ignore_transparent) { - json_object_array_add(effects, - json_object_new_string("blur_ignore_transparent")); - } - if (lsurface->has_shadow) { - json_object_array_add(effects, json_object_new_string("shadows")); - } - if (lsurface->corner_radius > 0) { - json_object_array_add(effects, json_object_new_string("corner_radius")); - } - json_object_object_add(layer, "effects", effects); - - json_object_array_add(layers, layer); - } - } - json_object_object_add(object, "layer_shell_surfaces", layers); - - struct sway_workspace *ws = output_get_active_workspace(output); - if (!sway_assert(ws, "Expected output to have a workspace")) { - return; - } - json_object_object_add(object, "current_workspace", - json_object_new_string(ws->name)); - - json_object *modes_array = json_object_new_array(); - struct wlr_output_mode *mode; - wl_list_for_each(mode, &wlr_output->modes, link) { - json_object *mode_object = - ipc_json_output_mode_description(mode); - json_object_array_add(modes_array, mode_object); - } - - json_object_object_add(object, "modes", modes_array); - - json_object *current_mode_object; - if (wlr_output->current_mode != NULL) { - current_mode_object = - ipc_json_output_mode_description(wlr_output->current_mode); - } else { - current_mode_object = json_object_new_object(); - json_object_object_add(current_mode_object, "width", - json_object_new_int(wlr_output->width)); - json_object_object_add(current_mode_object, "height", - json_object_new_int(wlr_output->height)); - json_object_object_add(current_mode_object, "refresh", - json_object_new_int(wlr_output->refresh)); - } - json_object_object_add(object, "current_mode", current_mode_object); - - struct sway_node *parent = node_get_parent(&output->node); - struct wlr_box parent_box = {0, 0, 0, 0}; - - if (parent != NULL) { - node_get_box(parent, &parent_box); - } - - if (parent_box.width != 0 && parent_box.height != 0) { - double percent = ((double)output->width / parent_box.width) - * ((double)output->height / parent_box.height); - json_object_object_add(object, "percent", json_object_new_double(percent)); - } - - json_object_object_add(object, "max_render_time", json_object_new_int(output->max_render_time)); -} - -json_object *ipc_json_describe_disabled_output(struct sway_output *output) { - struct wlr_output *wlr_output = output->wlr_output; - - json_object *object = json_object_new_object(); - - ipc_json_describe_output(output, object); - - json_object_object_add(object, "non_desktop", json_object_new_boolean(false)); - json_object_object_add(object, "type", json_object_new_string("output")); - json_object_object_add(object, "name", - json_object_new_string(wlr_output->name)); - json_object_object_add(object, "active", json_object_new_boolean(false)); - json_object_object_add(object, "dpms", json_object_new_boolean(false)); - json_object_object_add(object, "power", json_object_new_boolean(false)); - - json_object_object_add(object, "current_workspace", NULL); - - json_object *rect_object = json_object_new_object(); - json_object_object_add(rect_object, "x", json_object_new_int(0)); - json_object_object_add(rect_object, "y", json_object_new_int(0)); - json_object_object_add(rect_object, "width", json_object_new_int(0)); - json_object_object_add(rect_object, "height", json_object_new_int(0)); - json_object_object_add(object, "rect", rect_object); - - json_object_object_add(object, "percent", NULL); - - return object; -} - -json_object *ipc_json_describe_non_desktop_output(struct sway_output_non_desktop *output) { - struct wlr_output *wlr_output = output->wlr_output; - - json_object *object = json_object_new_object(); - - ipc_json_describe_wlr_output(wlr_output, NULL, object); - - json_object_object_add(object, "non_desktop", json_object_new_boolean(true)); - json_object_object_add(object, "type", json_object_new_string("output")); - json_object_object_add(object, "name", - json_object_new_string(wlr_output->name)); - - return object; -} - -static json_object *ipc_json_describe_scratchpad_output(void) { - struct wlr_box box; - root_get_box(root, &box); - - // Create focus stack for __i3_scratch workspace - json_object *workspace_focus = json_object_new_array(); - for (int i = root->scratchpad->length - 1; i >= 0; --i) { - struct sway_container *container = root->scratchpad->items[i]; - json_object_array_add(workspace_focus, - json_object_new_int(container->node.id)); - } - - json_object *workspace = ipc_json_create_node(i3_scratch_id, "workspace", - "__i3_scratch", false, workspace_focus, &box); - json_object_object_add(workspace, "fullscreen_mode", json_object_new_int(1)); - - // List all hidden scratchpad containers as floating nodes - json_object *floating_array = json_object_new_array(); - for (int i = 0; i < root->scratchpad->length; ++i) { - struct sway_container *container = root->scratchpad->items[i]; - if (container_is_scratchpad_hidden(container)) { - json_object_array_add(floating_array, - ipc_json_describe_node_recursive(&container->node)); - } - } - json_object_object_add(workspace, "floating_nodes", floating_array); - - // Create focus stack for __i3 output - json_object *output_focus = json_object_new_array(); - json_object_array_add(output_focus, json_object_new_int(i3_scratch_id)); - - json_object *output = ipc_json_create_node(i3_output_id, "output", - "__i3", false, output_focus, &box); - json_object_object_add(output, "layout", - json_object_new_string("output")); - - json_object *nodes = json_object_new_array(); - json_object_array_add(nodes, workspace); - json_object_object_add(output, "nodes", nodes); - - return output; -} - -static void ipc_json_describe_workspace(struct sway_workspace *workspace, - json_object *object) { - int num; - if (isdigit(workspace->name[0])) { - errno = 0; - char *endptr = NULL; - long long parsed_num = strtoll(workspace->name, &endptr, 10); - if (errno != 0 || parsed_num > INT32_MAX || parsed_num < 0 || endptr == workspace->name) { - num = -1; - } else { - num = (int) parsed_num; - } - } else { - num = -1; - } - json_object_object_add(object, "num", json_object_new_int(num)); - json_object_object_add(object, "fullscreen_mode", json_object_new_int(1)); - json_object_object_add(object, "output", workspace->output ? - json_object_new_string(workspace->output->wlr_output->name) : NULL); - json_object_object_add(object, "urgent", - json_object_new_boolean(workspace->urgent)); - json_object_object_add(object, "representation", workspace->representation ? - json_object_new_string(workspace->representation) : NULL); - - json_object_object_add(object, "layout", - json_object_new_string( - ipc_json_layout_description(workspace->layout))); - json_object_object_add(object, "orientation", - json_object_new_string( - ipc_json_orientation_description(workspace->layout))); - - // Floating - json_object *floating_array = json_object_new_array(); - for (int i = 0; i < workspace->floating->length; ++i) { - struct sway_container *floater = workspace->floating->items[i]; - json_object_array_add(floating_array, - ipc_json_describe_node_recursive(&floater->node)); - } - json_object_object_add(object, "floating_nodes", floating_array); -} - -static void get_deco_rect(struct sway_container *c, struct wlr_box *deco_rect) { - enum sway_container_layout parent_layout = container_parent_layout(c); - list_t *siblings = container_get_siblings(c); - bool tab_or_stack = (parent_layout == L_TABBED || parent_layout == L_STACKED) - && ((siblings && siblings->length > 1) || !config->hide_lone_tab); - if (((!tab_or_stack || container_is_floating(c)) && - c->current.border != B_NORMAL) || - c->pending.fullscreen_mode != FULLSCREEN_NONE || - c->pending.workspace == NULL) { - deco_rect->x = deco_rect->y = deco_rect->width = deco_rect->height = 0; - return; - } - - if (c->pending.parent) { - deco_rect->x = c->pending.x - c->pending.parent->pending.x; - deco_rect->y = c->pending.y - c->pending.parent->pending.y; - } else { - deco_rect->x = c->pending.x - c->pending.workspace->x; - deco_rect->y = c->pending.y - c->pending.workspace->y; - } - deco_rect->width = c->pending.width; - deco_rect->height = container_titlebar_height(); - - if (!container_is_floating(c)) { - if (parent_layout == L_TABBED) { - deco_rect->width = c->pending.parent - ? c->pending.parent->pending.width / c->pending.parent->pending.children->length - : c->pending.workspace->width / c->pending.workspace->tiling->length; - deco_rect->x += deco_rect->width * container_sibling_index(c); - } else if (parent_layout == L_STACKED) { - if (!c->view) { - size_t siblings = container_get_siblings(c)->length; - deco_rect->y -= deco_rect->height * siblings; - } - deco_rect->y += deco_rect->height * container_sibling_index(c); - } - } -} - -static void ipc_json_describe_view(struct sway_container *c, json_object *object) { - json_object_object_add(object, "pid", json_object_new_int(c->view->pid)); - - const char *app_id = view_get_app_id(c->view); - json_object_object_add(object, "app_id", - app_id ? json_object_new_string(app_id) : NULL); - - bool visible = view_is_visible(c->view); - json_object_object_add(object, "visible", json_object_new_boolean(visible)); - - struct wlr_box window_box = { - c->pending.content_x - c->pending.x, - (c->current.border == B_PIXEL) ? c->pending.content_y - c->pending.y : 0, - c->pending.content_width, - c->pending.content_height - }; - - json_object_object_add(object, "window_rect", ipc_json_create_rect(&window_box)); - - struct wlr_box geometry = {0, 0, c->view->natural_width, c->view->natural_height}; - json_object_object_add(object, "geometry", ipc_json_create_rect(&geometry)); - - json_object_object_add(object, "max_render_time", json_object_new_int(c->view->max_render_time)); - - json_object_object_add(object, "shell", json_object_new_string(view_get_shell(c->view))); - - json_object_object_add(object, "inhibit_idle", - json_object_new_boolean(view_inhibit_idle(c->view))); - - json_object *idle_inhibitors = json_object_new_object(); - - struct sway_idle_inhibitor_v1 *user_inhibitor = - sway_idle_inhibit_v1_user_inhibitor_for_view(c->view); - - if (user_inhibitor) { - json_object_object_add(idle_inhibitors, "user", - json_object_new_string( - ipc_json_user_idle_inhibitor_description(user_inhibitor->mode))); - } else { - json_object_object_add(idle_inhibitors, "user", - json_object_new_string("none")); - } - - struct sway_idle_inhibitor_v1 *application_inhibitor = - sway_idle_inhibit_v1_application_inhibitor_for_view(c->view); - - if (application_inhibitor) { - json_object_object_add(idle_inhibitors, "application", - json_object_new_string("enabled")); - } else { - json_object_object_add(idle_inhibitors, "application", - json_object_new_string("none")); - } - - json_object_object_add(object, "idle_inhibitors", idle_inhibitors); - - enum wp_content_type_v1_type content_type = WP_CONTENT_TYPE_V1_TYPE_NONE; - if (c->view->surface != NULL) { - content_type = wlr_surface_get_content_type_v1(server.content_type_manager_v1, - c->view->surface); - } - if (content_type != WP_CONTENT_TYPE_V1_TYPE_NONE) { - json_object_object_add(object, "content_type", - json_object_new_string(ipc_json_content_type_description(content_type))); - } - -#if HAVE_XWAYLAND - if (c->view->type == SWAY_VIEW_XWAYLAND) { - json_object_object_add(object, "window", - json_object_new_int(view_get_x11_window_id(c->view))); - - json_object *window_props = json_object_new_object(); - - const char *class = view_get_class(c->view); - if (class) { - json_object_object_add(window_props, "class", json_object_new_string(class)); - } - const char *instance = view_get_instance(c->view); - if (instance) { - json_object_object_add(window_props, "instance", json_object_new_string(instance)); - } - if (c->title) { - json_object_object_add(window_props, "title", json_object_new_string(c->title)); - } - - // the transient_for key is always present in i3's output - uint32_t parent_id = view_get_x11_parent_id(c->view); - json_object_object_add(window_props, "transient_for", - parent_id ? json_object_new_int(parent_id) : NULL); - - const char *role = view_get_window_role(c->view); - if (role) { - json_object_object_add(window_props, "window_role", json_object_new_string(role)); - } - - uint32_t window_type = view_get_window_type(c->view); - if (window_type) { - json_object_object_add(window_props, "window_type", - json_object_new_string( - ipc_json_xwindow_type_description(c->view))); - } - - json_object_object_add(object, "window_properties", window_props); - } -#endif -} - -static void ipc_json_describe_container(struct sway_container *c, json_object *object) { - json_object_object_add(object, "name", - c->title ? json_object_new_string(c->title) : NULL); - if (container_is_floating(c)) { - json_object_object_add(object, "type", - json_object_new_string("floating_con")); - } - - json_object_object_add(object, "layout", - json_object_new_string( - ipc_json_layout_description(c->pending.layout))); - - json_object_object_add(object, "orientation", - json_object_new_string( - ipc_json_orientation_description(c->pending.layout))); - - bool urgent = c->view ? - view_is_urgent(c->view) : container_has_urgent_child(c); - json_object_object_add(object, "urgent", json_object_new_boolean(urgent)); - json_object_object_add(object, "sticky", json_object_new_boolean(c->is_sticky)); - - json_object_object_add(object, "fullscreen_mode", - json_object_new_int(c->pending.fullscreen_mode)); - - struct sway_node *parent = node_get_parent(&c->node); - struct wlr_box parent_box = {0, 0, 0, 0}; - - if (parent != NULL) { - node_get_box(parent, &parent_box); - } - - if (parent_box.width != 0 && parent_box.height != 0) { - double percent = ((double)c->pending.width / parent_box.width) - * ((double)c->pending.height / parent_box.height); - json_object_object_add(object, "percent", json_object_new_double(percent)); - } - - json_object_object_add(object, "border", - json_object_new_string( - ipc_json_border_description(c->current.border))); - json_object_object_add(object, "current_border_width", - json_object_new_int(c->current.border_thickness)); - json_object_object_add(object, "floating_nodes", json_object_new_array()); - - struct wlr_box deco_box = {0, 0, 0, 0}; - get_deco_rect(c, &deco_box); - json_object_object_add(object, "deco_rect", ipc_json_create_rect(&deco_box)); - - json_object *marks = json_object_new_array(); - list_t *con_marks = c->marks; - for (int i = 0; i < con_marks->length; ++i) { - json_object_array_add(marks, json_object_new_string(con_marks->items[i])); - } - - json_object_object_add(object, "marks", marks); - - if (c->view) { - ipc_json_describe_view(c, object); - } -} - -struct focus_inactive_data { - struct sway_node *node; - json_object *object; -}; - -static void focus_inactive_children_iterator(struct sway_node *node, - void *_data) { - struct focus_inactive_data *data = _data; - json_object *focus = data->object; - if (data->node == &root->node) { - struct sway_output *output = node_get_output(node); - if (output == NULL) { - return; - } - size_t id = output->node.id; - int len = json_object_array_length(focus); - for (int i = 0; i < len; ++i) { - if ((size_t) json_object_get_int(json_object_array_get_idx(focus, i)) == id) { - return; - } - } - node = &output->node; - } else if (node_get_parent(node) != data->node) { - return; - } - json_object_array_add(focus, json_object_new_int(node->id)); -} - -json_object *ipc_json_describe_node(struct sway_node *node) { - struct sway_seat *seat = input_manager_get_default_seat(); - bool focused = seat_get_focus(seat) == node; - char *name = node_get_name(node); - - struct wlr_box box; - node_get_box(node, &box); - if (node->type == N_CONTAINER) { - struct wlr_box deco_rect = {0, 0, 0, 0}; - get_deco_rect(node->sway_container, &deco_rect); - size_t count = 1; - if (container_parent_layout(node->sway_container) == L_STACKED) { - count = container_get_siblings(node->sway_container)->length; - } - box.y += deco_rect.height * count; - box.height -= deco_rect.height * count; - } - - json_object *focus = json_object_new_array(); - struct focus_inactive_data data = { - .node = node, - .object = focus, - }; - seat_for_each_node(seat, focus_inactive_children_iterator, &data); - - json_object *object = ipc_json_create_node((int)node->id, - ipc_json_node_type_description(node->type), name, focused, focus, &box); - - switch (node->type) { - case N_ROOT: - break; - case N_OUTPUT: - ipc_json_describe_enabled_output(node->sway_output, object); - break; - case N_CONTAINER: - ipc_json_describe_container(node->sway_container, object); - break; - case N_WORKSPACE: - ipc_json_describe_workspace(node->sway_workspace, object); - break; - } - - return object; -} - -json_object *ipc_json_describe_node_recursive(struct sway_node *node) { - json_object *object = ipc_json_describe_node(node); - int i; - - json_object *children = json_object_new_array(); - switch (node->type) { - case N_ROOT: - json_object_array_add(children, - ipc_json_describe_scratchpad_output()); - for (i = 0; i < root->outputs->length; ++i) { - struct sway_output *output = root->outputs->items[i]; - json_object_array_add(children, - ipc_json_describe_node_recursive(&output->node)); - } - break; - case N_OUTPUT: - for (i = 0; i < node->sway_output->workspaces->length; ++i) { - struct sway_workspace *ws = node->sway_output->workspaces->items[i]; - json_object_array_add(children, - ipc_json_describe_node_recursive(&ws->node)); - } - break; - case N_WORKSPACE: - for (i = 0; i < node->sway_workspace->tiling->length; ++i) { - struct sway_container *con = node->sway_workspace->tiling->items[i]; - json_object_array_add(children, - ipc_json_describe_node_recursive(&con->node)); - } - break; - case N_CONTAINER: - if (node->sway_container->pending.children) { - for (i = 0; i < node->sway_container->pending.children->length; ++i) { - struct sway_container *child = - node->sway_container->pending.children->items[i]; - json_object_array_add(children, - ipc_json_describe_node_recursive(&child->node)); - } - } - break; - } - json_object_object_add(object, "nodes", children); - - return object; -} - -#if WLR_HAS_LIBINPUT_BACKEND -static json_object *describe_libinput_device(struct libinput_device *device) { - json_object *object = json_object_new_object(); - - const char *events = "unknown"; - switch (libinput_device_config_send_events_get_mode(device)) { - case LIBINPUT_CONFIG_SEND_EVENTS_ENABLED: - events = "enabled"; - break; - case LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE: - events = "disabled_on_external_mouse"; - break; - case LIBINPUT_CONFIG_SEND_EVENTS_DISABLED: - events = "disabled"; - break; - } - json_object_object_add(object, "send_events", - json_object_new_string(events)); - - if (libinput_device_config_tap_get_finger_count(device) > 0) { - const char *tap = "unknown"; - switch (libinput_device_config_tap_get_enabled(device)) { - case LIBINPUT_CONFIG_TAP_ENABLED: - tap = "enabled"; - break; - case LIBINPUT_CONFIG_TAP_DISABLED: - tap = "disabled"; - break; - } - json_object_object_add(object, "tap", json_object_new_string(tap)); - - const char *button_map = "unknown"; - switch (libinput_device_config_tap_get_button_map(device)) { - case LIBINPUT_CONFIG_TAP_MAP_LRM: - button_map = "lrm"; - break; - case LIBINPUT_CONFIG_TAP_MAP_LMR: - button_map = "lmr"; - break; - } - json_object_object_add(object, "tap_button_map", - json_object_new_string(button_map)); - - const char* drag = "unknown"; - switch (libinput_device_config_tap_get_drag_enabled(device)) { - case LIBINPUT_CONFIG_DRAG_ENABLED: - drag = "enabled"; - break; - case LIBINPUT_CONFIG_DRAG_DISABLED: - drag = "disabled"; - break; - } - json_object_object_add(object, "tap_drag", - json_object_new_string(drag)); - - const char *drag_lock = "unknown"; - switch (libinput_device_config_tap_get_drag_lock_enabled(device)) { - case LIBINPUT_CONFIG_DRAG_LOCK_ENABLED: - drag_lock = "enabled"; - break; - case LIBINPUT_CONFIG_DRAG_LOCK_DISABLED: - drag_lock = "disabled"; - break; - } - json_object_object_add(object, "tap_drag_lock", - json_object_new_string(drag_lock)); - } - - if (libinput_device_config_accel_is_available(device)) { - double accel = libinput_device_config_accel_get_speed(device); - json_object_object_add(object, "accel_speed", - json_object_new_double(accel)); - - const char *accel_profile = "unknown"; - switch (libinput_device_config_accel_get_profile(device)) { - case LIBINPUT_CONFIG_ACCEL_PROFILE_NONE: - accel_profile = "none"; - break; - case LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT: - accel_profile = "flat"; - break; - case LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE: - accel_profile = "adaptive"; - break; -#if HAVE_LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM - case LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM: - accel_profile = "custom"; - break; -#endif - } - json_object_object_add(object, "accel_profile", - json_object_new_string(accel_profile)); - } - - if (libinput_device_config_scroll_has_natural_scroll(device)) { - const char *natural_scroll = "disabled"; - if (libinput_device_config_scroll_get_natural_scroll_enabled(device)) { - natural_scroll = "enabled"; - } - json_object_object_add(object, "natural_scroll", - json_object_new_string(natural_scroll)); - } - - if (libinput_device_config_left_handed_is_available(device)) { - const char *left_handed = "disabled"; - if (libinput_device_config_left_handed_get(device) != 0) { - left_handed = "enabled"; - } - json_object_object_add(object, "left_handed", - json_object_new_string(left_handed)); - } - - uint32_t click_methods = libinput_device_config_click_get_methods(device); - if ((click_methods & ~LIBINPUT_CONFIG_CLICK_METHOD_NONE) != 0) { - const char *click_method = "unknown"; - switch (libinput_device_config_click_get_method(device)) { - case LIBINPUT_CONFIG_CLICK_METHOD_NONE: - click_method = "none"; - break; - case LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS: - click_method = "button_areas"; - break; - case LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER: - click_method = "clickfinger"; - break; - } - json_object_object_add(object, "click_method", - json_object_new_string(click_method)); - } - - if (libinput_device_config_middle_emulation_is_available(device)) { - const char *middle_emulation = "unknown"; - switch (libinput_device_config_middle_emulation_get_enabled(device)) { - case LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED: - middle_emulation = "enabled"; - break; - case LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED: - middle_emulation = "disabled"; - break; - } - json_object_object_add(object, "middle_emulation", - json_object_new_string(middle_emulation)); - } - - uint32_t scroll_methods = libinput_device_config_scroll_get_methods(device); - if ((scroll_methods & ~LIBINPUT_CONFIG_SCROLL_NO_SCROLL) != 0) { - const char *scroll_method = "unknown"; - switch (libinput_device_config_scroll_get_method(device)) { - case LIBINPUT_CONFIG_SCROLL_NO_SCROLL: - scroll_method = "none"; - break; - case LIBINPUT_CONFIG_SCROLL_2FG: - scroll_method = "two_finger"; - break; - case LIBINPUT_CONFIG_SCROLL_EDGE: - scroll_method = "edge"; - break; - case LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN: - scroll_method = "on_button_down"; - break; - } - json_object_object_add(object, "scroll_method", - json_object_new_string(scroll_method)); - - if ((scroll_methods & LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN) != 0) { - uint32_t button = libinput_device_config_scroll_get_button(device); - json_object_object_add(object, "scroll_button", - json_object_new_int(button)); - const char *lock = "unknown"; - switch (libinput_device_config_scroll_get_button_lock(device)) { - case LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_ENABLED: - lock = "enabled"; - break; - case LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED: - lock = "disabled"; - break; - } - json_object_object_add(object, "scroll_button_lock", - json_object_new_string(lock)); - } - } - - if (libinput_device_config_dwt_is_available(device)) { - const char *dwt = "unknown"; - switch (libinput_device_config_dwt_get_enabled(device)) { - case LIBINPUT_CONFIG_DWT_ENABLED: - dwt = "enabled"; - break; - case LIBINPUT_CONFIG_DWT_DISABLED: - dwt = "disabled"; - break; - } - json_object_object_add(object, "dwt", json_object_new_string(dwt)); - } - - if (libinput_device_config_dwtp_is_available(device)) { - const char *dwtp = "unknown"; - switch (libinput_device_config_dwtp_get_enabled(device)) { - case LIBINPUT_CONFIG_DWTP_ENABLED: - dwtp = "enabled"; - break; - case LIBINPUT_CONFIG_DWTP_DISABLED: - dwtp = "disabled"; - break; - } - json_object_object_add(object, "dwtp", json_object_new_string(dwtp)); - } - - if (libinput_device_config_calibration_has_matrix(device)) { - float matrix[6]; - libinput_device_config_calibration_get_matrix(device, matrix); - struct json_object* array = json_object_new_array(); - struct json_object* x; - for (int i = 0; i < 6; i++) { - x = json_object_new_double(matrix[i]); - json_object_array_add(array, x); - } - json_object_object_add(object, "calibration_matrix", array); - } - - return object; -} -#endif - -json_object *ipc_json_describe_input(struct sway_input_device *device) { - if (!(sway_assert(device, "Device must not be null"))) { - return NULL; - } - - json_object *object = json_object_new_object(); - - json_object_object_add(object, "identifier", - json_object_new_string(device->identifier)); - json_object_object_add(object, "name", - json_object_new_string(device->wlr_device->name)); - json_object_object_add(object, "vendor", - json_object_new_int(device->wlr_device->vendor)); - json_object_object_add(object, "product", - json_object_new_int(device->wlr_device->product)); - json_object_object_add(object, "type", - json_object_new_string( - input_device_get_type(device))); - - if (device->wlr_device->type == WLR_INPUT_DEVICE_KEYBOARD) { - struct wlr_keyboard *keyboard = - wlr_keyboard_from_input_device(device->wlr_device); - struct xkb_keymap *keymap = keyboard->keymap; - struct xkb_state *state = keyboard->xkb_state; - - json_object_object_add(object, "repeat_delay", - json_object_new_int(keyboard->repeat_info.delay)); - json_object_object_add(object, "repeat_rate", - json_object_new_int(keyboard->repeat_info.rate)); - - json_object *layouts_arr = json_object_new_array(); - json_object_object_add(object, "xkb_layout_names", layouts_arr); - - xkb_layout_index_t num_layouts = xkb_keymap_num_layouts(keymap); - xkb_layout_index_t layout_idx; - for (layout_idx = 0; layout_idx < num_layouts; layout_idx++) { - const char *layout = xkb_keymap_layout_get_name(keymap, layout_idx); - json_object_array_add(layouts_arr, - layout ? json_object_new_string(layout) : NULL); - - bool is_active = xkb_state_layout_index_is_active(state, - layout_idx, XKB_STATE_LAYOUT_EFFECTIVE); - if (is_active) { - json_object_object_add(object, "xkb_active_layout_index", - json_object_new_int(layout_idx)); - json_object_object_add(object, "xkb_active_layout_name", - layout ? json_object_new_string(layout) : NULL); - } - } - } - - if (device->wlr_device->type == WLR_INPUT_DEVICE_POINTER) { - struct input_config *ic = input_device_get_config(device); - float scroll_factor = 1.0f; - if (ic != NULL && !isnan(ic->scroll_factor) && - ic->scroll_factor != FLT_MIN) { - scroll_factor = ic->scroll_factor; - } - json_object_object_add(object, "scroll_factor", - json_object_new_double(scroll_factor)); - } - -#if WLR_HAS_LIBINPUT_BACKEND - if (wlr_input_device_is_libinput(device->wlr_device)) { - struct libinput_device *libinput_dev; - libinput_dev = wlr_libinput_get_device_handle(device->wlr_device); - json_object_object_add(object, "libinput", - describe_libinput_device(libinput_dev)); - } -#endif - - return object; -} - -json_object *ipc_json_describe_seat(struct sway_seat *seat) { - if (!(sway_assert(seat, "Seat must not be null"))) { - return NULL; - } - - json_object *object = json_object_new_object(); - struct sway_node *focus = seat_get_focus(seat); - - json_object_object_add(object, "name", - json_object_new_string(seat->wlr_seat->name)); - json_object_object_add(object, "capabilities", - json_object_new_int(seat->wlr_seat->capabilities)); - json_object_object_add(object, "focus", - json_object_new_int(focus ? focus->id : 0)); - - json_object *devices = json_object_new_array(); - struct sway_seat_device *device = NULL; - wl_list_for_each(device, &seat->devices, link) { - json_object_array_add(devices, ipc_json_describe_input(device->input_device)); - } - json_object_object_add(object, "devices", devices); - - return object; -} - -static uint32_t event_to_x11_button(uint32_t event) { - switch (event) { - case BTN_LEFT: - return 1; - case BTN_MIDDLE: - return 2; - case BTN_RIGHT: - return 3; - case SWAY_SCROLL_UP: - return 4; - case SWAY_SCROLL_DOWN: - return 5; - case SWAY_SCROLL_LEFT: - return 6; - case SWAY_SCROLL_RIGHT: - return 7; - case BTN_SIDE: - return 8; - case BTN_EXTRA: - return 9; - default: - return 0; - } -} - -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)); - 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, "position", - json_object_new_string(bar->position)); - json_object_object_add(json, "status_command", bar->status_command ? - json_object_new_string(bar->status_command) : NULL); - json_object_object_add(json, "font", - json_object_new_string((bar->font) ? bar->font : config->font)); - - json_object *gaps = json_object_new_object(); - json_object_object_add(gaps, "top", - json_object_new_int(bar->gaps.top)); - json_object_object_add(gaps, "right", - json_object_new_int(bar->gaps.right)); - json_object_object_add(gaps, "bottom", - json_object_new_int(bar->gaps.bottom)); - json_object_object_add(gaps, "left", - json_object_new_int(bar->gaps.left)); - json_object_object_add(json, "gaps", gaps); - - 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, "status_padding", - json_object_new_int(bar->status_padding)); - json_object_object_add(json, "status_edge_padding", - json_object_new_int(bar->status_edge_padding)); - 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, "strip_workspace_name", - json_object_new_boolean(bar->strip_workspace_name)); - json_object_object_add(json, "workspace_min_width", - json_object_new_int(bar->workspace_min_width)); - 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 == PANGO_MARKUP_DEFAULT - ? config->pango_markup - : 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); - - if (bar->bindings->length > 0) { - json_object *bindings = json_object_new_array(); - for (int i = 0; i < bar->bindings->length; ++i) { - struct bar_binding *binding = bar->bindings->items[i]; - json_object *bind = json_object_new_object(); - json_object_object_add(bind, "input_code", - json_object_new_int(event_to_x11_button(binding->button))); - json_object_object_add(bind, "event_code", - json_object_new_int(binding->button)); - json_object_object_add(bind, "command", - json_object_new_string(binding->command)); - json_object_object_add(bind, "release", - json_object_new_boolean(binding->release)); - json_object_array_add(bindings, bind); - } - json_object_object_add(json, "bindings", bindings); - } - - // Add outputs if defined - if (bar->outputs && bar->outputs->length > 0) { - json_object *outputs = json_object_new_array(); - for (int 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); - } -#if HAVE_TRAY - // Add tray outputs if defined - if (bar->tray_outputs && bar->tray_outputs->length > 0) { - json_object *tray_outputs = json_object_new_array(); - for (int i = 0; i < bar->tray_outputs->length; ++i) { - const char *name = bar->tray_outputs->items[i]; - json_object_array_add(tray_outputs, json_object_new_string(name)); - } - json_object_object_add(json, "tray_outputs", tray_outputs); - } - - json_object *tray_bindings = json_object_new_array(); - struct tray_binding *tray_bind = NULL; - wl_list_for_each(tray_bind, &bar->tray_bindings, link) { - json_object *bind = json_object_new_object(); - json_object_object_add(bind, "input_code", - json_object_new_int(event_to_x11_button(tray_bind->button))); - json_object_object_add(bind, "event_code", - json_object_new_int(tray_bind->button)); - json_object_object_add(bind, "command", - json_object_new_string(tray_bind->command)); - json_object_array_add(tray_bindings, bind); - } - if (json_object_array_length(tray_bindings) > 0) { - json_object_object_add(json, "tray_bindings", tray_bindings); - } else { - json_object_put(tray_bindings); - } - - if (bar->icon_theme) { - json_object_object_add(json, "icon_theme", - json_object_new_string(bar->icon_theme)); - } - - json_object_object_add(json, "tray_padding", - json_object_new_int(bar->tray_padding)); -#endif - return json; -} - -json_object *ipc_json_get_binding_mode(void) { - json_object *current_mode = json_object_new_object(); - json_object_object_add(current_mode, "name", - json_object_new_string(config->current_mode->name)); - return current_mode; -} diff --git a/sway/ipc-server.c b/sway/ipc-server.c deleted file mode 100644 index 9692a77fd..000000000 --- a/sway/ipc-server.c +++ /dev/null @@ -1,972 +0,0 @@ -// See https://i3wm.org/docs/ipc.html for protocol information -#define _POSIX_C_SOURCE 200112L -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/desktop/transaction.h" -#include "sway/ipc-json.h" -#include "sway/ipc-server.h" -#include "sway/output.h" -#include "sway/server.h" -#include "sway/input/input-manager.h" -#include "sway/input/keyboard.h" -#include "sway/input/seat.h" -#include "sway/tree/root.h" -#include "sway/tree/view.h" -#include "sway/tree/workspace.h" -#include "list.h" -#include "log.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 struct wl_listener ipc_display_destroy; - -static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'}; - -#define IPC_HEADER_SIZE (sizeof(ipc_magic) + 8) - -struct ipc_client { - struct wl_event_source *event_source; - struct wl_event_source *writable_event_source; - struct sway_server *server; - int fd; - enum ipc_command_type subscribed_events; - size_t write_buffer_len; - size_t write_buffer_size; - char *write_buffer; - // The following are for storing data between event_loop calls - uint32_t pending_length; - enum ipc_command_type pending_type; -}; - -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, uint32_t payload_length, - enum ipc_command_type payload_type); -bool ipc_send_reply(struct ipc_client *client, enum ipc_command_type payload_type, - const char *payload, uint32_t payload_length); - -static void handle_display_destroy(struct wl_listener *listener, void *data) { - if (ipc_event_source) { - wl_event_source_remove(ipc_event_source); - } - close(ipc_socket); - unlink(ipc_sockaddr->sun_path); - - while (ipc_client_list->length) { - ipc_client_disconnect(ipc_client_list->items[ipc_client_list->length-1]); - } - list_free(ipc_client_list); - - free(ipc_sockaddr); - - wl_list_remove(&ipc_display_destroy.link); -} - -void ipc_init(struct sway_server *server) { - ipc_socket = socket(AF_UNIX, SOCK_STREAM, 0); - if (ipc_socket == -1) { - sway_abort("Unable to create IPC socket"); - } - if (fcntl(ipc_socket, F_SETFD, FD_CLOEXEC) == -1) { - sway_abort("Unable to set CLOEXEC on IPC socket"); - } - if (fcntl(ipc_socket, F_SETFL, O_NONBLOCK) == -1) { - sway_abort("Unable to set NONBLOCK on 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) - 1); - 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_display_destroy.notify = handle_display_destroy; - wl_display_add_destroy_listener(server->wl_display, &ipc_display_destroy); - - ipc_event_source = wl_event_loop_add_fd(server->wl_event_loop, ipc_socket, - WL_EVENT_READABLE, ipc_handle_connection, server); -} - -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.%u.%i.sock", dir, getuid(), getpid())) { - sway_abort("Socket path won't fit into ipc_sockaddr->sun_path"); - } - - return ipc_sockaddr; -} - -int ipc_handle_connection(int fd, uint32_t mask, void *data) { - (void) fd; - struct sway_server *server = data; - assert(mask == WL_EVENT_READABLE); - - int client_fd = accept(ipc_socket, NULL, NULL); - if (client_fd == -1) { - sway_log_errno(SWAY_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(SWAY_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(SWAY_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(SWAY_ERROR, "Unable to allocate ipc client"); - close(client_fd); - return 0; - } - client->server = server; - client->pending_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(SWAY_ERROR, "Unable to allocate ipc client write buffer"); - close(client_fd); - return 0; - } - - sway_log(SWAY_DEBUG, "New client: fd %d", client_fd); - list_add(ipc_client_list, client); - return 0; -} - -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(SWAY_ERROR, "IPC Client socket error, removing client"); - ipc_client_disconnect(client); - return 0; - } - - if (mask & WL_EVENT_HANGUP) { - ipc_client_disconnect(client); - return 0; - } - - int read_available; - if (ioctl(client_fd, FIONREAD, &read_available) == -1) { - sway_log_errno(SWAY_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->pending_length > 0) { - if ((uint32_t)read_available >= client->pending_length) { - // Reset pending values. - uint32_t pending_length = client->pending_length; - enum ipc_command_type pending_type = client->pending_type; - client->pending_length = 0; - ipc_client_handle_command(client, pending_length, pending_type); - } - return 0; - } - - if (read_available < (int) IPC_HEADER_SIZE) { - return 0; - } - - uint8_t buf[IPC_HEADER_SIZE]; - // 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(SWAY_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(SWAY_DEBUG, "IPC header check failed"); - ipc_client_disconnect(client); - return 0; - } - - memcpy(&client->pending_length, buf + sizeof(ipc_magic), sizeof(uint32_t)); - memcpy(&client->pending_type, buf + sizeof(ipc_magic) + sizeof(uint32_t), sizeof(uint32_t)); - - if (read_available - received >= (long)client->pending_length) { - // Reset pending values. - uint32_t pending_length = client->pending_length; - enum ipc_command_type pending_type = client->pending_type; - client->pending_length = 0; - ipc_client_handle_command(client, pending_length, pending_type); - } - - return 0; -} - -static bool ipc_has_event_listeners(enum ipc_command_type event) { - for (int i = 0; i < ipc_client_list->length; i++) { - struct ipc_client *client = ipc_client_list->items[i]; - if ((client->subscribed_events & event_mask(event)) != 0) { - return true; - } - } - return false; -} - -static void ipc_send_event(const char *json_string, enum ipc_command_type event) { - struct ipc_client *client; - for (int i = 0; i < ipc_client_list->length; i++) { - client = ipc_client_list->items[i]; - if ((client->subscribed_events & event_mask(event)) == 0) { - continue; - } - if (!ipc_send_reply(client, event, json_string, - (uint32_t)strlen(json_string))) { - sway_log_errno(SWAY_INFO, "Unable to send reply to IPC client"); - /* ipc_send_reply destroys client on error, which also - * removes it from the list, so we need to process - * current index again */ - i--; - } - } -} - -void ipc_event_workspace(struct sway_workspace *old, - struct sway_workspace *new, const char *change) { - if (!ipc_has_event_listeners(IPC_EVENT_WORKSPACE)) { - return; - } - sway_log(SWAY_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 (old) { - json_object_object_add(obj, "old", - ipc_json_describe_node_recursive(&old->node)); - } else { - json_object_object_add(obj, "old", NULL); - } - - if (new) { - json_object_object_add(obj, "current", - ipc_json_describe_node_recursive(&new->node)); - } 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); -} - -void ipc_event_window(struct sway_container *window, const char *change) { - if (!ipc_has_event_listeners(IPC_EVENT_WINDOW)) { - return; - } - sway_log(SWAY_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_node_recursive(&window->node)); - - const char *json_string = json_object_to_json_string(obj); - ipc_send_event(json_string, IPC_EVENT_WINDOW); - json_object_put(obj); -} - -void ipc_event_barconfig_update(struct bar_config *bar) { - if (!ipc_has_event_listeners(IPC_EVENT_BARCONFIG_UPDATE)) { - return; - } - sway_log(SWAY_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); -} - -void ipc_event_bar_state_update(struct bar_config *bar) { - if (!ipc_has_event_listeners(IPC_EVENT_BAR_STATE_UPDATE)) { - return; - } - sway_log(SWAY_DEBUG, "Sending bar_state_update event"); - - json_object *json = json_object_new_object(); - json_object_object_add(json, "id", json_object_new_string(bar->id)); - json_object_object_add(json, "visible_by_modifier", - json_object_new_boolean(bar->visible_by_modifier)); - - const char *json_string = json_object_to_json_string(json); - ipc_send_event(json_string, IPC_EVENT_BAR_STATE_UPDATE); - json_object_put(json); -} - -void ipc_event_mode(const char *mode, bool pango) { - if (!ipc_has_event_listeners(IPC_EVENT_MODE)) { - return; - } - sway_log(SWAY_DEBUG, "Sending mode::%s event", mode); - json_object *obj = json_object_new_object(); - json_object_object_add(obj, "change", json_object_new_string(mode)); - json_object_object_add(obj, "pango_markup", - json_object_new_boolean(pango)); - - const char *json_string = json_object_to_json_string(obj); - ipc_send_event(json_string, IPC_EVENT_MODE); - json_object_put(obj); -} - -void ipc_event_shutdown(const char *reason) { - if (!ipc_has_event_listeners(IPC_EVENT_SHUTDOWN)) { - return; - } - sway_log(SWAY_DEBUG, "Sending shutdown::%s event", reason); - - json_object *json = json_object_new_object(); - json_object_object_add(json, "change", json_object_new_string(reason)); - - const char *json_string = json_object_to_json_string(json); - ipc_send_event(json_string, IPC_EVENT_SHUTDOWN); - json_object_put(json); -} - -void ipc_event_binding(struct sway_binding *binding) { - if (!ipc_has_event_listeners(IPC_EVENT_BINDING)) { - return; - } - sway_log(SWAY_DEBUG, "Sending binding event"); - - json_object *json_binding = json_object_new_object(); - json_object_object_add(json_binding, "command", json_object_new_string(binding->command)); - - const char *names[10]; - int len = get_modifier_names(names, binding->modifiers); - json_object *modifiers = json_object_new_array(); - for (int i = 0; i < len; ++i) { - json_object_array_add(modifiers, json_object_new_string(names[i])); - } - json_object_object_add(json_binding, "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; - - switch (binding->type) { - case BINDING_KEYCODE:; // bindcode: populate input_codes - uint32_t keycode; - for (int i = 0; i < binding->keys->length; ++i) { - keycode = *(uint32_t *)binding->keys->items[i]; - json_object_array_add(input_codes, json_object_new_int(keycode)); - if (i == 0) { - input_code = keycode; - } - } - break; - - case BINDING_KEYSYM: - case BINDING_MOUSESYM: - case BINDING_MOUSECODE:; // bindsym/mouse: populate symbols - uint32_t keysym; - char buffer[64]; - for (int i = 0; i < binding->keys->length; ++i) { - keysym = *(uint32_t *)binding->keys->items[i]; - if (keysym >= BTN_LEFT && keysym <= BTN_LEFT + 8) { - snprintf(buffer, 64, "button%u", keysym - BTN_LEFT + 1); - } else if (xkb_keysym_get_name(keysym, buffer, 64) < 0) { - continue; - } - - json_object *str = json_object_new_string(buffer); - if (i == 0) { - // str is owned by both symbol and symbols. Make sure - // to bump the ref count. - json_object_array_add(symbols, json_object_get(str)); - symbol = str; - } else { - json_object_array_add(symbols, str); - } - } - break; - - default: - sway_log(SWAY_DEBUG, "Unsupported ipc binding event"); - json_object_put(input_codes); - json_object_put(symbols); - json_object_put(json_binding); - return; // do not send any event - } - - json_object_object_add(json_binding, "input_codes", input_codes); - json_object_object_add(json_binding, "input_code", json_object_new_int(input_code)); - json_object_object_add(json_binding, "symbols", symbols); - json_object_object_add(json_binding, "symbol", symbol); - - bool mouse = binding->type == BINDING_MOUSECODE || - binding->type == BINDING_MOUSESYM; - json_object_object_add(json_binding, "input_type", mouse - ? json_object_new_string("mouse") - : json_object_new_string("keyboard")); - - json_object *json = json_object_new_object(); - json_object_object_add(json, "change", json_object_new_string("run")); - json_object_object_add(json, "binding", json_binding); - const char *json_string = json_object_to_json_string(json); - ipc_send_event(json_string, IPC_EVENT_BINDING); - json_object_put(json); -} - -static void ipc_event_tick(const char *payload) { - if (!ipc_has_event_listeners(IPC_EVENT_TICK)) { - return; - } - sway_log(SWAY_DEBUG, "Sending tick event"); - - json_object *json = json_object_new_object(); - json_object_object_add(json, "first", json_object_new_boolean(false)); - json_object_object_add(json, "payload", json_object_new_string(payload)); - - const char *json_string = json_object_to_json_string(json); - ipc_send_event(json_string, IPC_EVENT_TICK); - json_object_put(json); -} - -void ipc_event_input(const char *change, struct sway_input_device *device) { - if (!ipc_has_event_listeners(IPC_EVENT_INPUT)) { - return; - } - sway_log(SWAY_DEBUG, "Sending input event"); - - json_object *json = json_object_new_object(); - json_object_object_add(json, "change", json_object_new_string(change)); - json_object_object_add(json, "input", ipc_json_describe_input(device)); - - const char *json_string = json_object_to_json_string(json); - ipc_send_event(json_string, IPC_EVENT_INPUT); - json_object_put(json); -} - -void ipc_event_output(void) { - if (!ipc_has_event_listeners(IPC_EVENT_OUTPUT)) { - return; - } - sway_log(SWAY_DEBUG, "Sending output event"); - - json_object *json = json_object_new_object(); - json_object_object_add(json, "change", json_object_new_string("unspecified")); - - const char *json_string = json_object_to_json_string(json); - ipc_send_event(json_string, IPC_EVENT_OUTPUT); - json_object_put(json); -} - -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(SWAY_ERROR, "IPC Client socket error, removing client"); - ipc_client_disconnect(client); - return 0; - } - - if (mask & WL_EVENT_HANGUP) { - ipc_client_disconnect(client); - return 0; - } - - if (client->write_buffer_len <= 0) { - return 0; - } - - 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(SWAY_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; - } - - shutdown(client->fd, SHUT_RDWR); - - sway_log(SWAY_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); -} - -static void ipc_get_workspaces_callback(struct sway_workspace *workspace, - void *data) { - json_object *workspace_json = ipc_json_describe_node(&workspace->node); - // override the default focused indicator because - // it's set differently for the get_workspaces reply - struct sway_seat *seat = input_manager_get_default_seat(); - struct sway_workspace *focused_ws = seat_get_focused_workspace(seat); - bool focused = workspace == focused_ws; - 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); - - focused_ws = output_get_active_workspace(workspace->output); - bool visible = workspace == focused_ws; - json_object_object_add(workspace_json, "visible", - json_object_new_boolean(visible)); -} - -static void ipc_get_marks_callback(struct sway_container *con, void *data) { - json_object *marks = (json_object *)data; - for (int i = 0; i < con->marks->length; ++i) { - char *mark = (char *)con->marks->items[i]; - json_object_array_add(marks, json_object_new_string(mark)); - } -} - -void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_length, - enum ipc_command_type payload_type) { - if (!sway_assert(client != NULL, "client != NULL")) { - return; - } - - char *buf = malloc(payload_length + 1); - if (!buf) { - sway_log_errno(SWAY_INFO, "Unable to allocate IPC payload"); - ipc_client_disconnect(client); - return; - } - if (payload_length > 0) { - // Payload should be fully available - ssize_t received = recv(client->fd, buf, payload_length, 0); - if (received == -1) - { - sway_log_errno(SWAY_INFO, "Unable to receive payload from IPC client"); - ipc_client_disconnect(client); - free(buf); - return; - } - } - buf[payload_length] = '\0'; - - switch (payload_type) { - case IPC_COMMAND: - { - char *line = strtok(buf, "\n"); - while (line) { - size_t line_length = strlen(line); - if (line + line_length >= buf + payload_length) { - break; - } - line[line_length] = ';'; - line = strtok(NULL, "\n"); - } - - list_t *res_list = execute_command(buf, NULL, NULL); - transaction_commit_dirty(); - char *json = cmd_results_to_json(res_list); - int length = strlen(json); - ipc_send_reply(client, payload_type, json, (uint32_t)length); - free(json); - while (res_list->length) { - struct cmd_results *results = res_list->items[0]; - free_cmd_results(results); - list_del(res_list, 0); - } - list_free(res_list); - goto exit_cleanup; - } - - case IPC_SEND_TICK: - { - ipc_event_tick(buf); - ipc_send_reply(client, payload_type, "{\"success\": true}", 17); - goto exit_cleanup; - } - - case IPC_GET_OUTPUTS: - { - json_object *outputs = json_object_new_array(); - for (int i = 0; i < root->outputs->length; ++i) { - struct sway_output *output = root->outputs->items[i]; - json_object *output_json = ipc_json_describe_node(&output->node); - - // override the default focused indicator because it's set - // differently for the get_outputs reply - struct sway_seat *seat = input_manager_get_default_seat(); - struct sway_workspace *focused_ws = - seat_get_focused_workspace(seat); - bool focused = focused_ws && output == focused_ws->output; - json_object_object_del(output_json, "focused"); - json_object_object_add(output_json, "focused", - json_object_new_boolean(focused)); - - const char *subpixel = sway_wl_output_subpixel_to_string(output->wlr_output->subpixel); - json_object_object_add(output_json, "subpixel_hinting", json_object_new_string(subpixel)); - json_object_array_add(outputs, output_json); - } - struct sway_output *output; - wl_list_for_each(output, &root->all_outputs, link) { - if (!output->enabled && output != root->fallback_output) { - json_object_array_add(outputs, - ipc_json_describe_disabled_output(output)); - } - } - - for (int i = 0; i < root->non_desktop_outputs->length; i++) { - struct sway_output_non_desktop *non_desktop_output = root->non_desktop_outputs->items[i]; - json_object_array_add(outputs, ipc_json_describe_non_desktop_output(non_desktop_output)); - } - - const char *json_string = json_object_to_json_string(outputs); - ipc_send_reply(client, payload_type, json_string, - (uint32_t)strlen(json_string)); - json_object_put(outputs); // free - goto exit_cleanup; - } - - case IPC_GET_WORKSPACES: - { - json_object *workspaces = json_object_new_array(); - root_for_each_workspace(ipc_get_workspaces_callback, workspaces); - const char *json_string = json_object_to_json_string(workspaces); - ipc_send_reply(client, payload_type, json_string, - (uint32_t)strlen(json_string)); - json_object_put(workspaces); // free - 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 || !json_object_is_type(request, json_type_array)) { - const char msg[] = "{\"success\": false}"; - ipc_send_reply(client, payload_type, msg, strlen(msg)); - sway_log(SWAY_INFO, "Failed to parse subscribe request"); - goto exit_cleanup; - } - - bool is_tick = false; - // parse requested event types - for (size_t 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, "output") == 0) { - client->subscribed_events |= event_mask(IPC_EVENT_OUTPUT); - } else if (strcmp(event_type, "barconfig_update") == 0) { - client->subscribed_events |= event_mask(IPC_EVENT_BARCONFIG_UPDATE); - } else if (strcmp(event_type, "bar_state_update") == 0) { - client->subscribed_events |= event_mask(IPC_EVENT_BAR_STATE_UPDATE); - } else if (strcmp(event_type, "mode") == 0) { - client->subscribed_events |= event_mask(IPC_EVENT_MODE); - } else if (strcmp(event_type, "shutdown") == 0) { - client->subscribed_events |= event_mask(IPC_EVENT_SHUTDOWN); - } else if (strcmp(event_type, "window") == 0) { - client->subscribed_events |= event_mask(IPC_EVENT_WINDOW); - } else if (strcmp(event_type, "binding") == 0) { - client->subscribed_events |= event_mask(IPC_EVENT_BINDING); - } else if (strcmp(event_type, "tick") == 0) { - client->subscribed_events |= event_mask(IPC_EVENT_TICK); - is_tick = true; - } else if (strcmp(event_type, "input") == 0) { - client->subscribed_events |= event_mask(IPC_EVENT_INPUT); - } else { - const char msg[] = "{\"success\": false}"; - ipc_send_reply(client, payload_type, msg, strlen(msg)); - json_object_put(request); - sway_log(SWAY_INFO, "Unsupported event type in subscribe request"); - goto exit_cleanup; - } - } - - json_object_put(request); - const char msg[] = "{\"success\": true}"; - ipc_send_reply(client, payload_type, msg, strlen(msg)); - if (is_tick) { - const char tickmsg[] = "{\"first\": true, \"payload\": \"\"}"; - ipc_send_reply(client, IPC_EVENT_TICK, tickmsg, - strlen(tickmsg)); - } - goto exit_cleanup; - } - - case IPC_GET_INPUTS: - { - json_object *inputs = json_object_new_array(); - struct sway_input_device *device = NULL; - wl_list_for_each(device, &server.input->devices, link) { - json_object_array_add(inputs, ipc_json_describe_input(device)); - } - const char *json_string = json_object_to_json_string(inputs); - ipc_send_reply(client, payload_type, json_string, - (uint32_t)strlen(json_string)); - json_object_put(inputs); // free - goto exit_cleanup; - } - - case IPC_GET_SEATS: - { - json_object *seats = json_object_new_array(); - struct sway_seat *seat = NULL; - wl_list_for_each(seat, &server.input->seats, link) { - json_object_array_add(seats, ipc_json_describe_seat(seat)); - } - const char *json_string = json_object_to_json_string(seats); - ipc_send_reply(client, payload_type, json_string, - (uint32_t)strlen(json_string)); - json_object_put(seats); // free - goto exit_cleanup; - } - - case IPC_GET_TREE: - { - json_object *tree = ipc_json_describe_node_recursive(&root->node); - const char *json_string = json_object_to_json_string(tree); - ipc_send_reply(client, payload_type, json_string, - (uint32_t)strlen(json_string)); - json_object_put(tree); - goto exit_cleanup; - } - - case IPC_GET_MARKS: - { - json_object *marks = json_object_new_array(); - root_for_each_container(ipc_get_marks_callback, marks); - const char *json_string = json_object_to_json_string(marks); - ipc_send_reply(client, payload_type, 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, payload_type, json_string, - (uint32_t)strlen(json_string)); - json_object_put(version); // free - goto exit_cleanup; - } - - case IPC_GET_BAR_CONFIG: - { - if (!buf[0]) { - // Send list of configured bar IDs - json_object *bars = json_object_new_array(); - for (int 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, payload_type, json_string, - (uint32_t)strlen(json_string)); - json_object_put(bars); // free - } else { - // Send particular bar's details - struct bar_config *bar = NULL; - for (int 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, payload_type, 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, payload_type, json_string, - (uint32_t)strlen(json_string)); - json_object_put(json); // free - } - goto exit_cleanup; - } - - case IPC_GET_BINDING_MODES: - { - json_object *modes = json_object_new_array(); - for (int i = 0; i < config->modes->length; i++) { - struct sway_mode *mode = config->modes->items[i]; - json_object_array_add(modes, json_object_new_string(mode->name)); - } - const char *json_string = json_object_to_json_string(modes); - ipc_send_reply(client, payload_type, json_string, - (uint32_t)strlen(json_string)); - json_object_put(modes); // free - goto exit_cleanup; - } - - case IPC_GET_BINDING_STATE: - { - json_object *current_mode = ipc_json_get_binding_mode(); - const char *json_string = json_object_to_json_string(current_mode); - ipc_send_reply(client, payload_type, json_string, - (uint32_t)strlen(json_string)); - json_object_put(current_mode); // free - goto exit_cleanup; - } - - case IPC_GET_CONFIG: - { - json_object *json = json_object_new_object(); - json_object_object_add(json, "config", json_object_new_string(config->current_config)); - const char *json_string = json_object_to_json_string(json); - ipc_send_reply(client, payload_type, json_string, - (uint32_t)strlen(json_string)); - json_object_put(json); // free - goto exit_cleanup; - } - - case IPC_SYNC: - { - // It was decided sway will not support this, just return success:false - const char msg[] = "{\"success\": false}"; - ipc_send_reply(client, payload_type, msg, strlen(msg)); - goto exit_cleanup; - } - - default: - sway_log(SWAY_INFO, "Unknown IPC command type %x", payload_type); - goto exit_cleanup; - } - -exit_cleanup: - free(buf); -} - -bool ipc_send_reply(struct ipc_client *client, enum ipc_command_type payload_type, - const char *payload, uint32_t payload_length) { - assert(payload); - - char data[IPC_HEADER_SIZE]; - - memcpy(data, ipc_magic, sizeof(ipc_magic)); - memcpy(data + sizeof(ipc_magic), &payload_length, sizeof(payload_length)); - memcpy(data + sizeof(ipc_magic) + sizeof(payload_length), &payload_type, sizeof(payload_type)); - - while (client->write_buffer_len + IPC_HEADER_SIZE + payload_length >= - client->write_buffer_size) { - client->write_buffer_size *= 2; - } - - if (client->write_buffer_size > 4e6) { // 4 MB - sway_log(SWAY_ERROR, "Client write buffer too big (%zu), disconnecting client", - client->write_buffer_size); - ipc_client_disconnect(client); - return false; - } - - char *new_buffer = realloc(client->write_buffer, client->write_buffer_size); - if (!new_buffer) { - sway_log(SWAY_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); - } - - return true; -} diff --git a/sway/layer_criteria.c b/sway/layer_criteria.c deleted file mode 100644 index f7a1b084c..000000000 --- a/sway/layer_criteria.c +++ /dev/null @@ -1,91 +0,0 @@ -#include -#include "log.h" -#include "stringop.h" -#include "sway/commands.h" -#include "sway/layer_criteria.h" -#include "util.h" - -void layer_criteria_destroy(struct layer_criteria *criteria) { - free(criteria->namespace); - free(criteria->cmdlist); - free(criteria); -} - -bool layer_criteria_is_equal(struct layer_criteria *a, struct layer_criteria *b) { - return strcmp(a->namespace, b->namespace) == 0 - && strcmp(a->cmdlist, b->cmdlist) == 0; -} - -bool layer_criteria_already_exists(struct layer_criteria *criteria) { - list_t *criterias = config->layer_criteria; - for (int i = 0; i < criterias->length; ++i) { - struct layer_criteria *existing = criterias->items[i]; - if (layer_criteria_is_equal(criteria, existing)) { - return true; - } - } - return false; -} - -list_t *layer_criterias_for_sway_layer_surface(struct sway_layer_surface *sway_layer) { - list_t *criterias = config->layer_criteria; - list_t *matches = create_list(); - for (int i = 0; i < criterias->length; ++i) { - struct layer_criteria *criteria = criterias->items[i]; - if (strcmp(criteria->namespace, sway_layer->layer_surface->namespace) == 0) { - list_add(matches, criteria); - } - } - return matches; -} - -void layer_criteria_parse(struct sway_layer_surface *sway_layer, struct layer_criteria *criteria) { - char matched_delim = ';'; - char *head = malloc(strlen(criteria->cmdlist) + 1); - strcpy(head, criteria->cmdlist); - do { - // Trim leading whitespaces - for (; isspace(*head); ++head) {} - // Split command list - char *cmd = argsep(&head, ";,", &matched_delim); - for (; isspace(*cmd); ++cmd) {} - - if (strcmp(cmd, "") == 0) { - sway_log(SWAY_INFO, "Ignoring empty layer effect."); - continue; - } - sway_log(SWAY_INFO, "Handling layer effect '%s'", cmd); - - int argc; - char **argv = split_args(cmd, &argc); - // Strip all quotes from each token - for (int i = 1; i < argc; ++i) { - if (*argv[i] == '\"' || *argv[i] == '\'') { - strip_quotes(argv[i]); - } - } - if (strcmp(argv[0], "blur") == 0) { - sway_layer->has_blur = parse_boolean(argv[1], true); - continue; - } if (strcmp(argv[0], "blur_ignore_transparent") == 0) { - sway_layer->blur_ignore_transparent = parse_boolean(argv[1], true); - continue; - } else if (strcmp(argv[0], "shadows") == 0) { - sway_layer->has_shadow = parse_boolean(argv[1], true); - continue; - } else if (strcmp(argv[0], "corner_radius") == 0) { - int value; - if (cmd_corner_radius_parse_value(argv[1], &value)) { - sway_layer->corner_radius = value; - continue; - } - sway_log(SWAY_ERROR, - "Invalid layer_effects corner_radius size! Got \"%s\"", - argv[1]); - return; - } else { - sway_log(SWAY_ERROR, "Invalid layer_effects effect! Got \"%s\"", cmd); - return; - } - } while(head); -} diff --git a/sway/lock.c b/sway/lock.c deleted file mode 100644 index 199624fc4..000000000 --- a/sway/lock.c +++ /dev/null @@ -1,219 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include "log.h" -#include "sway/input/cursor.h" -#include "sway/input/keyboard.h" -#include "sway/input/seat.h" -#include "sway/output.h" -#include "sway/server.h" -#include "sway/surface.h" - -struct sway_session_lock_surface { - struct wlr_session_lock_surface_v1 *lock_surface; - struct sway_output *output; - struct wlr_surface *surface; - struct wl_listener map; - struct wl_listener destroy; - struct wl_listener surface_commit; - struct wl_listener output_commit; - struct wl_listener output_destroy; -}; - -static void set_lock_focused_surface(struct wlr_surface *focused) { - server.session_lock.focused = focused; - - struct sway_seat *seat; - wl_list_for_each(seat, &server.input->seats, link) { - seat_set_focus_surface(seat, focused, false); - } -} - -static void handle_surface_map(struct wl_listener *listener, void *data) { - struct sway_session_lock_surface *surf = wl_container_of(listener, surf, map); - if (server.session_lock.focused == NULL) { - set_lock_focused_surface(surf->surface); - } - cursor_rebase_all(); - surface_enter_output(surf->surface, surf->output); - output_damage_whole(surf->output); -} - -static void handle_surface_commit(struct wl_listener *listener, void *data) { - struct sway_session_lock_surface *surf = wl_container_of(listener, surf, surface_commit); - output_damage_surface(surf->output, 0, 0, surf->surface, false); -} - -static void handle_output_commit(struct wl_listener *listener, void *data) { - struct wlr_output_event_commit *event = data; - struct sway_session_lock_surface *surf = wl_container_of(listener, surf, output_commit); - if (event->state->committed & ( - WLR_OUTPUT_STATE_MODE | - WLR_OUTPUT_STATE_SCALE | - WLR_OUTPUT_STATE_TRANSFORM)) { - wlr_session_lock_surface_v1_configure(surf->lock_surface, - surf->output->width, surf->output->height); - } -} - -static void destroy_lock_surface(struct sway_session_lock_surface *surf) { - // Move the seat focus to another surface if one is available - if (server.session_lock.focused == surf->surface) { - struct wlr_surface *next_focus = NULL; - - struct wlr_session_lock_surface_v1 *other; - wl_list_for_each(other, &server.session_lock.lock->surfaces, link) { - if (other != surf->lock_surface && other->surface->mapped) { - next_focus = other->surface; - break; - } - } - set_lock_focused_surface(next_focus); - } - - wl_list_remove(&surf->map.link); - wl_list_remove(&surf->destroy.link); - wl_list_remove(&surf->surface_commit.link); - wl_list_remove(&surf->output_commit.link); - wl_list_remove(&surf->output_destroy.link); - output_damage_whole(surf->output); - free(surf); -} - -static void handle_surface_destroy(struct wl_listener *listener, void *data) { - struct sway_session_lock_surface *surf = wl_container_of(listener, surf, destroy); - destroy_lock_surface(surf); -} - -static void handle_output_destroy(struct wl_listener *listener, void *data) { - struct sway_session_lock_surface *surf = - wl_container_of(listener, surf, output_destroy); - destroy_lock_surface(surf); -} - -static void handle_new_surface(struct wl_listener *listener, void *data) { - struct wlr_session_lock_surface_v1 *lock_surface = data; - struct sway_session_lock_surface *surf = calloc(1, sizeof(*surf)); - if (surf == NULL) { - return; - } - - sway_log(SWAY_DEBUG, "new lock layer surface"); - - struct sway_output *output = lock_surface->output->data; - wlr_session_lock_surface_v1_configure(lock_surface, output->width, output->height); - - surf->lock_surface = lock_surface; - surf->surface = lock_surface->surface; - surf->output = output; - surf->map.notify = handle_surface_map; - wl_signal_add(&lock_surface->surface->events.map, &surf->map); - surf->destroy.notify = handle_surface_destroy; - wl_signal_add(&lock_surface->events.destroy, &surf->destroy); - surf->surface_commit.notify = handle_surface_commit; - wl_signal_add(&surf->surface->events.commit, &surf->surface_commit); - surf->output_commit.notify = handle_output_commit; - wl_signal_add(&output->wlr_output->events.commit, &surf->output_commit); - surf->output_destroy.notify = handle_output_destroy; - wl_signal_add(&output->node.events.destroy, &surf->output_destroy); -} - -static void handle_unlock(struct wl_listener *listener, void *data) { - sway_log(SWAY_DEBUG, "session unlocked"); - server.session_lock.locked = false; - server.session_lock.lock = NULL; - server.session_lock.focused = NULL; - - wl_list_remove(&server.session_lock.lock_new_surface.link); - wl_list_remove(&server.session_lock.lock_unlock.link); - wl_list_remove(&server.session_lock.lock_destroy.link); - - struct sway_seat *seat; - wl_list_for_each(seat, &server.input->seats, link) { - seat_set_exclusive_client(seat, NULL); - // copied from seat_set_focus_layer -- deduplicate? - struct sway_node *previous = seat_get_focus_inactive(seat, &root->node); - if (previous) { - // Hack to get seat to re-focus the return value of get_focus - seat_set_focus(seat, NULL); - seat_set_focus(seat, previous); - } - } - - // redraw everything - for (int i = 0; i < root->outputs->length; ++i) { - struct sway_output *output = root->outputs->items[i]; - output_damage_whole(output); - } -} - -static void handle_abandon(struct wl_listener *listener, void *data) { - sway_log(SWAY_INFO, "session lock abandoned"); - server.session_lock.lock = NULL; - server.session_lock.focused = NULL; - - wl_list_remove(&server.session_lock.lock_new_surface.link); - wl_list_remove(&server.session_lock.lock_unlock.link); - wl_list_remove(&server.session_lock.lock_destroy.link); - - struct sway_seat *seat; - wl_list_for_each(seat, &server.input->seats, link) { - seat->exclusive_client = NULL; - } - - // redraw everything - for (int i = 0; i < root->outputs->length; ++i) { - struct sway_output *output = root->outputs->items[i]; - output_damage_whole(output); - } -} - -static void handle_session_lock(struct wl_listener *listener, void *data) { - struct wlr_session_lock_v1 *lock = data; - struct wl_client *client = wl_resource_get_client(lock->resource); - - if (server.session_lock.lock) { - wlr_session_lock_v1_destroy(lock); - return; - } - - sway_log(SWAY_DEBUG, "session locked"); - server.session_lock.locked = true; - server.session_lock.lock = lock; - - struct sway_seat *seat; - wl_list_for_each(seat, &server.input->seats, link) { - seat_set_exclusive_client(seat, client); - } - - wl_signal_add(&lock->events.new_surface, &server.session_lock.lock_new_surface); - wl_signal_add(&lock->events.unlock, &server.session_lock.lock_unlock); - wl_signal_add(&lock->events.destroy, &server.session_lock.lock_destroy); - - wlr_session_lock_v1_send_locked(lock); - - // redraw everything - for (int i = 0; i < root->outputs->length; ++i) { - struct sway_output *output = root->outputs->items[i]; - output_damage_whole(output); - } -} - -static void handle_session_lock_destroy(struct wl_listener *listener, void *data) { - assert(server.session_lock.lock == NULL); - wl_list_remove(&server.session_lock.new_lock.link); - wl_list_remove(&server.session_lock.manager_destroy.link); -} - -void sway_session_lock_init(void) { - server.session_lock.manager = wlr_session_lock_manager_v1_create(server.wl_display); - - server.session_lock.lock_new_surface.notify = handle_new_surface; - server.session_lock.lock_unlock.notify = handle_unlock; - server.session_lock.lock_destroy.notify = handle_abandon; - server.session_lock.new_lock.notify = handle_session_lock; - server.session_lock.manager_destroy.notify = handle_session_lock_destroy; - wl_signal_add(&server.session_lock.manager->events.new_lock, - &server.session_lock.new_lock); - wl_signal_add(&server.session_lock.manager->events.destroy, - &server.session_lock.manager_destroy); -} diff --git a/sway/main.c b/sway/main.c deleted file mode 100644 index 681a24e9c..000000000 --- a/sway/main.c +++ /dev/null @@ -1,431 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/server.h" -#include "sway/swaynag.h" -#include "sway/desktop/transaction.h" -#include "sway/tree/root.h" -#include "sway/ipc-server.h" -#include "ipc-client.h" -#include "log.h" -#include "stringop.h" -#include "util.h" - -static bool terminate_request = false; -static int exit_value = 0; -static struct rlimit original_nofile_rlimit = {0}; -struct sway_server server = {0}; -struct sway_debug debug = {0}; - -void sway_terminate(int exit_code) { - if (!server.wl_display) { - // Running as IPC client - exit(exit_code); - } else { - // Running as server - terminate_request = true; - exit_value = exit_code; - ipc_event_shutdown("exit"); - wl_display_terminate(server.wl_display); - } -} - -void sig_handler(int signal) { - sway_terminate(EXIT_SUCCESS); -} - -void detect_proprietary(int allow_unsupported_gpu) { - FILE *f = fopen("/proc/modules", "r"); - if (!f) { - return; - } - char *line = NULL; - size_t line_size = 0; - while (getline(&line, &line_size, f) != -1) { - if (strncmp(line, "nvidia ", 7) == 0) { - if (allow_unsupported_gpu) { - sway_log(SWAY_ERROR, - "!!! Proprietary Nvidia drivers are in use !!!"); - } else { - sway_log(SWAY_ERROR, - "Proprietary Nvidia drivers are NOT supported. " - "Use Nouveau. To launch sway anyway, launch with " - "--unsupported-gpu and DO NOT report issues."); - exit(EXIT_FAILURE); - } - break; - } - if (strstr(line, "fglrx")) { - if (allow_unsupported_gpu) { - sway_log(SWAY_ERROR, - "!!! Proprietary AMD drivers are in use !!!"); - } else { - sway_log(SWAY_ERROR, "Proprietary AMD drivers do NOT support " - "Wayland. Use radeon. To try anyway, launch sway with " - "--unsupported-gpu and DO NOT report issues."); - exit(EXIT_FAILURE); - } - break; - } - } - free(line); - fclose(f); -} - -void run_as_ipc_client(char *command, char *socket_path) { - int socketfd = ipc_open_socket(socket_path); - uint32_t len = strlen(command); - char *resp = ipc_single_command(socketfd, IPC_COMMAND, command, &len); - printf("%s\n", resp); - free(resp); - close(socketfd); -} - -static void log_env(void) { - const char *log_vars[] = { - "LD_LIBRARY_PATH", - "LD_PRELOAD", - "PATH", - "SWAYSOCK", - }; - for (size_t i = 0; i < sizeof(log_vars) / sizeof(char *); ++i) { - char *value = getenv(log_vars[i]); - sway_log(SWAY_INFO, "%s=%s", log_vars[i], value != NULL ? value : ""); - } -} - -static void log_file(FILE *f) { - char *line = NULL; - size_t line_size = 0; - ssize_t nread; - while ((nread = getline(&line, &line_size, f)) != -1) { - if (line[nread - 1] == '\n') { - line[nread - 1] = '\0'; - } - sway_log(SWAY_INFO, "%s", line); - } - free(line); -} - -static void log_distro(void) { - const char *paths[] = { - "/etc/lsb-release", - "/etc/os-release", - "/etc/debian_version", - "/etc/redhat-release", - "/etc/gentoo-release", - }; - for (size_t i = 0; i < sizeof(paths) / sizeof(char *); ++i) { - FILE *f = fopen(paths[i], "r"); - if (f) { - sway_log(SWAY_INFO, "Contents of %s:", paths[i]); - log_file(f); - fclose(f); - } - } -} - -static void log_kernel(void) { - FILE *f = popen("uname -a", "r"); - if (!f) { - sway_log(SWAY_INFO, "Unable to determine kernel version"); - return; - } - log_file(f); - pclose(f); -} - -static bool detect_suid(void) { - if (geteuid() != 0 && getegid() != 0) { - return false; - } - - if (getuid() == geteuid() && getgid() == getegid()) { - return false; - } - - sway_log(SWAY_ERROR, "SUID operation is no longer supported, refusing to start. " - "This check will be removed in a future release."); - return true; -} - -static void increase_nofile_limit(void) { - if (getrlimit(RLIMIT_NOFILE, &original_nofile_rlimit) != 0) { - sway_log_errno(SWAY_ERROR, "Failed to bump max open files limit: " - "getrlimit(NOFILE) failed"); - return; - } - - struct rlimit new_rlimit = original_nofile_rlimit; - new_rlimit.rlim_cur = new_rlimit.rlim_max; - if (setrlimit(RLIMIT_NOFILE, &new_rlimit) != 0) { - sway_log_errno(SWAY_ERROR, "Failed to bump max open files limit: " - "setrlimit(NOFILE) failed"); - sway_log(SWAY_INFO, "Running with %d max open files", - (int)original_nofile_rlimit.rlim_cur); - } -} - -void restore_nofile_limit(void) { - if (original_nofile_rlimit.rlim_cur == 0) { - return; - } - if (setrlimit(RLIMIT_NOFILE, &original_nofile_rlimit) != 0) { - sway_log_errno(SWAY_ERROR, "Failed to restore max open files limit: " - "setrlimit(NOFILE) failed"); - } -} - -void enable_debug_flag(const char *flag) { - if (strcmp(flag, "damage=highlight") == 0) { - debug.damage = DAMAGE_HIGHLIGHT; - } else if (strcmp(flag, "damage=rerender") == 0) { - debug.damage = DAMAGE_RERENDER; - } else if (strcmp(flag, "noatomic") == 0) { - debug.noatomic = true; - } else if (strcmp(flag, "txn-wait") == 0) { - debug.txn_wait = true; - } else if (strcmp(flag, "txn-timings") == 0) { - debug.txn_timings = true; - } else if (strncmp(flag, "txn-timeout=", 12) == 0) { - server.txn_timeout_ms = atoi(&flag[12]); - } else if (strcmp(flag, "noscanout") == 0) { - debug.noscanout = true; - } else { - sway_log(SWAY_ERROR, "Unknown debug flag: %s", flag); - } -} - -static sway_log_importance_t convert_wlr_log_importance( - enum wlr_log_importance importance) { - switch (importance) { - case WLR_ERROR: - return SWAY_ERROR; - case WLR_INFO: - return SWAY_INFO; - default: - return SWAY_DEBUG; - } -} - -static void handle_wlr_log(enum wlr_log_importance importance, - const char *fmt, va_list args) { - static char sway_fmt[1024]; - snprintf(sway_fmt, sizeof(sway_fmt), "[wlr] %s", fmt); - _sway_vlog(convert_wlr_log_importance(importance), sway_fmt, args); -} - -static const struct option long_options[] = { - {"help", no_argument, NULL, 'h'}, - {"config", required_argument, NULL, 'c'}, - {"validate", no_argument, NULL, 'C'}, - {"debug", no_argument, NULL, 'd'}, - {"version", no_argument, NULL, 'v'}, - {"verbose", no_argument, NULL, 'V'}, - {"get-socketpath", no_argument, NULL, 'p'}, - {"unsupported-gpu", no_argument, NULL, 'u'}, - {0, 0, 0, 0} -}; - -static const char usage[] = - "Usage: sway [options] [command]\n" - "\n" - " -h, --help Show help message and quit.\n" - " -c, --config Specify a config file.\n" - " -C, --validate Check the validity of the config file, then exit.\n" - " -d, --debug Enables full logging, including debug information.\n" - " -v, --version Show the version number and quit.\n" - " -V, --verbose Enables more verbose logging.\n" - " --get-socketpath Gets the IPC socket path and prints it, then exits.\n" - "\n"; - -int main(int argc, char **argv) { - static bool verbose = false, debug = false, validate = false, allow_unsupported_gpu = false; - - char *config_path = NULL; - - int c; - while (1) { - int option_index = 0; - c = getopt_long(argc, argv, "hCdD:vVc:", long_options, &option_index); - if (c == -1) { - break; - } - switch (c) { - case 'h': // help - printf("%s", usage); - exit(EXIT_SUCCESS); - break; - case 'c': // config - free(config_path); - config_path = strdup(optarg); - break; - case 'C': // validate - validate = true; - break; - case 'd': // debug - debug = true; - break; - case 'D': // extended debug options - enable_debug_flag(optarg); - break; - case 'u': - allow_unsupported_gpu = true; - break; - case 'v': // version - printf("swayfx version " SWAY_VERSION " (based on sway " SWAY_ORIGINAL_VERSION ")\n"); - exit(EXIT_SUCCESS); - break; - case 'V': // verbose - verbose = true; - break; - case 'p': // --get-socketpath - if (getenv("SWAYSOCK")) { - printf("%s\n", getenv("SWAYSOCK")); - exit(EXIT_SUCCESS); - } else { - fprintf(stderr, "sway socket not detected.\n"); - exit(EXIT_FAILURE); - } - break; - default: - fprintf(stderr, "%s", usage); - exit(EXIT_FAILURE); - } - } - - // SUID operation is deprecated, so block it for now. - if (detect_suid()) { - exit(EXIT_FAILURE); - } - - // Since wayland requires XDG_RUNTIME_DIR to be set, abort with just the - // clear error message (when not running as an IPC client). - if (!getenv("XDG_RUNTIME_DIR") && optind == argc) { - fprintf(stderr, - "XDG_RUNTIME_DIR is not set in the environment. Aborting.\n"); - exit(EXIT_FAILURE); - } - - // As the 'callback' function for wlr_log is equivalent to that for - // sway, we do not need to override it. - if (debug) { - sway_log_init(SWAY_DEBUG, sway_terminate); - wlr_log_init(WLR_DEBUG, handle_wlr_log); - } else if (verbose) { - sway_log_init(SWAY_INFO, sway_terminate); - wlr_log_init(WLR_INFO, handle_wlr_log); - } else { - sway_log_init(SWAY_ERROR, sway_terminate); - wlr_log_init(WLR_ERROR, handle_wlr_log); - } - - sway_log(SWAY_INFO, "swayfx version " SWAY_VERSION " (based on sway version " SWAY_ORIGINAL_VERSION ")"); - sway_log(SWAY_INFO, "wlroots version " WLR_VERSION_STR); - log_kernel(); - log_distro(); - log_env(); - - if (optind < argc) { // Behave as IPC client - if (optind != 1) { - sway_log(SWAY_ERROR, - "Detected both options and positional arguments. If you " - "are trying to use the IPC client, options are not " - "supported. Otherwise, check the provided arguments for " - "issues. See `man 1 sway` or `sway -h` for usage. If you " - "are trying to generate a debug log, use " - "`sway -d 2>sway.log`."); - exit(EXIT_FAILURE); - } - char *socket_path = getenv("SWAYSOCK"); - if (!socket_path) { - sway_log(SWAY_ERROR, "Unable to retrieve socket path"); - exit(EXIT_FAILURE); - } - char *command = join_args(argv + optind, argc - optind); - run_as_ipc_client(command, socket_path); - free(command); - return 0; - } - - detect_proprietary(allow_unsupported_gpu); - increase_nofile_limit(); - - // handle SIGTERM signals - signal(SIGTERM, sig_handler); - signal(SIGINT, sig_handler); - - // prevent ipc from crashing sway - signal(SIGPIPE, SIG_IGN); - - sway_log(SWAY_INFO, "Starting swayfx version " SWAY_VERSION - " (based on sway version " SWAY_ORIGINAL_VERSION ")"); - - root = root_create(); - - if (!server_init(&server)) { - return 1; - } - - if (validate) { - bool valid = load_main_config(config_path, false, true); - free(config_path); - return valid ? 0 : 1; - } - - ipc_init(&server); - - setenv("WAYLAND_DISPLAY", server.socket, true); - if (!load_main_config(config_path, false, false)) { - sway_terminate(EXIT_FAILURE); - goto shutdown; - } - - set_rr_scheduling(); - - if (!server_start(&server)) { - sway_terminate(EXIT_FAILURE); - goto shutdown; - } - - config->active = true; - load_swaybars(); - run_deferred_commands(); - run_deferred_bindings(); - transaction_commit_dirty(); - - if (config->swaynag_config_errors.client != NULL) { - swaynag_show(&config->swaynag_config_errors); - } - - server_run(&server); - -shutdown: - sway_log(SWAY_INFO, "Shutting down sway"); - - server_fini(&server); - root_destroy(root); - root = NULL; - - free(config_path); - free_config(config); - - pango_cairo_font_map_set_default(NULL); - - return exit_value; -} diff --git a/sway/meson.build b/sway/meson.build deleted file mode 100644 index 40c7382e1..000000000 --- a/sway/meson.build +++ /dev/null @@ -1,277 +0,0 @@ -sway_sources = files( - 'commands.c', - 'config.c', - 'criteria.c', - 'decoration.c', - 'ipc-json.c', - 'ipc-server.c', - 'layer_criteria.c', - 'lock.c', - 'main.c', - 'realtime.c', - 'server.c', - 'swaynag.c', - 'xdg_activation_v1.c', - 'xdg_decoration.c', - - 'desktop/desktop.c', - 'desktop/idle_inhibit_v1.c', - 'desktop/layer_shell.c', - 'desktop/output.c', - 'desktop/render.c', - 'desktop/surface.c', - 'desktop/transaction.c', - 'desktop/xdg_shell.c', - 'desktop/launcher.c', - - 'input/input-manager.c', - 'input/cursor.c', - 'input/keyboard.c', - 'input/seat.c', - 'input/seatop_default.c', - 'input/seatop_down.c', - 'input/seatop_move_floating.c', - 'input/seatop_move_tiling.c', - 'input/seatop_resize_floating.c', - 'input/seatop_resize_tiling.c', - 'input/switch.c', - 'input/tablet.c', - 'input/text_input.c', - - 'config/bar.c', - 'config/output.c', - 'config/seat.c', - 'config/input.c', - - 'commands/assign.c', - 'commands/bar.c', - 'commands/bind.c', - 'commands/blur.c', - 'commands/blur_brightness.c', - 'commands/blur_contrast.c', - 'commands/blur_passes.c', - 'commands/blur_radius.c', - 'commands/blur_xray.c', - 'commands/blur_noise.c', - 'commands/blur_saturation.c', - 'commands/border.c', - 'commands/client.c', - 'commands/corner_radius.c', - 'commands/smart_corner_radius.c', - 'commands/create_output.c', - 'commands/default_border.c', - 'commands/default_dim_inactive.c', - 'commands/default_floating_border.c', - 'commands/default_orientation.c', - 'commands/dim_inactive.c', - 'commands/dim_inactive_colors.c', - 'commands/exit.c', - 'commands/exec.c', - 'commands/exec_always.c', - 'commands/floating.c', - 'commands/floating_minmax_size.c', - 'commands/floating_modifier.c', - 'commands/focus.c', - 'commands/focus_follows_mouse.c', - 'commands/focus_on_window_activation.c', - 'commands/focus_wrapping.c', - 'commands/font.c', - 'commands/for_window.c', - 'commands/force_display_urgency_hint.c', - 'commands/force_focus_wrapping.c', - 'commands/fullscreen.c', - 'commands/gaps.c', - 'commands/gesture.c', - 'commands/hide_edge_borders.c', - 'commands/inhibit_idle.c', - 'commands/kill.c', - 'commands/mark.c', - 'commands/max_render_time.c', - 'commands/opacity.c', - 'commands/include.c', - 'commands/input.c', - 'commands/layout.c', - 'commands/layer_effects.c', - 'commands/mode.c', - 'commands/mouse_warping.c', - 'commands/move.c', - 'commands/new_float.c', - 'commands/new_window.c', - 'commands/no_focus.c', - 'commands/nop.c', - 'commands/output.c', - 'commands/popup_during_fullscreen.c', - 'commands/primary_selection.c', - 'commands/reload.c', - 'commands/rename.c', - 'commands/resize.c', - 'commands/saturation.c', - 'commands/scratchpad.c', - 'commands/scratchpad_minimize.c', - 'commands/seat.c', - 'commands/seat/attach.c', - 'commands/seat/cursor.c', - 'commands/seat/fallback.c', - 'commands/seat/hide_cursor.c', - 'commands/seat/idle.c', - 'commands/seat/keyboard_grouping.c', - 'commands/seat/pointer_constraint.c', - 'commands/seat/shortcuts_inhibitor.c', - 'commands/seat/xcursor_theme.c', - 'commands/titlebar_separator.c', - 'commands/set.c', - 'commands/shadow_blur_radius.c', - 'commands/shadow_color.c', - 'commands/shadow_offset.c', - 'commands/shadow_inactive_color.c', - 'commands/shadows.c', - 'commands/shadows_on_csd.c', - 'commands/show_marks.c', - 'commands/shortcuts_inhibitor.c', - 'commands/smart_borders.c', - 'commands/smart_gaps.c', - 'commands/split.c', - 'commands/sticky.c', - 'commands/swaybg_command.c', - 'commands/swaynag_command.c', - 'commands/swap.c', - 'commands/tiling_drag.c', - 'commands/tiling_drag_threshold.c', - 'commands/title_align.c', - 'commands/title_format.c', - 'commands/titlebar_border_thickness.c', - 'commands/titlebar_padding.c', - 'commands/unmark.c', - 'commands/urgent.c', - 'commands/workspace.c', - 'commands/workspace_layout.c', - 'commands/ws_auto_back_and_forth.c', - 'commands/xwayland.c', - - 'commands/bar/bind.c', - 'commands/bar/binding_mode_indicator.c', - 'commands/bar/colors.c', - 'commands/bar/font.c', - 'commands/bar/gaps.c', - 'commands/bar/height.c', - 'commands/bar/hidden_state.c', - 'commands/bar/icon_theme.c', - 'commands/bar/id.c', - 'commands/bar/mode.c', - 'commands/bar/modifier.c', - 'commands/bar/output.c', - 'commands/bar/pango_markup.c', - 'commands/bar/position.c', - 'commands/bar/separator_symbol.c', - 'commands/bar/status_command.c', - 'commands/bar/status_edge_padding.c', - 'commands/bar/status_padding.c', - 'commands/bar/strip_workspace_numbers.c', - 'commands/bar/strip_workspace_name.c', - 'commands/bar/swaybar_command.c', - 'commands/bar/tray_bind.c', - 'commands/bar/tray_output.c', - 'commands/bar/tray_padding.c', - 'commands/bar/workspace_buttons.c', - 'commands/bar/workspace_min_width.c', - 'commands/bar/wrap_scroll.c', - - 'commands/input/accel_profile.c', - 'commands/input/calibration_matrix.c', - 'commands/input/click_method.c', - 'commands/input/drag.c', - 'commands/input/drag_lock.c', - 'commands/input/dwt.c', - 'commands/input/dwtp.c', - 'commands/input/events.c', - 'commands/input/left_handed.c', - 'commands/input/map_from_region.c', - 'commands/input/map_to_output.c', - 'commands/input/map_to_region.c', - 'commands/input/middle_emulation.c', - 'commands/input/natural_scroll.c', - 'commands/input/pointer_accel.c', - 'commands/input/rotation_angle.c', - 'commands/input/repeat_delay.c', - 'commands/input/repeat_rate.c', - 'commands/input/scroll_button.c', - 'commands/input/scroll_button_lock.c', - 'commands/input/scroll_factor.c', - 'commands/input/scroll_method.c', - 'commands/input/tap.c', - 'commands/input/tap_button_map.c', - 'commands/input/tool_mode.c', - 'commands/input/xkb_capslock.c', - 'commands/input/xkb_file.c', - 'commands/input/xkb_layout.c', - 'commands/input/xkb_model.c', - 'commands/input/xkb_numlock.c', - 'commands/input/xkb_options.c', - 'commands/input/xkb_rules.c', - 'commands/input/xkb_switch_layout.c', - 'commands/input/xkb_variant.c', - - 'commands/output/adaptive_sync.c', - 'commands/output/background.c', - 'commands/output/disable.c', - 'commands/output/dpms.c', - 'commands/output/enable.c', - 'commands/output/max_render_time.c', - 'commands/output/mode.c', - 'commands/output/position.c', - 'commands/output/power.c', - 'commands/output/render_bit_depth.c', - 'commands/output/scale.c', - 'commands/output/scale_filter.c', - 'commands/output/subpixel.c', - 'commands/output/toggle.c', - 'commands/output/transform.c', - 'commands/output/unplug.c', - - 'tree/arrange.c', - 'tree/container.c', - 'tree/node.c', - 'tree/root.c', - 'tree/view.c', - 'tree/workspace.c', - 'tree/output.c', -) - -sway_deps = [ - cairo, - drm, - jsonc, - libevdev, - libinput, - libudev, - math, - pango, - pcre2, - pixman, - scenefx, - threads, - wayland_server, - wlroots, - xkbcommon, - xcb, - xcb_icccm, - egl, -] - -if have_xwayland - sway_sources += 'desktop/xwayland.c' -endif - -if wlroots_features['libinput_backend'] - sway_sources += 'input/libinput.c' -endif - -executable( - 'sway', - sway_sources + wl_protos_src, - include_directories: [sway_inc], - dependencies: sway_deps, - link_with: [lib_sway_common], - install: true -) - diff --git a/sway/realtime.c b/sway/realtime.c deleted file mode 100644 index 11154af0e..000000000 --- a/sway/realtime.c +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include -#include -#include -#include "sway/server.h" -#include "log.h" - -static void child_fork_callback(void) { - struct sched_param param; - - param.sched_priority = 0; - - int ret = pthread_setschedparam(pthread_self(), SCHED_OTHER, ¶m); - if (ret != 0) { - sway_log(SWAY_ERROR, "Failed to reset scheduler policy on fork"); - } -} - -void set_rr_scheduling(void) { - int prio = sched_get_priority_min(SCHED_RR); - int old_policy; - int ret; - struct sched_param param; - - ret = pthread_getschedparam(pthread_self(), &old_policy, ¶m); - if (ret != 0) { - sway_log(SWAY_DEBUG, "Failed to get old scheduling priority"); - return; - } - - param.sched_priority = prio; - - ret = pthread_setschedparam(pthread_self(), SCHED_RR, ¶m); - if (ret != 0) { - sway_log(SWAY_INFO, "Failed to set scheduling priority to %d", prio); - return; - } - - pthread_atfork(NULL, NULL, child_fork_callback); -} diff --git a/sway/server.c b/sway/server.c deleted file mode 100644 index c4b98d220..000000000 --- a/sway/server.c +++ /dev/null @@ -1,401 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "config.h" -#include "list.h" -#include "log.h" -#include "sway/config.h" -#include "sway/desktop/idle_inhibit_v1.h" -#include "sway/input/input-manager.h" -#include "sway/output.h" -#include "sway/server.h" -#include "sway/input/cursor.h" -#include "sway/tree/root.h" - -#if HAVE_XWAYLAND -#include -#include "sway/xwayland.h" -#endif - -#if WLR_HAS_DRM_BACKEND -#include -#endif - -#define SWAY_XDG_SHELL_VERSION 2 -#define SWAY_LAYER_SHELL_VERSION 4 - -#if WLR_HAS_DRM_BACKEND -static void handle_drm_lease_request(struct wl_listener *listener, void *data) { - /* We only offer non-desktop outputs, but in the future we might want to do - * more logic here. */ - - struct wlr_drm_lease_request_v1 *req = data; - struct wlr_drm_lease_v1 *lease = wlr_drm_lease_request_v1_grant(req); - if (!lease) { - sway_log(SWAY_ERROR, "Failed to grant lease request"); - wlr_drm_lease_request_v1_reject(req); - } -} -#endif - -static bool is_privileged(const struct wl_global *global) { -#if WLR_HAS_DRM_BACKEND - if (server.drm_lease_manager != NULL) { - struct wlr_drm_lease_device_v1 *drm_lease_dev; - wl_list_for_each(drm_lease_dev, &server.drm_lease_manager->devices, link) { - if (drm_lease_dev->global == global) { - return true; - } - } - } -#endif - - return - global == server.output_manager_v1->global || - global == server.output_power_manager_v1->global || - global == server.input_method->global || - global == server.foreign_toplevel_manager->global || - global == server.data_control_manager_v1->global || - global == server.screencopy_manager_v1->global || - global == server.export_dmabuf_manager_v1->global || - global == server.security_context_manager_v1->global || - global == server.gamma_control_manager_v1->global || - global == server.layer_shell->global || - global == server.session_lock.manager->global || - global == server.input->inhibit->global || - global == server.input->keyboard_shortcuts_inhibit->global || - global == server.input->virtual_keyboard->global || - global == server.input->virtual_pointer->global; -} - -static bool filter_global(const struct wl_client *client, - const struct wl_global *global, void *data) { -#if HAVE_XWAYLAND - struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland; - if (xwayland && global == xwayland->shell_v1->global) { - return xwayland->server != NULL && client == xwayland->server->client; - } -#endif - - // Restrict usage of privileged protocols to unsandboxed clients - // TODO: add a way for users to configure an allow-list - const struct wlr_security_context_v1_state *security_context = - wlr_security_context_manager_v1_lookup_client( - server.security_context_manager_v1, (struct wl_client *)client); - if (is_privileged(global)) { - return security_context == NULL; - } - - return true; -} - -bool server_init(struct sway_server *server) { - sway_log(SWAY_DEBUG, "Initializing Wayland server"); - server->wl_display = wl_display_create(); - server->wl_event_loop = wl_display_get_event_loop(server->wl_display); - - wl_display_set_global_filter(server->wl_display, filter_global, NULL); - - server->backend = wlr_backend_autocreate(server->wl_display, &server->session); - if (!server->backend) { - sway_log(SWAY_ERROR, "Unable to create backend"); - return false; - } - - server->renderer = fx_renderer_create(server->backend); - if (!server->renderer) { - sway_log(SWAY_ERROR, "Failed to create fx_renderer"); - return false; - } - - wlr_renderer_init_wl_shm(server->renderer, server->wl_display); - - if (wlr_renderer_get_dmabuf_texture_formats(server->renderer) != NULL) { - wlr_drm_create(server->wl_display, server->renderer); - server->linux_dmabuf_v1 = wlr_linux_dmabuf_v1_create_with_renderer( - server->wl_display, 4, server->renderer); - } - - server->allocator = wlr_allocator_autocreate(server->backend, - server->renderer); - if (!server->allocator) { - sway_log(SWAY_ERROR, "Failed to create allocator"); - return false; - } - - server->compositor = wlr_compositor_create(server->wl_display, 6, - server->renderer); - server->compositor_new_surface.notify = handle_compositor_new_surface; - wl_signal_add(&server->compositor->events.new_surface, - &server->compositor_new_surface); - - wlr_subcompositor_create(server->wl_display); - - server->data_device_manager = - wlr_data_device_manager_create(server->wl_display); - - server->gamma_control_manager_v1 = - wlr_gamma_control_manager_v1_create(server->wl_display); - server->gamma_control_set_gamma.notify = handle_gamma_control_set_gamma; - wl_signal_add(&server->gamma_control_manager_v1->events.set_gamma, - &server->gamma_control_set_gamma); - - server->new_output.notify = handle_new_output; - wl_signal_add(&server->backend->events.new_output, &server->new_output); - server->output_layout_change.notify = handle_output_layout_change; - wl_signal_add(&root->output_layout->events.change, - &server->output_layout_change); - - wlr_xdg_output_manager_v1_create(server->wl_display, root->output_layout); - - server->idle_notifier_v1 = wlr_idle_notifier_v1_create(server->wl_display); - sway_idle_inhibit_manager_v1_init(); - - server->layer_shell = wlr_layer_shell_v1_create(server->wl_display, - SWAY_LAYER_SHELL_VERSION); - wl_signal_add(&server->layer_shell->events.new_surface, - &server->layer_shell_surface); - server->layer_shell_surface.notify = handle_layer_shell_surface; - - server->xdg_shell = wlr_xdg_shell_create(server->wl_display, - SWAY_XDG_SHELL_VERSION); - wl_signal_add(&server->xdg_shell->events.new_surface, - &server->xdg_shell_surface); - server->xdg_shell_surface.notify = handle_xdg_shell_surface; - - server->tablet_v2 = wlr_tablet_v2_create(server->wl_display); - - server->server_decoration_manager = - wlr_server_decoration_manager_create(server->wl_display); - wlr_server_decoration_manager_set_default_mode( - server->server_decoration_manager, - WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); - wl_signal_add(&server->server_decoration_manager->events.new_decoration, - &server->server_decoration); - server->server_decoration.notify = handle_server_decoration; - wl_list_init(&server->decorations); - - server->xdg_decoration_manager = - wlr_xdg_decoration_manager_v1_create(server->wl_display); - wl_signal_add( - &server->xdg_decoration_manager->events.new_toplevel_decoration, - &server->xdg_decoration); - server->xdg_decoration.notify = handle_xdg_decoration; - wl_list_init(&server->xdg_decorations); - - server->relative_pointer_manager = - wlr_relative_pointer_manager_v1_create(server->wl_display); - - server->pointer_constraints = - wlr_pointer_constraints_v1_create(server->wl_display); - server->pointer_constraint.notify = handle_pointer_constraint; - wl_signal_add(&server->pointer_constraints->events.new_constraint, - &server->pointer_constraint); - - server->presentation = - wlr_presentation_create(server->wl_display, server->backend); - - server->output_manager_v1 = - wlr_output_manager_v1_create(server->wl_display); - server->output_manager_apply.notify = handle_output_manager_apply; - wl_signal_add(&server->output_manager_v1->events.apply, - &server->output_manager_apply); - server->output_manager_test.notify = handle_output_manager_test; - wl_signal_add(&server->output_manager_v1->events.test, - &server->output_manager_test); - - server->output_power_manager_v1 = - wlr_output_power_manager_v1_create(server->wl_display); - server->output_power_manager_set_mode.notify = - handle_output_power_manager_set_mode; - wl_signal_add(&server->output_power_manager_v1->events.set_mode, - &server->output_power_manager_set_mode); - server->input_method = wlr_input_method_manager_v2_create(server->wl_display); - server->text_input = wlr_text_input_manager_v3_create(server->wl_display); - server->foreign_toplevel_manager = - wlr_foreign_toplevel_manager_v1_create(server->wl_display); - - sway_session_lock_init(); - -#if WLR_HAS_DRM_BACKEND - server->drm_lease_manager= - wlr_drm_lease_v1_manager_create(server->wl_display, server->backend); - if (server->drm_lease_manager) { - server->drm_lease_request.notify = handle_drm_lease_request; - wl_signal_add(&server->drm_lease_manager->events.request, - &server->drm_lease_request); - } else { - sway_log(SWAY_DEBUG, "Failed to create wlr_drm_lease_device_v1"); - sway_log(SWAY_INFO, "VR will not be available"); - } -#endif - - server->export_dmabuf_manager_v1 = wlr_export_dmabuf_manager_v1_create(server->wl_display); - server->screencopy_manager_v1 = wlr_screencopy_manager_v1_create(server->wl_display); - server->data_control_manager_v1 = wlr_data_control_manager_v1_create(server->wl_display); - server->security_context_manager_v1 = wlr_security_context_manager_v1_create(server->wl_display); - wlr_viewporter_create(server->wl_display); - wlr_single_pixel_buffer_manager_v1_create(server->wl_display); - server->content_type_manager_v1 = - wlr_content_type_manager_v1_create(server->wl_display, 1); - wlr_fractional_scale_manager_v1_create(server->wl_display, 1); - - struct wlr_xdg_foreign_registry *foreign_registry = - wlr_xdg_foreign_registry_create(server->wl_display); - wlr_xdg_foreign_v1_create(server->wl_display, foreign_registry); - wlr_xdg_foreign_v2_create(server->wl_display, foreign_registry); - - server->xdg_activation_v1 = wlr_xdg_activation_v1_create(server->wl_display); - server->xdg_activation_v1_request_activate.notify = - xdg_activation_v1_handle_request_activate; - wl_signal_add(&server->xdg_activation_v1->events.request_activate, - &server->xdg_activation_v1_request_activate); - server->xdg_activation_v1_new_token.notify = - xdg_activation_v1_handle_new_token; - wl_signal_add(&server->xdg_activation_v1->events.new_token, - &server->xdg_activation_v1_new_token); - - struct wlr_cursor_shape_manager_v1 *cursor_shape_manager = - wlr_cursor_shape_manager_v1_create(server->wl_display, 1); - server->request_set_cursor_shape.notify = handle_request_set_cursor_shape; - wl_signal_add(&cursor_shape_manager->events.request_set_shape, &server->request_set_cursor_shape); - - wl_list_init(&server->pending_launcher_ctxs); - - // Avoid using "wayland-0" as display socket - char name_candidate[16]; - for (unsigned int i = 1; i <= 32; ++i) { - snprintf(name_candidate, sizeof(name_candidate), "wayland-%u", i); - if (wl_display_add_socket(server->wl_display, name_candidate) >= 0) { - server->socket = strdup(name_candidate); - break; - } - } - - if (!server->socket) { - sway_log(SWAY_ERROR, "Unable to open wayland socket"); - wlr_backend_destroy(server->backend); - return false; - } - - server->headless_backend = wlr_headless_backend_create(server->wl_display); - if (!server->headless_backend) { - sway_log(SWAY_ERROR, "Failed to create secondary headless backend"); - wlr_backend_destroy(server->backend); - return false; - } else { - wlr_multi_backend_add(server->backend, server->headless_backend); - } - - struct wlr_output *wlr_output = - wlr_headless_add_output(server->headless_backend, 800, 600); - wlr_output_set_name(wlr_output, "FALLBACK"); - root->fallback_output = output_create(wlr_output); - - // This may have been set already via -Dtxn-timeout - if (!server->txn_timeout_ms) { - server->txn_timeout_ms = 200; - } - - server->dirty_nodes = create_list(); - - server->input = input_manager_create(server); - input_manager_get_default_seat(); // create seat0 - - return true; -} - -void server_fini(struct sway_server *server) { - // TODO: free sway-specific resources -#if HAVE_XWAYLAND - wlr_xwayland_destroy(server->xwayland.wlr_xwayland); -#endif - wl_display_destroy_clients(server->wl_display); - wl_display_destroy(server->wl_display); - list_free(server->dirty_nodes); -} - -bool server_start(struct sway_server *server) { -#if HAVE_XWAYLAND - if (config->xwayland != XWAYLAND_MODE_DISABLED) { - sway_log(SWAY_DEBUG, "Initializing Xwayland (lazy=%d)", - config->xwayland == XWAYLAND_MODE_LAZY); - server->xwayland.wlr_xwayland = - wlr_xwayland_create(server->wl_display, server->compositor, - config->xwayland == XWAYLAND_MODE_LAZY); - if (!server->xwayland.wlr_xwayland) { - sway_log(SWAY_ERROR, "Failed to start Xwayland"); - unsetenv("DISPLAY"); - } else { - wl_signal_add(&server->xwayland.wlr_xwayland->events.new_surface, - &server->xwayland_surface); - server->xwayland_surface.notify = handle_xwayland_surface; - wl_signal_add(&server->xwayland.wlr_xwayland->events.ready, - &server->xwayland_ready); - server->xwayland_ready.notify = handle_xwayland_ready; - - setenv("DISPLAY", server->xwayland.wlr_xwayland->display_name, true); - - /* xcursor configured by the default seat */ - } - } -#endif - - if (config->primary_selection) { - wlr_primary_selection_v1_device_manager_create(server->wl_display); - } - - sway_log(SWAY_INFO, "Starting backend on wayland display '%s'", - server->socket); - if (!wlr_backend_start(server->backend)) { - sway_log(SWAY_ERROR, "Failed to start backend"); - wlr_backend_destroy(server->backend); - return false; - } - - return true; -} - -void server_run(struct sway_server *server) { - sway_log(SWAY_INFO, "Running compositor on wayland display '%s'", - server->socket); - wl_display_run(server->wl_display); -} diff --git a/sway/sway-bar.5.scd b/sway/sway-bar.5.scd deleted file mode 100644 index 42e59d57d..000000000 --- a/sway/sway-bar.5.scd +++ /dev/null @@ -1,231 +0,0 @@ -sway-bar(5) - -# NAME - -sway-bar - bar configuration file and commands - -# DESCRIPTION - -Sway allows configuring swaybar in the sway configuration file. - -# COMMANDS - -The following commands may only be used in the configuration file. - -*id* - Sets the ID of the bar. - -*swaybar_command* - Executes custom bar command. Default is _swaybar_. - -The following commands may be used either in the configuration file or at -runtime. - -*bindcode* [--release] - Executes _command_ when the mouse button has been pressed (or if _released_ - is given, when the button has been released). The buttons can be given as - an event code, which can be obtaining from *libinput debug-events*. To - disable the default behavior for a button, use the command _nop_. - -*bindsym* [--release] button[1-9]| - Executes _command_ when the mouse button has been pressed (or if _released_ - is given, when the button has been released). The buttons can be given as a - x11 button number or an event name, which can be obtained from *libinput - debug-events*. To disable the default behavior for a button, use the - command _nop_. - -*binding_mode_indicator* yes|no - Enable or disable binding mode indicator. Default is _yes_. - -*font* - Specifies the font to be used in the bar. _font_ should be specified as a - pango font description. For more information on pango font descriptions, - see https://docs.gtk.org/Pango/type_func.FontDescription.from_string.html#description - -*gaps* | | - Sets the gaps from the edge of the screen for the bar. Gaps can either be - set all at once, per direction, or per side. Note that only sides that - touch an edge of the screen can have gaps. For the side that does not - touch an edge of the screen, per-side outer gaps for workspaces may be of - use. - -*height* - Sets the height of the bar. Default height (0) will match the font size. - -*hidden_state* hide|show [] - Specifies the behaviour of the bar when it is in _hide_ mode. When the - hidden state is _hide_, then it is normally hidden, and only unhidden by - pressing the modifier key or in case of urgency hints. When the hidden - state is _show_, then it is permanently visible, drawn on top of the - currently visible workspace. Default is _hide_. - - For compatibility with i3, _bar hidden_state hide|show []_ is - supported along with the sway only _bar hidden_state hide|show_ - syntax. When using the i3 syntax, if _bar-id_ is omitted, the hidden_state - will be changed for all bars. Attempting to use _bar - hidden_state hide|show _ will result in an error due to - conflicting bar ids. - -*mode* dock|hide|invisible|overlay [] - Specifies the visibility of the bar. In _dock_ mode, it is permanently - visible at one edge of the screen. In _hide_ mode, it is hidden unless the - modifier key is pressed, though this behaviour depends on the hidden state. - In _invisible_ mode, it is permanently hidden. In _overlay_ mode, it is - permanently visible on top of other windows. (In _overlay_ mode the bar is - transparent to input events.) Default is _dock_. - - For compatibility with i3, _bar mode []_ syntax is supported - along with the sway only _bar mode _ syntax. When using the - i3 syntax, if _bar-id_ is omitted, the mode will be changed for all bars. - Attempting to use _bar mode _ will result in an - error due to conflicting bar ids. - -*modifier* |none - Specifies the modifier key that shows a hidden bar. Default is _Mod4_. - -*output* |\* - Restrict the bar to a certain output, can be specified multiple times. If - the output command is omitted, the bar will be displayed on all outputs. _\*_ - can be given at any point to reset it back to all outputs. - -*pango_markup* enabled|disabled - Enables or disables pango markup for status lines. This has no effect on - status lines using the i3bar JSON protocol. - -*position* top|bottom - Sets position of the bar. Default is _bottom_. - -*separator_symbol* - Specifies the separator symbol to separate blocks on the bar. - -*status_command* - Executes the bar _status command_ with _sh -c_. Each line of text printed - to stdout from this command will be displayed in the status area of the - bar. You may also use swaybar's JSON status line protocol. See - *swaybar-protocol*(7) for more information on the protocol - - If running this command via IPC, you can disable a running status command by - setting the command to a single dash: _swaybar bar bar-0 status\_command -_ - -*status_edge_padding* - Sets the padding that is used when the status line is at the right edge of - the bar. This value will be multiplied by the output scale. The default is - _3_. - -*status_padding* - Sets the vertical padding that is used for the status line. The default is - _1_. If _padding_ is _0_, blocks will be able to take up the full height of - the bar. This value will be multiplied by the output scale. - -*strip_workspace_name* yes|no - If set to _yes_, then workspace names will be omitted from the workspace - button and only the custom number will be shown. Default is _no_. - -*strip_workspace_numbers* yes|no - If set to _yes_, then workspace numbers will be omitted from the workspace - button and only the custom name will be shown. Default is _no_. - -*unbindcode* [--release] - Removes the binding with the given . - -*unbindsym* [--release] button[1-9]| - Removes the binding with the given