diff options
author | emersion <contact@emersion.fr> | 2018-02-24 23:29:08 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-02-24 23:29:08 +0100 |
commit | 583c30dbe3e3249ec1b753fddbfa982db56dce31 (patch) | |
tree | ce07d65ab79287280f1f5468e2e62eb5cbef4089 | |
parent | Implement workspaces (diff) | |
parent | static bfs queue (diff) | |
download | sway-583c30dbe3e3249ec1b753fddbfa982db56dce31.tar.gz sway-583c30dbe3e3249ec1b753fddbfa982db56dce31.tar.zst sway-583c30dbe3e3249ec1b753fddbfa982db56dce31.zip |
Merge pull request #1585 from acrisci/focus-overhaul
focus overhaul
-rw-r--r-- | include/log.h | 4 | ||||
-rw-r--r-- | include/sway/commands.h | 4 | ||||
-rw-r--r-- | include/sway/container.h | 12 | ||||
-rw-r--r-- | include/sway/input/input-manager.h | 5 | ||||
-rw-r--r-- | include/sway/input/seat.h | 30 | ||||
-rw-r--r-- | include/sway/layout.h | 20 | ||||
-rw-r--r-- | include/sway/output.h | 1 | ||||
-rw-r--r-- | include/sway/server.h | 6 | ||||
-rw-r--r-- | include/sway/workspace.h | 10 | ||||
-rw-r--r-- | meson.build | 1 | ||||
-rw-r--r-- | sway/commands.c | 108 | ||||
-rw-r--r-- | sway/commands/exit.c | 3 | ||||
-rw-r--r-- | sway/commands/focus.c | 59 | ||||
-rw-r--r-- | sway/commands/kill.c | 7 | ||||
-rw-r--r-- | sway/commands/layout.c | 56 | ||||
-rw-r--r-- | sway/commands/reload.c | 3 | ||||
-rw-r--r-- | sway/commands/set.c | 1 | ||||
-rw-r--r-- | sway/commands/workspace.c | 3 | ||||
-rw-r--r-- | sway/desktop/output.c | 115 | ||||
-rw-r--r-- | sway/desktop/xdg_shell_v6.c | 3 | ||||
-rw-r--r-- | sway/input/input-manager.c | 65 | ||||
-rw-r--r-- | sway/input/keyboard.c | 2 | ||||
-rw-r--r-- | sway/input/seat.c | 183 | ||||
-rw-r--r-- | sway/ipc-json.c | 4 | ||||
-rw-r--r-- | sway/ipc-server.c | 2 | ||||
-rw-r--r-- | sway/meson.build | 2 | ||||
-rw-r--r-- | sway/server.c | 10 | ||||
-rw-r--r-- | sway/tree/container.c | 78 | ||||
-rw-r--r-- | sway/tree/layout.c | 285 | ||||
-rw-r--r-- | sway/tree/workspace.c | 37 |
30 files changed, 869 insertions, 250 deletions
diff --git a/include/log.h b/include/log.h index 350a59ef..a9748127 100644 --- a/include/log.h +++ b/include/log.h | |||
@@ -5,11 +5,11 @@ | |||
5 | 5 | ||
6 | void _sway_abort(const char *filename, ...) ATTRIB_PRINTF(1, 2); | 6 | void _sway_abort(const char *filename, ...) ATTRIB_PRINTF(1, 2); |
7 | #define sway_abort(FMT, ...) \ | 7 | #define sway_abort(FMT, ...) \ |
8 | _sway_abort("[%s:%d] " FMT, _strip_path(__FILE__), __LINE__, ##__VA_ARGS__) | 8 | _sway_abort("[%s:%d] " FMT, wlr_strip_path(__FILE__), __LINE__, ##__VA_ARGS__) |
9 | 9 | ||
10 | bool _sway_assert(bool condition, const char* format, ...) ATTRIB_PRINTF(2, 3); | 10 | bool _sway_assert(bool condition, const char* format, ...) ATTRIB_PRINTF(2, 3); |
11 | #define sway_assert(COND, FMT, ...) \ | 11 | #define sway_assert(COND, FMT, ...) \ |
12 | _sway_assert(COND, "[%s:%d] %s:" FMT, _strip_path(__FILE__), __LINE__, __PRETTY_FUNCTION__, ##__VA_ARGS__) | 12 | _sway_assert(COND, "[%s:%d] %s:" FMT, wlr_strip_path(__FILE__), __LINE__, __PRETTY_FUNCTION__, ##__VA_ARGS__) |
13 | 13 | ||
14 | void error_handler(int sig); | 14 | void error_handler(int sig); |
15 | 15 | ||
diff --git a/include/sway/commands.h b/include/sway/commands.h index 4ee7af2a..9ff18823 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h | |||
@@ -46,9 +46,9 @@ struct cmd_results *checkarg(int argc, const char *name, | |||
46 | enum expected_args type, int val); | 46 | enum expected_args type, int val); |
47 | 47 | ||
48 | /** | 48 | /** |
49 | * Parse and handles a command. | 49 | * Parse and executes a command. |
50 | */ | 50 | */ |
51 | struct cmd_results *handle_command(char *command); | 51 | struct cmd_results *execute_command(char *command, struct sway_seat *seat); |
52 | /** | 52 | /** |
53 | * Parse and handles a command during config file loading. | 53 | * Parse and handles a command during config file loading. |
54 | * | 54 | * |
diff --git a/include/sway/container.h b/include/sway/container.h index 0c66932d..f200a1a2 100644 --- a/include/sway/container.h +++ b/include/sway/container.h | |||
@@ -106,10 +106,6 @@ struct sway_container { | |||
106 | * The parent of this container. NULL for the root container. | 106 | * The parent of this container. NULL for the root container. |
107 | */ | 107 | */ |
108 | struct sway_container *parent; | 108 | struct sway_container *parent; |
109 | /** | ||
110 | * Which of this container's children has focus. | ||
111 | */ | ||
112 | struct sway_container *focused; | ||
113 | 109 | ||
114 | /** | 110 | /** |
115 | * Number of master views in auto layouts. | 111 | * Number of master views in auto layouts. |
@@ -162,4 +158,12 @@ void container_map(swayc_t *container, | |||
162 | swayc_t *swayc_at(swayc_t *parent, double lx, double ly, | 158 | swayc_t *swayc_at(swayc_t *parent, double lx, double ly, |
163 | struct wlr_surface **surface, double *sx, double *sy); | 159 | struct wlr_surface **surface, double *sx, double *sy); |
164 | 160 | ||
161 | /** | ||
162 | * Apply the function for each child of the container breadth first. | ||
163 | */ | ||
164 | void container_for_each_bfs(swayc_t *con, void (*f)(swayc_t *con, void *data), | ||
165 | void *data); | ||
166 | |||
167 | swayc_t *swayc_change_layout(swayc_t *container, enum swayc_layouts layout); | ||
168 | |||
165 | #endif | 169 | #endif |
diff --git a/include/sway/input/input-manager.h b/include/sway/input/input-manager.h index 66ace262..eab7dc90 100644 --- a/include/sway/input/input-manager.h +++ b/include/sway/input/input-manager.h | |||
@@ -16,14 +16,15 @@ struct sway_input_device { | |||
16 | struct wlr_input_device *wlr_device; | 16 | struct wlr_input_device *wlr_device; |
17 | struct input_config *config; | 17 | struct input_config *config; |
18 | struct wl_list link; | 18 | struct wl_list link; |
19 | struct wl_listener device_destroy; | ||
19 | }; | 20 | }; |
20 | 21 | ||
21 | struct sway_input_manager { | 22 | struct sway_input_manager { |
22 | struct wl_listener input_add; | ||
23 | struct wl_listener input_remove; | ||
24 | struct sway_server *server; | 23 | struct sway_server *server; |
25 | struct wl_list devices; | 24 | struct wl_list devices; |
26 | struct wl_list seats; | 25 | struct wl_list seats; |
26 | |||
27 | struct wl_listener new_input; | ||
27 | }; | 28 | }; |
28 | 29 | ||
29 | struct sway_input_manager *sway_input_manager_create( | 30 | struct sway_input_manager *sway_input_manager_create( |
diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index b21cbccb..1d55bec7 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h | |||
@@ -12,14 +12,26 @@ struct sway_seat_device { | |||
12 | struct wl_list link; // sway_seat::devices | 12 | struct wl_list link; // sway_seat::devices |
13 | }; | 13 | }; |
14 | 14 | ||
15 | struct sway_seat_container { | ||
16 | struct sway_seat *seat; | ||
17 | swayc_t *container; | ||
18 | |||
19 | struct wl_list link; // sway_seat::focus_stack | ||
20 | |||
21 | struct wl_listener destroy; | ||
22 | }; | ||
23 | |||
15 | struct sway_seat { | 24 | struct sway_seat { |
16 | struct wlr_seat *wlr_seat; | 25 | struct wlr_seat *wlr_seat; |
17 | struct seat_config *config; | 26 | struct seat_config *config; |
18 | struct sway_cursor *cursor; | 27 | struct sway_cursor *cursor; |
19 | struct sway_input_manager *input; | 28 | struct sway_input_manager *input; |
20 | swayc_t *focus; | 29 | |
30 | bool has_focus; | ||
31 | struct wl_list focus_stack; // list of containers in focus order | ||
21 | 32 | ||
22 | struct wl_listener focus_destroy; | 33 | struct wl_listener focus_destroy; |
34 | struct wl_listener new_container; | ||
23 | 35 | ||
24 | struct wl_list devices; // sway_seat_device::link | 36 | struct wl_list devices; // sway_seat_device::link |
25 | 37 | ||
@@ -44,6 +56,22 @@ void sway_seat_configure_xcursor(struct sway_seat *seat); | |||
44 | 56 | ||
45 | void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container); | 57 | void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container); |
46 | 58 | ||
59 | swayc_t *sway_seat_get_focus(struct sway_seat *seat); | ||
60 | |||
61 | /** | ||
62 | * Return the last container to be focused for the seat (or the most recently | ||
63 | * opened if no container has received focused) that is a child of the given | ||
64 | * container. The focus-inactive container of the root window is the focused | ||
65 | * container for the seat (if the seat does have focus). This function can be | ||
66 | * used to determine what container gets focused next if the focused container | ||
67 | * is destroyed, or focus moves to a container with children and we need to | ||
68 | * descend into the next leaf in focus order. | ||
69 | */ | ||
70 | swayc_t *sway_seat_get_focus_inactive(struct sway_seat *seat, swayc_t *container); | ||
71 | |||
72 | swayc_t *sway_seat_get_focus_by_type(struct sway_seat *seat, | ||
73 | enum swayc_types type); | ||
74 | |||
47 | void sway_seat_set_config(struct sway_seat *seat, struct seat_config *seat_config); | 75 | void sway_seat_set_config(struct sway_seat *seat, struct seat_config *seat_config); |
48 | 76 | ||
49 | #endif | 77 | #endif |
diff --git a/include/sway/layout.h b/include/sway/layout.h index af561453..e82c4442 100644 --- a/include/sway/layout.h +++ b/include/sway/layout.h | |||
@@ -2,6 +2,19 @@ | |||
2 | #define _SWAY_LAYOUT_H | 2 | #define _SWAY_LAYOUT_H |
3 | 3 | ||
4 | #include <wlr/types/wlr_output_layout.h> | 4 | #include <wlr/types/wlr_output_layout.h> |
5 | #include "sway/container.h" | ||
6 | |||
7 | enum movement_direction { | ||
8 | MOVE_LEFT, | ||
9 | MOVE_RIGHT, | ||
10 | MOVE_UP, | ||
11 | MOVE_DOWN, | ||
12 | MOVE_PARENT, | ||
13 | MOVE_CHILD, | ||
14 | MOVE_NEXT, | ||
15 | MOVE_PREV, | ||
16 | MOVE_FIRST | ||
17 | }; | ||
5 | 18 | ||
6 | struct sway_container; | 19 | struct sway_container; |
7 | 20 | ||
@@ -11,13 +24,20 @@ struct sway_root { | |||
11 | struct wl_listener output_layout_change; | 24 | struct wl_listener output_layout_change; |
12 | 25 | ||
13 | struct wl_list unmanaged_views; // sway_view::unmanaged_view_link | 26 | struct wl_list unmanaged_views; // sway_view::unmanaged_view_link |
27 | |||
28 | struct { | ||
29 | struct wl_signal new_container; | ||
30 | } events; | ||
14 | }; | 31 | }; |
15 | 32 | ||
16 | void init_layout(void); | 33 | void init_layout(void); |
17 | void add_child(struct sway_container *parent, struct sway_container *child); | 34 | void add_child(struct sway_container *parent, struct sway_container *child); |
35 | swayc_t *add_sibling(swayc_t *parent, swayc_t *child); | ||
18 | struct sway_container *remove_child(struct sway_container *child); | 36 | struct sway_container *remove_child(struct sway_container *child); |
19 | enum swayc_layouts default_layout(struct sway_container *output); | 37 | enum swayc_layouts default_layout(struct sway_container *output); |
20 | void sort_workspaces(struct sway_container *output); | 38 | void sort_workspaces(struct sway_container *output); |
21 | void arrange_windows(struct sway_container *container, double width, double height); | 39 | void arrange_windows(struct sway_container *container, double width, double height); |
40 | swayc_t *get_swayc_in_direction(swayc_t *container, | ||
41 | struct sway_seat *seat, enum movement_direction dir); | ||
22 | 42 | ||
23 | #endif | 43 | #endif |
diff --git a/include/sway/output.h b/include/sway/output.h index 7ca02d7b..95d64705 100644 --- a/include/sway/output.h +++ b/include/sway/output.h | |||
@@ -14,6 +14,7 @@ struct sway_output { | |||
14 | struct timespec last_frame; | 14 | struct timespec last_frame; |
15 | 15 | ||
16 | struct wl_listener frame; | 16 | struct wl_listener frame; |
17 | struct wl_listener output_destroy; | ||
17 | }; | 18 | }; |
18 | 19 | ||
19 | #endif | 20 | #endif |
diff --git a/include/sway/server.h b/include/sway/server.h index d497e132..3fcdb1ba 100644 --- a/include/sway/server.h +++ b/include/sway/server.h | |||
@@ -24,8 +24,7 @@ struct sway_server { | |||
24 | 24 | ||
25 | struct sway_input_manager *input; | 25 | struct sway_input_manager *input; |
26 | 26 | ||
27 | struct wl_listener output_add; | 27 | struct wl_listener new_output; |
28 | struct wl_listener output_remove; | ||
29 | struct wl_listener output_frame; | 28 | struct wl_listener output_frame; |
30 | 29 | ||
31 | struct wlr_xdg_shell_v6 *xdg_shell_v6; | 30 | struct wlr_xdg_shell_v6 *xdg_shell_v6; |
@@ -45,8 +44,7 @@ bool server_init(struct sway_server *server); | |||
45 | void server_fini(struct sway_server *server); | 44 | void server_fini(struct sway_server *server); |
46 | void server_run(struct sway_server *server); | 45 | void server_run(struct sway_server *server); |
47 | 46 | ||
48 | void output_add_notify(struct wl_listener *listener, void *data); | 47 | void handle_new_output(struct wl_listener *listener, void *data); |
49 | void output_remove_notify(struct wl_listener *listener, void *data); | ||
50 | 48 | ||
51 | void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data); | 49 | void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data); |
52 | void handle_xwayland_surface(struct wl_listener *listener, void *data); | 50 | void handle_xwayland_surface(struct wl_listener *listener, void *data); |
diff --git a/include/sway/workspace.h b/include/sway/workspace.h index 30bbdaa8..fee54255 100644 --- a/include/sway/workspace.h +++ b/include/sway/workspace.h | |||
@@ -1,7 +1,7 @@ | |||
1 | #ifndef _SWAY_WORKSPACE_H | 1 | #ifndef _SWAY_WORKSPACE_H |
2 | #define _SWAY_WORKSPACE_H | 2 | #define _SWAY_WORKSPACE_H |
3 | 3 | ||
4 | struct sway_container; | 4 | #include "sway/container.h" |
5 | 5 | ||
6 | extern char *prev_workspace_name; | 6 | extern char *prev_workspace_name; |
7 | 7 | ||
@@ -12,9 +12,9 @@ bool workspace_switch(swayc_t *workspace); | |||
12 | struct sway_container *workspace_by_number(const char* name); | 12 | struct sway_container *workspace_by_number(const char* name); |
13 | swayc_t *workspace_by_name(const char*); | 13 | swayc_t *workspace_by_name(const char*); |
14 | 14 | ||
15 | struct sway_container *workspace_output_next(struct sway_container *current); | 15 | struct sway_container *workspace_output_next(swayc_t *current); |
16 | struct sway_container *workspace_next(struct sway_container *current); | 16 | struct sway_container *workspace_next(swayc_t *current); |
17 | struct sway_container *workspace_output_prev(struct sway_container *current); | 17 | struct sway_container *workspace_output_prev(swayc_t *current); |
18 | struct sway_container *workspace_prev(struct sway_container *current); | 18 | struct sway_container *workspace_prev(swayc_t *current); |
19 | 19 | ||
20 | #endif | 20 | #endif |
diff --git a/meson.build b/meson.build index 49392126..fc995c81 100644 --- a/meson.build +++ b/meson.build | |||
@@ -10,6 +10,7 @@ project( | |||
10 | ) | 10 | ) |
11 | 11 | ||
12 | add_project_arguments('-Wno-unused-parameter', language: 'c') | 12 | add_project_arguments('-Wno-unused-parameter', language: 'c') |
13 | add_project_arguments('-Wno-unused-function', language: 'c') | ||
13 | 14 | ||
14 | cc = meson.get_compiler('c') | 15 | cc = meson.get_compiler('c') |
15 | 16 | ||
diff --git a/sway/commands.c b/sway/commands.c index 0d4aa104..b52eb200 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -125,23 +125,42 @@ struct cmd_results *add_color(const char *name, char *buffer, const char *color) | |||
125 | return NULL; | 125 | return NULL; |
126 | } | 126 | } |
127 | 127 | ||
128 | /* Keep alphabetized */ | 128 | /** |
129 | * handlers that can run in either config or command context | ||
130 | * Keep alphabetized | ||
131 | */ | ||
129 | static struct cmd_handler handlers[] = { | 132 | static struct cmd_handler handlers[] = { |
130 | { "bindcode", cmd_bindcode }, | 133 | { "bindcode", cmd_bindcode }, |
131 | { "bindsym", cmd_bindsym }, | 134 | { "bindsym", cmd_bindsym }, |
132 | { "exec", cmd_exec }, | 135 | { "exec", cmd_exec }, |
133 | { "exec_always", cmd_exec_always }, | 136 | { "exec_always", cmd_exec_always }, |
134 | { "exit", cmd_exit }, | ||
135 | { "include", cmd_include }, | 137 | { "include", cmd_include }, |
136 | { "input", cmd_input }, | 138 | { "input", cmd_input }, |
137 | { "kill", cmd_kill }, | ||
138 | { "output", cmd_output }, | 139 | { "output", cmd_output }, |
139 | { "reload", cmd_reload }, | ||
140 | { "seat", cmd_seat }, | 140 | { "seat", cmd_seat }, |
141 | { "set", cmd_set }, | ||
142 | { "workspace", cmd_workspace }, | 141 | { "workspace", cmd_workspace }, |
143 | }; | 142 | }; |
144 | 143 | ||
144 | /** | ||
145 | * Commands that can *only* run in the config loading context | ||
146 | * Keep alphabetized | ||
147 | */ | ||
148 | static struct cmd_handler config_handlers[] = { | ||
149 | { "set", cmd_set }, | ||
150 | }; | ||
151 | |||
152 | /** | ||
153 | * Commands that can *not* run in the config loading context | ||
154 | * Keep alphabetized | ||
155 | */ | ||
156 | static struct cmd_handler command_handlers[] = { | ||
157 | { "exit", cmd_exit }, | ||
158 | { "focus", cmd_focus }, | ||
159 | { "kill", cmd_kill }, | ||
160 | { "layout", cmd_layout }, | ||
161 | { "reload", cmd_reload }, | ||
162 | }; | ||
163 | |||
145 | static int handler_compare(const void *_a, const void *_b) { | 164 | static int handler_compare(const void *_a, const void *_b) { |
146 | const struct cmd_handler *a = _a; | 165 | const struct cmd_handler *a = _a; |
147 | const struct cmd_handler *b = _b; | 166 | const struct cmd_handler *b = _b; |
@@ -179,24 +198,48 @@ static struct cmd_handler *find_handler(char *line, enum cmd_status block) { | |||
179 | struct cmd_handler *res = NULL; | 198 | struct cmd_handler *res = NULL; |
180 | wlr_log(L_DEBUG, "find_handler(%s) %d", line, block == CMD_BLOCK_SEAT); | 199 | wlr_log(L_DEBUG, "find_handler(%s) %d", line, block == CMD_BLOCK_SEAT); |
181 | 200 | ||
201 | bool config_loading = config->reading || !config->active; | ||
202 | |||
182 | if (block == CMD_BLOCK_INPUT) { | 203 | if (block == CMD_BLOCK_INPUT) { |
183 | res = bsearch(&d, input_handlers, | 204 | // input commands can run in either context |
205 | return bsearch(&d, input_handlers, | ||
184 | sizeof(input_handlers) / sizeof(struct cmd_handler), | 206 | sizeof(input_handlers) / sizeof(struct cmd_handler), |
185 | sizeof(struct cmd_handler), handler_compare); | 207 | sizeof(struct cmd_handler), handler_compare); |
186 | } else if (block == CMD_BLOCK_SEAT) { | 208 | } else if (block == CMD_BLOCK_SEAT) { |
187 | res = bsearch(&d, seat_handlers, | 209 | // seat commands can run in either context |
210 | return bsearch(&d, seat_handlers, | ||
188 | sizeof(seat_handlers) / sizeof(struct cmd_handler), | 211 | sizeof(seat_handlers) / sizeof(struct cmd_handler), |
189 | sizeof(struct cmd_handler), handler_compare); | 212 | sizeof(struct cmd_handler), handler_compare); |
190 | } else { | 213 | } |
191 | res = bsearch(&d, handlers, | 214 | |
192 | sizeof(handlers) / sizeof(struct cmd_handler), | 215 | if (!config_loading) { |
216 | res = bsearch(&d, command_handlers, | ||
217 | sizeof(command_handlers) / sizeof(struct cmd_handler), | ||
193 | sizeof(struct cmd_handler), handler_compare); | 218 | sizeof(struct cmd_handler), handler_compare); |
219 | |||
220 | if (res) { | ||
221 | return res; | ||
222 | } | ||
223 | } | ||
224 | |||
225 | if (config->reading) { | ||
226 | res = bsearch(&d, config_handlers, | ||
227 | sizeof(config_handlers) / sizeof(struct cmd_handler), | ||
228 | sizeof(struct cmd_handler), handler_compare); | ||
229 | |||
230 | if (res) { | ||
231 | return res; | ||
232 | } | ||
194 | } | 233 | } |
195 | 234 | ||
235 | res = bsearch(&d, handlers, | ||
236 | sizeof(handlers) / sizeof(struct cmd_handler), | ||
237 | sizeof(struct cmd_handler), handler_compare); | ||
238 | |||
196 | return res; | 239 | return res; |
197 | } | 240 | } |
198 | 241 | ||
199 | struct cmd_results *handle_command(char *_exec) { | 242 | struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) { |
200 | // Even though this function will process multiple commands we will only | 243 | // Even though this function will process multiple commands we will only |
201 | // return the last error, if any (for now). (Since we have access to an | 244 | // return the last error, if any (for now). (Since we have access to an |
202 | // error string we could e.g. concatenate all errors there.) | 245 | // error string we could e.g. concatenate all errors there.) |
@@ -207,6 +250,16 @@ struct cmd_results *handle_command(char *_exec) { | |||
207 | char *cmd; | 250 | char *cmd; |
208 | list_t *containers = NULL; | 251 | list_t *containers = NULL; |
209 | 252 | ||
253 | if (seat == NULL) { | ||
254 | // passing a NULL seat means we just pick the default seat | ||
255 | seat = sway_input_manager_get_default_seat(input_manager); | ||
256 | if (!sway_assert(seat, "could not find a seat to run the command on")) { | ||
257 | return NULL; | ||
258 | } | ||
259 | } | ||
260 | |||
261 | config->handler_context.seat = seat; | ||
262 | |||
210 | head = exec; | 263 | head = exec; |
211 | do { | 264 | do { |
212 | // Extract criteria (valid for this command list only). | 265 | // Extract criteria (valid for this command list only). |
@@ -276,23 +329,22 @@ struct cmd_results *handle_command(char *_exec) { | |||
276 | if (!has_criteria) { | 329 | if (!has_criteria) { |
277 | // without criteria, the command acts upon the focused | 330 | // without criteria, the command acts upon the focused |
278 | // container | 331 | // container |
279 | struct sway_seat *seat = config->handler_context.seat; | 332 | config->handler_context.current_container = |
280 | if (!seat) { | 333 | sway_seat_get_focus_inactive(seat, &root_container); |
281 | seat = sway_input_manager_get_default_seat(input_manager); | 334 | if (!sway_assert(config->handler_context.current_container, |
335 | "could not get focus-inactive for root container")) { | ||
336 | return NULL; | ||
282 | } | 337 | } |
283 | if (seat) { | 338 | struct cmd_results *res = handler->handle(argc-1, argv+1); |
284 | config->handler_context.current_container = seat->focus; | 339 | if (res->status != CMD_SUCCESS) { |
285 | struct cmd_results *res = handler->handle(argc-1, argv+1); | 340 | free_argv(argc, argv); |
286 | if (res->status != CMD_SUCCESS) { | 341 | if (results) { |
287 | free_argv(argc, argv); | 342 | free_cmd_results(results); |
288 | if (results) { | ||
289 | free_cmd_results(results); | ||
290 | } | ||
291 | results = res; | ||
292 | goto cleanup; | ||
293 | } | 343 | } |
294 | free_cmd_results(res); | 344 | results = res; |
345 | goto cleanup; | ||
295 | } | 346 | } |
347 | free_cmd_results(res); | ||
296 | } else { | 348 | } else { |
297 | for (int i = 0; i < containers->length; ++i) { | 349 | for (int i = 0; i < containers->length; ++i) { |
298 | config->handler_context.current_container = containers->items[i]; | 350 | config->handler_context.current_container = containers->items[i]; |
@@ -319,13 +371,13 @@ cleanup: | |||
319 | return results; | 371 | return results; |
320 | } | 372 | } |
321 | 373 | ||
322 | // this is like handle_command above, except: | 374 | // this is like execute_command above, except: |
323 | // 1) it ignores empty commands (empty lines) | 375 | // 1) it ignores empty commands (empty lines) |
324 | // 2) it does variable substitution | 376 | // 2) it does variable substitution |
325 | // 3) it doesn't split commands (because the multiple commands are supposed to | 377 | // 3) it doesn't split commands (because the multiple commands are supposed to |
326 | // be chained together) | 378 | // be chained together) |
327 | // 4) handle_command handles all state internally while config_command has some | 379 | // 4) execute_command handles all state internally while config_command has |
328 | // state handled outside (notably the block mode, in read_config) | 380 | // some state handled outside (notably the block mode, in read_config) |
329 | struct cmd_results *config_command(char *exec, enum cmd_status block) { | 381 | struct cmd_results *config_command(char *exec, enum cmd_status block) { |
330 | struct cmd_results *results = NULL; | 382 | struct cmd_results *results = NULL; |
331 | int argc; | 383 | int argc; |
diff --git a/sway/commands/exit.c b/sway/commands/exit.c index 4bb6a97b..d5353c20 100644 --- a/sway/commands/exit.c +++ b/sway/commands/exit.c | |||
@@ -6,9 +6,6 @@ void sway_terminate(int exit_code); | |||
6 | 6 | ||
7 | struct cmd_results *cmd_exit(int argc, char **argv) { | 7 | struct cmd_results *cmd_exit(int argc, char **argv) { |
8 | struct cmd_results *error = NULL; | 8 | struct cmd_results *error = NULL; |
9 | if (config->reading) { | ||
10 | return cmd_results_new(CMD_FAILURE, "exit", "Can't be used in config file."); | ||
11 | } | ||
12 | if ((error = checkarg(argc, "exit", EXPECTED_EQUAL_TO, 0))) { | 9 | if ((error = checkarg(argc, "exit", EXPECTED_EQUAL_TO, 0))) { |
13 | return error; | 10 | return error; |
14 | } | 11 | } |
diff --git a/sway/commands/focus.c b/sway/commands/focus.c new file mode 100644 index 00000000..f1a8078f --- /dev/null +++ b/sway/commands/focus.c | |||
@@ -0,0 +1,59 @@ | |||
1 | #include <strings.h> | ||
2 | #include <wlr/util/log.h> | ||
3 | #include "log.h" | ||
4 | #include "sway/input/input-manager.h" | ||
5 | #include "sway/input/seat.h" | ||
6 | #include "sway/view.h" | ||
7 | #include "sway/commands.h" | ||
8 | |||
9 | static bool parse_movement_direction(const char *name, enum movement_direction *out) { | ||
10 | if (strcasecmp(name, "left") == 0) { | ||
11 | *out = MOVE_LEFT; | ||
12 | } else if (strcasecmp(name, "right") == 0) { | ||
13 | *out = MOVE_RIGHT; | ||
14 | } else if (strcasecmp(name, "up") == 0) { | ||
15 | *out = MOVE_UP; | ||
16 | } else if (strcasecmp(name, "down") == 0) { | ||
17 | *out = MOVE_DOWN; | ||
18 | } else if (strcasecmp(name, "parent") == 0) { | ||
19 | *out = MOVE_PARENT; | ||
20 | } else if (strcasecmp(name, "child") == 0) { | ||
21 | *out = MOVE_CHILD; | ||
22 | } else if (strcasecmp(name, "next") == 0) { | ||
23 | *out = MOVE_NEXT; | ||
24 | } else if (strcasecmp(name, "prev") == 0) { | ||
25 | *out = MOVE_PREV; | ||
26 | } else { | ||
27 | return false; | ||
28 | } | ||
29 | |||
30 | return true; | ||
31 | } | ||
32 | |||
33 | struct cmd_results *cmd_focus(int argc, char **argv) { | ||
34 | swayc_t *con = config->handler_context.current_container; | ||
35 | struct sway_seat *seat = config->handler_context.seat; | ||
36 | if (con->type < C_WORKSPACE) { | ||
37 | return cmd_results_new(CMD_FAILURE, "focus", | ||
38 | "Command 'focus' cannot be used above the workspace level"); | ||
39 | } | ||
40 | |||
41 | if (argc == 0) { | ||
42 | sway_seat_set_focus(seat, con); | ||
43 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
44 | } | ||
45 | |||
46 | // TODO mode_toggle | ||
47 | enum movement_direction direction = 0; | ||
48 | if (!parse_movement_direction(argv[0], &direction)) { | ||
49 | return cmd_results_new(CMD_INVALID, "focus", | ||
50 | "Expected 'focus <direction|parent|child|mode_toggle>' or 'focus output <direction|name>'"); | ||
51 | } | ||
52 | |||
53 | swayc_t *next_focus = get_swayc_in_direction(con, seat, direction); | ||
54 | if (next_focus) { | ||
55 | sway_seat_set_focus(seat, next_focus); | ||
56 | } | ||
57 | |||
58 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
59 | } | ||
diff --git a/sway/commands/kill.c b/sway/commands/kill.c index cebf7f3c..f408ce2a 100644 --- a/sway/commands/kill.c +++ b/sway/commands/kill.c | |||
@@ -6,15 +6,12 @@ | |||
6 | #include "sway/commands.h" | 6 | #include "sway/commands.h" |
7 | 7 | ||
8 | struct cmd_results *cmd_kill(int argc, char **argv) { | 8 | struct cmd_results *cmd_kill(int argc, char **argv) { |
9 | if (config->reading) { | ||
10 | return cmd_results_new(CMD_FAILURE, "kill", | ||
11 | "Command 'kill' cannot be used in the config file"); | ||
12 | } | ||
13 | enum swayc_types type = config->handler_context.current_container->type; | 9 | enum swayc_types type = config->handler_context.current_container->type; |
14 | if (type != C_VIEW || type != C_CONTAINER) { | 10 | if (type != C_VIEW && type != C_CONTAINER) { |
15 | return cmd_results_new(CMD_INVALID, NULL, | 11 | return cmd_results_new(CMD_INVALID, NULL, |
16 | "Can only kill views and containers with this command"); | 12 | "Can only kill views and containers with this command"); |
17 | } | 13 | } |
14 | |||
18 | // TODO close arbitrary containers without a view | 15 | // TODO close arbitrary containers without a view |
19 | struct sway_view *view = | 16 | struct sway_view *view = |
20 | config->handler_context.current_container->sway_view; | 17 | config->handler_context.current_container->sway_view; |
diff --git a/sway/commands/layout.c b/sway/commands/layout.c new file mode 100644 index 00000000..b0fc5d66 --- /dev/null +++ b/sway/commands/layout.c | |||
@@ -0,0 +1,56 @@ | |||
1 | #include <string.h> | ||
2 | #include <strings.h> | ||
3 | #include "sway/commands.h" | ||
4 | #include "sway/container.h" | ||
5 | #include "sway/layout.h" | ||
6 | #include "log.h" | ||
7 | |||
8 | struct cmd_results *cmd_layout(int argc, char **argv) { | ||
9 | struct cmd_results *error = NULL; | ||
10 | if ((error = checkarg(argc, "layout", EXPECTED_MORE_THAN, 0))) { | ||
11 | return error; | ||
12 | } | ||
13 | swayc_t *parent = config->handler_context.current_container; | ||
14 | |||
15 | // TODO: floating | ||
16 | /* | ||
17 | if (parent->is_floating) { | ||
18 | return cmd_results_new(CMD_FAILURE, "layout", "Unable to change layout of floating windows"); | ||
19 | } | ||
20 | */ | ||
21 | |||
22 | while (parent->type == C_VIEW) { | ||
23 | parent = parent->parent; | ||
24 | } | ||
25 | |||
26 | // TODO: stacks and tabs | ||
27 | |||
28 | if (strcasecmp(argv[0], "default") == 0) { | ||
29 | swayc_change_layout(parent, parent->prev_layout); | ||
30 | if (parent->layout == L_NONE) { | ||
31 | swayc_t *output = swayc_parent_by_type(parent, C_OUTPUT); | ||
32 | swayc_change_layout(parent, default_layout(output)); | ||
33 | } | ||
34 | } else { | ||
35 | if (parent->layout != L_TABBED && parent->layout != L_STACKED) { | ||
36 | parent->prev_layout = parent->layout; | ||
37 | } | ||
38 | |||
39 | if (strcasecmp(argv[0], "splith") == 0) { | ||
40 | swayc_change_layout(parent, L_HORIZ); | ||
41 | } else if (strcasecmp(argv[0], "splitv") == 0) { | ||
42 | swayc_change_layout(parent, L_VERT); | ||
43 | } else if (strcasecmp(argv[0], "toggle") == 0 && argc == 2 && strcasecmp(argv[1], "split") == 0) { | ||
44 | if (parent->layout == L_HORIZ && (parent->workspace_layout == L_NONE | ||
45 | || parent->workspace_layout == L_HORIZ)) { | ||
46 | swayc_change_layout(parent, L_VERT); | ||
47 | } else { | ||
48 | swayc_change_layout(parent, L_HORIZ); | ||
49 | } | ||
50 | } | ||
51 | } | ||
52 | |||
53 | arrange_windows(parent, parent->width, parent->height); | ||
54 | |||
55 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
56 | } | ||
diff --git a/sway/commands/reload.c b/sway/commands/reload.c index 419c7de3..d54d40db 100644 --- a/sway/commands/reload.c +++ b/sway/commands/reload.c | |||
@@ -4,9 +4,6 @@ | |||
4 | 4 | ||
5 | struct cmd_results *cmd_reload(int argc, char **argv) { | 5 | struct cmd_results *cmd_reload(int argc, char **argv) { |
6 | struct cmd_results *error = NULL; | 6 | struct cmd_results *error = NULL; |
7 | if (config->reading) { | ||
8 | return cmd_results_new(CMD_FAILURE, "reload", "Can't be used in config file."); | ||
9 | } | ||
10 | if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) { | 7 | if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) { |
11 | return error; | 8 | return error; |
12 | } | 9 | } |
diff --git a/sway/commands/set.c b/sway/commands/set.c index 856c73e7..84e9b792 100644 --- a/sway/commands/set.c +++ b/sway/commands/set.c | |||
@@ -27,7 +27,6 @@ void free_sway_variable(struct sway_variable *var) { | |||
27 | struct cmd_results *cmd_set(int argc, char **argv) { | 27 | struct cmd_results *cmd_set(int argc, char **argv) { |
28 | char *tmp; | 28 | char *tmp; |
29 | struct cmd_results *error = NULL; | 29 | struct cmd_results *error = NULL; |
30 | if (!config->reading) return cmd_results_new(CMD_FAILURE, "set", "Can only be used in config file."); | ||
31 | if ((error = checkarg(argc, "set", EXPECTED_AT_LEAST, 2))) { | 30 | if ((error = checkarg(argc, "set", EXPECTED_AT_LEAST, 2))) { |
32 | return error; | 31 | return error; |
33 | } | 32 | } |
diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c index 12984ed4..fa891398 100644 --- a/sway/commands/workspace.c +++ b/sway/commands/workspace.c | |||
@@ -90,7 +90,8 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { | |||
90 | free(name); | 90 | free(name); |
91 | } | 91 | } |
92 | workspace_switch(ws); | 92 | workspace_switch(ws); |
93 | current_container = config->handler_context.seat->focus; | 93 | current_container = |
94 | sway_seat_get_focus(config->handler_context.seat); | ||
94 | swayc_t *new_output = swayc_parent_by_type(current_container, C_OUTPUT); | 95 | swayc_t *new_output = swayc_parent_by_type(current_container, C_OUTPUT); |
95 | 96 | ||
96 | if (config->mouse_warping && old_output != new_output) { | 97 | if (config->mouse_warping && old_output != new_output) { |
diff --git a/sway/desktop/output.c b/sway/desktop/output.c index a650665f..63420d0c 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c | |||
@@ -46,57 +46,22 @@ static void render_surface(struct wlr_surface *surface, | |||
46 | int height = surface->current->height; | 46 | int height = surface->current->height; |
47 | int render_width = width * wlr_output->scale; | 47 | int render_width = width * wlr_output->scale; |
48 | int render_height = height * wlr_output->scale; | 48 | int render_height = height * wlr_output->scale; |
49 | double ox = lx, oy = ly; | 49 | int owidth, oheight; |
50 | wlr_output_layout_output_coords(layout, wlr_output, &ox, &oy); | 50 | wlr_output_effective_resolution(wlr_output, &owidth, &oheight); |
51 | ox *= wlr_output->scale; | ||
52 | oy *= wlr_output->scale; | ||
53 | 51 | ||
54 | struct wlr_box render_box = { | 52 | // FIXME: view coords are inconsistently assumed to be in output or layout coords |
55 | .x = lx, .y = ly, | 53 | struct wlr_box layout_box = { |
54 | .x = lx + wlr_output->lx, .y = ly + wlr_output->ly, | ||
56 | .width = render_width, .height = render_height, | 55 | .width = render_width, .height = render_height, |
57 | }; | 56 | }; |
58 | if (wlr_output_layout_intersects(layout, wlr_output, &render_box)) { | 57 | if (wlr_output_layout_intersects(layout, wlr_output, &layout_box)) { |
58 | struct wlr_box render_box = { | ||
59 | .x = lx, .y = ly, | ||
60 | .width = render_width, .height = render_height | ||
61 | }; | ||
59 | float matrix[16]; | 62 | float matrix[16]; |
60 | 63 | wlr_matrix_project_box(&matrix, &render_box, | |
61 | float translate_center[16]; | 64 | surface->current->transform, 0, &wlr_output->transform_matrix); |
62 | wlr_matrix_translate(&translate_center, | ||
63 | (int)ox + render_width / 2, (int)oy + render_height / 2, 0); | ||
64 | |||
65 | float rotate[16]; | ||
66 | wlr_matrix_rotate(&rotate, rotation); | ||
67 | |||
68 | float translate_origin[16]; | ||
69 | wlr_matrix_translate(&translate_origin, -render_width / 2, | ||
70 | -render_height / 2, 0); | ||
71 | |||
72 | float scale[16]; | ||
73 | wlr_matrix_scale(&scale, render_width, render_height, 1); | ||
74 | |||
75 | float transform[16]; | ||
76 | wlr_matrix_mul(&translate_center, &rotate, &transform); | ||
77 | wlr_matrix_mul(&transform, &translate_origin, &transform); | ||
78 | wlr_matrix_mul(&transform, &scale, &transform); | ||
79 | |||
80 | if (surface->current->transform != WL_OUTPUT_TRANSFORM_NORMAL) { | ||
81 | float surface_translate_center[16]; | ||
82 | wlr_matrix_translate(&surface_translate_center, 0.5, 0.5, 0); | ||
83 | |||
84 | float surface_transform[16]; | ||
85 | wlr_matrix_transform(surface_transform, | ||
86 | wlr_output_transform_invert(surface->current->transform)); | ||
87 | |||
88 | float surface_translate_origin[16]; | ||
89 | wlr_matrix_translate(&surface_translate_origin, -0.5, -0.5, 0); | ||
90 | |||
91 | wlr_matrix_mul(&transform, &surface_translate_center, | ||
92 | &transform); | ||
93 | wlr_matrix_mul(&transform, &surface_transform, &transform); | ||
94 | wlr_matrix_mul(&transform, &surface_translate_origin, | ||
95 | &transform); | ||
96 | } | ||
97 | |||
98 | wlr_matrix_mul(&wlr_output->transform_matrix, &transform, &matrix); | ||
99 | |||
100 | wlr_render_with_matrix(server.renderer, surface->texture, | 65 | wlr_render_with_matrix(server.renderer, surface->texture, |
101 | &matrix); | 66 | &matrix); |
102 | 67 | ||
@@ -125,8 +90,9 @@ static void render_xdg_v6_popups(struct wlr_xdg_surface_v6 *surface, | |||
125 | double width = surface->surface->current->width; | 90 | double width = surface->surface->current->width; |
126 | double height = surface->surface->current->height; | 91 | double height = surface->surface->current->height; |
127 | 92 | ||
128 | struct wlr_xdg_surface_v6 *popup; | 93 | struct wlr_xdg_popup_v6 *popup_state; |
129 | wl_list_for_each(popup, &surface->popups, popup_link) { | 94 | wl_list_for_each(popup_state, &surface->popups, link) { |
95 | struct wlr_xdg_surface_v6 *popup = popup_state->base; | ||
130 | if (!popup->configured) { | 96 | if (!popup->configured) { |
131 | continue; | 97 | continue; |
132 | } | 98 | } |
@@ -215,11 +181,20 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { | |||
215 | struct sway_output *soutput = wl_container_of(listener, soutput, frame); | 181 | struct sway_output *soutput = wl_container_of(listener, soutput, frame); |
216 | struct wlr_output *wlr_output = data; | 182 | struct wlr_output *wlr_output = data; |
217 | struct sway_server *server = soutput->server; | 183 | struct sway_server *server = soutput->server; |
184 | float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; | ||
185 | struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); | ||
186 | wlr_renderer_clear(renderer, &clear_color); | ||
218 | 187 | ||
219 | wlr_output_make_current(wlr_output); | 188 | int buffer_age = -1; |
189 | wlr_output_make_current(wlr_output, &buffer_age); | ||
220 | wlr_renderer_begin(server->renderer, wlr_output); | 190 | wlr_renderer_begin(server->renderer, wlr_output); |
221 | 191 | ||
222 | swayc_t *workspace = soutput->swayc->focused; | 192 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
193 | swayc_t *focus = sway_seat_get_focus_inactive(seat, soutput->swayc); | ||
194 | swayc_t *workspace = (focus->type == C_WORKSPACE ? | ||
195 | focus : | ||
196 | swayc_parent_by_type(focus, C_WORKSPACE)); | ||
197 | |||
223 | swayc_descendants_of_type(workspace, C_VIEW, output_frame_view, soutput); | 198 | swayc_descendants_of_type(workspace, C_VIEW, output_frame_view, soutput); |
224 | 199 | ||
225 | // render unmanaged views on top | 200 | // render unmanaged views on top |
@@ -236,15 +211,23 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { | |||
236 | } | 211 | } |
237 | 212 | ||
238 | wlr_renderer_end(server->renderer); | 213 | wlr_renderer_end(server->renderer); |
239 | wlr_output_swap_buffers(wlr_output); | 214 | wlr_output_swap_buffers(wlr_output, &soutput->last_frame, NULL); |
240 | 215 | ||
241 | struct timespec now; | 216 | struct timespec now; |
242 | clock_gettime(CLOCK_MONOTONIC, &now); | 217 | clock_gettime(CLOCK_MONOTONIC, &now); |
243 | soutput->last_frame = now; | 218 | soutput->last_frame = now; |
244 | } | 219 | } |
245 | 220 | ||
246 | void output_add_notify(struct wl_listener *listener, void *data) { | 221 | static void handle_output_destroy(struct wl_listener *listener, void *data) { |
247 | struct sway_server *server = wl_container_of(listener, server, output_add); | 222 | struct sway_output *output = wl_container_of(listener, output, output_destroy); |
223 | struct wlr_output *wlr_output = data; | ||
224 | wlr_log(L_DEBUG, "Output %p %s removed", wlr_output, wlr_output->name); | ||
225 | |||
226 | destroy_output(output->swayc); | ||
227 | } | ||
228 | |||
229 | void handle_new_output(struct wl_listener *listener, void *data) { | ||
230 | struct sway_server *server = wl_container_of(listener, server, new_output); | ||
248 | struct wlr_output *wlr_output = data; | 231 | struct wlr_output *wlr_output = data; |
249 | wlr_log(L_DEBUG, "New output %p: %s", wlr_output, wlr_output->name); | 232 | wlr_log(L_DEBUG, "New output %p: %s", wlr_output, wlr_output->name); |
250 | 233 | ||
@@ -269,27 +252,11 @@ void output_add_notify(struct wl_listener *listener, void *data) { | |||
269 | 252 | ||
270 | sway_input_manager_configure_xcursor(input_manager); | 253 | sway_input_manager_configure_xcursor(input_manager); |
271 | 254 | ||
272 | output->frame.notify = output_frame_notify; | ||
273 | wl_signal_add(&wlr_output->events.frame, &output->frame); | 255 | wl_signal_add(&wlr_output->events.frame, &output->frame); |
274 | } | 256 | output->frame.notify = output_frame_notify; |
275 | |||
276 | void output_remove_notify(struct wl_listener *listener, void *data) { | ||
277 | struct sway_server *server = wl_container_of(listener, server, output_remove); | ||
278 | struct wlr_output *wlr_output = data; | ||
279 | wlr_log(L_DEBUG, "Output %p %s removed", wlr_output, wlr_output->name); | ||
280 | 257 | ||
281 | swayc_t *output_container = NULL; | 258 | wl_signal_add(&wlr_output->events.destroy, &output->output_destroy); |
282 | for (int i = 0 ; i < root_container.children->length; ++i) { | 259 | output->output_destroy.notify = handle_output_destroy; |
283 | swayc_t *child = root_container.children->items[i]; | ||
284 | if (child->type == C_OUTPUT && | ||
285 | child->sway_output->wlr_output == wlr_output) { | ||
286 | output_container = child; | ||
287 | break; | ||
288 | } | ||
289 | } | ||
290 | if (!output_container) { | ||
291 | return; | ||
292 | } | ||
293 | 260 | ||
294 | destroy_output(output_container); | 261 | arrange_windows(&root_container, -1, -1); |
295 | } | 262 | } |
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index ca56a9c0..b44d9e54 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c | |||
@@ -135,7 +135,8 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { | |||
135 | wl_signal_add(&xdg_surface->events.destroy, &sway_surface->destroy); | 135 | wl_signal_add(&xdg_surface->events.destroy, &sway_surface->destroy); |
136 | 136 | ||
137 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 137 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
138 | swayc_t *cont = new_view(seat->focus, sway_view); | 138 | swayc_t *focus = sway_seat_get_focus_inactive(seat, &root_container); |
139 | swayc_t *cont = new_view(focus, sway_view); | ||
139 | sway_view->swayc = cont; | 140 | sway_view->swayc = cont; |
140 | 141 | ||
141 | arrange_windows(cont->parent, -1, -1); | 142 | arrange_windows(cont->parent, -1, -1); |
diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index d789c7eb..27c2c72e 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c | |||
@@ -160,9 +160,34 @@ static void sway_input_manager_libinput_config_pointer(struct sway_input_device | |||
160 | } | 160 | } |
161 | } | 161 | } |
162 | 162 | ||
163 | static void input_add_notify(struct wl_listener *listener, void *data) { | 163 | static void handle_device_destroy(struct wl_listener *listener, void *data) { |
164 | struct wlr_input_device *device = data; | ||
165 | |||
166 | struct sway_input_device *input_device = | ||
167 | input_sway_device_from_wlr(input_manager, device); | ||
168 | |||
169 | if (!sway_assert(input_device, "could not find sway device")) { | ||
170 | return; | ||
171 | } | ||
172 | |||
173 | wlr_log(L_DEBUG, "removing device: '%s'", | ||
174 | input_device->identifier); | ||
175 | |||
176 | struct sway_seat *seat = NULL; | ||
177 | wl_list_for_each(seat, &input_manager->seats, link) { | ||
178 | sway_seat_remove_device(seat, input_device); | ||
179 | } | ||
180 | |||
181 | wl_list_remove(&input_device->link); | ||
182 | wl_list_remove(&input_device->device_destroy.link); | ||
183 | free_input_config(input_device->config); | ||
184 | free(input_device->identifier); | ||
185 | free(input_device); | ||
186 | } | ||
187 | |||
188 | static void handle_new_input(struct wl_listener *listener, void *data) { | ||
164 | struct sway_input_manager *input = | 189 | struct sway_input_manager *input = |
165 | wl_container_of(listener, input, input_add); | 190 | wl_container_of(listener, input, new_input); |
166 | struct wlr_input_device *device = data; | 191 | struct wlr_input_device *device = data; |
167 | 192 | ||
168 | struct sway_input_device *input_device = | 193 | struct sway_input_device *input_device = |
@@ -226,32 +251,9 @@ static void input_add_notify(struct wl_listener *listener, void *data) { | |||
226 | "device '%s' is not configured on any seats", | 251 | "device '%s' is not configured on any seats", |
227 | input_device->identifier); | 252 | input_device->identifier); |
228 | } | 253 | } |
229 | } | ||
230 | |||
231 | static void input_remove_notify(struct wl_listener *listener, void *data) { | ||
232 | struct sway_input_manager *input = | ||
233 | wl_container_of(listener, input, input_remove); | ||
234 | struct wlr_input_device *device = data; | ||
235 | |||
236 | struct sway_input_device *input_device = | ||
237 | input_sway_device_from_wlr(input, device); | ||
238 | |||
239 | if (!sway_assert(input_device, "could not find sway device")) { | ||
240 | return; | ||
241 | } | ||
242 | |||
243 | wlr_log(L_DEBUG, "removing device: '%s'", | ||
244 | input_device->identifier); | ||
245 | |||
246 | struct sway_seat *seat = NULL; | ||
247 | wl_list_for_each(seat, &input->seats, link) { | ||
248 | sway_seat_remove_device(seat, input_device); | ||
249 | } | ||
250 | 254 | ||
251 | wl_list_remove(&input_device->link); | 255 | wl_signal_add(&device->events.destroy, &input_device->device_destroy); |
252 | free_input_config(input_device->config); | 256 | input_device->device_destroy.notify = handle_device_destroy; |
253 | free(input_device->identifier); | ||
254 | free(input_device); | ||
255 | } | 257 | } |
256 | 258 | ||
257 | struct sway_input_manager *sway_input_manager_create( | 259 | struct sway_input_manager *sway_input_manager_create( |
@@ -269,11 +271,8 @@ struct sway_input_manager *sway_input_manager_create( | |||
269 | // create the default seat | 271 | // create the default seat |
270 | input_manager_get_seat(input, default_seat); | 272 | input_manager_get_seat(input, default_seat); |
271 | 273 | ||
272 | input->input_add.notify = input_add_notify; | 274 | input->new_input.notify = handle_new_input; |
273 | wl_signal_add(&server->backend->events.input_add, &input->input_add); | 275 | wl_signal_add(&server->backend->events.new_input, &input->new_input); |
274 | |||
275 | input->input_remove.notify = input_remove_notify; | ||
276 | wl_signal_add(&server->backend->events.input_remove, &input->input_remove); | ||
277 | 276 | ||
278 | return input; | 277 | return input; |
279 | } | 278 | } |
@@ -282,7 +281,7 @@ bool sway_input_manager_has_focus(struct sway_input_manager *input, | |||
282 | swayc_t *container) { | 281 | swayc_t *container) { |
283 | struct sway_seat *seat = NULL; | 282 | struct sway_seat *seat = NULL; |
284 | wl_list_for_each(seat, &input->seats, link) { | 283 | wl_list_for_each(seat, &input->seats, link) { |
285 | if (seat->focus == container) { | 284 | if (sway_seat_get_focus(seat) == container) { |
286 | return true; | 285 | return true; |
287 | } | 286 | } |
288 | } | 287 | } |
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 6dc57d46..99685052 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c | |||
@@ -95,7 +95,7 @@ static void keyboard_execute_command(struct sway_keyboard *keyboard, | |||
95 | binding->command); | 95 | binding->command); |
96 | config_clear_handler_context(config); | 96 | config_clear_handler_context(config); |
97 | config->handler_context.seat = keyboard->seat_device->sway_seat; | 97 | config->handler_context.seat = keyboard->seat_device->sway_seat; |
98 | struct cmd_results *results = handle_command(binding->command); | 98 | struct cmd_results *results = execute_command(binding->command, NULL); |
99 | if (results->status != CMD_SUCCESS) { | 99 | if (results->status != CMD_SUCCESS) { |
100 | wlr_log(L_DEBUG, "could not run command for binding: %s", | 100 | wlr_log(L_DEBUG, "could not run command for binding: %s", |
101 | binding->command); | 101 | binding->command); |
diff --git a/sway/input/seat.c b/sway/input/seat.c index 5e87986d..648e7914 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c | |||
@@ -32,6 +32,81 @@ void sway_seat_destroy(struct sway_seat *seat) { | |||
32 | wlr_seat_destroy(seat->wlr_seat); | 32 | wlr_seat_destroy(seat->wlr_seat); |
33 | } | 33 | } |
34 | 34 | ||
35 | static void handle_seat_container_destroy(struct wl_listener *listener, | ||
36 | void *data) { | ||
37 | struct sway_seat_container *seat_con = | ||
38 | wl_container_of(listener, seat_con, destroy); | ||
39 | struct sway_seat *seat = seat_con->seat; | ||
40 | swayc_t *con = seat_con->container; | ||
41 | |||
42 | bool is_focus = (sway_seat_get_focus(seat) == con); | ||
43 | |||
44 | wl_list_remove(&seat_con->link); | ||
45 | |||
46 | if (is_focus) { | ||
47 | // pick next focus | ||
48 | sway_seat_set_focus(seat, NULL); | ||
49 | swayc_t *next = sway_seat_get_focus_inactive(seat, con->parent); | ||
50 | if (next == NULL) { | ||
51 | next = con->parent; | ||
52 | } | ||
53 | sway_seat_set_focus(seat, next); | ||
54 | } | ||
55 | |||
56 | wl_list_remove(&seat_con->destroy.link); | ||
57 | |||
58 | free(seat_con); | ||
59 | } | ||
60 | |||
61 | static struct sway_seat_container *seat_container_from_container( | ||
62 | struct sway_seat *seat, swayc_t *con) { | ||
63 | if (con->type < C_WORKSPACE) { | ||
64 | // these don't get seat containers ever | ||
65 | return NULL; | ||
66 | } | ||
67 | |||
68 | struct sway_seat_container *seat_con = NULL; | ||
69 | wl_list_for_each(seat_con, &seat->focus_stack, link) { | ||
70 | if (seat_con->container == con) { | ||
71 | return seat_con; | ||
72 | } | ||
73 | } | ||
74 | |||
75 | seat_con = calloc(1, sizeof(struct sway_seat_container)); | ||
76 | if (seat_con == NULL) { | ||
77 | wlr_log(L_ERROR, "could not allocate seat container"); | ||
78 | return NULL; | ||
79 | } | ||
80 | |||
81 | seat_con->container = con; | ||
82 | seat_con->seat = seat; | ||
83 | wl_list_insert(seat->focus_stack.prev, &seat_con->link); | ||
84 | wl_signal_add(&con->events.destroy, &seat_con->destroy); | ||
85 | seat_con->destroy.notify = handle_seat_container_destroy; | ||
86 | |||
87 | return seat_con; | ||
88 | } | ||
89 | |||
90 | static void handle_new_container(struct wl_listener *listener, void *data) { | ||
91 | struct sway_seat *seat = wl_container_of(listener, seat, new_container); | ||
92 | swayc_t *con = data; | ||
93 | seat_container_from_container(seat, con); | ||
94 | } | ||
95 | |||
96 | static void collect_focus_iter(swayc_t *con, void *data) { | ||
97 | struct sway_seat *seat = data; | ||
98 | if (con->type > C_WORKSPACE) { | ||
99 | return; | ||
100 | } | ||
101 | struct sway_seat_container *seat_con = | ||
102 | seat_container_from_container(seat, con); | ||
103 | if (!seat_con) { | ||
104 | return; | ||
105 | } | ||
106 | wl_list_remove(&seat_con->link); | ||
107 | wl_list_insert(&seat->focus_stack, &seat_con->link); | ||
108 | } | ||
109 | |||
35 | struct sway_seat *sway_seat_create(struct sway_input_manager *input, | 110 | struct sway_seat *sway_seat_create(struct sway_input_manager *input, |
36 | const char *seat_name) { | 111 | const char *seat_name) { |
37 | struct sway_seat *seat = calloc(1, sizeof(struct sway_seat)); | 112 | struct sway_seat *seat = calloc(1, sizeof(struct sway_seat)); |
@@ -52,6 +127,15 @@ struct sway_seat *sway_seat_create(struct sway_input_manager *input, | |||
52 | return NULL; | 127 | return NULL; |
53 | } | 128 | } |
54 | 129 | ||
130 | // init the focus stack | ||
131 | wl_list_init(&seat->focus_stack); | ||
132 | |||
133 | container_for_each_bfs(&root_container, collect_focus_iter, seat); | ||
134 | |||
135 | wl_signal_add(&root_container.sway_root->events.new_container, | ||
136 | &seat->new_container); | ||
137 | seat->new_container.notify = handle_new_container; | ||
138 | |||
55 | seat->input = input; | 139 | seat->input = input; |
56 | wl_list_init(&seat->devices); | 140 | wl_list_init(&seat->devices); |
57 | 141 | ||
@@ -81,13 +165,14 @@ static void seat_configure_keyboard(struct sway_seat *seat, | |||
81 | struct wlr_keyboard *wlr_keyboard = seat_device->input_device->wlr_device->keyboard; | 165 | struct wlr_keyboard *wlr_keyboard = seat_device->input_device->wlr_device->keyboard; |
82 | sway_keyboard_configure(seat_device->keyboard); | 166 | sway_keyboard_configure(seat_device->keyboard); |
83 | wlr_seat_set_keyboard(seat->wlr_seat, | 167 | wlr_seat_set_keyboard(seat->wlr_seat, |
84 | seat_device->input_device->wlr_device); | 168 | seat_device->input_device->wlr_device); |
85 | if (seat->focus && seat->focus->type == C_VIEW) { | 169 | swayc_t *focus = sway_seat_get_focus(seat); |
170 | if (focus && focus->type == C_VIEW) { | ||
86 | // force notify reenter to pick up the new configuration | 171 | // force notify reenter to pick up the new configuration |
87 | wlr_seat_keyboard_clear_focus(seat->wlr_seat); | 172 | wlr_seat_keyboard_clear_focus(seat->wlr_seat); |
88 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, | 173 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, |
89 | seat->focus->sway_view->surface, wlr_keyboard->keycodes, | 174 | focus->sway_view->surface, wlr_keyboard->keycodes, |
90 | wlr_keyboard->num_keycodes, &wlr_keyboard->modifiers); | 175 | wlr_keyboard->num_keycodes, &wlr_keyboard->modifiers); |
91 | } | 176 | } |
92 | } | 177 | } |
93 | 178 | ||
@@ -204,47 +289,83 @@ void sway_seat_configure_xcursor(struct sway_seat *seat) { | |||
204 | seat->cursor->cursor->y); | 289 | seat->cursor->cursor->y); |
205 | } | 290 | } |
206 | 291 | ||
207 | static void handle_focus_destroy(struct wl_listener *listener, void *data) { | ||
208 | struct sway_seat *seat = wl_container_of(listener, seat, focus_destroy); | ||
209 | swayc_t *container = data; | ||
210 | sway_seat_set_focus(seat, container->parent); | ||
211 | } | ||
212 | |||
213 | void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) { | 292 | void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) { |
214 | swayc_t *last_focus = seat->focus; | 293 | swayc_t *last_focus = sway_seat_get_focus(seat); |
215 | 294 | ||
216 | if (last_focus == container) { | 295 | if (container && last_focus == container) { |
217 | return; | 296 | return; |
218 | } | 297 | } |
219 | 298 | ||
220 | if (last_focus && last_focus->type == C_VIEW) { | 299 | if (container) { |
221 | wl_list_remove(&seat->focus_destroy.link); | 300 | struct sway_seat_container *seat_con = |
222 | } | 301 | seat_container_from_container(seat, container); |
302 | if (!seat_con) { | ||
303 | return; | ||
304 | } | ||
223 | 305 | ||
224 | if (container && container->type == C_VIEW) { | 306 | wl_list_remove(&seat_con->link); |
225 | struct sway_view *view = container->sway_view; | 307 | wl_list_insert(&seat->focus_stack, &seat_con->link); |
226 | view_set_activated(view, true); | 308 | |
227 | wl_signal_add(&container->events.destroy, &seat->focus_destroy); | 309 | if (container->type == C_VIEW) { |
228 | seat->focus_destroy.notify = handle_focus_destroy; | 310 | struct sway_view *view = container->sway_view; |
229 | 311 | view_set_activated(view, true); | |
230 | struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); | 312 | struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); |
231 | if (keyboard) { | 313 | if (keyboard) { |
232 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, view->surface, | 314 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, view->surface, |
233 | keyboard->keycodes, keyboard->num_keycodes, | 315 | keyboard->keycodes, keyboard->num_keycodes, |
234 | &keyboard->modifiers); | 316 | &keyboard->modifiers); |
235 | } else { | 317 | } else { |
236 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, view->surface, | 318 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, view->surface, |
237 | NULL, 0, NULL); | 319 | NULL, 0, NULL); |
320 | } | ||
238 | } | 321 | } |
239 | } | 322 | } |
240 | 323 | ||
241 | seat->focus = container; | ||
242 | |||
243 | if (last_focus && last_focus->type == C_VIEW && | 324 | if (last_focus && last_focus->type == C_VIEW && |
244 | !sway_input_manager_has_focus(seat->input, last_focus)) { | 325 | !sway_input_manager_has_focus(seat->input, last_focus)) { |
245 | struct sway_view *view = last_focus->sway_view; | 326 | struct sway_view *view = last_focus->sway_view; |
246 | view_set_activated(view, false); | 327 | view_set_activated(view, false); |
247 | } | 328 | } |
329 | |||
330 | seat->has_focus = (container != NULL); | ||
331 | } | ||
332 | |||
333 | swayc_t *sway_seat_get_focus_inactive(struct sway_seat *seat, swayc_t *container) { | ||
334 | struct sway_seat_container *current = NULL; | ||
335 | swayc_t *parent = NULL; | ||
336 | wl_list_for_each(current, &seat->focus_stack, link) { | ||
337 | parent = current->container->parent; | ||
338 | |||
339 | if (current->container == container) { | ||
340 | return current->container; | ||
341 | } | ||
342 | |||
343 | while (parent) { | ||
344 | if (parent == container) { | ||
345 | return current->container; | ||
346 | } | ||
347 | parent = parent->parent; | ||
348 | } | ||
349 | } | ||
350 | |||
351 | return NULL; | ||
352 | } | ||
353 | |||
354 | swayc_t *sway_seat_get_focus(struct sway_seat *seat) { | ||
355 | if (!seat->has_focus) { | ||
356 | return NULL; | ||
357 | } | ||
358 | return sway_seat_get_focus_inactive(seat, &root_container); | ||
359 | } | ||
360 | |||
361 | swayc_t *sway_seat_get_focus_by_type(struct sway_seat *seat, | ||
362 | enum swayc_types type) { | ||
363 | swayc_t *focus = sway_seat_get_focus_inactive(seat, &root_container); | ||
364 | if (focus->type == type) { | ||
365 | return focus; | ||
366 | } | ||
367 | |||
368 | return swayc_parent_by_type(focus, type); | ||
248 | } | 369 | } |
249 | 370 | ||
250 | void sway_seat_set_config(struct sway_seat *seat, | 371 | void sway_seat_set_config(struct sway_seat *seat, |
diff --git a/sway/ipc-json.c b/sway/ipc-json.c index bab9a201..f0afdc9f 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c | |||
@@ -74,8 +74,8 @@ static void ipc_json_describe_output(swayc_t *container, json_object *object) { | |||
74 | json_object_object_add(object, "refresh", json_object_new_int(wlr_output->refresh)); | 74 | json_object_object_add(object, "refresh", json_object_new_int(wlr_output->refresh)); |
75 | json_object_object_add(object, "transform", | 75 | json_object_object_add(object, "transform", |
76 | json_object_new_string(ipc_json_get_output_transform(wlr_output->transform))); | 76 | json_object_new_string(ipc_json_get_output_transform(wlr_output->transform))); |
77 | json_object_object_add(object, "current_workspace", | 77 | // TODO WLR need to set "current_workspace" to the currently focused |
78 | (container->focused) ? json_object_new_string(container->focused->name) : NULL); | 78 | // workspace in a way that makes sense with multiseat |
79 | } | 79 | } |
80 | 80 | ||
81 | static void ipc_json_describe_workspace(swayc_t *workspace, json_object *object) { | 81 | static void ipc_json_describe_workspace(swayc_t *workspace, json_object *object) { |
diff --git a/sway/ipc-server.c b/sway/ipc-server.c index a16a2b80..4c0953e8 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c | |||
@@ -336,7 +336,7 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
336 | case IPC_COMMAND: | 336 | case IPC_COMMAND: |
337 | { | 337 | { |
338 | config_clear_handler_context(config); | 338 | config_clear_handler_context(config); |
339 | struct cmd_results *results = handle_command(buf); | 339 | struct cmd_results *results = execute_command(buf, NULL); |
340 | const char *json = cmd_results_to_json(results); | 340 | const char *json = cmd_results_to_json(results); |
341 | char reply[256]; | 341 | char reply[256]; |
342 | int length = snprintf(reply, sizeof(reply), "%s", json); | 342 | int length = snprintf(reply, sizeof(reply), "%s", json); |
diff --git a/sway/meson.build b/sway/meson.build index 271d4a99..26e56ad2 100644 --- a/sway/meson.build +++ b/sway/meson.build | |||
@@ -10,9 +10,11 @@ sway_sources = files( | |||
10 | 'commands/exit.c', | 10 | 'commands/exit.c', |
11 | 'commands/exec.c', | 11 | 'commands/exec.c', |
12 | 'commands/exec_always.c', | 12 | 'commands/exec_always.c', |
13 | 'commands/focus.c', | ||
13 | 'commands/kill.c', | 14 | 'commands/kill.c', |
14 | 'commands/include.c', | 15 | 'commands/include.c', |
15 | 'commands/input.c', | 16 | 'commands/input.c', |
17 | 'commands/layout.c', | ||
16 | 'commands/seat.c', | 18 | 'commands/seat.c', |
17 | 'commands/seat/attach.c', | 19 | 'commands/seat/attach.c', |
18 | 'commands/seat/fallback.c', | 20 | 'commands/seat/fallback.c', |
diff --git a/sway/server.c b/sway/server.c index b5eb510b..495769ee 100644 --- a/sway/server.c +++ b/sway/server.c | |||
@@ -22,7 +22,7 @@ static void server_ready(struct wl_listener *listener, void *data) { | |||
22 | config->active = true; | 22 | config->active = true; |
23 | while (config->cmd_queue->length) { | 23 | while (config->cmd_queue->length) { |
24 | char *line = config->cmd_queue->items[0]; | 24 | char *line = config->cmd_queue->items[0]; |
25 | struct cmd_results *res = handle_command(line); | 25 | struct cmd_results *res = execute_command(line, NULL); |
26 | if (res->status != CMD_SUCCESS) { | 26 | if (res->status != CMD_SUCCESS) { |
27 | wlr_log(L_ERROR, "Error on line '%s': %s", line, res->error); | 27 | wlr_log(L_ERROR, "Error on line '%s': %s", line, res->error); |
28 | } | 28 | } |
@@ -48,12 +48,8 @@ bool server_init(struct sway_server *server) { | |||
48 | server->data_device_manager = | 48 | server->data_device_manager = |
49 | wlr_data_device_manager_create(server->wl_display); | 49 | wlr_data_device_manager_create(server->wl_display); |
50 | 50 | ||
51 | server->output_add.notify = output_add_notify; | 51 | server->new_output.notify = handle_new_output; |
52 | wl_signal_add(&server->backend->events.output_add, &server->output_add); | 52 | wl_signal_add(&server->backend->events.new_output, &server->new_output); |
53 | |||
54 | server->output_remove.notify = output_remove_notify; | ||
55 | wl_signal_add(&server->backend->events.output_remove, | ||
56 | &server->output_remove); | ||
57 | 53 | ||
58 | server->xdg_shell_v6 = wlr_xdg_shell_v6_create(server->wl_display); | 54 | server->xdg_shell_v6 = wlr_xdg_shell_v6_create(server->wl_display); |
59 | wl_signal_add(&server->xdg_shell_v6->events.new_surface, | 55 | wl_signal_add(&server->xdg_shell_v6->events.new_surface, |
diff --git a/sway/tree/container.c b/sway/tree/container.c index 48aabd86..fafbdb03 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -17,6 +17,21 @@ | |||
17 | #include "sway/workspace.h" | 17 | #include "sway/workspace.h" |
18 | #include "log.h" | 18 | #include "log.h" |
19 | 19 | ||
20 | static list_t *bfs_queue; | ||
21 | |||
22 | static list_t *get_bfs_queue() { | ||
23 | if (!bfs_queue) { | ||
24 | bfs_queue = create_list(); | ||
25 | if (!bfs_queue) { | ||
26 | wlr_log(L_ERROR, "could not allocate list for bfs queue"); | ||
27 | return NULL; | ||
28 | } | ||
29 | } | ||
30 | bfs_queue->length = 0; | ||
31 | |||
32 | return bfs_queue; | ||
33 | } | ||
34 | |||
20 | swayc_t *swayc_by_test(swayc_t *container, | 35 | swayc_t *swayc_by_test(swayc_t *container, |
21 | bool (*test)(swayc_t *view, void *data), void *data) { | 36 | bool (*test)(swayc_t *view, void *data), void *data) { |
22 | if (!container->children) { | 37 | if (!container->children) { |
@@ -151,19 +166,16 @@ swayc_t *new_output(struct sway_output *sway_output) { | |||
151 | char *ws_name = workspace_next_name(output->name); | 166 | char *ws_name = workspace_next_name(output->name); |
152 | wlr_log(L_DEBUG, "Creating default workspace %s", ws_name); | 167 | wlr_log(L_DEBUG, "Creating default workspace %s", ws_name); |
153 | swayc_t *ws = new_workspace(output, ws_name); | 168 | swayc_t *ws = new_workspace(output, ws_name); |
154 | output->focused = ws; | ||
155 | // Set each seat's focus if not already set | 169 | // Set each seat's focus if not already set |
156 | // TODO FOCUS: this is probably stupid, we shouldn't define focus in two | ||
157 | // places. We should probably put the active workspace on the sway_output | ||
158 | // struct instead of trying to do focus semantics like this | ||
159 | struct sway_seat *seat = NULL; | 170 | struct sway_seat *seat = NULL; |
160 | wl_list_for_each(seat, &input_manager->seats, link) { | 171 | wl_list_for_each(seat, &input_manager->seats, link) { |
161 | if (!seat->focus) { | 172 | if (!seat->has_focus) { |
162 | seat->focus = ws; | 173 | sway_seat_set_focus(seat, ws); |
163 | } | 174 | } |
164 | } | 175 | } |
165 | 176 | ||
166 | free(ws_name); | 177 | free(ws_name); |
178 | wl_signal_emit(&root_container.sway_root->events.new_container, output); | ||
167 | return output; | 179 | return output; |
168 | } | 180 | } |
169 | 181 | ||
@@ -185,6 +197,7 @@ swayc_t *new_workspace(swayc_t *output, const char *name) { | |||
185 | 197 | ||
186 | add_child(output, workspace); | 198 | add_child(output, workspace); |
187 | sort_workspaces(output); | 199 | sort_workspaces(output); |
200 | wl_signal_emit(&root_container.sway_root->events.new_container, workspace); | ||
188 | return workspace; | 201 | return workspace; |
189 | } | 202 | } |
190 | 203 | ||
@@ -207,9 +220,9 @@ swayc_t *new_view(swayc_t *sibling, struct sway_view *sway_view) { | |||
207 | add_child(sibling, swayc); | 220 | add_child(sibling, swayc); |
208 | } else { | 221 | } else { |
209 | // Regular case, create as sibling of current container | 222 | // Regular case, create as sibling of current container |
210 | // TODO WLR | 223 | add_sibling(sibling, swayc); |
211 | //add_sibling(sibling, swayc); | ||
212 | } | 224 | } |
225 | wl_signal_emit(&root_container.sway_root->events.new_container, swayc); | ||
213 | return swayc; | 226 | return swayc; |
214 | } | 227 | } |
215 | 228 | ||
@@ -235,6 +248,8 @@ swayc_t *destroy_output(swayc_t *output) { | |||
235 | } | 248 | } |
236 | } | 249 | } |
237 | 250 | ||
251 | wl_list_remove(&output->sway_output->output_destroy.link); | ||
252 | |||
238 | wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name); | 253 | wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name); |
239 | free_swayc(output); | 254 | free_swayc(output); |
240 | 255 | ||
@@ -273,7 +288,11 @@ swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type) { | |||
273 | 288 | ||
274 | swayc_t *swayc_at(swayc_t *parent, double lx, double ly, | 289 | swayc_t *swayc_at(swayc_t *parent, double lx, double ly, |
275 | struct wlr_surface **surface, double *sx, double *sy) { | 290 | struct wlr_surface **surface, double *sx, double *sy) { |
276 | list_t *queue = create_list(); | 291 | list_t *queue = get_bfs_queue(); |
292 | if (!queue) { | ||
293 | return NULL; | ||
294 | } | ||
295 | |||
277 | list_add(queue, parent); | 296 | list_add(queue, parent); |
278 | 297 | ||
279 | swayc_t *swayc = NULL; | 298 | swayc_t *swayc = NULL; |
@@ -313,7 +332,6 @@ swayc_t *swayc_at(swayc_t *parent, double lx, double ly, | |||
313 | *sx = view_sx - popup_sx; | 332 | *sx = view_sx - popup_sx; |
314 | *sy = view_sy - popup_sy; | 333 | *sy = view_sy - popup_sy; |
315 | *surface = popup->surface; | 334 | *surface = popup->surface; |
316 | list_free(queue); | ||
317 | return swayc; | 335 | return swayc; |
318 | } | 336 | } |
319 | break; | 337 | break; |
@@ -332,7 +350,6 @@ swayc_t *swayc_at(swayc_t *parent, double lx, double ly, | |||
332 | *sx = view_sx - sub_x; | 350 | *sx = view_sx - sub_x; |
333 | *sy = view_sy - sub_y; | 351 | *sy = view_sy - sub_y; |
334 | *surface = subsurface->surface; | 352 | *surface = subsurface->surface; |
335 | list_free(queue); | ||
336 | return swayc; | 353 | return swayc; |
337 | } | 354 | } |
338 | 355 | ||
@@ -344,7 +361,6 @@ swayc_t *swayc_at(swayc_t *parent, double lx, double ly, | |||
344 | *sx = view_sx; | 361 | *sx = view_sx; |
345 | *sy = view_sy; | 362 | *sy = view_sy; |
346 | *surface = swayc->sway_view->surface; | 363 | *surface = swayc->sway_view->surface; |
347 | list_free(queue); | ||
348 | return swayc; | 364 | return swayc; |
349 | } | 365 | } |
350 | } else { | 366 | } else { |
@@ -352,8 +368,6 @@ swayc_t *swayc_at(swayc_t *parent, double lx, double ly, | |||
352 | } | 368 | } |
353 | } | 369 | } |
354 | 370 | ||
355 | list_free(queue); | ||
356 | |||
357 | return NULL; | 371 | return NULL; |
358 | } | 372 | } |
359 | 373 | ||
@@ -378,3 +392,39 @@ void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), voi | |||
378 | f(container, data); | 392 | f(container, data); |
379 | } | 393 | } |
380 | } | 394 | } |
395 | |||
396 | void container_for_each_bfs(swayc_t *con, void (*f)(swayc_t *con, void *data), | ||
397 | void *data) { | ||
398 | list_t *queue = get_bfs_queue(); | ||
399 | if (!queue) { | ||
400 | return; | ||
401 | } | ||
402 | |||
403 | if (queue == NULL) { | ||
404 | wlr_log(L_ERROR, "could not allocate list"); | ||
405 | return; | ||
406 | } | ||
407 | |||
408 | list_add(queue, con); | ||
409 | |||
410 | swayc_t *current = NULL; | ||
411 | while (queue->length) { | ||
412 | current = queue->items[0]; | ||
413 | list_del(queue, 0); | ||
414 | f(current, data); | ||
415 | // TODO floating containers | ||
416 | list_cat(queue, current->children); | ||
417 | } | ||
418 | } | ||
419 | |||
420 | swayc_t *swayc_change_layout(swayc_t *container, enum swayc_layouts layout) { | ||
421 | if (container->type == C_WORKSPACE) { | ||
422 | container->workspace_layout = layout; | ||
423 | if (layout == L_HORIZ || layout == L_VERT) { | ||
424 | container->layout = layout; | ||
425 | } | ||
426 | } else { | ||
427 | container->layout = layout; | ||
428 | } | ||
429 | return container; | ||
430 | } | ||
diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 41ff81b2..3d04a1a7 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include "sway/layout.h" | 10 | #include "sway/layout.h" |
11 | #include "sway/output.h" | 11 | #include "sway/output.h" |
12 | #include "sway/view.h" | 12 | #include "sway/view.h" |
13 | #include "sway/input/seat.h" | ||
13 | #include "list.h" | 14 | #include "list.h" |
14 | #include "log.h" | 15 | #include "log.h" |
15 | 16 | ||
@@ -48,10 +49,12 @@ void init_layout(void) { | |||
48 | root_container.layout = L_NONE; | 49 | root_container.layout = L_NONE; |
49 | root_container.name = strdup("root"); | 50 | root_container.name = strdup("root"); |
50 | root_container.children = create_list(); | 51 | root_container.children = create_list(); |
52 | wl_signal_init(&root_container.events.destroy); | ||
51 | 53 | ||
52 | root_container.sway_root = calloc(1, sizeof(*root_container.sway_root)); | 54 | root_container.sway_root = calloc(1, sizeof(*root_container.sway_root)); |
53 | root_container.sway_root->output_layout = wlr_output_layout_create(); | 55 | root_container.sway_root->output_layout = wlr_output_layout_create(); |
54 | wl_list_init(&root_container.sway_root->unmanaged_views); | 56 | wl_list_init(&root_container.sway_root->unmanaged_views); |
57 | wl_signal_init(&root_container.sway_root->events.new_container); | ||
55 | 58 | ||
56 | root_container.sway_root->output_layout_change.notify = | 59 | root_container.sway_root->output_layout_change.notify = |
57 | output_layout_change_notify; | 60 | output_layout_change_notify; |
@@ -59,6 +62,32 @@ void init_layout(void) { | |||
59 | &root_container.sway_root->output_layout_change); | 62 | &root_container.sway_root->output_layout_change); |
60 | } | 63 | } |
61 | 64 | ||
65 | static int index_child(const swayc_t *child) { | ||
66 | // TODO handle floating | ||
67 | swayc_t *parent = child->parent; | ||
68 | int i, len; | ||
69 | len = parent->children->length; | ||
70 | for (i = 0; i < len; ++i) { | ||
71 | if (parent->children->items[i] == child) { | ||
72 | break; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | if (!sway_assert(i < len, "Stray container")) { | ||
77 | return -1; | ||
78 | } | ||
79 | return i; | ||
80 | } | ||
81 | |||
82 | swayc_t *add_sibling(swayc_t *fixed, swayc_t *active) { | ||
83 | // TODO handle floating | ||
84 | swayc_t *parent = fixed->parent; | ||
85 | int i = index_child(fixed); | ||
86 | list_insert(parent->children, i + 1, active); | ||
87 | active->parent = parent; | ||
88 | return active->parent; | ||
89 | } | ||
90 | |||
62 | void add_child(swayc_t *parent, swayc_t *child) { | 91 | void add_child(swayc_t *parent, swayc_t *child) { |
63 | wlr_log(L_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)", | 92 | wlr_log(L_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)", |
64 | child, child->type, child->width, child->height, | 93 | child, child->type, child->width, child->height, |
@@ -66,9 +95,6 @@ void add_child(swayc_t *parent, swayc_t *child) { | |||
66 | list_add(parent->children, child); | 95 | list_add(parent->children, child); |
67 | child->parent = parent; | 96 | child->parent = parent; |
68 | // set focus for this container | 97 | // set focus for this container |
69 | if (!parent->focused) { | ||
70 | parent->focused = child; | ||
71 | } | ||
72 | /* TODO WLR | 98 | /* TODO WLR |
73 | if (parent->type == C_WORKSPACE && child->type == C_VIEW && (parent->workspace_layout == L_TABBED || parent->workspace_layout == L_STACKED)) { | 99 | if (parent->type == C_WORKSPACE && child->type == C_VIEW && (parent->workspace_layout == L_TABBED || parent->workspace_layout == L_STACKED)) { |
74 | child = new_container(child, parent->workspace_layout); | 100 | child = new_container(child, parent->workspace_layout); |
@@ -147,8 +173,8 @@ void arrange_windows(swayc_t *container, double width, double height) { | |||
147 | height = floor(height); | 173 | height = floor(height); |
148 | 174 | ||
149 | wlr_log(L_DEBUG, "Arranging layout for %p %s %fx%f+%f,%f", container, | 175 | wlr_log(L_DEBUG, "Arranging layout for %p %s %fx%f+%f,%f", container, |
150 | container->name, container->width, container->height, container->x, | 176 | container->name, container->width, container->height, container->x, |
151 | container->y); | 177 | container->y); |
152 | 178 | ||
153 | double x = 0, y = 0; | 179 | double x = 0, y = 0; |
154 | switch (container->type) { | 180 | switch (container->type) { |
@@ -249,8 +275,8 @@ static void apply_horiz_layout(swayc_t *container, | |||
249 | for (int i = start; i < end; ++i) { | 275 | for (int i = start; i < end; ++i) { |
250 | swayc_t *child = container->children->items[i]; | 276 | swayc_t *child = container->children->items[i]; |
251 | wlr_log(L_DEBUG, | 277 | wlr_log(L_DEBUG, |
252 | "Calculating arrangement for %p:%d (will scale %f by %f)", | 278 | "Calculating arrangement for %p:%d (will scale %f by %f)", |
253 | child, child->type, width, scale); | 279 | child, child->type, width, scale); |
254 | view_set_position(child->sway_view, child_x, y); | 280 | view_set_position(child->sway_view, child_x, y); |
255 | 281 | ||
256 | if (i == end - 1) { | 282 | if (i == end - 1) { |
@@ -299,8 +325,8 @@ void apply_vert_layout(swayc_t *container, | |||
299 | for (i = start; i < end; ++i) { | 325 | for (i = start; i < end; ++i) { |
300 | swayc_t *child = container->children->items[i]; | 326 | swayc_t *child = container->children->items[i]; |
301 | wlr_log(L_DEBUG, | 327 | wlr_log(L_DEBUG, |
302 | "Calculating arrangement for %p:%d (will scale %f by %f)", | 328 | "Calculating arrangement for %p:%d (will scale %f by %f)", |
303 | child, child->type, height, scale); | 329 | child, child->type, height, scale); |
304 | view_set_position(child->sway_view, x, child_y); | 330 | view_set_position(child->sway_view, x, child_y); |
305 | 331 | ||
306 | if (i == end - 1) { | 332 | if (i == end - 1) { |
@@ -321,3 +347,244 @@ void apply_vert_layout(swayc_t *container, | |||
321 | */ | 347 | */ |
322 | } | 348 | } |
323 | } | 349 | } |
350 | |||
351 | /** | ||
352 | * Get swayc in the direction of newly entered output. | ||
353 | */ | ||
354 | static swayc_t *get_swayc_in_output_direction(swayc_t *output, | ||
355 | enum movement_direction dir, struct sway_seat *seat) { | ||
356 | if (!output) { | ||
357 | return NULL; | ||
358 | } | ||
359 | |||
360 | swayc_t *ws = sway_seat_get_focus_inactive(seat, output); | ||
361 | if (ws->type != C_WORKSPACE) { | ||
362 | ws = swayc_parent_by_type(ws, C_WORKSPACE); | ||
363 | } | ||
364 | |||
365 | if (ws == NULL) { | ||
366 | wlr_log(L_ERROR, "got an output without a workspace"); | ||
367 | return NULL; | ||
368 | } | ||
369 | |||
370 | if (ws->children->length > 0) { | ||
371 | switch (dir) { | ||
372 | case MOVE_LEFT: | ||
373 | // get most right child of new output | ||
374 | return ws->children->items[ws->children->length-1]; | ||
375 | case MOVE_RIGHT: | ||
376 | // get most left child of new output | ||
377 | return ws->children->items[0]; | ||
378 | case MOVE_UP: | ||
379 | case MOVE_DOWN: { | ||
380 | swayc_t *focused = sway_seat_get_focus_inactive(seat, ws); | ||
381 | if (focused && focused->parent) { | ||
382 | swayc_t *parent = focused->parent; | ||
383 | if (parent->layout == L_VERT) { | ||
384 | if (dir == MOVE_UP) { | ||
385 | // get child furthest down on new output | ||
386 | return parent->children->items[parent->children->length-1]; | ||
387 | } else if (dir == MOVE_DOWN) { | ||
388 | // get child furthest up on new output | ||
389 | return parent->children->items[0]; | ||
390 | } | ||
391 | } | ||
392 | return focused; | ||
393 | } | ||
394 | break; | ||
395 | } | ||
396 | default: | ||
397 | break; | ||
398 | } | ||
399 | } | ||
400 | |||
401 | return ws; | ||
402 | } | ||
403 | |||
404 | static void get_layout_center_position(swayc_t *container, int *x, int *y) { | ||
405 | // FIXME view coords are inconsistently referred to in layout/output systems | ||
406 | if (container->type == C_OUTPUT) { | ||
407 | *x = container->x + container->width/2; | ||
408 | *y = container->y + container->height/2; | ||
409 | } else { | ||
410 | swayc_t *output = swayc_parent_by_type(container, C_OUTPUT); | ||
411 | if (container->type == C_WORKSPACE) { | ||
412 | // Workspace coordinates are actually wrong/arbitrary, but should | ||
413 | // be same as output. | ||
414 | *x = output->x; | ||
415 | *y = output->y; | ||
416 | } else { | ||
417 | *x = output->x + container->x; | ||
418 | *y = output->y + container->y; | ||
419 | } | ||
420 | } | ||
421 | } | ||
422 | |||
423 | static bool sway_dir_to_wlr(enum movement_direction dir, enum wlr_direction *out) { | ||
424 | switch (dir) { | ||
425 | case MOVE_UP: | ||
426 | *out = WLR_DIRECTION_UP; | ||
427 | break; | ||
428 | case MOVE_DOWN: | ||
429 | *out = WLR_DIRECTION_DOWN; | ||
430 | break; | ||
431 | case MOVE_LEFT: | ||
432 | *out = WLR_DIRECTION_LEFT; | ||
433 | break; | ||
434 | case MOVE_RIGHT: | ||
435 | *out = WLR_DIRECTION_RIGHT; | ||
436 | break; | ||
437 | default: | ||
438 | return false; | ||
439 | } | ||
440 | |||
441 | return true; | ||
442 | } | ||
443 | |||
444 | static swayc_t *sway_output_from_wlr(struct wlr_output *output) { | ||
445 | if (output == NULL) { | ||
446 | return NULL; | ||
447 | } | ||
448 | for (int i = 0; i < root_container.children->length; ++i) { | ||
449 | swayc_t *o = root_container.children->items[i]; | ||
450 | if (o->type == C_OUTPUT && o->sway_output->wlr_output == output) { | ||
451 | return o; | ||
452 | } | ||
453 | } | ||
454 | return NULL; | ||
455 | } | ||
456 | |||
457 | static swayc_t *get_swayc_in_direction_under(swayc_t *container, | ||
458 | enum movement_direction dir, struct sway_seat *seat, swayc_t *limit) { | ||
459 | if (dir == MOVE_CHILD) { | ||
460 | return sway_seat_get_focus_inactive(seat, container); | ||
461 | } | ||
462 | |||
463 | swayc_t *parent = container->parent; | ||
464 | if (dir == MOVE_PARENT) { | ||
465 | if (parent->type == C_OUTPUT) { | ||
466 | return NULL; | ||
467 | } else { | ||
468 | return parent; | ||
469 | } | ||
470 | } | ||
471 | |||
472 | if (dir == MOVE_PREV || dir == MOVE_NEXT) { | ||
473 | int focused_idx = index_child(container); | ||
474 | if (focused_idx == -1) { | ||
475 | return NULL; | ||
476 | } else { | ||
477 | int desired = (focused_idx + (dir == MOVE_NEXT ? 1 : -1)) % | ||
478 | parent->children->length; | ||
479 | if (desired < 0) { | ||
480 | desired += parent->children->length; | ||
481 | } | ||
482 | return parent->children->items[desired]; | ||
483 | } | ||
484 | } | ||
485 | |||
486 | // If moving to an adjacent output we need a starting position (since this | ||
487 | // output might border to multiple outputs). | ||
488 | //struct wlc_point abs_pos; | ||
489 | //get_layout_center_position(container, &abs_pos); | ||
490 | |||
491 | |||
492 | // TODO WLR fullscreen | ||
493 | /* | ||
494 | if (container->type == C_VIEW && swayc_is_fullscreen(container)) { | ||
495 | wlr_log(L_DEBUG, "Moving from fullscreen view, skipping to output"); | ||
496 | container = swayc_parent_by_type(container, C_OUTPUT); | ||
497 | get_layout_center_position(container, &abs_pos); | ||
498 | swayc_t *output = swayc_adjacent_output(container, dir, &abs_pos, true); | ||
499 | return get_swayc_in_output_direction(output, dir); | ||
500 | } | ||
501 | if (container->type == C_WORKSPACE && container->fullscreen) { | ||
502 | sway_log(L_DEBUG, "Moving to fullscreen view"); | ||
503 | return container->fullscreen; | ||
504 | } | ||
505 | */ | ||
506 | |||
507 | swayc_t *wrap_candidate = NULL; | ||
508 | while (true) { | ||
509 | // Test if we can even make a difference here | ||
510 | bool can_move = false; | ||
511 | int desired; | ||
512 | int idx = index_child(container); | ||
513 | if (parent->type == C_ROOT) { | ||
514 | enum wlr_direction wlr_dir = 0; | ||
515 | if (!sway_assert(sway_dir_to_wlr(dir, &wlr_dir), | ||
516 | "got invalid direction: %d", dir)) { | ||
517 | return NULL; | ||
518 | } | ||
519 | int lx, ly; | ||
520 | get_layout_center_position(container, &lx, &ly); | ||
521 | struct wlr_output_layout *layout = root_container.sway_root->output_layout; | ||
522 | struct wlr_output *wlr_adjacent = | ||
523 | wlr_output_layout_adjacent_output(layout, wlr_dir, | ||
524 | container->sway_output->wlr_output, lx, ly); | ||
525 | swayc_t *adjacent = sway_output_from_wlr(wlr_adjacent); | ||
526 | |||
527 | if (!adjacent || adjacent == container) { | ||
528 | return wrap_candidate; | ||
529 | } | ||
530 | swayc_t *next = get_swayc_in_output_direction(adjacent, dir, seat); | ||
531 | if (next == NULL) { | ||
532 | return NULL; | ||
533 | } | ||
534 | if (next->children && next->children->length) { | ||
535 | // TODO consider floating children as well | ||
536 | return sway_seat_get_focus_inactive(seat, next); | ||
537 | } else { | ||
538 | return next; | ||
539 | } | ||
540 | } else { | ||
541 | if (dir == MOVE_LEFT || dir == MOVE_RIGHT) { | ||
542 | if (parent->layout == L_HORIZ || parent->layout == L_TABBED) { | ||
543 | can_move = true; | ||
544 | desired = idx + (dir == MOVE_LEFT ? -1 : 1); | ||
545 | } | ||
546 | } else { | ||
547 | if (parent->layout == L_VERT || parent->layout == L_STACKED) { | ||
548 | can_move = true; | ||
549 | desired = idx + (dir == MOVE_UP ? -1 : 1); | ||
550 | } | ||
551 | } | ||
552 | } | ||
553 | |||
554 | if (can_move) { | ||
555 | // TODO handle floating | ||
556 | if (desired < 0 || desired >= parent->children->length) { | ||
557 | can_move = false; | ||
558 | int len = parent->children->length; | ||
559 | if (!wrap_candidate && len > 1) { | ||
560 | if (desired < 0) { | ||
561 | wrap_candidate = parent->children->items[len-1]; | ||
562 | } else { | ||
563 | wrap_candidate = parent->children->items[0]; | ||
564 | } | ||
565 | if (config->force_focus_wrapping) { | ||
566 | return wrap_candidate; | ||
567 | } | ||
568 | } | ||
569 | } else { | ||
570 | wlr_log(L_DEBUG, "%s cont %d-%p dir %i sibling %d: %p", __func__, | ||
571 | idx, container, dir, desired, parent->children->items[desired]); | ||
572 | return parent->children->items[desired]; | ||
573 | } | ||
574 | } | ||
575 | |||
576 | if (!can_move) { | ||
577 | container = parent; | ||
578 | parent = parent->parent; | ||
579 | if (!parent || container == limit) { | ||
580 | // wrapping is the last chance | ||
581 | return wrap_candidate; | ||
582 | } | ||
583 | } | ||
584 | } | ||
585 | } | ||
586 | |||
587 | swayc_t *get_swayc_in_direction(swayc_t *container, struct sway_seat *seat, | ||
588 | enum movement_direction dir) { | ||
589 | return get_swayc_in_direction_under(container, dir, seat, NULL); | ||
590 | } | ||
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 23c630b6..861fda4d 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c | |||
@@ -63,9 +63,10 @@ static bool _workspace_by_name(swayc_t *view, void *data) { | |||
63 | swayc_t *workspace_by_name(const char *name) { | 63 | swayc_t *workspace_by_name(const char *name) { |
64 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 64 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
65 | swayc_t *current_workspace = NULL, *current_output = NULL; | 65 | swayc_t *current_workspace = NULL, *current_output = NULL; |
66 | if (seat->focus) { | 66 | swayc_t *focus = sway_seat_get_focus(seat); |
67 | current_workspace = swayc_parent_by_type(seat->focus, C_WORKSPACE); | 67 | if (focus) { |
68 | current_output = swayc_parent_by_type(seat->focus, C_OUTPUT); | 68 | current_workspace = swayc_parent_by_type(focus, C_WORKSPACE); |
69 | current_output = swayc_parent_by_type(focus, C_OUTPUT); | ||
69 | } | 70 | } |
70 | if (strcmp(name, "prev") == 0) { | 71 | if (strcmp(name, "prev") == 0) { |
71 | return workspace_prev(current_workspace); | 72 | return workspace_prev(current_workspace); |
@@ -102,7 +103,8 @@ swayc_t *workspace_create(const char *name) { | |||
102 | } | 103 | } |
103 | // Otherwise create a new one | 104 | // Otherwise create a new one |
104 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 105 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
105 | parent = seat->focus; | 106 | swayc_t *focus = sway_seat_get_focus_inactive(seat, &root_container); |
107 | parent = focus; | ||
106 | parent = swayc_parent_by_type(parent, C_OUTPUT); | 108 | parent = swayc_parent_by_type(parent, C_OUTPUT); |
107 | return new_workspace(parent, name); | 109 | return new_workspace(parent, name); |
108 | } | 110 | } |
@@ -118,9 +120,15 @@ swayc_t *workspace_output_prev_next_impl(swayc_t *output, bool next) { | |||
118 | return NULL; | 120 | return NULL; |
119 | } | 121 | } |
120 | 122 | ||
123 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
124 | swayc_t *focus = sway_seat_get_focus_inactive(seat, output); | ||
125 | swayc_t *workspace = (focus->type == C_WORKSPACE ? | ||
126 | focus : | ||
127 | swayc_parent_by_type(focus, C_WORKSPACE)); | ||
128 | |||
121 | int i; | 129 | int i; |
122 | for (i = 0; i < output->children->length; i++) { | 130 | for (i = 0; i < output->children->length; i++) { |
123 | if (output->children->items[i] == output->focused) { | 131 | if (output->children->items[i] == workspace) { |
124 | return output->children->items[ | 132 | return output->children->items[ |
125 | wrap(i + (next ? 1 : -1), output->children->length)]; | 133 | wrap(i + (next ? 1 : -1), output->children->length)]; |
126 | } | 134 | } |
@@ -193,12 +201,13 @@ bool workspace_switch(swayc_t *workspace) { | |||
193 | return false; | 201 | return false; |
194 | } | 202 | } |
195 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 203 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
196 | if (!seat || !seat->focus) { | 204 | swayc_t *focus = sway_seat_get_focus_inactive(seat, &root_container); |
205 | if (!seat || !focus) { | ||
197 | return false; | 206 | return false; |
198 | } | 207 | } |
199 | swayc_t *active_ws = seat->focus; | 208 | swayc_t *active_ws = focus; |
200 | if (active_ws->type != C_WORKSPACE) { | 209 | if (active_ws->type != C_WORKSPACE) { |
201 | swayc_parent_by_type(seat->focus, C_WORKSPACE); | 210 | swayc_parent_by_type(focus, C_WORKSPACE); |
202 | } | 211 | } |
203 | 212 | ||
204 | if (config->auto_back_and_forth | 213 | if (config->auto_back_and_forth |
@@ -222,16 +231,12 @@ bool workspace_switch(swayc_t *workspace) { | |||
222 | // TODO: Deal with sticky containers | 231 | // TODO: Deal with sticky containers |
223 | 232 | ||
224 | wlr_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name); | 233 | wlr_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name); |
225 | // TODO FOCUS: Focus the last view this seat had focused on this workspace | 234 | swayc_t *next = sway_seat_get_focus_inactive(seat, workspace); |
226 | if (workspace->children->length) { | 235 | if (next == NULL) { |
227 | // TODO FOCUS: This is really fucking stupid | 236 | next = workspace; |
228 | sway_seat_set_focus(seat, workspace->children->items[0]); | ||
229 | } else { | ||
230 | sway_seat_set_focus(seat, workspace); | ||
231 | } | 237 | } |
238 | sway_seat_set_focus(seat, next); | ||
232 | swayc_t *output = swayc_parent_by_type(workspace, C_OUTPUT); | 239 | swayc_t *output = swayc_parent_by_type(workspace, C_OUTPUT); |
233 | // TODO FOCUS: take a look at this | ||
234 | output->focused = workspace; | ||
235 | arrange_windows(output, -1, -1); | 240 | arrange_windows(output, -1, -1); |
236 | return true; | 241 | return true; |
237 | } | 242 | } |