aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sway/container.h10
-rw-r--r--include/sway/input/seat.h21
-rw-r--r--include/sway/layout.h20
-rw-r--r--include/sway/workspace.h10
-rw-r--r--sway/commands.c3
-rw-r--r--sway/commands/kill.c7
-rw-r--r--sway/commands/workspace.c3
-rw-r--r--sway/desktop/output.c10
-rw-r--r--sway/desktop/xdg_shell_v6.c3
-rw-r--r--sway/input/input-manager.c2
-rw-r--r--sway/input/seat.c183
-rw-r--r--sway/ipc-json.c4
-rw-r--r--sway/tree/container.c33
-rw-r--r--sway/tree/layout.c208
-rw-r--r--sway/tree/workspace.c37
15 files changed, 480 insertions, 74 deletions
diff --git a/include/sway/container.h b/include/sway/container.h
index 0c66932d..48363be6 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,10 @@ void container_map(swayc_t *container,
162swayc_t *swayc_at(swayc_t *parent, double lx, double ly, 158swayc_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 */
164void container_for_each_bfs(swayc_t *con, void (*f)(swayc_t *con, void *data),
165 void *data);
166
165#endif 167#endif
diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h
index b21cbccb..f9244f43 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
15struct 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
15struct sway_seat { 24struct 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,13 @@ void sway_seat_configure_xcursor(struct sway_seat *seat);
44 56
45void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container); 57void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container);
46 58
59swayc_t *sway_seat_get_focus(struct sway_seat *seat);
60
61swayc_t *sway_seat_get_focus_inactive(struct sway_seat *seat, swayc_t *container);
62
63swayc_t *sway_seat_get_focus_by_type(struct sway_seat *seat,
64 enum swayc_types type);
65
47void sway_seat_set_config(struct sway_seat *seat, struct seat_config *seat_config); 66void sway_seat_set_config(struct sway_seat *seat, struct seat_config *seat_config);
48 67
49#endif 68#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
7enum 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
6struct sway_container; 19struct 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
16void init_layout(void); 33void init_layout(void);
17void add_child(struct sway_container *parent, struct sway_container *child); 34void add_child(struct sway_container *parent, struct sway_container *child);
35swayc_t *add_sibling(swayc_t *parent, swayc_t *child);
18struct sway_container *remove_child(struct sway_container *child); 36struct sway_container *remove_child(struct sway_container *child);
19enum swayc_layouts default_layout(struct sway_container *output); 37enum swayc_layouts default_layout(struct sway_container *output);
20void sort_workspaces(struct sway_container *output); 38void sort_workspaces(struct sway_container *output);
21void arrange_windows(struct sway_container *container, double width, double height); 39void arrange_windows(struct sway_container *container, double width, double height);
40swayc_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/workspace.h b/include/sway/workspace.h
index 30bbdaa8..ca6f9bdb 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
4struct sway_container; 4#include <sway/container.h>
5 5
6extern char *prev_workspace_name; 6extern char *prev_workspace_name;
7 7
@@ -12,9 +12,9 @@ bool workspace_switch(swayc_t *workspace);
12struct sway_container *workspace_by_number(const char* name); 12struct sway_container *workspace_by_number(const char* name);
13swayc_t *workspace_by_name(const char*); 13swayc_t *workspace_by_name(const char*);
14 14
15struct sway_container *workspace_output_next(struct sway_container *current); 15struct sway_container *workspace_output_next(swayc_t *current);
16struct sway_container *workspace_next(struct sway_container *current); 16struct sway_container *workspace_next(swayc_t *current);
17struct sway_container *workspace_output_prev(struct sway_container *current); 17struct sway_container *workspace_output_prev(swayc_t *current);
18struct sway_container *workspace_prev(struct sway_container *current); 18struct sway_container *workspace_prev(swayc_t *current);
19 19
20#endif 20#endif
diff --git a/sway/commands.c b/sway/commands.c
index 0d4aa104..d8d29a1c 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -281,7 +281,8 @@ struct cmd_results *handle_command(char *_exec) {
281 seat = sway_input_manager_get_default_seat(input_manager); 281 seat = sway_input_manager_get_default_seat(input_manager);
282 } 282 }
283 if (seat) { 283 if (seat) {
284 config->handler_context.current_container = seat->focus; 284 config->handler_context.current_container =
285 sway_seat_get_focus(seat);
285 struct cmd_results *res = handler->handle(argc-1, argv+1); 286 struct cmd_results *res = handler->handle(argc-1, argv+1);
286 if (res->status != CMD_SUCCESS) { 287 if (res->status != CMD_SUCCESS) {
287 free_argv(argc, argv); 288 free_argv(argc, argv);
diff --git a/sway/commands/kill.c b/sway/commands/kill.c
index cebf7f3c..4b3666be 100644
--- a/sway/commands/kill.c
+++ b/sway/commands/kill.c
@@ -10,11 +10,16 @@ struct cmd_results *cmd_kill(int argc, char **argv) {
10 return cmd_results_new(CMD_FAILURE, "kill", 10 return cmd_results_new(CMD_FAILURE, "kill",
11 "Command 'kill' cannot be used in the config file"); 11 "Command 'kill' cannot be used in the config file");
12 } 12 }
13 if (config->handler_context.current_container == NULL) {
14 wlr_log(L_DEBUG, "no container to kill");
15 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
16 }
13 enum swayc_types type = config->handler_context.current_container->type; 17 enum swayc_types type = config->handler_context.current_container->type;
14 if (type != C_VIEW || type != C_CONTAINER) { 18 if (type != C_VIEW && type != C_CONTAINER) {
15 return cmd_results_new(CMD_INVALID, NULL, 19 return cmd_results_new(CMD_INVALID, NULL,
16 "Can only kill views and containers with this command"); 20 "Can only kill views and containers with this command");
17 } 21 }
22
18 // TODO close arbitrary containers without a view 23 // TODO close arbitrary containers without a view
19 struct sway_view *view = 24 struct sway_view *view =
20 config->handler_context.current_container->sway_view; 25 config->handler_context.current_container->sway_view;
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 a66601b5..e250d450 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -220,12 +220,18 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
220 struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); 220 struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend);
221 wlr_renderer_clear(renderer, &clear_color); 221 wlr_renderer_clear(renderer, &clear_color);
222 222
223 wlr_renderer_clear(renderer, &clear_color);
224
223 int buffer_age = -1; 225 int buffer_age = -1;
224 wlr_output_make_current(wlr_output, &buffer_age); 226 wlr_output_make_current(wlr_output, &buffer_age);
225 wlr_renderer_begin(server->renderer, wlr_output);
226 wlr_renderer_begin(server->renderer, wlr_output); 227 wlr_renderer_begin(server->renderer, wlr_output);
227 228
228 swayc_t *workspace = soutput->swayc->focused; 229 struct sway_seat *seat = input_manager_current_seat(input_manager);
230 swayc_t *focus = sway_seat_get_focus_inactive(seat, soutput->swayc);
231 swayc_t *workspace = (focus->type == C_WORKSPACE ?
232 focus :
233 swayc_parent_by_type(focus, C_WORKSPACE));
234
229 swayc_descendants_of_type(workspace, C_VIEW, output_frame_view, soutput); 235 swayc_descendants_of_type(workspace, C_VIEW, output_frame_view, soutput);
230 236
231 // render unmanaged views on top 237 // render unmanaged views on top
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 f59daea3..e6708bad 100644
--- a/sway/input/input-manager.c
+++ b/sway/input/input-manager.c
@@ -281,7 +281,7 @@ bool sway_input_manager_has_focus(struct sway_input_manager *input,
281 swayc_t *container) { 281 swayc_t *container) {
282 struct sway_seat *seat = NULL; 282 struct sway_seat *seat = NULL;
283 wl_list_for_each(seat, &input->seats, link) { 283 wl_list_for_each(seat, &input->seats, link) {
284 if (seat->focus == container) { 284 if (sway_seat_get_focus(seat) == container) {
285 return true; 285 return true;
286 } 286 }
287 } 287 }
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
35static 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
61static 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
90static 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
96static 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
35struct sway_seat *sway_seat_create(struct sway_input_manager *input, 110struct 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
207static 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
213void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) { 292void 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
333swayc_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
354swayc_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
361swayc_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
250void sway_seat_set_config(struct sway_seat *seat, 371void 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
81static void ipc_json_describe_workspace(swayc_t *workspace, json_object *object) { 81static void ipc_json_describe_workspace(swayc_t *workspace, json_object *object) {
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 1a468c19..a6268133 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -151,19 +151,19 @@ swayc_t *new_output(struct sway_output *sway_output) {
151 char *ws_name = workspace_next_name(output->name); 151 char *ws_name = workspace_next_name(output->name);
152 wlr_log(L_DEBUG, "Creating default workspace %s", ws_name); 152 wlr_log(L_DEBUG, "Creating default workspace %s", ws_name);
153 swayc_t *ws = new_workspace(output, ws_name); 153 swayc_t *ws = new_workspace(output, ws_name);
154 output->focused = ws;
155 // Set each seat's focus if not already set 154 // Set each seat's focus if not already set
156 // TODO FOCUS: this is probably stupid, we shouldn't define focus in two 155 // 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 156 // places. We should probably put the active workspace on the sway_output
158 // struct instead of trying to do focus semantics like this 157 // struct instead of trying to do focus semantics like this
159 struct sway_seat *seat = NULL; 158 struct sway_seat *seat = NULL;
160 wl_list_for_each(seat, &input_manager->seats, link) { 159 wl_list_for_each(seat, &input_manager->seats, link) {
161 if (!seat->focus) { 160 if (!seat->has_focus) {
162 seat->focus = ws; 161 sway_seat_set_focus(seat, ws);
163 } 162 }
164 } 163 }
165 164
166 free(ws_name); 165 free(ws_name);
166 wl_signal_emit(&root_container.sway_root->events.new_container, output);
167 return output; 167 return output;
168} 168}
169 169
@@ -185,6 +185,7 @@ swayc_t *new_workspace(swayc_t *output, const char *name) {
185 185
186 add_child(output, workspace); 186 add_child(output, workspace);
187 sort_workspaces(output); 187 sort_workspaces(output);
188 wl_signal_emit(&root_container.sway_root->events.new_container, workspace);
188 return workspace; 189 return workspace;
189} 190}
190 191
@@ -207,9 +208,9 @@ swayc_t *new_view(swayc_t *sibling, struct sway_view *sway_view) {
207 add_child(sibling, swayc); 208 add_child(sibling, swayc);
208 } else { 209 } else {
209 // Regular case, create as sibling of current container 210 // Regular case, create as sibling of current container
210 // TODO WLR 211 add_sibling(sibling, swayc);
211 //add_sibling(sibling, swayc);
212 } 212 }
213 wl_signal_emit(&root_container.sway_root->events.new_container, swayc);
213 return swayc; 214 return swayc;
214} 215}
215 216
@@ -380,3 +381,25 @@ void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), voi
380 f(container, data); 381 f(container, data);
381 } 382 }
382} 383}
384
385void container_for_each_bfs(swayc_t *con, void (*f)(swayc_t *con, void *data),
386 void *data) {
387 list_t *queue = create_list();
388 if (queue == NULL) {
389 wlr_log(L_ERROR, "could not allocate list");
390 return;
391 }
392
393 list_add(queue, con);
394
395 swayc_t *current = NULL;
396 while (queue->length) {
397 current = queue->items[0];
398 list_del(queue, 0);
399 f(current, data);
400 // TODO floating containers
401 list_cat(queue, current->children);
402 }
403
404 list_free(queue);
405}
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index 41ff81b2..205f42eb 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
65static 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
82swayc_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
62void add_child(swayc_t *parent, swayc_t *child) { 91void 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);
@@ -321,3 +347,179 @@ 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 */
354static swayc_t *get_swayc_in_output_direction(swayc_t *output,
355 enum movement_direction dir, struct sway_seat *seat) {
356 // XXX is this really a seat function or can we do it with the default
357 // seat?
358 if (!output) {
359 return NULL;
360 }
361
362 swayc_t *ws = sway_seat_get_focus_inactive(seat, output);
363 if (ws->type != C_WORKSPACE) {
364 ws = swayc_parent_by_type(ws, C_WORKSPACE);
365 }
366
367 if (ws && ws->children->length > 0) {
368 switch (dir) {
369 case MOVE_LEFT:
370 // get most right child of new output
371 return ws->children->items[ws->children->length-1];
372 case MOVE_RIGHT:
373 // get most left child of new output
374 return ws->children->items[0];
375 case MOVE_UP:
376 case MOVE_DOWN:
377 {
378 swayc_t *focused = sway_seat_get_focus_inactive(seat, ws);
379 if (focused && focused->parent) {
380 swayc_t *parent = focused->parent;
381 if (parent->layout == L_VERT) {
382 if (dir == MOVE_UP) {
383 // get child furthest down on new output
384 return parent->children->items[parent->children->length-1];
385 } else if (dir == MOVE_DOWN) {
386 // get child furthest up on new output
387 return parent->children->items[0];
388 }
389 }
390 return focused;
391 }
392 break;
393 }
394 default:
395 break;
396 }
397 }
398
399 return output;
400}
401
402static void get_absolute_center_position(swayc_t *container, int *x, int *y) {
403 *x = container->x + container->width/2;
404 *y = container->y + container->height/2;
405}
406
407static swayc_t *get_swayc_in_direction_under(swayc_t *container,
408 enum movement_direction dir, struct sway_seat *seat, swayc_t *limit) {
409 if (dir == MOVE_CHILD) {
410 return sway_seat_get_focus_inactive(seat, container);
411 }
412
413 swayc_t *parent = container->parent;
414 if (dir == MOVE_PARENT) {
415 if (parent->type == C_OUTPUT) {
416 return NULL;
417 } else {
418 return parent;
419 }
420 }
421
422 if (dir == MOVE_PREV || dir == MOVE_NEXT) {
423 int focused_idx = index_child(container);
424 if (focused_idx == -1) {
425 return NULL;
426 } else {
427 int desired = (focused_idx + (dir == MOVE_NEXT ? 1 : -1)) %
428 parent->children->length;
429 if (desired < 0) {
430 desired += parent->children->length;
431 }
432 return parent->children->items[desired];
433 }
434 }
435
436 // If moving to an adjacent output we need a starting position (since this
437 // output might border to multiple outputs).
438 //struct wlc_point abs_pos;
439 //get_absolute_center_position(container, &abs_pos);
440
441
442 // TODO WLR fullscreen
443 /*
444 if (container->type == C_VIEW && swayc_is_fullscreen(container)) {
445 wlr_log(L_DEBUG, "Moving from fullscreen view, skipping to output");
446 container = swayc_parent_by_type(container, C_OUTPUT);
447 get_absolute_center_position(container, &abs_pos);
448 swayc_t *output = swayc_adjacent_output(container, dir, &abs_pos, true);
449 return get_swayc_in_output_direction(output, dir);
450 }
451 if (container->type == C_WORKSPACE && container->fullscreen) {
452 sway_log(L_DEBUG, "Moving to fullscreen view");
453 return container->fullscreen;
454 }
455 */
456
457 swayc_t *wrap_candidate = NULL;
458 while (true) {
459 // Test if we can even make a difference here
460 bool can_move = false;
461 int desired;
462 int idx = index_child(container);
463 if (parent->type == C_ROOT) {
464 // TODO
465 /*
466 struct wlr_output_layout *layout = root_container.sway_root->output_layout;
467 wlr_output_layout_adjacent_output(layout, container->sway_output->wlr_output);
468 //swayc_t *output = swayc_adjacent_output(container, dir, &abs_pos, true);
469 if (!output || output == container) {
470 return wrap_candidate;
471 }
472 wlr_log(L_DEBUG, "Moving between outputs");
473 return get_swayc_in_output_direction(output, dir, seat);
474 */
475 } else {
476 if (dir == MOVE_LEFT || dir == MOVE_RIGHT) {
477 if (parent->layout == L_HORIZ || parent->layout == L_TABBED) {
478 can_move = true;
479 desired = idx + (dir == MOVE_LEFT ? -1 : 1);
480 }
481 } else {
482 if (parent->layout == L_VERT || parent->layout == L_STACKED) {
483 can_move = true;
484 desired = idx + (dir == MOVE_UP ? -1 : 1);
485 }
486 }
487 }
488
489 if (can_move) {
490 // TODO handle floating
491 if (desired < 0 || desired >= parent->children->length) {
492 can_move = false;
493 int len = parent->children->length;
494 if (!wrap_candidate && len > 1) {
495 if (desired < 0) {
496 wrap_candidate = parent->children->items[len-1];
497 } else {
498 wrap_candidate = parent->children->items[0];
499 }
500 if (config->force_focus_wrapping) {
501 return wrap_candidate;
502 }
503 }
504 } else {
505 wlr_log(L_DEBUG, "%s cont %d-%p dir %i sibling %d: %p", __func__,
506 idx, container, dir, desired, parent->children->items[desired]);
507 return parent->children->items[desired];
508 }
509 }
510
511 if (!can_move) {
512 container = parent;
513 parent = parent->parent;
514 if (!parent || container == limit) {
515 // wrapping is the last chance
516 return wrap_candidate;
517 }
518 }
519 }
520}
521
522swayc_t *get_swayc_in_direction(swayc_t *container, struct sway_seat *seat,
523 enum movement_direction dir) {
524 return get_swayc_in_direction_under(container, dir, seat, NULL);
525}
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) {
63swayc_t *workspace_by_name(const char *name) { 63swayc_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}