diff options
Diffstat (limited to 'sway')
97 files changed, 1441 insertions, 643 deletions
diff --git a/sway/commands.c b/sway/commands.c index 55eda183..8d003dfa 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809 | ||
2 | #include <ctype.h> | 1 | #include <ctype.h> |
3 | #include <stdarg.h> | 2 | #include <stdarg.h> |
4 | #include <stdlib.h> | 3 | #include <stdlib.h> |
@@ -82,7 +81,6 @@ static const struct cmd_handler handlers[] = { | |||
82 | { "no_focus", cmd_no_focus }, | 81 | { "no_focus", cmd_no_focus }, |
83 | { "output", cmd_output }, | 82 | { "output", cmd_output }, |
84 | { "popup_during_fullscreen", cmd_popup_during_fullscreen }, | 83 | { "popup_during_fullscreen", cmd_popup_during_fullscreen }, |
85 | { "primary_selection", cmd_primary_selection }, | ||
86 | { "seat", cmd_seat }, | 84 | { "seat", cmd_seat }, |
87 | { "set", cmd_set }, | 85 | { "set", cmd_set }, |
88 | { "show_marks", cmd_show_marks }, | 86 | { "show_marks", cmd_show_marks }, |
@@ -105,6 +103,7 @@ static const struct cmd_handler handlers[] = { | |||
105 | static const struct cmd_handler config_handlers[] = { | 103 | static const struct cmd_handler config_handlers[] = { |
106 | { "default_orientation", cmd_default_orientation }, | 104 | { "default_orientation", cmd_default_orientation }, |
107 | { "include", cmd_include }, | 105 | { "include", cmd_include }, |
106 | { "primary_selection", cmd_primary_selection }, | ||
108 | { "swaybg_command", cmd_swaybg_command }, | 107 | { "swaybg_command", cmd_swaybg_command }, |
109 | { "swaynag_command", cmd_swaynag_command }, | 108 | { "swaynag_command", cmd_swaynag_command }, |
110 | { "workspace_layout", cmd_workspace_layout }, | 109 | { "workspace_layout", cmd_workspace_layout }, |
diff --git a/sway/commands/assign.c b/sway/commands/assign.c index f7d911f7..bf95cf00 100644 --- a/sway/commands/assign.c +++ b/sway/commands/assign.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <stdio.h> | 1 | #include <stdio.h> |
3 | #include <string.h> | 2 | #include <string.h> |
4 | #include "sway/commands.h" | 3 | #include "sway/commands.h" |
diff --git a/sway/commands/bar.c b/sway/commands/bar.c index 22756acb..635e895b 100644 --- a/sway/commands/bar.c +++ b/sway/commands/bar.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809 | ||
2 | #include <stdio.h> | 1 | #include <stdio.h> |
3 | #include <string.h> | 2 | #include <string.h> |
4 | #include <strings.h> | 3 | #include <strings.h> |
diff --git a/sway/commands/bar/font.c b/sway/commands/bar/font.c index 891c87af..0c074679 100644 --- a/sway/commands/bar/font.c +++ b/sway/commands/bar/font.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <string.h> | 1 | #include <string.h> |
3 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
4 | #include "log.h" | 3 | #include "log.h" |
diff --git a/sway/commands/bar/hidden_state.c b/sway/commands/bar/hidden_state.c index 8b661e3a..7b38831e 100644 --- a/sway/commands/bar/hidden_state.c +++ b/sway/commands/bar/hidden_state.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <string.h> | 1 | #include <string.h> |
3 | #include <strings.h> | 2 | #include <strings.h> |
4 | #include "sway/commands.h" | 3 | #include "sway/commands.h" |
diff --git a/sway/commands/bar/icon_theme.c b/sway/commands/bar/icon_theme.c index 6ac07843..fee21709 100644 --- a/sway/commands/bar/icon_theme.c +++ b/sway/commands/bar/icon_theme.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <string.h> | 1 | #include <string.h> |
3 | #include "config.h" | 2 | #include "config.h" |
4 | #include "sway/commands.h" | 3 | #include "sway/commands.h" |
diff --git a/sway/commands/bar/id.c b/sway/commands/bar/id.c index a9a61743..46cf4ca9 100644 --- a/sway/commands/bar/id.c +++ b/sway/commands/bar/id.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <string.h> | 1 | #include <string.h> |
3 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
4 | #include "log.h" | 3 | #include "log.h" |
diff --git a/sway/commands/bar/mode.c b/sway/commands/bar/mode.c index 7c2f423b..d69e910b 100644 --- a/sway/commands/bar/mode.c +++ b/sway/commands/bar/mode.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <string.h> | 1 | #include <string.h> |
3 | #include <strings.h> | 2 | #include <strings.h> |
4 | #include "sway/commands.h" | 3 | #include "sway/commands.h" |
diff --git a/sway/commands/bar/output.c b/sway/commands/bar/output.c index cac1d056..51730176 100644 --- a/sway/commands/bar/output.c +++ b/sway/commands/bar/output.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <stdbool.h> | 1 | #include <stdbool.h> |
3 | #include <string.h> | 2 | #include <string.h> |
4 | #include "sway/commands.h" | 3 | #include "sway/commands.h" |
diff --git a/sway/commands/bar/position.c b/sway/commands/bar/position.c index b207de0b..94f530ec 100644 --- a/sway/commands/bar/position.c +++ b/sway/commands/bar/position.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <string.h> | 1 | #include <string.h> |
3 | #include <strings.h> | 2 | #include <strings.h> |
4 | #include "sway/commands.h" | 3 | #include "sway/commands.h" |
diff --git a/sway/commands/bar/separator_symbol.c b/sway/commands/bar/separator_symbol.c index 6737d4d2..50e9a873 100644 --- a/sway/commands/bar/separator_symbol.c +++ b/sway/commands/bar/separator_symbol.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <string.h> | 1 | #include <string.h> |
3 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
4 | #include "log.h" | 3 | #include "log.h" |
diff --git a/sway/commands/bar/tray_output.c b/sway/commands/bar/tray_output.c index eb3b486e..679facf7 100644 --- a/sway/commands/bar/tray_output.c +++ b/sway/commands/bar/tray_output.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <string.h> | 1 | #include <string.h> |
3 | #include "config.h" | 2 | #include "config.h" |
4 | #include "sway/commands.h" | 3 | #include "sway/commands.h" |
diff --git a/sway/commands/bind.c b/sway/commands/bind.c index 979e178f..268f2855 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <libevdev/libevdev.h> | 1 | #include <libevdev/libevdev.h> |
3 | #include <linux/input-event-codes.h> | 2 | #include <linux/input-event-codes.h> |
4 | #include <string.h> | 3 | #include <string.h> |
diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c index 8fca1909..8bc1048c 100644 --- a/sway/commands/exec_always.c +++ b/sway/commands/exec_always.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <stdlib.h> | 1 | #include <stdlib.h> |
3 | #include <stdint.h> | 2 | #include <stdint.h> |
4 | #include <string.h> | 3 | #include <string.h> |
diff --git a/sway/commands/font.c b/sway/commands/font.c index 74bb6b9f..9920d03e 100644 --- a/sway/commands/font.c +++ b/sway/commands/font.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <string.h> | 1 | #include <string.h> |
3 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
4 | #include "sway/config.h" | 3 | #include "sway/config.h" |
diff --git a/sway/commands/gesture.c b/sway/commands/gesture.c index d4442cc3..90a20716 100644 --- a/sway/commands/gesture.c +++ b/sway/commands/gesture.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include "sway/config.h" | 1 | #include "sway/config.h" |
3 | 2 | ||
4 | #include "gesture.h" | 3 | #include "gesture.h" |
diff --git a/sway/commands/input/calibration_matrix.c b/sway/commands/input/calibration_matrix.c index 38749fbb..53fe2c35 100644 --- a/sway/commands/input/calibration_matrix.c +++ b/sway/commands/input/calibration_matrix.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <string.h> | 1 | #include <string.h> |
3 | #include <strings.h> | 2 | #include <strings.h> |
4 | #include "sway/config.h" | 3 | #include "sway/config.h" |
diff --git a/sway/commands/input/events.c b/sway/commands/input/events.c index 08d99bf0..3cea026e 100644 --- a/sway/commands/input/events.c +++ b/sway/commands/input/events.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include "sway/config.h" | 5 | #include "sway/config.h" |
6 | #include "sway/commands.h" | 6 | #include "sway/commands.h" |
7 | #include "sway/input/input-manager.h" | 7 | #include "sway/input/input-manager.h" |
8 | #include "sway/server.h" | ||
8 | #include "log.h" | 9 | #include "log.h" |
9 | 10 | ||
10 | #if WLR_HAS_LIBINPUT_BACKEND | 11 | #if WLR_HAS_LIBINPUT_BACKEND |
diff --git a/sway/commands/input/map_from_region.c b/sway/commands/input/map_from_region.c index 4400e111..2f8f753d 100644 --- a/sway/commands/input/map_from_region.c +++ b/sway/commands/input/map_from_region.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <stdbool.h> | 1 | #include <stdbool.h> |
3 | #include <string.h> | 2 | #include <string.h> |
4 | #include <strings.h> | 3 | #include <strings.h> |
diff --git a/sway/commands/input/map_to_output.c b/sway/commands/input/map_to_output.c index f60fb7d5..a7266baa 100644 --- a/sway/commands/input/map_to_output.c +++ b/sway/commands/input/map_to_output.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <string.h> | 1 | #include <string.h> |
3 | #include <strings.h> | 2 | #include <strings.h> |
4 | #include "sway/config.h" | 3 | #include "sway/config.h" |
diff --git a/sway/commands/input/map_to_region.c b/sway/commands/input/map_to_region.c index ad535db2..9087c589 100644 --- a/sway/commands/input/map_to_region.c +++ b/sway/commands/input/map_to_region.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <stdlib.h> | 1 | #include <stdlib.h> |
3 | #include <string.h> | 2 | #include <string.h> |
4 | #include "sway/commands.h" | 3 | #include "sway/commands.h" |
diff --git a/sway/commands/input/xkb_file.c b/sway/commands/input/xkb_file.c index 493f94fb..056f00e5 100644 --- a/sway/commands/input/xkb_file.c +++ b/sway/commands/input/xkb_file.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <unistd.h> | 1 | #include <unistd.h> |
3 | #include <errno.h> | 2 | #include <errno.h> |
4 | #include "sway/config.h" | 3 | #include "sway/config.h" |
diff --git a/sway/commands/input/xkb_layout.c b/sway/commands/input/xkb_layout.c index 22626517..1d01886c 100644 --- a/sway/commands/input/xkb_layout.c +++ b/sway/commands/input/xkb_layout.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include "sway/config.h" | 1 | #include "sway/config.h" |
3 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
4 | #include "log.h" | 3 | #include "log.h" |
diff --git a/sway/commands/input/xkb_model.c b/sway/commands/input/xkb_model.c index f4a33de3..a9144a8a 100644 --- a/sway/commands/input/xkb_model.c +++ b/sway/commands/input/xkb_model.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include "sway/config.h" | 1 | #include "sway/config.h" |
3 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
4 | #include "log.h" | 3 | #include "log.h" |
diff --git a/sway/commands/input/xkb_numlock.c b/sway/commands/input/xkb_numlock.c index 87d3e60c..bbe848fe 100644 --- a/sway/commands/input/xkb_numlock.c +++ b/sway/commands/input/xkb_numlock.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include "sway/config.h" | 1 | #include "sway/config.h" |
3 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
4 | #include "util.h" | 3 | #include "util.h" |
diff --git a/sway/commands/input/xkb_options.c b/sway/commands/input/xkb_options.c index d609293f..7ca20777 100644 --- a/sway/commands/input/xkb_options.c +++ b/sway/commands/input/xkb_options.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include "sway/config.h" | 1 | #include "sway/config.h" |
3 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
4 | #include "log.h" | 3 | #include "log.h" |
diff --git a/sway/commands/input/xkb_rules.c b/sway/commands/input/xkb_rules.c index 3b59622c..8fbd26fb 100644 --- a/sway/commands/input/xkb_rules.c +++ b/sway/commands/input/xkb_rules.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include "sway/config.h" | 1 | #include "sway/config.h" |
3 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
4 | #include "log.h" | 3 | #include "log.h" |
diff --git a/sway/commands/input/xkb_switch_layout.c b/sway/commands/input/xkb_switch_layout.c index 3cce4ec8..8d600fca 100644 --- a/sway/commands/input/xkb_switch_layout.c +++ b/sway/commands/input/xkb_switch_layout.c | |||
@@ -1,9 +1,9 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <assert.h> | 1 | #include <assert.h> |
3 | #include <wlr/interfaces/wlr_keyboard.h> | 2 | #include <wlr/interfaces/wlr_keyboard.h> |
4 | #include "sway/config.h" | 3 | #include "sway/config.h" |
5 | #include "sway/commands.h" | 4 | #include "sway/commands.h" |
6 | #include "sway/input/input-manager.h" | 5 | #include "sway/input/input-manager.h" |
6 | #include "sway/server.h" | ||
7 | #include "log.h" | 7 | #include "log.h" |
8 | 8 | ||
9 | struct xkb_switch_layout_action { | 9 | struct xkb_switch_layout_action { |
diff --git a/sway/commands/input/xkb_variant.c b/sway/commands/input/xkb_variant.c index d0e21d77..2d14ea9c 100644 --- a/sway/commands/input/xkb_variant.c +++ b/sway/commands/input/xkb_variant.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include "sway/config.h" | 1 | #include "sway/config.h" |
3 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
4 | #include "log.h" | 3 | #include "log.h" |
diff --git a/sway/commands/mark.c b/sway/commands/mark.c index 30cf458c..2bfc86b3 100644 --- a/sway/commands/mark.c +++ b/sway/commands/mark.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <string.h> | 1 | #include <string.h> |
3 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
4 | #include "sway/config.h" | 3 | #include "sway/config.h" |
diff --git a/sway/commands/mode.c b/sway/commands/mode.c index 7263efcb..b3216967 100644 --- a/sway/commands/mode.c +++ b/sway/commands/mode.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <stdbool.h> | 1 | #include <stdbool.h> |
3 | #include <string.h> | 2 | #include <string.h> |
4 | #include "sway/commands.h" | 3 | #include "sway/commands.h" |
diff --git a/sway/commands/move.c b/sway/commands/move.c index 69ed06c0..ff656cfb 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <ctype.h> | 1 | #include <ctype.h> |
3 | #include <math.h> | 2 | #include <math.h> |
4 | #include <stdbool.h> | 3 | #include <stdbool.h> |
@@ -12,6 +11,7 @@ | |||
12 | #include "sway/input/seat.h" | 11 | #include "sway/input/seat.h" |
13 | #include "sway/ipc-server.h" | 12 | #include "sway/ipc-server.h" |
14 | #include "sway/output.h" | 13 | #include "sway/output.h" |
14 | #include "sway/server.h" | ||
15 | #include "sway/tree/arrange.h" | 15 | #include "sway/tree/arrange.h" |
16 | #include "sway/tree/container.h" | 16 | #include "sway/tree/container.h" |
17 | #include "sway/tree/root.h" | 17 | #include "sway/tree/root.h" |
@@ -770,15 +770,6 @@ static struct cmd_results *cmd_move_in_direction( | |||
770 | ipc_event_window(container, "move"); | 770 | ipc_event_window(container, "move"); |
771 | } | 771 | } |
772 | 772 | ||
773 | // Hack to re-focus container | ||
774 | seat_set_raw_focus(config->handler_context.seat, &new_ws->node); | ||
775 | seat_set_focus_container(config->handler_context.seat, container); | ||
776 | |||
777 | if (old_ws != new_ws) { | ||
778 | ipc_event_workspace(old_ws, new_ws, "focus"); | ||
779 | workspace_detect_urgent(old_ws); | ||
780 | workspace_detect_urgent(new_ws); | ||
781 | } | ||
782 | container_end_mouse_operation(container); | 773 | container_end_mouse_operation(container); |
783 | 774 | ||
784 | return cmd_results_new(CMD_SUCCESS, NULL); | 775 | return cmd_results_new(CMD_SUCCESS, NULL); |
diff --git a/sway/commands/output.c b/sway/commands/output.c index df32c673..b822e770 100644 --- a/sway/commands/output.c +++ b/sway/commands/output.c | |||
@@ -10,6 +10,7 @@ static const struct cmd_handler output_handlers[] = { | |||
10 | { "adaptive_sync", output_cmd_adaptive_sync }, | 10 | { "adaptive_sync", output_cmd_adaptive_sync }, |
11 | { "background", output_cmd_background }, | 11 | { "background", output_cmd_background }, |
12 | { "bg", output_cmd_background }, | 12 | { "bg", output_cmd_background }, |
13 | { "color_profile", output_cmd_color_profile }, | ||
13 | { "disable", output_cmd_disable }, | 14 | { "disable", output_cmd_disable }, |
14 | { "dpms", output_cmd_dpms }, | 15 | { "dpms", output_cmd_dpms }, |
15 | { "enable", output_cmd_enable }, | 16 | { "enable", output_cmd_enable }, |
@@ -103,15 +104,18 @@ struct cmd_results *cmd_output(int argc, char **argv) { | |||
103 | 104 | ||
104 | bool background = output->background; | 105 | bool background = output->background; |
105 | 106 | ||
106 | output = store_output_config(output); | 107 | store_output_config(output); |
107 | 108 | ||
108 | // If reloading, the output configs will be applied after reading the | 109 | // If reloading, the output configs will be applied after reading the |
109 | // entire config and before the deferred commands so that an auto generated | 110 | // entire config and before the deferred commands so that an auto generated |
110 | // workspace name is not given to re-enabled outputs. | 111 | // workspace name is not given to re-enabled outputs. |
111 | if (!config->reloading && !config->validating) { | 112 | if (!config->reloading && !config->validating) { |
112 | apply_output_config_to_outputs(output); | 113 | apply_all_output_configs(); |
113 | if (background) { | 114 | if (background) { |
114 | spawn_swaybg(); | 115 | if (!spawn_swaybg()) { |
116 | return cmd_results_new(CMD_FAILURE, | ||
117 | "Failed to apply background configuration"); | ||
118 | } | ||
115 | } | 119 | } |
116 | } | 120 | } |
117 | 121 | ||
diff --git a/sway/commands/output/background.c b/sway/commands/output/background.c index d691295f..55bd7671 100644 --- a/sway/commands/output/background.c +++ b/sway/commands/output/background.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <libgen.h> | 1 | #include <libgen.h> |
3 | #include <stdio.h> | 2 | #include <stdio.h> |
4 | #include <string.h> | 3 | #include <string.h> |
diff --git a/sway/commands/output/color_profile.c b/sway/commands/output/color_profile.c new file mode 100644 index 00000000..792bd55f --- /dev/null +++ b/sway/commands/output/color_profile.c | |||
@@ -0,0 +1,101 @@ | |||
1 | #include <fcntl.h> | ||
2 | #include <strings.h> | ||
3 | #include <sys/stat.h> | ||
4 | #include <unistd.h> | ||
5 | #include <wlr/render/color.h> | ||
6 | #include "sway/commands.h" | ||
7 | #include "sway/config.h" | ||
8 | |||
9 | static bool read_file_into_buf(const char *path, void **buf, size_t *size) { | ||
10 | /* Why not use fopen/fread directly? glibc will succesfully open directories, | ||
11 | * not just files, and supports seeking on them. Instead, we directly | ||
12 | * work with file descriptors and use the more consistent open/fstat/read. */ | ||
13 | int fd = open(path, O_RDONLY | O_NOCTTY | O_CLOEXEC); | ||
14 | if (fd == -1) { | ||
15 | return false; | ||
16 | } | ||
17 | char *b = NULL; | ||
18 | struct stat info; | ||
19 | if (fstat(fd, &info) == -1) { | ||
20 | goto fail; | ||
21 | } | ||
22 | // only regular files, to avoid issues with e.g. opening pipes | ||
23 | if (!S_ISREG(info.st_mode)) { | ||
24 | goto fail; | ||
25 | } | ||
26 | off_t s = info.st_size; | ||
27 | if (s <= 0) { | ||
28 | goto fail; | ||
29 | } | ||
30 | b = calloc(1, s); | ||
31 | if (!b) { | ||
32 | goto fail; | ||
33 | } | ||
34 | size_t nread = 0; | ||
35 | while (nread < (size_t)s) { | ||
36 | size_t to_read = (size_t)s - nread; | ||
37 | ssize_t r = read(fd, b + nread, to_read); | ||
38 | if ((r == -1 && errno != EINTR) || r == 0) { | ||
39 | goto fail; | ||
40 | } | ||
41 | nread += (size_t)r; | ||
42 | } | ||
43 | close(fd); | ||
44 | *buf = b; | ||
45 | *size = (size_t)s; | ||
46 | return true; // success | ||
47 | fail: | ||
48 | free(b); | ||
49 | close(fd); | ||
50 | return false; | ||
51 | } | ||
52 | |||
53 | struct cmd_results *output_cmd_color_profile(int argc, char **argv) { | ||
54 | if (!config->handler_context.output_config) { | ||
55 | return cmd_results_new(CMD_FAILURE, "Missing output config"); | ||
56 | } | ||
57 | if (!argc) { | ||
58 | return cmd_results_new(CMD_INVALID, "Missing color_profile first argument."); | ||
59 | } | ||
60 | |||
61 | if (strcmp(*argv, "srgb") == 0) { | ||
62 | wlr_color_transform_unref(config->handler_context.output_config->color_transform); | ||
63 | config->handler_context.output_config->color_transform = NULL; | ||
64 | config->handler_context.output_config->set_color_transform = true; | ||
65 | |||
66 | config->handler_context.leftovers.argc = argc - 1; | ||
67 | config->handler_context.leftovers.argv = argv + 1; | ||
68 | } else if (strcmp(*argv, "icc") == 0) { | ||
69 | if (argc < 2) { | ||
70 | return cmd_results_new(CMD_INVALID, | ||
71 | "Invalid color profile specification: icc type requires a file"); | ||
72 | } | ||
73 | void *data = NULL; | ||
74 | size_t size = 0; | ||
75 | if (!read_file_into_buf(argv[1], &data, &size)) { | ||
76 | return cmd_results_new(CMD_FAILURE, | ||
77 | "Failed to load color profile: could not read ICC file"); | ||
78 | } | ||
79 | |||
80 | struct wlr_color_transform *tmp = | ||
81 | wlr_color_transform_init_linear_to_icc(data, size); | ||
82 | if (!tmp) { | ||
83 | free(data); | ||
84 | return cmd_results_new(CMD_FAILURE, | ||
85 | "Failed to load color profile: failed to initialize transform from ICC"); | ||
86 | } | ||
87 | free(data); | ||
88 | |||
89 | wlr_color_transform_unref(config->handler_context.output_config->color_transform); | ||
90 | config->handler_context.output_config->color_transform = tmp; | ||
91 | config->handler_context.output_config->set_color_transform = true; | ||
92 | |||
93 | config->handler_context.leftovers.argc = argc - 2; | ||
94 | config->handler_context.leftovers.argv = argv + 2; | ||
95 | } else { | ||
96 | return cmd_results_new(CMD_INVALID, | ||
97 | "Invalid color profile specification: first argument should be icc|srgb"); | ||
98 | } | ||
99 | |||
100 | return NULL; | ||
101 | } | ||
diff --git a/sway/commands/output/toggle.c b/sway/commands/output/toggle.c index 6342d526..c6b72845 100644 --- a/sway/commands/output/toggle.c +++ b/sway/commands/output/toggle.c | |||
@@ -29,7 +29,7 @@ struct cmd_results *output_cmd_toggle(int argc, char **argv) { | |||
29 | config->handler_context.output_config->enabled = 1; | 29 | config->handler_context.output_config->enabled = 1; |
30 | } | 30 | } |
31 | 31 | ||
32 | free(oc); | 32 | free_output_config(oc); |
33 | config->handler_context.leftovers.argc = argc; | 33 | config->handler_context.leftovers.argc = argc; |
34 | config->handler_context.leftovers.argv = argv; | 34 | config->handler_context.leftovers.argv = argv; |
35 | return NULL; | 35 | return NULL; |
diff --git a/sway/commands/primary_selection.c b/sway/commands/primary_selection.c index 585b079d..9e2689c2 100644 --- a/sway/commands/primary_selection.c +++ b/sway/commands/primary_selection.c | |||
@@ -12,12 +12,14 @@ struct cmd_results *cmd_primary_selection(int argc, char **argv) { | |||
12 | 12 | ||
13 | bool primary_selection = parse_boolean(argv[0], true); | 13 | bool primary_selection = parse_boolean(argv[0], true); |
14 | 14 | ||
15 | // config->primary_selection is reset to the previous value on reload in | ||
16 | // load_main_config() | ||
15 | if (config->reloading && config->primary_selection != primary_selection) { | 17 | if (config->reloading && config->primary_selection != primary_selection) { |
16 | return cmd_results_new(CMD_FAILURE, | 18 | return cmd_results_new(CMD_FAILURE, |
17 | "primary_selection can only be enabled/disabled at launch"); | 19 | "primary_selection can only be enabled/disabled at launch"); |
18 | } | 20 | } |
19 | 21 | ||
20 | config->primary_selection = parse_boolean(argv[0], true); | 22 | config->primary_selection = primary_selection; |
21 | 23 | ||
22 | return cmd_results_new(CMD_SUCCESS, NULL); | 24 | return cmd_results_new(CMD_SUCCESS, NULL); |
23 | } | 25 | } |
diff --git a/sway/commands/reload.c b/sway/commands/reload.c index 82967ca7..6c0aac26 100644 --- a/sway/commands/reload.c +++ b/sway/commands/reload.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <string.h> | 1 | #include <string.h> |
3 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
4 | #include "sway/config.h" | 3 | #include "sway/config.h" |
diff --git a/sway/commands/seat/attach.c b/sway/commands/seat/attach.c index 00bfdab6..47d18546 100644 --- a/sway/commands/seat/attach.c +++ b/sway/commands/seat/attach.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <string.h> | 1 | #include <string.h> |
3 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
4 | #include "sway/config.h" | 3 | #include "sway/config.h" |
diff --git a/sway/commands/seat/cursor.c b/sway/commands/seat/cursor.c index 5a8a3bc8..434e6bbb 100644 --- a/sway/commands/seat/cursor.c +++ b/sway/commands/seat/cursor.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <linux/input-event-codes.h> | 1 | #include <linux/input-event-codes.h> |
3 | 2 | ||
4 | #include <strings.h> | 3 | #include <strings.h> |
@@ -6,6 +5,7 @@ | |||
6 | #include <wlr/types/wlr_pointer.h> | 5 | #include <wlr/types/wlr_pointer.h> |
7 | #include "sway/commands.h" | 6 | #include "sway/commands.h" |
8 | #include "sway/input/cursor.h" | 7 | #include "sway/input/cursor.h" |
8 | #include "sway/server.h" | ||
9 | 9 | ||
10 | static struct cmd_results *press_or_release(struct sway_cursor *cursor, | 10 | static struct cmd_results *press_or_release(struct sway_cursor *cursor, |
11 | char *action, char *button_str); | 11 | char *action, char *button_str); |
@@ -85,12 +85,12 @@ struct cmd_results *seat_cmd_cursor(int argc, char **argv) { | |||
85 | 85 | ||
86 | static struct cmd_results *press_or_release(struct sway_cursor *cursor, | 86 | static struct cmd_results *press_or_release(struct sway_cursor *cursor, |
87 | char *action, char *button_str) { | 87 | char *action, char *button_str) { |
88 | enum wlr_button_state state; | 88 | enum wl_pointer_button_state state; |
89 | uint32_t button; | 89 | uint32_t button; |
90 | if (strcasecmp(action, "press") == 0) { | 90 | if (strcasecmp(action, "press") == 0) { |
91 | state = WLR_BUTTON_PRESSED; | 91 | state = WL_POINTER_BUTTON_STATE_PRESSED; |
92 | } else if (strcasecmp(action, "release") == 0) { | 92 | } else if (strcasecmp(action, "release") == 0) { |
93 | state = WLR_BUTTON_RELEASED; | 93 | state = WL_POINTER_BUTTON_STATE_RELEASED; |
94 | } else { | 94 | } else { |
95 | return cmd_results_new(CMD_INVALID, "%s", expected_syntax); | 95 | return cmd_results_new(CMD_INVALID, "%s", expected_syntax); |
96 | } | 96 | } |
@@ -105,16 +105,16 @@ static struct cmd_results *press_or_release(struct sway_cursor *cursor, | |||
105 | } else if (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_DOWN | 105 | } else if (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_DOWN |
106 | || button == SWAY_SCROLL_LEFT || button == SWAY_SCROLL_RIGHT) { | 106 | || button == SWAY_SCROLL_LEFT || button == SWAY_SCROLL_RIGHT) { |
107 | // Dispatch axis event | 107 | // Dispatch axis event |
108 | enum wlr_axis_orientation orientation = | 108 | enum wl_pointer_axis orientation = |
109 | (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_DOWN) | 109 | (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_DOWN) |
110 | ? WLR_AXIS_ORIENTATION_VERTICAL | 110 | ? WL_POINTER_AXIS_VERTICAL_SCROLL |
111 | : WLR_AXIS_ORIENTATION_HORIZONTAL; | 111 | : WL_POINTER_AXIS_HORIZONTAL_SCROLL; |
112 | double delta = (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_LEFT) | 112 | double delta = (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_LEFT) |
113 | ? -1 : 1; | 113 | ? -1 : 1; |
114 | struct wlr_pointer_axis_event event = { | 114 | struct wlr_pointer_axis_event event = { |
115 | .pointer = NULL, | 115 | .pointer = NULL, |
116 | .time_msec = 0, | 116 | .time_msec = 0, |
117 | .source = WLR_AXIS_SOURCE_WHEEL, | 117 | .source = WL_POINTER_AXIS_SOURCE_WHEEL, |
118 | .orientation = orientation, | 118 | .orientation = orientation, |
119 | .delta = delta * 15, | 119 | .delta = delta * 15, |
120 | .delta_discrete = delta | 120 | .delta_discrete = delta |
diff --git a/sway/commands/seat/hide_cursor.c b/sway/commands/seat/hide_cursor.c index e09b82d9..f5177a47 100644 --- a/sway/commands/seat/hide_cursor.c +++ b/sway/commands/seat/hide_cursor.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <string.h> | 1 | #include <string.h> |
3 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
4 | #include "sway/config.h" | 3 | #include "sway/config.h" |
diff --git a/sway/commands/seat/idle.c b/sway/commands/seat/idle.c index 62b94db2..2974453e 100644 --- a/sway/commands/seat/idle.c +++ b/sway/commands/seat/idle.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <limits.h> | 1 | #include <limits.h> |
3 | #include <string.h> | 2 | #include <string.h> |
4 | #include <strings.h> | 3 | #include <strings.h> |
diff --git a/sway/commands/seat/pointer_constraint.c b/sway/commands/seat/pointer_constraint.c index 3890ebde..38f85bcd 100644 --- a/sway/commands/seat/pointer_constraint.c +++ b/sway/commands/seat/pointer_constraint.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include "sway/config.h" | 4 | #include "sway/config.h" |
5 | #include "sway/input/cursor.h" | 5 | #include "sway/input/cursor.h" |
6 | #include "sway/input/seat.h" | 6 | #include "sway/input/seat.h" |
7 | #include "sway/server.h" | ||
7 | 8 | ||
8 | enum operation { | 9 | enum operation { |
9 | OP_ENABLE, | 10 | OP_ENABLE, |
diff --git a/sway/commands/seat/shortcuts_inhibitor.c b/sway/commands/seat/shortcuts_inhibitor.c index 7c7f99cf..df68618d 100644 --- a/sway/commands/seat/shortcuts_inhibitor.c +++ b/sway/commands/seat/shortcuts_inhibitor.c | |||
@@ -2,6 +2,7 @@ | |||
2 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
3 | #include "sway/input/seat.h" | 3 | #include "sway/input/seat.h" |
4 | #include "sway/input/input-manager.h" | 4 | #include "sway/input/input-manager.h" |
5 | #include "sway/server.h" | ||
5 | #include "util.h" | 6 | #include "util.h" |
6 | 7 | ||
7 | static struct cmd_results *handle_action(struct seat_config *sc, | 8 | static struct cmd_results *handle_action(struct seat_config *sc, |
diff --git a/sway/commands/seat/xcursor_theme.c b/sway/commands/seat/xcursor_theme.c index 202f35b9..61322a57 100644 --- a/sway/commands/seat/xcursor_theme.c +++ b/sway/commands/seat/xcursor_theme.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <string.h> | 1 | #include <string.h> |
3 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
4 | #include "sway/config.h" | 3 | #include "sway/config.h" |
diff --git a/sway/commands/set.c b/sway/commands/set.c index c539e9fc..ba384c7c 100644 --- a/sway/commands/set.c +++ b/sway/commands/set.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <stdio.h> | 1 | #include <stdio.h> |
3 | #include <string.h> | 2 | #include <string.h> |
4 | #include <strings.h> | 3 | #include <strings.h> |
diff --git a/sway/commands/shortcuts_inhibitor.c b/sway/commands/shortcuts_inhibitor.c index ffa1a5c9..2dfd1b9f 100644 --- a/sway/commands/shortcuts_inhibitor.c +++ b/sway/commands/shortcuts_inhibitor.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include "sway/commands.h" | 3 | #include "sway/commands.h" |
4 | #include "sway/config.h" | 4 | #include "sway/config.h" |
5 | #include "sway/input/seat.h" | 5 | #include "sway/input/seat.h" |
6 | #include "sway/server.h" | ||
6 | #include "sway/tree/container.h" | 7 | #include "sway/tree/container.h" |
7 | #include "sway/tree/view.h" | 8 | #include "sway/tree/view.h" |
8 | 9 | ||
diff --git a/sway/commands/show_marks.c b/sway/commands/show_marks.c index fecb5ade..60cef9fa 100644 --- a/sway/commands/show_marks.c +++ b/sway/commands/show_marks.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <string.h> | 1 | #include <string.h> |
3 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
4 | #include "sway/config.h" | 3 | #include "sway/config.h" |
diff --git a/sway/commands/swap.c b/sway/commands/swap.c index d44eb006..c0b0d0b9 100644 --- a/sway/commands/swap.c +++ b/sway/commands/swap.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <strings.h> | 1 | #include <strings.h> |
3 | #include "config.h" | 2 | #include "config.h" |
4 | #include "log.h" | 3 | #include "log.h" |
@@ -19,7 +18,7 @@ static bool test_con_id(struct sway_container *container, void *data) { | |||
19 | return container->node.id == *con_id; | 18 | return container->node.id == *con_id; |
20 | } | 19 | } |
21 | 20 | ||
22 | #if HAVE_XWAYLAND | 21 | #if WLR_HAS_XWAYLAND |
23 | static bool test_id(struct sway_container *container, void *data) { | 22 | static bool test_id(struct sway_container *container, void *data) { |
24 | xcb_window_t *wid = data; | 23 | xcb_window_t *wid = data; |
25 | return (container->view && container->view->type == SWAY_VIEW_XWAYLAND | 24 | return (container->view && container->view->type == SWAY_VIEW_XWAYLAND |
@@ -54,7 +53,7 @@ struct cmd_results *cmd_swap(int argc, char **argv) { | |||
54 | 53 | ||
55 | char *value = join_args(argv + 3, argc - 3); | 54 | char *value = join_args(argv + 3, argc - 3); |
56 | if (strcasecmp(argv[2], "id") == 0) { | 55 | if (strcasecmp(argv[2], "id") == 0) { |
57 | #if HAVE_XWAYLAND | 56 | #if WLR_HAS_XWAYLAND |
58 | xcb_window_t id = strtol(value, NULL, 0); | 57 | xcb_window_t id = strtol(value, NULL, 0); |
59 | other = root_find_container(test_id, &id); | 58 | other = root_find_container(test_id, &id); |
60 | #endif | 59 | #endif |
diff --git a/sway/commands/title_format.c b/sway/commands/title_format.c index a2446b7e..0b2ea265 100644 --- a/sway/commands/title_format.c +++ b/sway/commands/title_format.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <string.h> | 1 | #include <string.h> |
3 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
4 | #include "sway/config.h" | 3 | #include "sway/config.h" |
diff --git a/sway/commands/unmark.c b/sway/commands/unmark.c index c3a6ac4b..4aba5bae 100644 --- a/sway/commands/unmark.c +++ b/sway/commands/unmark.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <string.h> | 1 | #include <string.h> |
3 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
4 | #include "sway/config.h" | 3 | #include "sway/config.h" |
diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c index 8536929e..37a201b4 100644 --- a/sway/commands/workspace.c +++ b/sway/commands/workspace.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <ctype.h> | 1 | #include <ctype.h> |
3 | #include <limits.h> | 2 | #include <limits.h> |
4 | #include <string.h> | 3 | #include <string.h> |
diff --git a/sway/commands/xwayland.c b/sway/commands/xwayland.c index 6ca26923..c0b175fc 100644 --- a/sway/commands/xwayland.c +++ b/sway/commands/xwayland.c | |||
@@ -10,7 +10,7 @@ struct cmd_results *cmd_xwayland(int argc, char **argv) { | |||
10 | return error; | 10 | return error; |
11 | } | 11 | } |
12 | 12 | ||
13 | #ifdef HAVE_XWAYLAND | 13 | #ifdef WLR_HAS_XWAYLAND |
14 | enum xwayland_mode xwayland; | 14 | enum xwayland_mode xwayland; |
15 | if (strcmp(argv[0], "force") == 0) { | 15 | if (strcmp(argv[0], "force") == 0) { |
16 | xwayland = XWAYLAND_MODE_IMMEDIATE; | 16 | xwayland = XWAYLAND_MODE_IMMEDIATE; |
@@ -20,6 +20,8 @@ struct cmd_results *cmd_xwayland(int argc, char **argv) { | |||
20 | xwayland = XWAYLAND_MODE_DISABLED; | 20 | xwayland = XWAYLAND_MODE_DISABLED; |
21 | } | 21 | } |
22 | 22 | ||
23 | // config->xwayland is reset to the previous value on reload in | ||
24 | // load_main_config() | ||
23 | if (config->reloading && config->xwayland != xwayland) { | 25 | if (config->reloading && config->xwayland != xwayland) { |
24 | return cmd_results_new(CMD_FAILURE, | 26 | return cmd_results_new(CMD_FAILURE, |
25 | "xwayland can only be enabled/disabled at launch"); | 27 | "xwayland can only be enabled/disabled at launch"); |
diff --git a/sway/config.c b/sway/config.c index 4b51dc73..5058efcc 100644 --- a/sway/config.c +++ b/sway/config.c | |||
@@ -1,3 +1,4 @@ | |||
1 | #undef _POSIX_C_SOURCE | ||
1 | #define _XOPEN_SOURCE 700 // for realpath | 2 | #define _XOPEN_SOURCE 700 // for realpath |
2 | #include <stdio.h> | 3 | #include <stdio.h> |
3 | #include <stdbool.h> | 4 | #include <stdbool.h> |
@@ -22,6 +23,7 @@ | |||
22 | #include "sway/config.h" | 23 | #include "sway/config.h" |
23 | #include "sway/criteria.h" | 24 | #include "sway/criteria.h" |
24 | #include "sway/desktop/transaction.h" | 25 | #include "sway/desktop/transaction.h" |
26 | #include "sway/server.h" | ||
25 | #include "sway/swaynag.h" | 27 | #include "sway/swaynag.h" |
26 | #include "sway/tree/arrange.h" | 28 | #include "sway/tree/arrange.h" |
27 | #include "sway/tree/root.h" | 29 | #include "sway/tree/root.h" |
@@ -36,19 +38,26 @@ | |||
36 | struct sway_config *config = NULL; | 38 | struct sway_config *config = NULL; |
37 | 39 | ||
38 | static struct xkb_state *keysym_translation_state_create( | 40 | static struct xkb_state *keysym_translation_state_create( |
39 | struct xkb_rule_names rules) { | 41 | struct xkb_rule_names rules, uint32_t context_flags) { |
40 | struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_SECURE_GETENV); | 42 | struct xkb_context *context = xkb_context_new(context_flags | XKB_CONTEXT_NO_SECURE_GETENV); |
41 | struct xkb_keymap *xkb_keymap = xkb_keymap_new_from_names( | 43 | struct xkb_keymap *xkb_keymap = xkb_keymap_new_from_names( |
42 | context, | 44 | context, |
43 | &rules, | 45 | &rules, |
44 | XKB_KEYMAP_COMPILE_NO_FLAGS); | 46 | XKB_KEYMAP_COMPILE_NO_FLAGS); |
45 | |||
46 | xkb_context_unref(context); | 47 | xkb_context_unref(context); |
48 | if (xkb_keymap == NULL) { | ||
49 | sway_log(SWAY_ERROR, "Failed to compile keysym translation XKB keymap"); | ||
50 | return NULL; | ||
51 | } | ||
52 | |||
47 | return xkb_state_new(xkb_keymap); | 53 | return xkb_state_new(xkb_keymap); |
48 | } | 54 | } |
49 | 55 | ||
50 | static void keysym_translation_state_destroy( | 56 | static void keysym_translation_state_destroy( |
51 | struct xkb_state *state) { | 57 | struct xkb_state *state) { |
58 | if (state == NULL) { | ||
59 | return; | ||
60 | } | ||
52 | xkb_keymap_unref(xkb_state_get_keymap(state)); | 61 | xkb_keymap_unref(xkb_state_get_keymap(state)); |
53 | xkb_state_unref(state); | 62 | xkb_state_unref(state); |
54 | } | 63 | } |
@@ -336,8 +345,14 @@ static void config_defaults(struct sway_config *config) { | |||
336 | 345 | ||
337 | // The keysym to keycode translation | 346 | // The keysym to keycode translation |
338 | struct xkb_rule_names rules = {0}; | 347 | struct xkb_rule_names rules = {0}; |
339 | config->keysym_translation_state = | 348 | config->keysym_translation_state = keysym_translation_state_create(rules, 0); |
340 | keysym_translation_state_create(rules); | 349 | if (config->keysym_translation_state == NULL) { |
350 | config->keysym_translation_state = keysym_translation_state_create(rules, | ||
351 | XKB_CONTEXT_NO_ENVIRONMENT_NAMES); | ||
352 | } | ||
353 | if (config->keysym_translation_state == NULL) { | ||
354 | goto cleanup; | ||
355 | } | ||
341 | 356 | ||
342 | return; | 357 | return; |
343 | cleanup: | 358 | cleanup: |
@@ -352,13 +367,7 @@ static char *config_path(const char *prefix, const char *config_folder) { | |||
352 | if (!prefix || !prefix[0] || !config_folder || !config_folder[0]) { | 367 | if (!prefix || !prefix[0] || !config_folder || !config_folder[0]) { |
353 | return NULL; | 368 | return NULL; |
354 | } | 369 | } |
355 | 370 | return format_str("%s/%s/config", prefix, config_folder); | |
356 | const char *filename = "config"; | ||
357 | |||
358 | size_t size = 3 + strlen(prefix) + strlen(config_folder) + strlen(filename); | ||
359 | char *path = calloc(size, sizeof(char)); | ||
360 | snprintf(path, size, "%s/%s/%s", prefix, config_folder, filename); | ||
361 | return path; | ||
362 | } | 371 | } |
363 | 372 | ||
364 | static char *get_config_path(void) { | 373 | static char *get_config_path(void) { |
@@ -368,10 +377,7 @@ static char *get_config_path(void) { | |||
368 | 377 | ||
369 | const char *config_home = getenv("XDG_CONFIG_HOME"); | 378 | const char *config_home = getenv("XDG_CONFIG_HOME"); |
370 | if ((config_home == NULL || config_home[0] == '\0') && home != NULL) { | 379 | if ((config_home == NULL || config_home[0] == '\0') && home != NULL) { |
371 | size_t size_fallback = 1 + strlen(home) + strlen("/.config"); | 380 | config_home_fallback = format_str("%s/.config", home); |
372 | config_home_fallback = calloc(size_fallback, sizeof(char)); | ||
373 | if (config_home_fallback != NULL) | ||
374 | snprintf(config_home_fallback, size_fallback, "%s/.config", home); | ||
375 | config_home = config_home_fallback; | 381 | config_home = config_home_fallback; |
376 | } | 382 | } |
377 | 383 | ||
@@ -475,6 +481,11 @@ bool load_main_config(const char *file, bool is_active, bool validating) { | |||
475 | old_config->xwayland ? "enabled" : "disabled"); | 481 | old_config->xwayland ? "enabled" : "disabled"); |
476 | config->xwayland = old_config->xwayland; | 482 | config->xwayland = old_config->xwayland; |
477 | 483 | ||
484 | // primary_selection can only be enabled/disabled at launch | ||
485 | sway_log(SWAY_DEBUG, "primary_selection will remain %s", | ||
486 | old_config->primary_selection ? "enabled" : "disabled"); | ||
487 | config->primary_selection = old_config->primary_selection; | ||
488 | |||
478 | if (!config->validating) { | 489 | if (!config->validating) { |
479 | if (old_config->swaybg_client != NULL) { | 490 | if (old_config->swaybg_client != NULL) { |
480 | wl_client_destroy(old_config->swaybg_client); | 491 | wl_client_destroy(old_config->swaybg_client); |
@@ -494,56 +505,7 @@ bool load_main_config(const char *file, bool is_active, bool validating) { | |||
494 | 505 | ||
495 | config->reading = true; | 506 | config->reading = true; |
496 | 507 | ||
497 | // Read security configs | 508 | bool success = load_config(path, config, &config->swaynag_config_errors); |
498 | // TODO: Security | ||
499 | bool success = true; | ||
500 | /* | ||
501 | DIR *dir = opendir(SYSCONFDIR "/sway/security.d"); | ||
502 | if (!dir) { | ||
503 | sway_log(SWAY_ERROR, | ||
504 | "%s does not exist, sway will have no security configuration" | ||
505 | " and will probably be broken", SYSCONFDIR "/sway/security.d"); | ||
506 | } else { | ||
507 | list_t *secconfigs = create_list(); | ||
508 | char *base = SYSCONFDIR "/sway/security.d/"; | ||
509 | struct dirent *ent = readdir(dir); | ||
510 | struct stat s; | ||
511 | while (ent != NULL) { | ||
512 | char *_path = malloc(strlen(ent->d_name) + strlen(base) + 1); | ||
513 | strcpy(_path, base); | ||
514 | strcat(_path, ent->d_name); | ||
515 | lstat(_path, &s); | ||
516 | if (S_ISREG(s.st_mode) && ent->d_name[0] != '.') { | ||
517 | list_add(secconfigs, _path); | ||
518 | } | ||
519 | else { | ||
520 | free(_path); | ||
521 | } | ||
522 | ent = readdir(dir); | ||
523 | } | ||
524 | closedir(dir); | ||
525 | |||
526 | list_qsort(secconfigs, qstrcmp); | ||
527 | for (int i = 0; i < secconfigs->length; ++i) { | ||
528 | char *_path = secconfigs->items[i]; | ||
529 | if (stat(_path, &s) || s.st_uid != 0 || s.st_gid != 0 || | ||
530 | (((s.st_mode & 0777) != 0644) && | ||
531 | (s.st_mode & 0777) != 0444)) { | ||
532 | sway_log(SWAY_ERROR, | ||
533 | "Refusing to load %s - it must be owned by root " | ||
534 | "and mode 644 or 444", _path); | ||
535 | success = false; | ||
536 | } else { | ||
537 | success = success && load_config(_path, config); | ||
538 | } | ||
539 | } | ||
540 | |||
541 | list_free_items_and_destroy(secconfigs); | ||
542 | } | ||
543 | */ | ||
544 | |||
545 | success = success && load_config(path, config, | ||
546 | &config->swaynag_config_errors); | ||
547 | 509 | ||
548 | if (validating) { | 510 | if (validating) { |
549 | free_config(config); | 511 | free_config(config); |
@@ -571,7 +533,7 @@ bool load_main_config(const char *file, bool is_active, bool validating) { | |||
571 | } | 533 | } |
572 | sway_switch_retrigger_bindings_for_all(); | 534 | sway_switch_retrigger_bindings_for_all(); |
573 | 535 | ||
574 | reset_outputs(); | 536 | apply_all_output_configs(); |
575 | spawn_swaybg(); | 537 | spawn_swaybg(); |
576 | 538 | ||
577 | config->reloading = false; | 539 | config->reloading = false; |
@@ -1037,8 +999,12 @@ void translate_keysyms(struct input_config *input_config) { | |||
1037 | 999 | ||
1038 | struct xkb_rule_names rules = {0}; | 1000 | struct xkb_rule_names rules = {0}; |
1039 | input_config_fill_rule_names(input_config, &rules); | 1001 | input_config_fill_rule_names(input_config, &rules); |
1040 | config->keysym_translation_state = | 1002 | config->keysym_translation_state = keysym_translation_state_create(rules, 0); |
1041 | keysym_translation_state_create(rules); | 1003 | if (config->keysym_translation_state == NULL) { |
1004 | sway_log(SWAY_ERROR, "Failed to create keysym translation XKB state " | ||
1005 | "for device '%s'", input_config->identifier); | ||
1006 | return; | ||
1007 | } | ||
1042 | 1008 | ||
1043 | for (int i = 0; i < config->modes->length; ++i) { | 1009 | for (int i = 0; i < config->modes->length; ++i) { |
1044 | struct sway_mode *mode = config->modes->items[i]; | 1010 | struct sway_mode *mode = config->modes->items[i]; |
diff --git a/sway/config/bar.c b/sway/config/bar.c index a8389244..ecefb61a 100644 --- a/sway/config/bar.c +++ b/sway/config/bar.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <signal.h> | 1 | #include <signal.h> |
3 | #include <stdbool.h> | 2 | #include <stdbool.h> |
4 | #include <stdio.h> | 3 | #include <stdio.h> |
@@ -13,6 +12,7 @@ | |||
13 | #include "sway/config.h" | 12 | #include "sway/config.h" |
14 | #include "sway/input/keyboard.h" | 13 | #include "sway/input/keyboard.h" |
15 | #include "sway/output.h" | 14 | #include "sway/output.h" |
15 | #include "sway/server.h" | ||
16 | #include "config.h" | 16 | #include "config.h" |
17 | #include "list.h" | 17 | #include "list.h" |
18 | #include "log.h" | 18 | #include "log.h" |
diff --git a/sway/config/input.c b/sway/config/input.c index 44c2be28..613270df 100644 --- a/sway/config/input.c +++ b/sway/config/input.c | |||
@@ -1,9 +1,9 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <stdlib.h> | 1 | #include <stdlib.h> |
3 | #include <limits.h> | 2 | #include <limits.h> |
4 | #include <float.h> | 3 | #include <float.h> |
5 | #include "sway/config.h" | 4 | #include "sway/config.h" |
6 | #include "sway/input/keyboard.h" | 5 | #include "sway/input/keyboard.h" |
6 | #include "sway/server.h" | ||
7 | #include "log.h" | 7 | #include "log.h" |
8 | 8 | ||
9 | struct input_config *new_input_config(const char* identifier) { | 9 | struct input_config *new_input_config(const char* identifier) { |
diff --git a/sway/config/output.c b/sway/config/output.c index 1a5215fe..16be49c8 100644 --- a/sway/config/output.c +++ b/sway/config/output.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <assert.h> | 1 | #include <assert.h> |
3 | #include <drm_fourcc.h> | 2 | #include <drm_fourcc.h> |
4 | #include <stdbool.h> | 3 | #include <stdbool.h> |
@@ -10,9 +9,11 @@ | |||
10 | #include <wlr/types/wlr_cursor.h> | 9 | #include <wlr/types/wlr_cursor.h> |
11 | #include <wlr/types/wlr_output_layout.h> | 10 | #include <wlr/types/wlr_output_layout.h> |
12 | #include <wlr/types/wlr_output.h> | 11 | #include <wlr/types/wlr_output.h> |
12 | #include <wlr/types/wlr_output_swapchain_manager.h> | ||
13 | #include "sway/config.h" | 13 | #include "sway/config.h" |
14 | #include "sway/input/cursor.h" | 14 | #include "sway/input/cursor.h" |
15 | #include "sway/output.h" | 15 | #include "sway/output.h" |
16 | #include "sway/server.h" | ||
16 | #include "sway/tree/root.h" | 17 | #include "sway/tree/root.h" |
17 | #include "log.h" | 18 | #include "log.h" |
18 | #include "util.h" | 19 | #include "util.h" |
@@ -75,11 +76,78 @@ struct output_config *new_output_config(const char *name) { | |||
75 | oc->max_render_time = -1; | 76 | oc->max_render_time = -1; |
76 | oc->adaptive_sync = -1; | 77 | oc->adaptive_sync = -1; |
77 | oc->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT; | 78 | oc->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT; |
79 | oc->set_color_transform = false; | ||
80 | oc->color_transform = NULL; | ||
78 | oc->power = -1; | 81 | oc->power = -1; |
79 | return oc; | 82 | return oc; |
80 | } | 83 | } |
81 | 84 | ||
82 | void merge_output_config(struct output_config *dst, struct output_config *src) { | 85 | // supersede_output_config clears all fields in dst that were set in src |
86 | static void supersede_output_config(struct output_config *dst, struct output_config *src) { | ||
87 | if (src->enabled != -1) { | ||
88 | dst->enabled = -1; | ||
89 | } | ||
90 | if (src->width != -1) { | ||
91 | dst->width = -1; | ||
92 | } | ||
93 | if (src->height != -1) { | ||
94 | dst->height = -1; | ||
95 | } | ||
96 | if (src->x != -1) { | ||
97 | dst->x = -1; | ||
98 | } | ||
99 | if (src->y != -1) { | ||
100 | dst->y = -1; | ||
101 | } | ||
102 | if (src->scale != -1) { | ||
103 | dst->scale = -1; | ||
104 | } | ||
105 | if (src->scale_filter != SCALE_FILTER_DEFAULT) { | ||
106 | dst->scale_filter = SCALE_FILTER_DEFAULT; | ||
107 | } | ||
108 | if (src->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN) { | ||
109 | dst->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN; | ||
110 | } | ||
111 | if (src->refresh_rate != -1) { | ||
112 | dst->refresh_rate = -1; | ||
113 | } | ||
114 | if (src->custom_mode != -1) { | ||
115 | dst->custom_mode = -1; | ||
116 | } | ||
117 | if (src->drm_mode.type != (uint32_t) -1) { | ||
118 | dst->drm_mode.type = -1; | ||
119 | } | ||
120 | if (src->transform != -1) { | ||
121 | dst->transform = -1; | ||
122 | } | ||
123 | if (src->max_render_time != -1) { | ||
124 | dst->max_render_time = -1; | ||
125 | } | ||
126 | if (src->adaptive_sync != -1) { | ||
127 | dst->adaptive_sync = -1; | ||
128 | } | ||
129 | if (src->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) { | ||
130 | dst->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT; | ||
131 | } | ||
132 | if (src->background) { | ||
133 | free(dst->background); | ||
134 | dst->background = NULL; | ||
135 | } | ||
136 | if (src->background_option) { | ||
137 | free(dst->background_option); | ||
138 | dst->background_option = NULL; | ||
139 | } | ||
140 | if (src->background_fallback) { | ||
141 | free(dst->background_fallback); | ||
142 | dst->background_fallback = NULL; | ||
143 | } | ||
144 | if (src->power != -1) { | ||
145 | dst->power = -1; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | // merge_output_config sets all fields in dst that were set in src | ||
150 | static void merge_output_config(struct output_config *dst, struct output_config *src) { | ||
83 | if (src->enabled != -1) { | 151 | if (src->enabled != -1) { |
84 | dst->enabled = src->enabled; | 152 | dst->enabled = src->enabled; |
85 | } | 153 | } |
@@ -125,6 +193,14 @@ void merge_output_config(struct output_config *dst, struct output_config *src) { | |||
125 | if (src->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) { | 193 | if (src->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) { |
126 | dst->render_bit_depth = src->render_bit_depth; | 194 | dst->render_bit_depth = src->render_bit_depth; |
127 | } | 195 | } |
196 | if (src->set_color_transform) { | ||
197 | if (src->color_transform) { | ||
198 | wlr_color_transform_ref(src->color_transform); | ||
199 | } | ||
200 | wlr_color_transform_unref(dst->color_transform); | ||
201 | dst->set_color_transform = true; | ||
202 | dst->color_transform = src->color_transform; | ||
203 | } | ||
128 | if (src->background) { | 204 | if (src->background) { |
129 | free(dst->background); | 205 | free(dst->background); |
130 | dst->background = strdup(src->background); | 206 | dst->background = strdup(src->background); |
@@ -142,94 +218,42 @@ void merge_output_config(struct output_config *dst, struct output_config *src) { | |||
142 | } | 218 | } |
143 | } | 219 | } |
144 | 220 | ||
145 | static void merge_wildcard_on_all(struct output_config *wildcard) { | 221 | void store_output_config(struct output_config *oc) { |
146 | for (int i = 0; i < config->output_configs->length; i++) { | 222 | bool merged = false; |
147 | struct output_config *oc = config->output_configs->items[i]; | 223 | bool wildcard = strcmp(oc->name, "*") == 0; |
148 | if (strcmp(wildcard->name, oc->name) != 0) { | 224 | struct sway_output *output = wildcard ? NULL : all_output_by_name_or_id(oc->name); |
149 | sway_log(SWAY_DEBUG, "Merging output * config on %s", oc->name); | ||
150 | merge_output_config(oc, wildcard); | ||
151 | } | ||
152 | } | ||
153 | } | ||
154 | |||
155 | static void merge_id_on_name(struct output_config *oc) { | ||
156 | struct sway_output *output = all_output_by_name_or_id(oc->name); | ||
157 | if (output == NULL) { | ||
158 | return; | ||
159 | } | ||
160 | 225 | ||
161 | const char *name = output->wlr_output->name; | ||
162 | char id[128]; | 226 | char id[128]; |
163 | output_get_identifier(id, sizeof(id), output); | 227 | if (output) { |
164 | 228 | output_get_identifier(id, sizeof(id), output); | |
165 | char *id_on_name = format_str("%s on %s", id, name); | ||
166 | if (!id_on_name) { | ||
167 | return; | ||
168 | } | 229 | } |
169 | 230 | ||
170 | int i = list_seq_find(config->output_configs, output_name_cmp, id_on_name); | 231 | for (int i = 0; i < config->output_configs->length; i++) { |
171 | if (i >= 0) { | 232 | struct output_config *old = config->output_configs->items[i]; |
172 | sway_log(SWAY_DEBUG, "Merging on top of existing id on name config"); | 233 | |
173 | merge_output_config(config->output_configs->items[i], oc); | 234 | // If the old config matches the new config's name, regardless of |
174 | } else { | 235 | // whether it was name or identifier, merge on top of the existing |
175 | // If both a name and identifier config, exist generate an id on name | 236 | // config. If the new config is a wildcard, this also merges on top of |
176 | int ni = list_seq_find(config->output_configs, output_name_cmp, name); | 237 | // old wildcard configs. |
177 | int ii = list_seq_find(config->output_configs, output_name_cmp, id); | 238 | if (strcmp(old->name, oc->name) == 0) { |
178 | if ((ni >= 0 && ii >= 0) || (ni >= 0 && strcmp(oc->name, id) == 0) | 239 | merge_output_config(old, oc); |
179 | || (ii >= 0 && strcmp(oc->name, name) == 0)) { | 240 | merged = true; |
180 | struct output_config *ion_oc = new_output_config(id_on_name); | 241 | continue; |
181 | if (ni >= 0) { | ||
182 | merge_output_config(ion_oc, config->output_configs->items[ni]); | ||
183 | } | ||
184 | if (ii >= 0) { | ||
185 | merge_output_config(ion_oc, config->output_configs->items[ii]); | ||
186 | } | ||
187 | merge_output_config(ion_oc, oc); | ||
188 | list_add(config->output_configs, ion_oc); | ||
189 | sway_log(SWAY_DEBUG, "Generated id on name output config \"%s\"" | ||
190 | " (enabled: %d) (%dx%d@%fHz position %d,%d scale %f " | ||
191 | "transform %d) (bg %s %s) (power %d) (max render time: %d)", | ||
192 | ion_oc->name, ion_oc->enabled, ion_oc->width, ion_oc->height, | ||
193 | ion_oc->refresh_rate, ion_oc->x, ion_oc->y, ion_oc->scale, | ||
194 | ion_oc->transform, ion_oc->background, | ||
195 | ion_oc->background_option, ion_oc->power, | ||
196 | ion_oc->max_render_time); | ||
197 | } | 242 | } |
198 | } | ||
199 | free(id_on_name); | ||
200 | } | ||
201 | 243 | ||
202 | struct output_config *store_output_config(struct output_config *oc) { | 244 | // If the new config is a wildcard config we supersede all non-wildcard |
203 | bool wildcard = strcmp(oc->name, "*") == 0; | 245 | // configs. Old wildcard configs have already been handled above. |
204 | if (wildcard) { | 246 | if (wildcard) { |
205 | merge_wildcard_on_all(oc); | 247 | supersede_output_config(old, oc); |
206 | } else { | 248 | continue; |
207 | merge_id_on_name(oc); | 249 | } |
208 | } | ||
209 | 250 | ||
210 | int i = list_seq_find(config->output_configs, output_name_cmp, oc->name); | 251 | // If the new config matches an output's name, and the old config |
211 | if (i >= 0) { | 252 | // matches on that output's identifier, supersede it. |
212 | sway_log(SWAY_DEBUG, "Merging on top of existing output config"); | 253 | if (output && strcmp(old->name, id) == 0 && |
213 | struct output_config *current = config->output_configs->items[i]; | 254 | strcmp(oc->name, output->wlr_output->name) == 0) { |
214 | merge_output_config(current, oc); | 255 | supersede_output_config(old, oc); |
215 | free_output_config(oc); | ||
216 | oc = current; | ||
217 | } else if (!wildcard) { | ||
218 | sway_log(SWAY_DEBUG, "Adding non-wildcard output config"); | ||
219 | i = list_seq_find(config->output_configs, output_name_cmp, "*"); | ||
220 | if (i >= 0) { | ||
221 | sway_log(SWAY_DEBUG, "Merging on top of output * config"); | ||
222 | struct output_config *current = new_output_config(oc->name); | ||
223 | merge_output_config(current, config->output_configs->items[i]); | ||
224 | merge_output_config(current, oc); | ||
225 | free_output_config(oc); | ||
226 | oc = current; | ||
227 | } | 256 | } |
228 | list_add(config->output_configs, oc); | ||
229 | } else { | ||
230 | // New wildcard config. Just add it | ||
231 | sway_log(SWAY_DEBUG, "Adding output * config"); | ||
232 | list_add(config->output_configs, oc); | ||
233 | } | 257 | } |
234 | 258 | ||
235 | sway_log(SWAY_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz " | 259 | sway_log(SWAY_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz " |
@@ -240,7 +264,13 @@ struct output_config *store_output_config(struct output_config *oc) { | |||
240 | oc->transform, oc->background, oc->background_option, oc->power, | 264 | oc->transform, oc->background, oc->background_option, oc->power, |
241 | oc->max_render_time); | 265 | oc->max_render_time); |
242 | 266 | ||
243 | return oc; | 267 | // If the configuration was not merged into an existing configuration, add |
268 | // it to the list. Otherwise we're done with it and can free it. | ||
269 | if (!merged) { | ||
270 | list_add(config->output_configs, oc); | ||
271 | } else { | ||
272 | free_output_config(oc); | ||
273 | } | ||
244 | } | 274 | } |
245 | 275 | ||
246 | static void set_mode(struct wlr_output *output, struct wlr_output_state *pending, | 276 | static void set_mode(struct wlr_output *output, struct wlr_output_state *pending, |
@@ -367,22 +397,18 @@ static int compute_default_scale(struct wlr_output *output, | |||
367 | return 2; | 397 | return 2; |
368 | } | 398 | } |
369 | 399 | ||
370 | /* Lists of formats to try, in order, when a specific render bit depth has | 400 | static bool render_format_is_10bit(uint32_t render_format) { |
371 | * been asked for. The second to last format in each list should always | 401 | return render_format == DRM_FORMAT_XRGB2101010 || |
372 | * be XRGB8888, as a reliable backup in case the others are not available; | 402 | render_format == DRM_FORMAT_XBGR2101010; |
373 | * the last should be DRM_FORMAT_INVALID, to indicate the end of the list. */ | 403 | } |
374 | static const uint32_t *bit_depth_preferences[] = { | 404 | |
375 | [RENDER_BIT_DEPTH_8] = (const uint32_t []){ | 405 | static bool render_format_is_bgr(uint32_t fmt) { |
376 | DRM_FORMAT_XRGB8888, | 406 | return fmt == DRM_FORMAT_XBGR2101010 || fmt == DRM_FORMAT_XBGR8888; |
377 | DRM_FORMAT_INVALID, | 407 | } |
378 | }, | 408 | |
379 | [RENDER_BIT_DEPTH_10] = (const uint32_t []){ | 409 | static bool output_config_is_disabling(struct output_config *oc) { |
380 | DRM_FORMAT_XRGB2101010, | 410 | return oc && (!oc->enabled || oc->power == 0); |
381 | DRM_FORMAT_XBGR2101010, | 411 | } |
382 | DRM_FORMAT_XRGB8888, | ||
383 | DRM_FORMAT_INVALID, | ||
384 | }, | ||
385 | }; | ||
386 | 412 | ||
387 | static void queue_output_config(struct output_config *oc, | 413 | static void queue_output_config(struct output_config *oc, |
388 | struct sway_output *output, struct wlr_output_state *pending) { | 414 | struct sway_output *output, struct wlr_output_state *pending) { |
@@ -392,7 +418,7 @@ static void queue_output_config(struct output_config *oc, | |||
392 | 418 | ||
393 | struct wlr_output *wlr_output = output->wlr_output; | 419 | struct wlr_output *wlr_output = output->wlr_output; |
394 | 420 | ||
395 | if (oc && (!oc->enabled || oc->power == 0)) { | 421 | if (output_config_is_disabling(oc)) { |
396 | sway_log(SWAY_DEBUG, "Turning off output %s", wlr_output->name); | 422 | sway_log(SWAY_DEBUG, "Turning off output %s", wlr_output->name); |
397 | wlr_output_state_set_enabled(pending, false); | 423 | wlr_output_state_set_enabled(pending, false); |
398 | return; | 424 | return; |
@@ -415,22 +441,6 @@ static void queue_output_config(struct output_config *oc, | |||
415 | struct wlr_output_mode *preferred_mode = | 441 | struct wlr_output_mode *preferred_mode = |
416 | wlr_output_preferred_mode(wlr_output); | 442 | wlr_output_preferred_mode(wlr_output); |
417 | wlr_output_state_set_mode(pending, preferred_mode); | 443 | wlr_output_state_set_mode(pending, preferred_mode); |
418 | |||
419 | if (!wlr_output_test_state(wlr_output, pending)) { | ||
420 | sway_log(SWAY_DEBUG, "Preferred mode rejected, " | ||
421 | "falling back to another mode"); | ||
422 | struct wlr_output_mode *mode; | ||
423 | wl_list_for_each(mode, &wlr_output->modes, link) { | ||
424 | if (mode == preferred_mode) { | ||
425 | continue; | ||
426 | } | ||
427 | |||
428 | wlr_output_state_set_mode(pending, mode); | ||
429 | if (wlr_output_test_state(wlr_output, pending)) { | ||
430 | break; | ||
431 | } | ||
432 | } | ||
433 | } | ||
434 | } | 444 | } |
435 | 445 | ||
436 | if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) { | 446 | if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) { |
@@ -449,7 +459,7 @@ static void queue_output_config(struct output_config *oc, | |||
449 | #endif | 459 | #endif |
450 | } | 460 | } |
451 | if (wlr_output->transform != tr) { | 461 | if (wlr_output->transform != tr) { |
452 | sway_log(SWAY_DEBUG, "Set %s transform to %d", oc->name, tr); | 462 | sway_log(SWAY_DEBUG, "Set %s transform to %d", wlr_output->name, tr); |
453 | wlr_output_state_set_transform(pending, tr); | 463 | wlr_output_state_set_transform(pending, tr); |
454 | } | 464 | } |
455 | 465 | ||
@@ -481,54 +491,27 @@ static void queue_output_config(struct output_config *oc, | |||
481 | sway_log(SWAY_DEBUG, "Set %s adaptive sync to %d", wlr_output->name, | 491 | sway_log(SWAY_DEBUG, "Set %s adaptive sync to %d", wlr_output->name, |
482 | oc->adaptive_sync); | 492 | oc->adaptive_sync); |
483 | wlr_output_state_set_adaptive_sync_enabled(pending, oc->adaptive_sync == 1); | 493 | wlr_output_state_set_adaptive_sync_enabled(pending, oc->adaptive_sync == 1); |
484 | if (oc->adaptive_sync == 1 && !wlr_output_test_state(wlr_output, pending)) { | ||
485 | sway_log(SWAY_DEBUG, "Adaptive sync failed, ignoring"); | ||
486 | wlr_output_state_set_adaptive_sync_enabled(pending, false); | ||
487 | } | ||
488 | } | 494 | } |
489 | 495 | ||
490 | if (oc && oc->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) { | 496 | if (oc && oc->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) { |
491 | const uint32_t *fmts = bit_depth_preferences[oc->render_bit_depth]; | 497 | if (oc->render_bit_depth == RENDER_BIT_DEPTH_10 && |
492 | assert(fmts); | 498 | render_format_is_10bit(output->wlr_output->render_format)) { |
493 | 499 | // 10-bit was set successfully before, try to save some tests by reusing the format | |
494 | for (size_t i = 0; fmts[i] != DRM_FORMAT_INVALID; i++) { | 500 | wlr_output_state_set_render_format(pending, output->wlr_output->render_format); |
495 | wlr_output_state_set_render_format(pending, fmts[i]); | 501 | } else if (oc->render_bit_depth == RENDER_BIT_DEPTH_10) { |
496 | if (wlr_output_test_state(wlr_output, pending)) { | 502 | wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB2101010); |
497 | break; | 503 | } else { |
498 | } | 504 | wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB8888); |
499 | |||
500 | sway_log(SWAY_DEBUG, "Preferred output format 0x%08x " | ||
501 | "failed to work, falling back to next in " | ||
502 | "list, 0x%08x", fmts[i], fmts[i + 1]); | ||
503 | } | 505 | } |
504 | } | 506 | } |
505 | } | 507 | } |
506 | 508 | ||
507 | bool apply_output_config(struct output_config *oc, struct sway_output *output) { | 509 | static bool finalize_output_config(struct output_config *oc, struct sway_output *output) { |
508 | if (output == root->fallback_output) { | 510 | if (output == root->fallback_output) { |
509 | return false; | 511 | return false; |
510 | } | 512 | } |
511 | 513 | ||
512 | struct wlr_output *wlr_output = output->wlr_output; | 514 | struct wlr_output *wlr_output = output->wlr_output; |
513 | |||
514 | // Flag to prevent the output mode event handler from calling us | ||
515 | output->enabling = (!oc || oc->enabled); | ||
516 | |||
517 | struct wlr_output_state pending = {0}; | ||
518 | queue_output_config(oc, output, &pending); | ||
519 | |||
520 | sway_log(SWAY_DEBUG, "Committing output %s", wlr_output->name); | ||
521 | if (!wlr_output_commit_state(wlr_output, &pending)) { | ||
522 | // Failed to commit output changes, maybe the output is missing a CRTC. | ||
523 | // Leave the output disabled for now and try again when the output gets | ||
524 | // the mode we asked for. | ||
525 | sway_log(SWAY_ERROR, "Failed to commit output %s", wlr_output->name); | ||
526 | output->enabling = false; | ||
527 | return false; | ||
528 | } | ||
529 | |||
530 | output->enabling = false; | ||
531 | |||
532 | if (oc && !oc->enabled) { | 515 | if (oc && !oc->enabled) { |
533 | sway_log(SWAY_DEBUG, "Disabling output %s", oc->name); | 516 | sway_log(SWAY_DEBUG, "Disabling output %s", oc->name); |
534 | if (output->enabled) { | 517 | if (output->enabled) { |
@@ -584,23 +567,14 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) { | |||
584 | output->max_render_time = oc->max_render_time; | 567 | output->max_render_time = oc->max_render_time; |
585 | } | 568 | } |
586 | 569 | ||
587 | // Reconfigure all devices, since input config may have been applied before | 570 | if (oc && oc->set_color_transform) { |
588 | // this output came online, and some config items (like map_to_output) are | 571 | if (oc->color_transform) { |
589 | // dependent on an output being present. | 572 | wlr_color_transform_ref(oc->color_transform); |
590 | input_manager_configure_all_input_mappings(); | 573 | } |
591 | // Reconfigure the cursor images, since the scale may have changed. | 574 | wlr_color_transform_unref(output->color_transform); |
592 | input_manager_configure_xcursor(); | 575 | output->color_transform = oc->color_transform; |
593 | return true; | ||
594 | } | ||
595 | |||
596 | bool test_output_config(struct output_config *oc, struct sway_output *output) { | ||
597 | if (output == root->fallback_output) { | ||
598 | return false; | ||
599 | } | 576 | } |
600 | 577 | return true; | |
601 | struct wlr_output_state pending = {0}; | ||
602 | queue_output_config(oc, output, &pending); | ||
603 | return wlr_output_test_state(output->wlr_output, &pending); | ||
604 | } | 578 | } |
605 | 579 | ||
606 | static void default_output_config(struct output_config *oc, | 580 | static void default_output_config(struct output_config *oc, |
@@ -622,140 +596,416 @@ static void default_output_config(struct output_config *oc, | |||
622 | oc->max_render_time = 0; | 596 | oc->max_render_time = 0; |
623 | } | 597 | } |
624 | 598 | ||
625 | static struct output_config *get_output_config(char *identifier, | 599 | // find_output_config returns a merged output_config containing all stored |
626 | struct sway_output *sway_output) { | 600 | // configuration that applies to the specified output. |
601 | struct output_config *find_output_config(struct sway_output *sway_output) { | ||
627 | const char *name = sway_output->wlr_output->name; | 602 | const char *name = sway_output->wlr_output->name; |
603 | struct output_config *oc = NULL; | ||
604 | |||
605 | struct output_config *result = new_output_config(name); | ||
606 | if (config->reloading) { | ||
607 | default_output_config(result, sway_output->wlr_output); | ||
608 | } | ||
628 | 609 | ||
629 | struct output_config *oc_id_on_name = NULL; | 610 | char id[128]; |
630 | struct output_config *oc_name = NULL; | 611 | output_get_identifier(id, sizeof(id), sway_output); |
631 | struct output_config *oc_id = NULL; | ||
632 | 612 | ||
633 | char *id_on_name = format_str("%s on %s", identifier, name); | 613 | int i; |
634 | int i = list_seq_find(config->output_configs, output_name_cmp, id_on_name); | 614 | bool match = false; |
635 | if (i >= 0) { | 615 | if ((i = list_seq_find(config->output_configs, output_name_cmp, "*")) >= 0) { |
636 | oc_id_on_name = config->output_configs->items[i]; | 616 | match = true; |
637 | } else { | 617 | oc = config->output_configs->items[i]; |
638 | i = list_seq_find(config->output_configs, output_name_cmp, name); | 618 | merge_output_config(result, oc); |
639 | if (i >= 0) { | 619 | } |
640 | oc_name = config->output_configs->items[i]; | 620 | if ((i = list_seq_find(config->output_configs, output_name_cmp, name)) >= 0) { |
621 | match = true; | ||
622 | oc = config->output_configs->items[i]; | ||
623 | merge_output_config(result, oc); | ||
624 | } | ||
625 | if ((i = list_seq_find(config->output_configs, output_name_cmp, id)) >= 0) { | ||
626 | match = true; | ||
627 | oc = config->output_configs->items[i]; | ||
628 | merge_output_config(result, oc); | ||
629 | } | ||
630 | |||
631 | if (!match && !config->reloading) { | ||
632 | // No name, identifier, or wildcard config. Since we are not | ||
633 | // reloading with defaults, the output config will be empty, so | ||
634 | // just return NULL | ||
635 | free_output_config(result); | ||
636 | return NULL; | ||
637 | } | ||
638 | |||
639 | return result; | ||
640 | } | ||
641 | |||
642 | static bool config_has_auto_mode(struct output_config *oc) { | ||
643 | if (!oc) { | ||
644 | return true; | ||
645 | } | ||
646 | if (oc->drm_mode.type != 0 && oc->drm_mode.type != (uint32_t)-1) { | ||
647 | return true; | ||
648 | } else if (oc->width > 0 && oc->height > 0) { | ||
649 | return true; | ||
650 | } | ||
651 | return false; | ||
652 | } | ||
653 | |||
654 | struct search_context { | ||
655 | struct wlr_output_swapchain_manager *swapchain_mgr; | ||
656 | struct wlr_backend_output_state *states; | ||
657 | struct matched_output_config *configs; | ||
658 | size_t configs_len; | ||
659 | bool degrade_to_off; | ||
660 | }; | ||
661 | |||
662 | static void dump_output_state(struct wlr_output *wlr_output, struct wlr_output_state *state) { | ||
663 | sway_log(SWAY_DEBUG, "Output state for %s", wlr_output->name); | ||
664 | if (state->committed & WLR_OUTPUT_STATE_ENABLED) { | ||
665 | sway_log(SWAY_DEBUG, " enabled: %s", state->enabled ? "yes" : "no"); | ||
666 | } | ||
667 | if (state->committed & WLR_OUTPUT_STATE_RENDER_FORMAT) { | ||
668 | sway_log(SWAY_DEBUG, " render_format: %d", state->render_format); | ||
669 | } | ||
670 | if (state->committed & WLR_OUTPUT_STATE_MODE) { | ||
671 | if (state->mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM) { | ||
672 | sway_log(SWAY_DEBUG, " custom mode: %dx%d@%dmHz", | ||
673 | state->custom_mode.width, state->custom_mode.height, state->custom_mode.refresh); | ||
674 | } else { | ||
675 | sway_log(SWAY_DEBUG, " mode: %dx%d@%dmHz%s", | ||
676 | state->mode->width, state->mode->height, state->mode->refresh, | ||
677 | state->mode->preferred ? " (preferred)" : ""); | ||
641 | } | 678 | } |
679 | } | ||
680 | if (state->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) { | ||
681 | sway_log(SWAY_DEBUG, " adaptive_sync: %s", | ||
682 | state->adaptive_sync_enabled ? "enabled": "disabled"); | ||
683 | } | ||
684 | } | ||
685 | |||
686 | static bool search_valid_config(struct search_context *ctx, size_t output_idx); | ||
687 | |||
688 | static void reset_output_state(struct wlr_output_state *state) { | ||
689 | wlr_output_state_finish(state); | ||
690 | wlr_output_state_init(state); | ||
691 | state->committed = 0; | ||
692 | } | ||
693 | |||
694 | static void clear_later_output_states(struct wlr_backend_output_state *states, | ||
695 | size_t configs_len, size_t output_idx) { | ||
642 | 696 | ||
643 | i = list_seq_find(config->output_configs, output_name_cmp, identifier); | 697 | // Clear and disable all output states after this one to avoid conflict |
644 | if (i >= 0) { | 698 | // with previous tests. |
645 | oc_id = config->output_configs->items[i]; | 699 | for (size_t idx = output_idx+1; idx < configs_len; idx++) { |
700 | struct wlr_backend_output_state *backend_state = &states[idx]; | ||
701 | struct wlr_output_state *state = &backend_state->base; | ||
702 | |||
703 | reset_output_state(state); | ||
704 | wlr_output_state_set_enabled(state, false); | ||
705 | } | ||
706 | } | ||
707 | |||
708 | static bool search_finish(struct search_context *ctx, size_t output_idx) { | ||
709 | struct wlr_backend_output_state *backend_state = &ctx->states[output_idx]; | ||
710 | struct wlr_output_state *state = &backend_state->base; | ||
711 | struct wlr_output *wlr_output = backend_state->output; | ||
712 | |||
713 | clear_later_output_states(ctx->states, ctx->configs_len, output_idx); | ||
714 | dump_output_state(wlr_output, state); | ||
715 | return wlr_output_swapchain_manager_prepare(ctx->swapchain_mgr, ctx->states, ctx->configs_len) && | ||
716 | search_valid_config(ctx, output_idx+1); | ||
717 | } | ||
718 | |||
719 | static bool search_adaptive_sync(struct search_context *ctx, size_t output_idx) { | ||
720 | struct matched_output_config *cfg = &ctx->configs[output_idx]; | ||
721 | struct wlr_backend_output_state *backend_state = &ctx->states[output_idx]; | ||
722 | struct wlr_output_state *state = &backend_state->base; | ||
723 | |||
724 | if (cfg->config && cfg->config->adaptive_sync == 1) { | ||
725 | wlr_output_state_set_adaptive_sync_enabled(state, true); | ||
726 | if (search_finish(ctx, output_idx)) { | ||
727 | return true; | ||
646 | } | 728 | } |
647 | } | 729 | } |
730 | if (!cfg->config || cfg->config->adaptive_sync != -1) { | ||
731 | wlr_output_state_set_adaptive_sync_enabled(state, false); | ||
732 | if (search_finish(ctx, output_idx)) { | ||
733 | return true; | ||
734 | } | ||
735 | } | ||
736 | // If adaptive sync has not been set, or fallback in case we are on a | ||
737 | // backend that cannot disable adaptive sync such as the wayland backend. | ||
738 | state->committed &= ~WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED; | ||
739 | return search_finish(ctx, output_idx); | ||
740 | } | ||
648 | 741 | ||
649 | struct output_config *result = new_output_config("temp"); | 742 | static bool search_mode(struct search_context *ctx, size_t output_idx) { |
650 | if (config->reloading) { | 743 | struct matched_output_config *cfg = &ctx->configs[output_idx]; |
651 | default_output_config(result, sway_output->wlr_output); | 744 | struct wlr_backend_output_state *backend_state = &ctx->states[output_idx]; |
745 | struct wlr_output_state *state = &backend_state->base; | ||
746 | struct wlr_output *wlr_output = backend_state->output; | ||
747 | |||
748 | if (!config_has_auto_mode(cfg->config)) { | ||
749 | return search_adaptive_sync(ctx, output_idx); | ||
652 | } | 750 | } |
653 | if (oc_id_on_name) { | 751 | |
654 | // Already have an identifier on name config, use that | 752 | struct wlr_output_mode *preferred_mode = wlr_output_preferred_mode(wlr_output); |
655 | free(result->name); | 753 | if (preferred_mode) { |
656 | result->name = strdup(id_on_name); | 754 | wlr_output_state_set_mode(state, preferred_mode); |
657 | merge_output_config(result, oc_id_on_name); | 755 | if (search_adaptive_sync(ctx, output_idx)) { |
658 | } else if (oc_name && oc_id) { | 756 | return true; |
659 | // Generate a config named `<identifier> on <name>` which contains a | ||
660 | // merged copy of the identifier on name. This will make sure that both | ||
661 | // identifier and name configs are respected, with identifier getting | ||
662 | // priority | ||
663 | struct output_config *temp = new_output_config(id_on_name); | ||
664 | merge_output_config(temp, oc_name); | ||
665 | merge_output_config(temp, oc_id); | ||
666 | list_add(config->output_configs, temp); | ||
667 | |||
668 | free(result->name); | ||
669 | result->name = strdup(id_on_name); | ||
670 | merge_output_config(result, temp); | ||
671 | |||
672 | sway_log(SWAY_DEBUG, "Generated output config \"%s\" (enabled: %d)" | ||
673 | " (%dx%d@%fHz position %d,%d scale %f transform %d) (bg %s %s)" | ||
674 | " (power %d) (max render time: %d)", result->name, result->enabled, | ||
675 | result->width, result->height, result->refresh_rate, | ||
676 | result->x, result->y, result->scale, result->transform, | ||
677 | result->background, result->background_option, result->power, | ||
678 | result->max_render_time); | ||
679 | } else if (oc_name) { | ||
680 | // No identifier config, just return a copy of the name config | ||
681 | free(result->name); | ||
682 | result->name = strdup(name); | ||
683 | merge_output_config(result, oc_name); | ||
684 | } else if (oc_id) { | ||
685 | // No name config, just return a copy of the identifier config | ||
686 | free(result->name); | ||
687 | result->name = strdup(identifier); | ||
688 | merge_output_config(result, oc_id); | ||
689 | } else { | ||
690 | i = list_seq_find(config->output_configs, output_name_cmp, "*"); | ||
691 | if (i >= 0) { | ||
692 | // No name or identifier config, but there is a wildcard config | ||
693 | free(result->name); | ||
694 | result->name = strdup("*"); | ||
695 | merge_output_config(result, config->output_configs->items[i]); | ||
696 | } else if (!config->reloading) { | ||
697 | // No name, identifier, or wildcard config. Since we are not | ||
698 | // reloading with defaults, the output config will be empty, so | ||
699 | // just return NULL | ||
700 | free_output_config(result); | ||
701 | result = NULL; | ||
702 | } | 757 | } |
703 | } | 758 | } |
704 | 759 | ||
705 | free(id_on_name); | 760 | if (wl_list_empty(&wlr_output->modes)) { |
706 | return result; | 761 | state->committed &= ~WLR_OUTPUT_STATE_MODE; |
762 | return search_adaptive_sync(ctx, output_idx); | ||
763 | } | ||
764 | |||
765 | struct wlr_output_mode *mode; | ||
766 | wl_list_for_each(mode, &backend_state->output->modes, link) { | ||
767 | if (mode == preferred_mode) { | ||
768 | continue; | ||
769 | } | ||
770 | wlr_output_state_set_mode(state, mode); | ||
771 | if (search_adaptive_sync(ctx, output_idx)) { | ||
772 | return true; | ||
773 | } | ||
774 | } | ||
775 | |||
776 | return false; | ||
707 | } | 777 | } |
708 | 778 | ||
709 | struct output_config *find_output_config(struct sway_output *output) { | 779 | static bool search_render_format(struct search_context *ctx, size_t output_idx) { |
710 | char id[128]; | 780 | struct matched_output_config *cfg = &ctx->configs[output_idx]; |
711 | output_get_identifier(id, sizeof(id), output); | 781 | struct wlr_backend_output_state *backend_state = &ctx->states[output_idx]; |
712 | return get_output_config(id, output); | 782 | struct wlr_output_state *state = &backend_state->base; |
783 | struct wlr_output *wlr_output = backend_state->output; | ||
784 | |||
785 | uint32_t fmts[] = { | ||
786 | DRM_FORMAT_XRGB2101010, | ||
787 | DRM_FORMAT_XBGR2101010, | ||
788 | DRM_FORMAT_XRGB8888, | ||
789 | DRM_FORMAT_INVALID, | ||
790 | }; | ||
791 | if (render_format_is_bgr(wlr_output->render_format)) { | ||
792 | // Start with BGR in the unlikely event that we previously required it. | ||
793 | fmts[0] = DRM_FORMAT_XBGR2101010; | ||
794 | fmts[1] = DRM_FORMAT_XRGB2101010; | ||
795 | } | ||
796 | |||
797 | const struct wlr_drm_format_set *primary_formats = | ||
798 | wlr_output_get_primary_formats(wlr_output, WLR_BUFFER_CAP_DMABUF); | ||
799 | bool need_10bit = cfg->config && cfg->config->render_bit_depth == RENDER_BIT_DEPTH_10; | ||
800 | for (size_t idx = 0; fmts[idx] != DRM_FORMAT_INVALID; idx++) { | ||
801 | if (!need_10bit && render_format_is_10bit(fmts[idx])) { | ||
802 | continue; | ||
803 | } | ||
804 | if (!wlr_drm_format_set_get(primary_formats, fmts[idx])) { | ||
805 | // This is not a supported format for this output | ||
806 | continue; | ||
807 | } | ||
808 | wlr_output_state_set_render_format(state, fmts[idx]); | ||
809 | if (search_mode(ctx, output_idx)) { | ||
810 | return true; | ||
811 | } | ||
812 | } | ||
813 | return false; | ||
713 | } | 814 | } |
714 | 815 | ||
715 | void apply_output_config_to_outputs(struct output_config *oc) { | 816 | static bool search_valid_config(struct search_context *ctx, size_t output_idx) { |
716 | // Try to find the output container and apply configuration now. If | 817 | if (output_idx >= ctx->configs_len) { |
717 | // this is during startup then there will be no container and config | 818 | // We reached the end of the search, all good! |
718 | // will be applied during normal "new output" event from wlroots. | 819 | return true; |
719 | bool wildcard = strcmp(oc->name, "*") == 0; | 820 | } |
720 | struct sway_output *sway_output, *tmp; | ||
721 | wl_list_for_each_safe(sway_output, tmp, &root->all_outputs, link) { | ||
722 | if (output_match_name_or_id(sway_output, oc->name)) { | ||
723 | char id[128]; | ||
724 | output_get_identifier(id, sizeof(id), sway_output); | ||
725 | struct output_config *current = get_output_config(id, sway_output); | ||
726 | if (!current) { | ||
727 | // No stored output config matched, apply oc directly | ||
728 | sway_log(SWAY_DEBUG, "Applying oc directly"); | ||
729 | current = new_output_config(oc->name); | ||
730 | merge_output_config(current, oc); | ||
731 | } | ||
732 | apply_output_config(current, sway_output); | ||
733 | free_output_config(current); | ||
734 | 821 | ||
735 | if (!wildcard) { | 822 | struct matched_output_config *cfg = &ctx->configs[output_idx]; |
736 | // Stop looking if the output config isn't applicable to all | 823 | struct wlr_backend_output_state *backend_state = &ctx->states[output_idx]; |
737 | // outputs | 824 | struct wlr_output_state *state = &backend_state->base; |
738 | break; | 825 | struct wlr_output *wlr_output = backend_state->output; |
739 | } | 826 | |
827 | if (!output_config_is_disabling(cfg->config)) { | ||
828 | // Search through our possible configurations, doing a depth-first | ||
829 | // through render_format, modes, adaptive_sync and the next output's | ||
830 | // config. | ||
831 | queue_output_config(cfg->config, cfg->output, &backend_state->base); | ||
832 | if (search_render_format(ctx, output_idx)) { | ||
833 | return true; | ||
834 | } else if (!ctx->degrade_to_off) { | ||
835 | return false; | ||
740 | } | 836 | } |
837 | // We could not get anything to work, try to disable this output to see | ||
838 | // if we can at least make the outputs before us work. | ||
839 | sway_log(SWAY_DEBUG, "Unable to find valid config with output %s, disabling", | ||
840 | wlr_output->name); | ||
841 | reset_output_state(state); | ||
842 | } | ||
843 | |||
844 | wlr_output_state_set_enabled(state, false); | ||
845 | return search_finish(ctx, output_idx); | ||
846 | } | ||
847 | |||
848 | static int compare_matched_output_config_priority(const void *a, const void *b) { | ||
849 | |||
850 | const struct matched_output_config *amc = a; | ||
851 | const struct matched_output_config *bmc = b; | ||
852 | bool a_disabling = output_config_is_disabling(amc->config); | ||
853 | bool b_disabling = output_config_is_disabling(bmc->config); | ||
854 | bool a_enabled = amc->output->enabled; | ||
855 | bool b_enabled = bmc->output->enabled; | ||
856 | |||
857 | // We want to give priority to existing enabled outputs. To do so, we want | ||
858 | // the configuration order to be: | ||
859 | // 1. Existing, enabled outputs | ||
860 | // 2. Outputs that need to be enabled | ||
861 | // 3. Disabled or disabling outputs | ||
862 | if (a_enabled && !a_disabling) { | ||
863 | return -1; | ||
864 | } else if (b_enabled && !b_disabling) { | ||
865 | return 1; | ||
866 | } else if (b_disabling && !a_disabling) { | ||
867 | return -1; | ||
868 | } else if (a_disabling && !b_disabling) { | ||
869 | return 1; | ||
870 | } | ||
871 | return 0; | ||
872 | } | ||
873 | |||
874 | void sort_output_configs_by_priority(struct matched_output_config *configs, | ||
875 | size_t configs_len) { | ||
876 | qsort(configs, configs_len, sizeof(*configs), compare_matched_output_config_priority); | ||
877 | } | ||
878 | |||
879 | bool apply_output_configs(struct matched_output_config *configs, | ||
880 | size_t configs_len, bool test_only, bool degrade_to_off) { | ||
881 | struct wlr_backend_output_state *states = calloc(configs_len, sizeof(*states)); | ||
882 | if (!states) { | ||
883 | return false; | ||
884 | } | ||
885 | |||
886 | sway_log(SWAY_DEBUG, "Committing %zd outputs", configs_len); | ||
887 | for (size_t idx = 0; idx < configs_len; idx++) { | ||
888 | struct matched_output_config *cfg = &configs[idx]; | ||
889 | struct wlr_backend_output_state *backend_state = &states[idx]; | ||
890 | |||
891 | backend_state->output = cfg->output->wlr_output; | ||
892 | wlr_output_state_init(&backend_state->base); | ||
893 | |||
894 | sway_log(SWAY_DEBUG, "Preparing config for %s", | ||
895 | cfg->output->wlr_output->name); | ||
896 | queue_output_config(cfg->config, cfg->output, &backend_state->base); | ||
897 | } | ||
898 | |||
899 | struct wlr_output_swapchain_manager swapchain_mgr; | ||
900 | wlr_output_swapchain_manager_init(&swapchain_mgr, server.backend); | ||
901 | |||
902 | bool ok = wlr_output_swapchain_manager_prepare(&swapchain_mgr, states, configs_len); | ||
903 | if (!ok) { | ||
904 | sway_log(SWAY_ERROR, "Requested backend configuration failed, searching for valid fallbacks"); | ||
905 | struct search_context ctx = { | ||
906 | .swapchain_mgr = &swapchain_mgr, | ||
907 | .states = states, | ||
908 | .configs = configs, | ||
909 | .configs_len = configs_len, | ||
910 | .degrade_to_off = degrade_to_off, | ||
911 | }; | ||
912 | if (!search_valid_config(&ctx, 0)) { | ||
913 | sway_log(SWAY_ERROR, "Search for valid config failed"); | ||
914 | goto out; | ||
915 | } | ||
916 | } | ||
917 | |||
918 | if (test_only) { | ||
919 | // The swapchain manager already did a test for us | ||
920 | goto out; | ||
741 | } | 921 | } |
742 | 922 | ||
923 | for (size_t idx = 0; idx < configs_len; idx++) { | ||
924 | struct matched_output_config *cfg = &configs[idx]; | ||
925 | struct wlr_backend_output_state *backend_state = &states[idx]; | ||
926 | |||
927 | struct wlr_scene_output_state_options opts = { | ||
928 | .swapchain = wlr_output_swapchain_manager_get_swapchain( | ||
929 | &swapchain_mgr, backend_state->output), | ||
930 | .color_transform = cfg->output->color_transform, | ||
931 | }; | ||
932 | struct wlr_scene_output *scene_output = cfg->output->scene_output; | ||
933 | struct wlr_output_state *state = &backend_state->base; | ||
934 | if (!wlr_scene_output_build_state(scene_output, state, &opts)) { | ||
935 | sway_log(SWAY_ERROR, "Building output state for '%s' failed", | ||
936 | backend_state->output->name); | ||
937 | goto out; | ||
938 | } | ||
939 | } | ||
940 | |||
941 | ok = wlr_backend_commit(server.backend, states, configs_len); | ||
942 | if (!ok) { | ||
943 | sway_log(SWAY_ERROR, "Backend commit failed"); | ||
944 | goto out; | ||
945 | } | ||
946 | |||
947 | sway_log(SWAY_DEBUG, "Commit of %zd outputs succeeded", configs_len); | ||
948 | |||
949 | wlr_output_swapchain_manager_apply(&swapchain_mgr); | ||
950 | |||
951 | for (size_t idx = 0; idx < configs_len; idx++) { | ||
952 | struct matched_output_config *cfg = &configs[idx]; | ||
953 | sway_log(SWAY_DEBUG, "Finalizing config for %s", | ||
954 | cfg->output->wlr_output->name); | ||
955 | finalize_output_config(cfg->config, cfg->output); | ||
956 | } | ||
957 | |||
958 | out: | ||
959 | wlr_output_swapchain_manager_finish(&swapchain_mgr); | ||
960 | for (size_t idx = 0; idx < configs_len; idx++) { | ||
961 | struct wlr_backend_output_state *backend_state = &states[idx]; | ||
962 | wlr_output_state_finish(&backend_state->base); | ||
963 | } | ||
964 | free(states); | ||
965 | |||
966 | // Reconfigure all devices, since input config may have been applied before | ||
967 | // this output came online, and some config items (like map_to_output) are | ||
968 | // dependent on an output being present. | ||
969 | input_manager_configure_all_input_mappings(); | ||
970 | // Reconfigure the cursor images, since the scale may have changed. | ||
971 | input_manager_configure_xcursor(); | ||
972 | |||
743 | struct sway_seat *seat; | 973 | struct sway_seat *seat; |
744 | wl_list_for_each(seat, &server.input->seats, link) { | 974 | wl_list_for_each(seat, &server.input->seats, link) { |
745 | wlr_seat_pointer_notify_clear_focus(seat->wlr_seat); | 975 | wlr_seat_pointer_notify_clear_focus(seat->wlr_seat); |
746 | cursor_rebase(seat->cursor); | 976 | cursor_rebase(seat->cursor); |
747 | } | 977 | } |
978 | |||
979 | return ok; | ||
748 | } | 980 | } |
749 | 981 | ||
750 | void reset_outputs(void) { | 982 | void apply_all_output_configs(void) { |
751 | struct output_config *oc = NULL; | 983 | size_t configs_len = wl_list_length(&root->all_outputs); |
752 | int i = list_seq_find(config->output_configs, output_name_cmp, "*"); | 984 | struct matched_output_config *configs = calloc(configs_len, sizeof(*configs)); |
753 | if (i >= 0) { | 985 | if (!configs) { |
754 | oc = config->output_configs->items[i]; | 986 | return; |
755 | } else { | ||
756 | oc = store_output_config(new_output_config("*")); | ||
757 | } | 987 | } |
758 | apply_output_config_to_outputs(oc); | 988 | |
989 | int config_idx = 0; | ||
990 | struct sway_output *sway_output; | ||
991 | wl_list_for_each(sway_output, &root->all_outputs, link) { | ||
992 | if (sway_output == root->fallback_output) { | ||
993 | configs_len--; | ||
994 | continue; | ||
995 | } | ||
996 | |||
997 | struct matched_output_config *config = &configs[config_idx++]; | ||
998 | config->output = sway_output; | ||
999 | config->config = find_output_config(sway_output); | ||
1000 | } | ||
1001 | |||
1002 | sort_output_configs_by_priority(configs, configs_len); | ||
1003 | apply_output_configs(configs, configs_len, false, true); | ||
1004 | for (size_t idx = 0; idx < configs_len; idx++) { | ||
1005 | struct matched_output_config *cfg = &configs[idx]; | ||
1006 | free_output_config(cfg->config); | ||
1007 | } | ||
1008 | free(configs); | ||
759 | } | 1009 | } |
760 | 1010 | ||
761 | void free_output_config(struct output_config *oc) { | 1011 | void free_output_config(struct output_config *oc) { |
@@ -765,6 +1015,7 @@ void free_output_config(struct output_config *oc) { | |||
765 | free(oc->name); | 1015 | free(oc->name); |
766 | free(oc->background); | 1016 | free(oc->background); |
767 | free(oc->background_option); | 1017 | free(oc->background_option); |
1018 | wlr_color_transform_unref(oc->color_transform); | ||
768 | free(oc); | 1019 | free(oc); |
769 | } | 1020 | } |
770 | 1021 | ||
@@ -822,7 +1073,9 @@ static bool _spawn_swaybg(char **command) { | |||
822 | setenv("WAYLAND_SOCKET", wayland_socket_str, true); | 1073 | setenv("WAYLAND_SOCKET", wayland_socket_str, true); |
823 | 1074 | ||
824 | execvp(command[0], command); | 1075 | execvp(command[0], command); |
825 | sway_log_errno(SWAY_ERROR, "execvp failed"); | 1076 | sway_log_errno(SWAY_ERROR, "failed to execute '%s' " |
1077 | "(background configuration probably not applied)", | ||
1078 | command[0]); | ||
826 | _exit(EXIT_FAILURE); | 1079 | _exit(EXIT_FAILURE); |
827 | } | 1080 | } |
828 | _exit(EXIT_SUCCESS); | 1081 | _exit(EXIT_SUCCESS); |
@@ -832,12 +1085,13 @@ static bool _spawn_swaybg(char **command) { | |||
832 | sway_log_errno(SWAY_ERROR, "close failed"); | 1085 | sway_log_errno(SWAY_ERROR, "close failed"); |
833 | return false; | 1086 | return false; |
834 | } | 1087 | } |
835 | if (waitpid(pid, NULL, 0) < 0) { | 1088 | int fork_status = 0; |
1089 | if (waitpid(pid, &fork_status, 0) < 0) { | ||
836 | sway_log_errno(SWAY_ERROR, "waitpid failed"); | 1090 | sway_log_errno(SWAY_ERROR, "waitpid failed"); |
837 | return false; | 1091 | return false; |
838 | } | 1092 | } |
839 | 1093 | ||
840 | return true; | 1094 | return WIFEXITED(fork_status) && WEXITSTATUS(fork_status) == EXIT_SUCCESS; |
841 | } | 1095 | } |
842 | 1096 | ||
843 | bool spawn_swaybg(void) { | 1097 | bool spawn_swaybg(void) { |
diff --git a/sway/config/seat.c b/sway/config/seat.c index 6d5d91ae..f2326189 100644 --- a/sway/config/seat.c +++ b/sway/config/seat.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <limits.h> | 1 | #include <limits.h> |
3 | #include <stdlib.h> | 2 | #include <stdlib.h> |
4 | #include <string.h> | 3 | #include <string.h> |
diff --git a/sway/criteria.c b/sway/criteria.c index 78ea8b8a..2b7290c0 100644 --- a/sway/criteria.c +++ b/sway/criteria.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <stdlib.h> | 1 | #include <stdlib.h> |
3 | #include <stdio.h> | 2 | #include <stdio.h> |
4 | #include <stdbool.h> | 3 | #include <stdbool.h> |
@@ -8,6 +7,7 @@ | |||
8 | #include "sway/criteria.h" | 7 | #include "sway/criteria.h" |
9 | #include "sway/tree/container.h" | 8 | #include "sway/tree/container.h" |
10 | #include "sway/config.h" | 9 | #include "sway/config.h" |
10 | #include "sway/server.h" | ||
11 | #include "sway/tree/root.h" | 11 | #include "sway/tree/root.h" |
12 | #include "sway/tree/view.h" | 12 | #include "sway/tree/view.h" |
13 | #include "sway/tree/workspace.h" | 13 | #include "sway/tree/workspace.h" |
@@ -23,7 +23,7 @@ bool criteria_is_empty(struct criteria *criteria) { | |||
23 | && !criteria->app_id | 23 | && !criteria->app_id |
24 | && !criteria->con_mark | 24 | && !criteria->con_mark |
25 | && !criteria->con_id | 25 | && !criteria->con_id |
26 | #if HAVE_XWAYLAND | 26 | #if WLR_HAS_XWAYLAND |
27 | && !criteria->class | 27 | && !criteria->class |
28 | && !criteria->id | 28 | && !criteria->id |
29 | && !criteria->instance | 29 | && !criteria->instance |
@@ -91,7 +91,7 @@ void criteria_destroy(struct criteria *criteria) { | |||
91 | pattern_destroy(criteria->title); | 91 | pattern_destroy(criteria->title); |
92 | pattern_destroy(criteria->shell); | 92 | pattern_destroy(criteria->shell); |
93 | pattern_destroy(criteria->app_id); | 93 | pattern_destroy(criteria->app_id); |
94 | #if HAVE_XWAYLAND | 94 | #if WLR_HAS_XWAYLAND |
95 | pattern_destroy(criteria->class); | 95 | pattern_destroy(criteria->class); |
96 | pattern_destroy(criteria->instance); | 96 | pattern_destroy(criteria->instance); |
97 | pattern_destroy(criteria->window_role); | 97 | pattern_destroy(criteria->window_role); |
@@ -111,7 +111,7 @@ static int regex_cmp(const char *item, const pcre2_code *regex) { | |||
111 | return result; | 111 | return result; |
112 | } | 112 | } |
113 | 113 | ||
114 | #if HAVE_XWAYLAND | 114 | #if WLR_HAS_XWAYLAND |
115 | static bool view_has_window_type(struct sway_view *view, enum atom_name name) { | 115 | static bool view_has_window_type(struct sway_view *view, enum atom_name name) { |
116 | if (view->type != SWAY_VIEW_XWAYLAND) { | 116 | if (view->type != SWAY_VIEW_XWAYLAND) { |
117 | return false; | 117 | return false; |
@@ -252,7 +252,7 @@ static bool criteria_matches_view(struct criteria *criteria, | |||
252 | return false; | 252 | return false; |
253 | } | 253 | } |
254 | 254 | ||
255 | #if HAVE_XWAYLAND | 255 | #if WLR_HAS_XWAYLAND |
256 | if (criteria->id) { // X11 window ID | 256 | if (criteria->id) { // X11 window ID |
257 | uint32_t x11_window_id = view_get_x11_window_id(view); | 257 | uint32_t x11_window_id = view_get_x11_window_id(view); |
258 | if (!x11_window_id || x11_window_id != criteria->id) { | 258 | if (!x11_window_id || x11_window_id != criteria->id) { |
@@ -429,7 +429,7 @@ list_t *criteria_get_containers(struct criteria *criteria) { | |||
429 | return matches; | 429 | return matches; |
430 | } | 430 | } |
431 | 431 | ||
432 | #if HAVE_XWAYLAND | 432 | #if WLR_HAS_XWAYLAND |
433 | static enum atom_name parse_window_type(const char *type) { | 433 | static enum atom_name parse_window_type(const char *type) { |
434 | if (strcasecmp(type, "normal") == 0) { | 434 | if (strcasecmp(type, "normal") == 0) { |
435 | return NET_WM_WINDOW_TYPE_NORMAL; | 435 | return NET_WM_WINDOW_TYPE_NORMAL; |
@@ -462,7 +462,7 @@ enum criteria_token { | |||
462 | T_CON_ID, | 462 | T_CON_ID, |
463 | T_CON_MARK, | 463 | T_CON_MARK, |
464 | T_FLOATING, | 464 | T_FLOATING, |
465 | #if HAVE_XWAYLAND | 465 | #if WLR_HAS_XWAYLAND |
466 | T_CLASS, | 466 | T_CLASS, |
467 | T_ID, | 467 | T_ID, |
468 | T_INSTANCE, | 468 | T_INSTANCE, |
@@ -488,7 +488,7 @@ static enum criteria_token token_from_name(char *name) { | |||
488 | return T_CON_ID; | 488 | return T_CON_ID; |
489 | } else if (strcmp(name, "con_mark") == 0) { | 489 | } else if (strcmp(name, "con_mark") == 0) { |
490 | return T_CON_MARK; | 490 | return T_CON_MARK; |
491 | #if HAVE_XWAYLAND | 491 | #if WLR_HAS_XWAYLAND |
492 | } else if (strcmp(name, "class") == 0) { | 492 | } else if (strcmp(name, "class") == 0) { |
493 | return T_CLASS; | 493 | return T_CLASS; |
494 | } else if (strcmp(name, "id") == 0) { | 494 | } else if (strcmp(name, "id") == 0) { |
@@ -567,7 +567,7 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) { | |||
567 | case T_CON_MARK: | 567 | case T_CON_MARK: |
568 | pattern_create(&criteria->con_mark, value); | 568 | pattern_create(&criteria->con_mark, value); |
569 | break; | 569 | break; |
570 | #if HAVE_XWAYLAND | 570 | #if WLR_HAS_XWAYLAND |
571 | case T_CLASS: | 571 | case T_CLASS: |
572 | pattern_create(&criteria->class, value); | 572 | pattern_create(&criteria->class, value); |
573 | break; | 573 | break; |
@@ -675,7 +675,7 @@ struct criteria *criteria_parse(char *raw, char **error_arg) { | |||
675 | ++head; | 675 | ++head; |
676 | 676 | ||
677 | struct criteria *criteria = calloc(1, sizeof(struct criteria)); | 677 | struct criteria *criteria = calloc(1, sizeof(struct criteria)); |
678 | #if HAVE_XWAYLAND | 678 | #if WLR_HAS_XWAYLAND |
679 | criteria->window_type = ATOM_LAST; // default value | 679 | criteria->window_type = ATOM_LAST; // default value |
680 | #endif | 680 | #endif |
681 | char *name = NULL, *value = NULL; | 681 | char *name = NULL, *value = NULL; |
diff --git a/sway/desktop/launcher.c b/sway/desktop/launcher.c index 00a7e38a..2362e1ba 100644 --- a/sway/desktop/launcher.c +++ b/sway/desktop/launcher.c | |||
@@ -1,10 +1,10 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <stdlib.h> | 1 | #include <stdlib.h> |
3 | #include <string.h> | 2 | #include <string.h> |
4 | #include <wlr/types/wlr_xdg_activation_v1.h> | 3 | #include <wlr/types/wlr_xdg_activation_v1.h> |
5 | #include "sway/input/seat.h" | 4 | #include "sway/input/seat.h" |
6 | #include "sway/output.h" | 5 | #include "sway/output.h" |
7 | #include "sway/desktop/launcher.h" | 6 | #include "sway/desktop/launcher.h" |
7 | #include "sway/server.h" | ||
8 | #include "sway/tree/node.h" | 8 | #include "sway/tree/node.h" |
9 | #include "sway/tree/container.h" | 9 | #include "sway/tree/container.h" |
10 | #include "sway/tree/workspace.h" | 10 | #include "sway/tree/workspace.h" |
@@ -67,6 +67,9 @@ void launcher_ctx_destroy(struct launcher_ctx *ctx) { | |||
67 | } | 67 | } |
68 | wl_list_remove(&ctx->node_destroy.link); | 68 | wl_list_remove(&ctx->node_destroy.link); |
69 | wl_list_remove(&ctx->token_destroy.link); | 69 | wl_list_remove(&ctx->token_destroy.link); |
70 | if (ctx->seat) { | ||
71 | wl_list_remove(&ctx->seat_destroy.link); | ||
72 | } | ||
70 | wl_list_remove(&ctx->link); | 73 | wl_list_remove(&ctx->link); |
71 | wlr_xdg_activation_token_v1_destroy(ctx->token); | 74 | wlr_xdg_activation_token_v1_destroy(ctx->token); |
72 | free(ctx->fallback_name); | 75 | free(ctx->fallback_name); |
@@ -213,6 +216,8 @@ struct launcher_ctx *launcher_ctx_create(struct wlr_xdg_activation_token_v1 *tok | |||
213 | ctx->fallback_name = strdup(fallback_name); | 216 | ctx->fallback_name = strdup(fallback_name); |
214 | ctx->token = token; | 217 | ctx->token = token; |
215 | ctx->node = node; | 218 | ctx->node = node; |
219 | // Having surface set means that the focus check in wlroots has passed | ||
220 | ctx->had_focused_surface = token->surface != NULL; | ||
216 | 221 | ||
217 | ctx->node_destroy.notify = ctx_handle_node_destroy; | 222 | ctx->node_destroy.notify = ctx_handle_node_destroy; |
218 | wl_signal_add(&ctx->node->events.destroy, &ctx->node_destroy); | 223 | wl_signal_add(&ctx->node->events.destroy, &ctx->node_destroy); |
@@ -227,6 +232,12 @@ struct launcher_ctx *launcher_ctx_create(struct wlr_xdg_activation_token_v1 *tok | |||
227 | return ctx; | 232 | return ctx; |
228 | } | 233 | } |
229 | 234 | ||
235 | static void launch_ctx_handle_seat_destroy(struct wl_listener *listener, void *data) { | ||
236 | struct launcher_ctx *ctx = wl_container_of(listener, ctx, seat_destroy); | ||
237 | ctx->seat = NULL; | ||
238 | wl_list_remove(&ctx->seat_destroy.link); | ||
239 | } | ||
240 | |||
230 | // Creates a context with a new token for the internal launcher | 241 | // Creates a context with a new token for the internal launcher |
231 | struct launcher_ctx *launcher_ctx_create_internal(void) { | 242 | struct launcher_ctx *launcher_ctx_create_internal(void) { |
232 | struct sway_seat *seat = input_manager_current_seat(); | 243 | struct sway_seat *seat = input_manager_current_seat(); |
@@ -238,13 +249,15 @@ struct launcher_ctx *launcher_ctx_create_internal(void) { | |||
238 | 249 | ||
239 | struct wlr_xdg_activation_token_v1 *token = | 250 | struct wlr_xdg_activation_token_v1 *token = |
240 | wlr_xdg_activation_token_v1_create(server.xdg_activation_v1); | 251 | wlr_xdg_activation_token_v1_create(server.xdg_activation_v1); |
241 | token->seat = seat->wlr_seat; | ||
242 | 252 | ||
243 | struct launcher_ctx *ctx = launcher_ctx_create(token, &ws->node); | 253 | struct launcher_ctx *ctx = launcher_ctx_create(token, &ws->node); |
244 | if (!ctx) { | 254 | if (!ctx) { |
245 | wlr_xdg_activation_token_v1_destroy(token); | 255 | wlr_xdg_activation_token_v1_destroy(token); |
246 | return NULL; | 256 | return NULL; |
247 | } | 257 | } |
258 | ctx->seat = seat; | ||
259 | ctx->seat_destroy.notify = launch_ctx_handle_seat_destroy; | ||
260 | wl_signal_add(&seat->wlr_seat->events.destroy, &ctx->seat_destroy); | ||
248 | 261 | ||
249 | return ctx; | 262 | return ctx; |
250 | } | 263 | } |
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index c71abce7..6221b7b9 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c | |||
@@ -2,9 +2,12 @@ | |||
2 | #include <stdlib.h> | 2 | #include <stdlib.h> |
3 | #include <string.h> | 3 | #include <string.h> |
4 | #include <wayland-server-core.h> | 4 | #include <wayland-server-core.h> |
5 | #include <wlr/types/wlr_fractional_scale_v1.h> | ||
5 | #include <wlr/types/wlr_layer_shell_v1.h> | 6 | #include <wlr/types/wlr_layer_shell_v1.h> |
6 | #include <wlr/types/wlr_output.h> | 7 | #include <wlr/types/wlr_output.h> |
8 | #include <wlr/types/wlr_scene.h> | ||
7 | #include <wlr/types/wlr_subcompositor.h> | 9 | #include <wlr/types/wlr_subcompositor.h> |
10 | #include <wlr/types/wlr_xdg_shell.h> | ||
8 | #include "log.h" | 11 | #include "log.h" |
9 | #include "sway/scene_descriptor.h" | 12 | #include "sway/scene_descriptor.h" |
10 | #include "sway/desktop/transaction.h" | 13 | #include "sway/desktop/transaction.h" |
@@ -16,7 +19,6 @@ | |||
16 | #include "sway/server.h" | 19 | #include "sway/server.h" |
17 | #include "sway/tree/arrange.h" | 20 | #include "sway/tree/arrange.h" |
18 | #include "sway/tree/workspace.h" | 21 | #include "sway/tree/workspace.h" |
19 | #include <wlr/types/wlr_scene.h> | ||
20 | 22 | ||
21 | struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface( | 23 | struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface( |
22 | struct wlr_surface *surface) { | 24 | struct wlr_surface *surface) { |
@@ -85,6 +87,8 @@ void arrange_layers(struct sway_output *output) { | |||
85 | sway_log(SWAY_DEBUG, "Usable area changed, rearranging output"); | 87 | sway_log(SWAY_DEBUG, "Usable area changed, rearranging output"); |
86 | output->usable_area = usable_area; | 88 | output->usable_area = usable_area; |
87 | arrange_output(output); | 89 | arrange_output(output); |
90 | } else { | ||
91 | arrange_popups(root->layers.popup); | ||
88 | } | 92 | } |
89 | } | 93 | } |
90 | 94 | ||
@@ -120,10 +124,21 @@ static struct sway_layer_surface *sway_layer_surface_create( | |||
120 | return NULL; | 124 | return NULL; |
121 | } | 125 | } |
122 | 126 | ||
127 | surface->desc.relative = &scene->tree->node; | ||
128 | |||
129 | if (!scene_descriptor_assign(&popups->node, | ||
130 | SWAY_SCENE_DESC_POPUP, &surface->desc)) { | ||
131 | sway_log(SWAY_ERROR, "Failed to allocate a popup scene descriptor"); | ||
132 | wlr_scene_node_destroy(&popups->node); | ||
133 | free(surface); | ||
134 | return NULL; | ||
135 | } | ||
136 | |||
123 | surface->tree = scene->tree; | 137 | surface->tree = scene->tree; |
124 | surface->scene = scene; | 138 | surface->scene = scene; |
125 | surface->layer_surface = scene->layer_surface; | 139 | surface->layer_surface = scene->layer_surface; |
126 | surface->popups = popups; | 140 | surface->popups = popups; |
141 | surface->layer_surface->data = surface; | ||
127 | 142 | ||
128 | return surface; | 143 | return surface; |
129 | } | 144 | } |
@@ -197,6 +212,8 @@ static void handle_node_destroy(struct wl_listener *listener, void *data) { | |||
197 | wl_list_remove(&layer->node_destroy.link); | 212 | wl_list_remove(&layer->node_destroy.link); |
198 | wl_list_remove(&layer->output_destroy.link); | 213 | wl_list_remove(&layer->output_destroy.link); |
199 | 214 | ||
215 | layer->layer_surface->data = NULL; | ||
216 | |||
200 | free(layer); | 217 | free(layer); |
201 | } | 218 | } |
202 | 219 | ||
@@ -222,10 +239,6 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) { | |||
222 | arrange_layers(surface->output); | 239 | arrange_layers(surface->output); |
223 | transaction_commit_dirty(); | 240 | transaction_commit_dirty(); |
224 | } | 241 | } |
225 | |||
226 | int lx, ly; | ||
227 | wlr_scene_node_coords(&surface->scene->tree->node, &lx, &ly); | ||
228 | wlr_scene_node_set_position(&surface->popups->node, lx, ly); | ||
229 | } | 242 | } |
230 | 243 | ||
231 | static void handle_map(struct wl_listener *listener, void *data) { | 244 | static void handle_map(struct wl_listener *listener, void *data) { |
@@ -420,6 +433,12 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { | |||
420 | 433 | ||
421 | surface->output = output; | 434 | surface->output = output; |
422 | 435 | ||
436 | // now that the surface's output is known, we can advertise its scale | ||
437 | wlr_fractional_scale_v1_notify_scale(surface->layer_surface->surface, | ||
438 | layer_surface->output->scale); | ||
439 | wlr_surface_set_preferred_buffer_scale(surface->layer_surface->surface, | ||
440 | ceil(layer_surface->output->scale)); | ||
441 | |||
423 | surface->surface_commit.notify = handle_surface_commit; | 442 | surface->surface_commit.notify = handle_surface_commit; |
424 | wl_signal_add(&layer_surface->surface->events.commit, | 443 | wl_signal_add(&layer_surface->surface->events.commit, |
425 | &surface->surface_commit); | 444 | &surface->surface_commit); |
diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 9c4baafd..6bf77d17 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <assert.h> | 1 | #include <assert.h> |
3 | #include <stdlib.h> | 2 | #include <stdlib.h> |
4 | #include <strings.h> | 3 | #include <strings.h> |
@@ -12,6 +11,8 @@ | |||
12 | #include <wlr/types/wlr_gamma_control_v1.h> | 11 | #include <wlr/types/wlr_gamma_control_v1.h> |
13 | #include <wlr/types/wlr_matrix.h> | 12 | #include <wlr/types/wlr_matrix.h> |
14 | #include <wlr/types/wlr_output_layout.h> | 13 | #include <wlr/types/wlr_output_layout.h> |
14 | #include <wlr/types/wlr_output_management_v1.h> | ||
15 | #include <wlr/types/wlr_output_power_management_v1.h> | ||
15 | #include <wlr/types/wlr_output.h> | 16 | #include <wlr/types/wlr_output.h> |
16 | #include <wlr/types/wlr_presentation_time.h> | 17 | #include <wlr/types/wlr_presentation_time.h> |
17 | #include <wlr/types/wlr_compositor.h> | 18 | #include <wlr/types/wlr_compositor.h> |
@@ -182,7 +183,15 @@ static void send_frame_done_iterator(struct wlr_scene_buffer *buffer, | |||
182 | } | 183 | } |
183 | } | 184 | } |
184 | 185 | ||
185 | static enum wlr_scale_filter_mode get_scale_filter(struct sway_output *output) { | 186 | static enum wlr_scale_filter_mode get_scale_filter(struct sway_output *output, |
187 | struct wlr_scene_buffer *buffer) { | ||
188 | // if we are scaling down, we should always choose linear | ||
189 | if (buffer->dst_width > 0 && buffer->dst_height > 0 && ( | ||
190 | buffer->dst_width < buffer->buffer_width || | ||
191 | buffer->dst_height < buffer->buffer_height)) { | ||
192 | return WLR_SCALE_FILTER_BILINEAR; | ||
193 | } | ||
194 | |||
186 | switch (output->scale_filter) { | 195 | switch (output->scale_filter) { |
187 | case SCALE_FILTER_LINEAR: | 196 | case SCALE_FILTER_LINEAR: |
188 | return WLR_SCALE_FILTER_BILINEAR; | 197 | return WLR_SCALE_FILTER_BILINEAR; |
@@ -211,7 +220,7 @@ static void output_configure_scene(struct sway_output *output, | |||
211 | // hack: don't call the scene setter because that will damage all outputs | 220 | // hack: don't call the scene setter because that will damage all outputs |
212 | // We don't want to damage outputs that aren't our current output that | 221 | // We don't want to damage outputs that aren't our current output that |
213 | // we're configuring | 222 | // we're configuring |
214 | buffer->filter_mode = get_scale_filter(output); | 223 | buffer->filter_mode = get_scale_filter(output, buffer); |
215 | 224 | ||
216 | wlr_scene_buffer_set_opacity(buffer, opacity); | 225 | wlr_scene_buffer_set_opacity(buffer, opacity); |
217 | } else if (node->type == WLR_SCENE_NODE_TREE) { | 226 | } else if (node->type == WLR_SCENE_NODE_TREE) { |
@@ -234,10 +243,14 @@ static int output_repaint_timer_handler(void *data) { | |||
234 | 243 | ||
235 | output_configure_scene(output, &root->root_scene->tree.node, 1.0f); | 244 | output_configure_scene(output, &root->root_scene->tree.node, 1.0f); |
236 | 245 | ||
246 | struct wlr_scene_output_state_options opts = { | ||
247 | .color_transform = output->color_transform, | ||
248 | }; | ||
249 | |||
237 | if (output->gamma_lut_changed) { | 250 | if (output->gamma_lut_changed) { |
238 | struct wlr_output_state pending; | 251 | struct wlr_output_state pending; |
239 | wlr_output_state_init(&pending); | 252 | wlr_output_state_init(&pending); |
240 | if (!wlr_scene_output_build_state(output->scene_output, &pending, NULL)) { | 253 | if (!wlr_scene_output_build_state(output->scene_output, &pending, &opts)) { |
241 | return 0; | 254 | return 0; |
242 | } | 255 | } |
243 | 256 | ||
@@ -260,7 +273,7 @@ static int output_repaint_timer_handler(void *data) { | |||
260 | return 0; | 273 | return 0; |
261 | } | 274 | } |
262 | 275 | ||
263 | wlr_scene_output_commit(output->scene_output, NULL); | 276 | wlr_scene_output_commit(output->scene_output, &opts); |
264 | return 0; | 277 | return 0; |
265 | } | 278 | } |
266 | 279 | ||
@@ -512,9 +525,7 @@ void handle_new_output(struct wl_listener *listener, void *data) { | |||
512 | sway_session_lock_add_output(server->session_lock.lock, output); | 525 | sway_session_lock_add_output(server->session_lock.lock, output); |
513 | } | 526 | } |
514 | 527 | ||
515 | struct output_config *oc = find_output_config(output); | 528 | apply_all_output_configs(); |
516 | apply_output_config(oc, output); | ||
517 | free_output_config(oc); | ||
518 | 529 | ||
519 | transaction_commit_dirty(); | 530 | transaction_commit_dirty(); |
520 | 531 | ||
@@ -543,63 +554,89 @@ void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data) { | |||
543 | wlr_output_schedule_frame(output->wlr_output); | 554 | wlr_output_schedule_frame(output->wlr_output); |
544 | } | 555 | } |
545 | 556 | ||
557 | static struct output_config *output_config_for_config_head( | ||
558 | struct wlr_output_configuration_head_v1 *config_head, | ||
559 | struct sway_output *output) { | ||
560 | struct output_config *oc = new_output_config(output->wlr_output->name); | ||
561 | oc->enabled = config_head->state.enabled; | ||
562 | if (!oc->enabled) { | ||
563 | return oc; | ||
564 | } | ||
565 | |||
566 | if (config_head->state.mode != NULL) { | ||
567 | struct wlr_output_mode *mode = config_head->state.mode; | ||
568 | oc->width = mode->width; | ||
569 | oc->height = mode->height; | ||
570 | oc->refresh_rate = mode->refresh / 1000.f; | ||
571 | } else { | ||
572 | oc->width = config_head->state.custom_mode.width; | ||
573 | oc->height = config_head->state.custom_mode.height; | ||
574 | oc->refresh_rate = | ||
575 | config_head->state.custom_mode.refresh / 1000.f; | ||
576 | } | ||
577 | oc->x = config_head->state.x; | ||
578 | oc->y = config_head->state.y; | ||
579 | oc->transform = config_head->state.transform; | ||
580 | oc->scale = config_head->state.scale; | ||
581 | oc->adaptive_sync = config_head->state.adaptive_sync_enabled; | ||
582 | return oc; | ||
583 | } | ||
584 | |||
546 | static void output_manager_apply(struct sway_server *server, | 585 | static void output_manager_apply(struct sway_server *server, |
547 | struct wlr_output_configuration_v1 *config, bool test_only) { | 586 | struct wlr_output_configuration_v1 *config, bool test_only) { |
548 | // TODO: perform atomic tests on the whole backend atomically | 587 | size_t configs_len = wl_list_length(&root->all_outputs); |
549 | 588 | struct matched_output_config *configs = calloc(configs_len, sizeof(*configs)); | |
550 | struct wlr_output_configuration_head_v1 *config_head; | 589 | if (!configs) { |
551 | // First disable outputs we need to disable | 590 | return; |
552 | bool ok = true; | 591 | } |
553 | wl_list_for_each(config_head, &config->heads, link) { | 592 | |
554 | struct wlr_output *wlr_output = config_head->state.output; | 593 | int config_idx = 0; |
555 | struct sway_output *output = wlr_output->data; | 594 | struct sway_output *sway_output; |
556 | if (!output->enabled || config_head->state.enabled) { | 595 | wl_list_for_each(sway_output, &root->all_outputs, link) { |
596 | if (sway_output == root->fallback_output) { | ||
597 | configs_len--; | ||
557 | continue; | 598 | continue; |
558 | } | 599 | } |
559 | struct output_config *oc = new_output_config(output->wlr_output->name); | ||
560 | oc->enabled = false; | ||
561 | 600 | ||
562 | if (test_only) { | 601 | struct matched_output_config *cfg = &configs[config_idx++]; |
563 | ok &= test_output_config(oc, output); | 602 | cfg->output = sway_output; |
564 | } else { | 603 | |
565 | oc = store_output_config(oc); | 604 | struct wlr_output_configuration_head_v1 *config_head; |
566 | ok &= apply_output_config(oc, output); | 605 | wl_list_for_each(config_head, &config->heads, link) { |
606 | if (config_head->state.output == sway_output->wlr_output) { | ||
607 | cfg->config = output_config_for_config_head(config_head, sway_output); | ||
608 | break; | ||
609 | } | ||
610 | } | ||
611 | if (!cfg->config) { | ||
612 | cfg->config = find_output_config(sway_output); | ||
567 | } | 613 | } |
568 | } | 614 | } |
569 | 615 | ||
570 | // Then enable outputs that need to | 616 | sort_output_configs_by_priority(configs, configs_len); |
571 | wl_list_for_each(config_head, &config->heads, link) { | 617 | bool ok = apply_output_configs(configs, configs_len, test_only, false); |
572 | struct wlr_output *wlr_output = config_head->state.output; | 618 | for (size_t idx = 0; idx < configs_len; idx++) { |
573 | struct sway_output *output = wlr_output->data; | 619 | struct matched_output_config *cfg = &configs[idx]; |
574 | if (!config_head->state.enabled) { | 620 | |
575 | continue; | 621 | // Only store new configs for successful non-test commits. Old configs, |
576 | } | 622 | // test-only and failed commits just get freed. |
577 | struct output_config *oc = new_output_config(output->wlr_output->name); | 623 | bool store_config = false; |
578 | oc->enabled = true; | 624 | if (!test_only && ok) { |
579 | if (config_head->state.mode != NULL) { | 625 | struct wlr_output_configuration_head_v1 *config_head; |
580 | struct wlr_output_mode *mode = config_head->state.mode; | 626 | wl_list_for_each(config_head, &config->heads, link) { |
581 | oc->width = mode->width; | 627 | if (config_head->state.output == cfg->output->wlr_output) { |
582 | oc->height = mode->height; | 628 | store_config = true; |
583 | oc->refresh_rate = mode->refresh / 1000.f; | 629 | break; |
584 | } else { | 630 | } |
585 | oc->width = config_head->state.custom_mode.width; | 631 | } |
586 | oc->height = config_head->state.custom_mode.height; | ||
587 | oc->refresh_rate = | ||
588 | config_head->state.custom_mode.refresh / 1000.f; | ||
589 | } | 632 | } |
590 | oc->x = config_head->state.x; | 633 | if (store_config) { |
591 | oc->y = config_head->state.y; | 634 | store_output_config(cfg->config); |
592 | oc->transform = config_head->state.transform; | ||
593 | oc->scale = config_head->state.scale; | ||
594 | oc->adaptive_sync = config_head->state.adaptive_sync_enabled; | ||
595 | |||
596 | if (test_only) { | ||
597 | ok &= test_output_config(oc, output); | ||
598 | } else { | 635 | } else { |
599 | oc = store_output_config(oc); | 636 | free_output_config(cfg->config); |
600 | ok &= apply_output_config(oc, output); | ||
601 | } | 637 | } |
602 | } | 638 | } |
639 | free(configs); | ||
603 | 640 | ||
604 | if (ok) { | 641 | if (ok) { |
605 | wlr_output_configuration_v1_send_succeeded(config); | 642 | wlr_output_configuration_v1_send_succeeded(config); |
@@ -643,6 +680,6 @@ void handle_output_power_manager_set_mode(struct wl_listener *listener, | |||
643 | oc->power = 1; | 680 | oc->power = 1; |
644 | break; | 681 | break; |
645 | } | 682 | } |
646 | oc = store_output_config(oc); | 683 | store_output_config(oc); |
647 | apply_output_config(oc, output); | 684 | apply_all_output_configs(); |
648 | } | 685 | } |
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index acc3e3f9..d1898843 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <stdbool.h> | 1 | #include <stdbool.h> |
3 | #include <stdlib.h> | 2 | #include <stdlib.h> |
4 | #include <string.h> | 3 | #include <string.h> |
@@ -11,6 +10,7 @@ | |||
11 | #include "sway/input/cursor.h" | 10 | #include "sway/input/cursor.h" |
12 | #include "sway/input/input-manager.h" | 11 | #include "sway/input/input-manager.h" |
13 | #include "sway/output.h" | 12 | #include "sway/output.h" |
13 | #include "sway/server.h" | ||
14 | #include "sway/tree/container.h" | 14 | #include "sway/tree/container.h" |
15 | #include "sway/tree/node.h" | 15 | #include "sway/tree/node.h" |
16 | #include "sway/tree/view.h" | 16 | #include "sway/tree/view.h" |
@@ -606,21 +606,15 @@ static void arrange_output(struct sway_output *output, int width, int height) { | |||
606 | } | 606 | } |
607 | } | 607 | } |
608 | 608 | ||
609 | static void arrange_popup(struct wlr_scene_tree *popup) { | 609 | void arrange_popups(struct wlr_scene_tree *popups) { |
610 | struct wlr_scene_node *node; | 610 | struct wlr_scene_node *node; |
611 | wl_list_for_each(node, &popup->children, link) { | 611 | wl_list_for_each(node, &popups->children, link) { |
612 | struct sway_xdg_popup *popup = scene_descriptor_try_get(node, | 612 | struct sway_popup_desc *popup = scene_descriptor_try_get(node, |
613 | SWAY_SCENE_DESC_POPUP); | 613 | SWAY_SCENE_DESC_POPUP); |
614 | 614 | ||
615 | // the popup layer may have popups from layer_shell surfaces, in this | 615 | int lx, ly; |
616 | // case those don't have a scene descriptor, so lets skip those here. | 616 | wlr_scene_node_coords(popup->relative, &lx, &ly); |
617 | if (popup) { | 617 | wlr_scene_node_set_position(node, lx, ly); |
618 | struct wlr_scene_tree *tree = popup->view->content_tree; | ||
619 | |||
620 | int lx, ly; | ||
621 | wlr_scene_node_coords(&tree->node, &lx, &ly); | ||
622 | wlr_scene_node_set_position(&popup->scene_tree->node, lx, ly); | ||
623 | } | ||
624 | } | 618 | } |
625 | } | 619 | } |
626 | 620 | ||
@@ -679,7 +673,7 @@ static void arrange_root(struct sway_root *root) { | |||
679 | } | 673 | } |
680 | } | 674 | } |
681 | 675 | ||
682 | arrange_popup(root->layers.popup); | 676 | arrange_popups(root->layers.popup); |
683 | } | 677 | } |
684 | 678 | ||
685 | /** | 679 | /** |
@@ -768,7 +762,7 @@ static bool should_configure(struct sway_node *node, | |||
768 | } | 762 | } |
769 | struct sway_container_state *cstate = &node->sway_container->current; | 763 | struct sway_container_state *cstate = &node->sway_container->current; |
770 | struct sway_container_state *istate = &instruction->container_state; | 764 | struct sway_container_state *istate = &instruction->container_state; |
771 | #if HAVE_XWAYLAND | 765 | #if WLR_HAS_XWAYLAND |
772 | // Xwayland views are position-aware and need to be reconfigured | 766 | // Xwayland views are position-aware and need to be reconfigured |
773 | // when their position changes. | 767 | // when their position changes. |
774 | if (node->sway_container->view->type == SWAY_VIEW_XWAYLAND) { | 768 | if (node->sway_container->view->type == SWAY_VIEW_XWAYLAND) { |
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 7cdd97c8..7c417891 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 199309L | ||
2 | #include <float.h> | 1 | #include <float.h> |
3 | #include <stdbool.h> | 2 | #include <stdbool.h> |
4 | #include <stdlib.h> | 3 | #include <stdlib.h> |
@@ -36,6 +35,7 @@ static void popup_handle_destroy(struct wl_listener *listener, void *data) { | |||
36 | wl_list_remove(&popup->new_popup.link); | 35 | wl_list_remove(&popup->new_popup.link); |
37 | wl_list_remove(&popup->destroy.link); | 36 | wl_list_remove(&popup->destroy.link); |
38 | wl_list_remove(&popup->surface_commit.link); | 37 | wl_list_remove(&popup->surface_commit.link); |
38 | wl_list_remove(&popup->reposition.link); | ||
39 | wlr_scene_node_destroy(&popup->scene_tree->node); | 39 | wlr_scene_node_destroy(&popup->scene_tree->node); |
40 | free(popup); | 40 | free(popup); |
41 | } | 41 | } |
@@ -71,6 +71,11 @@ static void popup_handle_surface_commit(struct wl_listener *listener, void *data | |||
71 | } | 71 | } |
72 | } | 72 | } |
73 | 73 | ||
74 | static void popup_handle_reposition(struct wl_listener *listener, void *data) { | ||
75 | struct sway_xdg_popup *popup = wl_container_of(listener, popup, reposition); | ||
76 | popup_unconstrain(popup); | ||
77 | } | ||
78 | |||
74 | static struct sway_xdg_popup *popup_create(struct wlr_xdg_popup *wlr_popup, | 79 | static struct sway_xdg_popup *popup_create(struct wlr_xdg_popup *wlr_popup, |
75 | struct sway_view *view, struct wlr_scene_tree *parent) { | 80 | struct sway_view *view, struct wlr_scene_tree *parent) { |
76 | struct wlr_xdg_surface *xdg_surface = wlr_popup->base; | 81 | struct wlr_xdg_surface *xdg_surface = wlr_popup->base; |
@@ -97,8 +102,11 @@ static struct sway_xdg_popup *popup_create(struct wlr_xdg_popup *wlr_popup, | |||
97 | return NULL; | 102 | return NULL; |
98 | } | 103 | } |
99 | 104 | ||
105 | popup->desc.relative = &view->content_tree->node; | ||
106 | popup->desc.view = view; | ||
107 | |||
100 | if (!scene_descriptor_assign(&popup->scene_tree->node, | 108 | if (!scene_descriptor_assign(&popup->scene_tree->node, |
101 | SWAY_SCENE_DESC_POPUP, popup)) { | 109 | SWAY_SCENE_DESC_POPUP, &popup->desc)) { |
102 | sway_log(SWAY_ERROR, "Failed to allocate a popup scene descriptor"); | 110 | sway_log(SWAY_ERROR, "Failed to allocate a popup scene descriptor"); |
103 | wlr_scene_node_destroy(&popup->scene_tree->node); | 111 | wlr_scene_node_destroy(&popup->scene_tree->node); |
104 | free(popup); | 112 | free(popup); |
@@ -114,6 +122,8 @@ static struct sway_xdg_popup *popup_create(struct wlr_xdg_popup *wlr_popup, | |||
114 | popup->surface_commit.notify = popup_handle_surface_commit; | 122 | popup->surface_commit.notify = popup_handle_surface_commit; |
115 | wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup); | 123 | wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup); |
116 | popup->new_popup.notify = popup_handle_new_popup; | 124 | popup->new_popup.notify = popup_handle_new_popup; |
125 | wl_signal_add(&wlr_popup->events.reposition, &popup->reposition); | ||
126 | popup->reposition.notify = popup_handle_reposition; | ||
117 | wl_signal_add(&wlr_popup->events.destroy, &popup->destroy); | 127 | wl_signal_add(&wlr_popup->events.destroy, &popup->destroy); |
118 | popup->destroy.notify = popup_handle_destroy; | 128 | popup->destroy.notify = popup_handle_destroy; |
119 | 129 | ||
@@ -279,6 +289,7 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
279 | } | 289 | } |
280 | // XXX: https://github.com/swaywm/sway/issues/2176 | 290 | // XXX: https://github.com/swaywm/sway/issues/2176 |
281 | wlr_xdg_surface_schedule_configure(xdg_surface); | 291 | wlr_xdg_surface_schedule_configure(xdg_surface); |
292 | // TODO: wlr_xdg_toplevel_set_bounds() | ||
282 | return; | 293 | return; |
283 | } | 294 | } |
284 | 295 | ||
@@ -337,6 +348,7 @@ static void handle_set_app_id(struct wl_listener *listener, void *data) { | |||
337 | struct sway_xdg_shell_view *xdg_shell_view = | 348 | struct sway_xdg_shell_view *xdg_shell_view = |
338 | wl_container_of(listener, xdg_shell_view, set_app_id); | 349 | wl_container_of(listener, xdg_shell_view, set_app_id); |
339 | struct sway_view *view = &xdg_shell_view->view; | 350 | struct sway_view *view = &xdg_shell_view->view; |
351 | view_update_app_id(view); | ||
340 | view_execute_criteria(view); | 352 | view_execute_criteria(view); |
341 | } | 353 | } |
342 | 354 | ||
@@ -563,4 +575,7 @@ void handle_xdg_shell_toplevel(struct wl_listener *listener, void *data) { | |||
563 | wlr_scene_xdg_surface_create(xdg_shell_view->view.content_tree, xdg_toplevel->base); | 575 | wlr_scene_xdg_surface_create(xdg_shell_view->view.content_tree, xdg_toplevel->base); |
564 | 576 | ||
565 | xdg_toplevel->base->data = xdg_shell_view; | 577 | xdg_toplevel->base->data = xdg_shell_view; |
578 | |||
579 | wlr_xdg_toplevel_set_wm_capabilities(xdg_toplevel, | ||
580 | XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); | ||
566 | } | 581 | } |
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 9f3f4d5f..270cf08f 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 199309L | ||
2 | #include <float.h> | 1 | #include <float.h> |
3 | #include <stdbool.h> | 2 | #include <stdbool.h> |
4 | #include <stdlib.h> | 3 | #include <stdlib.h> |
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 404c1eed..235951d4 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <assert.h> | 1 | #include <assert.h> |
3 | #include <math.h> | 2 | #include <math.h> |
4 | #include <libevdev/libevdev.h> | 3 | #include <libevdev/libevdev.h> |
@@ -9,6 +8,7 @@ | |||
9 | #include <wlr/types/wlr_cursor.h> | 8 | #include <wlr/types/wlr_cursor.h> |
10 | #include <wlr/types/wlr_cursor_shape_v1.h> | 9 | #include <wlr/types/wlr_cursor_shape_v1.h> |
11 | #include <wlr/types/wlr_pointer.h> | 10 | #include <wlr/types/wlr_pointer.h> |
11 | #include <wlr/types/wlr_relative_pointer_v1.h> | ||
12 | #include <wlr/types/wlr_touch.h> | 12 | #include <wlr/types/wlr_touch.h> |
13 | #include <wlr/types/wlr_tablet_v2.h> | 13 | #include <wlr/types/wlr_tablet_v2.h> |
14 | #include <wlr/types/wlr_tablet_pad.h> | 14 | #include <wlr/types/wlr_tablet_pad.h> |
@@ -25,6 +25,7 @@ | |||
25 | #include "sway/layers.h" | 25 | #include "sway/layers.h" |
26 | #include "sway/output.h" | 26 | #include "sway/output.h" |
27 | #include "sway/scene_descriptor.h" | 27 | #include "sway/scene_descriptor.h" |
28 | #include "sway/server.h" | ||
28 | #include "sway/tree/container.h" | 29 | #include "sway/tree/container.h" |
29 | #include "sway/tree/root.h" | 30 | #include "sway/tree/root.h" |
30 | #include "sway/tree/view.h" | 31 | #include "sway/tree/view.h" |
@@ -90,9 +91,9 @@ struct sway_node *node_at_coords( | |||
90 | } | 91 | } |
91 | 92 | ||
92 | if (!con) { | 93 | if (!con) { |
93 | struct sway_xdg_popup *popup = | 94 | struct sway_popup_desc *popup = |
94 | scene_descriptor_try_get(current, SWAY_SCENE_DESC_POPUP); | 95 | scene_descriptor_try_get(current, SWAY_SCENE_DESC_POPUP); |
95 | if (popup) { | 96 | if (popup && popup->view) { |
96 | con = popup->view->container; | 97 | con = popup->view->container; |
97 | } | 98 | } |
98 | } | 99 | } |
@@ -107,7 +108,7 @@ struct sway_node *node_at_coords( | |||
107 | return NULL; | 108 | return NULL; |
108 | } | 109 | } |
109 | 110 | ||
110 | #if HAVE_XWAYLAND | 111 | #if WLR_HAS_XWAYLAND |
111 | if (scene_descriptor_try_get(current, SWAY_SCENE_DESC_XWAYLAND_UNMANAGED)) { | 112 | if (scene_descriptor_try_get(current, SWAY_SCENE_DESC_XWAYLAND_UNMANAGED)) { |
112 | return NULL; | 113 | return NULL; |
113 | } | 114 | } |
@@ -243,7 +244,7 @@ static enum sway_input_idle_source idle_source_from_device( | |||
243 | return IDLE_SOURCE_POINTER; | 244 | return IDLE_SOURCE_POINTER; |
244 | case WLR_INPUT_DEVICE_TOUCH: | 245 | case WLR_INPUT_DEVICE_TOUCH: |
245 | return IDLE_SOURCE_TOUCH; | 246 | return IDLE_SOURCE_TOUCH; |
246 | case WLR_INPUT_DEVICE_TABLET_TOOL: | 247 | case WLR_INPUT_DEVICE_TABLET: |
247 | return IDLE_SOURCE_TABLET_TOOL; | 248 | return IDLE_SOURCE_TABLET_TOOL; |
248 | case WLR_INPUT_DEVICE_TABLET_PAD: | 249 | case WLR_INPUT_DEVICE_TABLET_PAD: |
249 | return IDLE_SOURCE_TABLET_PAD; | 250 | return IDLE_SOURCE_TABLET_PAD; |
@@ -356,7 +357,7 @@ static void handle_pointer_motion_absolute( | |||
356 | 357 | ||
357 | void dispatch_cursor_button(struct sway_cursor *cursor, | 358 | void dispatch_cursor_button(struct sway_cursor *cursor, |
358 | struct wlr_input_device *device, uint32_t time_msec, uint32_t button, | 359 | struct wlr_input_device *device, uint32_t time_msec, uint32_t button, |
359 | enum wlr_button_state state) { | 360 | enum wl_pointer_button_state state) { |
360 | if (time_msec == 0) { | 361 | if (time_msec == 0) { |
361 | time_msec = get_current_time_msec(); | 362 | time_msec = get_current_time_msec(); |
362 | } | 363 | } |
@@ -368,7 +369,7 @@ static void handle_pointer_button(struct wl_listener *listener, void *data) { | |||
368 | struct sway_cursor *cursor = wl_container_of(listener, cursor, button); | 369 | struct sway_cursor *cursor = wl_container_of(listener, cursor, button); |
369 | struct wlr_pointer_button_event *event = data; | 370 | struct wlr_pointer_button_event *event = data; |
370 | 371 | ||
371 | if (event->state == WLR_BUTTON_PRESSED) { | 372 | if (event->state == WL_POINTER_BUTTON_STATE_PRESSED) { |
372 | cursor->pressed_button_count++; | 373 | cursor->pressed_button_count++; |
373 | } else { | 374 | } else { |
374 | if (cursor->pressed_button_count > 0) { | 375 | if (cursor->pressed_button_count > 0) { |
@@ -430,7 +431,7 @@ static void handle_touch_up(struct wl_listener *listener, void *data) { | |||
430 | if (cursor->pointer_touch_id == cursor->seat->touch_id) { | 431 | if (cursor->pointer_touch_id == cursor->seat->touch_id) { |
431 | cursor->pointer_touch_up = true; | 432 | cursor->pointer_touch_up = true; |
432 | dispatch_cursor_button(cursor, &event->touch->base, | 433 | dispatch_cursor_button(cursor, &event->touch->base, |
433 | event->time_msec, BTN_LEFT, WLR_BUTTON_RELEASED); | 434 | event->time_msec, BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED); |
434 | } | 435 | } |
435 | } else { | 436 | } else { |
436 | seatop_touch_up(seat, event); | 437 | seatop_touch_up(seat, event); |
@@ -448,7 +449,7 @@ static void handle_touch_cancel(struct wl_listener *listener, void *data) { | |||
448 | if (cursor->pointer_touch_id == cursor->seat->touch_id) { | 449 | if (cursor->pointer_touch_id == cursor->seat->touch_id) { |
449 | cursor->pointer_touch_up = true; | 450 | cursor->pointer_touch_up = true; |
450 | dispatch_cursor_button(cursor, &event->touch->base, | 451 | dispatch_cursor_button(cursor, &event->touch->base, |
451 | event->time_msec, BTN_LEFT, WLR_BUTTON_RELEASED); | 452 | event->time_msec, BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED); |
452 | } | 453 | } |
453 | } else { | 454 | } else { |
454 | seatop_touch_cancel(seat, event); | 455 | seatop_touch_cancel(seat, event); |
@@ -518,7 +519,7 @@ static void apply_mapping_from_region(struct wlr_input_device *device, | |||
518 | double x1 = region->x1, x2 = region->x2; | 519 | double x1 = region->x1, x2 = region->x2; |
519 | double y1 = region->y1, y2 = region->y2; | 520 | double y1 = region->y1, y2 = region->y2; |
520 | 521 | ||
521 | if (region->mm && device->type == WLR_INPUT_DEVICE_TABLET_TOOL) { | 522 | if (region->mm && device->type == WLR_INPUT_DEVICE_TABLET) { |
522 | struct wlr_tablet *tablet = wlr_tablet_from_input_device(device); | 523 | struct wlr_tablet *tablet = wlr_tablet_from_input_device(device); |
523 | if (tablet->width_mm == 0 || tablet->height_mm == 0) { | 524 | if (tablet->width_mm == 0 || tablet->height_mm == 0) { |
524 | return; | 525 | return; |
@@ -661,7 +662,7 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) { | |||
661 | event->state == WLR_TABLET_TOOL_TIP_UP) { | 662 | event->state == WLR_TABLET_TOOL_TIP_UP) { |
662 | cursor->simulating_pointer_from_tool_tip = false; | 663 | cursor->simulating_pointer_from_tool_tip = false; |
663 | dispatch_cursor_button(cursor, &event->tablet->base, event->time_msec, | 664 | dispatch_cursor_button(cursor, &event->tablet->base, event->time_msec, |
664 | BTN_LEFT, WLR_BUTTON_RELEASED); | 665 | BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED); |
665 | wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); | 666 | wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); |
666 | } else if (!surface || !wlr_surface_accepts_tablet_v2(tablet_v2, surface)) { | 667 | } else if (!surface || !wlr_surface_accepts_tablet_v2(tablet_v2, surface)) { |
667 | // If we started holding the tool tip down on a surface that accepts | 668 | // If we started holding the tool tip down on a surface that accepts |
@@ -673,7 +674,7 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) { | |||
673 | } else { | 674 | } else { |
674 | cursor->simulating_pointer_from_tool_tip = true; | 675 | cursor->simulating_pointer_from_tool_tip = true; |
675 | dispatch_cursor_button(cursor, &event->tablet->base, | 676 | dispatch_cursor_button(cursor, &event->tablet->base, |
676 | event->time_msec, BTN_LEFT, WLR_BUTTON_PRESSED); | 677 | event->time_msec, BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED); |
677 | wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); | 678 | wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); |
678 | } | 679 | } |
679 | } else { | 680 | } else { |
@@ -776,13 +777,13 @@ static void handle_tool_button(struct wl_listener *listener, void *data) { | |||
776 | case WLR_BUTTON_PRESSED: | 777 | case WLR_BUTTON_PRESSED: |
777 | if (cursor->tool_buttons == 0) { | 778 | if (cursor->tool_buttons == 0) { |
778 | dispatch_cursor_button(cursor, &event->tablet->base, | 779 | dispatch_cursor_button(cursor, &event->tablet->base, |
779 | event->time_msec, BTN_RIGHT, event->state); | 780 | event->time_msec, BTN_RIGHT, WL_POINTER_BUTTON_STATE_PRESSED); |
780 | } | 781 | } |
781 | break; | 782 | break; |
782 | case WLR_BUTTON_RELEASED: | 783 | case WLR_BUTTON_RELEASED: |
783 | if (cursor->tool_buttons <= 1) { | 784 | if (cursor->tool_buttons <= 1) { |
784 | dispatch_cursor_button(cursor, &event->tablet->base, | 785 | dispatch_cursor_button(cursor, &event->tablet->base, |
785 | event->time_msec, BTN_RIGHT, event->state); | 786 | event->time_msec, BTN_RIGHT, WL_POINTER_BUTTON_STATE_RELEASED); |
786 | } | 787 | } |
787 | break; | 788 | break; |
788 | } | 789 | } |
diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index c1bbdde0..248ca34e 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c | |||
@@ -1,9 +1,10 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <ctype.h> | 1 | #include <ctype.h> |
3 | #include <stdio.h> | 2 | #include <stdio.h> |
4 | #include <string.h> | 3 | #include <string.h> |
5 | #include <math.h> | 4 | #include <math.h> |
5 | #include <assert.h> | ||
6 | #include <wlr/config.h> | 6 | #include <wlr/config.h> |
7 | #include <wlr/backend/libinput.h> | ||
7 | #include <wlr/types/wlr_cursor.h> | 8 | #include <wlr/types/wlr_cursor.h> |
8 | #include <wlr/types/wlr_keyboard_group.h> | 9 | #include <wlr/types/wlr_keyboard_group.h> |
9 | #include <wlr/types/wlr_virtual_keyboard_v1.h> | 10 | #include <wlr/types/wlr_virtual_keyboard_v1.h> |
@@ -66,8 +67,15 @@ struct sway_seat *input_manager_sway_seat_from_wlr_seat(struct wlr_seat *wlr_sea | |||
66 | } | 67 | } |
67 | 68 | ||
68 | char *input_device_get_identifier(struct wlr_input_device *device) { | 69 | char *input_device_get_identifier(struct wlr_input_device *device) { |
69 | int vendor = device->vendor; | 70 | int vendor = 0, product = 0; |
70 | int product = device->product; | 71 | #if WLR_HAS_LIBINPUT_BACKEND |
72 | if (wlr_input_device_is_libinput(device)) { | ||
73 | struct libinput_device *libinput_dev = wlr_libinput_get_device_handle(device); | ||
74 | vendor = libinput_device_get_id_vendor(libinput_dev); | ||
75 | product = libinput_device_get_id_product(libinput_dev); | ||
76 | } | ||
77 | #endif | ||
78 | |||
71 | char *name = strdup(device->name ? device->name : ""); | 79 | char *name = strdup(device->name ? device->name : ""); |
72 | strip_whitespace(name); | 80 | strip_whitespace(name); |
73 | 81 | ||
@@ -112,7 +120,7 @@ const char *input_device_get_type(struct sway_input_device *device) { | |||
112 | return "keyboard"; | 120 | return "keyboard"; |
113 | case WLR_INPUT_DEVICE_TOUCH: | 121 | case WLR_INPUT_DEVICE_TOUCH: |
114 | return "touch"; | 122 | return "touch"; |
115 | case WLR_INPUT_DEVICE_TABLET_TOOL: | 123 | case WLR_INPUT_DEVICE_TABLET: |
116 | return "tablet_tool"; | 124 | return "tablet_tool"; |
117 | case WLR_INPUT_DEVICE_TABLET_PAD: | 125 | case WLR_INPUT_DEVICE_TABLET_PAD: |
118 | return "tablet_pad"; | 126 | return "tablet_pad"; |
@@ -425,6 +433,20 @@ void handle_virtual_pointer(struct wl_listener *listener, void *data) { | |||
425 | } | 433 | } |
426 | } | 434 | } |
427 | 435 | ||
436 | static void handle_transient_seat_manager_create_seat( | ||
437 | struct wl_listener *listener, void *data) { | ||
438 | struct wlr_transient_seat_v1 *transient_seat = data; | ||
439 | static uint64_t i; | ||
440 | char name[256]; | ||
441 | snprintf(name, sizeof(name), "transient-%"PRIx64, i++); | ||
442 | struct sway_seat *seat = seat_create(name); | ||
443 | if (seat && seat->wlr_seat) { | ||
444 | wlr_transient_seat_v1_ready(transient_seat, seat->wlr_seat); | ||
445 | } else { | ||
446 | wlr_transient_seat_v1_deny(transient_seat); | ||
447 | } | ||
448 | } | ||
449 | |||
428 | struct sway_input_manager *input_manager_create(struct sway_server *server) { | 450 | struct sway_input_manager *input_manager_create(struct sway_server *server) { |
429 | struct sway_input_manager *input = | 451 | struct sway_input_manager *input = |
430 | calloc(1, sizeof(struct sway_input_manager)); | 452 | calloc(1, sizeof(struct sway_input_manager)); |
@@ -460,6 +482,15 @@ struct sway_input_manager *input_manager_create(struct sway_server *server) { | |||
460 | 482 | ||
461 | input->pointer_gestures = wlr_pointer_gestures_v1_create(server->wl_display); | 483 | input->pointer_gestures = wlr_pointer_gestures_v1_create(server->wl_display); |
462 | 484 | ||
485 | input->transient_seat_manager = | ||
486 | wlr_transient_seat_manager_v1_create(server->wl_display); | ||
487 | assert(input->transient_seat_manager); | ||
488 | |||
489 | input->transient_seat_create.notify = | ||
490 | handle_transient_seat_manager_create_seat; | ||
491 | wl_signal_add(&input->transient_seat_manager->events.create_seat, | ||
492 | &input->transient_seat_create); | ||
493 | |||
463 | return input; | 494 | return input; |
464 | } | 495 | } |
465 | 496 | ||
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index b97f0152..9ac21664 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include "sway/input/seat.h" | 13 | #include "sway/input/seat.h" |
14 | #include "sway/input/cursor.h" | 14 | #include "sway/input/cursor.h" |
15 | #include "sway/ipc-server.h" | 15 | #include "sway/ipc-server.h" |
16 | #include "sway/server.h" | ||
16 | #include "log.h" | 17 | #include "log.h" |
17 | 18 | ||
18 | #if WLR_HAS_SESSION | 19 | #if WLR_HAS_SESSION |
@@ -32,6 +33,7 @@ static struct modifier_key { | |||
32 | { XKB_MOD_NAME_NUM, WLR_MODIFIER_MOD2 }, | 33 | { XKB_MOD_NAME_NUM, WLR_MODIFIER_MOD2 }, |
33 | { "Mod3", WLR_MODIFIER_MOD3 }, | 34 | { "Mod3", WLR_MODIFIER_MOD3 }, |
34 | { XKB_MOD_NAME_LOGO, WLR_MODIFIER_LOGO }, | 35 | { XKB_MOD_NAME_LOGO, WLR_MODIFIER_LOGO }, |
36 | { "Super", WLR_MODIFIER_LOGO }, | ||
35 | { "Mod5", WLR_MODIFIER_MOD5 }, | 37 | { "Mod5", WLR_MODIFIER_MOD5 }, |
36 | }; | 38 | }; |
37 | 39 | ||
diff --git a/sway/input/seat.c b/sway/input/seat.c index 75fea484..da4bb12a 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <assert.h> | 1 | #include <assert.h> |
3 | #include <linux/input-event-codes.h> | 2 | #include <linux/input-event-codes.h> |
4 | #include <string.h> | 3 | #include <string.h> |
@@ -68,6 +67,12 @@ static void seat_node_destroy(struct sway_seat_node *seat_node) { | |||
68 | } | 67 | } |
69 | 68 | ||
70 | void seat_destroy(struct sway_seat *seat) { | 69 | void seat_destroy(struct sway_seat *seat) { |
70 | wlr_seat_destroy(seat->wlr_seat); | ||
71 | } | ||
72 | |||
73 | static void handle_seat_destroy(struct wl_listener *listener, void *data) { | ||
74 | struct sway_seat *seat = wl_container_of(listener, seat, destroy); | ||
75 | |||
71 | if (seat == config->handler_context.seat) { | 76 | if (seat == config->handler_context.seat) { |
72 | config->handler_context.seat = input_manager_get_default_seat(); | 77 | config->handler_context.seat = input_manager_get_default_seat(); |
73 | } | 78 | } |
@@ -88,7 +93,7 @@ void seat_destroy(struct sway_seat *seat) { | |||
88 | wl_list_remove(&seat->request_set_selection.link); | 93 | wl_list_remove(&seat->request_set_selection.link); |
89 | wl_list_remove(&seat->request_set_primary_selection.link); | 94 | wl_list_remove(&seat->request_set_primary_selection.link); |
90 | wl_list_remove(&seat->link); | 95 | wl_list_remove(&seat->link); |
91 | wlr_seat_destroy(seat->wlr_seat); | 96 | wl_list_remove(&seat->destroy.link); |
92 | for (int i = 0; i < seat->deferred_bindings->length; i++) { | 97 | for (int i = 0; i < seat->deferred_bindings->length; i++) { |
93 | free_sway_binding(seat->deferred_bindings->items[i]); | 98 | free_sway_binding(seat->deferred_bindings->items[i]); |
94 | } | 99 | } |
@@ -185,7 +190,7 @@ static void seat_send_focus(struct sway_node *node, struct sway_seat *seat) { | |||
185 | node->sway_container->view : NULL; | 190 | node->sway_container->view : NULL; |
186 | 191 | ||
187 | if (view && seat_is_input_allowed(seat, view->surface)) { | 192 | if (view && seat_is_input_allowed(seat, view->surface)) { |
188 | #if HAVE_XWAYLAND | 193 | #if WLR_HAS_XWAYLAND |
189 | if (view->type == SWAY_VIEW_XWAYLAND) { | 194 | if (view->type == SWAY_VIEW_XWAYLAND) { |
190 | struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland; | 195 | struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland; |
191 | wlr_xwayland_set_seat(xwayland, seat->wlr_seat); | 196 | wlr_xwayland_set_seat(xwayland, seat->wlr_seat); |
@@ -535,6 +540,9 @@ struct sway_seat *seat_create(const char *seat_name) { | |||
535 | return NULL; | 540 | return NULL; |
536 | } | 541 | } |
537 | 542 | ||
543 | seat->destroy.notify = handle_seat_destroy; | ||
544 | wl_signal_add(&seat->wlr_seat->events.destroy, &seat->destroy); | ||
545 | |||
538 | seat->idle_inhibit_sources = seat->idle_wake_sources = | 546 | seat->idle_inhibit_sources = seat->idle_wake_sources = |
539 | IDLE_SOURCE_KEYBOARD | | 547 | IDLE_SOURCE_KEYBOARD | |
540 | IDLE_SOURCE_POINTER | | 548 | IDLE_SOURCE_POINTER | |
@@ -608,7 +616,7 @@ static void seat_update_capabilities(struct sway_seat *seat) { | |||
608 | case WLR_INPUT_DEVICE_TOUCH: | 616 | case WLR_INPUT_DEVICE_TOUCH: |
609 | caps |= WL_SEAT_CAPABILITY_TOUCH; | 617 | caps |= WL_SEAT_CAPABILITY_TOUCH; |
610 | break; | 618 | break; |
611 | case WLR_INPUT_DEVICE_TABLET_TOOL: | 619 | case WLR_INPUT_DEVICE_TABLET: |
612 | caps |= WL_SEAT_CAPABILITY_POINTER; | 620 | caps |= WL_SEAT_CAPABILITY_POINTER; |
613 | break; | 621 | break; |
614 | case WLR_INPUT_DEVICE_SWITCH: | 622 | case WLR_INPUT_DEVICE_SWITCH: |
@@ -666,7 +674,7 @@ static const char *get_builtin_output_name(void) { | |||
666 | static bool is_touch_or_tablet_tool(struct sway_seat_device *seat_device) { | 674 | static bool is_touch_or_tablet_tool(struct sway_seat_device *seat_device) { |
667 | switch (seat_device->input_device->wlr_device->type) { | 675 | switch (seat_device->input_device->wlr_device->type) { |
668 | case WLR_INPUT_DEVICE_TOUCH: | 676 | case WLR_INPUT_DEVICE_TOUCH: |
669 | case WLR_INPUT_DEVICE_TABLET_TOOL: | 677 | case WLR_INPUT_DEVICE_TABLET: |
670 | return true; | 678 | return true; |
671 | default: | 679 | default: |
672 | return false; | 680 | return false; |
@@ -681,7 +689,7 @@ static void seat_apply_input_mapping(struct sway_seat *seat, | |||
681 | switch (sway_device->input_device->wlr_device->type) { | 689 | switch (sway_device->input_device->wlr_device->type) { |
682 | case WLR_INPUT_DEVICE_POINTER: | 690 | case WLR_INPUT_DEVICE_POINTER: |
683 | case WLR_INPUT_DEVICE_TOUCH: | 691 | case WLR_INPUT_DEVICE_TOUCH: |
684 | case WLR_INPUT_DEVICE_TABLET_TOOL: | 692 | case WLR_INPUT_DEVICE_TABLET: |
685 | break; | 693 | break; |
686 | default: | 694 | default: |
687 | return; // these devices don't support mappings | 695 | return; // these devices don't support mappings |
@@ -874,7 +882,7 @@ void seat_configure_device(struct sway_seat *seat, | |||
874 | case WLR_INPUT_DEVICE_TOUCH: | 882 | case WLR_INPUT_DEVICE_TOUCH: |
875 | seat_configure_touch(seat, seat_device); | 883 | seat_configure_touch(seat, seat_device); |
876 | break; | 884 | break; |
877 | case WLR_INPUT_DEVICE_TABLET_TOOL: | 885 | case WLR_INPUT_DEVICE_TABLET: |
878 | seat_configure_tablet_tool(seat, seat_device); | 886 | seat_configure_tablet_tool(seat, seat_device); |
879 | break; | 887 | break; |
880 | case WLR_INPUT_DEVICE_TABLET_PAD: | 888 | case WLR_INPUT_DEVICE_TABLET_PAD: |
@@ -913,7 +921,7 @@ void seat_reset_device(struct sway_seat *seat, | |||
913 | case WLR_INPUT_DEVICE_TOUCH: | 921 | case WLR_INPUT_DEVICE_TOUCH: |
914 | seat_reset_input_config(seat, seat_device); | 922 | seat_reset_input_config(seat, seat_device); |
915 | break; | 923 | break; |
916 | case WLR_INPUT_DEVICE_TABLET_TOOL: | 924 | case WLR_INPUT_DEVICE_TABLET: |
917 | seat_reset_input_config(seat, seat_device); | 925 | seat_reset_input_config(seat, seat_device); |
918 | break; | 926 | break; |
919 | case WLR_INPUT_DEVICE_TABLET_PAD: | 927 | case WLR_INPUT_DEVICE_TABLET_PAD: |
@@ -994,7 +1002,7 @@ void seat_configure_xcursor(struct sway_seat *seat) { | |||
994 | setenv("XCURSOR_THEME", cursor_theme, 1); | 1002 | setenv("XCURSOR_THEME", cursor_theme, 1); |
995 | } | 1003 | } |
996 | 1004 | ||
997 | #if HAVE_XWAYLAND | 1005 | #if WLR_HAS_XWAYLAND |
998 | if (server.xwayland.wlr_xwayland && (!server.xwayland.xcursor_manager || | 1006 | if (server.xwayland.wlr_xwayland && (!server.xwayland.xcursor_manager || |
999 | !xcursor_manager_is_named(server.xwayland.xcursor_manager, | 1007 | !xcursor_manager_is_named(server.xwayland.xcursor_manager, |
1000 | cursor_theme) || | 1008 | cursor_theme) || |
@@ -1521,7 +1529,7 @@ struct seat_config *seat_get_config_by_name(const char *name) { | |||
1521 | } | 1529 | } |
1522 | 1530 | ||
1523 | void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec, | 1531 | void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec, |
1524 | uint32_t button, enum wlr_button_state state) { | 1532 | uint32_t button, enum wl_pointer_button_state state) { |
1525 | seat->last_button_serial = wlr_seat_pointer_notify_button(seat->wlr_seat, | 1533 | seat->last_button_serial = wlr_seat_pointer_notify_button(seat->wlr_seat, |
1526 | time_msec, button, state); | 1534 | time_msec, button, state); |
1527 | } | 1535 | } |
@@ -1558,7 +1566,7 @@ void seatop_unref(struct sway_seat *seat, struct sway_container *con) { | |||
1558 | 1566 | ||
1559 | void seatop_button(struct sway_seat *seat, uint32_t time_msec, | 1567 | void seatop_button(struct sway_seat *seat, uint32_t time_msec, |
1560 | struct wlr_input_device *device, uint32_t button, | 1568 | struct wlr_input_device *device, uint32_t button, |
1561 | enum wlr_button_state state) { | 1569 | enum wl_pointer_button_state state) { |
1562 | if (seat->seatop_impl->button) { | 1570 | if (seat->seatop_impl->button) { |
1563 | seat->seatop_impl->button(seat, time_msec, device, button, state); | 1571 | seat->seatop_impl->button(seat, time_msec, device, button, state); |
1564 | } | 1572 | } |
diff --git a/sway/input/seatop_default.c b/sway/input/seatop_default.c index c56330fd..f4a0f463 100644 --- a/sway/input/seatop_default.c +++ b/sway/input/seatop_default.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <float.h> | 1 | #include <float.h> |
3 | #include <libevdev/libevdev.h> | 2 | #include <libevdev/libevdev.h> |
4 | #include <wlr/types/wlr_cursor.h> | 3 | #include <wlr/types/wlr_cursor.h> |
@@ -12,11 +11,12 @@ | |||
12 | #include "sway/input/tablet.h" | 11 | #include "sway/input/tablet.h" |
13 | #include "sway/layers.h" | 12 | #include "sway/layers.h" |
14 | #include "sway/output.h" | 13 | #include "sway/output.h" |
14 | #include "sway/server.h" | ||
15 | #include "sway/scene_descriptor.h" | 15 | #include "sway/scene_descriptor.h" |
16 | #include "sway/tree/view.h" | 16 | #include "sway/tree/view.h" |
17 | #include "sway/tree/workspace.h" | 17 | #include "sway/tree/workspace.h" |
18 | #include "log.h" | 18 | #include "log.h" |
19 | #if HAVE_XWAYLAND | 19 | #if WLR_HAS_XWAYLAND |
20 | #include "sway/xwayland.h" | 20 | #include "sway/xwayland.h" |
21 | #endif | 21 | #endif |
22 | 22 | ||
@@ -235,7 +235,7 @@ static void handle_tablet_tool_tip(struct sway_seat *seat, | |||
235 | node->sway_container : NULL; | 235 | node->sway_container : NULL; |
236 | 236 | ||
237 | struct wlr_layer_surface_v1 *layer; | 237 | struct wlr_layer_surface_v1 *layer; |
238 | #if HAVE_XWAYLAND | 238 | #if WLR_HAS_XWAYLAND |
239 | struct wlr_xwayland_surface *xsurface; | 239 | struct wlr_xwayland_surface *xsurface; |
240 | #endif | 240 | #endif |
241 | if ((layer = wlr_layer_surface_v1_try_from_wlr_surface(surface)) && | 241 | if ((layer = wlr_layer_surface_v1_try_from_wlr_surface(surface)) && |
@@ -269,7 +269,7 @@ static void handle_tablet_tool_tip(struct sway_seat *seat, | |||
269 | seat_set_focus_container(seat, cont); | 269 | seat_set_focus_container(seat, cont); |
270 | seatop_begin_down(seat, node->sway_container, sx, sy); | 270 | seatop_begin_down(seat, node->sway_container, sx, sy); |
271 | } | 271 | } |
272 | #if HAVE_XWAYLAND | 272 | #if WLR_HAS_XWAYLAND |
273 | // Handle tapping on an xwayland unmanaged view | 273 | // Handle tapping on an xwayland unmanaged view |
274 | else if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(surface)) && | 274 | else if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(surface)) && |
275 | xsurface->override_redirect && | 275 | xsurface->override_redirect && |
@@ -291,7 +291,7 @@ static void handle_tablet_tool_tip(struct sway_seat *seat, | |||
291 | 291 | ||
292 | static bool trigger_pointer_button_binding(struct sway_seat *seat, | 292 | static bool trigger_pointer_button_binding(struct sway_seat *seat, |
293 | struct wlr_input_device *device, uint32_t button, | 293 | struct wlr_input_device *device, uint32_t button, |
294 | enum wlr_button_state state, uint32_t modifiers, | 294 | enum wl_pointer_button_state state, uint32_t modifiers, |
295 | bool on_titlebar, bool on_border, bool on_contents, bool on_workspace) { | 295 | bool on_titlebar, bool on_border, bool on_contents, bool on_workspace) { |
296 | // We can reach this for non-pointer devices if we're currently emulating | 296 | // We can reach this for non-pointer devices if we're currently emulating |
297 | // pointer input for one. Emulated input should not trigger bindings. The | 297 | // pointer input for one. Emulated input should not trigger bindings. The |
@@ -305,7 +305,7 @@ static bool trigger_pointer_button_binding(struct sway_seat *seat, | |||
305 | char *device_identifier = device ? input_device_get_identifier(device) | 305 | char *device_identifier = device ? input_device_get_identifier(device) |
306 | : strdup("*"); | 306 | : strdup("*"); |
307 | struct sway_binding *binding = NULL; | 307 | struct sway_binding *binding = NULL; |
308 | if (state == WLR_BUTTON_PRESSED) { | 308 | if (state == WL_POINTER_BUTTON_STATE_PRESSED) { |
309 | state_add_button(e, button); | 309 | state_add_button(e, button); |
310 | binding = get_active_mouse_binding(e, | 310 | binding = get_active_mouse_binding(e, |
311 | config->current_mode->mouse_bindings, modifiers, false, | 311 | config->current_mode->mouse_bindings, modifiers, false, |
@@ -330,7 +330,7 @@ static bool trigger_pointer_button_binding(struct sway_seat *seat, | |||
330 | 330 | ||
331 | static void handle_button(struct sway_seat *seat, uint32_t time_msec, | 331 | static void handle_button(struct sway_seat *seat, uint32_t time_msec, |
332 | struct wlr_input_device *device, uint32_t button, | 332 | struct wlr_input_device *device, uint32_t button, |
333 | enum wlr_button_state state) { | 333 | enum wl_pointer_button_state state) { |
334 | struct sway_cursor *cursor = seat->cursor; | 334 | struct sway_cursor *cursor = seat->cursor; |
335 | 335 | ||
336 | // Determine what's under the cursor | 336 | // Determine what's under the cursor |
@@ -363,7 +363,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
363 | 363 | ||
364 | // Handle clicking an empty workspace | 364 | // Handle clicking an empty workspace |
365 | if (node && node->type == N_WORKSPACE) { | 365 | if (node && node->type == N_WORKSPACE) { |
366 | if (state == WLR_BUTTON_PRESSED) { | 366 | if (state == WL_POINTER_BUTTON_STATE_PRESSED) { |
367 | seat_set_focus(seat, node); | 367 | seat_set_focus(seat, node); |
368 | transaction_commit_dirty(); | 368 | transaction_commit_dirty(); |
369 | } | 369 | } |
@@ -378,7 +378,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
378 | seat_set_focus_layer(seat, layer); | 378 | seat_set_focus_layer(seat, layer); |
379 | transaction_commit_dirty(); | 379 | transaction_commit_dirty(); |
380 | } | 380 | } |
381 | if (state == WLR_BUTTON_PRESSED) { | 381 | if (state == WL_POINTER_BUTTON_STATE_PRESSED) { |
382 | seatop_begin_down_on_surface(seat, surface, sx, sy); | 382 | seatop_begin_down_on_surface(seat, surface, sx, sy); |
383 | } | 383 | } |
384 | seat_pointer_notify_button(seat, time_msec, button, state); | 384 | seat_pointer_notify_button(seat, time_msec, button, state); |
@@ -387,7 +387,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
387 | 387 | ||
388 | // Handle tiling resize via border | 388 | // Handle tiling resize via border |
389 | if (cont && resize_edge && button == BTN_LEFT && | 389 | if (cont && resize_edge && button == BTN_LEFT && |
390 | state == WLR_BUTTON_PRESSED && !is_floating) { | 390 | state == WL_POINTER_BUTTON_STATE_PRESSED && !is_floating) { |
391 | // If a resize is triggered on a tabbed or stacked container, change | 391 | // If a resize is triggered on a tabbed or stacked container, change |
392 | // focus to the tab which already had inactive focus -- otherwise, we'd | 392 | // focus to the tab which already had inactive focus -- otherwise, we'd |
393 | // change the active tab when the user probably just wanted to resize. | 393 | // change the active tab when the user probably just wanted to resize. |
@@ -405,7 +405,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
405 | // Handle tiling resize via mod | 405 | // Handle tiling resize via mod |
406 | bool mod_pressed = modifiers & config->floating_mod; | 406 | bool mod_pressed = modifiers & config->floating_mod; |
407 | if (cont && !is_floating_or_child && mod_pressed && | 407 | if (cont && !is_floating_or_child && mod_pressed && |
408 | state == WLR_BUTTON_PRESSED) { | 408 | state == WL_POINTER_BUTTON_STATE_PRESSED) { |
409 | uint32_t btn_resize = config->floating_mod_inverse ? | 409 | uint32_t btn_resize = config->floating_mod_inverse ? |
410 | BTN_LEFT : BTN_RIGHT; | 410 | BTN_LEFT : BTN_RIGHT; |
411 | if (button == btn_resize) { | 411 | if (button == btn_resize) { |
@@ -433,7 +433,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
433 | } | 433 | } |
434 | 434 | ||
435 | // Handle changing focus when clicking on a container | 435 | // Handle changing focus when clicking on a container |
436 | if (cont && state == WLR_BUTTON_PRESSED) { | 436 | if (cont && state == WL_POINTER_BUTTON_STATE_PRESSED) { |
437 | // Default case: focus the container that was just clicked. | 437 | // Default case: focus the container that was just clicked. |
438 | node = &cont->node; | 438 | node = &cont->node; |
439 | 439 | ||
@@ -454,7 +454,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
454 | 454 | ||
455 | // Handle beginning floating move | 455 | // Handle beginning floating move |
456 | if (cont && is_floating_or_child && !is_fullscreen_or_child && | 456 | if (cont && is_floating_or_child && !is_fullscreen_or_child && |
457 | state == WLR_BUTTON_PRESSED) { | 457 | state == WL_POINTER_BUTTON_STATE_PRESSED) { |
458 | uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT; | 458 | uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT; |
459 | if (button == btn_move && (mod_pressed || on_titlebar)) { | 459 | if (button == btn_move && (mod_pressed || on_titlebar)) { |
460 | seatop_begin_move_floating(seat, container_toplevel_ancestor(cont)); | 460 | seatop_begin_move_floating(seat, container_toplevel_ancestor(cont)); |
@@ -464,7 +464,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
464 | 464 | ||
465 | // Handle beginning floating resize | 465 | // Handle beginning floating resize |
466 | if (cont && is_floating_or_child && !is_fullscreen_or_child && | 466 | if (cont && is_floating_or_child && !is_fullscreen_or_child && |
467 | state == WLR_BUTTON_PRESSED) { | 467 | state == WL_POINTER_BUTTON_STATE_PRESSED) { |
468 | // Via border | 468 | // Via border |
469 | if (button == BTN_LEFT && resize_edge != WLR_EDGE_NONE) { | 469 | if (button == BTN_LEFT && resize_edge != WLR_EDGE_NONE) { |
470 | seat_set_focus_container(seat, cont); | 470 | seat_set_focus_container(seat, cont); |
@@ -490,7 +490,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
490 | 490 | ||
491 | // Handle moving a tiling container | 491 | // Handle moving a tiling container |
492 | if (config->tiling_drag && (mod_pressed || on_titlebar) && | 492 | if (config->tiling_drag && (mod_pressed || on_titlebar) && |
493 | state == WLR_BUTTON_PRESSED && !is_floating_or_child && | 493 | state == WL_POINTER_BUTTON_STATE_PRESSED && !is_floating_or_child && |
494 | cont && cont->pending.fullscreen_mode == FULLSCREEN_NONE) { | 494 | cont && cont->pending.fullscreen_mode == FULLSCREEN_NONE) { |
495 | // If moving a container by its title bar, use a threshold for the drag | 495 | // If moving a container by its title bar, use a threshold for the drag |
496 | if (!mod_pressed && config->tiling_drag_threshold > 0) { | 496 | if (!mod_pressed && config->tiling_drag_threshold > 0) { |
@@ -503,19 +503,19 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
503 | } | 503 | } |
504 | 504 | ||
505 | // Handle mousedown on a container surface | 505 | // Handle mousedown on a container surface |
506 | if (surface && cont && state == WLR_BUTTON_PRESSED) { | 506 | if (surface && cont && state == WL_POINTER_BUTTON_STATE_PRESSED) { |
507 | seatop_begin_down(seat, cont, sx, sy); | 507 | seatop_begin_down(seat, cont, sx, sy); |
508 | seat_pointer_notify_button(seat, time_msec, button, WLR_BUTTON_PRESSED); | 508 | seat_pointer_notify_button(seat, time_msec, button, WL_POINTER_BUTTON_STATE_PRESSED); |
509 | return; | 509 | return; |
510 | } | 510 | } |
511 | 511 | ||
512 | // Handle clicking a container surface or decorations | 512 | // Handle clicking a container surface or decorations |
513 | if (cont && state == WLR_BUTTON_PRESSED) { | 513 | if (cont && state == WL_POINTER_BUTTON_STATE_PRESSED) { |
514 | seat_pointer_notify_button(seat, time_msec, button, state); | 514 | seat_pointer_notify_button(seat, time_msec, button, state); |
515 | return; | 515 | return; |
516 | } | 516 | } |
517 | 517 | ||
518 | #if HAVE_XWAYLAND | 518 | #if WLR_HAS_XWAYLAND |
519 | // Handle clicking on xwayland unmanaged view | 519 | // Handle clicking on xwayland unmanaged view |
520 | struct wlr_xwayland_surface *xsurface; | 520 | struct wlr_xwayland_surface *xsurface; |
521 | if (surface && | 521 | if (surface && |
@@ -685,7 +685,7 @@ static void handle_touch_down(struct sway_seat *seat, | |||
685 | pointer_motion(cursor, event->time_msec, &event->touch->base, dx, dy, | 685 | pointer_motion(cursor, event->time_msec, &event->touch->base, dx, dy, |
686 | dx, dy); | 686 | dx, dy); |
687 | dispatch_cursor_button(cursor, &event->touch->base, event->time_msec, | 687 | dispatch_cursor_button(cursor, &event->touch->base, event->time_msec, |
688 | BTN_LEFT, WLR_BUTTON_PRESSED); | 688 | BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED); |
689 | } | 689 | } |
690 | } | 690 | } |
691 | 691 | ||
@@ -695,9 +695,9 @@ static void handle_touch_down(struct sway_seat *seat, | |||
695 | 695 | ||
696 | static uint32_t wl_axis_to_button(struct wlr_pointer_axis_event *event) { | 696 | static uint32_t wl_axis_to_button(struct wlr_pointer_axis_event *event) { |
697 | switch (event->orientation) { | 697 | switch (event->orientation) { |
698 | case WLR_AXIS_ORIENTATION_VERTICAL: | 698 | case WL_POINTER_AXIS_VERTICAL_SCROLL: |
699 | return event->delta < 0 ? SWAY_SCROLL_UP : SWAY_SCROLL_DOWN; | 699 | return event->delta < 0 ? SWAY_SCROLL_UP : SWAY_SCROLL_DOWN; |
700 | case WLR_AXIS_ORIENTATION_HORIZONTAL: | 700 | case WL_POINTER_AXIS_HORIZONTAL_SCROLL: |
701 | return event->delta < 0 ? SWAY_SCROLL_LEFT : SWAY_SCROLL_RIGHT; | 701 | return event->delta < 0 ? SWAY_SCROLL_LEFT : SWAY_SCROLL_RIGHT; |
702 | default: | 702 | default: |
703 | sway_log(SWAY_DEBUG, "Unknown axis orientation"); | 703 | sway_log(SWAY_DEBUG, "Unknown axis orientation"); |
diff --git a/sway/input/seatop_down.c b/sway/input/seatop_down.c index b4421fe6..340e334b 100644 --- a/sway/input/seatop_down.c +++ b/sway/input/seatop_down.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <float.h> | 1 | #include <float.h> |
3 | #include <wlr/types/wlr_cursor.h> | 2 | #include <wlr/types/wlr_cursor.h> |
4 | #include <wlr/types/wlr_tablet_v2.h> | 3 | #include <wlr/types/wlr_tablet_v2.h> |
@@ -118,7 +117,11 @@ static void handle_touch_cancel(struct sway_seat *seat, | |||
118 | } | 117 | } |
119 | 118 | ||
120 | if (e->surface) { | 119 | if (e->surface) { |
121 | wlr_seat_touch_notify_cancel(seat->wlr_seat, e->surface); | 120 | struct wl_client *client = wl_resource_get_client(e->surface->resource); |
121 | struct wlr_seat_client *seat_client = wlr_seat_client_for_wl_client(seat->wlr_seat, client); | ||
122 | if (seat_client != NULL) { | ||
123 | wlr_seat_touch_notify_cancel(seat->wlr_seat, seat_client); | ||
124 | } | ||
122 | } | 125 | } |
123 | 126 | ||
124 | if (wl_list_empty(&e->point_events)) { | 127 | if (wl_list_empty(&e->point_events)) { |
@@ -143,7 +146,7 @@ static void handle_pointer_axis(struct sway_seat *seat, | |||
143 | 146 | ||
144 | static void handle_button(struct sway_seat *seat, uint32_t time_msec, | 147 | static void handle_button(struct sway_seat *seat, uint32_t time_msec, |
145 | struct wlr_input_device *device, uint32_t button, | 148 | struct wlr_input_device *device, uint32_t button, |
146 | enum wlr_button_state state) { | 149 | enum wl_pointer_button_state state) { |
147 | seat_pointer_notify_button(seat, time_msec, button, state); | 150 | seat_pointer_notify_button(seat, time_msec, button, state); |
148 | 151 | ||
149 | if (seat->cursor->pressed_button_count == 0) { | 152 | if (seat->cursor->pressed_button_count == 0) { |
diff --git a/sway/input/seatop_move_floating.c b/sway/input/seatop_move_floating.c index 21d048ce..83668d88 100644 --- a/sway/input/seatop_move_floating.c +++ b/sway/input/seatop_move_floating.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <wlr/types/wlr_cursor.h> | 1 | #include <wlr/types/wlr_cursor.h> |
3 | #include "sway/desktop/transaction.h" | 2 | #include "sway/desktop/transaction.h" |
4 | #include "sway/input/cursor.h" | 3 | #include "sway/input/cursor.h" |
@@ -22,7 +21,7 @@ static void finalize_move(struct sway_seat *seat) { | |||
22 | 21 | ||
23 | static void handle_button(struct sway_seat *seat, uint32_t time_msec, | 22 | static void handle_button(struct sway_seat *seat, uint32_t time_msec, |
24 | struct wlr_input_device *device, uint32_t button, | 23 | struct wlr_input_device *device, uint32_t button, |
25 | enum wlr_button_state state) { | 24 | enum wl_pointer_button_state state) { |
26 | if (seat->cursor->pressed_button_count == 0) { | 25 | if (seat->cursor->pressed_button_count == 0) { |
27 | finalize_move(seat); | 26 | finalize_move(seat); |
28 | } | 27 | } |
diff --git a/sway/input/seatop_move_tiling.c b/sway/input/seatop_move_tiling.c index 7de39ff6..c525b77a 100644 --- a/sway/input/seatop_move_tiling.c +++ b/sway/input/seatop_move_tiling.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <limits.h> | 1 | #include <limits.h> |
3 | #include <wlr/types/wlr_cursor.h> | 2 | #include <wlr/types/wlr_cursor.h> |
4 | #include <wlr/util/edges.h> | 3 | #include <wlr/util/edges.h> |
@@ -406,7 +405,7 @@ static void finalize_move(struct sway_seat *seat) { | |||
406 | 405 | ||
407 | static void handle_button(struct sway_seat *seat, uint32_t time_msec, | 406 | static void handle_button(struct sway_seat *seat, uint32_t time_msec, |
408 | struct wlr_input_device *device, uint32_t button, | 407 | struct wlr_input_device *device, uint32_t button, |
409 | enum wlr_button_state state) { | 408 | enum wl_pointer_button_state state) { |
410 | if (seat->cursor->pressed_button_count == 0) { | 409 | if (seat->cursor->pressed_button_count == 0) { |
411 | finalize_move(seat); | 410 | finalize_move(seat); |
412 | } | 411 | } |
diff --git a/sway/input/seatop_resize_floating.c b/sway/input/seatop_resize_floating.c index df683026..bec86e33 100644 --- a/sway/input/seatop_resize_floating.c +++ b/sway/input/seatop_resize_floating.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <limits.h> | 1 | #include <limits.h> |
3 | #include <wlr/types/wlr_cursor.h> | 2 | #include <wlr/types/wlr_cursor.h> |
4 | #include <wlr/types/wlr_xcursor_manager.h> | 3 | #include <wlr/types/wlr_xcursor_manager.h> |
@@ -21,7 +20,7 @@ struct seatop_resize_floating_event { | |||
21 | 20 | ||
22 | static void handle_button(struct sway_seat *seat, uint32_t time_msec, | 21 | static void handle_button(struct sway_seat *seat, uint32_t time_msec, |
23 | struct wlr_input_device *device, uint32_t button, | 22 | struct wlr_input_device *device, uint32_t button, |
24 | enum wlr_button_state state) { | 23 | enum wl_pointer_button_state state) { |
25 | struct seatop_resize_floating_event *e = seat->seatop_data; | 24 | struct seatop_resize_floating_event *e = seat->seatop_data; |
26 | struct sway_container *con = e->con; | 25 | struct sway_container *con = e->con; |
27 | 26 | ||
diff --git a/sway/input/seatop_resize_tiling.c b/sway/input/seatop_resize_tiling.c index 869d11b5..15fd333b 100644 --- a/sway/input/seatop_resize_tiling.c +++ b/sway/input/seatop_resize_tiling.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <wlr/types/wlr_cursor.h> | 1 | #include <wlr/types/wlr_cursor.h> |
3 | #include <wlr/util/edges.h> | 2 | #include <wlr/util/edges.h> |
4 | #include "sway/commands.h" | 3 | #include "sway/commands.h" |
@@ -46,7 +45,7 @@ static struct sway_container *container_get_resize_sibling( | |||
46 | 45 | ||
47 | static void handle_button(struct sway_seat *seat, uint32_t time_msec, | 46 | static void handle_button(struct sway_seat *seat, uint32_t time_msec, |
48 | struct wlr_input_device *device, uint32_t button, | 47 | struct wlr_input_device *device, uint32_t button, |
49 | enum wlr_button_state state) { | 48 | enum wl_pointer_button_state state) { |
50 | struct seatop_resize_tiling_event *e = seat->seatop_data; | 49 | struct seatop_resize_tiling_event *e = seat->seatop_data; |
51 | 50 | ||
52 | if (seat->cursor->pressed_button_count == 0) { | 51 | if (seat->cursor->pressed_button_count == 0) { |
diff --git a/sway/input/switch.c b/sway/input/switch.c index 831f4dbf..6aab4ad0 100644 --- a/sway/input/switch.c +++ b/sway/input/switch.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #include "sway/config.h" | 1 | #include "sway/config.h" |
2 | #include "sway/input/switch.h" | 2 | #include "sway/input/switch.h" |
3 | #include "sway/server.h" | ||
3 | #include "log.h" | 4 | #include "log.h" |
4 | 5 | ||
5 | struct sway_switch *sway_switch_create(struct sway_seat *seat, | 6 | struct sway_switch *sway_switch_create(struct sway_seat *seat, |
diff --git a/sway/input/tablet.c b/sway/input/tablet.c index 902cb7ed..ec1e4f68 100644 --- a/sway/input/tablet.c +++ b/sway/input/tablet.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <stdlib.h> | 1 | #include <stdlib.h> |
3 | #include <wlr/config.h> | 2 | #include <wlr/config.h> |
4 | #include <wlr/types/wlr_tablet_v2.h> | 3 | #include <wlr/types/wlr_tablet_v2.h> |
@@ -8,6 +7,7 @@ | |||
8 | #include "sway/input/cursor.h" | 7 | #include "sway/input/cursor.h" |
9 | #include "sway/input/seat.h" | 8 | #include "sway/input/seat.h" |
10 | #include "sway/input/tablet.h" | 9 | #include "sway/input/tablet.h" |
10 | #include "sway/server.h" | ||
11 | 11 | ||
12 | #if WLR_HAS_LIBINPUT_BACKEND | 12 | #if WLR_HAS_LIBINPUT_BACKEND |
13 | #include <wlr/backend/libinput.h> | 13 | #include <wlr/backend/libinput.h> |
diff --git a/sway/input/text_input.c b/sway/input/text_input.c index 58911c2d..580a9f54 100644 --- a/sway/input/text_input.c +++ b/sway/input/text_input.c | |||
@@ -2,7 +2,16 @@ | |||
2 | #include <stdlib.h> | 2 | #include <stdlib.h> |
3 | #include "log.h" | 3 | #include "log.h" |
4 | #include "sway/input/seat.h" | 4 | #include "sway/input/seat.h" |
5 | #include "sway/scene_descriptor.h" | ||
6 | #include "sway/tree/root.h" | ||
7 | #include "sway/tree/view.h" | ||
8 | #include "sway/output.h" | ||
5 | #include "sway/input/text_input.h" | 9 | #include "sway/input/text_input.h" |
10 | #include "sway/input/text_input_popup.h" | ||
11 | #include "sway/layers.h" | ||
12 | #include "sway/server.h" | ||
13 | |||
14 | static void input_popup_update(struct sway_input_popup *popup); | ||
6 | 15 | ||
7 | static struct sway_text_input *relay_get_focusable_text_input( | 16 | static struct sway_text_input *relay_get_focusable_text_input( |
8 | struct sway_input_method_relay *relay) { | 17 | struct sway_input_method_relay *relay) { |
@@ -59,11 +68,13 @@ static void handle_im_keyboard_grab_destroy(struct wl_listener *listener, void * | |||
59 | struct sway_input_method_relay *relay = wl_container_of(listener, relay, | 68 | struct sway_input_method_relay *relay = wl_container_of(listener, relay, |
60 | input_method_keyboard_grab_destroy); | 69 | input_method_keyboard_grab_destroy); |
61 | struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data; | 70 | struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data; |
71 | struct wlr_seat *wlr_seat = keyboard_grab->input_method->seat; | ||
62 | wl_list_remove(&relay->input_method_keyboard_grab_destroy.link); | 72 | wl_list_remove(&relay->input_method_keyboard_grab_destroy.link); |
63 | 73 | ||
64 | if (keyboard_grab->keyboard) { | 74 | if (keyboard_grab->keyboard) { |
65 | // send modifier state to original client | 75 | // send modifier state to original client |
66 | wlr_seat_keyboard_notify_modifiers(keyboard_grab->input_method->seat, | 76 | wlr_seat_set_keyboard(wlr_seat, keyboard_grab->keyboard); |
77 | wlr_seat_keyboard_notify_modifiers(wlr_seat, | ||
67 | &keyboard_grab->keyboard->modifiers); | 78 | &keyboard_grab->keyboard->modifiers); |
68 | } | 79 | } |
69 | } | 80 | } |
@@ -102,6 +113,10 @@ static void handle_im_destroy(struct wl_listener *listener, void *data) { | |||
102 | input_method_destroy); | 113 | input_method_destroy); |
103 | struct wlr_input_method_v2 *context = data; | 114 | struct wlr_input_method_v2 *context = data; |
104 | assert(context == relay->input_method); | 115 | assert(context == relay->input_method); |
116 | wl_list_remove(&relay->input_method_commit.link); | ||
117 | wl_list_remove(&relay->input_method_grab_keyboard.link); | ||
118 | wl_list_remove(&relay->input_method_destroy.link); | ||
119 | wl_list_remove(&relay->input_method_new_popup_surface.link); | ||
105 | relay->input_method = NULL; | 120 | relay->input_method = NULL; |
106 | struct sway_text_input *text_input = relay_get_focused_text_input(relay); | 121 | struct sway_text_input *text_input = relay_get_focused_text_input(relay); |
107 | if (text_input) { | 122 | if (text_input) { |
@@ -133,6 +148,11 @@ static void relay_send_im_state(struct sway_input_method_relay *relay, | |||
133 | input->current.content_type.hint, | 148 | input->current.content_type.hint, |
134 | input->current.content_type.purpose); | 149 | input->current.content_type.purpose); |
135 | } | 150 | } |
151 | struct sway_input_popup *popup; | ||
152 | wl_list_for_each(popup, &relay->input_popups, link) { | ||
153 | // send_text_input_rectangle is called in this function | ||
154 | input_popup_update(popup); | ||
155 | } | ||
136 | wlr_input_method_v2_send_done(input_method); | 156 | wlr_input_method_v2_send_done(input_method); |
137 | // TODO: pass intent, display popup size | 157 | // TODO: pass intent, display popup size |
138 | } | 158 | } |
@@ -255,6 +275,211 @@ static void relay_handle_text_input(struct wl_listener *listener, | |||
255 | sway_text_input_create(relay, wlr_text_input); | 275 | sway_text_input_create(relay, wlr_text_input); |
256 | } | 276 | } |
257 | 277 | ||
278 | static void input_popup_update(struct sway_input_popup *popup) { | ||
279 | struct sway_text_input *text_input = | ||
280 | relay_get_focused_text_input(popup->relay); | ||
281 | |||
282 | if (text_input == NULL || text_input->input->focused_surface == NULL) { | ||
283 | return; | ||
284 | } | ||
285 | |||
286 | if (popup->scene_tree != NULL) { | ||
287 | wlr_scene_node_destroy(&popup->scene_tree->node); | ||
288 | popup->scene_tree = NULL; | ||
289 | } | ||
290 | if (popup->desc.relative != NULL) { | ||
291 | wlr_scene_node_destroy(popup->desc.relative); | ||
292 | popup->desc.relative = NULL; | ||
293 | } | ||
294 | popup->desc.view = NULL; | ||
295 | |||
296 | if (!popup->popup_surface->surface->mapped) { | ||
297 | return; | ||
298 | } | ||
299 | |||
300 | bool cursor_rect = text_input->input->current.features | ||
301 | & WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE; | ||
302 | struct wlr_surface *focused_surface = text_input->input->focused_surface; | ||
303 | struct wlr_box cursor_area = text_input->input->current.cursor_rectangle; | ||
304 | |||
305 | struct wlr_box output_box; | ||
306 | struct wlr_box parent = {0}; | ||
307 | struct wlr_layer_surface_v1 *layer_surface = | ||
308 | wlr_layer_surface_v1_try_from_wlr_surface(focused_surface); | ||
309 | struct wlr_scene_tree *relative_parent; | ||
310 | |||
311 | struct wlr_box geo = {0}; | ||
312 | |||
313 | popup->scene_tree = wlr_scene_subsurface_tree_create(root->layers.popup, popup->popup_surface->surface); | ||
314 | if (layer_surface != NULL) { | ||
315 | struct sway_layer_surface *layer = | ||
316 | layer_surface->data; | ||
317 | if (layer == NULL) { | ||
318 | return; | ||
319 | } | ||
320 | |||
321 | relative_parent = layer->scene->tree; | ||
322 | struct wlr_output *output = layer->layer_surface->output; | ||
323 | wlr_output_layout_get_box(root->output_layout, output, &output_box); | ||
324 | int lx, ly; | ||
325 | wlr_scene_node_coords(&layer->tree->node, &lx, &ly); | ||
326 | parent.x = lx; | ||
327 | parent.y = ly; | ||
328 | popup->desc.view = NULL; | ||
329 | } else { | ||
330 | struct sway_view *view = view_from_wlr_surface(focused_surface); | ||
331 | relative_parent = view->scene_tree; | ||
332 | geo = view->geometry; | ||
333 | int lx, ly; | ||
334 | wlr_scene_node_coords(&view->scene_tree->node, &lx, &ly); | ||
335 | struct wlr_output *output = wlr_output_layout_output_at(root->output_layout, | ||
336 | view->container->pending.content_x + view->geometry.x, | ||
337 | view->container->pending.content_y + view->geometry.y); | ||
338 | wlr_output_layout_get_box(root->output_layout, output, &output_box); | ||
339 | parent.x = lx; | ||
340 | parent.y = ly; | ||
341 | |||
342 | parent.width = view->geometry.width; | ||
343 | parent.height = view->geometry.height; | ||
344 | popup->desc.view = view; | ||
345 | } | ||
346 | |||
347 | struct wlr_scene_tree *relative = wlr_scene_tree_create(relative_parent); | ||
348 | |||
349 | popup->desc.relative = &relative->node; | ||
350 | if (!scene_descriptor_assign(&popup->scene_tree->node, | ||
351 | SWAY_SCENE_DESC_POPUP, &popup->desc)) { | ||
352 | wlr_scene_node_destroy(&popup->scene_tree->node); | ||
353 | popup->scene_tree = NULL; | ||
354 | return; | ||
355 | } | ||
356 | |||
357 | if (!cursor_rect) { | ||
358 | cursor_area.x = 0; | ||
359 | cursor_area.y = 0; | ||
360 | cursor_area.width = parent.width; | ||
361 | cursor_area.height = parent.height; | ||
362 | } | ||
363 | |||
364 | int popup_width = popup->popup_surface->surface->current.width; | ||
365 | int popup_height = popup->popup_surface->surface->current.height; | ||
366 | int x1 = parent.x + cursor_area.x; | ||
367 | int x2 = parent.x + cursor_area.x + cursor_area.width; | ||
368 | int y1 = parent.y + cursor_area.y; | ||
369 | int y2 = parent.y + cursor_area.y + cursor_area.height; | ||
370 | int x = x1; | ||
371 | int y = y2; | ||
372 | |||
373 | int available_right = output_box.x + output_box.width - x1; | ||
374 | int available_left = x2 - output_box.x; | ||
375 | if (available_right < popup_width && available_left > available_right) { | ||
376 | x = x2 - popup_width; | ||
377 | } | ||
378 | |||
379 | int available_down = output_box.y + output_box.height - y2; | ||
380 | int available_up = y1 - output_box.y; | ||
381 | if (available_down < popup_height && available_up > available_down) { | ||
382 | y = y1 - popup_height; | ||
383 | } | ||
384 | |||
385 | wlr_scene_node_set_position(&relative->node, x - parent.x - geo.x, y - parent.y - geo.y); | ||
386 | if (cursor_rect) { | ||
387 | struct wlr_box box = { | ||
388 | .x = x1 - x, | ||
389 | .y = y1 - y, | ||
390 | .width = cursor_area.width, | ||
391 | .height = cursor_area.height, | ||
392 | }; | ||
393 | wlr_input_popup_surface_v2_send_text_input_rectangle( | ||
394 | popup->popup_surface, &box); | ||
395 | } | ||
396 | wlr_scene_node_set_position(&popup->scene_tree->node, x - geo.x, y - geo.y); | ||
397 | } | ||
398 | |||
399 | static void input_popup_set_focus(struct sway_input_popup *popup, | ||
400 | struct wlr_surface *surface) { | ||
401 | wl_list_remove(&popup->focused_surface_unmap.link); | ||
402 | |||
403 | if (surface == NULL) { | ||
404 | wl_list_init(&popup->focused_surface_unmap.link); | ||
405 | input_popup_update(popup); | ||
406 | return; | ||
407 | } | ||
408 | struct wlr_layer_surface_v1 *layer_surface = | ||
409 | wlr_layer_surface_v1_try_from_wlr_surface(surface); | ||
410 | if (layer_surface != NULL) { | ||
411 | wl_signal_add( | ||
412 | &layer_surface->surface->events.unmap, &popup->focused_surface_unmap); | ||
413 | input_popup_update(popup); | ||
414 | return; | ||
415 | } | ||
416 | |||
417 | struct sway_view *view = view_from_wlr_surface(surface); | ||
418 | wl_signal_add(&view->events.unmap, &popup->focused_surface_unmap); | ||
419 | } | ||
420 | |||
421 | static void handle_im_popup_destroy(struct wl_listener *listener, void *data) { | ||
422 | struct sway_input_popup *popup = | ||
423 | wl_container_of(listener, popup, popup_destroy); | ||
424 | wl_list_remove(&popup->focused_surface_unmap.link); | ||
425 | wl_list_remove(&popup->popup_surface_commit.link); | ||
426 | wl_list_remove(&popup->popup_destroy.link); | ||
427 | wl_list_remove(&popup->link); | ||
428 | |||
429 | free(popup); | ||
430 | } | ||
431 | |||
432 | static void handle_im_popup_surface_commit(struct wl_listener *listener, | ||
433 | void *data) { | ||
434 | struct sway_input_popup *popup = | ||
435 | wl_container_of(listener, popup, popup_surface_commit); | ||
436 | input_popup_update(popup); | ||
437 | } | ||
438 | |||
439 | static void handle_im_focused_surface_unmap( | ||
440 | struct wl_listener *listener, void *data) { | ||
441 | struct sway_input_popup *popup = | ||
442 | wl_container_of(listener, popup, focused_surface_unmap); | ||
443 | input_popup_update(popup); | ||
444 | } | ||
445 | |||
446 | static void handle_im_new_popup_surface(struct wl_listener *listener, | ||
447 | void *data) { | ||
448 | struct sway_input_method_relay *relay = wl_container_of(listener, relay, | ||
449 | input_method_new_popup_surface); | ||
450 | struct sway_input_popup *popup = calloc(1, sizeof(*popup)); | ||
451 | popup->relay = relay; | ||
452 | popup->popup_surface = data; | ||
453 | popup->popup_surface->data = popup; | ||
454 | |||
455 | wl_signal_add( | ||
456 | &popup->popup_surface->events.destroy, &popup->popup_destroy); | ||
457 | popup->popup_destroy.notify = handle_im_popup_destroy; | ||
458 | wl_signal_add(&popup->popup_surface->surface->events.commit, | ||
459 | &popup->popup_surface_commit); | ||
460 | popup->popup_surface_commit.notify = handle_im_popup_surface_commit; | ||
461 | wl_list_init(&popup->focused_surface_unmap.link); | ||
462 | popup->focused_surface_unmap.notify = handle_im_focused_surface_unmap; | ||
463 | |||
464 | struct sway_text_input *text_input = relay_get_focused_text_input(relay); | ||
465 | if (text_input != NULL) { | ||
466 | input_popup_set_focus(popup, text_input->input->focused_surface); | ||
467 | } else { | ||
468 | input_popup_set_focus(popup, NULL); | ||
469 | } | ||
470 | |||
471 | wl_list_insert(&relay->input_popups, &popup->link); | ||
472 | } | ||
473 | |||
474 | static void text_input_send_enter(struct sway_text_input *text_input, | ||
475 | struct wlr_surface *surface) { | ||
476 | wlr_text_input_v3_send_enter(text_input->input, surface); | ||
477 | struct sway_input_popup *popup; | ||
478 | wl_list_for_each(popup, &text_input->relay->input_popups, link) { | ||
479 | input_popup_set_focus(popup, surface); | ||
480 | } | ||
481 | } | ||
482 | |||
258 | static void relay_handle_input_method(struct wl_listener *listener, | 483 | static void relay_handle_input_method(struct wl_listener *listener, |
259 | void *data) { | 484 | void *data) { |
260 | struct sway_input_method_relay *relay = wl_container_of(listener, relay, | 485 | struct sway_input_method_relay *relay = wl_container_of(listener, relay, |
@@ -280,10 +505,13 @@ static void relay_handle_input_method(struct wl_listener *listener, | |||
280 | wl_signal_add(&relay->input_method->events.destroy, | 505 | wl_signal_add(&relay->input_method->events.destroy, |
281 | &relay->input_method_destroy); | 506 | &relay->input_method_destroy); |
282 | relay->input_method_destroy.notify = handle_im_destroy; | 507 | relay->input_method_destroy.notify = handle_im_destroy; |
508 | wl_signal_add(&relay->input_method->events.new_popup_surface, | ||
509 | &relay->input_method_new_popup_surface); | ||
510 | relay->input_method_new_popup_surface.notify = handle_im_new_popup_surface; | ||
283 | 511 | ||
284 | struct sway_text_input *text_input = relay_get_focusable_text_input(relay); | 512 | struct sway_text_input *text_input = relay_get_focusable_text_input(relay); |
285 | if (text_input) { | 513 | if (text_input) { |
286 | wlr_text_input_v3_send_enter(text_input->input, | 514 | text_input_send_enter(text_input, |
287 | text_input->pending_focused_surface); | 515 | text_input->pending_focused_surface); |
288 | text_input_set_pending_focused_surface(text_input, NULL); | 516 | text_input_set_pending_focused_surface(text_input, NULL); |
289 | } | 517 | } |
@@ -293,6 +521,7 @@ void sway_input_method_relay_init(struct sway_seat *seat, | |||
293 | struct sway_input_method_relay *relay) { | 521 | struct sway_input_method_relay *relay) { |
294 | relay->seat = seat; | 522 | relay->seat = seat; |
295 | wl_list_init(&relay->text_inputs); | 523 | wl_list_init(&relay->text_inputs); |
524 | wl_list_init(&relay->input_popups); | ||
296 | 525 | ||
297 | relay->text_input_new.notify = relay_handle_text_input; | 526 | relay->text_input_new.notify = relay_handle_text_input; |
298 | wl_signal_add(&server.text_input->events.text_input, | 527 | wl_signal_add(&server.text_input->events.text_input, |
diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 58356d4e..1ee39124 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include "log.h" | 11 | #include "log.h" |
12 | #include "sway/config.h" | 12 | #include "sway/config.h" |
13 | #include "sway/ipc-json.h" | 13 | #include "sway/ipc-json.h" |
14 | #include "sway/server.h" | ||
14 | #include "sway/tree/container.h" | 15 | #include "sway/tree/container.h" |
15 | #include "sway/tree/view.h" | 16 | #include "sway/tree/view.h" |
16 | #include "sway/tree/workspace.h" | 17 | #include "sway/tree/workspace.h" |
@@ -154,7 +155,7 @@ static json_object *ipc_json_output_mode_description( | |||
154 | return mode_object; | 155 | return mode_object; |
155 | } | 156 | } |
156 | 157 | ||
157 | #if HAVE_XWAYLAND | 158 | #if WLR_HAS_XWAYLAND |
158 | static const char *ipc_json_xwindow_type_description(struct sway_view *view) { | 159 | static const char *ipc_json_xwindow_type_description(struct sway_view *view) { |
159 | struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface; | 160 | struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface; |
160 | struct sway_xwayland *xwayland = &server.xwayland; | 161 | struct sway_xwayland *xwayland = &server.xwayland; |
@@ -288,6 +289,8 @@ static json_object *ipc_json_create_node(int id, const char* type, char *name, | |||
288 | json_object_object_add(object, "focus", focus); | 289 | json_object_object_add(object, "focus", focus); |
289 | json_object_object_add(object, "fullscreen_mode", json_object_new_int(0)); | 290 | json_object_object_add(object, "fullscreen_mode", json_object_new_int(0)); |
290 | json_object_object_add(object, "sticky", json_object_new_boolean(false)); | 291 | json_object_object_add(object, "sticky", json_object_new_boolean(false)); |
292 | json_object_object_add(object, "floating", NULL); | ||
293 | json_object_object_add(object, "scratchpad_state", NULL); | ||
291 | 294 | ||
292 | return object; | 295 | return object; |
293 | } | 296 | } |
@@ -631,7 +634,7 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object | |||
631 | json_object_new_string(ipc_json_content_type_description(content_type))); | 634 | json_object_new_string(ipc_json_content_type_description(content_type))); |
632 | } | 635 | } |
633 | 636 | ||
634 | #if HAVE_XWAYLAND | 637 | #if WLR_HAS_XWAYLAND |
635 | if (c->view->type == SWAY_VIEW_XWAYLAND) { | 638 | if (c->view->type == SWAY_VIEW_XWAYLAND) { |
636 | json_object_object_add(object, "window", | 639 | json_object_object_add(object, "window", |
637 | json_object_new_int(view_get_x11_window_id(c->view))); | 640 | json_object_new_int(view_get_x11_window_id(c->view))); |
@@ -675,7 +678,8 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object | |||
675 | static void ipc_json_describe_container(struct sway_container *c, json_object *object) { | 678 | static void ipc_json_describe_container(struct sway_container *c, json_object *object) { |
676 | json_object_object_add(object, "name", | 679 | json_object_object_add(object, "name", |
677 | c->title ? json_object_new_string(c->title) : NULL); | 680 | c->title ? json_object_new_string(c->title) : NULL); |
678 | if (container_is_floating(c)) { | 681 | bool floating = container_is_floating(c); |
682 | if (floating) { | ||
679 | json_object_object_add(object, "type", | 683 | json_object_object_add(object, "type", |
680 | json_object_new_string("floating_con")); | 684 | json_object_new_string("floating_con")); |
681 | } | 685 | } |
@@ -693,9 +697,17 @@ static void ipc_json_describe_container(struct sway_container *c, json_object *o | |||
693 | json_object_object_add(object, "urgent", json_object_new_boolean(urgent)); | 697 | json_object_object_add(object, "urgent", json_object_new_boolean(urgent)); |
694 | json_object_object_add(object, "sticky", json_object_new_boolean(c->is_sticky)); | 698 | json_object_object_add(object, "sticky", json_object_new_boolean(c->is_sticky)); |
695 | 699 | ||
700 | // sway doesn't track the floating reason, so we can't use "auto_on" or "user_off" | ||
701 | json_object_object_add(object, "floating", | ||
702 | json_object_new_string(floating ? "user_on" : "auto_off")); | ||
703 | |||
696 | json_object_object_add(object, "fullscreen_mode", | 704 | json_object_object_add(object, "fullscreen_mode", |
697 | json_object_new_int(c->pending.fullscreen_mode)); | 705 | json_object_new_int(c->pending.fullscreen_mode)); |
698 | 706 | ||
707 | // sway doesn't track if window was resized in scratchpad, so we can't use "changed" | ||
708 | json_object_object_add(object, "scratchpad_state", | ||
709 | json_object_new_string(!c->scratchpad ? "none" : "fresh")); | ||
710 | |||
699 | struct sway_node *parent = node_get_parent(&c->node); | 711 | struct sway_node *parent = node_get_parent(&c->node); |
700 | struct wlr_box parent_box = {0, 0, 0, 0}; | 712 | struct wlr_box parent_box = {0, 0, 0, 0}; |
701 | 713 | ||
@@ -1086,10 +1098,6 @@ json_object *ipc_json_describe_input(struct sway_input_device *device) { | |||
1086 | json_object_new_string(device->identifier)); | 1098 | json_object_new_string(device->identifier)); |
1087 | json_object_object_add(object, "name", | 1099 | json_object_object_add(object, "name", |
1088 | json_object_new_string(device->wlr_device->name)); | 1100 | json_object_new_string(device->wlr_device->name)); |
1089 | json_object_object_add(object, "vendor", | ||
1090 | json_object_new_int(device->wlr_device->vendor)); | ||
1091 | json_object_object_add(object, "product", | ||
1092 | json_object_new_int(device->wlr_device->product)); | ||
1093 | json_object_object_add(object, "type", | 1101 | json_object_object_add(object, "type", |
1094 | json_object_new_string( | 1102 | json_object_new_string( |
1095 | input_device_get_type(device))); | 1103 | input_device_get_type(device))); |
@@ -1143,6 +1151,10 @@ json_object *ipc_json_describe_input(struct sway_input_device *device) { | |||
1143 | libinput_dev = wlr_libinput_get_device_handle(device->wlr_device); | 1151 | libinput_dev = wlr_libinput_get_device_handle(device->wlr_device); |
1144 | json_object_object_add(object, "libinput", | 1152 | json_object_object_add(object, "libinput", |
1145 | describe_libinput_device(libinput_dev)); | 1153 | describe_libinput_device(libinput_dev)); |
1154 | json_object_object_add(object, "vendor", | ||
1155 | json_object_new_int(libinput_device_get_id_vendor(libinput_dev))); | ||
1156 | json_object_object_add(object, "product", | ||
1157 | json_object_new_int(libinput_device_get_id_product(libinput_dev))); | ||
1146 | } | 1158 | } |
1147 | #endif | 1159 | #endif |
1148 | 1160 | ||
diff --git a/sway/ipc-server.c b/sway/ipc-server.c index 9692a77f..7f353c0e 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c | |||
@@ -1,5 +1,4 @@ | |||
1 | // See https://i3wm.org/docs/ipc.html for protocol information | 1 | // See https://i3wm.org/docs/ipc.html for protocol information |
2 | #define _POSIX_C_SOURCE 200112L | ||
3 | #include <linux/input-event-codes.h> | 2 | #include <linux/input-event-codes.h> |
4 | #include <assert.h> | 3 | #include <assert.h> |
5 | #include <errno.h> | 4 | #include <errno.h> |
diff --git a/sway/lock.c b/sway/lock.c index 8ad9c3f6..289e8ca4 100644 --- a/sway/lock.c +++ b/sway/lock.c | |||
@@ -1,6 +1,6 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <assert.h> | 1 | #include <assert.h> |
3 | #include <wlr/types/wlr_scene.h> | 2 | #include <wlr/types/wlr_scene.h> |
3 | #include <wlr/types/wlr_session_lock_v1.h> | ||
4 | #include "log.h" | 4 | #include "log.h" |
5 | #include "sway/input/cursor.h" | 5 | #include "sway/input/cursor.h" |
6 | #include "sway/input/keyboard.h" | 6 | #include "sway/input/keyboard.h" |
diff --git a/sway/main.c b/sway/main.c index 73254dc2..1c4939aa 100644 --- a/sway/main.c +++ b/sway/main.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <getopt.h> | 1 | #include <getopt.h> |
3 | #include <pango/pangocairo.h> | 2 | #include <pango/pangocairo.h> |
4 | #include <signal.h> | 3 | #include <signal.h> |
diff --git a/sway/meson.build b/sway/meson.build index d937e425..a189fe9a 100644 --- a/sway/meson.build +++ b/sway/meson.build | |||
@@ -202,6 +202,7 @@ sway_sources = files( | |||
202 | 'commands/output/toggle.c', | 202 | 'commands/output/toggle.c', |
203 | 'commands/output/transform.c', | 203 | 'commands/output/transform.c', |
204 | 'commands/output/unplug.c', | 204 | 'commands/output/unplug.c', |
205 | 'commands/output/color_profile.c', | ||
205 | 206 | ||
206 | 'tree/arrange.c', | 207 | 'tree/arrange.c', |
207 | 'tree/container.c', | 208 | 'tree/container.c', |
@@ -231,7 +232,7 @@ sway_deps = [ | |||
231 | xcb_icccm, | 232 | xcb_icccm, |
232 | ] | 233 | ] |
233 | 234 | ||
234 | if have_xwayland | 235 | if wlroots_features['xwayland'] |
235 | sway_sources += 'desktop/xwayland.c' | 236 | sway_sources += 'desktop/xwayland.c' |
236 | endif | 237 | endif |
237 | 238 | ||
diff --git a/sway/server.c b/sway/server.c index cc20e89d..edbc1a4b 100644 --- a/sway/server.c +++ b/sway/server.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <assert.h> | 1 | #include <assert.h> |
3 | #include <stdbool.h> | 2 | #include <stdbool.h> |
4 | #include <stdlib.h> | 3 | #include <stdlib.h> |
@@ -8,24 +7,32 @@ | |||
8 | #include <wlr/backend/headless.h> | 7 | #include <wlr/backend/headless.h> |
9 | #include <wlr/backend/multi.h> | 8 | #include <wlr/backend/multi.h> |
10 | #include <wlr/config.h> | 9 | #include <wlr/config.h> |
10 | #include <wlr/render/allocator.h> | ||
11 | #include <wlr/render/wlr_renderer.h> | 11 | #include <wlr/render/wlr_renderer.h> |
12 | #include <wlr/types/wlr_compositor.h> | 12 | #include <wlr/types/wlr_compositor.h> |
13 | #include <wlr/types/wlr_content_type_v1.h> | 13 | #include <wlr/types/wlr_content_type_v1.h> |
14 | #include <wlr/types/wlr_cursor_shape_v1.h> | 14 | #include <wlr/types/wlr_cursor_shape_v1.h> |
15 | #include <wlr/types/wlr_data_control_v1.h> | 15 | #include <wlr/types/wlr_data_control_v1.h> |
16 | #include <wlr/types/wlr_data_device.h> | ||
16 | #include <wlr/types/wlr_drm.h> | 17 | #include <wlr/types/wlr_drm.h> |
17 | #include <wlr/types/wlr_export_dmabuf_v1.h> | 18 | #include <wlr/types/wlr_export_dmabuf_v1.h> |
19 | #include <wlr/types/wlr_ext_foreign_toplevel_list_v1.h> | ||
20 | #include <wlr/types/wlr_foreign_toplevel_management_v1.h> | ||
18 | #include <wlr/types/wlr_fractional_scale_v1.h> | 21 | #include <wlr/types/wlr_fractional_scale_v1.h> |
19 | #include <wlr/types/wlr_gamma_control_v1.h> | 22 | #include <wlr/types/wlr_gamma_control_v1.h> |
20 | #include <wlr/types/wlr_idle_notify_v1.h> | 23 | #include <wlr/types/wlr_idle_notify_v1.h> |
21 | #include <wlr/types/wlr_layer_shell_v1.h> | 24 | #include <wlr/types/wlr_layer_shell_v1.h> |
22 | #include <wlr/types/wlr_linux_dmabuf_v1.h> | 25 | #include <wlr/types/wlr_linux_dmabuf_v1.h> |
26 | #include <wlr/types/wlr_output_management_v1.h> | ||
27 | #include <wlr/types/wlr_output_power_management_v1.h> | ||
23 | #include <wlr/types/wlr_pointer_constraints_v1.h> | 28 | #include <wlr/types/wlr_pointer_constraints_v1.h> |
29 | #include <wlr/types/wlr_presentation_time.h> | ||
24 | #include <wlr/types/wlr_primary_selection_v1.h> | 30 | #include <wlr/types/wlr_primary_selection_v1.h> |
25 | #include <wlr/types/wlr_relative_pointer_v1.h> | 31 | #include <wlr/types/wlr_relative_pointer_v1.h> |
26 | #include <wlr/types/wlr_screencopy_v1.h> | 32 | #include <wlr/types/wlr_screencopy_v1.h> |
27 | #include <wlr/types/wlr_security_context_v1.h> | 33 | #include <wlr/types/wlr_security_context_v1.h> |
28 | #include <wlr/types/wlr_server_decoration.h> | 34 | #include <wlr/types/wlr_server_decoration.h> |
35 | #include <wlr/types/wlr_session_lock_v1.h> | ||
29 | #include <wlr/types/wlr_single_pixel_buffer_v1.h> | 36 | #include <wlr/types/wlr_single_pixel_buffer_v1.h> |
30 | #include <wlr/types/wlr_subcompositor.h> | 37 | #include <wlr/types/wlr_subcompositor.h> |
31 | #include <wlr/types/wlr_tablet_v2.h> | 38 | #include <wlr/types/wlr_tablet_v2.h> |
@@ -49,7 +56,7 @@ | |||
49 | #include "sway/input/cursor.h" | 56 | #include "sway/input/cursor.h" |
50 | #include "sway/tree/root.h" | 57 | #include "sway/tree/root.h" |
51 | 58 | ||
52 | #if HAVE_XWAYLAND | 59 | #if WLR_HAS_XWAYLAND |
53 | #include <wlr/xwayland/shell.h> | 60 | #include <wlr/xwayland/shell.h> |
54 | #include "sway/xwayland.h" | 61 | #include "sway/xwayland.h" |
55 | #endif | 62 | #endif |
@@ -58,8 +65,9 @@ | |||
58 | #include <wlr/types/wlr_drm_lease_v1.h> | 65 | #include <wlr/types/wlr_drm_lease_v1.h> |
59 | #endif | 66 | #endif |
60 | 67 | ||
61 | #define SWAY_XDG_SHELL_VERSION 2 | 68 | #define SWAY_XDG_SHELL_VERSION 5 |
62 | #define SWAY_LAYER_SHELL_VERSION 4 | 69 | #define SWAY_LAYER_SHELL_VERSION 4 |
70 | #define SWAY_FOREIGN_TOPLEVEL_LIST_VERSION 1 | ||
63 | 71 | ||
64 | bool allow_unsupported_gpu = false; | 72 | bool allow_unsupported_gpu = false; |
65 | 73 | ||
@@ -93,6 +101,7 @@ static bool is_privileged(const struct wl_global *global) { | |||
93 | global == server.output_manager_v1->global || | 101 | global == server.output_manager_v1->global || |
94 | global == server.output_power_manager_v1->global || | 102 | global == server.output_power_manager_v1->global || |
95 | global == server.input_method->global || | 103 | global == server.input_method->global || |
104 | global == server.foreign_toplevel_list->global || | ||
96 | global == server.foreign_toplevel_manager->global || | 105 | global == server.foreign_toplevel_manager->global || |
97 | global == server.data_control_manager_v1->global || | 106 | global == server.data_control_manager_v1->global || |
98 | global == server.screencopy_manager_v1->global || | 107 | global == server.screencopy_manager_v1->global || |
@@ -103,12 +112,14 @@ static bool is_privileged(const struct wl_global *global) { | |||
103 | global == server.session_lock.manager->global || | 112 | global == server.session_lock.manager->global || |
104 | global == server.input->keyboard_shortcuts_inhibit->global || | 113 | global == server.input->keyboard_shortcuts_inhibit->global || |
105 | global == server.input->virtual_keyboard->global || | 114 | global == server.input->virtual_keyboard->global || |
106 | global == server.input->virtual_pointer->global; | 115 | global == server.input->virtual_pointer->global || |
116 | global == server.input->transient_seat_manager->global || | ||
117 | global == server.xdg_output_manager_v1->global; | ||
107 | } | 118 | } |
108 | 119 | ||
109 | static bool filter_global(const struct wl_client *client, | 120 | static bool filter_global(const struct wl_client *client, |
110 | const struct wl_global *global, void *data) { | 121 | const struct wl_global *global, void *data) { |
111 | #if HAVE_XWAYLAND | 122 | #if WLR_HAS_XWAYLAND |
112 | struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland; | 123 | struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland; |
113 | if (xwayland && global == xwayland->shell_v1->global) { | 124 | if (xwayland && global == xwayland->shell_v1->global) { |
114 | return xwayland->server != NULL && client == xwayland->server->client; | 125 | return xwayland->server != NULL && client == xwayland->server->client; |
@@ -163,6 +174,45 @@ static void detect_proprietary(struct wlr_backend *backend, void *data) { | |||
163 | drmFreeVersion(version); | 174 | drmFreeVersion(version); |
164 | } | 175 | } |
165 | 176 | ||
177 | static void handle_renderer_lost(struct wl_listener *listener, void *data) { | ||
178 | struct sway_server *server = wl_container_of(listener, server, renderer_lost); | ||
179 | |||
180 | sway_log(SWAY_INFO, "Re-creating renderer after GPU reset"); | ||
181 | |||
182 | struct wlr_renderer *renderer = wlr_renderer_autocreate(server->backend); | ||
183 | if (renderer == NULL) { | ||
184 | sway_log(SWAY_ERROR, "Unable to create renderer"); | ||
185 | return; | ||
186 | } | ||
187 | |||
188 | struct wlr_allocator *allocator = | ||
189 | wlr_allocator_autocreate(server->backend, renderer); | ||
190 | if (allocator == NULL) { | ||
191 | sway_log(SWAY_ERROR, "Unable to create allocator"); | ||
192 | wlr_renderer_destroy(renderer); | ||
193 | return; | ||
194 | } | ||
195 | |||
196 | struct wlr_renderer *old_renderer = server->renderer; | ||
197 | struct wlr_allocator *old_allocator = server->allocator; | ||
198 | server->renderer = renderer; | ||
199 | server->allocator = allocator; | ||
200 | |||
201 | wl_list_remove(&server->renderer_lost.link); | ||
202 | wl_signal_add(&server->renderer->events.lost, &server->renderer_lost); | ||
203 | |||
204 | wlr_compositor_set_renderer(server->compositor, renderer); | ||
205 | |||
206 | for (int i = 0; i < root->outputs->length; ++i) { | ||
207 | struct sway_output *output = root->outputs->items[i]; | ||
208 | wlr_output_init_render(output->wlr_output, | ||
209 | server->allocator, server->renderer); | ||
210 | } | ||
211 | |||
212 | wlr_allocator_destroy(old_allocator); | ||
213 | wlr_renderer_destroy(old_renderer); | ||
214 | } | ||
215 | |||
166 | bool server_init(struct sway_server *server) { | 216 | bool server_init(struct sway_server *server) { |
167 | sway_log(SWAY_DEBUG, "Initializing Wayland server"); | 217 | sway_log(SWAY_DEBUG, "Initializing Wayland server"); |
168 | server->wl_display = wl_display_create(); | 218 | server->wl_display = wl_display_create(); |
@@ -186,15 +236,17 @@ bool server_init(struct sway_server *server) { | |||
186 | return false; | 236 | return false; |
187 | } | 237 | } |
188 | 238 | ||
239 | server->renderer_lost.notify = handle_renderer_lost; | ||
240 | wl_signal_add(&server->renderer->events.lost, &server->renderer_lost); | ||
241 | |||
189 | wlr_renderer_init_wl_shm(server->renderer, server->wl_display); | 242 | wlr_renderer_init_wl_shm(server->renderer, server->wl_display); |
190 | 243 | ||
191 | if (wlr_renderer_get_dmabuf_texture_formats(server->renderer) != NULL) { | 244 | if (wlr_renderer_get_texture_formats(server->renderer, WLR_BUFFER_CAP_DMABUF) != NULL) { |
192 | server->linux_dmabuf_v1 = wlr_linux_dmabuf_v1_create_with_renderer( | 245 | server->linux_dmabuf_v1 = wlr_linux_dmabuf_v1_create_with_renderer( |
193 | server->wl_display, 4, server->renderer); | 246 | server->wl_display, 4, server->renderer); |
194 | } | 247 | if (debug.legacy_wl_drm) { |
195 | if (wlr_renderer_get_dmabuf_texture_formats(server->renderer) != NULL && | 248 | wlr_drm_create(server->wl_display, server->renderer); |
196 | debug.legacy_wl_drm) { | 249 | } |
197 | wlr_drm_create(server->wl_display, server->renderer); | ||
198 | } | 250 | } |
199 | 251 | ||
200 | server->allocator = wlr_allocator_autocreate(server->backend, | 252 | server->allocator = wlr_allocator_autocreate(server->backend, |
@@ -224,7 +276,8 @@ bool server_init(struct sway_server *server) { | |||
224 | wl_signal_add(&root->output_layout->events.change, | 276 | wl_signal_add(&root->output_layout->events.change, |
225 | &server->output_layout_change); | 277 | &server->output_layout_change); |
226 | 278 | ||
227 | wlr_xdg_output_manager_v1_create(server->wl_display, root->output_layout); | 279 | server->xdg_output_manager_v1 = |
280 | wlr_xdg_output_manager_v1_create(server->wl_display, root->output_layout); | ||
228 | 281 | ||
229 | server->idle_notifier_v1 = wlr_idle_notifier_v1_create(server->wl_display); | 282 | server->idle_notifier_v1 = wlr_idle_notifier_v1_create(server->wl_display); |
230 | sway_idle_inhibit_manager_v1_init(); | 283 | sway_idle_inhibit_manager_v1_init(); |
@@ -289,6 +342,8 @@ bool server_init(struct sway_server *server) { | |||
289 | &server->output_power_manager_set_mode); | 342 | &server->output_power_manager_set_mode); |
290 | server->input_method = wlr_input_method_manager_v2_create(server->wl_display); | 343 | server->input_method = wlr_input_method_manager_v2_create(server->wl_display); |
291 | server->text_input = wlr_text_input_manager_v3_create(server->wl_display); | 344 | server->text_input = wlr_text_input_manager_v3_create(server->wl_display); |
345 | server->foreign_toplevel_list = | ||
346 | wlr_ext_foreign_toplevel_list_v1_create(server->wl_display, SWAY_FOREIGN_TOPLEVEL_LIST_VERSION); | ||
292 | server->foreign_toplevel_manager = | 347 | server->foreign_toplevel_manager = |
293 | wlr_foreign_toplevel_manager_v1_create(server->wl_display); | 348 | wlr_foreign_toplevel_manager_v1_create(server->wl_display); |
294 | 349 | ||
@@ -384,16 +439,17 @@ bool server_init(struct sway_server *server) { | |||
384 | 439 | ||
385 | void server_fini(struct sway_server *server) { | 440 | void server_fini(struct sway_server *server) { |
386 | // TODO: free sway-specific resources | 441 | // TODO: free sway-specific resources |
387 | #if HAVE_XWAYLAND | 442 | #if WLR_HAS_XWAYLAND |
388 | wlr_xwayland_destroy(server->xwayland.wlr_xwayland); | 443 | wlr_xwayland_destroy(server->xwayland.wlr_xwayland); |
389 | #endif | 444 | #endif |
390 | wl_display_destroy_clients(server->wl_display); | 445 | wl_display_destroy_clients(server->wl_display); |
446 | wlr_backend_destroy(server->backend); | ||
391 | wl_display_destroy(server->wl_display); | 447 | wl_display_destroy(server->wl_display); |
392 | list_free(server->dirty_nodes); | 448 | list_free(server->dirty_nodes); |
393 | } | 449 | } |
394 | 450 | ||
395 | bool server_start(struct sway_server *server) { | 451 | bool server_start(struct sway_server *server) { |
396 | #if HAVE_XWAYLAND | 452 | #if WLR_HAS_XWAYLAND |
397 | if (config->xwayland != XWAYLAND_MODE_DISABLED) { | 453 | if (config->xwayland != XWAYLAND_MODE_DISABLED) { |
398 | sway_log(SWAY_DEBUG, "Initializing Xwayland (lazy=%d)", | 454 | sway_log(SWAY_DEBUG, "Initializing Xwayland (lazy=%d)", |
399 | config->xwayland == XWAYLAND_MODE_LAZY); | 455 | config->xwayland == XWAYLAND_MODE_LAZY); |
diff --git a/sway/sway-ipc.7.scd b/sway/sway-ipc.7.scd index f4a5ccff..2f697248 100644 --- a/sway/sway-ipc.7.scd +++ b/sway/sway-ipc.7.scd | |||
@@ -376,6 +376,12 @@ node and will have the following properties: | |||
376 | : integer | 376 | : integer |
377 | : (Only containers and views) The fullscreen mode of the node. 0 means none, 1 means | 377 | : (Only containers and views) The fullscreen mode of the node. 0 means none, 1 means |
378 | full workspace, and 2 means global fullscreen | 378 | full workspace, and 2 means global fullscreen |
379 | |- floating | ||
380 | : string | ||
381 | : Floating state of container. Can be either "auto_off" or "user_on" | ||
382 | |- scratchpad_state | ||
383 | : string | ||
384 | : Whether the window is in the scratchpad. Can be either "none" or "fresh" | ||
379 | |- app_id | 385 | |- app_id |
380 | : string | 386 | : string |
381 | : (Only views) For an xdg-shell view, the name of the application, if set. | 387 | : (Only views) For an xdg-shell view, the name of the application, if set. |
@@ -1040,7 +1046,7 @@ An object with a single string property containing the contents of the config | |||
1040 | *Example Reply:* | 1046 | *Example Reply:* |
1041 | ``` | 1047 | ``` |
1042 | { | 1048 | { |
1043 | "config": "set $mod Mod4\nbindsym $mod+q exit\n" | 1049 | "config": "set $mod Mod4\\nbindsym $mod+q exit\\n" |
1044 | } | 1050 | } |
1045 | ``` | 1051 | ``` |
1046 | 1052 | ||
diff --git a/sway/sway-output.5.scd b/sway/sway-output.5.scd index 028cb7ab..6d7c0860 100644 --- a/sway/sway-output.5.scd +++ b/sway/sway-output.5.scd | |||
@@ -72,13 +72,11 @@ must be separated by one space. For example: | |||
72 | 72 | ||
73 | *output* <name> scale <factor> | 73 | *output* <name> scale <factor> |
74 | Scales the specified output by the specified scale _factor_. An integer is | 74 | Scales the specified output by the specified scale _factor_. An integer is |
75 | recommended, but fractional values are also supported. If a fractional | 75 | recommended, but fractional values are also supported. You may be better |
76 | value are specified, be warned that it is not possible to faithfully | 76 | served by setting an integer scale factor and adjusting the font size of |
77 | represent the contents of your windows - they will be rendered at the next | 77 | your applications to taste. HiDPI isn't supported with Xwayland clients |
78 | highest integer scale factor and downscaled. You may be better served by | 78 | (windows will blur). A fractional scale may be slightly adjusted to match |
79 | setting an integer scale factor and adjusting the font size of your | 79 | requirements of the protocol. |
80 | applications to taste. HiDPI isn't supported with Xwayland clients (windows | ||
81 | will blur). | ||
82 | 80 | ||
83 | *output* <name> scale_filter linear|nearest|smart | 81 | *output* <name> scale_filter linear|nearest|smart |
84 | Indicates how to scale application buffers that are rendered at a scale | 82 | Indicates how to scale application buffers that are rendered at a scale |
@@ -180,6 +178,18 @@ must be separated by one space. For example: | |||
180 | updated to work with different bit depths. This command is experimental, | 178 | updated to work with different bit depths. This command is experimental, |
181 | and may be removed or changed in the future. | 179 | and may be removed or changed in the future. |
182 | 180 | ||
181 | *output* <name> color_profile srgb|[icc <file>] | ||
182 | Sets the color profile for an output. The default is _srgb_. <file> should be a | ||
183 | path to a display ICC profile. | ||
184 | |||
185 | Not all renderers support this feature; currently it only works with the | ||
186 | the Vulkan renderer. Even where supported, the application of the color | ||
187 | profile may be inaccurate. | ||
188 | |||
189 | This command is experimental, and may be removed or changed in the future. It | ||
190 | may have no effect or produce unexpected output when used together with future | ||
191 | HDR support features. | ||
192 | |||
183 | # SEE ALSO | 193 | # SEE ALSO |
184 | 194 | ||
185 | *sway*(5) *sway-input*(5) | 195 | *sway*(5) *sway-input*(5) |
diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 7e58b528..9f823947 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd | |||
@@ -400,6 +400,12 @@ runtime. | |||
400 | only be available for that group. By default, if you overwrite a binding, | 400 | only be available for that group. By default, if you overwrite a binding, |
401 | swaynag will give you a warning. To silence this, use the _--no-warn_ flag. | 401 | swaynag will give you a warning. To silence this, use the _--no-warn_ flag. |
402 | 402 | ||
403 | For specifying modifier keys, you can use the XKB modifier names _Shift_, | ||
404 | _Lock_ (for Caps Lock), _Control_, _Mod1_ (for Alt), _Mod2_ (for Num Lock), | ||
405 | _Mod3_ (for XKB modifier Mod3), _Mod4_ (for the Logo key), and _Mod5_ (for | ||
406 | AltGr). In addition, you can use the aliases _Ctrl_ (for Control), _Alt_ | ||
407 | (for Alt), and _Super_ (for the Logo key). | ||
408 | |||
403 | Unless the flag _--locked_ is set, the command will not be run when a | 409 | Unless the flag _--locked_ is set, the command will not be run when a |
404 | screen locking program is active. If there is a matching binding with | 410 | screen locking program is active. If there is a matching binding with |
405 | and without _--locked_, the one with will be preferred when locked and the | 411 | and without _--locked_, the one with will be preferred when locked and the |
diff --git a/sway/sway_text_node.c b/sway/sway_text_node.c index b9a77d94..4b7ee999 100644 --- a/sway/sway_text_node.c +++ b/sway/sway_text_node.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <drm_fourcc.h> | 1 | #include <drm_fourcc.h> |
3 | #include <stdio.h> | 2 | #include <stdio.h> |
4 | #include <stdlib.h> | 3 | #include <stdlib.h> |
@@ -58,11 +57,11 @@ struct text_buffer { | |||
58 | }; | 57 | }; |
59 | 58 | ||
60 | static int get_text_width(struct sway_text_node *props) { | 59 | static int get_text_width(struct sway_text_node *props) { |
61 | if (props->max_width) { | 60 | int width = props->width; |
62 | return MIN(props->max_width, props->width); | 61 | if (props->max_width >= 0) { |
62 | width = MIN(width, props->max_width); | ||
63 | } | 63 | } |
64 | 64 | return MAX(width, 0); | |
65 | return props->width; | ||
66 | } | 65 | } |
67 | 66 | ||
68 | static void update_source_box(struct text_buffer *buffer) { | 67 | static void update_source_box(struct text_buffer *buffer) { |
@@ -82,6 +81,11 @@ static void render_backing_buffer(struct text_buffer *buffer) { | |||
82 | return; | 81 | return; |
83 | } | 82 | } |
84 | 83 | ||
84 | if (buffer->props.max_width == 0) { | ||
85 | wlr_scene_buffer_set_buffer(buffer->buffer_node, NULL); | ||
86 | return; | ||
87 | } | ||
88 | |||
85 | float scale = buffer->scale; | 89 | float scale = buffer->scale; |
86 | int width = ceil(buffer->props.width * scale); | 90 | int width = ceil(buffer->props.width * scale); |
87 | int height = ceil(buffer->props.height * scale); | 91 | int height = ceil(buffer->props.height * scale); |
@@ -237,6 +241,7 @@ struct sway_text_node *sway_text_node_create(struct wlr_scene_tree *parent, | |||
237 | 241 | ||
238 | buffer->buffer_node = node; | 242 | buffer->buffer_node = node; |
239 | buffer->props.node = &node->node; | 243 | buffer->props.node = &node->node; |
244 | buffer->props.max_width = -1; | ||
240 | buffer->text = strdup(text); | 245 | buffer->text = strdup(text); |
241 | if (!buffer->text) { | 246 | if (!buffer->text) { |
242 | free(buffer); | 247 | free(buffer); |
diff --git a/sway/swaynag.c b/sway/swaynag.c index 6031174d..bc5e23ea 100644 --- a/sway/swaynag.c +++ b/sway/swaynag.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <signal.h> | 1 | #include <signal.h> |
3 | #include <stdbool.h> | 2 | #include <stdbool.h> |
4 | #include <stdlib.h> | 3 | #include <stdlib.h> |
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c index af925d05..d4003fe6 100644 --- a/sway/tree/arrange.c +++ b/sway/tree/arrange.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <ctype.h> | 1 | #include <ctype.h> |
3 | #include <stdbool.h> | 2 | #include <stdbool.h> |
4 | #include <stdlib.h> | 3 | #include <stdlib.h> |
diff --git a/sway/tree/container.c b/sway/tree/container.c index 30cb97ba..80ef34fe 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -1,9 +1,9 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <assert.h> | 1 | #include <assert.h> |
3 | #include <drm_fourcc.h> | 2 | #include <drm_fourcc.h> |
4 | #include <stdint.h> | 3 | #include <stdint.h> |
5 | #include <stdlib.h> | 4 | #include <stdlib.h> |
6 | #include <wayland-server-core.h> | 5 | #include <wayland-server-core.h> |
6 | #include <wlr/types/wlr_foreign_toplevel_management_v1.h> | ||
7 | #include <wlr/types/wlr_linux_dmabuf_v1.h> | 7 | #include <wlr/types/wlr_linux_dmabuf_v1.h> |
8 | #include <wlr/types/wlr_output_layout.h> | 8 | #include <wlr/types/wlr_output_layout.h> |
9 | #include <wlr/types/wlr_subcompositor.h> | 9 | #include <wlr/types/wlr_subcompositor.h> |
@@ -352,6 +352,8 @@ void container_arrange_title_bar(struct sway_container *con) { | |||
352 | 352 | ||
353 | int alloc_width = MIN((int)node->width, | 353 | int alloc_width = MIN((int)node->width, |
354 | width - h_padding - config->titlebar_h_padding); | 354 | width - h_padding - config->titlebar_h_padding); |
355 | alloc_width = MAX(alloc_width, 0); | ||
356 | |||
355 | sway_text_node_set_max_width(node, alloc_width); | 357 | sway_text_node_set_max_width(node, alloc_width); |
356 | wlr_scene_node_set_position(node->node, | 358 | wlr_scene_node_set_position(node->node, |
357 | h_padding, (height - node->height) >> 1); | 359 | h_padding, (height - node->height) >> 1); |
@@ -376,6 +378,8 @@ void container_arrange_title_bar(struct sway_container *con) { | |||
376 | 378 | ||
377 | int alloc_width = MIN((int) node->width, | 379 | int alloc_width = MIN((int) node->width, |
378 | width - h_padding - config->titlebar_h_padding); | 380 | width - h_padding - config->titlebar_h_padding); |
381 | alloc_width = MAX(alloc_width, 0); | ||
382 | |||
379 | sway_text_node_set_max_width(node, alloc_width); | 383 | sway_text_node_set_max_width(node, alloc_width); |
380 | wlr_scene_node_set_position(node->node, | 384 | wlr_scene_node_set_position(node->node, |
381 | h_padding, (height - node->height) >> 1); | 385 | h_padding, (height - node->height) >> 1); |
diff --git a/sway/tree/node.c b/sway/tree/node.c index 213cf0a6..7aaf9762 100644 --- a/sway/tree/node.c +++ b/sway/tree/node.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include "sway/output.h" | 1 | #include "sway/output.h" |
3 | #include "sway/server.h" | 2 | #include "sway/server.h" |
4 | #include "sway/tree/container.h" | 3 | #include "sway/tree/container.h" |
diff --git a/sway/tree/output.c b/sway/tree/output.c index cd7bf0c2..6c8dd6dc 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <assert.h> | 1 | #include <assert.h> |
3 | #include <ctype.h> | 2 | #include <ctype.h> |
4 | #include <string.h> | 3 | #include <string.h> |
@@ -280,6 +279,7 @@ void output_destroy(struct sway_output *output) { | |||
280 | list_free(output->workspaces); | 279 | list_free(output->workspaces); |
281 | list_free(output->current.workspaces); | 280 | list_free(output->current.workspaces); |
282 | wl_event_source_remove(output->repaint_timer); | 281 | wl_event_source_remove(output->repaint_timer); |
282 | wlr_color_transform_unref(output->color_transform); | ||
283 | free(output); | 283 | free(output); |
284 | } | 284 | } |
285 | 285 | ||
diff --git a/sway/tree/root.c b/sway/tree/root.c index e9cea5e2..20fcfa59 100644 --- a/sway/tree/root.c +++ b/sway/tree/root.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <stdbool.h> | 1 | #include <stdbool.h> |
3 | #include <stdlib.h> | 2 | #include <stdlib.h> |
4 | #include <string.h> | 3 | #include <string.h> |
@@ -54,7 +53,7 @@ struct sway_root *root_create(struct wl_display *wl_display) { | |||
54 | root->layers.shell_top = alloc_scene_tree(root->layer_tree, &failed); | 53 | root->layers.shell_top = alloc_scene_tree(root->layer_tree, &failed); |
55 | root->layers.fullscreen = alloc_scene_tree(root->layer_tree, &failed); | 54 | root->layers.fullscreen = alloc_scene_tree(root->layer_tree, &failed); |
56 | root->layers.fullscreen_global = alloc_scene_tree(root->layer_tree, &failed); | 55 | root->layers.fullscreen_global = alloc_scene_tree(root->layer_tree, &failed); |
57 | #if HAVE_XWAYLAND | 56 | #if WLR_HAS_XWAYLAND |
58 | root->layers.unmanaged = alloc_scene_tree(root->layer_tree, &failed); | 57 | root->layers.unmanaged = alloc_scene_tree(root->layer_tree, &failed); |
59 | #endif | 58 | #endif |
60 | root->layers.shell_overlay = alloc_scene_tree(root->layer_tree, &failed); | 59 | root->layers.shell_overlay = alloc_scene_tree(root->layer_tree, &failed); |
diff --git a/sway/tree/view.c b/sway/tree/view.c index d6984178..086a8ff3 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -1,15 +1,16 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <stdlib.h> | 1 | #include <stdlib.h> |
3 | #include <strings.h> | 2 | #include <strings.h> |
4 | #include <wayland-server-core.h> | 3 | #include <wayland-server-core.h> |
4 | #include <wlr/config.h> | ||
5 | #include <wlr/render/wlr_renderer.h> | 5 | #include <wlr/render/wlr_renderer.h> |
6 | #include <wlr/types/wlr_buffer.h> | 6 | #include <wlr/types/wlr_buffer.h> |
7 | #include <wlr/types/wlr_ext_foreign_toplevel_list_v1.h> | ||
8 | #include <wlr/types/wlr_foreign_toplevel_management_v1.h> | ||
7 | #include <wlr/types/wlr_output_layout.h> | 9 | #include <wlr/types/wlr_output_layout.h> |
8 | #include <wlr/types/wlr_server_decoration.h> | 10 | #include <wlr/types/wlr_server_decoration.h> |
9 | #include <wlr/types/wlr_subcompositor.h> | 11 | #include <wlr/types/wlr_subcompositor.h> |
10 | #include <wlr/types/wlr_xdg_decoration_v1.h> | 12 | #include <wlr/types/wlr_xdg_decoration_v1.h> |
11 | #include "config.h" | 13 | #if WLR_HAS_XWAYLAND |
12 | #if HAVE_XWAYLAND | ||
13 | #include <wlr/xwayland.h> | 14 | #include <wlr/xwayland.h> |
14 | #endif | 15 | #endif |
15 | #include "list.h" | 16 | #include "list.h" |
@@ -125,7 +126,7 @@ const char *view_get_instance(struct sway_view *view) { | |||
125 | } | 126 | } |
126 | return NULL; | 127 | return NULL; |
127 | } | 128 | } |
128 | #if HAVE_XWAYLAND | 129 | #if WLR_HAS_XWAYLAND |
129 | uint32_t view_get_x11_window_id(struct sway_view *view) { | 130 | uint32_t view_get_x11_window_id(struct sway_view *view) { |
130 | if (view->impl->get_int_prop) { | 131 | if (view->impl->get_int_prop) { |
131 | return view->impl->get_int_prop(view, VIEW_PROP_X11_WINDOW_ID); | 132 | return view->impl->get_int_prop(view, VIEW_PROP_X11_WINDOW_ID); |
@@ -158,7 +159,7 @@ const char *view_get_shell(struct sway_view *view) { | |||
158 | switch(view->type) { | 159 | switch(view->type) { |
159 | case SWAY_VIEW_XDG_SHELL: | 160 | case SWAY_VIEW_XDG_SHELL: |
160 | return "xdg_shell"; | 161 | return "xdg_shell"; |
161 | #if HAVE_XWAYLAND | 162 | #if WLR_HAS_XWAYLAND |
162 | case SWAY_VIEW_XWAYLAND: | 163 | case SWAY_VIEW_XWAYLAND: |
163 | return "xwayland"; | 164 | return "xwayland"; |
164 | #endif | 165 | #endif |
@@ -172,9 +173,9 @@ void view_get_constraints(struct sway_view *view, double *min_width, | |||
172 | view->impl->get_constraints(view, | 173 | view->impl->get_constraints(view, |
173 | min_width, max_width, min_height, max_height); | 174 | min_width, max_width, min_height, max_height); |
174 | } else { | 175 | } else { |
175 | *min_width = DBL_MIN; | 176 | *min_width = 1; |
176 | *max_width = DBL_MAX; | 177 | *max_width = DBL_MAX; |
177 | *min_height = DBL_MIN; | 178 | *min_height = 1; |
178 | *max_height = DBL_MAX; | 179 | *max_height = DBL_MAX; |
179 | } | 180 | } |
180 | } | 181 | } |
@@ -364,8 +365,8 @@ void view_autoconfigure(struct sway_view *view) { | |||
364 | 365 | ||
365 | con->pending.content_x = x; | 366 | con->pending.content_x = x; |
366 | con->pending.content_y = y; | 367 | con->pending.content_y = y; |
367 | con->pending.content_width = width; | 368 | con->pending.content_width = fmax(width, 1); |
368 | con->pending.content_height = height; | 369 | con->pending.content_height = fmax(height, 1); |
369 | } | 370 | } |
370 | 371 | ||
371 | void view_set_activated(struct sway_view *view, bool activated) { | 372 | void view_set_activated(struct sway_view *view, bool activated) { |
@@ -410,6 +411,12 @@ void view_request_activate(struct sway_view *view, struct sway_seat *seat) { | |||
410 | transaction_commit_dirty(); | 411 | transaction_commit_dirty(); |
411 | } | 412 | } |
412 | 413 | ||
414 | void view_request_urgent(struct sway_view *view) { | ||
415 | if (config->focus_on_window_activation != FOWA_NONE) { | ||
416 | view_set_urgent(view, true); | ||
417 | } | ||
418 | } | ||
419 | |||
413 | void view_set_csd_from_server(struct sway_view *view, bool enabled) { | 420 | void view_set_csd_from_server(struct sway_view *view, bool enabled) { |
414 | sway_log(SWAY_DEBUG, "Telling view %p to set CSD to %i", view, enabled); | 421 | sway_log(SWAY_DEBUG, "Telling view %p to set CSD to %i", view, enabled); |
415 | if (view->xdg_decoration) { | 422 | if (view->xdg_decoration) { |
@@ -492,7 +499,7 @@ void view_execute_criteria(struct sway_view *view) { | |||
492 | static void view_populate_pid(struct sway_view *view) { | 499 | static void view_populate_pid(struct sway_view *view) { |
493 | pid_t pid; | 500 | pid_t pid; |
494 | switch (view->type) { | 501 | switch (view->type) { |
495 | #if HAVE_XWAYLAND | 502 | #if WLR_HAS_XWAYLAND |
496 | case SWAY_VIEW_XWAYLAND:; | 503 | case SWAY_VIEW_XWAYLAND:; |
497 | struct wlr_xwayland_surface *surf = | 504 | struct wlr_xwayland_surface *surf = |
498 | wlr_xwayland_surface_try_from_wlr_surface(view->surface); | 505 | wlr_xwayland_surface_try_from_wlr_surface(view->surface); |
@@ -582,6 +589,14 @@ static struct sway_workspace *select_workspace(struct sway_view *view) { | |||
582 | return NULL; | 589 | return NULL; |
583 | } | 590 | } |
584 | 591 | ||
592 | static void update_ext_foreign_toplevel(struct sway_view *view) { | ||
593 | struct wlr_ext_foreign_toplevel_handle_v1_state toplevel_state = { | ||
594 | .app_id = view_get_app_id(view), | ||
595 | .title = view_get_title(view), | ||
596 | }; | ||
597 | wlr_ext_foreign_toplevel_handle_v1_update_state(view->ext_foreign_toplevel, &toplevel_state); | ||
598 | } | ||
599 | |||
585 | static bool should_focus(struct sway_view *view) { | 600 | static bool should_focus(struct sway_view *view) { |
586 | struct sway_seat *seat = input_manager_current_seat(); | 601 | struct sway_seat *seat = input_manager_current_seat(); |
587 | struct sway_container *prev_con = seat_get_focused_container(seat); | 602 | struct sway_container *prev_con = seat_get_focused_container(seat); |
@@ -751,6 +766,13 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, | |||
751 | } | 766 | } |
752 | } | 767 | } |
753 | 768 | ||
769 | struct wlr_ext_foreign_toplevel_handle_v1_state foreign_toplevel_state = { | ||
770 | .app_id = view_get_app_id(view), | ||
771 | .title = view_get_title(view), | ||
772 | }; | ||
773 | view->ext_foreign_toplevel = | ||
774 | wlr_ext_foreign_toplevel_handle_v1_create(server.foreign_toplevel_list, &foreign_toplevel_state); | ||
775 | |||
754 | view->foreign_toplevel = | 776 | view->foreign_toplevel = |
755 | wlr_foreign_toplevel_handle_v1_create(server.foreign_toplevel_manager); | 777 | wlr_foreign_toplevel_handle_v1_create(server.foreign_toplevel_manager); |
756 | view->foreign_activate_request.notify = handle_foreign_activate_request; | 778 | view->foreign_activate_request.notify = handle_foreign_activate_request; |
@@ -816,7 +838,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, | |||
816 | 838 | ||
817 | bool set_focus = should_focus(view); | 839 | bool set_focus = should_focus(view); |
818 | 840 | ||
819 | #if HAVE_XWAYLAND | 841 | #if WLR_HAS_XWAYLAND |
820 | struct wlr_xwayland_surface *xsurface; | 842 | struct wlr_xwayland_surface *xsurface; |
821 | if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(wlr_surface))) { | 843 | if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(wlr_surface))) { |
822 | set_focus &= wlr_xwayland_icccm_input_model(xsurface) != | 844 | set_focus &= wlr_xwayland_icccm_input_model(xsurface) != |
@@ -828,6 +850,10 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, | |||
828 | input_manager_set_focus(&view->container->node); | 850 | input_manager_set_focus(&view->container->node); |
829 | } | 851 | } |
830 | 852 | ||
853 | if (view->ext_foreign_toplevel) { | ||
854 | update_ext_foreign_toplevel(view); | ||
855 | } | ||
856 | |||
831 | const char *app_id; | 857 | const char *app_id; |
832 | const char *class; | 858 | const char *class; |
833 | if ((app_id = view_get_app_id(view)) != NULL) { | 859 | if ((app_id = view_get_app_id(view)) != NULL) { |
@@ -847,6 +873,11 @@ void view_unmap(struct sway_view *view) { | |||
847 | view->urgent_timer = NULL; | 873 | view->urgent_timer = NULL; |
848 | } | 874 | } |
849 | 875 | ||
876 | if (view->ext_foreign_toplevel) { | ||
877 | wlr_ext_foreign_toplevel_handle_v1_destroy(view->ext_foreign_toplevel); | ||
878 | view->ext_foreign_toplevel = NULL; | ||
879 | } | ||
880 | |||
850 | if (view->foreign_toplevel) { | 881 | if (view->foreign_toplevel) { |
851 | wlr_foreign_toplevel_handle_v1_destroy(view->foreign_toplevel); | 882 | wlr_foreign_toplevel_handle_v1_destroy(view->foreign_toplevel); |
852 | view->foreign_toplevel = NULL; | 883 | view->foreign_toplevel = NULL; |
@@ -896,11 +927,14 @@ void view_update_size(struct sway_view *view) { | |||
896 | void view_center_and_clip_surface(struct sway_view *view) { | 927 | void view_center_and_clip_surface(struct sway_view *view) { |
897 | struct sway_container *con = view->container; | 928 | struct sway_container *con = view->container; |
898 | 929 | ||
930 | bool clip_to_geometry = true; | ||
931 | |||
899 | if (container_is_floating(con)) { | 932 | if (container_is_floating(con)) { |
900 | // We always center the current coordinates rather than the next, as the | 933 | // We always center the current coordinates rather than the next, as the |
901 | // geometry immediately affects the currently active rendering. | 934 | // geometry immediately affects the currently active rendering. |
902 | int x = (int) fmax(0, (con->current.content_width - view->geometry.width) / 2); | 935 | int x = (int) fmax(0, (con->current.content_width - view->geometry.width) / 2); |
903 | int y = (int) fmax(0, (con->current.content_height - view->geometry.height) / 2); | 936 | int y = (int) fmax(0, (con->current.content_height - view->geometry.height) / 2); |
937 | clip_to_geometry = !view->using_csd; | ||
904 | 938 | ||
905 | wlr_scene_node_set_position(&view->content_tree->node, x, y); | 939 | wlr_scene_node_set_position(&view->content_tree->node, x, y); |
906 | } else { | 940 | } else { |
@@ -909,12 +943,16 @@ void view_center_and_clip_surface(struct sway_view *view) { | |||
909 | 943 | ||
910 | // only make sure to clip the content if there is content to clip | 944 | // only make sure to clip the content if there is content to clip |
911 | if (!wl_list_empty(&con->view->content_tree->children)) { | 945 | if (!wl_list_empty(&con->view->content_tree->children)) { |
912 | wlr_scene_subsurface_tree_set_clip(&con->view->content_tree->node, &(struct wlr_box){ | 946 | struct wlr_box clip = {0}; |
913 | .x = con->view->geometry.x, | 947 | if (clip_to_geometry) { |
914 | .y = con->view->geometry.y, | 948 | clip = (struct wlr_box){ |
915 | .width = con->current.content_width, | 949 | .x = con->view->geometry.x, |
916 | .height = con->current.content_height, | 950 | .y = con->view->geometry.y, |
917 | }); | 951 | .width = con->current.content_width, |
952 | .height = con->current.content_height, | ||
953 | }; | ||
954 | } | ||
955 | wlr_scene_subsurface_tree_set_clip(&con->view->content_tree->node, &clip); | ||
918 | } | 956 | } |
919 | } | 957 | } |
920 | 958 | ||
@@ -923,7 +961,7 @@ struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) { | |||
923 | if ((xdg_surface = wlr_xdg_surface_try_from_wlr_surface(wlr_surface))) { | 961 | if ((xdg_surface = wlr_xdg_surface_try_from_wlr_surface(wlr_surface))) { |
924 | return view_from_wlr_xdg_surface(xdg_surface); | 962 | return view_from_wlr_xdg_surface(xdg_surface); |
925 | } | 963 | } |
926 | #if HAVE_XWAYLAND | 964 | #if WLR_HAS_XWAYLAND |
927 | struct wlr_xwayland_surface *xsurface; | 965 | struct wlr_xwayland_surface *xsurface; |
928 | if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(wlr_surface))) { | 966 | if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(wlr_surface))) { |
929 | return view_from_wlr_xwayland_surface(xsurface); | 967 | return view_from_wlr_xwayland_surface(xsurface); |
@@ -1014,6 +1052,18 @@ static size_t parse_title_format(struct sway_view *view, char *buffer) { | |||
1014 | return len; | 1052 | return len; |
1015 | } | 1053 | } |
1016 | 1054 | ||
1055 | void view_update_app_id(struct sway_view *view) { | ||
1056 | const char *app_id = view_get_app_id(view); | ||
1057 | |||
1058 | if (view->foreign_toplevel && app_id) { | ||
1059 | wlr_foreign_toplevel_handle_v1_set_app_id(view->foreign_toplevel, app_id); | ||
1060 | } | ||
1061 | |||
1062 | if (view->ext_foreign_toplevel) { | ||
1063 | update_ext_foreign_toplevel(view); | ||
1064 | } | ||
1065 | } | ||
1066 | |||
1017 | void view_update_title(struct sway_view *view, bool force) { | 1067 | void view_update_title(struct sway_view *view, bool force) { |
1018 | const char *title = view_get_title(view); | 1068 | const char *title = view_get_title(view); |
1019 | 1069 | ||
@@ -1060,6 +1110,10 @@ void view_update_title(struct sway_view *view, bool force) { | |||
1060 | if (view->foreign_toplevel && title) { | 1110 | if (view->foreign_toplevel && title) { |
1061 | wlr_foreign_toplevel_handle_v1_set_title(view->foreign_toplevel, title); | 1111 | wlr_foreign_toplevel_handle_v1_set_title(view->foreign_toplevel, title); |
1062 | } | 1112 | } |
1113 | |||
1114 | if (view->ext_foreign_toplevel) { | ||
1115 | update_ext_foreign_toplevel(view); | ||
1116 | } | ||
1063 | } | 1117 | } |
1064 | 1118 | ||
1065 | bool view_is_visible(struct sway_view *view) { | 1119 | bool view_is_visible(struct sway_view *view) { |
@@ -1131,7 +1185,7 @@ void view_set_urgent(struct sway_view *view, bool enable) { | |||
1131 | 1185 | ||
1132 | ipc_event_window(view->container, "urgent"); | 1186 | ipc_event_window(view->container, "urgent"); |
1133 | 1187 | ||
1134 | if (!container_is_scratchpad_hidden(view->container)) { | 1188 | if (!container_is_scratchpad_hidden_or_child(view->container)) { |
1135 | workspace_detect_urgent(view->container->pending.workspace); | 1189 | workspace_detect_urgent(view->container->pending.workspace); |
1136 | } | 1190 | } |
1137 | } | 1191 | } |
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 40d33435..f8709a4c 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define _POSIX_C_SOURCE 200809 | ||
2 | #include <ctype.h> | 1 | #include <ctype.h> |
3 | #include <limits.h> | 2 | #include <limits.h> |
4 | #include <stdbool.h> | 3 | #include <stdbool.h> |
@@ -11,6 +10,7 @@ | |||
11 | #include "sway/input/seat.h" | 10 | #include "sway/input/seat.h" |
12 | #include "sway/ipc-server.h" | 11 | #include "sway/ipc-server.h" |
13 | #include "sway/output.h" | 12 | #include "sway/output.h" |
13 | #include "sway/server.h" | ||
14 | #include "sway/tree/arrange.h" | 14 | #include "sway/tree/arrange.h" |
15 | #include "sway/tree/container.h" | 15 | #include "sway/tree/container.h" |
16 | #include "sway/tree/node.h" | 16 | #include "sway/tree/node.h" |
@@ -708,6 +708,11 @@ void workspace_for_each_container(struct sway_workspace *ws, | |||
708 | struct sway_container *workspace_find_container(struct sway_workspace *ws, | 708 | struct sway_container *workspace_find_container(struct sway_workspace *ws, |
709 | bool (*test)(struct sway_container *con, void *data), void *data) { | 709 | bool (*test)(struct sway_container *con, void *data), void *data) { |
710 | struct sway_container *result = NULL; | 710 | struct sway_container *result = NULL; |
711 | if (ws == NULL){ | ||
712 | sway_log(SWAY_ERROR, "Cannot find container with no workspace."); | ||
713 | return NULL; | ||
714 | } | ||
715 | |||
711 | // Tiling | 716 | // Tiling |
712 | for (int i = 0; i < ws->tiling->length; ++i) { | 717 | for (int i = 0; i < ws->tiling->length; ++i) { |
713 | struct sway_container *child = ws->tiling->items[i]; | 718 | struct sway_container *child = ws->tiling->items[i]; |
diff --git a/sway/xdg_activation_v1.c b/sway/xdg_activation_v1.c index c26ee19a..b7c80dd4 100644 --- a/sway/xdg_activation_v1.c +++ b/sway/xdg_activation_v1.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #include <wlr/types/wlr_xdg_activation_v1.h> | 1 | #include <wlr/types/wlr_xdg_activation_v1.h> |
2 | #include <wlr/types/wlr_xdg_shell.h> | ||
2 | #include "sway/desktop/launcher.h" | 3 | #include "sway/desktop/launcher.h" |
3 | #include "sway/tree/view.h" | 4 | #include "sway/tree/view.h" |
4 | #include "sway/tree/workspace.h" | 5 | #include "sway/tree/workspace.h" |
@@ -17,11 +18,15 @@ void xdg_activation_v1_handle_request_activate(struct wl_listener *listener, | |||
17 | return; | 18 | return; |
18 | } | 19 | } |
19 | 20 | ||
21 | struct launcher_ctx *ctx = event->token->data; | ||
22 | if (ctx == NULL) { | ||
23 | return; | ||
24 | } | ||
25 | |||
20 | if (!xdg_surface->surface->mapped) { | 26 | if (!xdg_surface->surface->mapped) { |
21 | // This is a startup notification. If we are tracking it, the data | 27 | // This is a startup notification. If we are tracking it, the data |
22 | // field is a launcher_ctx. | 28 | // field is a launcher_ctx. |
23 | struct launcher_ctx *ctx = event->token->data; | 29 | if (ctx->activated) { |
24 | if (!ctx || ctx->activated) { | ||
25 | // This ctx has already been activated and cannot be used again | 30 | // This ctx has already been activated and cannot be used again |
26 | // for a startup notification. It will be destroyed | 31 | // for a startup notification. It will be destroyed |
27 | return; | 32 | return; |
@@ -32,9 +37,19 @@ void xdg_activation_v1_handle_request_activate(struct wl_listener *listener, | |||
32 | return; | 37 | return; |
33 | } | 38 | } |
34 | 39 | ||
35 | struct wlr_seat *wlr_seat = event->token->seat; | 40 | // This is an activation request. If this context is internal we have ctx->seat. |
36 | struct sway_seat *seat = wlr_seat ? wlr_seat->data : NULL; | 41 | struct sway_seat *seat = ctx->seat; |
37 | view_request_activate(view, seat); | 42 | if (!seat) { |
43 | // Otherwise, use the seat indicated by the launcher client in set_serial | ||
44 | seat = ctx->token->seat ? ctx->token->seat->data : NULL; | ||
45 | } | ||
46 | |||
47 | if (seat && ctx->had_focused_surface) { | ||
48 | view_request_activate(view, seat); | ||
49 | } else { | ||
50 | // The token is valid, but cannot be used to activate a window | ||
51 | view_request_urgent(view); | ||
52 | } | ||
38 | } | 53 | } |
39 | 54 | ||
40 | void xdg_activation_v1_handle_new_token(struct wl_listener *listener, void *data) { | 55 | void xdg_activation_v1_handle_new_token(struct wl_listener *listener, void *data) { |